diff --git a/.hgignore b/.hgignore index ca1b0b21ee2..0092bd4ff5a 100644 --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,3 @@ ^build/ ^dist/ -^nbproject/private/ +/nbproject/private/ diff --git a/.hgtags b/.hgtags index 68872664ece..fdf92c01ecc 100644 --- a/.hgtags +++ b/.hgtags @@ -51,3 +51,7 @@ ce74bd35ce948d629a356e168797f44b593b1578 jdk7-b73 4e7661eaa211e186674f6cbefec4aef1144ac2a0 jdk7-b74 946518568340c4e511549318f19f47f06b7f5f9b jdk7-b75 09e0b33177af2b98a03c9ca19eedf61440bd1cf6 jdk7-b76 +1d0121b741f029dc4b828e4b36ba6fda92907dd7 jdk7-b77 +4061c66ba1af1a2e27c2c839ba887407dd3ce050 jdk7-b78 +e9c98378f6b9256c0595ef2985ca5899f0c0e274 jdk7-b79 +e6abd38682d237306d6c147c17538ec9e7f8e3a7 jdk7-b80 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index a82460bf48f..7f37898d353 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -51,3 +51,7 @@ e1b972ff53cd58f825791f8ed9b2deffd16e768c jdk7-b68 2c88089b6e1c053597418099a14232182c387edc jdk7-b74 d1516b9f23954b29b8e76e6f4efc467c08c78133 jdk7-b75 c8b63075403d53a208104a8a6ea5072c1cb66aab jdk7-b76 +1f17ca8353babb13f4908c1f87d11508232518c8 jdk7-b77 +ab4ae8f4514693a9fe17ca2fec0239d8f8450d2c jdk7-b78 +20aeeb51713990dbea6929a2e100a8bbf5df70d4 jdk7-b79 +a3242906c7747b5d9bcc3d118c7c3c69aa40f4b7 jdk7-b80 diff --git a/Makefile b/Makefile index a0b2dc384f9..1131c8b251a 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ endif # For start and finish echo lines TITLE_TEXT = Control $(PLATFORM) $(ARCH) $(RELEASE) -DAYE_STAMP = `$(DATE) '+%y-%m-%d %H:%M'` +DATE_STAMP = `$(DATE) '+%y-%m-%d %H:%M'` START_ECHO = echo "$(TITLE_TEXT) $@ build started: $(DATE_STAMP)" FINISH_ECHO = echo "$(TITLE_TEXT) $@ build finished: $(DATE_STAMP)" @@ -188,7 +188,7 @@ FRESH_DEBUG_BOOTDIR=$(ABS_BOOTDIR_OUTPUTDIR)-$(DEBUG_NAME)/j2sdk-image create_fresh_product_bootdir: FRC @$(START_ECHO) $(MAKE) ALT_OUTPUTDIR=$(ABS_BOOTDIR_OUTPUTDIR) \ - NO_DOCS=true \ + GENERATE_DOCS=false \ BOOT_CYCLE_SETTINGS= \ build_product_image @$(FINISH_ECHO) @@ -196,7 +196,7 @@ create_fresh_product_bootdir: FRC create_fresh_debug_bootdir: FRC @$(START_ECHO) $(MAKE) ALT_OUTPUTDIR=$(ABS_BOOTDIR_OUTPUTDIR) \ - NO_DOCS=true \ + GENERATE_DOCS=false \ BOOT_CYCLE_DEBUG_SETTINGS= \ build_debug_image @$(FINISH_ECHO) @@ -204,7 +204,7 @@ create_fresh_debug_bootdir: FRC create_fresh_fastdebug_bootdir: FRC @$(START_ECHO) $(MAKE) ALT_OUTPUTDIR=$(ABS_BOOTDIR_OUTPUTDIR) \ - NO_DOCS=true \ + GENERATE_DOCS=false \ BOOT_CYCLE_DEBUG_SETTINGS= \ build_fastdebug_image @$(FINISH_ECHO) @@ -253,7 +253,7 @@ generic_debug_build: $(MAKE) \ ALT_OUTPUTDIR=$(ABS_OUTPUTDIR)-$(DEBUG_NAME) \ DEBUG_NAME=$(DEBUG_NAME) \ - NO_DOCS=true \ + GENERATE_DOCS=false \ $(BOOT_CYCLE_DEBUG_SETTINGS) \ generic_build_repo_series @$(FINISH_ECHO) @@ -323,7 +323,7 @@ openjdk_build: $(MKDIR) -p $(OPENJDK_OUTPUTDIR) ($(CD) $(OPENJDK_BUILDDIR) && $(MAKE) \ OPENJDK=true \ - NO_DOCS=true \ + GENERATE_DOCS=false \ ALT_JDK_DEVTOOLS_DIR=$(JDK_DEVTOOLS_DIR) \ ALT_OUTPUTDIR=$(OPENJDK_OUTPUTDIR) \ ALT_BINARY_PLUGS_PATH=$(OPENJDK_PLUGS) \ diff --git a/corba/.hgignore b/corba/.hgignore index ca1b0b21ee2..0092bd4ff5a 100644 --- a/corba/.hgignore +++ b/corba/.hgignore @@ -1,3 +1,3 @@ ^build/ ^dist/ -^nbproject/private/ +/nbproject/private/ diff --git a/corba/.hgtags b/corba/.hgtags index 9e8067101da..2472579cb11 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -51,3 +51,7 @@ b751c528c55560cf2adeaeef24b39ca1f4d1cbf7 jdk7-b73 5d0cf59a3203b9f57aceebc33ae656b884987955 jdk7-b74 0fb137085952c8e47878e240d1cb40f14de463c4 jdk7-b75 937144222e2219939101b0129d26a872a7956b13 jdk7-b76 +6881f0383f623394b5ec73f27a5f329ff55d0467 jdk7-b77 +a7f7276b48cd74d8eb1baa83fbf3d1ef4a2603c8 jdk7-b78 +ec0421b5703b677e2226cf4bf7ae4eaafd8061c5 jdk7-b79 +0336e70ca0aeabc783cc01658f36cb6e27ea7934 jdk7-b80 diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/constExpr/Expression.java b/corba/src/share/classes/com/sun/tools/corba/se/idl/constExpr/Expression.java index 1dc4583e568..99d41510b02 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/constExpr/Expression.java +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/constExpr/Expression.java @@ -123,7 +123,7 @@ public abstract class Expression /** * Coerces a number to the target type of this expression. - * @parm number The number to coerce. + * @param obj The number to coerce. * @return the value of number coerced to the (target) type of * this expression. **/ @@ -142,7 +142,7 @@ public abstract class Expression /** * Coerces an integral value (BigInteger) to its corresponding unsigned * representation, if the target type of this expression is unsigned. - * @parm b The BigInteger to be coerced. + * @param b The BigInteger to be coerced. * @return the value of an integral type coerced to its corresponding * unsigned integral type, if the target type of this expression is * unsigned. @@ -170,7 +170,7 @@ public abstract class Expression /** * Coerces an integral value (BigInteger) to its corresponding signed * representation, if the target type of this expression is signed. - * @parm b The BigInteger to be coerced. + * @param b The BigInteger to be coerced. * @return the value of an integral type coerced to its corresponding * signed integral type, if the target type of this expression is * signed. diff --git a/corba/src/share/classes/javax/rmi/PortableRemoteObject.java b/corba/src/share/classes/javax/rmi/PortableRemoteObject.java index 432eb4a6fc8..10c3b95200e 100644 --- a/corba/src/share/classes/javax/rmi/PortableRemoteObject.java +++ b/corba/src/share/classes/javax/rmi/PortableRemoteObject.java @@ -161,7 +161,7 @@ public class PortableRemoteObject { * happens implicitly when the object is sent or received as an argument * on a remote method call, but in some circumstances it is useful to * perform this action by making an explicit call. See the - * {@link Stub#connect} method for more information. + * {@link javax.rmi.CORBA.Stub#connect} method for more information. * @param target the object to connect. * @param source a previously connected object. * @throws RemoteException if source is not connected diff --git a/corba/src/share/classes/org/omg/CORBA/SetOverrideType.java b/corba/src/share/classes/org/omg/CORBA/SetOverrideType.java index acf946871ee..a1e1acc595f 100644 --- a/corba/src/share/classes/org/omg/CORBA/SetOverrideType.java +++ b/corba/src/share/classes/org/omg/CORBA/SetOverrideType.java @@ -31,7 +31,7 @@ package org.omg.CORBA; * indicate whether policies should replace the * existing policies of an Object or be added to them. *

- * The method {@link omg.org.CORBA.Object._set_policy_override} takes + * The method {@link org.omg.CORBA.Object#_set_policy_override} takes * either SetOverrideType.SET_OVERRIDE or * SetOverrideType.ADD_OVERRIDE as its second argument. * The method _set_policy_override diff --git a/corba/src/share/classes/org/omg/CORBA/TCKind.java b/corba/src/share/classes/org/omg/CORBA/TCKind.java index bb3a748f26a..8aa33032da7 100644 --- a/corba/src/share/classes/org/omg/CORBA/TCKind.java +++ b/corba/src/share/classes/org/omg/CORBA/TCKind.java @@ -545,8 +545,6 @@ public class TCKind { * @param _value the int to convert. It must be one of * the int constants in the class * TCKind. - * @return a new TCKind instance whose value - * field matches the given int */ @Deprecated protected TCKind(int _value){ diff --git a/corba/src/share/classes/org/omg/CORBA/UnknownUserException.java b/corba/src/share/classes/org/omg/CORBA/UnknownUserException.java index 8509b2d5146..c66bbc99f1d 100644 --- a/corba/src/share/classes/org/omg/CORBA/UnknownUserException.java +++ b/corba/src/share/classes/org/omg/CORBA/UnknownUserException.java @@ -56,7 +56,7 @@ public final class UnknownUserException extends UserException { * Constructs an UnknownUserException object that contains the given * Any object. * - * @ param a an Any object that contains a user exception returned + * @param a an Any object that contains a user exception returned * by the server */ public UnknownUserException(Any a) { diff --git a/corba/src/share/classes/org/omg/CORBA/portable/ServantObject.java b/corba/src/share/classes/org/omg/CORBA/portable/ServantObject.java index c2c04e11cab..dd1ed8d0e26 100644 --- a/corba/src/share/classes/org/omg/CORBA/portable/ServantObject.java +++ b/corba/src/share/classes/org/omg/CORBA/portable/ServantObject.java @@ -43,7 +43,6 @@ public class ServantObject /** The real servant. The local stub may cast this field to the expected type, and then * invoke the operation directly. Note, the object may or may not be the actual servant * instance. - * @return The real servant */ public java.lang.Object servant; } diff --git a/corba/src/share/classes/org/omg/CosNaming/nameservice.idl b/corba/src/share/classes/org/omg/CosNaming/nameservice.idl index 226454d0fbd..7543484b0ed 100644 --- a/corba/src/share/classes/org/omg/CosNaming/nameservice.idl +++ b/corba/src/share/classes/org/omg/CosNaming/nameservice.idl @@ -256,7 +256,7 @@ module CosNaming * * @param n Name of the object

* - * @parm obj The Object to rebind with the given name

+ * @param obj The Object to rebind with the given name

* * @exception org.omg.CosNaming.NamingContextPackage.NotFound Indicates the name does not identify a binding.

* diff --git a/corba/src/share/classes/org/omg/PortableInterceptor/Interceptors.idl b/corba/src/share/classes/org/omg/PortableInterceptor/Interceptors.idl index ba94343d73d..8edefdf16ae 100644 --- a/corba/src/share/classes/org/omg/PortableInterceptor/Interceptors.idl +++ b/corba/src/share/classes/org/omg/PortableInterceptor/Interceptors.idl @@ -1730,7 +1730,7 @@ module PortableInterceptor { *

* Any number of components may exist with the same component ID. * - * @param a_component The IOP.TaggedComponent to add. + * @param tagged_component The IOP.TaggedComponent to add. */ void add_ior_component (in IOP::TaggedComponent tagged_component); @@ -1744,7 +1744,7 @@ module PortableInterceptor { *

* Any number of components may exist with the same component ID. * - * @param a_component The IOP.TaggedComponent to add. + * @param tagged_component The IOP.TaggedComponent to add. * @param profile_id The profile id of the profile to * which this component will be added. * @exception BAD_PARAM thrown, with a standard minor code of 29, if the diff --git a/hotspot/.hgignore b/hotspot/.hgignore index fec499bf63f..9818ff1af6e 100644 --- a/hotspot/.hgignore +++ b/hotspot/.hgignore @@ -1,6 +1,6 @@ ^build/ ^dist/ -^nbproject/private/ +/nbproject/private/ ^src/share/tools/hsdis/build/ ^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/ ^src/share/tools/IdealGraphVisualizer/build/ diff --git a/hotspot/.hgtags b/hotspot/.hgtags index d91cec8c3fe..84c4c8bc4c3 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -51,3 +51,7 @@ faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73 f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 jdk7-b74 d8dd291a362acb656026a9c0a9da48501505a1e7 jdk7-b75 9174bb32e934965288121f75394874eeb1fcb649 jdk7-b76 +455105fc81d941482f8f8056afaa7aa0949c9300 jdk7-b77 +e703499b4b51e3af756ae77c3d5e8b3058a14e4e jdk7-b78 +a5a6adfca6ecefb5894a848debabfe442ff50e25 jdk7-b79 +3003ddd1d4330b06cb4691ae74d600d3685899eb jdk7-b80 diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java index 629d23c54bd..0a157356207 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java @@ -63,12 +63,12 @@ public class SystemDictionary { javaSystemLoaderField = type.getOopField("_java_system_loader"); nofBuckets = db.lookupIntConstant("SystemDictionary::_nof_buckets").intValue(); - objectKlassField = type.getOopField(WK_KLASS("object_klass")); - classLoaderKlassField = type.getOopField(WK_KLASS("classloader_klass")); - stringKlassField = type.getOopField(WK_KLASS("string_klass")); - systemKlassField = type.getOopField(WK_KLASS("system_klass")); - threadKlassField = type.getOopField(WK_KLASS("thread_klass")); - threadGroupKlassField = type.getOopField(WK_KLASS("threadGroup_klass")); + objectKlassField = type.getOopField(WK_KLASS("Object_klass")); + classLoaderKlassField = type.getOopField(WK_KLASS("ClassLoader_klass")); + stringKlassField = type.getOopField(WK_KLASS("String_klass")); + systemKlassField = type.getOopField(WK_KLASS("System_klass")); + threadKlassField = type.getOopField(WK_KLASS("Thread_klass")); + threadGroupKlassField = type.getOopField(WK_KLASS("ThreadGroup_klass")); } // This WK functions must follow the definitions in systemDictionary.hpp: diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 5da770b9f1e..4dfc3baf752 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2009 HS_MAJOR_VER=17 HS_MINOR_VER=0 -HS_BUILD_NUMBER=05 +HS_BUILD_NUMBER=08 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/linux/makefiles/debug.make b/hotspot/make/linux/makefiles/debug.make index 4743745228d..1837d97311f 100644 --- a/hotspot/make/linux/makefiles/debug.make +++ b/hotspot/make/linux/makefiles/debug.make @@ -38,7 +38,7 @@ _JUNK_ := $(shell echo -e >&2 ""\ "Please use 'make jvmg' to build debug JVM. \n" \ "----------------------------------------------------------------------\n") -G_SUFFIX = +G_SUFFIX = _g VERSION = debug SYSDEFS += -DASSERT -DDEBUG PICFLAGS = DEFAULT diff --git a/hotspot/make/linux/makefiles/fastdebug.make b/hotspot/make/linux/makefiles/fastdebug.make index 740b7584364..c875123ea88 100644 --- a/hotspot/make/linux/makefiles/fastdebug.make +++ b/hotspot/make/linux/makefiles/fastdebug.make @@ -58,7 +58,7 @@ CFLAGS$(HOTSPARC_GENERIC) += $(OPT_CFLAGS/BYFILE) # Linker mapfile MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug -G_SUFFIX = +G_SUFFIX = _g VERSION = optimized SYSDEFS += -DASSERT -DFASTDEBUG PICFLAGS = DEFAULT diff --git a/hotspot/make/linux/makefiles/jsig.make b/hotspot/make/linux/makefiles/jsig.make index 6dcff6aa72a..611793967d8 100644 --- a/hotspot/make/linux/makefiles/jsig.make +++ b/hotspot/make/linux/makefiles/jsig.make @@ -25,9 +25,12 @@ # Rules to build signal interposition library, used by vm.make # libjsig[_g].so: signal interposition library -JSIG = jsig$(G_SUFFIX) +JSIG = jsig LIBJSIG = lib$(JSIG).so +JSIG_G = $(JSIG)$(G_SUFFIX) +LIBJSIG_G = lib$(JSIG_G).so + JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm DEST_JSIG = $(JDK_LIBDIR)/$(LIBJSIG) @@ -50,6 +53,7 @@ $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< -ldl + $(QUIETLY) [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); } install_jsig: $(LIBJSIG) @echo "Copying $(LIBJSIG) to $(DEST_JSIG)" diff --git a/hotspot/make/linux/makefiles/jvmg.make b/hotspot/make/linux/makefiles/jvmg.make index 4b09db64d21..edd0d9c5476 100644 --- a/hotspot/make/linux/makefiles/jvmg.make +++ b/hotspot/make/linux/makefiles/jvmg.make @@ -35,7 +35,7 @@ CFLAGS += $(DEBUG_CFLAGS/BYFILE) # Linker mapfile MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug -G_SUFFIX = +G_SUFFIX = _g VERSION = debug SYSDEFS += -DASSERT -DDEBUG PICFLAGS = DEFAULT diff --git a/hotspot/make/linux/makefiles/launcher.make b/hotspot/make/linux/makefiles/launcher.make index e367409f00e..e7f813c2df6 100644 --- a/hotspot/make/linux/makefiles/launcher.make +++ b/hotspot/make/linux/makefiles/launcher.make @@ -25,7 +25,9 @@ # Rules to build gamma launcher, used by vm.make # gamma[_g]: launcher -LAUNCHER = gamma$(G_SUFFIX) + +LAUNCHER = gamma +LAUNCHER_G = $(LAUNCHER)$(G_SUFFIX) LAUNCHERDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/launcher LAUNCHERFLAGS = $(ARCHFLAG) \ @@ -70,4 +72,5 @@ $(LAUNCHER): $(LAUNCHER.o) $(LIBJVM) $(LAUNCHER_MAPFILE) $(LINK_LAUNCHER/PRE_HOOK) \ $(LINK_LAUNCHER) $(LFLAGS_LAUNCHER) -o $@ $(LAUNCHER.o) $(LIBS_LAUNCHER); \ $(LINK_LAUNCHER/POST_HOOK) \ + [ -f $(LAUNCHER_G) ] || { ln -s $@ $(LAUNCHER_G); }; \ } diff --git a/hotspot/make/linux/makefiles/saproc.make b/hotspot/make/linux/makefiles/saproc.make index 696157969ea..4cbd9cb9b2b 100644 --- a/hotspot/make/linux/makefiles/saproc.make +++ b/hotspot/make/linux/makefiles/saproc.make @@ -25,9 +25,13 @@ # Rules to build serviceability agent library, used by vm.make # libsaproc[_g].so: serviceability agent -SAPROC = saproc$(G_SUFFIX) + +SAPROC = saproc LIBSAPROC = lib$(SAPROC).so +SAPROC_G = $(SAPROC)$(G_SUFFIX) +LIBSAPROC_G = lib$(SAPROC_G).so + AGENT_DIR = $(GAMMADIR)/agent SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) @@ -75,6 +79,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) $(SA_DEBUG_CFLAGS) \ -o $@ \ -lthread_db + $(QUIETLY) [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); } install_saproc: checkAndBuildSA $(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \ diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make index 641d0d79514..fb847e31922 100644 --- a/hotspot/make/linux/makefiles/vm.make +++ b/hotspot/make/linux/makefiles/vm.make @@ -113,8 +113,9 @@ include $(MAKEFILES_DIR)/dtrace.make #---------------------------------------------------------------------- # JVM -JVM = jvm$(G_SUFFIX) -LIBJVM = lib$(JVM).so +JVM = jvm +LIBJVM = lib$(JVM).so +LIBJVM_G = lib$(JVM)$(G_SUFFIX).so JVM_OBJ_FILES = $(Obj_Files) @@ -201,6 +202,7 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) $(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \ $(LINK_LIB.CC/POST_HOOK) \ rm -f $@.1; ln -s $@ $@.1; \ + [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \ if [ -x /usr/sbin/selinuxenabled ] ; then \ /usr/sbin/selinuxenabled; \ if [ $$? = 0 ] ; then \ diff --git a/hotspot/make/solaris/makefiles/debug.make b/hotspot/make/solaris/makefiles/debug.make index 4fdf4a7463e..ba312ffeb99 100644 --- a/hotspot/make/solaris/makefiles/debug.make +++ b/hotspot/make/solaris/makefiles/debug.make @@ -54,7 +54,7 @@ _JUNK_ := $(shell echo >&2 ""\ "Please use 'gnumake jvmg' to build debug JVM. \n" \ "-------------------------------------------------------------------------\n") -G_SUFFIX = +G_SUFFIX = _g VERSION = debug SYSDEFS += -DASSERT -DDEBUG PICFLAGS = DEFAULT diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index 0ba875dc58e..4482f26fffa 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -24,8 +24,8 @@ # Rules to build jvm_db/dtrace, used by vm.make -# we build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 -# but not for CORE configuration +# We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 +# but not for CORE or KERNEL configurations. ifneq ("${TYPE}", "CORE") ifneq ("${TYPE}", "KERNEL") @@ -37,12 +37,13 @@ dtraceCheck: else - JVM_DB = libjvm_db -LIBJVM_DB = libjvm$(G_SUFFIX)_db.so +LIBJVM_DB = libjvm_db.so +LIBJVM_DB_G = libjvm$(G_SUFFIX)_db.so JVM_DTRACE = jvm_dtrace -LIBJVM_DTRACE = libjvm$(G_SUFFIX)_dtrace.so +LIBJVM_DTRACE = libjvm_dtrace.so +LIBJVM_DTRACE_G = libjvm$(G_SUFFIX)_dtrace.so JVMOFFS = JvmOffsets JVMOFFS.o = $(JVMOFFS).o @@ -77,7 +78,7 @@ LFLAGS_JVM_DB += -D_REENTRANT $(PICFLAG) LFLAGS_JVM_DTRACE += -D_REENTRANT $(PICFLAG) else LFLAGS_JVM_DB += -mt $(PICFLAG) -xnolib -LFLAGS_JVM_DTRACE += -mt $(PICFLAG) -xnolib +LFLAGS_JVM_DTRACE += -mt $(PICFLAG) -xnolib -ldl endif ISA = $(subst i386,i486,$(shell isainfo -n)) @@ -86,18 +87,24 @@ ISA = $(subst i386,i486,$(shell isainfo -n)) ifneq ("${ISA}","${BUILDARCH}") XLIBJVM_DB = 64/$(LIBJVM_DB) +XLIBJVM_DB_G = 64/$(LIBJVM_DB_G) XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE) +XLIBJVM_DTRACE_G = 64/$(LIBJVM_DTRACE_G) $(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc + [ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); } + $(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor + [ -f $(XLIBJVM_DTRACE_G) ] || { ln -s $(LIBJVM_DTRACE) $(XLIBJVM_DTRACE_G); } + endif # ifneq ("${ISA}","${BUILDARCH}") ifdef USE_GCC @@ -142,11 +149,13 @@ $(LIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS.o) $(XLIBJVM_DB) $(LIBJVM_D @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc + [ -f $(LIBJVM_DB_G) ] || { ln -s $@ $(LIBJVM_DB_G); } $(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor + [ -f $(LIBJVM_DTRACE_G) ] || { ln -s $@ $(LIBJVM_DTRACE_G); } $(DTRACE).d: $(DTRACE_SRCDIR)/hotspot.d $(DTRACE_SRCDIR)/hotspot_jni.d \ $(DTRACE_SRCDIR)/hs_private.d $(DTRACE_SRCDIR)/jhelper.d diff --git a/hotspot/make/solaris/makefiles/fastdebug.make b/hotspot/make/solaris/makefiles/fastdebug.make index 084814d6758..4edeb373f9e 100644 --- a/hotspot/make/solaris/makefiles/fastdebug.make +++ b/hotspot/make/solaris/makefiles/fastdebug.make @@ -90,7 +90,6 @@ endif # Platform_compiler == sparcWorks # for this method for now. (fix this when dtrace bug 6258412 is fixed) OPT_CFLAGS/ciEnv.o = $(OPT_CFLAGS) -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_ - # (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files) # If you set HOTSPARC_GENERIC=yes, you disable all OPT_CFLAGS settings @@ -115,8 +114,7 @@ MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \ # and mustn't be otherwise. MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE) - -G_SUFFIX = +G_SUFFIX = _g VERSION = optimized SYSDEFS += -DASSERT -DFASTDEBUG -DCHECK_UNHANDLED_OOPS PICFLAGS = DEFAULT diff --git a/hotspot/make/solaris/makefiles/jsig.make b/hotspot/make/solaris/makefiles/jsig.make index e4a4aef771a..81497767202 100644 --- a/hotspot/make/solaris/makefiles/jsig.make +++ b/hotspot/make/solaris/makefiles/jsig.make @@ -25,8 +25,11 @@ # Rules to build signal interposition library, used by vm.make # libjsig[_g].so: signal interposition library -JSIG = jsig$(G_SUFFIX) -LIBJSIG = lib$(JSIG).so +JSIG = jsig +LIBJSIG = lib$(JSIG).so + +JSIG_G = $(JSIG)$(G_SUFFIX) +LIBJSIG_G = lib$(JSIG_G).so JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm @@ -46,6 +49,7 @@ $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ $(LFLAGS_JSIG) -o $@ $< -ldl + [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); } install_jsig: $(LIBJSIG) @echo "Copying $(LIBJSIG) to $(DEST_JSIG)" diff --git a/hotspot/make/solaris/makefiles/jvmg.make b/hotspot/make/solaris/makefiles/jvmg.make index e6603005fdd..160ea5df1d8 100644 --- a/hotspot/make/solaris/makefiles/jvmg.make +++ b/hotspot/make/solaris/makefiles/jvmg.make @@ -51,7 +51,7 @@ MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \ # and mustn't be otherwise. MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE) -G_SUFFIX = +G_SUFFIX = _g VERSION = debug SYSDEFS += -DASSERT -DDEBUG PICFLAGS = DEFAULT diff --git a/hotspot/make/solaris/makefiles/launcher.make b/hotspot/make/solaris/makefiles/launcher.make index 2224d58017d..bf32444c5c3 100644 --- a/hotspot/make/solaris/makefiles/launcher.make +++ b/hotspot/make/solaris/makefiles/launcher.make @@ -25,7 +25,8 @@ # Rules to build gamma launcher, used by vm.make # gamma[_g]: launcher -LAUNCHER = gamma$(G_SUFFIX) +LAUNCHER = gamma +LAUNCHER_G = $(LAUNCHER)$(G_SUFFIX) LAUNCHERDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/launcher LAUNCHERFLAGS = $(ARCHFLAG) \ @@ -88,5 +89,6 @@ $(LAUNCHER): $(LAUNCHER.o) $(LIBJVM) $(LAUNCHER_MAPFILE) $(LINK_LAUNCHER/PRE_HOOK) \ $(LINK_LAUNCHER) $(LFLAGS_LAUNCHER) -o $@ $(LAUNCHER.o) $(LIBS_LAUNCHER); \ $(LINK_LAUNCHER/POST_HOOK) \ + [ -f $(LAUNCHER_G) ] || { ln -s $@ $(LAUNCHER_G); }; \ ;; \ esac diff --git a/hotspot/make/solaris/makefiles/saproc.make b/hotspot/make/solaris/makefiles/saproc.make index 906cd9d998e..38751e8f1bf 100644 --- a/hotspot/make/solaris/makefiles/saproc.make +++ b/hotspot/make/solaris/makefiles/saproc.make @@ -25,9 +25,13 @@ # Rules to build serviceability agent library, used by vm.make # libsaproc[_g].so: serviceability agent -SAPROC = saproc$(G_SUFFIX) + +SAPROC = saproc LIBSAPROC = lib$(SAPROC).so +SAPROC_G = $(SAPROC)$(G_SUFFIX) +LIBSAPROC_G = lib$(SAPROC_G).so + AGENT_DIR = $(GAMMADIR)/agent SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)/proc @@ -69,6 +73,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) $(SA_LFLAGS) \ -o $@ \ -ldl -ldemangle -lthread -lc + [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); } install_saproc: checkAndBuildSA $(QUIETLY) if [ -f $(LIBSAPROC) ] ; then \ diff --git a/hotspot/make/solaris/makefiles/sparcWorks.make b/hotspot/make/solaris/makefiles/sparcWorks.make index d1648383857..acab5192183 100644 --- a/hotspot/make/solaris/makefiles/sparcWorks.make +++ b/hotspot/make/solaris/makefiles/sparcWorks.make @@ -281,8 +281,6 @@ else OPT_CFLAGS=-xO4 $(EXTRA_OPT_CFLAGS) endif -CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_sparc/vm/solaris_sparc.il - endif # sparc ifeq ("${Platform_arch_model}", "x86_32") @@ -293,13 +291,14 @@ OPT_CFLAGS=-xtarget=pentium $(EXTRA_OPT_CFLAGS) # [phh] Is this still true for 6.1? OPT_CFLAGS+=-xO3 -CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_x86/vm/solaris_x86_32.il - endif # 32bit x86 # no more exceptions CFLAGS/NOEX=-noex +# Inline functions +CFLAGS += $(GAMMADIR)/src/os_cpu/solaris_${Platform_arch}/vm/solaris_${Platform_arch_model}.il + # Reduce code bloat by reverting back to 5.0 behavior for static initializers CFLAGS += -Qoption ccfe -one_static_init @@ -312,6 +311,15 @@ PICFLAG/DEFAULT = $(PICFLAG) PICFLAG/BETTER = $(PICFLAG/DEFAULT) PICFLAG/BYFILE = $(PICFLAG/$@)$(PICFLAG/DEFAULT$(PICFLAG/$@)) +# Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file. +MAPFLAG = -M FILENAME + +# Use $(SONAMEFLAG:SONAME=soname) to specify the intrinsic name of a shared obj +SONAMEFLAG = -h SONAME + +# Build shared library +SHARED_FLAG = -G + # Would be better if these weren't needed, since we link with CC, but # at present removing them causes run-time errors LFLAGS += -library=Crun diff --git a/hotspot/make/solaris/makefiles/vm.make b/hotspot/make/solaris/makefiles/vm.make index 32850b18bbd..058bb6bd7e4 100644 --- a/hotspot/make/solaris/makefiles/vm.make +++ b/hotspot/make/solaris/makefiles/vm.make @@ -108,11 +108,16 @@ ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1) # older libm before libCrun, just to make sure it's found and used first. LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc else +ifeq ($(COMPILER_REV_NUMERIC), 502) +# SC6.1 has it's own libm.so: specifying anything else provokes a name conflict. +LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor +else LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor -endif +endif # 502 +endif # 505 else LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -endif +endif # sparcWorks # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM @@ -126,8 +131,9 @@ include $(MAKEFILES_DIR)/dtrace.make #---------------------------------------------------------------------- # JVM -JVM = jvm$(G_SUFFIX) -LIBJVM = lib$(JVM).so +JVM = jvm +LIBJVM = lib$(JVM).so +LIBJVM_G = lib$(JVM)$(G_SUFFIX).so JVM_OBJ_FILES = $(Obj_Files) $(DTRACE_OBJS) @@ -173,11 +179,12 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) -sbfast|-xsbfast) \ ;; \ *) \ - echo Linking vm...; \ - $(LINK_LIB.CC/PRE_HOOK) \ - $(LINK_VM) $(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \ - $(LINK_LIB.CC/POST_HOOK) \ - rm -f $@.1; ln -s $@ $@.1; \ + echo Linking vm...; \ + $(LINK_LIB.CC/PRE_HOOK) \ + $(LINK_VM) $(LFLAGS_VM) -o $@ $(LIBJVM.o) $(LIBS_VM); \ + $(LINK_LIB.CC/POST_HOOK) \ + rm -f $@.1; ln -s $@ $@.1; \ + [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \ ;; \ esac diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 2583f7cee23..2b054b43e65 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -189,14 +189,17 @@ void LIR_Assembler::osr_entry() { Register OSR_buf = osrBufferPointer()->as_register(); { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); int monitor_offset = BytesPerWord * method()->max_locals() + - (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1); + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. for (int i = 0; i < number_of_locks; i++) { - int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord); + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); #ifdef ASSERT // verify the interpreter's monitor has a non-null object { Label L; - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); __ cmp(G0, O7); __ br(Assembler::notEqual, false, Assembler::pt, L); __ delayed()->nop(); @@ -205,9 +208,9 @@ void LIR_Assembler::osr_entry() { } #endif // ASSERT // Copy the lock field into the compiled activation. - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 0, O7); __ st_ptr(O7, frame_map()->address_for_monitor_lock(i)); - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); __ st_ptr(O7, frame_map()->address_for_monitor_object(i)); } } @@ -953,9 +956,11 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ } else { #ifdef _LP64 assert(base != to_reg->as_register_lo(), "can't handle this"); + assert(O7 != to_reg->as_register_lo(), "can't handle this"); __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_lo()); + __ lduw(base, offset + lo_word_offset_in_bytes, O7); // in case O7 is base or offset, use it last __ sllx(to_reg->as_register_lo(), 32, to_reg->as_register_lo()); - __ ld(base, offset + lo_word_offset_in_bytes, to_reg->as_register_lo()); + __ or3(to_reg->as_register_lo(), O7, to_reg->as_register_lo()); #else if (base == to_reg->as_register_lo()) { __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_hi()); @@ -976,8 +981,8 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ FloatRegister reg = to_reg->as_double_reg(); // split unaligned loads if (unaligned || PatchALot) { - __ ldf(FloatRegisterImpl::S, base, offset + BytesPerWord, reg->successor()); - __ ldf(FloatRegisterImpl::S, base, offset, reg); + __ ldf(FloatRegisterImpl::S, base, offset + 4, reg->successor()); + __ ldf(FloatRegisterImpl::S, base, offset, reg); } else { __ ldf(FloatRegisterImpl::D, base, offset, to_reg->as_double_reg()); } @@ -2200,6 +2205,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { Register len = O2; __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); + LP64_ONLY(__ sra(src_pos, 0, src_pos);) //higher 32bits must be null if (shift == 0) { __ add(src_ptr, src_pos, src_ptr); } else { @@ -2208,6 +2214,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { } __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); + LP64_ONLY(__ sra(dst_pos, 0, dst_pos);) //higher 32bits must be null if (shift == 0) { __ add(dst_ptr, dst_pos, dst_ptr); } else { diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index 2a69ade2156..87b47124352 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -144,17 +144,17 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, if (index->is_register()) { // apply the shift and accumulate the displacement if (shift > 0) { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); __ shift_left(index, shift, tmp); index = tmp; } if (disp != 0) { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); if (Assembler::is_simm13(disp)) { - __ add(tmp, LIR_OprFact::intConst(disp), tmp); + __ add(tmp, LIR_OprFact::intptrConst(disp), tmp); index = tmp; } else { - __ move(LIR_OprFact::intConst(disp), tmp); + __ move(LIR_OprFact::intptrConst(disp), tmp); __ add(tmp, index, tmp); index = tmp; } @@ -162,8 +162,8 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, } } else if (disp != 0 && !Assembler::is_simm13(disp)) { // index is illegal so replace it with the displacement loaded into a register - index = new_register(T_INT); - __ move(LIR_OprFact::intConst(disp), index); + index = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(disp), index); disp = 0; } diff --git a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp index cb2bab6ea93..d47f7ce41d5 100644 --- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the client compiler. // (see c1_globals.hpp) -// + #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); define_pd_global(bool, CICompileOSR, true ); @@ -48,27 +47,24 @@ define_pd_global(intx, OnStackReplacePercentage, 1400 ); define_pd_global(bool, UseTLAB, true ); define_pd_global(bool, ProfileInterpreter, false); define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(intx, NewRatio, 8 ); // Design center runs on 1.3.1 define_pd_global(bool, ResizeTLAB, true ); define_pd_global(intx, ReservedCodeCacheSize, 32*M ); define_pd_global(intx, CodeCacheExpansionSize, 32*K ); define_pd_global(uintx,CodeCacheMinBlockLength, 1); -define_pd_global(uintx, PermSize, 12*M ); -define_pd_global(uintx, MaxPermSize, 64*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true); +define_pd_global(uintx,PermSize, 12*M ); +define_pd_global(uintx,MaxPermSize, 64*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); define_pd_global(intx, NewSizeThreadIncrease, 16*K ); -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); define_pd_global(intx, InitialCodeCacheSize, 160*K); -#endif // TIERED +#endif // !TIERED define_pd_global(bool, UseTypeProfile, false); define_pd_global(bool, RoundFPResults, false); - -define_pd_global(bool, LIRFillDelaySlots, true); +define_pd_global(bool, LIRFillDelaySlots, true ); define_pd_global(bool, OptimizeSinglePrecision, false); -define_pd_global(bool, CSEArrayLength, true); +define_pd_global(bool, CSEArrayLength, true ); define_pd_global(bool, TwoOperandLIRForm, false); - -define_pd_global(intx, SafepointPollOffset, 0); +define_pd_global(intx, SafepointPollOffset, 0 ); diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 92f69be26bb..2df4dbd8ede 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -59,7 +59,6 @@ define_pd_global(intx, FLOATPRESSURE, 52); // C2 on V9 gets to u define_pd_global(intx, FreqInlineSize, 175); define_pd_global(intx, INTPRESSURE, 48); // large register set define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment -define_pd_global(intx, NewRatio, 2); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); // The default setting 16/16 seems to work best. // (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.) @@ -83,25 +82,25 @@ define_pd_global(bool, OptoScheduling, true); // sequence of instructions to load a 64 bit pointer. // // InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(intx, ReservedCodeCacheSize, 48*M); -define_pd_global(intx, CodeCacheExpansionSize, 64*K); +define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize +define_pd_global(intx, ReservedCodeCacheSize, 48*M); +define_pd_global(intx, CodeCacheExpansionSize, 64*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 32*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); #else // InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(intx, ReservedCodeCacheSize, 32*M); -define_pd_global(intx, CodeCacheExpansionSize, 32*K); +define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize +define_pd_global(intx, ReservedCodeCacheSize, 32*M); +define_pd_global(intx, CodeCacheExpansionSize, 32*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 4ULL*G); #endif -define_pd_global(uintx,CodeCacheMinBlockLength, 4); +define_pd_global(uintx,CodeCacheMinBlockLength, 4); // Heap related flags -define_pd_global(uintx, PermSize, ScaleForWordSize(16*M)); -define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M)); +define_pd_global(uintx,PermSize, ScaleForWordSize(16*M)); +define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M)); // Ergonomics related flags define_pd_global(bool, NeverActAsServerClassMachine, false); diff --git a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp index ff28c96cfc7..e115ef2a9e0 100644 --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp @@ -22,10 +22,8 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// // For sparc we do not do call backs when a thread is in the interpreter, because the // interpreter dispatch needs at least two instructions - first to load the dispatch address @@ -41,26 +39,23 @@ define_pd_global(bool, NeedsDeoptSuspend, true); // register window ma define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast -define_pd_global(intx, CodeEntryAlignment, 32); -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); +define_pd_global(intx, CodeEntryAlignment, 32); +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); -define_pd_global(intx, VMThreadStackSize, 1024); +define_pd_global(intx, ThreadStackSize, 1024); +define_pd_global(intx, VMThreadStackSize, 1024); #else -define_pd_global(intx, ThreadStackSize, 512); -define_pd_global(intx, VMThreadStackSize, 512); +define_pd_global(intx, ThreadStackSize, 512); +define_pd_global(intx, VMThreadStackSize, 512); #endif define_pd_global(intx, StackYellowPages, 2); define_pd_global(intx, StackRedPages, 1); define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); -define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center +define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp index 9f0dd7166fd..d68d2b7702c 100644 --- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -394,6 +394,11 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter: } +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + // No special entry points that preclude compilation + return true; +} + // This method tells the deoptimizer how big an interpreted frame must be: int AbstractInterpreter::size_activation(methodOop method, int tempcount, diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 2c56575e09f..73e94021152 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1,5 +1,5 @@ // -// Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -1885,6 +1885,10 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } +const RegMask Matcher::method_handle_invoke_SP_save_mask() { + return RegMask(); +} + %} @@ -6664,7 +6668,7 @@ instruct cmovII_imm(cmpOp cmp, flagsReg icc, iRegI dst, immI11 src) %{ ins_pipe(ialu_imm); %} -instruct cmovII_U_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{ +instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{ match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); ins_cost(150); size(4); @@ -6673,7 +6677,7 @@ instruct cmovII_U_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{ ins_pipe(ialu_reg); %} -instruct cmovII_U_imm(cmpOpU cmp, flagsRegU icc, iRegI dst, immI11 src) %{ +instruct cmovIIu_imm(cmpOpU cmp, flagsRegU icc, iRegI dst, immI11 src) %{ match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); ins_cost(140); size(4); @@ -6719,6 +6723,16 @@ instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{ ins_pipe(ialu_reg); %} +// This instruction also works with CmpN so we don't need cmovNN_reg. +instruct cmovNIu_reg(cmpOpU cmp, flagsRegU icc, iRegN dst, iRegN src) %{ + match(Set dst (CMoveN (Binary cmp icc) (Binary dst src))); + ins_cost(150); + size(4); + format %{ "MOV$cmp $icc,$src,$dst" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(ialu_reg); +%} + instruct cmovNF_reg(cmpOpF cmp, flagsRegF fcc, iRegN dst, iRegN src) %{ match(Set dst (CMoveN (Binary cmp fcc) (Binary dst src))); ins_cost(150); @@ -6756,6 +6770,16 @@ instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{ ins_pipe(ialu_reg); %} +instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); + ins_cost(150); + + size(4); + format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(ialu_reg); +%} + instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{ match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); ins_cost(140); @@ -6766,6 +6790,16 @@ instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{ ins_pipe(ialu_imm); %} +instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{ + match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); + ins_cost(140); + + size(4); + format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} + ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(ialu_imm); +%} + instruct cmovPF_reg(cmpOpF cmp, flagsRegF fcc, iRegP dst, iRegP src) %{ match(Set dst (CMoveP (Binary cmp fcc) (Binary dst src))); ins_cost(150); @@ -6805,6 +6839,17 @@ instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{ ins_pipe(int_conditional_float_move); %} +instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{ + match(Set dst (CMoveF (Binary cmp icc) (Binary dst src))); + ins_cost(150); + + size(4); + format %{ "FMOVS$cmp $icc,$src,$dst" %} + opcode(0x101); + ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(int_conditional_float_move); +%} + // Conditional move, instruct cmovFF_reg(cmpOpF cmp, flagsRegF fcc, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp fcc) (Binary dst src))); @@ -6838,6 +6883,17 @@ instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{ ins_pipe(int_conditional_double_move); %} +instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{ + match(Set dst (CMoveD (Binary cmp icc) (Binary dst src))); + ins_cost(150); + + size(4); + format %{ "FMOVD$cmp $icc,$src,$dst" %} + opcode(0x102); + ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(int_conditional_double_move); +%} + // Conditional move, instruct cmovDF_reg(cmpOpF cmp, flagsRegF fcc, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cmp fcc) (Binary dst src))); @@ -6877,6 +6933,17 @@ instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{ %} +instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{ + match(Set dst (CMoveL (Binary cmp icc) (Binary dst src))); + ins_cost(150); + + size(4); + format %{ "MOV$cmp $icc,$src,$dst\t! long" %} + ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); + ins_pipe(ialu_reg); +%} + + instruct cmovLF_reg(cmpOpF cmp, flagsRegF fcc, iRegL dst, iRegL src) %{ match(Set dst (CMoveL (Binary cmp fcc) (Binary dst src))); ins_cost(150); diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index a2dc1501462..66c5a218dcc 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2862,6 +2862,9 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); + + // Don't initialize the platform math functions since sparc + // doesn't have intrinsics for these operations. } diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index b83ed82cf13..ada795d7ea1 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -150,8 +150,7 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { } -address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) { - assert(!unbox, "NYI");//6815692// +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) { address compiled_entry = __ pc(); Label cont; diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index aa93bc8f23c..c22a8c1d01a 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2251,6 +2251,7 @@ void Assembler::popf() { emit_byte(0x9D); } +#ifndef _LP64 // no 32bit push/pop on amd64 void Assembler::popl(Address dst) { // NOTE: this will adjust stack by 8byte on 64bits InstructionMark im(this); @@ -2258,6 +2259,7 @@ void Assembler::popl(Address dst) { emit_byte(0x8F); emit_operand(rax, dst); } +#endif void Assembler::prefetch_prefix(Address src) { prefix(src); @@ -2428,6 +2430,7 @@ void Assembler::pushf() { emit_byte(0x9C); } +#ifndef _LP64 // no 32bit push/pop on amd64 void Assembler::pushl(Address src) { // Note this will push 64bit on 64bit InstructionMark im(this); @@ -2435,6 +2438,7 @@ void Assembler::pushl(Address src) { emit_byte(0xFF); emit_operand(rsi, src); } +#endif void Assembler::pxor(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -5591,7 +5595,12 @@ void MacroAssembler::align(int modulus) { } void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src) { - andpd(dst, as_Address(src)); + if (reachable(src)) { + andpd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + andpd(dst, Address(rscratch1, 0)); + } } void MacroAssembler::andptr(Register dst, int32_t imm32) { @@ -6078,11 +6087,21 @@ void MacroAssembler::cmpxchgptr(Register reg, Address adr) { } void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src) { - comisd(dst, as_Address(src)); + if (reachable(src)) { + comisd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + comisd(dst, Address(rscratch1, 0)); + } } void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src) { - comiss(dst, as_Address(src)); + if (reachable(src)) { + comiss(dst, as_Address(src)); + } else { + lea(rscratch1, src); + comiss(dst, Address(rscratch1, 0)); + } } @@ -7647,7 +7666,7 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad #ifdef ASSERT Label L; - testl(tmp, tmp); + testptr(tmp, tmp); jccb(Assembler::notZero, L); hlt(); bind(L); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 7aa0d0877a4..f44ae2dde48 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1244,7 +1244,9 @@ private: void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); void pcmpestri(XMMRegister xmm1, Address src, int imm8); +#ifndef _LP64 // no 32bit push/pop on amd64 void popl(Address dst); +#endif #ifdef _LP64 void popq(Address dst); @@ -1285,7 +1287,9 @@ private: // Interleave Low Bytes void punpcklbw(XMMRegister dst, XMMRegister src); +#ifndef _LP64 // no 32bit push/pop on amd64 void pushl(Address src); +#endif void pushq(Address src); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index f8cdb23ee82..2fae5406861 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -301,22 +301,25 @@ void LIR_Assembler::osr_entry() { Register OSR_buf = osrBufferPointer()->as_pointer_register(); { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); int monitor_offset = BytesPerWord * method()->max_locals() + - (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1); + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. for (int i = 0; i < number_of_locks; i++) { - int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord); + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); #ifdef ASSERT // verify the interpreter's monitor has a non-null object { Label L; - __ cmpptr(Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); + __ cmpptr(Address(OSR_buf, slot_offset + 1*BytesPerWord), (int32_t)NULL_WORD); __ jcc(Assembler::notZero, L); __ stop("locked object is NULL"); __ bind(L); } #endif - __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes())); + __ movptr(rbx, Address(OSR_buf, slot_offset + 0)); __ movptr(frame_map()->address_for_monitor_lock(i), rbx); - __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes())); + __ movptr(rbx, Address(OSR_buf, slot_offset + 1*BytesPerWord)); __ movptr(frame_map()->address_for_monitor_object(i), rbx); } } @@ -785,7 +788,13 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi ShouldNotReachHere(); __ movoop(as_Address(addr, noreg), c->as_jobject()); } else { +#ifdef _LP64 + __ movoop(rscratch1, c->as_jobject()); + null_check_here = code_offset(); + __ movptr(as_Address_lo(addr), rscratch1); +#else __ movoop(as_Address(addr), c->as_jobject()); +#endif } } break; @@ -1118,8 +1127,14 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { __ pushptr(frame_map()->address_for_slot(src ->single_stack_ix())); __ popptr (frame_map()->address_for_slot(dest->single_stack_ix())); } else { +#ifndef _LP64 __ pushl(frame_map()->address_for_slot(src ->single_stack_ix())); __ popl (frame_map()->address_for_slot(dest->single_stack_ix())); +#else + //no pushl on 64bits + __ movl(rscratch1, frame_map()->address_for_slot(src ->single_stack_ix())); + __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), rscratch1); +#endif } } else if (src->is_double_stack()) { @@ -3136,8 +3151,10 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { #ifdef _LP64 assert_different_registers(c_rarg0, dst, dst_pos, length); + __ movl2ptr(src_pos, src_pos); //higher 32bits must be null __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); assert_different_registers(c_rarg1, length); + __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); __ mov(c_rarg2, length); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 2e2c1364717..f98bfaa8ea3 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -755,8 +755,19 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { } LIR_Opr addr = new_pointer_register(); - __ move(obj.result(), addr); - __ add(addr, offset.result(), addr); + LIR_Address* a; + if(offset.result()->is_constant()) { + a = new LIR_Address(obj.result(), + NOT_LP64(offset.result()->as_constant_ptr()->as_jint()) LP64_ONLY((int)offset.result()->as_constant_ptr()->as_jlong()), + as_BasicType(type)); + } else { + a = new LIR_Address(obj.result(), + offset.result(), + LIR_Address::times_1, + 0, + as_BasicType(type)); + } + __ leal(LIR_OprFact::address(a), addr); if (type == objectType) { // Write-barrier needed for Object fields. // Do the pre-write barrier, if any. diff --git a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp index 659dcca4732..bbf96cba1f2 100644 --- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp @@ -22,10 +22,8 @@ * */ -// // Sets the default values for platform dependent flags used by the client compiler. // (see c1_globals.hpp) -// #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); @@ -48,27 +46,24 @@ define_pd_global(intx, Tier4BackEdgeThreshold, 100000); define_pd_global(intx, OnStackReplacePercentage, 933 ); define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(intx, NewRatio, 12 ); define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(intx, InitialCodeCacheSize, 160*K); define_pd_global(intx, ReservedCodeCacheSize, 32*M ); define_pd_global(bool, ProfileInterpreter, false); define_pd_global(intx, CodeCacheExpansionSize, 32*K ); define_pd_global(uintx,CodeCacheMinBlockLength, 1); -define_pd_global(uintx, PermSize, 12*M ); -define_pd_global(uintx, MaxPermSize, 64*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true); -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uintx,PermSize, 12*M ); +define_pd_global(uintx,MaxPermSize, 64*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); define_pd_global(bool, CICompileOSR, true ); -#endif // TIERED +#endif // !TIERED define_pd_global(bool, UseTypeProfile, false); define_pd_global(bool, RoundFPResults, true ); - define_pd_global(bool, LIRFillDelaySlots, false); -define_pd_global(bool, OptimizeSinglePrecision, true); +define_pd_global(bool, OptimizeSinglePrecision, true ); define_pd_global(bool, CSEArrayLength, false); -define_pd_global(bool, TwoOperandLIRForm, true); +define_pd_global(bool, TwoOperandLIRForm, true ); - -define_pd_global(intx, SafepointPollOffset, 256); +define_pd_global(intx, SafepointPollOffset, 256 ); diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index 6b3d7250442..b299e5a5480 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -22,7 +22,6 @@ * */ -// // Sets the default values for platform dependent flags used by the server compiler. // (see c2_globals.hpp). Alpha-sorted. @@ -46,8 +45,8 @@ define_pd_global(intx, CompileThreshold, 1000); define_pd_global(intx, CompileThreshold, 10000); #endif // TIERED define_pd_global(intx, Tier2CompileThreshold, 10000); -define_pd_global(intx, Tier3CompileThreshold, 20000 ); -define_pd_global(intx, Tier4CompileThreshold, 40000 ); +define_pd_global(intx, Tier3CompileThreshold, 20000); +define_pd_global(intx, Tier4CompileThreshold, 40000); define_pd_global(intx, BackEdgeThreshold, 100000); define_pd_global(intx, Tier2BackEdgeThreshold, 100000); @@ -61,7 +60,6 @@ define_pd_global(intx, FreqInlineSize, 325); #ifdef AMD64 define_pd_global(intx, INTPRESSURE, 13); define_pd_global(intx, InteriorEntryAlignment, 16); -define_pd_global(intx, NewRatio, 2); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); // InitialCodeCacheSize derived from specjbb2000 run. @@ -69,19 +67,18 @@ define_pd_global(intx, InitialCodeCacheSize, 2496*K); // Integral multip define_pd_global(intx, CodeCacheExpansionSize, 64*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 32*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); #else define_pd_global(intx, INTPRESSURE, 6); define_pd_global(intx, InteriorEntryAlignment, 4); -define_pd_global(intx, NewRatio, 8); // Design center runs on 1.3.1 define_pd_global(intx, NewSizeThreadIncrease, 4*K); -define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 +define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 // InitialCodeCacheSize derived from specjbb2000 run. define_pd_global(intx, InitialCodeCacheSize, 2304*K); // Integral multiple of CodeCacheExpansionSize define_pd_global(intx, CodeCacheExpansionSize, 32*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 4ULL*G); #endif // AMD64 define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, RegisterCostAreaRatio, 16000); @@ -97,8 +94,8 @@ define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(uintx,CodeCacheMinBlockLength, 4); // Heap related flags -define_pd_global(uintx, PermSize, ScaleForWordSize(16*M)); -define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M)); +define_pd_global(uintx,PermSize, ScaleForWordSize(16*M)); +define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M)); // Ergonomics related flags define_pd_global(bool, NeverActAsServerClassMachine, false); diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 8ec4ba76295..7bbd7311dfa 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -330,6 +330,14 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); + address sender_pc = this->sender_pc(); + CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc); + assert(sender_cb, "sanity"); + nmethod* sender_nm = sender_cb->as_nmethod_or_null(); + if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) { + unextended_sp = (intptr_t*) at(link_offset); + } + // The interpreter and compiler(s) always save EBP/RBP in a known // location on entry. We must record where that location is // so this if EBP/RBP was live on callout from c2 we can find @@ -352,7 +360,7 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { #endif // AMD64 } #endif /* COMPILER2 */ - return frame(sp, unextended_sp, link(), sender_pc()); + return frame(sp, unextended_sp, link(), sender_pc); } @@ -375,6 +383,18 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); + intptr_t* unextended_sp = sender_sp; + // If we are returning to a compiled method handle call site, + // the saved_fp will in fact be a saved value of the unextended SP. + // The simplest way to tell whether we are returning to such a call + // site is as follows: + CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc); + assert(sender_cb, "sanity"); + nmethod* sender_nm = sender_cb->as_nmethod_or_null(); + if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) { + unextended_sp = saved_fp; + } + if (map->update_map()) { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag @@ -399,7 +419,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { } assert(sender_sp != sp(), "must have changed"); - return frame(sender_sp, saved_fp, sender_pc); + return frame(sender_sp, unextended_sp, saved_fp, sender_pc); } frame frame::sender(RegisterMap* map) const { diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index c3bfdae6d01..1f2065ba449 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -225,11 +225,12 @@ inline methodOop* frame::interpreter_frame_method_addr() const { // top of expression stack inline intptr_t* frame::interpreter_frame_tos_address() const { intptr_t* last_sp = interpreter_frame_last_sp(); - if (last_sp == NULL ) { + if (last_sp == NULL) { return sp(); } else { - // sp() may have been extended by an adapter - assert(last_sp < fp() && last_sp >= sp(), "bad tos"); + // sp() may have been extended or shrunk by an adapter. At least + // check that we don't fall behind the legal region. + assert(last_sp < (intptr_t*) interpreter_frame_monitor_begin(), "bad tos"); return last_sp; } } diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index f5586c1ee56..764e7ef284a 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -22,17 +22,16 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// -define_pd_global(bool, ConvertSleepToYield, true); -define_pd_global(bool, ShareVtableStubs, true); -define_pd_global(bool, CountInterpCalls, true); +define_pd_global(bool, ConvertSleepToYield, true); +define_pd_global(bool, ShareVtableStubs, true); +define_pd_global(bool, CountInterpCalls, true); +define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this -define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks -define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast +define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks +define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast // See 4827828 for this change. There is no globals_core_i486.hpp. I can't // assign a different value for C2 without touching a number of files. Use @@ -42,29 +41,24 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NUL // the uep and the vep doesn't get real alignment but just slops on by // only assured that the entry instruction meets the 5 byte size requirement. #ifdef COMPILER2 -define_pd_global(intx, CodeEntryAlignment, 32); +define_pd_global(intx, CodeEntryAlignment, 32); #else -define_pd_global(intx, CodeEntryAlignment, 16); +define_pd_global(intx, CodeEntryAlignment, 16); #endif // COMPILER2 +define_pd_global(intx, InlineFrequencyCount, 100); +define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this - -define_pd_global(uintx, TLABSize, 0); +define_pd_global(intx, StackYellowPages, 2); +define_pd_global(intx, StackRedPages, 1); #ifdef AMD64 -define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K)); // Very large C++ stack frames using solaris-amd64 optimized builds // due to lack of optimization caused by C++ compiler bugs define_pd_global(intx, StackShadowPages, SOLARIS_ONLY(20) NOT_SOLARIS(6) DEBUG_ONLY(+2)); #else -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); -define_pd_global(intx, StackRedPages, 1); +define_pd_global(intx, PreInflateSpin, 10); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); 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 e06e423a43a..a30092523a8 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -196,6 +196,9 @@ void InterpreterMacroAssembler::get_cache_index_at_bcp(Register reg, int bcp_off } else { assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic"); movl(reg, Address(rsi, bcp_offset)); + // Check if the secondary index definition is still ~x, otherwise + // we have to change the following assembler code to calculate the + // plain index. assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); notl(reg); // convert to plain index } 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 ad449c8bdd2..9418540dc09 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -185,12 +185,30 @@ void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp( } +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, + int bcp_offset, + bool giant_index) { + assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + if (!giant_index) { + load_unsigned_short(index, Address(r13, bcp_offset)); + } else { + assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic"); + movl(index, Address(r13, bcp_offset)); + // Check if the secondary index definition is still ~x, otherwise + // we have to change the following assembler code to calculate the + // plain index. + assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); + notl(index); // convert to plain index + } +} + + 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"); + int bcp_offset, + bool giant_index) { assert(cache != index, "must use different registers"); - load_unsigned_short(index, Address(r13, bcp_offset)); + get_cache_index_at_bcp(index, bcp_offset, giant_index); 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 @@ -200,10 +218,10 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, 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"); + int bcp_offset, + bool giant_index) { assert(cache != tmp, "must use different register"); - load_unsigned_short(tmp, Address(r13, bcp_offset)); + get_cache_index_at_bcp(tmp, bcp_offset, giant_index); assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); // convert from field index to ConstantPoolCacheEntry index // and from word offset to byte offset @@ -1236,7 +1254,8 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp, - Register reg2) { + Register reg2, + bool receiver_can_be_null) { if (ProfileInterpreter) { Label profile_continue; @@ -1246,8 +1265,15 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, // We are making a call. Increment the count. increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + Label skip_receiver_profile; + if (receiver_can_be_null) { + testptr(receiver, receiver); + jcc(Assembler::zero, skip_receiver_profile); + } + // Record the receiver type. record_klass_in_profile(receiver, mdp, reg2); + bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(mdp, diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp index c35cb3a1940..0cfc9bf7fb8 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -95,9 +95,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); void get_cache_and_index_at_bcp(Register cache, Register index, - int bcp_offset); + int bcp_offset, bool giant_index = false); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, - int bcp_offset); + int bcp_offset, bool giant_index = false); + void get_cache_index_at_bcp(Register index, int bcp_offset, bool giant_index = false); void pop_ptr(Register r = rax); @@ -236,7 +237,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, - Register scratch2); + Register scratch2, + bool receiver_can_be_null = false); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp index c3cbf56cab8..6c234a33a18 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp @@ -277,12 +277,11 @@ address InterpreterGenerator::generate_abstract_entry(void) { address entry_point = __ pc(); // abstract method entry - // remove return address. Not really needed, since exception - // handling throws away expression stack - __ pop(rbx); - // adjust stack to what a normal return would do - __ mov(rsp, r13); + // pop return address, reset last_sp to NULL + __ empty_expression_stack(); + __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) // throw exception __ call_VM(noreg, CAST_FROM_FN_PTR(address, @@ -300,7 +299,10 @@ address InterpreterGenerator::generate_method_handle_entry(void) { if (!EnableMethodHandles) { return generate_abstract_entry(); } - return generate_abstract_entry(); //6815692// + + address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm); + + return entry_point; } diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index a682a81b833..fc11240e030 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -65,9 +65,9 @@ static void verify_argslot(MacroAssembler* _masm, Register rax_argslot, // Verify that argslot lies within (rsp, rbp]. Label L_ok, L_bad; __ cmpptr(rax_argslot, rbp); - __ jcc(Assembler::above, L_bad); + __ jccb(Assembler::above, L_bad); __ cmpptr(rsp, rax_argslot); - __ jcc(Assembler::below, L_ok); + __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop(error_message); __ bind(L_ok); @@ -136,9 +136,9 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm, if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); - __ jcc(Assembler::greater, L_bad); + __ jccb(Assembler::greater, L_bad); __ testl(arg_slots.as_register(), -stack_move_unit() - 1); - __ jcc(Assembler::zero, L_ok); + __ jccb(Assembler::zero, L_ok); __ bind(L_bad); __ stop("assert arg_slots <= 0 and clear low bits"); __ bind(L_ok); @@ -173,7 +173,7 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm, __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); __ addptr(rdx_temp, wordSize); __ cmpptr(rdx_temp, rax_argslot); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); } // Now move the argslot down, to point to the opened-up space. @@ -211,9 +211,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, Label L_ok, L_bad; __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); __ cmpptr(rbx_temp, rbp); - __ jcc(Assembler::above, L_bad); + __ jccb(Assembler::above, L_bad); __ cmpptr(rsp, rax_argslot); - __ jcc(Assembler::below, L_ok); + __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop("deleted argument(s) must fall within current frame"); __ bind(L_ok); @@ -221,9 +221,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); - __ jcc(Assembler::less, L_bad); + __ jccb(Assembler::less, L_bad); __ testl(arg_slots.as_register(), -stack_move_unit() - 1); - __ jcc(Assembler::zero, L_ok); + __ jccb(Assembler::zero, L_ok); __ bind(L_bad); __ stop("assert arg_slots >= 0 and clear low bits"); __ bind(L_ok); @@ -258,7 +258,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); __ addptr(rdx_temp, -wordSize); __ cmpptr(rdx_temp, rsp); - __ jcc(Assembler::greaterEqual, loop); + __ jccb(Assembler::greaterEqual, loop); } // Now move the argslot up, to point to the just-copied block. @@ -268,8 +268,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm, } #ifndef PRODUCT +extern "C" void print_method_handle(oop mh); void trace_method_handle_stub(const char* adaptername, - oopDesc* mh, + oop mh, intptr_t* entry_sp, intptr_t* saved_sp, intptr_t* saved_bp) { @@ -280,6 +281,7 @@ void trace_method_handle_stub(const char* adaptername, adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); if (last_sp != saved_sp) printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp); + if (Verbose) print_method_handle(mh); } #endif //PRODUCT @@ -382,11 +384,11 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // FIXME: fill in _raise_exception_method with a suitable sun.dyn method __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); __ testptr(rbx_method, rbx_method); - __ jcc(Assembler::zero, no_method); + __ jccb(Assembler::zero, no_method); int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject __ testptr(rbx_method, rbx_method); - __ jcc(Assembler::zero, no_method); + __ jccb(Assembler::zero, no_method); __ verify_oop(rbx_method); __ push(rdi_pc); // and restore caller PC __ jmp(rbx_method_fie); @@ -448,7 +450,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan rbx_index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes()); Register rbx_method = rbx_temp; - __ movl(rbx_method, vtable_entry_addr); + __ movptr(rbx_method, vtable_entry_addr); __ verify_oop(rbx_method); __ jmp(rbx_method_fie); @@ -533,16 +535,15 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan if (arg_type == T_OBJECT) { __ movptr(Address(rax_argslot, 0), rbx_temp); } else { - __ load_sized_value(rbx_temp, prim_value_addr, + __ load_sized_value(rdx_temp, prim_value_addr, type2aelembytes(arg_type), is_signed_subword_type(arg_type)); - __ movptr(Address(rax_argslot, 0), rbx_temp); + __ movptr(Address(rax_argslot, 0), rdx_temp); #ifndef _LP64 if (arg_slots == 2) { - __ movl(rbx_temp, prim_value_addr.plus_disp(wordSize)); - __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp); + __ movl(rdx_temp, prim_value_addr.plus_disp(wordSize)); + __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rdx_temp); } #endif //_LP64 - break; } if (direct_to_method) { @@ -584,7 +585,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan Label done; __ movptr(rdx_temp, vmarg); __ testl(rdx_temp, rdx_temp); - __ jcc(Assembler::zero, done); // no cast if null + __ jccb(Assembler::zero, done); // no cast if null __ load_klass(rdx_temp, rdx_temp); // live at this point: @@ -675,24 +676,24 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // (now we are done with the old MH) // original 32-bit vmdata word must be of this form: - // | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | - __ xchgl(rcx, rbx_vminfo); // free rcx for shifts + // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | + __ xchgptr(rcx, rbx_vminfo); // free rcx for shifts __ shll(rdx_temp /*, rcx*/); Label zero_extend, done; __ testl(rcx, CONV_VMINFO_SIGN_FLAG); - __ jcc(Assembler::zero, zero_extend); + __ jccb(Assembler::zero, zero_extend); // this path is taken for int->byte, int->short __ sarl(rdx_temp /*, rcx*/); - __ jmp(done); + __ jmpb(done); __ bind(zero_extend); // this is taken for int->char __ shrl(rdx_temp /*, rcx*/); __ bind(done); - __ movptr(vmarg, rdx_temp); - __ xchgl(rcx, rbx_vminfo); // restore rcx_recv + __ movl(vmarg, rdx_temp); + __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } @@ -861,7 +862,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // Verify that argslot > destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::aboveEqual, L_ok); + __ jccb(Assembler::aboveEqual, L_ok); __ stop("source must be above destination (upward rotation)"); __ bind(L_ok); } @@ -877,7 +878,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ movptr(Address(rax_argslot, swap_bytes), rdx_temp); __ addptr(rax_argslot, -wordSize); __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::aboveEqual, loop); + __ jccb(Assembler::aboveEqual, loop); } else { __ addptr(rax_argslot, swap_bytes); #ifdef ASSERT @@ -885,7 +886,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // Verify that argslot < destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::belowEqual, L_ok); + __ jccb(Assembler::belowEqual, L_ok); __ stop("source must be below destination (downward rotation)"); __ bind(L_ok); } @@ -901,7 +902,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp); __ addptr(rax_argslot, wordSize); __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::belowEqual, loop); + __ jccb(Assembler::belowEqual, loop); } // pop the original first chunk into the destination slot, now free @@ -967,7 +968,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ addptr(rax_argslot, wordSize); __ addptr(rdx_newarg, wordSize); __ cmpptr(rdx_newarg, rbx_oldarg); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); __ pop(rdi); // restore temp @@ -1119,7 +1120,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan } __ addptr(rax_argslot, Interpreter::stackElementSize()); __ cmpptr(rax_argslot, rdx_argslot_limit); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); } else if (length_constant == 0) { __ bind(skip_array_check); // nothing to copy diff --git a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp index 5a0de22f475..428d239d494 100644 --- a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp @@ -43,11 +43,11 @@ ExceptionBlob* OptoRuntime::_exception_blob; // This code is entered with a jmp. // // Arguments: -// rax,: exception oop +// rax: exception oop // rdx: exception pc // // Results: -// rax,: exception oop +// rax: exception oop // rdx: exception pc in caller or ??? // destination: exception handler of caller // @@ -113,17 +113,17 @@ void OptoRuntime::generate_exception_blob() { __ addptr(rsp, return_off * wordSize); // Epilog! __ pop(rdx); // Exception pc + // rax: exception handler for given - // rax,: exception handler for given + // Restore SP from BP if the exception PC is a MethodHandle call. + __ cmpl(Address(rcx, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); // We have a handler in rax, (could be deopt blob) // rdx - throwing pc, deopt blob will need it. __ push(rax); - // rcx contains handler address - - __ get_thread(rcx); // TLS // Get the exception __ movptr(rax, Address(rcx, JavaThread::exception_oop_offset())); // Get the exception pc in case we are deoptimized @@ -137,7 +137,7 @@ void OptoRuntime::generate_exception_blob() { __ pop(rcx); - // rax,: exception oop + // rax: exception oop // rcx: exception handler // rdx: exception pc __ jmp (rcx); diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 68cb61979db..269f71d989f 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -638,6 +638,10 @@ static void gen_i2c_adapter(MacroAssembler *masm, __ movptr(rax, Address(rsp, 0)); + // Must preserve original SP for loading incoming arguments because + // we need to align the outgoing SP for compiled code. + __ movptr(r11, rsp); + // Cut-out for having no stack args. Since up to 2 int/oop args are passed // in registers, we will occasionally have no stack args. int comp_words_on_stack = 0; @@ -661,6 +665,10 @@ static void gen_i2c_adapter(MacroAssembler *masm, // as far as the placement of the call instruction __ push(rax); + // Put saved SP in another register + const Register saved_sp = rax; + __ movptr(saved_sp, r11); + // Will jump to the compiled code just as if compiled code was doing it. // Pre-load the register-jump target early, to schedule it better. __ movptr(r11, Address(rbx, in_bytes(methodOopDesc::from_compiled_offset()))); @@ -680,11 +688,7 @@ static void gen_i2c_adapter(MacroAssembler *masm, assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "scrambled load targets?"); // Load in argument order going down. - // int ld_off = (total_args_passed + comp_words_on_stack -i)*wordSize; - // base ld_off on r13 (sender_sp) as the stack alignment makes offsets from rsp - // unpredictable - int ld_off = ((total_args_passed - 1) - i)*Interpreter::stackElementSize(); - + int ld_off = (total_args_passed - i)*Interpreter::stackElementSize() + Interpreter::value_offset_in_bytes(); // Point to interpreter value (vs. tag) int next_off = ld_off - Interpreter::stackElementSize(); // @@ -699,10 +703,14 @@ static void gen_i2c_adapter(MacroAssembler *masm, if (r_1->is_stack()) { // Convert stack slot to an SP offset (+ wordSize to account for return address ) int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size + wordSize; + + // We can use r13 as a temp here because compiled code doesn't need r13 as an input + // and if we end up going thru a c2i because of a miss a reasonable value of r13 + // will be generated. if (!r_2->is_valid()) { // sign extend??? - __ movl(rax, Address(r13, ld_off)); - __ movptr(Address(rsp, st_off), rax); + __ movl(r13, Address(saved_sp, ld_off)); + __ movptr(Address(rsp, st_off), r13); } else { // // We are using two optoregs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE @@ -715,9 +723,9 @@ static void gen_i2c_adapter(MacroAssembler *masm, // ld_off is MSW so get LSW const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? next_off : ld_off; - __ movq(rax, Address(r13, offset)); + __ movq(r13, Address(saved_sp, offset)); // st_off is LSW (i.e. reg.first()) - __ movq(Address(rsp, st_off), rax); + __ movq(Address(rsp, st_off), r13); } } else if (r_1->is_Register()) { // Register argument Register r = r_1->as_Register(); @@ -732,16 +740,16 @@ static void gen_i2c_adapter(MacroAssembler *masm, next_off : ld_off; // this can be a misaligned move - __ movq(r, Address(r13, offset)); + __ movq(r, Address(saved_sp, offset)); } else { // sign extend and use a full word? - __ movl(r, Address(r13, ld_off)); + __ movl(r, Address(saved_sp, ld_off)); } } else { if (!r_2->is_valid()) { - __ movflt(r_1->as_XMMRegister(), Address(r13, ld_off)); + __ movflt(r_1->as_XMMRegister(), Address(saved_sp, ld_off)); } else { - __ movdbl(r_1->as_XMMRegister(), Address(r13, next_off)); + __ movdbl(r_1->as_XMMRegister(), Address(saved_sp, next_off)); } } } @@ -3319,6 +3327,10 @@ void OptoRuntime::generate_exception_blob() { // rax: exception handler + // Restore SP from BP if the exception PC is a MethodHandle call. + __ cmpl(Address(r15_thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); + // We have a handler in rax (could be deopt blob). __ mov(r8, rax); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 3d6ca91a0ea..ad4b745ab42 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-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2030,6 +2030,54 @@ class StubGenerator: public StubCodeGenerator { entry_checkcast_arraycopy); } + void generate_math_stubs() { + { + StubCodeMark mark(this, "StubRoutines", "log"); + StubRoutines::_intrinsic_log = (double (*)(double)) __ pc(); + + __ fld_d(Address(rsp, 4)); + __ flog(); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "log10"); + StubRoutines::_intrinsic_log10 = (double (*)(double)) __ pc(); + + __ fld_d(Address(rsp, 4)); + __ flog10(); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "sin"); + StubRoutines::_intrinsic_sin = (double (*)(double)) __ pc(); + + __ fld_d(Address(rsp, 4)); + __ trigfunc('s'); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "cos"); + StubRoutines::_intrinsic_cos = (double (*)(double)) __ pc(); + + __ fld_d(Address(rsp, 4)); + __ trigfunc('c'); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "tan"); + StubRoutines::_intrinsic_tan = (double (*)(double)) __ pc(); + + __ fld_d(Address(rsp, 4)); + __ trigfunc('t'); + __ ret(0); + } + + // The intrinsic version of these seem to return the same value as + // the strict version. + StubRoutines::_intrinsic_exp = SharedRuntime::dexp; + StubRoutines::_intrinsic_pow = SharedRuntime::dpow; + } + public: // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since @@ -2228,6 +2276,8 @@ class StubGenerator: public StubCodeGenerator { MethodHandles::generate_method_handle_stub(_masm, ek); } } + + generate_math_stubs(); } diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 6b0731490fd..70620836653 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-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2731,6 +2731,79 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_oop_arraycopy = StubRoutines::_oop_arraycopy; } + void generate_math_stubs() { + { + StubCodeMark mark(this, "StubRoutines", "log"); + StubRoutines::_intrinsic_log = (double (*)(double)) __ pc(); + + __ subq(rsp, 8); + __ movdbl(Address(rsp, 0), xmm0); + __ fld_d(Address(rsp, 0)); + __ flog(); + __ fstp_d(Address(rsp, 0)); + __ movdbl(xmm0, Address(rsp, 0)); + __ addq(rsp, 8); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "log10"); + StubRoutines::_intrinsic_log10 = (double (*)(double)) __ pc(); + + __ subq(rsp, 8); + __ movdbl(Address(rsp, 0), xmm0); + __ fld_d(Address(rsp, 0)); + __ flog10(); + __ fstp_d(Address(rsp, 0)); + __ movdbl(xmm0, Address(rsp, 0)); + __ addq(rsp, 8); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "sin"); + StubRoutines::_intrinsic_sin = (double (*)(double)) __ pc(); + + __ subq(rsp, 8); + __ movdbl(Address(rsp, 0), xmm0); + __ fld_d(Address(rsp, 0)); + __ trigfunc('s'); + __ fstp_d(Address(rsp, 0)); + __ movdbl(xmm0, Address(rsp, 0)); + __ addq(rsp, 8); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "cos"); + StubRoutines::_intrinsic_cos = (double (*)(double)) __ pc(); + + __ subq(rsp, 8); + __ movdbl(Address(rsp, 0), xmm0); + __ fld_d(Address(rsp, 0)); + __ trigfunc('c'); + __ fstp_d(Address(rsp, 0)); + __ movdbl(xmm0, Address(rsp, 0)); + __ addq(rsp, 8); + __ ret(0); + } + { + StubCodeMark mark(this, "StubRoutines", "tan"); + StubRoutines::_intrinsic_tan = (double (*)(double)) __ pc(); + + __ subq(rsp, 8); + __ movdbl(Address(rsp, 0), xmm0); + __ fld_d(Address(rsp, 0)); + __ trigfunc('t'); + __ fstp_d(Address(rsp, 0)); + __ movdbl(xmm0, Address(rsp, 0)); + __ addq(rsp, 8); + __ ret(0); + } + + // The intrinsic version of these seem to return the same value as + // the strict version. + StubRoutines::_intrinsic_exp = SharedRuntime::dexp; + StubRoutines::_intrinsic_pow = SharedRuntime::dpow; + } + #undef __ #define __ masm-> @@ -2935,6 +3008,18 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); + + // generic method handle stubs + if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) { + for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; + ek < MethodHandles::_EK_LIMIT; + ek = MethodHandles::EntryKind(1 + (int)ek)) { + StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); + MethodHandles::generate_method_handle_stub(_masm, ek); + } + } + + generate_math_stubs(); } public: diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index b78f0e2a066..eecfb3fd114 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-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,15 +155,8 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) } -address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) { +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) { TosState incoming_state = state; - if (EnableInvokeDynamic) { - if (unbox) { - incoming_state = atos; - } - } else { - assert(!unbox, "old behavior"); - } Label interpreter_entry; address compiled_entry = __ pc(); @@ -216,46 +209,6 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, __ restore_bcp(); __ restore_locals(); - Label L_fail; - - if (unbox && state != atos) { - // cast and unbox - BasicType type = as_BasicType(state); - if (type == T_BYTE) type = T_BOOLEAN; // FIXME - KlassHandle boxk = SystemDictionaryHandles::box_klass(type); - __ mov32(rbx, ExternalAddress((address) boxk.raw_value())); - __ testl(rax, rax); - Label L_got_value, L_get_value; - // convert nulls to zeroes (avoid NPEs here) - if (!(type == T_FLOAT || type == T_DOUBLE)) { - // if rax already contains zero bits, forge ahead - __ jcc(Assembler::zero, L_got_value); - } else { - __ jcc(Assembler::notZero, L_get_value); - __ fldz(); - __ jmp(L_got_value); - } - __ bind(L_get_value); - __ cmp32(rbx, Address(rax, oopDesc::klass_offset_in_bytes())); - __ jcc(Assembler::notEqual, L_fail); - int offset = java_lang_boxing_object::value_offset_in_bytes(type); - // Cf. TemplateTable::getfield_or_static - switch (type) { - case T_BYTE: // fall through: - case T_BOOLEAN: __ load_signed_byte(rax, Address(rax, offset)); break; - case T_CHAR: __ load_unsigned_short(rax, Address(rax, offset)); break; - case T_SHORT: __ load_signed_short(rax, Address(rax, offset)); break; - case T_INT: __ movl(rax, Address(rax, offset)); break; - case T_FLOAT: __ fld_s(Address(rax, offset)); break; - case T_DOUBLE: __ fld_d(Address(rax, offset)); break; - // Access to java.lang.Double.value does not need to be atomic: - case T_LONG: { __ movl(rdx, Address(rax, offset + 4)); - __ movl(rax, Address(rax, offset + 0)); } break; - default: ShouldNotReachHere(); - } - __ bind(L_got_value); - } - Label L_got_cache, L_giant_index; if (EnableInvokeDynamic) { __ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic); @@ -263,32 +216,6 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, } __ get_cache_and_index_at_bcp(rbx, rcx, 1, false); __ bind(L_got_cache); - if (unbox && state == atos) { - // insert a casting conversion, to keep verifier sane - Label L_ok, L_ok_pops; - __ testl(rax, rax); - __ jcc(Assembler::zero, L_ok); - __ push(rax); // save the object to check - __ push(rbx); // save CP cache reference - __ movl(rdx, Address(rax, oopDesc::klass_offset_in_bytes())); - __ movl(rbx, Address(rbx, rcx, - Address::times_4, constantPoolCacheOopDesc::base_offset() + - ConstantPoolCacheEntry::f1_offset())); - __ movl(rbx, Address(rbx, __ delayed_value(sun_dyn_CallSiteImpl::type_offset_in_bytes, rcx))); - __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx))); - __ movl(rax, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx))); - __ check_klass_subtype(rdx, rax, rbx, L_ok_pops); - __ pop(rcx); // pop and discard CP cache - __ mov(rbx, rax); // target supertype into rbx for L_fail - __ pop(rax); // failed object into rax for L_fail - __ jmp(L_fail); - - __ bind(L_ok_pops); - // restore pushed temp regs: - __ pop(rbx); - __ pop(rax); - __ bind(L_ok); - } __ movl(rbx, Address(rbx, rcx, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::flags_offset())); @@ -301,14 +228,6 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, __ bind(L_giant_index); __ get_cache_and_index_at_bcp(rbx, rcx, 1, true); __ jmp(L_got_cache); - - if (unbox) { - __ bind(L_fail); - __ push(rbx); // missed klass (required) - __ push(rax); // bad object (actual) - __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry)); - __ call(rdx); - } } return entry; @@ -1512,6 +1431,23 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter: } +// These should never be compiled since the interpreter will prefer +// the compiled version to the intrinsic version. +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + switch (method_kind(m)) { + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : + return false; + default: + return true; + } +} + // How much stack a method activation needs in words. int AbstractInterpreter::size_top_interpreter_activation(methodOop method) { @@ -1569,7 +1505,10 @@ int AbstractInterpreter::layout_activation(methodOop method, if (interpreter_frame != NULL) { #ifdef ASSERT - assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); + if (!EnableMethodHandles) + // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? + // Probably, since deoptimization doesn't work yet. + assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)"); #endif diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 4f0c3c9f779..44225441635 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,21 +100,26 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() { return entry; } -// Arguments are: required type in rarg1, failing object (or NULL) in rarg2 +// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4. address TemplateInterpreterGenerator::generate_WrongMethodType_handler() { address entry = __ pc(); __ pop(c_rarg2); // failing object is at TOS __ pop(c_rarg1); // required type is at TOS+8 - // expression stack must be empty before entering the VM if an - // exception happened + __ verify_oop(c_rarg1); + __ verify_oop(c_rarg2); + + // Various method handle types use interpreter registers as temps. + __ restore_bcp(); + __ restore_locals(); + + // Expression stack must be empty before entering the VM for an exception. __ empty_expression_stack(); __ call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime:: - throw_WrongMethodTypeException), + InterpreterRuntime::throw_WrongMethodTypeException), // pass required type, failing object (or NULL) c_rarg1, c_rarg2); return entry; @@ -166,8 +171,7 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, - int step, bool unbox) { - assert(!unbox, "NYI");//6815692// + int step) { // amd64 doesn't need to do anything special about compiled returns // to the interpreter so the code that exists on x86 to place a sentinel @@ -183,15 +187,29 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, __ restore_bcp(); __ restore_locals(); - __ get_cache_and_index_at_bcp(rbx, rcx, 1); + Label L_got_cache, L_giant_index; + if (EnableInvokeDynamic) { + __ cmpb(Address(r13, 0), Bytecodes::_invokedynamic); + __ jcc(Assembler::equal, L_giant_index); + } + __ get_cache_and_index_at_bcp(rbx, rcx, 1, false); + __ bind(L_got_cache); __ movl(rbx, Address(rbx, rcx, - Address::times_8, + Address::times_ptr, in_bytes(constantPoolCacheOopDesc::base_offset()) + 3 * wordSize)); __ andl(rbx, 0xFF); if (TaggedStackInterpreter) __ shll(rbx, 1); // 2 slots per parameter. __ lea(rsp, Address(rsp, rbx, Address::times_8)); __ dispatch_next(state, step); + + // out of the main line of code... + if (EnableInvokeDynamic) { + __ bind(L_giant_index); + __ get_cache_and_index_at_bcp(rbx, rcx, 1, true); + __ jmp(L_got_cache); + } + return entry; } @@ -431,8 +449,12 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { __ addptr(rax, stack_base); __ subptr(rax, stack_size); + // Use the maximum number of pages we might bang. + const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : + (StackRedPages+StackYellowPages); + // add in the red and yellow zone sizes - __ addptr(rax, (StackRedPages + StackYellowPages) * page_size); + __ addptr(rax, max_pages * page_size); // check against the current stack bottom __ cmpptr(rsp, rax); @@ -1434,6 +1456,23 @@ address AbstractInterpreterGenerator::generate_method_entry( generate_normal_entry(synchronized); } +// These should never be compiled since the interpreter will prefer +// the compiled version to the intrinsic version. +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + switch (method_kind(m)) { + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : + return false; + default: + return true; + } +} + // How much stack a method activation needs in words. int AbstractInterpreter::size_top_interpreter_activation(methodOop method) { const int entry_size = frame::interpreter_frame_monitor_size(); @@ -1484,8 +1523,10 @@ int AbstractInterpreter::layout_activation(methodOop method, tempcount* Interpreter::stackElementWords() + popframe_extra_args; if (interpreter_frame != NULL) { #ifdef ASSERT - assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), - "Frame not properly walkable"); + if (!EnableMethodHandles) + // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? + // Probably, since deoptimization doesn't work yet. + assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)"); #endif diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index 50ae3190953..8959b341023 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -2890,9 +2890,6 @@ void TemplateTable::count_calls(Register method, Register temp) { void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) { - bool is_invdyn_bootstrap = (byte_no < 0); - if (is_invdyn_bootstrap) byte_no = -byte_no; - // determine flags Bytecodes::Code code = bytecode(); const bool is_invokeinterface = code == Bytecodes::_invokeinterface; @@ -2907,8 +2904,6 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) const Register flags = rdx; assert_different_registers(method, index, recv, flags); - assert(!is_invdyn_bootstrap || is_invokedynamic, "byte_no<0 hack only for invdyn"); - // save 'interpreter return address' __ save_bcp(); @@ -2944,9 +2939,7 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) // load return address { address table_addr; - if (is_invdyn_bootstrap) - table_addr = (address)Interpreter::return_5_unbox_addrs_by_index_table(); - else if (is_invokeinterface || is_invokedynamic) + if (is_invokeinterface || is_invokedynamic) table_addr = (address)Interpreter::return_5_addrs_by_index_table(); else table_addr = (address)Interpreter::return_3_addrs_by_index_table(); @@ -3153,54 +3146,10 @@ void TemplateTable::invokedynamic(int byte_no) { __ profile_call(rsi); } - Label handle_unlinked_site; - __ movptr(rcx, Address(rax, __ delayed_value(sun_dyn_CallSiteImpl::target_offset_in_bytes, rcx))); - __ testptr(rcx, rcx); - __ jcc(Assembler::zero, handle_unlinked_site); - + __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx))); + __ null_check(rcx); __ prepare_to_jump_from_interpreted(); __ jump_to_method_handle_entry(rcx, rdx); - - // Initial calls come here... - __ bind(handle_unlinked_site); - __ pop(rcx); // remove return address pushed by prepare_invoke - - // box stacked arguments into an array for the bootstrap method - address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic); - __ restore_bcp(); // rsi must be correct for call_VM - __ call_VM(rax, entry, rax); - __ movl(rdi, rax); // protect bootstrap MH from prepare_invoke - - // recompute return address - __ restore_bcp(); // rsi must be correct for prepare_invoke - prepare_invoke(rax, rbx, -byte_no); // smashes rcx, rdx - // rax: CallSite object (f1) - // rbx: unused (f2) - // rdi: bootstrap MH - // rdx: flags - - // now load up the arglist, which has been neatly boxed - __ get_thread(rcx); - __ movptr(rdx, Address(rcx, JavaThread::vm_result_2_offset())); - __ movptr(Address(rcx, JavaThread::vm_result_2_offset()), NULL_WORD); - __ verify_oop(rdx); - // rdx = arglist - - // save SP now, before we add the bootstrap call to the stack - // We must preserve a fiction that the original arguments are outgoing, - // because the return sequence will reset the stack to this point - // and then pop all those arguments. It seems error-prone to use - // a different argument list size just for bootstrapping. - __ prepare_to_jump_from_interpreted(); - - // Now let's play adapter, pushing the real arguments on the stack. - __ pop(rbx); // return PC - __ push(rdi); // boot MH - __ push(rax); // call site - __ push(rdx); // arglist - __ push(rbx); // return PC, again - __ mov(rcx, rdi); - __ jump_to_method_handle_entry(rcx, rdx); } //---------------------------------------------------------------------------------------------------- diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index 1180227b59f..f461b10e451 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -203,18 +203,15 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bytecode, Register bc, __ jcc(Assembler::notEqual, fast_patch); __ get_method(scratch); // Let breakpoint table handling rewrite to quicker bytecode - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::set_original_bytecode_at), - scratch, r13, bc); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), scratch, r13, bc); #ifndef ASSERT __ jmpb(patch_done); - __ bind(fast_patch); - } #else __ jmp(patch_done); +#endif __ bind(fast_patch); } +#ifdef ASSERT Label okay; __ load_unsigned_byte(scratch, at_bcp(0)); __ cmpl(scratch, (int) Bytecodes::java_code(bytecode)); @@ -2054,26 +2051,28 @@ void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits } } -void TemplateTable::resolve_cache_and_index(int byte_no, - Register Rcache, - Register index) { +void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register index) { assert(byte_no == 1 || byte_no == 2, "byte_no out of range"); + bool is_invokedynamic = (bytecode() == Bytecodes::_invokedynamic); const Register temp = rbx; assert_different_registers(Rcache, index, temp); const int shift_count = (1 + byte_no) * BitsPerByte; Label resolved; - __ get_cache_and_index_at_bcp(Rcache, index, 1); - __ movl(temp, Address(Rcache, - index, Address::times_8, - constantPoolCacheOopDesc::base_offset() + - ConstantPoolCacheEntry::indices_offset())); - __ shrl(temp, shift_count); - // have we resolved this bytecode? - __ andl(temp, 0xFF); - __ cmpl(temp, (int) bytecode()); - __ jcc(Assembler::equal, resolved); + __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic); + if (is_invokedynamic) { + // we are resolved if the f1 field contains a non-null CallSite object + __ cmpptr(Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), (int32_t) NULL_WORD); + __ jcc(Assembler::notEqual, resolved); + } else { + __ movl(temp, Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset())); + __ shrl(temp, shift_count); + // have we resolved this bytecode? + __ andl(temp, 0xFF); + __ cmpl(temp, (int) bytecode()); + __ jcc(Assembler::equal, resolved); + } // resolve first time through address entry; @@ -2090,6 +2089,9 @@ void TemplateTable::resolve_cache_and_index(int byte_no, case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; + case Bytecodes::_invokedynamic: + entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); + break; default: ShouldNotReachHere(); break; @@ -2098,7 +2100,7 @@ void TemplateTable::resolve_cache_and_index(int byte_no, __ call_VM(noreg, entry, temp); // Update registers with resolved info - __ get_cache_and_index_at_bcp(Rcache, index, 1); + __ get_cache_and_index_at_bcp(Rcache, index, 1, is_invokedynamic); __ bind(resolved); } @@ -2832,15 +2834,14 @@ void TemplateTable::count_calls(Register method, Register temp) { ShouldNotReachHere(); } -void TemplateTable::prepare_invoke(Register method, - Register index, - int byte_no, - Bytecodes::Code code) { +void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) { // determine flags + Bytecodes::Code code = bytecode(); const bool is_invokeinterface = code == Bytecodes::_invokeinterface; + const bool is_invokedynamic = code == Bytecodes::_invokedynamic; const bool is_invokevirtual = code == Bytecodes::_invokevirtual; const bool is_invokespecial = code == Bytecodes::_invokespecial; - const bool load_receiver = code != Bytecodes::_invokestatic; + const bool load_receiver = (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic); const bool receiver_null_check = is_invokespecial; const bool save_flags = is_invokeinterface || is_invokevirtual; // setup registers & access constant pool cache @@ -2858,9 +2859,13 @@ void TemplateTable::prepare_invoke(Register method, __ movl(recv, flags); __ andl(recv, 0xFF); if (TaggedStackInterpreter) __ shll(recv, 1); // index*2 - __ movptr(recv, Address(rsp, recv, Address::times_8, - -Interpreter::expr_offset_in_bytes(1))); - __ verify_oop(recv); + Address recv_addr(rsp, recv, Address::times_8, -Interpreter::expr_offset_in_bytes(1)); + if (is_invokedynamic) { + __ lea(recv, recv_addr); + } else { + __ movptr(recv, recv_addr); + __ verify_oop(recv); + } } // do null check if needed @@ -2878,10 +2883,14 @@ void TemplateTable::prepare_invoke(Register method, ConstantPoolCacheEntry::verify_tosBits(); // load return address { - ExternalAddress return_5((address)Interpreter::return_5_addrs_by_index_table()); - ExternalAddress return_3((address)Interpreter::return_3_addrs_by_index_table()); - __ lea(rscratch1, (is_invokeinterface ? return_5 : return_3)); - __ movptr(flags, Address(rscratch1, flags, Address::times_8)); + address table_addr; + if (is_invokeinterface || is_invokedynamic) + table_addr = (address)Interpreter::return_5_addrs_by_index_table(); + else + table_addr = (address)Interpreter::return_3_addrs_by_index_table(); + ExternalAddress table(table_addr); + __ lea(rscratch1, table); + __ movptr(flags, Address(rscratch1, flags, Address::times_ptr)); } // push return address @@ -2947,7 +2956,7 @@ void TemplateTable::invokevirtual_helper(Register index, void TemplateTable::invokevirtual(int byte_no) { transition(vtos, vtos); - prepare_invoke(rbx, noreg, byte_no, bytecode()); + prepare_invoke(rbx, noreg, byte_no); // rbx: index // rcx: receiver @@ -2959,7 +2968,7 @@ void TemplateTable::invokevirtual(int byte_no) { void TemplateTable::invokespecial(int byte_no) { transition(vtos, vtos); - prepare_invoke(rbx, noreg, byte_no, bytecode()); + prepare_invoke(rbx, noreg, byte_no); // do the call __ verify_oop(rbx); __ profile_call(rax); @@ -2969,7 +2978,7 @@ void TemplateTable::invokespecial(int byte_no) { void TemplateTable::invokestatic(int byte_no) { transition(vtos, vtos); - prepare_invoke(rbx, noreg, byte_no, bytecode()); + prepare_invoke(rbx, noreg, byte_no); // do the call __ verify_oop(rbx); __ profile_call(rax); @@ -2983,7 +2992,7 @@ void TemplateTable::fast_invokevfinal(int byte_no) { void TemplateTable::invokeinterface(int byte_no) { transition(vtos, vtos); - prepare_invoke(rax, rbx, byte_no, bytecode()); + prepare_invoke(rax, rbx, byte_no); // rax: Interface // rbx: index @@ -3072,7 +3081,24 @@ void TemplateTable::invokedynamic(int byte_no) { return; } - __ stop("invokedynamic NYI");//6815692// + prepare_invoke(rax, rbx, byte_no); + + // rax: CallSite object (f1) + // rbx: unused (f2) + // rcx: receiver address + // rdx: flags (unused) + + if (ProfileInterpreter) { + Label L; + // %%% should make a type profile for any invokedynamic that takes a ref argument + // profile this call + __ profile_call(r13); + } + + __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx))); + __ null_check(rcx); + __ prepare_to_jump_from_interpreted(); + __ jump_to_method_handle_entry(rcx, rdx); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp index ec531a7bc1a..6a9fdf9ed90 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp @@ -22,8 +22,7 @@ * */ - static void prepare_invoke(Register method, Register index, int byte_no, - Bytecodes::Code code); + static void prepare_invoke(Register method, Register index, int byte_no); static void invokevirtual_helper(Register index, Register recv, Register flags); static void volatile_barrier(Assembler::Membar_mask_bits order_constraint); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index ae8efb86939..5965fd3ead8 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -255,6 +255,8 @@ void VM_Version::get_processor_features() { if (!VM_Version::supports_sse2()) { vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); } + // in 64 bit the use of SSE2 is the minimum + if (UseSSE < 2) UseSSE = 2; #endif // If the OS doesn't support SSE, we can't use this feature even if the HW does diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 71657a809bf..72cb4175ab2 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -268,22 +268,36 @@ static jlong *double_signmask_pool = double_quadword(&fp_signmask_pool[2*2], CON static jlong *float_signflip_pool = double_quadword(&fp_signmask_pool[3*2], CONST64(0x8000000080000000), CONST64(0x8000000080000000)); static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], CONST64(0x8000000000000000), CONST64(0x8000000000000000)); +// Offset hacking within calls. +static int pre_call_FPU_size() { + if (Compile::current()->in_24_bit_fp_mode()) + return 6; // fldcw + return 0; +} + +static int preserve_SP_size() { + return LP64_ONLY(1 +) 2; // [rex,] op, rm(reg/reg) +} + // !!!!! Special hack to get all type of calls to specify the byte offset // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { - return 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 5 bytes from start of call to where return address points + int offset = 5 + pre_call_FPU_size(); // 5 bytes from start of call to where return address points + if (_method_handle_invoke) + offset += preserve_SP_size(); + return offset; } int MachCallDynamicJavaNode::ret_addr_offset() { - return 10 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 10 bytes from start of call to where return address points + return 10 + pre_call_FPU_size(); // 10 bytes from start of call to where return address points } static int sizeof_FFree_Float_Stack_All = -1; int MachCallRuntimeNode::ret_addr_offset() { assert(sizeof_FFree_Float_Stack_All != -1, "must have been emitted already"); - return sizeof_FFree_Float_Stack_All + 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); + return sizeof_FFree_Float_Stack_All + 5 + pre_call_FPU_size(); } // Indicate if the safepoint node needs the polling page as an input. @@ -299,8 +313,16 @@ bool SafePointNode::needs_polling_address_input() { // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallStaticJavaDirectNode::compute_padding(int current_offset) const { - if (Compile::current()->in_24_bit_fp_mode()) - current_offset += 6; // skip fldcw in pre_call_FPU, if any + current_offset += pre_call_FPU_size(); // skip fldcw, if any + current_offset += 1; // skip call opcode byte + return round_to(current_offset, alignment_required()) - current_offset; +} + +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallStaticJavaHandleNode::compute_padding(int current_offset) const { + current_offset += pre_call_FPU_size(); // skip fldcw, if any + current_offset += preserve_SP_size(); // skip mov rbp, rsp current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; } @@ -308,8 +330,7 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const { // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { - if (Compile::current()->in_24_bit_fp_mode()) - current_offset += 6; // skip fldcw in pre_call_FPU, if any + current_offset += pre_call_FPU_size(); // skip fldcw, if any current_offset += 5; // skip MOV instruction current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; @@ -1460,6 +1481,10 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } +const RegMask Matcher::method_handle_invoke_SP_save_mask() { + return EBP_REG_mask; +} + %} //----------ENCODING BLOCK----------------------------------------------------- @@ -1772,10 +1797,13 @@ encode %{ enc_class pre_call_FPU %{ // If method sets FPU control word restore it here + debug_only(int off0 = cbuf.code_size()); if( Compile::current()->in_24_bit_fp_mode() ) { MacroAssembler masm(&cbuf); masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); } + debug_only(int off1 = cbuf.code_size()); + assert(off1 - off0 == pre_call_FPU_size(), "correct size prediction"); %} enc_class post_call_FPU %{ @@ -1786,6 +1814,21 @@ encode %{ } %} + enc_class preserve_SP %{ + debug_only(int off0 = cbuf.code_size()); + MacroAssembler _masm(&cbuf); + // RBP is preserved across all calls, even compiled calls. + // Use it to preserve RSP in places where the callee might change the SP. + __ movptr(rbp, rsp); + debug_only(int off1 = cbuf.code_size()); + assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); + %} + + enc_class restore_SP %{ + MacroAssembler _masm(&cbuf); + __ movptr(rsp, rbp); + %} + enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. @@ -13406,6 +13449,7 @@ instruct cmovXX_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regX dst, // compute_padding() functions will have to be adjusted. instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); + predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -13420,6 +13464,30 @@ instruct CallStaticJavaDirect(method meth) %{ ins_alignment(4); %} +// Call Java Static Instruction (method handle version) +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallStaticJavaHandle(method meth, eBPRegP ebp) %{ + match(CallStaticJava); + predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); + effect(USE meth); + // EBP is saved by all callees (for interpreter stack correction). + // We use it here for a similar purpose, in {preserve,restore}_SP. + + ins_cost(300); + format %{ "CALL,static/MethodHandle " %} + opcode(0xE8); /* E8 cd */ + ins_encode( pre_call_FPU, + preserve_SP, + Java_Static_Call( meth ), + restore_SP, + call_epilog, + post_call_FPU ); + ins_pipe( pipe_slow ); + ins_pc_relative(1); + ins_alignment(4); +%} + // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 5927b5081a7..86e28eed7ea 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -551,12 +551,19 @@ source %{ #define __ _masm. +static int preserve_SP_size() { + return LP64_ONLY(1 +) 2; // [rex,] op, rm(reg/reg) +} + // !!!!! Special hack to get all types of calls to specify the byte offset // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { - return 5; // 5 bytes from start of call to where return address points + int offset = 5; // 5 bytes from start of call to where return address points + if (_method_handle_invoke) + offset += preserve_SP_size(); + return offset; } int MachCallDynamicJavaNode::ret_addr_offset() @@ -587,6 +594,15 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const return round_to(current_offset, alignment_required()) - current_offset; } +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallStaticJavaHandleNode::compute_padding(int current_offset) const +{ + current_offset += preserve_SP_size(); // skip mov rbp, rsp + current_offset += 1; // skip call opcode byte + return round_to(current_offset, alignment_required()) - current_offset; +} + // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const @@ -2113,6 +2129,10 @@ RegMask Matcher::modL_proj_mask() { return LONG_RDX_REG_mask; } +const RegMask Matcher::method_handle_invoke_SP_save_mask() { + return PTR_RBP_REG_mask; +} + static Address build_address(int b, int i, int s, int d) { Register index = as_Register(i); Address::ScaleFactor scale = (Address::ScaleFactor)s; @@ -2608,6 +2628,21 @@ encode %{ RELOC_DISP32); %} + enc_class preserve_SP %{ + debug_only(int off0 = cbuf.code_size()); + MacroAssembler _masm(&cbuf); + // RBP is preserved across all calls, even compiled calls. + // Use it to preserve RSP in places where the callee might change the SP. + __ movptr(rbp, rsp); + debug_only(int off1 = cbuf.code_size()); + assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); + %} + + enc_class restore_SP %{ + MacroAssembler _masm(&cbuf); + __ movptr(rsp, rbp); + %} + enc_class Java_Static_Call(method meth) %{ // JAVA STATIC CALL @@ -12526,9 +12561,9 @@ instruct safePoint_poll(rFlagsReg cr) // Call Java Static Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. -instruct CallStaticJavaDirect(method meth) -%{ +instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); + predicate(!((CallStaticJavaNode*) n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -12540,6 +12575,28 @@ instruct CallStaticJavaDirect(method meth) ins_alignment(4); %} +// Call Java Static Instruction (method handle version) +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallStaticJavaHandle(method meth, rbp_RegP rbp) %{ + match(CallStaticJava); + predicate(((CallStaticJavaNode*) n)->is_method_handle_invoke()); + effect(USE meth); + // RBP is saved by all callees (for interpreter stack correction). + // We use it here for a similar purpose, in {preserve,restore}_SP. + + ins_cost(300); + format %{ "call,static/MethodHandle " %} + opcode(0xE8); /* E8 cd */ + ins_encode(preserve_SP, + Java_Static_Call(meth), + restore_SP, + call_epilog); + ins_pipe(pipe_slow); + ins_pc_relative(1); + ins_alignment(4); +%} + // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 8c99fbf4556..8fcb75c8b36 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -204,6 +204,20 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) { goto unwind_and_return; } + // Update the invocation counter + if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) { + thread->set_do_not_unlock(); + InvocationCounter *counter = method->invocation_counter(); + counter->increment(); + if (counter->reached_InvocationLimit()) { + CALL_VM_NOCHECK( + InterpreterRuntime::frequency_counter_overflow(thread, NULL)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; + } + thread->clr_do_not_unlock(); + } + // Lock if necessary BasicObjectLock *monitor; monitor = NULL; @@ -231,7 +245,7 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) { if (handlerAddr == NULL) { CALL_VM_NOCHECK(InterpreterRuntime::prepare_native_call(thread, method)); if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; + goto unlock_unwind_and_return; handlerAddr = method->signature_handler(); assert(handlerAddr != NULL, "eh?"); @@ -240,7 +254,7 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) { CALL_VM_NOCHECK(handlerAddr = InterpreterRuntime::slow_signature_handler(thread, method, NULL,NULL)); if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; + goto unlock_unwind_and_return; } handler = \ InterpreterRuntime::SignatureHandler::from_handlerAddr(handlerAddr); @@ -351,10 +365,10 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) { // Reset handle block thread->active_handles()->clear(); - // Unlock if necessary. It seems totally wrong that this - // is skipped in the event of an exception but apparently - // the template interpreter does this so we do too. - if (monitor && !HAS_PENDING_EXCEPTION) { + unlock_unwind_and_return: + + // Unlock if necessary + if (monitor) { BasicLock *lock = monitor->lock(); markOop header = lock->displaced_header(); oop rcvr = monitor->obj(); diff --git a/hotspot/src/cpu/zero/vm/frame_zero.cpp b/hotspot/src/cpu/zero/vm/frame_zero.cpp index 1b3cafdc589..323912e1cb3 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.cpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp @@ -36,11 +36,8 @@ bool frame::is_interpreted_frame() const { return zeroframe()->is_interpreter_frame(); } -bool frame::is_fake_stub_frame() const { - return zeroframe()->is_fake_stub_frame(); -} - frame frame::sender_for_entry_frame(RegisterMap *map) const { + assert(zeroframe()->is_entry_frame(), "wrong type of frame"); assert(map != NULL, "map must be set"); assert(!entry_frame_is_first(), "next Java fp must be non zero"); assert(entry_frame_call_wrapper()->anchor()->last_Java_sp() == sender_sp(), @@ -50,15 +47,10 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const { return frame(sender_sp(), sp() + 1); } -frame frame::sender_for_interpreter_frame(RegisterMap *map) const { - return frame(sender_sp(), sp() + 1); -} - -frame frame::sender_for_compiled_frame(RegisterMap *map) const { - return frame(sender_sp(), sp() + 1); -} - -frame frame::sender_for_fake_stub_frame(RegisterMap *map) const { +frame frame::sender_for_nonentry_frame(RegisterMap *map) const { + assert(zeroframe()->is_interpreter_frame() || + zeroframe()->is_shark_frame() || + zeroframe()->is_fake_stub_frame(), "wrong type of frame"); return frame(sender_sp(), sp() + 1); } @@ -69,17 +61,8 @@ frame frame::sender(RegisterMap* map) const { if (is_entry_frame()) return sender_for_entry_frame(map); - - if (is_interpreted_frame()) - return sender_for_interpreter_frame(map); - - if (is_compiled_frame()) - return sender_for_compiled_frame(map); - - if (is_fake_stub_frame()) - return sender_for_fake_stub_frame(map); - - ShouldNotReachHere(); + else + return sender_for_nonentry_frame(map); } #ifdef CC_INTERP diff --git a/hotspot/src/cpu/zero/vm/frame_zero.hpp b/hotspot/src/cpu/zero/vm/frame_zero.hpp index 81b6314571d..84d248fe0c4 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.hpp @@ -65,10 +65,7 @@ } public: - bool is_fake_stub_frame() const; - - public: - frame sender_for_fake_stub_frame(RegisterMap* map) const; + frame sender_for_nonentry_frame(RegisterMap* map) const; public: void zero_print_on_error(int index, diff --git a/hotspot/src/cpu/zero/vm/globals_zero.hpp b/hotspot/src/cpu/zero/vm/globals_zero.hpp index 89cf7077dee..e8a32f1d47a 100644 --- a/hotspot/src/cpu/zero/vm/globals_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp @@ -23,10 +23,8 @@ * */ -// // Set the default values for platform dependent flags used by the // runtime system. See globals.hpp for details of what they do. -// define_pd_global(bool, ConvertSleepToYield, true); define_pd_global(bool, ShareVtableStubs, true); @@ -37,14 +35,7 @@ define_pd_global(bool, ImplicitNullChecks, true); define_pd_global(bool, UncommonNullCast, true); define_pd_global(intx, CodeEntryAlignment, 32); -define_pd_global(uintx, TLABSize, 0); -#ifdef _LP64 -define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K)); -#else -define_pd_global(uintx, NewSize, ScaleForWordSize(1024 * K)); -#endif // _LP64 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/zero/vm/sharedRuntime_zero.cpp b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp index 7bb4614980f..5adb87aef70 100644 --- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp +++ b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp @@ -1,6 +1,6 @@ /* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2009 Red Hat, Inc. * 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,7 +61,14 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type) { +#ifdef SHARK + return SharkCompiler::compiler()->generate_native_wrapper(masm, + method, + in_sig_bt, + ret_type); +#else ShouldNotCallThis(); +#endif // SHARK } int Deoptimization::last_frame_adjust(int callee_parameters, diff --git a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp b/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp index 3337219a370..2473ebf7ae6 100644 --- a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp +++ b/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp @@ -1,6 +1,6 @@ /* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2008 Red Hat, Inc. + * Copyright 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ // | ... | class SharkFrame : public ZeroFrame { - friend class SharkFunction; + friend class SharkStack; private: SharkFrame() : ZeroFrame() { diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 281e81c264f..a4c54456504 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -223,8 +223,8 @@ static const char *unstable_chroot_error = "/proc file system not found.\n" "environment on Linux when /proc filesystem is not mounted."; void os::Linux::initialize_system_info() { - _processor_count = sysconf(_SC_NPROCESSORS_CONF); - if (_processor_count == 1) { + set_processor_count(sysconf(_SC_NPROCESSORS_CONF)); + if (processor_count() == 1) { pid_t pid = os::Linux::gettid(); char fname[32]; jio_snprintf(fname, sizeof(fname), "/proc/%d", pid); @@ -236,7 +236,7 @@ void os::Linux::initialize_system_info() { } } _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE); - assert(_processor_count > 0, "linux error"); + assert(processor_count() > 0, "linux error"); } void os::init_system_properties_values() { @@ -4683,6 +4683,7 @@ void Parker::park(bool isAbsolute, jlong time) { // Return immediately if a permit is available. if (_counter > 0) { _counter = 0 ; + OrderAccess::fence(); return ; } @@ -4725,6 +4726,7 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0; status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; + OrderAccess::fence(); return; } @@ -4765,6 +4767,7 @@ void Parker::park(bool isAbsolute, jlong time) { jt->java_suspend_self(); } + OrderAccess::fence(); } void Parker::unpark() { diff --git a/hotspot/src/os/solaris/dtrace/libjvm_db.c b/hotspot/src/os/solaris/dtrace/libjvm_db.c index b162f057b5b..7db194a517e 100644 --- a/hotspot/src/os/solaris/dtrace/libjvm_db.c +++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c @@ -937,54 +937,56 @@ scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf) return err; } -static int -scopeDesc_chain(Nmethod_t *N) -{ +static int scopeDesc_chain(Nmethod_t *N) { int32_t decode_offset = 0; int32_t err; - if (debug > 2) - fprintf(stderr, "\t scopeDesc_chain: BEGIN\n"); + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: BEGIN\n"); + } err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset, &decode_offset, SZ32); CHECK_FAIL(err); while (decode_offset > 0) { - if (debug > 2) - fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset); + Vframe_t *vf = &N->vframes[N->vf_cnt]; - Vframe_t *vf = &N->vframes[N->vf_cnt]; + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset); + } - err = scope_desc_at(N, decode_offset, vf); + err = scope_desc_at(N, decode_offset, vf); + CHECK_FAIL(err); + + if (vf->methodIdx > N->oops_len) { + fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops_len) !\n"); + return -1; + } + err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE, + &vf->methodOop); + CHECK_FAIL(err); + + if (vf->methodOop) { + N->vf_cnt++; + err = line_number_from_bci(N->J, vf); CHECK_FAIL(err); - - if (vf->methodIdx > N->oops_len) { - fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops_len) !\n"); - return -1; + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n", + vf->methodOop, vf->line); } - err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE, - &vf->methodOop); - CHECK_FAIL(err); - - if (vf->methodOop) { - N->vf_cnt++; - err = line_number_from_bci(N->J, vf); - CHECK_FAIL(err); - if (debug > 2) { - fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n", - vf->methodOop, vf->line); - } - } - decode_offset = vf->sender_decode_offset; + } + decode_offset = vf->sender_decode_offset; + } + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: END \n\n"); } - if (debug > 2) - fprintf(stderr, "\t scopeDesc_chain: END \n\n"); return PS_OK; fail: - if (debug) - fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n"); + if (debug) { + fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n"); + } return err; } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 13abbf9d4b9..2ef21349881 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -457,7 +457,7 @@ static volatile int max_hrtime_lock = LOCK_FREE; // Update counter with LSB void os::Solaris::initialize_system_info() { - _processor_count = sysconf(_SC_NPROCESSORS_CONF); + set_processor_count(sysconf(_SC_NPROCESSORS_CONF)); _processors_online = sysconf (_SC_NPROCESSORS_ONLN); _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE); } @@ -5803,6 +5803,7 @@ void Parker::park(bool isAbsolute, jlong time) { // Return immediately if a permit is available. if (_counter > 0) { _counter = 0 ; + OrderAccess::fence(); return ; } @@ -5846,6 +5847,7 @@ void Parker::park(bool isAbsolute, jlong time) { _counter = 0; status = os::Solaris::mutex_unlock(_mutex); assert (status == 0, "invariant") ; + OrderAccess::fence(); return; } @@ -5892,6 +5894,7 @@ void Parker::park(bool isAbsolute, jlong time) { jt->java_suspend_self(); } + OrderAccess::fence(); } void Parker::unpark() { diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0c941d66db9..40f7bf5a95b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -3150,7 +3150,7 @@ void os::win32::initialize_system_info() { _vm_allocation_granularity = si.dwAllocationGranularity; _processor_type = si.dwProcessorType; _processor_level = si.wProcessorLevel; - _processor_count = si.dwNumberOfProcessors; + set_processor_count(si.dwNumberOfProcessors); MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); 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 a1cb9732ace..708cc3e085c 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 @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, false); #ifdef AMD64 define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default @@ -39,11 +38,10 @@ define_pd_global(intx, VMThreadStackSize, 512); #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); -define_pd_global(intx, SurvivorRatio, 8); -define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +define_pd_global(uintx,JVMInvokeMethodSlack, 8192); // Only used on 64 bit platforms -define_pd_global(uintx, HeapBaseMinAddress, 2*G); +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_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index 572702e7d6d..b9a140a5136 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -1,6 +1,6 @@ /* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * 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,7 +239,21 @@ void os::Linux::set_fpu_control_word(int fpu) { } bool os::is_allocatable(size_t bytes) { - ShouldNotCallThis(); +#ifdef _LP64 + return true; +#else + if (bytes < 2 * G) { + return true; + } + + char* addr = reserve_memory(bytes, NULL); + + if (addr != NULL) { + release_memory(addr, bytes); + } + + return addr != NULL; +#endif // _LP64 } /////////////////////////////////////////////////////////////////////////////// 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 4b51eef5ee0..4b2749bc193 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 @@ -22,31 +22,25 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, true); // Determined in the design center #ifdef AMD64 define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 1024); -define_pd_global(intx, SurvivorRatio, 6); -define_pd_global(uintx, JVMInvokeMethodSlack, 8*K); +define_pd_global(uintx,JVMInvokeMethodSlack, 8*K); #else -// UseStackBanging is not pd -// define_pd_global(bool, UseStackBanging, true); - // ThreadStackSize 320 allows TaggedStackInterpreter and a couple of test cases // to run while keeping the number of threads that can be created high. define_pd_global(intx, ThreadStackSize, 320); define_pd_global(intx, VMThreadStackSize, 512); -define_pd_global(intx, SurvivorRatio, 8); -define_pd_global(uintx, JVMInvokeMethodSlack, 10*K); +define_pd_global(uintx,JVMInvokeMethodSlack, 10*K); #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); // Only used on 64 bit platforms -define_pd_global(uintx, HeapBaseMinAddress, 256*M); +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/windows_x86/vm/globals_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp index 300541e0e96..e5cf1dfe371 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 @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, false); // Default stack size on Windows is determined by the executable (java.exe @@ -35,8 +34,6 @@ define_pd_global(bool, DontYieldALot, false); define_pd_global(intx, ThreadStackSize, 0); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 0); // 0 => use system default -define_pd_global(intx, SurvivorRatio, 8); - #ifdef ASSERT define_pd_global(intx, CompilerThreadStackSize, 1024); #else diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index caa99ded618..f567d6e120d 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -365,7 +365,7 @@ void BlockListBuilder::make_loop_header(BlockBegin* block) { if (_next_loop_index < 31) _next_loop_index++; } else { // block already marked as loop header - assert(is_power_of_2(_loop_map.at(block->block_id())), "exactly one bit must be set"); + assert(is_power_of_2((unsigned int)_loop_map.at(block->block_id())), "exactly one bit must be set"); } } diff --git a/hotspot/src/share/vm/c1/c1_IR.hpp b/hotspot/src/share/vm/c1/c1_IR.hpp index f7bbea2ff3b..e1af926aef1 100644 --- a/hotspot/src/share/vm/c1/c1_IR.hpp +++ b/hotspot/src/share/vm/c1/c1_IR.hpp @@ -251,8 +251,9 @@ class IRScopeDebugInfo: public CompilationResourceObj { DebugToken* expvals = recorder->create_scope_values(expressions()); DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame - bool reexecute = topmost ? should_reexecute() : false; - recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, locvals, expvals, monvals); + bool reexecute = topmost ? should_reexecute() : false; + bool is_method_handle_invoke = false; + recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, locvals, expvals, monvals); } }; diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index c3da44e2329..fb51de4ca2d 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2000,7 +2000,7 @@ class LIR_OpVisitState: public StackObj { typedef enum { inputMode, firstMode = inputMode, tempMode, outputMode, numModes, invalidMode = -1 } OprMode; enum { - maxNumberOfOperands = 14, + maxNumberOfOperands = 16, maxNumberOfInfos = 4 }; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 8eb667dda29..a393028792d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1855,12 +1855,26 @@ void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) { addr = new LIR_Address(base_op, index_op->as_jint(), dst_type); } else { #ifdef X86 +#ifdef _LP64 + if (!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type); #else if (index_op->is_illegal() || log2_scale == 0) { +#ifdef _LP64 + if (!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif addr = new LIR_Address(base_op, index_op, dst_type); } else { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); __ shift_left(index_op, log2_scale, tmp); addr = new LIR_Address(base_op, tmp, dst_type); } @@ -1915,10 +1929,25 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) { LIR_Opr index_op = idx.result(); if (log2_scale != 0) { // temporary fix (platform dependent code without shift on Intel would be better) - index_op = new_register(T_INT); - __ move(idx.result(), index_op); + index_op = new_pointer_register(); +#ifdef _LP64 + if(idx.result()->type() == T_INT) { + __ convert(Bytecodes::_i2l, idx.result(), index_op); + } else { +#endif + __ move(idx.result(), index_op); +#ifdef _LP64 + } +#endif __ shift_left(index_op, log2_scale, index_op); } +#ifdef _LP64 + else if(!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type()); __ move(value.result(), addr); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index bab43e2ad21..ab049832121 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -2464,6 +2464,10 @@ int LinearScan::append_scope_value_for_constant(LIR_Opr opr, GrowableArrayappend(&_int_0_scope_value); + scope_values->append(new ConstantLongValue(c->as_jlong_bits())); +#else if (hi_word_offset_in_bytes > lo_word_offset_in_bytes) { scope_values->append(new ConstantIntValue(c->as_jint_hi_bits())); scope_values->append(new ConstantIntValue(c->as_jint_lo_bits())); @@ -2471,7 +2475,7 @@ int LinearScan::append_scope_value_for_constant(LIR_Opr opr, GrowableArrayappend(new ConstantIntValue(c->as_jint_lo_bits())); scope_values->append(new ConstantIntValue(c->as_jint_hi_bits())); } - +#endif return 2; } @@ -2503,17 +2507,18 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArrayis_single_cpu()) { bool is_oop = opr->is_oop_register(); int cache_idx = opr->cpu_regnr() * 2 + (is_oop ? 1 : 0); + Location::Type int_loc_type = NOT_LP64(Location::normal) LP64_ONLY(Location::int_in_long); ScopeValue* sv = _scope_value_cache.at(cache_idx); if (sv == NULL) { - Location::Type loc_type = is_oop ? Location::oop : Location::normal; + Location::Type loc_type = is_oop ? Location::oop : int_loc_type; VMReg rname = frame_map()->regname(opr); sv = new LocationValue(Location::new_reg_loc(loc_type, rname)); _scope_value_cache.at_put(cache_idx, sv); } // check if cached value is correct - DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : Location::normal, frame_map()->regname(opr))))); + DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : int_loc_type, frame_map()->regname(opr))))); scope_values->append(sv); return 1; diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 986cfd28561..9093885ce45 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -425,7 +425,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); assert(exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError - if (!(exception->is_a(SystemDictionary::throwable_klass()))) { + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp index 8c5122c1486..86de9695cc5 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp @@ -61,9 +61,11 @@ class BCEscapeAnalyzer : public ResourceObj { BCEscapeAnalyzer* _parent; int _level; + public: class ArgumentMap; class StateInfo; + private: // helper functions bool is_argument(int i) { return i >= 0 && i < _arg_size; } diff --git a/hotspot/src/share/vm/ci/ciCPCache.cpp b/hotspot/src/share/vm/ci/ciCPCache.cpp new file mode 100644 index 00000000000..87bd409a615 --- /dev/null +++ b/hotspot/src/share/vm/ci/ciCPCache.cpp @@ -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. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_ciCPCache.cpp.incl" + +// ciCPCache + +// ------------------------------------------------------------------ +// ciCPCache::get_f1_offset +size_t ciCPCache::get_f1_offset(int index) { + // Calculate the offset from the constantPoolCacheOop to the f1 + // field. + ByteSize f1_offset = + constantPoolCacheOopDesc::entry_offset(index) + + ConstantPoolCacheEntry::f1_offset(); + + return in_bytes(f1_offset); +} + + +// ------------------------------------------------------------------ +// ciCPCache::print +// +// Print debugging information about the cache. +void ciCPCache::print() { + Unimplemented(); +} diff --git a/hotspot/src/share/vm/ci/ciCPCache.hpp b/hotspot/src/share/vm/ci/ciCPCache.hpp new file mode 100644 index 00000000000..48e0c3b8fe7 --- /dev/null +++ b/hotspot/src/share/vm/ci/ciCPCache.hpp @@ -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. + * + */ + +// ciCPCache +// +// This class represents a constant pool cache. +// +// Note: This class is called ciCPCache as ciConstantPoolCache is used +// for something different. +class ciCPCache : public ciObject { +public: + ciCPCache(constantPoolCacheHandle cpcache) : ciObject(cpcache) {} + + // What kind of ciObject is this? + bool is_cpcache() const { return true; } + + // Get the offset in bytes from the oop to the f1 field of the + // requested entry. + size_t get_f1_offset(int index); + + void print(); +}; diff --git a/hotspot/src/share/vm/ci/ciCallSite.cpp b/hotspot/src/share/vm/ci/ciCallSite.cpp new file mode 100644 index 00000000000..541432b914b --- /dev/null +++ b/hotspot/src/share/vm/ci/ciCallSite.cpp @@ -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. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_ciCallSite.cpp.incl" + +// ciCallSite + +// ------------------------------------------------------------------ +// ciCallSite::get_target +// +// Return the target MethodHandle of this CallSite. +ciMethodHandle* ciCallSite::get_target() const { + VM_ENTRY_MARK; + oop method_handle_oop = java_dyn_CallSite::target(get_oop()); + return CURRENT_ENV->get_object(method_handle_oop)->as_method_handle(); +} + +// ------------------------------------------------------------------ +// ciCallSite::print +// +// Print debugging information about the CallSite. +void ciCallSite::print() { + Unimplemented(); +} diff --git a/hotspot/src/share/vm/ci/ciCallSite.hpp b/hotspot/src/share/vm/ci/ciCallSite.hpp new file mode 100644 index 00000000000..3700ad54430 --- /dev/null +++ b/hotspot/src/share/vm/ci/ciCallSite.hpp @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// ciCallSite +// +// The class represents a java.dyn.CallSite object. +class ciCallSite : public ciInstance { +public: + ciCallSite(instanceHandle h_i) : ciInstance(h_i) {} + + // What kind of ciObject is this? + bool is_call_site() const { return true; } + + // Return the target MethodHandle of this CallSite. + ciMethodHandle* get_target() const; + + void print(); +}; diff --git a/hotspot/src/share/vm/ci/ciClassList.hpp b/hotspot/src/share/vm/ci/ciClassList.hpp index f6a534477e2..5dc67b2c779 100644 --- a/hotspot/src/share/vm/ci/ciClassList.hpp +++ b/hotspot/src/share/vm/ci/ciClassList.hpp @@ -25,6 +25,7 @@ class ciEnv; class ciObjectFactory; class ciConstantPoolCache; +class ciCPCache; class ciField; class ciConstant; @@ -42,6 +43,8 @@ class ciTypeFlow; class ciObject; class ciNullObject; class ciInstance; +class ciCallSite; +class ciMethodHandle; class ciMethod; class ciMethodData; class ciReceiverTypeData; // part of ciMethodData @@ -78,6 +81,7 @@ friend class ciObjectFactory; // Any more access must be given explicitly. #define CI_PACKAGE_ACCESS_TO \ friend class ciObjectFactory; \ +friend class ciCallSite; \ friend class ciConstantPoolCache; \ friend class ciField; \ friend class ciConstant; \ @@ -93,6 +97,7 @@ friend class ciNullObject; \ friend class ciInstance; \ friend class ciMethod; \ friend class ciMethodData; \ +friend class ciMethodHandle; \ friend class ciReceiverTypeData; \ friend class ciSymbol; \ friend class ciArray; \ diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index b0a17b35c2e..e09c66a74dd 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -38,14 +38,9 @@ ciInstanceKlassKlass* ciEnv::_instance_klass_klass_instance; ciTypeArrayKlassKlass* ciEnv::_type_array_klass_klass_instance; ciObjArrayKlassKlass* ciEnv::_obj_array_klass_klass_instance; -ciInstanceKlass* ciEnv::_ArrayStoreException; -ciInstanceKlass* ciEnv::_Class; -ciInstanceKlass* ciEnv::_ClassCastException; -ciInstanceKlass* ciEnv::_Object; -ciInstanceKlass* ciEnv::_Throwable; -ciInstanceKlass* ciEnv::_Thread; -ciInstanceKlass* ciEnv::_OutOfMemoryError; -ciInstanceKlass* ciEnv::_String; +#define WK_KLASS_DEFN(name, ignore_s, ignore_o) ciInstanceKlass* ciEnv::_##name = NULL; +WK_KLASSES_DO(WK_KLASS_DEFN) +#undef WK_KLASS_DEFN ciSymbol* ciEnv::_unloaded_cisymbol = NULL; ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL; @@ -110,6 +105,8 @@ ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter) { _ArrayIndexOutOfBoundsException_instance = NULL; _ArrayStoreException_instance = NULL; _ClassCastException_instance = NULL; + _the_null_string = NULL; + _the_min_jint_string = NULL; } ciEnv::ciEnv(Arena* arena) { @@ -163,6 +160,8 @@ ciEnv::ciEnv(Arena* arena) { _ArrayIndexOutOfBoundsException_instance = NULL; _ArrayStoreException_instance = NULL; _ClassCastException_instance = NULL; + _the_null_string = NULL; + _the_min_jint_string = NULL; } ciEnv::~ciEnv() { @@ -248,6 +247,22 @@ ciInstance* ciEnv::ClassCastException_instance() { return _ClassCastException_instance; } +ciInstance* ciEnv::the_null_string() { + if (_the_null_string == NULL) { + VM_ENTRY_MARK; + _the_null_string = get_object(Universe::the_null_string())->as_instance(); + } + return _the_null_string; +} + +ciInstance* ciEnv::the_min_jint_string() { + if (_the_min_jint_string == NULL) { + VM_ENTRY_MARK; + _the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance(); + } + return _the_min_jint_string; +} + // ------------------------------------------------------------------ // ciEnv::get_method_from_handle ciMethod* ciEnv::get_method_from_handle(jobject method) { @@ -419,12 +434,11 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass, // ciEnv::get_klass_by_index_impl // // Implementation of get_klass_by_index. -ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor, +ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool, int index, - bool& is_accessible) { - assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool"); + bool& is_accessible, + ciInstanceKlass* accessor) { EXCEPTION_CONTEXT; - constantPoolHandle cpool(THREAD, accessor->get_instanceKlass()->constants()); KlassHandle klass (THREAD, constantPoolOopDesc::klass_at_if_loaded(cpool, index)); symbolHandle klass_name; if (klass.is_null()) { @@ -486,22 +500,21 @@ ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor, // ciEnv::get_klass_by_index // // Get a klass from the constant pool. -ciKlass* ciEnv::get_klass_by_index(ciInstanceKlass* accessor, +ciKlass* ciEnv::get_klass_by_index(constantPoolHandle cpool, int index, - bool& is_accessible) { - GUARDED_VM_ENTRY(return get_klass_by_index_impl(accessor, index, is_accessible);) + bool& is_accessible, + ciInstanceKlass* accessor) { + GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);) } // ------------------------------------------------------------------ // ciEnv::get_constant_by_index_impl // // Implementation of get_constant_by_index(). -ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor, - int index) { +ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool, + int index, + ciInstanceKlass* accessor) { EXCEPTION_CONTEXT; - instanceKlass* ik_accessor = accessor->get_instanceKlass(); - assert(ik_accessor->is_linked(), "must be linked before accessing constant pool"); - constantPoolOop cpool = ik_accessor->constants(); constantTag tag = cpool->tag_at(index); if (tag.is_int()) { return ciConstant(T_INT, (jint)cpool->int_at(index)); @@ -529,7 +542,7 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor, } else if (tag.is_klass() || tag.is_unresolved_klass()) { // 4881222: allow ldc to take a class type bool ignore; - ciKlass* klass = get_klass_by_index_impl(accessor, index, ignore); + ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore, accessor); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; record_out_of_memory_failure(); @@ -538,6 +551,11 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor, assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); return ciConstant(T_OBJECT, klass); + } else if (tag.is_object()) { + oop obj = cpool->object_at(index); + assert(obj->is_instance(), "must be an instance"); + ciObject* ciobj = get_object(obj); + return ciConstant(T_OBJECT, ciobj); } else { ShouldNotReachHere(); return ciConstant(); @@ -574,9 +592,10 @@ bool ciEnv::is_unresolved_klass_impl(instanceKlass* accessor, int index) const { // Pull a constant out of the constant pool. How appropriate. // // Implementation note: this query is currently in no way cached. -ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor, - int index) { - GUARDED_VM_ENTRY(return get_constant_by_index_impl(accessor, index); ) +ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool, + int index, + ciInstanceKlass* accessor) { + GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, index, accessor);) } // ------------------------------------------------------------------ @@ -586,7 +605,7 @@ ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor, // // Implementation note: this query is currently in no way cached. bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor, - int index) const { + int index) const { GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); ) } @@ -597,7 +616,7 @@ bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor, // // Implementation note: this query is currently in no way cached. bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor, - int index) const { + int index) const { GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); ) } @@ -678,22 +697,17 @@ methodOop ciEnv::lookup_method(instanceKlass* accessor, // ------------------------------------------------------------------ // ciEnv::get_method_by_index_impl -ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor, - int index, Bytecodes::Code bc) { - // Get the method's declared holder. - - assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool"); - constantPoolHandle cpool = accessor->get_instanceKlass()->constants(); +ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool, + int index, Bytecodes::Code bc, + ciInstanceKlass* accessor) { int holder_index = cpool->klass_ref_index_at(index); bool holder_is_accessible; - ciKlass* holder = get_klass_by_index_impl(accessor, holder_index, holder_is_accessible); + ciKlass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder); // Get the method's name and signature. - int nt_index = cpool->name_and_type_ref_index_at(index); - int sig_index = cpool->signature_ref_index_at(nt_index); symbolOop name_sym = cpool->name_ref_at(index); - symbolOop sig_sym = cpool->symbol_at(sig_index); + symbolOop sig_sym = cpool->signature_ref_at(index); if (holder_is_accessible) { // Our declared holder is loaded. instanceKlass* lookup = declared_holder->get_instanceKlass(); @@ -714,6 +728,33 @@ ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor, } +// ------------------------------------------------------------------ +// ciEnv::get_fake_invokedynamic_method_impl +ciMethod* ciEnv::get_fake_invokedynamic_method_impl(constantPoolHandle cpool, + int index, Bytecodes::Code bc) { + assert(bc == Bytecodes::_invokedynamic, "must be invokedynamic"); + + // Get the CallSite from the constant pool cache. + ConstantPoolCacheEntry* cpc_entry = cpool->cache()->secondary_entry_at(index); + assert(cpc_entry != NULL && cpc_entry->is_secondary_entry(), "sanity"); + Handle call_site = cpc_entry->f1(); + + // Call site might not be linked yet. + if (call_site.is_null()) { + ciInstanceKlass* mh_klass = get_object(SystemDictionary::MethodHandle_klass())->as_instance_klass(); + ciSymbol* sig_sym = get_object(cpool->signature_ref_at(index))->as_symbol(); + return get_unloaded_method(mh_klass, ciSymbol::invoke_name(), sig_sym); + } + + // Get the methodOop from the CallSite. + methodOop method_oop = (methodOop) java_dyn_CallSite::vmmethod(call_site()); + assert(method_oop != NULL, "sanity"); + assert(method_oop->is_method_handle_invoke(), "consistent"); + + return get_object(method_oop)->as_method(); +} + + // ------------------------------------------------------------------ // ciEnv::get_instance_klass_for_declared_method_holder ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* method_holder) { @@ -736,15 +777,19 @@ ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* m } - - // ------------------------------------------------------------------ // ciEnv::get_method_by_index -ciMethod* ciEnv::get_method_by_index(ciInstanceKlass* accessor, - int index, Bytecodes::Code bc) { - GUARDED_VM_ENTRY(return get_method_by_index_impl(accessor, index, bc);) +ciMethod* ciEnv::get_method_by_index(constantPoolHandle cpool, + int index, Bytecodes::Code bc, + ciInstanceKlass* accessor) { + if (bc == Bytecodes::_invokedynamic) { + GUARDED_VM_ENTRY(return get_fake_invokedynamic_method_impl(cpool, index, bc);) + } else { + GUARDED_VM_ENTRY(return get_method_by_index_impl(cpool, index, bc, accessor);) + } } + // ------------------------------------------------------------------ // ciEnv::name_buffer char *ciEnv::name_buffer(int req_len) { diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index e855dbf9e4f..63b5ffe57bf 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -74,14 +74,9 @@ private: static ciTypeArrayKlassKlass* _type_array_klass_klass_instance; static ciObjArrayKlassKlass* _obj_array_klass_klass_instance; - static ciInstanceKlass* _ArrayStoreException; - static ciInstanceKlass* _Class; - static ciInstanceKlass* _ClassCastException; - static ciInstanceKlass* _Object; - static ciInstanceKlass* _Throwable; - static ciInstanceKlass* _Thread; - static ciInstanceKlass* _OutOfMemoryError; - static ciInstanceKlass* _String; +#define WK_KLASS_DECL(name, ignore_s, ignore_o) static ciInstanceKlass* _##name; + WK_KLASSES_DO(WK_KLASS_DECL) +#undef WK_KLASS_DECL static ciSymbol* _unloaded_cisymbol; static ciInstanceKlass* _unloaded_ciinstance_klass; @@ -97,6 +92,9 @@ private: ciInstance* _ArrayStoreException_instance; ciInstance* _ClassCastException_instance; + ciInstance* _the_null_string; // The Java string "null" + ciInstance* _the_min_jint_string; // The Java string "-2147483648" + // Look up a klass by name from a particular class loader (the accessor's). // If require_local, result must be defined in that class loader, or NULL. // If !require_local, a result from remote class loader may be reported, @@ -114,37 +112,45 @@ private: bool require_local); // Constant pool access. - ciKlass* get_klass_by_index(ciInstanceKlass* loading_klass, + ciKlass* get_klass_by_index(constantPoolHandle cpool, int klass_index, - bool& is_accessible); - ciConstant get_constant_by_index(ciInstanceKlass* loading_klass, - int constant_index); + bool& is_accessible, + ciInstanceKlass* loading_klass); + ciConstant get_constant_by_index(constantPoolHandle cpool, + int constant_index, + ciInstanceKlass* accessor); bool is_unresolved_string(ciInstanceKlass* loading_klass, int constant_index) const; bool is_unresolved_klass(ciInstanceKlass* loading_klass, int constant_index) const; ciField* get_field_by_index(ciInstanceKlass* loading_klass, int field_index); - ciMethod* get_method_by_index(ciInstanceKlass* loading_klass, - int method_index, Bytecodes::Code bc); + ciMethod* get_method_by_index(constantPoolHandle cpool, + int method_index, Bytecodes::Code bc, + ciInstanceKlass* loading_klass); // Implementation methods for loading and constant pool access. ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass, ciSymbol* klass_name, bool require_local); - ciKlass* get_klass_by_index_impl(ciInstanceKlass* loading_klass, + ciKlass* get_klass_by_index_impl(constantPoolHandle cpool, int klass_index, - bool& is_accessible); - ciConstant get_constant_by_index_impl(ciInstanceKlass* loading_klass, - int constant_index); + bool& is_accessible, + ciInstanceKlass* loading_klass); + ciConstant get_constant_by_index_impl(constantPoolHandle cpool, + int constant_index, + ciInstanceKlass* loading_klass); bool is_unresolved_string_impl (instanceKlass* loading_klass, int constant_index) const; bool is_unresolved_klass_impl (instanceKlass* loading_klass, int constant_index) const; ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass, int field_index); - ciMethod* get_method_by_index_impl(ciInstanceKlass* loading_klass, - int method_index, Bytecodes::Code bc); + ciMethod* get_method_by_index_impl(constantPoolHandle cpool, + int method_index, Bytecodes::Code bc, + ciInstanceKlass* loading_klass); + ciMethod* get_fake_invokedynamic_method_impl(constantPoolHandle cpool, + int index, Bytecodes::Code bc); // Helper methods bool check_klass_accessibility(ciKlass* accessing_klass, @@ -286,30 +292,13 @@ public: // Access to certain well known ciObjects. - ciInstanceKlass* ArrayStoreException_klass() { - return _ArrayStoreException; - } - ciInstanceKlass* Class_klass() { - return _Class; - } - ciInstanceKlass* ClassCastException_klass() { - return _ClassCastException; - } - ciInstanceKlass* Object_klass() { - return _Object; - } - ciInstanceKlass* Throwable_klass() { - return _Throwable; - } - ciInstanceKlass* Thread_klass() { - return _Thread; - } - ciInstanceKlass* OutOfMemoryError_klass() { - return _OutOfMemoryError; - } - ciInstanceKlass* String_klass() { - return _String; +#define WK_KLASS_FUNC(name, ignore_s, ignore_o) \ + ciInstanceKlass* name() { \ + return _##name;\ } + WK_KLASSES_DO(WK_KLASS_FUNC) +#undef WK_KLASS_FUNC + ciInstance* NullPointerException_instance() { assert(_NullPointerException_instance != NULL, "initialization problem"); return _NullPointerException_instance; @@ -324,6 +313,9 @@ public: ciInstance* ArrayStoreException_instance(); ciInstance* ClassCastException_instance(); + ciInstance* the_null_string(); + ciInstance* the_min_jint_string(); + static ciSymbol* unloaded_cisymbol() { return _unloaded_cisymbol; } diff --git a/hotspot/src/share/vm/ci/ciExceptionHandler.cpp b/hotspot/src/share/vm/ci/ciExceptionHandler.cpp index 209f00e5b86..79f6ccec50f 100644 --- a/hotspot/src/share/vm/ci/ciExceptionHandler.cpp +++ b/hotspot/src/share/vm/ci/ciExceptionHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2003 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 @@ -34,12 +34,16 @@ // // Get the exception klass that this handler catches. ciInstanceKlass* ciExceptionHandler::catch_klass() { + VM_ENTRY_MARK; assert(!is_catch_all(), "bad index"); if (_catch_klass == NULL) { bool will_link; - ciKlass* k = CURRENT_ENV->get_klass_by_index(_loading_klass, + assert(_loading_klass->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool"); + constantPoolHandle cpool(_loading_klass->get_instanceKlass()->constants()); + ciKlass* k = CURRENT_ENV->get_klass_by_index(cpool, _catch_klass_index, - will_link); + will_link, + _loading_klass); if (!will_link && k->is_loaded()) { GUARDED_VM_ENTRY( k = CURRENT_ENV->get_unloaded_klass(_loading_klass, k->name()); diff --git a/hotspot/src/share/vm/ci/ciField.cpp b/hotspot/src/share/vm/ci/ciField.cpp index ed66c1781c4..39a5651dc68 100644 --- a/hotspot/src/share/vm/ci/ciField.cpp +++ b/hotspot/src/share/vm/ci/ciField.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 @@ -86,7 +86,7 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) { bool ignore; // This is not really a class reference; the index always refers to the // field's type signature, as a symbol. Linkage checks do not apply. - _type = ciEnv::current(thread)->get_klass_by_index(klass, sig_index, ignore); + _type = ciEnv::current(thread)->get_klass_by_index(cpool, sig_index, ignore, klass); } else { _type = ciType::make(field_type); } @@ -100,9 +100,9 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) { int holder_index = cpool->klass_ref_index_at(index); bool holder_is_accessible; ciInstanceKlass* declared_holder = - ciEnv::current(thread)->get_klass_by_index(klass, holder_index, - holder_is_accessible) - ->as_instance_klass(); + ciEnv::current(thread)->get_klass_by_index(cpool, holder_index, + holder_is_accessible, + klass)->as_instance_klass(); // The declared holder of this field may not have been loaded. // Bail out with partial field information. @@ -161,6 +161,18 @@ ciField::ciField(fieldDescriptor *fd): _known_to_link_with(NULL) { "bootstrap classes must not create & cache unshared fields"); } +static bool trust_final_non_static_fields(ciInstanceKlass* holder) { + if (holder == NULL) + return false; + if (holder->name() == ciSymbol::java_lang_System()) + // Never trust strangely unstable finals: System.out, etc. + return false; + // Even if general trusting is disabled, trust system-built closures in these packages. + if (holder->is_in_package("java/dyn") || holder->is_in_package("sun/dyn")) + return true; + return TrustFinalNonStaticFields; +} + void ciField::initialize_from(fieldDescriptor* fd) { // Get the flags, offset, and canonical holder of the field. _flags = ciFlags(fd->access_flags()); @@ -168,8 +180,18 @@ void ciField::initialize_from(fieldDescriptor* fd) { _holder = CURRENT_ENV->get_object(fd->field_holder())->as_instance_klass(); // Check to see if the field is constant. - if (_holder->is_initialized() && - this->is_final() && this->is_static()) { + if (_holder->is_initialized() && this->is_final()) { + if (!this->is_static()) { + // A field can be constant if it's a final static field or if it's + // a final non-static field of a trusted class ({java,sun}.dyn). + if (trust_final_non_static_fields(_holder)) { + _is_constant = true; + return; + } + _is_constant = false; + return; + } + // This field just may be constant. The only cases where it will // not be constant are: // @@ -182,8 +204,8 @@ void ciField::initialize_from(fieldDescriptor* fd) { // java.lang.System.out, and java.lang.System.err. klassOop k = _holder->get_klassOop(); - assert( SystemDictionary::system_klass() != NULL, "Check once per vm"); - if( k == SystemDictionary::system_klass() ) { + assert( SystemDictionary::System_klass() != NULL, "Check once per vm"); + if( k == SystemDictionary::System_klass() ) { // Check offsets for case 2: System.in, System.out, or System.err if( _offset == java_lang_System::in_offset_in_bytes() || _offset == java_lang_System::out_offset_in_bytes() || diff --git a/hotspot/src/share/vm/ci/ciField.hpp b/hotspot/src/share/vm/ci/ciField.hpp index 193d848d41c..ffe1f925e2c 100644 --- a/hotspot/src/share/vm/ci/ciField.hpp +++ b/hotspot/src/share/vm/ci/ciField.hpp @@ -138,10 +138,18 @@ public: // Get the constant value of this field. ciConstant constant_value() { - assert(is_constant(), "illegal call to constant_value()"); + assert(is_static() && is_constant(), "illegal call to constant_value()"); return _constant_value; } + // Get the constant value of non-static final field in the given + // object. + ciConstant constant_value_of(ciObject* object) { + assert(!is_static() && is_constant(), "only if field is non-static constant"); + assert(object->is_instance(), "must be instance"); + return object->as_instance()->field_value(this); + } + // Check for link time errors. Accessing a field from a // certain class via a certain bytecode may or may not be legal. // This call checks to see if an exception may be raised by diff --git a/hotspot/src/share/vm/ci/ciInstance.cpp b/hotspot/src/share/vm/ci/ciInstance.cpp index 9d07a4a6229..c377a739ba3 100644 --- a/hotspot/src/share/vm/ci/ciInstance.cpp +++ b/hotspot/src/share/vm/ci/ciInstance.cpp @@ -36,7 +36,7 @@ ciType* ciInstance::java_mirror_type() { VM_ENTRY_MARK; oop m = get_oop(); // Return NULL if it is not java.lang.Class. - if (m == NULL || m->klass() != SystemDictionary::class_klass()) { + if (m == NULL || m->klass() != SystemDictionary::Class_klass()) { return NULL; } // Return either a primitive type or a klass. diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp index 1053727a93f..60fabd0bac8 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp @@ -75,7 +75,7 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : _java_mirror = NULL; if (is_shared()) { - if (h_k() != SystemDictionary::object_klass()) { + if (h_k() != SystemDictionary::Object_klass()) { super(); } java_mirror(); @@ -232,8 +232,48 @@ bool ciInstanceKlass::is_java_lang_Object() { // ------------------------------------------------------------------ // ciInstanceKlass::uses_default_loader bool ciInstanceKlass::uses_default_loader() { - VM_ENTRY_MARK; - return loader() == NULL; + // Note: We do not need to resolve the handle or enter the VM + // in order to test null-ness. + return _loader == NULL; +} + +// ------------------------------------------------------------------ +// ciInstanceKlass::is_in_package +// +// Is this klass in the given package? +bool ciInstanceKlass::is_in_package(const char* packagename, int len) { + // To avoid class loader mischief, this test always rejects application classes. + if (!uses_default_loader()) + return false; + GUARDED_VM_ENTRY( + return is_in_package_impl(packagename, len); + ) +} + +bool ciInstanceKlass::is_in_package_impl(const char* packagename, int len) { + ASSERT_IN_VM; + + // If packagename contains trailing '/' exclude it from the + // prefix-test since we test for it explicitly. + if (packagename[len - 1] == '/') + len--; + + if (!name()->starts_with(packagename, len)) + return false; + + // Test if the class name is something like "java/lang". + if ((len + 1) > name()->utf8_length()) + return false; + + // Test for trailing '/' + if ((char) name()->byte_at(len) != '/') + return false; + + // Make sure it's not actually in a subpackage: + if (name()->index_of_at(len+1, "/", 1) >= 0) + return false; + + return true; } // ------------------------------------------------------------------ @@ -340,6 +380,20 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static) return field; } +// ------------------------------------------------------------------ +// ciInstanceKlass::get_field_by_name +ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) { + VM_ENTRY_MARK; + instanceKlass* k = get_instanceKlass(); + fieldDescriptor fd; + klassOop def = k->find_field(name->get_symbolOop(), signature->get_symbolOop(), is_static, &fd); + if (def == NULL) { + return NULL; + } + ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd); + return field; +} + // ------------------------------------------------------------------ // ciInstanceKlass::non_static_fields. diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp index a60020adc34..29aeffa01f3 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp @@ -29,10 +29,11 @@ // be loaded. class ciInstanceKlass : public ciKlass { CI_PACKAGE_ACCESS + friend class ciBytecodeStream; friend class ciEnv; + friend class ciExceptionHandler; friend class ciMethod; friend class ciField; - friend class ciBytecodeStream; private: jobject _loader; @@ -78,6 +79,8 @@ protected: const char* type_string() { return "ciInstanceKlass"; } + bool is_in_package_impl(const char* packagename, int len); + void print_impl(outputStream* st); ciConstantPoolCache* field_cache(); @@ -148,6 +151,7 @@ public: ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); + ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); GrowableArray* non_static_fields(); @@ -195,6 +199,12 @@ public: bool is_java_lang_Object(); + // Is this klass in the given package? + bool is_in_package(const char* packagename) { + return is_in_package(packagename, (int) strlen(packagename)); + } + bool is_in_package(const char* packagename, int len); + // What kind of ciObject is this? bool is_instance_klass() { return true; } bool is_java_klass() { return true; } diff --git a/hotspot/src/share/vm/ci/ciKlass.cpp b/hotspot/src/share/vm/ci/ciKlass.cpp index ac5da354422..b0f28620ab2 100644 --- a/hotspot/src/share/vm/ci/ciKlass.cpp +++ b/hotspot/src/share/vm/ci/ciKlass.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/ci/ciKlass.hpp b/hotspot/src/share/vm/ci/ciKlass.hpp index 1f2571718bc..3f1c6d7aa45 100644 --- a/hotspot/src/share/vm/ci/ciKlass.hpp +++ b/hotspot/src/share/vm/ci/ciKlass.hpp @@ -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 @@ -69,7 +69,7 @@ public: ciKlass(KlassHandle k_h); // What is the name of this klass? - ciSymbol* name() { return _name; } + ciSymbol* name() const { return _name; } // What is its layout helper value? jint layout_helper() { return _layout_helper; } diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index f83429c1adf..3a271b3f226 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -687,7 +687,7 @@ int ciMethod::scale_count(int count, float prof_factor) { // ------------------------------------------------------------------ // invokedynamic support // -bool ciMethod::is_method_handle_invoke() { +bool ciMethod::is_method_handle_invoke() const { check_is_loaded(); bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS); #ifdef ASSERT @@ -700,6 +700,12 @@ bool ciMethod::is_method_handle_invoke() { return flag; } +bool ciMethod::is_method_handle_adapter() const { + check_is_loaded(); + VM_ENTRY_MARK; + return get_methodOop()->is_method_handle_adapter(); +} + ciInstance* ciMethod::method_handle_type() { check_is_loaded(); VM_ENTRY_MARK; diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 1b65bc90c50..d574fa07b71 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,6 +38,8 @@ class ciMethod : public ciObject { CI_PACKAGE_ACCESS friend class ciEnv; friend class ciExceptionHandlerStream; + friend class ciBytecodeStream; + friend class ciMethodHandle; private: // General method information. @@ -213,7 +215,10 @@ class ciMethod : public ciObject { bool check_call(int refinfo_index, bool is_static) const; void build_method_data(); // make sure it exists in the VM also int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC - bool is_method_handle_invoke(); + + // JSR 292 support + bool is_method_handle_invoke() const; + bool is_method_handle_adapter() const; ciInstance* method_handle_type(); // What kind of ciObject is this? @@ -251,4 +256,10 @@ class ciMethod : public ciObject { // Print the name of this method in various incarnations. void print_name(outputStream* st = tty); void print_short_name(outputStream* st = tty); + + methodOop get_method_handle_target() { + klassOop receiver_limit_oop = NULL; + int flags = 0; + return MethodHandles::decode_method(get_oop(), receiver_limit_oop, flags); + } }; diff --git a/hotspot/src/share/vm/ci/ciMethodHandle.cpp b/hotspot/src/share/vm/ci/ciMethodHandle.cpp new file mode 100644 index 00000000000..d9612192bf8 --- /dev/null +++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp @@ -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. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_ciMethodHandle.cpp.incl" + +// ciMethodHandle + +// ------------------------------------------------------------------ +// ciMethodHandle::get_adapter +// +// Return an adapter for this MethodHandle. +ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const { + VM_ENTRY_MARK; + + Handle h(get_oop()); + methodHandle callee(_callee->get_methodOop()); + MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD); + methodHandle m = mhc.compile(CHECK_NULL); + return CURRENT_ENV->get_object(m())->as_method(); +} + + +// ------------------------------------------------------------------ +// ciMethodHandle::print_impl +// +// Implementation of the print method. +void ciMethodHandle::print_impl(outputStream* st) { + st->print(" type="); + get_oop()->print(); +} diff --git a/hotspot/src/share/vm/ci/ciMethodHandle.hpp b/hotspot/src/share/vm/ci/ciMethodHandle.hpp new file mode 100644 index 00000000000..26d317f248d --- /dev/null +++ b/hotspot/src/share/vm/ci/ciMethodHandle.hpp @@ -0,0 +1,56 @@ +/* + * 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. + * + */ + +// ciMethodHandle +// +// The class represents a java.dyn.MethodHandle object. +class ciMethodHandle : public ciInstance { +private: + ciMethod* _callee; + + // Return an adapter for this MethodHandle. + ciMethod* get_adapter(bool is_invokedynamic) const; + +protected: + void print_impl(outputStream* st); + +public: + ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {}; + + // What kind of ciObject is this? + bool is_method_handle() const { return true; } + + ciMethod* callee() const { return _callee; } + void set_callee(ciMethod* m) { _callee = m; } + + // Return an adapter for a MethodHandle call. + ciMethod* get_method_handle_adapter() const { + return get_adapter(false); + } + + // Return an adapter for an invokedynamic call. + ciMethod* get_invokedynamic_adapter() const { + return get_adapter(true); + } +}; diff --git a/hotspot/src/share/vm/ci/ciObject.hpp b/hotspot/src/share/vm/ci/ciObject.hpp index 8d5e6b7f4dd..1f38e9c7109 100644 --- a/hotspot/src/share/vm/ci/ciObject.hpp +++ b/hotspot/src/share/vm/ci/ciObject.hpp @@ -131,9 +131,12 @@ public: // What kind of ciObject is this? virtual bool is_null_object() const { return false; } + virtual bool is_call_site() const { return false; } + virtual bool is_cpcache() const { return false; } virtual bool is_instance() { return false; } virtual bool is_method() { return false; } virtual bool is_method_data() { return false; } + virtual bool is_method_handle() const { return false; } virtual bool is_array() { return false; } virtual bool is_obj_array() { return false; } virtual bool is_type_array() { return false; } @@ -185,6 +188,14 @@ public: assert(is_null_object(), "bad cast"); return (ciNullObject*)this; } + ciCallSite* as_call_site() { + assert(is_call_site(), "bad cast"); + return (ciCallSite*) this; + } + ciCPCache* as_cpcache() { + assert(is_cpcache(), "bad cast"); + return (ciCPCache*) this; + } ciInstance* as_instance() { assert(is_instance(), "bad cast"); return (ciInstance*)this; @@ -197,6 +208,10 @@ public: assert(is_method_data(), "bad cast"); return (ciMethodData*)this; } + ciMethodHandle* as_method_handle() { + assert(is_method_handle(), "bad cast"); + return (ciMethodHandle*) this; + } ciArray* as_array() { assert(is_array(), "bad cast"); return (ciArray*)this; diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.cpp b/hotspot/src/share/vm/ci/ciObjectFactory.cpp index 6fb4edc4d9c..cfbdf1659eb 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp @@ -144,30 +144,13 @@ void ciObjectFactory::init_shared_objects() { ciEnv::_obj_array_klass_klass_instance = get(Universe::objArrayKlassKlassObj()) ->as_obj_array_klass_klass(); - ciEnv::_ArrayStoreException = - get(SystemDictionary::ArrayStoreException_klass()) - ->as_instance_klass(); - ciEnv::_Class = - get(SystemDictionary::class_klass()) - ->as_instance_klass(); - ciEnv::_ClassCastException = - get(SystemDictionary::ClassCastException_klass()) - ->as_instance_klass(); - ciEnv::_Object = - get(SystemDictionary::object_klass()) - ->as_instance_klass(); - ciEnv::_Throwable = - get(SystemDictionary::throwable_klass()) - ->as_instance_klass(); - ciEnv::_Thread = - get(SystemDictionary::thread_klass()) - ->as_instance_klass(); - ciEnv::_OutOfMemoryError = - get(SystemDictionary::OutOfMemoryError_klass()) - ->as_instance_klass(); - ciEnv::_String = - get(SystemDictionary::string_klass()) - ->as_instance_klass(); + +#define WK_KLASS_DEFN(name, ignore_s, opt) \ + if (SystemDictionary::name() != NULL) \ + ciEnv::_##name = get(SystemDictionary::name())->as_instance_klass(); + + WK_KLASSES_DO(WK_KLASS_DEFN) +#undef WK_KLASS_DEFN for (int len = -1; len != _ci_objects->length(); ) { len = _ci_objects->length(); @@ -324,13 +307,21 @@ ciObject* ciObjectFactory::create_new_object(oop o) { return new (arena()) ciMethodData(h_md); } else if (o->is_instance()) { instanceHandle h_i(THREAD, (instanceOop)o); - return new (arena()) ciInstance(h_i); + if (java_dyn_CallSite::is_instance(o)) + return new (arena()) ciCallSite(h_i); + else if (java_dyn_MethodHandle::is_instance(o)) + return new (arena()) ciMethodHandle(h_i); + else + return new (arena()) ciInstance(h_i); } else if (o->is_objArray()) { objArrayHandle h_oa(THREAD, (objArrayOop)o); return new (arena()) ciObjArray(h_oa); } else if (o->is_typeArray()) { typeArrayHandle h_ta(THREAD, (typeArrayOop)o); return new (arena()) ciTypeArray(h_ta); + } else if (o->is_constantPoolCache()) { + constantPoolCacheHandle h_cpc(THREAD, (constantPoolCacheOop) o); + return new (arena()) ciCPCache(h_cpc); } // The oop is of some type not supported by the compiler interface. @@ -567,7 +558,7 @@ ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) { if (key->is_perm() && _non_perm_count == 0) { return emptyBucket; } else if (key->is_instance()) { - if (key->klass() == SystemDictionary::class_klass()) { + if (key->klass() == SystemDictionary::Class_klass()) { // class mirror instances are always perm return emptyBucket; } diff --git a/hotspot/src/share/vm/ci/ciStreams.cpp b/hotspot/src/share/vm/ci/ciStreams.cpp index d343ab8446d..52f17c33b47 100644 --- a/hotspot/src/share/vm/ci/ciStreams.cpp +++ b/hotspot/src/share/vm/ci/ciStreams.cpp @@ -186,8 +186,9 @@ int ciBytecodeStream::get_klass_index() const { // If this bytecode is a new, newarray, multianewarray, instanceof, // or checkcast, get the referenced klass. ciKlass* ciBytecodeStream::get_klass(bool& will_link) { - return CURRENT_ENV->get_klass_by_index(_holder, get_klass_index(), - will_link); + VM_ENTRY_MARK; + constantPoolHandle cpool(_method->get_methodOop()->constants()); + return CURRENT_ENV->get_klass_by_index(cpool, get_klass_index(), will_link, _holder); } // ------------------------------------------------------------------ @@ -213,7 +214,9 @@ int ciBytecodeStream::get_constant_index() const { // If this bytecode is one of the ldc variants, get the referenced // constant. ciConstant ciBytecodeStream::get_constant() { - return CURRENT_ENV->get_constant_by_index(_holder, get_constant_index()); + VM_ENTRY_MARK; + constantPoolHandle cpool(_method->get_methodOop()->constants()); + return CURRENT_ENV->get_constant_by_index(cpool, get_constant_index(), _holder); } // ------------------------------------------------------------------ @@ -264,9 +267,11 @@ ciField* ciBytecodeStream::get_field(bool& will_link) { // There is no "will_link" result passed back. The user is responsible // for checking linkability when retrieving the associated field. ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() { + VM_ENTRY_MARK; + constantPoolHandle cpool(_method->get_methodOop()->constants()); int holder_index = get_field_holder_index(); bool ignore; - return CURRENT_ENV->get_klass_by_index(_holder, holder_index, ignore) + return CURRENT_ENV->get_klass_by_index(cpool, holder_index, ignore, _holder) ->as_instance_klass(); } @@ -277,9 +282,10 @@ ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() { // referenced by the current bytecode. Used for generating // deoptimization information. int ciBytecodeStream::get_field_holder_index() { - VM_ENTRY_MARK; - constantPoolOop cpool = _holder->get_instanceKlass()->constants(); - return cpool->klass_ref_index_at(get_field_index()); + GUARDED_VM_ENTRY( + constantPoolOop cpool = _holder->get_instanceKlass()->constants(); + return cpool->klass_ref_index_at(get_field_index()); + ) } // ------------------------------------------------------------------ @@ -321,7 +327,9 @@ int ciBytecodeStream::get_method_index() { // // If this is a method invocation bytecode, get the invoked method. ciMethod* ciBytecodeStream::get_method(bool& will_link) { - ciMethod* m = CURRENT_ENV->get_method_by_index(_holder, get_method_index(),cur_bc()); + VM_ENTRY_MARK; + constantPoolHandle cpool(_method->get_methodOop()->constants()); + ciMethod* m = CURRENT_ENV->get_method_by_index(cpool, get_method_index(), cur_bc(), _holder); will_link = m->is_loaded(); return m; } @@ -338,11 +346,13 @@ ciMethod* ciBytecodeStream::get_method(bool& will_link) { // There is no "will_link" result passed back. The user is responsible // for checking linkability when retrieving the associated method. ciKlass* ciBytecodeStream::get_declared_method_holder() { + VM_ENTRY_MARK; + constantPoolHandle cpool(_method->get_methodOop()->constants()); bool ignore; - // report as Dynamic for invokedynamic, which is syntactically classless + // report as InvokeDynamic for invokedynamic, which is syntactically classless if (cur_bc() == Bytecodes::_invokedynamic) - return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_Dynamic(), false); - return CURRENT_ENV->get_klass_by_index(_holder, get_method_holder_index(), ignore); + return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_InvokeDynamic(), false); + return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder); } // ------------------------------------------------------------------ @@ -352,8 +362,7 @@ ciKlass* ciBytecodeStream::get_declared_method_holder() { // referenced by the current bytecode. Used for generating // deoptimization information. int ciBytecodeStream::get_method_holder_index() { - VM_ENTRY_MARK; - constantPoolOop cpool = _holder->get_instanceKlass()->constants(); + constantPoolOop cpool = _method->get_methodOop()->constants(); return cpool->klass_ref_index_at(get_method_index()); } @@ -370,3 +379,31 @@ int ciBytecodeStream::get_method_signature_index() { int name_and_type_index = cpool->name_and_type_ref_index_at(method_index); return cpool->signature_ref_index_at(name_and_type_index); } + +// ------------------------------------------------------------------ +// ciBytecodeStream::get_cpcache +ciCPCache* ciBytecodeStream::get_cpcache() { + VM_ENTRY_MARK; + // Get the constant pool. + constantPoolOop cpool = _holder->get_instanceKlass()->constants(); + constantPoolCacheOop cpcache = cpool->cache(); + + return CURRENT_ENV->get_object(cpcache)->as_cpcache(); +} + +// ------------------------------------------------------------------ +// ciBytecodeStream::get_call_site +ciCallSite* ciBytecodeStream::get_call_site() { + VM_ENTRY_MARK; + // Get the constant pool. + constantPoolOop cpool = _holder->get_instanceKlass()->constants(); + constantPoolCacheOop cpcache = cpool->cache(); + + // Get the CallSite from the constant pool cache. + int method_index = get_method_index(); + ConstantPoolCacheEntry* cpcache_entry = cpcache->secondary_entry_at(method_index); + oop call_site_oop = cpcache_entry->f1(); + + // Create a CallSite object and return it. + return CURRENT_ENV->get_object(call_site_oop)->as_call_site(); +} diff --git a/hotspot/src/share/vm/ci/ciStreams.hpp b/hotspot/src/share/vm/ci/ciStreams.hpp index 448e27cb16a..97a046f132f 100644 --- a/hotspot/src/share/vm/ci/ciStreams.hpp +++ b/hotspot/src/share/vm/ci/ciStreams.hpp @@ -232,6 +232,9 @@ public: int get_method_holder_index(); int get_method_signature_index(); + ciCPCache* get_cpcache(); + ciCallSite* get_call_site(); + private: void assert_index_size(int required_size) const { #ifdef ASSERT diff --git a/hotspot/src/share/vm/ci/ciSymbol.cpp b/hotspot/src/share/vm/ci/ciSymbol.cpp index 7284893e81d..e534f04c3de 100644 --- a/hotspot/src/share/vm/ci/ciSymbol.cpp +++ b/hotspot/src/share/vm/ci/ciSymbol.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 @@ -59,6 +59,22 @@ int ciSymbol::byte_at(int i) { GUARDED_VM_ENTRY(return get_symbolOop()->byte_at(i);) } +// ------------------------------------------------------------------ +// ciSymbol::starts_with +// +// Tests if the symbol starts with the given prefix. +bool ciSymbol::starts_with(const char* prefix, int len) const { + GUARDED_VM_ENTRY(return get_symbolOop()->starts_with(prefix, len);) +} + +// ------------------------------------------------------------------ +// ciSymbol::index_of +// +// Determines where the symbol contains the given substring. +int ciSymbol::index_of_at(int i, const char* str, int len) const { + GUARDED_VM_ENTRY(return get_symbolOop()->index_of_at(i, str, len);) +} + // ------------------------------------------------------------------ // ciSymbol::utf8_length int ciSymbol::utf8_length() { diff --git a/hotspot/src/share/vm/ci/ciSymbol.hpp b/hotspot/src/share/vm/ci/ciSymbol.hpp index 701fb8023d7..abb3088edbf 100644 --- a/hotspot/src/share/vm/ci/ciSymbol.hpp +++ b/hotspot/src/share/vm/ci/ciSymbol.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2001 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 @@ -28,6 +28,7 @@ // machine. class ciSymbol : public ciObject { CI_PACKAGE_ACCESS + // These friends all make direct use of get_symbolOop: friend class ciEnv; friend class ciInstanceKlass; friend class ciSignature; @@ -38,13 +39,13 @@ private: ciSymbol(symbolOop s) : ciObject(s) {} ciSymbol(symbolHandle s); // for use with vmSymbolHandles - symbolOop get_symbolOop() { return (symbolOop)get_oop(); } + symbolOop get_symbolOop() const { return (symbolOop)get_oop(); } const char* type_string() { return "ciSymbol"; } void print_impl(outputStream* st); - int byte_at(int i); + // This is public in symbolOop but private here, because the base can move: jbyte* base(); // Make a ciSymbol from a C string (implementation). @@ -55,6 +56,15 @@ public: const char* as_utf8(); int utf8_length(); + // Return the i-th utf8 byte, where i < utf8_length + int byte_at(int i); + + // Tests if the symbol starts with the given prefix. + bool starts_with(const char* prefix, int len) const; + + // Determines where the symbol contains the given substring. + int index_of_at(int i, const char* str, int len) const; + // What kind of ciObject is this? bool is_symbol() { return true; } diff --git a/hotspot/src/share/vm/ci/ciType.cpp b/hotspot/src/share/vm/ci/ciType.cpp index ca2c79a102a..e94af7d89a4 100644 --- a/hotspot/src/share/vm/ci/ciType.cpp +++ b/hotspot/src/share/vm/ci/ciType.cpp @@ -111,7 +111,7 @@ ciType* ciType::make(BasicType t) { // short, etc. // Note: Bare T_ADDRESS means a raw pointer type, not a return_address. assert((uint)t < T_CONFLICT+1, "range check"); - if (t == T_OBJECT) return ciEnv::_Object; // java/lang/Object + if (t == T_OBJECT) return ciEnv::_Object_klass; // java/lang/Object assert(_basic_types[t] != NULL, "domain check"); return _basic_types[t]; } diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index d21ea761a4f..4aceca8410a 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -635,8 +635,15 @@ void ciTypeFlow::StateVector::do_invoke(ciBytecodeStream* str, ciMethod* method = str->get_method(will_link); if (!will_link) { // We weren't able to find the method. - ciKlass* unloaded_holder = method->holder(); - trap(str, unloaded_holder, str->get_method_holder_index()); + if (str->cur_bc() == Bytecodes::_invokedynamic) { + trap(str, NULL, + Deoptimization::make_trap_request + (Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret)); + } else { + ciKlass* unloaded_holder = method->holder(); + trap(str, unloaded_holder, str->get_method_holder_index()); + } } else { ciSignature* signature = method->signature(); ciSignatureStream sigstr(signature); @@ -1292,8 +1299,8 @@ bool ciTypeFlow::StateVector::apply_one_bytecode(ciBytecodeStream* str) { case Bytecodes::_invokeinterface: do_invoke(str, true); break; case Bytecodes::_invokespecial: do_invoke(str, true); break; case Bytecodes::_invokestatic: do_invoke(str, false); break; - case Bytecodes::_invokevirtual: do_invoke(str, true); break; + case Bytecodes::_invokedynamic: do_invoke(str, false); break; case Bytecodes::_istore: store_local_int(str->get_index()); break; case Bytecodes::_istore_0: store_local_int(0); break; diff --git a/hotspot/src/share/vm/ci/ciUtilities.hpp b/hotspot/src/share/vm/ci/ciUtilities.hpp index 163e8089b65..709752d0d14 100644 --- a/hotspot/src/share/vm/ci/ciUtilities.hpp +++ b/hotspot/src/share/vm/ci/ciUtilities.hpp @@ -79,7 +79,7 @@ THREAD); \ if (HAS_PENDING_EXCEPTION) { \ if (PENDING_EXCEPTION->klass() == \ - SystemDictionary::threaddeath_klass()) { \ + SystemDictionary::ThreadDeath_klass()) { \ /* Kill the compilation. */ \ fatal("unhandled ci exception"); \ return (result); \ diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 8235db6f082..8671af37de6 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -430,7 +430,7 @@ void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Hand case JVM_CONSTANT_UnresolvedClass : // Patching a class means pre-resolving it. // The name in the constant pool is ignored. - if (patch->klass() == SystemDictionary::class_klass()) { // %%% java_lang_Class::is_instance + if (patch->klass() == SystemDictionary::Class_klass()) { // %%% java_lang_Class::is_instance guarantee_property(!java_lang_Class::is_primitive(patch()), "Illegal class patch at %d in class file %s", index, CHECK); @@ -643,7 +643,7 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK); break; case T_OBJECT: - guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;", 18) + guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;") && (value_type.is_string() || value_type.is_unresolved_string())), "Bad string initial value in class file %s", CHECK); break; @@ -1718,9 +1718,7 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf m->set_exception_table(exception_handlers()); // Copy byte codes - if (code_length > 0) { - memcpy(m->code_base(), code_start, code_length); - } + m->set_code(code_start); // Copy line number table if (linenumber_table != NULL) { @@ -2511,23 +2509,12 @@ void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp, fac_ptr->nonstatic_byte_count -= 1; (*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index); - if (wordSize == jintSize) { - fac_ptr->nonstatic_word_count += 1; - } else { - fac_ptr->nonstatic_double_count += 1; - } + fac_ptr->nonstatic_word_count += 1; - FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4); + FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i + instanceKlass::low_offset); assert(atype == NONSTATIC_BYTE, ""); FieldAllocationType new_atype = NONSTATIC_WORD; - if (wordSize > jintSize) { - if (Universe::field_type_should_be_aligned(T_LONG)) { - atype = NONSTATIC_ALIGNED_DOUBLE; - } else { - atype = NONSTATIC_DOUBLE; - } - } - (*fields_ptr)->ushort_at_put(i+4, new_atype); + (*fields_ptr)->ushort_at_put(i + instanceKlass::low_offset, new_atype); found_vmentry = true; break; @@ -3085,7 +3072,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, int len = fields->length(); for (int i = 0; i < len; i += instanceKlass::next_offset) { int real_offset; - FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i+4); + FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset); switch (atype) { case STATIC_OOP: real_offset = next_static_oop_offset; @@ -3173,8 +3160,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, default: ShouldNotReachHere(); } - fields->short_at_put(i+4, extract_low_short_from_int(real_offset) ); - fields->short_at_put(i+5, extract_high_short_from_int(real_offset) ); + fields->short_at_put(i + instanceKlass::low_offset, extract_low_short_from_int(real_offset)); + fields->short_at_put(i + instanceKlass::high_offset, extract_high_short_from_int(real_offset)); } // Size of instances @@ -3482,8 +3469,8 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { #endif // Check if this klass supports the java.lang.Cloneable interface - if (SystemDictionary::cloneable_klass_loaded()) { - if (k->is_subtype_of(SystemDictionary::cloneable_klass())) { + if (SystemDictionary::Cloneable_klass_loaded()) { + if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) { k->set_is_cloneable(); } } @@ -3766,8 +3753,9 @@ bool ClassFileParser::has_illegal_visibility(jint flags) { } bool ClassFileParser::is_supported_version(u2 major, u2 minor) { - u2 max_version = JDK_Version::is_gte_jdk17x_version() ? - JAVA_MAX_SUPPORTED_VERSION : JAVA_6_VERSION; + u2 max_version = + JDK_Version::is_gte_jdk17x_version() ? JAVA_MAX_SUPPORTED_VERSION : + (JDK_Version::is_gte_jdk16x_version() ? JAVA_6_VERSION : JAVA_1_5_VERSION); return (major >= JAVA_MIN_SUPPORTED_VERSION) && (major <= max_version) && ((major != max_version) || @@ -4188,7 +4176,7 @@ char* ClassFileParser::skip_over_field_name(char* name, bool slash_ok, unsigned // Check if ch is Java identifier start or is Java identifier part // 4672820: call java.lang.Character methods directly without generating separate tables. EXCEPTION_MARK; - instanceKlassHandle klass (THREAD, SystemDictionary::char_klass()); + instanceKlassHandle klass (THREAD, SystemDictionary::Character_klass()); // return value JavaValue result(T_BOOLEAN); diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 669beb7ff32..2fb9de039bc 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -819,7 +819,7 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) { _package_hash_table->copy_pkgnames(packages); } // Allocate objArray and fill with java.lang.String - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), nof_entries, CHECK_0); objArrayHandle result(THREAD, r); for (int i = 0; i < nof_entries; i++) { diff --git a/hotspot/src/share/vm/classfile/javaAssertions.cpp b/hotspot/src/share/vm/classfile/javaAssertions.cpp index 8f318e6a426..551dd2acd86 100644 --- a/hotspot/src/share/vm/classfile/javaAssertions.cpp +++ b/hotspot/src/share/vm/classfile/javaAssertions.cpp @@ -95,14 +95,14 @@ oop JavaAssertions::createAssertionStatusDirectives(TRAPS) { int len; typeArrayOop t; len = OptionList::count(_packages); - objArrayOop pn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL); + objArrayOop pn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL); objArrayHandle pkgNames (THREAD, pn); t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL); typeArrayHandle pkgEnabled(THREAD, t); fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL); len = OptionList::count(_classes); - objArrayOop cn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL); + objArrayOop cn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL); objArrayHandle classNames (THREAD, cn); t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL); typeArrayHandle classEnabled(THREAD, t); diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index cc0db7a173b..173f2e26e5d 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -68,9 +68,9 @@ Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) { // and the char array it points to end up in the same cache line. oop obj; if (tenured) { - obj = instanceKlass::cast(SystemDictionary::string_klass())->allocate_permanent_instance(CHECK_NH); + obj = instanceKlass::cast(SystemDictionary::String_klass())->allocate_permanent_instance(CHECK_NH); } else { - obj = instanceKlass::cast(SystemDictionary::string_klass())->allocate_instance(CHECK_NH); + obj = instanceKlass::cast(SystemDictionary::String_klass())->allocate_instance(CHECK_NH); } // Create the char array. The String object must be handlized here @@ -293,7 +293,7 @@ char* java_lang_String::as_utf8_string(oop java_string, int start, int len) { bool java_lang_String::equals(oop java_string, jchar* chars, int len) { assert(SharedSkipVerify || - java_string->klass() == SystemDictionary::string_klass(), + java_string->klass() == SystemDictionary::String_klass(), "must be java_string"); typeArrayOop value = java_lang_String::value(java_string); int offset = java_lang_String::offset(java_string); @@ -311,7 +311,7 @@ bool java_lang_String::equals(oop java_string, jchar* chars, int len) { void java_lang_String::print(Handle java_string, outputStream* st) { oop obj = java_string(); - assert(obj->klass() == SystemDictionary::string_klass(), "must be java_string"); + assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string"); typeArrayOop value = java_lang_String::value(obj); int offset = java_lang_String::offset(obj); int length = java_lang_String::length(obj); @@ -339,9 +339,9 @@ oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) { // class is put into the system dictionary. int computed_modifiers = k->compute_modifier_flags(CHECK_0); k->set_modifier_flags(computed_modifiers); - if (SystemDictionary::class_klass_loaded()) { + if (SystemDictionary::Class_klass_loaded()) { // Allocate mirror (java.lang.Class instance) - Handle mirror = instanceKlass::cast(SystemDictionary::class_klass())->allocate_permanent_instance(CHECK_0); + Handle mirror = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); // Setup indirections mirror->obj_field_put(klass_offset, k()); k->set_java_mirror(mirror()); @@ -378,7 +378,7 @@ oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) { oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) - oop java_class = instanceKlass::cast(SystemDictionary::class_klass())->allocate_permanent_instance(CHECK_0); + oop java_class = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); if (type != T_VOID) { klassOop aklass = Universe::typeArrayKlassObj(type); assert(aklass != NULL, "correct bootstrap"); @@ -502,7 +502,7 @@ BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klas oop java_lang_Class::primitive_mirror(BasicType t) { oop mirror = Universe::java_mirror(t); - assert(mirror != NULL && mirror->is_a(SystemDictionary::class_klass()), "must be a Class"); + assert(mirror != NULL && mirror->is_a(SystemDictionary::Class_klass()), "must be a Class"); assert(java_lang_Class::is_primitive(mirror), "must be primitive"); return mirror; } @@ -515,14 +515,14 @@ void java_lang_Class::compute_offsets() { assert(!offsets_computed, "offsets should be initialized only once"); offsets_computed = true; - klassOop k = SystemDictionary::class_klass(); + klassOop k = SystemDictionary::Class_klass(); // The classRedefinedCount field is only present starting in 1.5, // so don't go fatal. compute_optional_offset(classRedefinedCount_offset, k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature()); // The field indicating parallelCapable (parallelLockMap) is only present starting in 7, - klassOop k1 = SystemDictionary::classloader_klass(); + klassOop k1 = SystemDictionary::ClassLoader_klass(); compute_optional_offset(parallelCapable_offset, k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature()); } @@ -588,7 +588,7 @@ int java_lang_Thread::_park_event_offset = 0 ; void java_lang_Thread::compute_offsets() { assert(_group_offset == 0, "offsets should be initialized only once"); - klassOop k = SystemDictionary::thread_klass(); + klassOop k = SystemDictionary::Thread_klass(); compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::char_array_signature()); compute_offset(_group_offset, k, vmSymbols::group_name(), vmSymbols::threadgroup_signature()); compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), vmSymbols::classloader_signature()); @@ -847,7 +847,7 @@ bool java_lang_ThreadGroup::is_vmAllowSuspension(oop java_thread_group) { void java_lang_ThreadGroup::compute_offsets() { assert(_parent_offset == 0, "offsets should be initialized only once"); - klassOop k = SystemDictionary::threadGroup_klass(); + klassOop k = SystemDictionary::ThreadGroup_klass(); compute_offset(_parent_offset, k, vmSymbols::parent_name(), vmSymbols::threadgroup_signature()); compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); @@ -1124,8 +1124,7 @@ class BacktraceBuilder: public StackObj { if (_dirty && _methods != NULL) { BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); - bs->write_ref_array(MemRegion((HeapWord*)_methods->base(), - _methods->array_size())); + bs->write_ref_array((HeapWord*)_methods->base(), _methods->length()); _dirty = false; } } @@ -1345,7 +1344,7 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t // No-op if stack trace is disabled if (!StackTraceInThrowable) return; - assert(throwable->is_a(SystemDictionary::throwable_klass()), "sanity check"); + assert(throwable->is_a(SystemDictionary::Throwable_klass()), "sanity check"); oop backtrace = java_lang_Throwable::backtrace(throwable()); assert(backtrace != NULL, "backtrace not preallocated"); @@ -1450,7 +1449,7 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4"); // Allocate java.lang.StackTraceElement instance - klassOop k = SystemDictionary::stackTraceElement_klass(); + klassOop k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); instanceKlassHandle ik (THREAD, k); if (ik->should_be_initialized()) { @@ -1488,7 +1487,7 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { void java_lang_reflect_AccessibleObject::compute_offsets() { - klassOop k = SystemDictionary::reflect_accessible_object_klass(); + klassOop k = SystemDictionary::reflect_AccessibleObject_klass(); compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); } @@ -1503,7 +1502,7 @@ void java_lang_reflect_AccessibleObject::set_override(oop reflect, jboolean valu } void java_lang_reflect_Method::compute_offsets() { - klassOop k = SystemDictionary::reflect_method_klass(); + klassOop k = SystemDictionary::reflect_Method_klass(); compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); compute_offset(returnType_offset, k, vmSymbols::returnType_name(), vmSymbols::class_signature()); @@ -1524,7 +1523,7 @@ void java_lang_reflect_Method::compute_offsets() { Handle java_lang_reflect_Method::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); - klassOop klass = SystemDictionary::reflect_method_klass(); + klassOop klass = SystemDictionary::reflect_Method_klass(); // This class is eagerly initialized during VM initialization, since we keep a refence // to one of the methods assert(instanceKlass::cast(klass)->is_initialized(), "must be initialized"); @@ -1666,7 +1665,7 @@ void java_lang_reflect_Method::set_annotation_default(oop method, oop value) { } void java_lang_reflect_Constructor::compute_offsets() { - klassOop k = SystemDictionary::reflect_constructor_klass(); + klassOop k = SystemDictionary::reflect_Constructor_klass(); compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature()); compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature()); @@ -1790,7 +1789,7 @@ void java_lang_reflect_Constructor::set_parameter_annotations(oop method, oop va } void java_lang_reflect_Field::compute_offsets() { - klassOop k = SystemDictionary::reflect_field_klass(); + klassOop k = SystemDictionary::reflect_Field_klass(); compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); compute_offset(type_offset, k, vmSymbols::type_name(), vmSymbols::class_signature()); @@ -1897,7 +1896,7 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) { void sun_reflect_ConstantPool::compute_offsets() { - klassOop k = SystemDictionary::reflect_constant_pool_klass(); + klassOop k = SystemDictionary::reflect_ConstantPool_klass(); // This null test can be removed post beta if (k != NULL) { compute_offset(_cp_oop_offset, k, vmSymbols::constantPoolOop_name(), vmSymbols::object_signature()); @@ -1907,7 +1906,7 @@ void sun_reflect_ConstantPool::compute_offsets() { Handle sun_reflect_ConstantPool::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); - klassOop k = SystemDictionary::reflect_constant_pool_klass(); + klassOop k = SystemDictionary::reflect_ConstantPool_klass(); instanceKlassHandle klass (THREAD, k); // Ensure it is initialized klass->initialize(CHECK_NH); @@ -1927,7 +1926,7 @@ void sun_reflect_ConstantPool::set_cp_oop(oop reflect, oop value) { } void sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() { - klassOop k = SystemDictionary::reflect_unsafe_static_field_accessor_impl_klass(); + klassOop k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass(); // This null test can be removed post beta if (k != NULL) { compute_offset(_base_offset, k, @@ -2073,7 +2072,7 @@ void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream* // Support for java_lang_ref_Reference oop java_lang_ref_Reference::pending_list_lock() { - instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass()); + instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); char *addr = (((char *)ik->start_of_static_fields()) + static_lock_offset); if (UseCompressedOops) { return oopDesc::load_decode_heap_oop((narrowOop *)addr); @@ -2083,7 +2082,7 @@ oop java_lang_ref_Reference::pending_list_lock() { } HeapWord *java_lang_ref_Reference::pending_list_addr() { - instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass()); + instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); char *addr = (((char *)ik->start_of_static_fields()) + static_pending_offset); // XXX This might not be HeapWord aligned, almost rather be char *. return (HeapWord*)addr; @@ -2106,17 +2105,17 @@ jlong java_lang_ref_SoftReference::timestamp(oop ref) { } jlong java_lang_ref_SoftReference::clock() { - instanceKlass* ik = instanceKlass::cast(SystemDictionary::soft_reference_klass()); + instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); int offset = ik->offset_of_static_fields() + static_clock_offset; - return SystemDictionary::soft_reference_klass()->long_field(offset); + return SystemDictionary::SoftReference_klass()->long_field(offset); } void java_lang_ref_SoftReference::set_clock(jlong value) { - instanceKlass* ik = instanceKlass::cast(SystemDictionary::soft_reference_klass()); + instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); int offset = ik->offset_of_static_fields() + static_clock_offset; - SystemDictionary::soft_reference_klass()->long_field_put(offset, value); + SystemDictionary::SoftReference_klass()->long_field_put(offset, value); } @@ -2404,6 +2403,10 @@ oop java_dyn_MethodType::ptype(oop mt, int idx) { return ptypes(mt)->obj_at(idx); } +int java_dyn_MethodType::ptype_count(oop mt) { + return ptypes(mt)->length(); +} + // Support for java_dyn_MethodTypeForm @@ -2430,15 +2433,15 @@ oop java_dyn_MethodTypeForm::erasedType(oop mtform) { } -// Support for sun_dyn_CallSiteImpl +// Support for java_dyn_CallSite -int sun_dyn_CallSiteImpl::_type_offset; -int sun_dyn_CallSiteImpl::_target_offset; -int sun_dyn_CallSiteImpl::_vmmethod_offset; +int java_dyn_CallSite::_type_offset; +int java_dyn_CallSite::_target_offset; +int java_dyn_CallSite::_vmmethod_offset; -void sun_dyn_CallSiteImpl::compute_offsets() { +void java_dyn_CallSite::compute_offsets() { if (!EnableInvokeDynamic) return; - klassOop k = SystemDictionary::CallSiteImpl_klass(); + klassOop k = SystemDictionary::CallSite_klass(); if (k != NULL) { compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true); compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true); @@ -2446,23 +2449,23 @@ void sun_dyn_CallSiteImpl::compute_offsets() { } } -oop sun_dyn_CallSiteImpl::type(oop site) { +oop java_dyn_CallSite::type(oop site) { return site->obj_field(_type_offset); } -oop sun_dyn_CallSiteImpl::target(oop site) { +oop java_dyn_CallSite::target(oop site) { return site->obj_field(_target_offset); } -void sun_dyn_CallSiteImpl::set_target(oop site, oop target) { +void java_dyn_CallSite::set_target(oop site, oop target) { site->obj_field_put(_target_offset, target); } -oop sun_dyn_CallSiteImpl::vmmethod(oop site) { +oop java_dyn_CallSite::vmmethod(oop site) { return site->obj_field(_vmmethod_offset); } -void sun_dyn_CallSiteImpl::set_vmmethod(oop site, oop ref) { +void java_dyn_CallSite::set_vmmethod(oop site, oop ref) { site->obj_field_put(_vmmethod_offset, ref); } @@ -2535,7 +2538,7 @@ oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { // the generated bytecodes for reflection, and if so, "magically" // delegate to its parent to prevent class loading from occurring // in places where applications using reflection didn't expect it. - klassOop delegating_cl_class = SystemDictionary::reflect_delegating_classloader_klass(); + klassOop delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass(); // This might be null in non-1.4 JDKs if (delegating_cl_class != NULL && loader->is_a(delegating_cl_class)) { return parent(loader); @@ -2550,7 +2553,7 @@ oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { void java_lang_System::compute_offsets() { assert(offset_of_static_fields == 0, "offsets should be initialized only once"); - instanceKlass* ik = instanceKlass::cast(SystemDictionary::system_klass()); + instanceKlass* ik = instanceKlass::cast(SystemDictionary::System_klass()); offset_of_static_fields = ik->offset_of_static_fields(); } @@ -2811,7 +2814,7 @@ void JavaClasses::compute_offsets() { java_dyn_MethodTypeForm::compute_offsets(); } if (EnableInvokeDynamic) { - sun_dyn_CallSiteImpl::compute_offsets(); + java_dyn_CallSite::compute_offsets(); } java_security_AccessControlContext::compute_offsets(); // Initialize reflection classes. The layouts of these classes diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 048fba8d4b0..af78d5e58b3 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -111,7 +111,7 @@ class java_lang_String : AllStatic { // Testers static bool is_instance(oop obj) { - return obj != NULL && obj->klass() == SystemDictionary::string_klass(); + return obj != NULL && obj->klass() == SystemDictionary::String_klass(); } // Debugging @@ -161,7 +161,7 @@ class java_lang_Class : AllStatic { static void print_signature(oop java_class, outputStream *st); // Testing static bool is_instance(oop obj) { - return obj != NULL && obj->klass() == SystemDictionary::class_klass(); + return obj != NULL && obj->klass() == SystemDictionary::Class_klass(); } static bool is_primitive(oop java_class); static BasicType primitive_type(oop java_class); @@ -1027,6 +1027,7 @@ class java_dyn_MethodType: AllStatic { static oop form(oop mt); static oop ptype(oop mt, int index); + static int ptype_count(oop mt); static symbolOop as_signature(oop mt, bool intern_if_not_found, TRAPS); static void print_signature(oop mt, outputStream* st); @@ -1061,9 +1062,9 @@ class java_dyn_MethodTypeForm: AllStatic { }; -// Interface to sun.dyn.CallSiteImpl objects +// Interface to java.dyn.CallSite objects -class sun_dyn_CallSiteImpl: AllStatic { +class java_dyn_CallSite: AllStatic { friend class JavaClasses; private: @@ -1083,6 +1084,14 @@ public: static oop vmmethod(oop site); static void set_vmmethod(oop site, oop ref); + // Testers + static bool is_subclass(klassOop klass) { + return Klass::cast(klass)->is_subclass_of(SystemDictionary::CallSite_klass()); + } + static bool is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); + } + // Accessors for code generation: static int target_offset_in_bytes() { return _target_offset; } static int type_offset_in_bytes() { return _type_offset; } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 5598c9fcfb3..fb22282e97c 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -60,10 +60,10 @@ oop SystemDictionary::java_system_loader() { } void SystemDictionary::compute_java_system_loader(TRAPS) { - KlassHandle system_klass(THREAD, WK_KLASS(classloader_klass)); + KlassHandle system_klass(THREAD, WK_KLASS(ClassLoader_klass)); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, - KlassHandle(THREAD, WK_KLASS(classloader_klass)), + KlassHandle(THREAD, WK_KLASS(ClassLoader_klass)), vmSymbolHandles::getSystemClassLoader_name(), vmSymbolHandles::void_classloader_signature(), CHECK); @@ -99,6 +99,15 @@ bool SystemDictionary::is_parallelCapable(Handle class_loader) { return java_lang_Class::parallelCapable(class_loader()); } // ---------------------------------------------------------------------------- +// ParallelDefineClass flag does not apply to bootclass loader +bool SystemDictionary::is_parallelDefine(Handle class_loader) { + if (class_loader.is_null()) return false; + if (AllowParallelDefineClass && java_lang_Class::parallelCapable(class_loader())) { + return true; + } + return false; +} +// ---------------------------------------------------------------------------- // Resolving of classes // Forwards to resolve_or_null @@ -119,7 +128,7 @@ klassOop SystemDictionary::handle_resolution_exception(symbolHandle class_name, // in which case we have to check whether the pending exception is a ClassNotFoundException, // and if so convert it to a NoClassDefFoundError // And chain the original ClassNotFoundException - if (throw_error && PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass())) { + if (throw_error && PENDING_EXCEPTION->is_a(SystemDictionary::ClassNotFoundException_klass())) { ResourceMark rm(THREAD); assert(klass_h() == NULL, "Should not have result with exception pending"); Handle e(THREAD, PENDING_EXCEPTION); @@ -350,7 +359,7 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, assert(class_loader() != NULL, "should not have non-null protection domain for null classloader"); - KlassHandle system_loader(THREAD, SystemDictionary::classloader_klass()); + KlassHandle system_loader(THREAD, SystemDictionary::ClassLoader_klass()); JavaCalls::call_special(&result, class_loader, system_loader, @@ -724,17 +733,17 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam // Do actual loading k = load_instance_class(name, class_loader, THREAD); - // For UnsyncloadClass and AllowParallelDefineClass only: + // For UnsyncloadClass only // If they got a linkageError, check if a parallel class load succeeded. // If it did, then for bytecode resolution the specification requires // that we return the same result we did for the other thread, i.e. the // successfully loaded instanceKlass // Should not get here for classloaders that support parallelism - // with the new cleaner mechanism + // with the new cleaner mechanism, even with AllowParallelDefineClass // Bootstrap goes through here to allow for an extra guarantee check if (UnsyncloadClass || (class_loader.is_null())) { if (k.is_null() && HAS_PENDING_EXCEPTION - && PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) { + && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { MutexLocker mu(SystemDictionary_lock, THREAD); klassOop check = find_class(d_index, d_hash, name, class_loader); if (check != NULL) { @@ -1358,7 +1367,7 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam JavaValue result(T_OBJECT); - KlassHandle spec_klass (THREAD, SystemDictionary::classloader_klass()); + KlassHandle spec_klass (THREAD, SystemDictionary::ClassLoader_klass()); // Call public unsynchronized loadClass(String) directly for all class loaders // for parallelCapable class loaders. JDK >=7, loadClass(String, boolean) will @@ -1483,14 +1492,17 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { } // Support parallel classloading -// Initial implementation for bootstrap classloader -// For custom class loaders that support parallel classloading, +// All parallel class loaders, including bootstrap classloader +// lock a placeholder entry for this class/class_loader pair +// to allow parallel defines of different classes for this class loader // With AllowParallelDefine flag==true, in case they do not synchronize around // FindLoadedClass/DefineClass, calls, we check for parallel // loading for them, wait if a defineClass is in progress // and return the initial requestor's results +// This flag does not apply to the bootstrap classloader. // With AllowParallelDefine flag==false, call through to define_instance_class // which will throw LinkageError: duplicate class definition. +// False is the requested default. // For better performance, the class loaders should synchronize // findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they // potentially waste time reading and parsing the bytestream. @@ -1511,9 +1523,11 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle { MutexLocker mu(SystemDictionary_lock, THREAD); // First check if class already defined - klassOop check = find_class(d_index, d_hash, name_h, class_loader); - if (check != NULL) { - return(instanceKlassHandle(THREAD, check)); + if (UnsyncloadClass || (is_parallelDefine(class_loader))) { + klassOop check = find_class(d_index, d_hash, name_h, class_loader); + if (check != NULL) { + return(instanceKlassHandle(THREAD, check)); + } } // Acquire define token for this class/classloader @@ -1529,7 +1543,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle // Only special cases allow parallel defines and can use other thread's results // Other cases fall through, and may run into duplicate defines // caught by finding an entry in the SystemDictionary - if ((UnsyncloadClass || AllowParallelDefineClass) && (probe->instanceKlass() != NULL)) { + if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instanceKlass() != NULL)) { probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD); SystemDictionary_lock->notify_all(); @@ -1930,13 +1944,13 @@ void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id void SystemDictionary::initialize_preloaded_classes(TRAPS) { - assert(WK_KLASS(object_klass) == NULL, "preloaded classes should only be initialized once"); + assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once"); // Preload commonly used klasses WKID scan = FIRST_WKID; // first do Object, String, Class - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(class_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK); - debug_only(instanceKlass::verify_class_klass_nonstatic_oop_maps(WK_KLASS(class_klass))); + debug_only(instanceKlass::verify_class_klass_nonstatic_oop_maps(WK_KLASS(Class_klass))); // Fixup mirrors for classes loaded before java.lang.Class. // These calls iterate over the objects currently in the perm gen @@ -1947,17 +1961,17 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { Universe::fixup_mirrors(CHECK); // do a bunch more: - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(reference_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Reference_klass), scan, CHECK); // Preload ref klasses and set reference types - instanceKlass::cast(WK_KLASS(reference_klass))->set_reference_type(REF_OTHER); - instanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(reference_klass)); + instanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); + instanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass)); - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(phantom_reference_klass), scan, CHECK); - instanceKlass::cast(WK_KLASS(soft_reference_klass))->set_reference_type(REF_SOFT); - instanceKlass::cast(WK_KLASS(weak_reference_klass))->set_reference_type(REF_WEAK); - instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL); - instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); + instanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); + instanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); + instanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); + instanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass); @@ -1970,10 +1984,10 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { scan = WKID(meth_group_end+1); } WKID indy_group_start = WK_KLASS_ENUM_NAME(Linkage_klass); - WKID indy_group_end = WK_KLASS_ENUM_NAME(Dynamic_klass); + WKID indy_group_end = WK_KLASS_ENUM_NAME(InvokeDynamic_klass); initialize_wk_klasses_until(indy_group_start, scan, CHECK); if (EnableInvokeDynamic) { - initialize_wk_klasses_through(indy_group_start, scan, CHECK); + initialize_wk_klasses_through(indy_group_end, scan, CHECK); } if (_well_known_klasses[indy_group_start] == NULL) { // Skip the rest of the dynamic typing classes, if Linkage is not loaded. @@ -1982,14 +1996,14 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK); - _box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass); - _box_klasses[T_CHAR] = WK_KLASS(char_klass); - _box_klasses[T_FLOAT] = WK_KLASS(float_klass); - _box_klasses[T_DOUBLE] = WK_KLASS(double_klass); - _box_klasses[T_BYTE] = WK_KLASS(byte_klass); - _box_klasses[T_SHORT] = WK_KLASS(short_klass); - _box_klasses[T_INT] = WK_KLASS(int_klass); - _box_klasses[T_LONG] = WK_KLASS(long_klass); + _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); + _box_klasses[T_CHAR] = WK_KLASS(Character_klass); + _box_klasses[T_FLOAT] = WK_KLASS(Float_klass); + _box_klasses[T_DOUBLE] = WK_KLASS(Double_klass); + _box_klasses[T_BYTE] = WK_KLASS(Byte_klass); + _box_klasses[T_SHORT] = WK_KLASS(Short_klass); + _box_klasses[T_INT] = WK_KLASS(Integer_klass); + _box_klasses[T_LONG] = WK_KLASS(Long_klass); //_box_klasses[T_OBJECT] = WK_KLASS(object_klass); //_box_klasses[T_ARRAY] = WK_KLASS(object_klass); @@ -2000,11 +2014,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { #endif // KERNEL { // Compute whether we should use loadClass or loadClassInternal when loading classes. - methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature()); + methodOop method = instanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature()); _has_loadClassInternal = (method != NULL); } { // Compute whether we should use checkPackageAccess or NOT - methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature()); + methodOop method = instanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature()); _has_checkPackageAccess = (method != NULL); } } @@ -2326,6 +2340,8 @@ methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature, SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature); if (spe == NULL || spe->property_oop() == NULL) { // Must create lots of stuff here, but outside of the SystemDictionary lock. + if (THREAD->is_Compiler_thread()) + return NULL; // do not attempt from within compiler Handle mt = compute_method_handle_type(signature(), class_loader, protection_domain, CHECK_NULL); @@ -2358,7 +2374,7 @@ Handle SystemDictionary::compute_method_handle_type(symbolHandle signature, TRAPS) { Handle empty; int npts = ArgumentCount(signature()).size(); - objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::class_klass(), npts, CHECK_(empty)); + objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::Class_klass(), npts, CHECK_(empty)); int arg = 0; Handle rt; // the return type from the signature for (SignatureStream ss(signature()); !ss.is_done(); ss.next()) { @@ -2404,7 +2420,7 @@ Handle SystemDictionary::make_dynamic_call_site(KlassHandle caller, methodHandle mh_invdyn, TRAPS) { Handle empty; - // call sun.dyn.CallSiteImpl::makeSite(caller, name, mtype, cmid, cbci) + // call java.dyn.CallSite::makeSite(caller, name, mtype, cmid, cbci) oop name_str_oop = StringTable::intern(name(), CHECK_(empty)); // not a handle! JavaCallArguments args(Handle(THREAD, caller->java_mirror())); args.push_oop(name_str_oop); @@ -2413,17 +2429,19 @@ Handle SystemDictionary::make_dynamic_call_site(KlassHandle caller, args.push_int(caller_bci); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, - SystemDictionary::CallSiteImpl_klass(), + SystemDictionary::CallSite_klass(), vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(), &args, CHECK_(empty)); oop call_site_oop = (oop) result.get_jobject(); assert(call_site_oop->is_oop() - /*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane"); - sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn()); + /*&& java_dyn_CallSite::is_instance(call_site_oop)*/, "must be sane"); + java_dyn_CallSite::set_vmmethod(call_site_oop, mh_invdyn()); if (TraceMethodHandles) { +#ifndef PRODUCT tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop); call_site_oop->print(); tty->cr(); +#endif //PRODUCT } return call_site_oop; } @@ -2436,9 +2454,17 @@ Handle SystemDictionary::find_bootstrap_method(KlassHandle caller, instanceKlassHandle ik(THREAD, caller()); - if (ik->bootstrap_method() != NULL) { - return Handle(THREAD, ik->bootstrap_method()); + oop boot_method_oop = ik->bootstrap_method(); + if (boot_method_oop != NULL) { + if (TraceMethodHandles) { + tty->print_cr("bootstrap method for "PTR_FORMAT" cached as "PTR_FORMAT":", ik(), boot_method_oop); + } + NOT_PRODUCT(if (!boot_method_oop->is_oop()) { tty->print_cr("*** boot MH of "PTR_FORMAT" = "PTR_FORMAT, ik(), boot_method_oop); ik()->print(); }); + assert(boot_method_oop->is_oop() + && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); + return Handle(THREAD, boot_method_oop); } + boot_method_oop = NULL; // GC safety // call java.dyn.Linkage::findBootstrapMethod(caller, sbk) JavaCallArguments args(Handle(THREAD, ik->java_mirror())); @@ -2452,9 +2478,18 @@ Handle SystemDictionary::find_bootstrap_method(KlassHandle caller, vmSymbols::findBootstrapMethod_name(), vmSymbols::findBootstrapMethod_signature(), &args, CHECK_(empty)); - oop boot_method_oop = (oop) result.get_jobject(); + boot_method_oop = (oop) result.get_jobject(); if (boot_method_oop != NULL) { + if (TraceMethodHandles) { +#ifndef PRODUCT + tty->print_cr("--------"); + tty->print_cr("bootstrap method for "PTR_FORMAT" computed as "PTR_FORMAT":", ik(), boot_method_oop); + ik()->print(); + boot_method_oop->print(); + tty->print_cr("========"); +#endif //PRODUCT + } assert(boot_method_oop->is_oop() && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); // probably no race conditions, but let's be careful: @@ -2463,6 +2498,14 @@ Handle SystemDictionary::find_bootstrap_method(KlassHandle caller, else boot_method_oop = ik->bootstrap_method(); } else { + if (TraceMethodHandles) { +#ifndef PRODUCT + tty->print_cr("--------"); + tty->print_cr("bootstrap method for "PTR_FORMAT" computed as NULL:", ik()); + ik()->print(); + tty->print_cr("========"); +#endif //PRODUCT + } boot_method_oop = ik->bootstrap_method(); } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index b7c82033628..03b2aeb6b42 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,55 +82,55 @@ class SymbolPropertyTable; #define WK_KLASSES_DO(template) \ /* well-known classes */ \ - template(object_klass, java_lang_Object, Pre) \ - template(string_klass, java_lang_String, Pre) \ - template(class_klass, java_lang_Class, Pre) \ - template(cloneable_klass, java_lang_Cloneable, Pre) \ - template(classloader_klass, java_lang_ClassLoader, Pre) \ - template(serializable_klass, java_io_Serializable, Pre) \ - template(system_klass, java_lang_System, Pre) \ - template(throwable_klass, java_lang_Throwable, Pre) \ - template(error_klass, java_lang_Error, Pre) \ - template(threaddeath_klass, java_lang_ThreadDeath, Pre) \ - template(exception_klass, java_lang_Exception, Pre) \ - template(runtime_exception_klass, java_lang_RuntimeException, Pre) \ - template(protectionDomain_klass, java_security_ProtectionDomain, Pre) \ + template(Object_klass, java_lang_Object, Pre) \ + template(String_klass, java_lang_String, Pre) \ + template(Class_klass, java_lang_Class, Pre) \ + template(Cloneable_klass, java_lang_Cloneable, Pre) \ + template(ClassLoader_klass, java_lang_ClassLoader, Pre) \ + template(Serializable_klass, java_io_Serializable, Pre) \ + template(System_klass, java_lang_System, Pre) \ + template(Throwable_klass, java_lang_Throwable, Pre) \ + template(Error_klass, java_lang_Error, Pre) \ + template(ThreadDeath_klass, java_lang_ThreadDeath, Pre) \ + template(Exception_klass, java_lang_Exception, Pre) \ + template(RuntimeException_klass, java_lang_RuntimeException, Pre) \ + template(ProtectionDomain_klass, java_security_ProtectionDomain, Pre) \ template(AccessControlContext_klass, java_security_AccessControlContext, Pre) \ - template(classNotFoundException_klass, java_lang_ClassNotFoundException, Pre) \ - template(noClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre) \ - template(linkageError_klass, java_lang_LinkageError, Pre) \ + template(ClassNotFoundException_klass, java_lang_ClassNotFoundException, Pre) \ + template(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre) \ + template(LinkageError_klass, java_lang_LinkageError, Pre) \ template(ClassCastException_klass, java_lang_ClassCastException, Pre) \ template(ArrayStoreException_klass, java_lang_ArrayStoreException, Pre) \ - template(virtualMachineError_klass, java_lang_VirtualMachineError, Pre) \ + template(VirtualMachineError_klass, java_lang_VirtualMachineError, Pre) \ template(OutOfMemoryError_klass, java_lang_OutOfMemoryError, Pre) \ template(StackOverflowError_klass, java_lang_StackOverflowError, Pre) \ template(IllegalMonitorStateException_klass, java_lang_IllegalMonitorStateException, Pre) \ - template(reference_klass, java_lang_ref_Reference, Pre) \ + template(Reference_klass, java_lang_ref_Reference, Pre) \ \ /* Preload ref klasses and set reference types */ \ - template(soft_reference_klass, java_lang_ref_SoftReference, Pre) \ - template(weak_reference_klass, java_lang_ref_WeakReference, Pre) \ - template(final_reference_klass, java_lang_ref_FinalReference, Pre) \ - template(phantom_reference_klass, java_lang_ref_PhantomReference, Pre) \ - template(finalizer_klass, java_lang_ref_Finalizer, Pre) \ + template(SoftReference_klass, java_lang_ref_SoftReference, Pre) \ + template(WeakReference_klass, java_lang_ref_WeakReference, Pre) \ + template(FinalReference_klass, java_lang_ref_FinalReference, Pre) \ + template(PhantomReference_klass, java_lang_ref_PhantomReference, Pre) \ + template(Finalizer_klass, java_lang_ref_Finalizer, Pre) \ \ - template(thread_klass, java_lang_Thread, Pre) \ - template(threadGroup_klass, java_lang_ThreadGroup, Pre) \ - template(properties_klass, java_util_Properties, Pre) \ - template(reflect_accessible_object_klass, java_lang_reflect_AccessibleObject, Pre) \ - template(reflect_field_klass, java_lang_reflect_Field, Pre) \ - template(reflect_method_klass, java_lang_reflect_Method, Pre) \ - template(reflect_constructor_klass, java_lang_reflect_Constructor, Pre) \ + template(Thread_klass, java_lang_Thread, Pre) \ + template(ThreadGroup_klass, java_lang_ThreadGroup, Pre) \ + template(Properties_klass, java_util_Properties, Pre) \ + template(reflect_AccessibleObject_klass, java_lang_reflect_AccessibleObject, Pre) \ + template(reflect_Field_klass, java_lang_reflect_Field, Pre) \ + template(reflect_Method_klass, java_lang_reflect_Method, Pre) \ + template(reflect_Constructor_klass, java_lang_reflect_Constructor, Pre) \ \ /* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \ /* Universe::is_gte_jdk14x_version() is not set up by this point. */ \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ - template(reflect_magic_klass, sun_reflect_MagicAccessorImpl, Opt) \ - template(reflect_method_accessor_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \ - template(reflect_constructor_accessor_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \ - template(reflect_delegating_classloader_klass, sun_reflect_DelegatingClassLoader, Opt) \ - template(reflect_constant_pool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \ - template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \ + template(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt) \ + template(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \ + template(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \ + template(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt) \ + template(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \ + template(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \ \ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \ @@ -144,16 +144,14 @@ class SymbolPropertyTable; template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \ template(Linkage_klass, java_dyn_Linkage, Opt) \ template(CallSite_klass, java_dyn_CallSite, Opt) \ - template(CallSiteImpl_klass, sun_dyn_CallSiteImpl, Opt) \ - template(Dynamic_klass, java_dyn_Dynamic, Opt) \ - /* Note: MethodHandle must be first, and Dynamic last in group */ \ + template(InvokeDynamic_klass, java_dyn_InvokeDynamic, Opt) \ + /* Note: MethodHandle must be first, and InvokeDynamic last in group */ \ \ - template(vector_klass, java_util_Vector, Pre) \ - template(hashtable_klass, java_util_Hashtable, Pre) \ - template(stringBuffer_klass, java_lang_StringBuffer, Pre) \ + template(StringBuffer_klass, java_lang_StringBuffer, Pre) \ + template(StringBuilder_klass, java_lang_StringBuilder, Pre) \ \ /* It's NULL in non-1.4 JDKs. */ \ - template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \ + template(StackTraceElement_klass, java_lang_StackTraceElement, Opt) \ /* Universe::is_gte_jdk14x_version() is not set up by this point. */ \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ template(java_nio_Buffer_klass, java_nio_Buffer, Opt) \ @@ -164,14 +162,14 @@ class SymbolPropertyTable; template(sun_jkernel_DownloadManager_klass, sun_jkernel_DownloadManager, Opt_Kernel) \ \ /* Preload boxing klasses */ \ - template(boolean_klass, java_lang_Boolean, Pre) \ - template(char_klass, java_lang_Character, Pre) \ - template(float_klass, java_lang_Float, Pre) \ - template(double_klass, java_lang_Double, Pre) \ - template(byte_klass, java_lang_Byte, Pre) \ - template(short_klass, java_lang_Short, Pre) \ - template(int_klass, java_lang_Integer, Pre) \ - template(long_klass, java_lang_Long, Pre) \ + template(Boolean_klass, java_lang_Boolean, Pre) \ + template(Character_klass, java_lang_Character, Pre) \ + template(Float_klass, java_lang_Float, Pre) \ + template(Double_klass, java_lang_Double, Pre) \ + template(Byte_klass, java_lang_Byte, Pre) \ + template(Short_klass, java_lang_Short, Pre) \ + template(Integer_klass, java_lang_Integer, Pre) \ + template(Long_klass, java_lang_Long, Pre) \ /*end*/ @@ -438,8 +436,8 @@ public: // Tells whether ClassLoader.checkPackageAccess is present static bool has_checkPackageAccess() { return _has_checkPackageAccess; } - static bool class_klass_loaded() { return WK_KLASS(class_klass) != NULL; } - static bool cloneable_klass_loaded() { return WK_KLASS(cloneable_klass) != NULL; } + static bool Class_klass_loaded() { return WK_KLASS(Class_klass) != NULL; } + static bool Cloneable_klass_loaded() { return WK_KLASS(Cloneable_klass) != NULL; } // Returns default system loader static oop java_system_loader(); @@ -578,6 +576,7 @@ private: static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS); static bool is_parallelCapable(Handle class_loader); + static bool is_parallelDefine(Handle class_loader); static klassOop find_shared_class(symbolHandle class_name); diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index dd947d19cfb..3a9136c7b9b 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -143,7 +143,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul bool Verifier::is_eligible_for_verification(instanceKlassHandle klass, bool should_verify_class) { symbolOop name = klass->name(); - klassOop refl_magic_klass = SystemDictionary::reflect_magic_klass(); + klassOop refl_magic_klass = SystemDictionary::reflect_MagicAccessorImpl_klass(); return (should_verify_for(klass->class_loader(), should_verify_class) && // return if the class is a bootstrapping class @@ -1903,17 +1903,8 @@ void ClassVerifier::verify_invoke_instructions( verify_cp_type(index, cp, types, CHECK_VERIFY(this)); // Get method name and signature - symbolHandle method_name; - symbolHandle method_sig; - if (opcode == Bytecodes::_invokedynamic) { - int name_index = cp->name_ref_index_at(index); - int sig_index = cp->signature_ref_index_at(index); - method_name = symbolHandle(THREAD, cp->symbol_at(name_index)); - method_sig = symbolHandle(THREAD, cp->symbol_at(sig_index)); - } else { - method_name = symbolHandle(THREAD, cp->name_ref_at(index)); - method_sig = symbolHandle(THREAD, cp->signature_ref_at(index)); - } + symbolHandle method_name(THREAD, cp->name_ref_at(index)); + symbolHandle method_sig(THREAD, cp->signature_ref_at(index)); if (!SignatureVerifier::is_valid_method_signature(method_sig)) { class_format_error( diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index c805af344e7..6cc7f3c2d33 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.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 @@ static const char* vm_symbol_bodies = VM_SYMBOLS_DO(VM_SYMBOL_BODY, VM_ALIAS_IGN void vmSymbols::initialize(TRAPS) { assert((int)SID_LIMIT <= (1< (1<find_method(mname, msig); +} + #define VM_INTRINSIC_INITIALIZE(id, klass, name, sig, flags) #id "\0" static const char* vm_intrinsic_name_bodies = @@ -303,6 +356,11 @@ inline bool match_F_R(jshort flags) { const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } +inline bool match_F_Y(jshort flags) { + const int req = JVM_ACC_SYNCHRONIZED; + const int neg = JVM_ACC_STATIC; + return (flags & (req | neg)) == req; +} inline bool match_F_RN(jshort flags) { const int req = JVM_ACC_NATIVE; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; @@ -325,15 +383,15 @@ inline bool match_F_RNY(jshort flags) { } // These are for forming case labels: -#define ID3(x, y, z) (( jint)(z) + \ - ((jint)(y) << vmSymbols::log2_SID_LIMIT) + \ - ((jint)(x) << (2*vmSymbols::log2_SID_LIMIT)) ) +#define ID3(x, y, z) (( jlong)(z) + \ + ((jlong)(y) << vmSymbols::log2_SID_LIMIT) + \ + ((jlong)(x) << (2*vmSymbols::log2_SID_LIMIT)) ) #define SID_ENUM(n) vmSymbols::VM_SYMBOL_ENUM_NAME(n) -vmIntrinsics::ID vmIntrinsics::find_id(vmSymbols::SID holder, - vmSymbols::SID name, - vmSymbols::SID sig, - jshort flags) { +vmIntrinsics::ID vmIntrinsics::find_id_impl(vmSymbols::SID holder, + vmSymbols::SID name, + vmSymbols::SID sig, + jshort flags) { assert((int)vmSymbols::SID_LIMIT <= (1<> shift) & mask) == 1021, ""); + return vmSymbols::SID( (info >> shift) & mask ); } vmSymbols::SID vmIntrinsics::name_for(vmIntrinsics::ID id) { -#ifndef PRODUCT -#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \ - case id: return SID_ENUM(name); - - switch (id) { - VM_INTRINSICS_DO(VM_INTRINSIC_CASE, - VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); - } -#undef VM_INTRINSIC_CASE -#endif //PRODUCT - return vmSymbols::NO_SID; + jlong info = intrinsic_info(id); + int shift = vmSymbols::log2_SID_LIMIT + log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT); + assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1022, ""); + return vmSymbols::SID( (info >> shift) & mask ); } vmSymbols::SID vmIntrinsics::signature_for(vmIntrinsics::ID id) { -#ifndef PRODUCT -#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \ - case id: return SID_ENUM(sig); - - switch (id) { - VM_INTRINSICS_DO(VM_INTRINSIC_CASE, - VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); - } -#undef VM_INTRINSIC_CASE -#endif //PRODUCT - return vmSymbols::NO_SID; + jlong info = intrinsic_info(id); + int shift = log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT); + assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1023, ""); + return vmSymbols::SID( (info >> shift) & mask ); } vmIntrinsics::Flags vmIntrinsics::flags_for(vmIntrinsics::ID id) { -#ifndef PRODUCT -#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \ - case id: return fcode; - - switch (id) { - VM_INTRINSICS_DO(VM_INTRINSIC_CASE, - VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); - } -#undef VM_INTRINSIC_CASE -#endif //PRODUCT - return F_none; + jlong info = intrinsic_info(id); + int shift = 0, mask = right_n_bits(log2_FLAG_LIMIT); + assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 15, ""); + return Flags( (info >> shift) & mask ); } diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 04bb9369205..0b4652157d1 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -84,6 +84,7 @@ template(java_lang_reflect_Field, "java/lang/reflect/Field") \ template(java_lang_reflect_Array, "java/lang/reflect/Array") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ + template(java_lang_StringBuilder, "java/lang/StringBuilder") \ template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_security_AccessControlContext, "java/security/AccessControlContext") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ @@ -104,6 +105,7 @@ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ + template(setBootClassLoaderHook_name, "setBootClassLoaderHook") \ \ /* class file format tags */ \ template(tag_source_file, "SourceFile") \ @@ -217,7 +219,7 @@ template(base_name, "base") \ \ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \ - template(java_dyn_Dynamic, "java/dyn/Dynamic") \ + template(java_dyn_InvokeDynamic, "java/dyn/InvokeDynamic") \ template(java_dyn_Linkage, "java/dyn/Linkage") \ template(java_dyn_CallSite, "java/dyn/CallSite") \ template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \ @@ -233,10 +235,9 @@ template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \ template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \ template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \ - template(sun_dyn_CallSiteImpl, "sun/dyn/CallSiteImpl") \ template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \ template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \ - template(makeSite_name, "makeSite") /*CallSiteImpl::makeImpl*/ \ + template(makeSite_name, "makeSite") /*CallSite::makeSite*/ \ template(makeSite_signature, "(Ljava/lang/Class;Ljava/lang/String;Ljava/dyn/MethodType;II)Ljava/dyn/CallSite;") \ template(findBootstrapMethod_name, "findBootstrapMethod") \ template(findBootstrapMethod_signature, "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/dyn/MethodHandle;") \ @@ -335,6 +336,7 @@ template(ptypes_name, "ptypes") \ template(form_name, "form") \ template(erasedType_name, "erasedType") \ + template(append_name, "append") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -345,9 +347,14 @@ \ /* common signatures names */ \ template(void_method_signature, "()V") \ + template(void_boolean_signature, "()Z") \ + template(void_byte_signature, "()B") \ + template(void_char_signature, "()C") \ + template(void_short_signature, "()S") \ template(void_int_signature, "()I") \ template(void_long_signature, "()J") \ - template(void_boolean_signature, "()Z") \ + template(void_float_signature, "()F") \ + template(void_double_signature, "()D") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(int_bool_signature, "(I)Z") \ @@ -416,6 +423,13 @@ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ + template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ + template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \ + template(char_StringBuilder_signature, "(C)Ljava/lang/StringBuilder;") \ + template(String_StringBuffer_signature, "(Ljava/lang/String;)Ljava/lang/StringBuffer;") \ + template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \ + template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ + template(int_String_signature, "(I)Ljava/lang/String;") \ /* signature symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ \ @@ -815,12 +829,76 @@ /*the compiler does have special inlining code for these; bytecode inline is just fine */ \ \ do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \ - \ - do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \ - /* (symbol object_initializer_name defined above) */ \ - \ + \ + do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \ + do_intrinsic(_StringBuilder_int, java_lang_StringBuilder, object_initializer_name, int_void_signature, F_R) \ + do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_StringBuilder_append_char, java_lang_StringBuilder, append_name, char_StringBuilder_signature, F_R) \ + do_intrinsic(_StringBuilder_append_int, java_lang_StringBuilder, append_name, int_StringBuilder_signature, F_R) \ + do_intrinsic(_StringBuilder_append_String, java_lang_StringBuilder, append_name, String_StringBuilder_signature, F_R) \ + \ + do_intrinsic(_StringBuilder_toString, java_lang_StringBuilder, toString_name, void_string_signature, F_R) \ + \ + do_intrinsic(_StringBuffer_void, java_lang_StringBuffer, object_initializer_name, void_method_signature, F_R) \ + do_intrinsic(_StringBuffer_int, java_lang_StringBuffer, object_initializer_name, int_void_signature, F_R) \ + do_intrinsic(_StringBuffer_String, java_lang_StringBuffer, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_StringBuffer_append_char, java_lang_StringBuffer, append_name, char_StringBuffer_signature, F_Y) \ + do_intrinsic(_StringBuffer_append_int, java_lang_StringBuffer, append_name, int_StringBuffer_signature, F_Y) \ + do_intrinsic(_StringBuffer_append_String, java_lang_StringBuffer, append_name, String_StringBuffer_signature, F_Y) \ + \ + do_intrinsic(_StringBuffer_toString, java_lang_StringBuffer, toString_name, void_string_signature, F_Y) \ + \ + do_intrinsic(_Integer_toString, java_lang_Integer, toString_name, int_String_signature, F_S) \ + \ + do_intrinsic(_String_String, java_lang_String, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \ + /* (symbol object_initializer_name defined above) */ \ + \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \ /* (symbols invoke_name and invoke_signature defined above) */ \ + do_intrinsic(_checkSpreadArgument, sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \ + do_name( checkSpreadArgument_name, "checkSpreadArgument") \ + do_name( checkSpreadArgument_signature, "(Ljava/lang/Object;I)V") \ + \ + /* unboxing methods: */ \ + do_intrinsic(_booleanValue, java_lang_Boolean, booleanValue_name, void_boolean_signature, F_R) \ + do_name( booleanValue_name, "booleanValue") \ + do_intrinsic(_byteValue, java_lang_Byte, byteValue_name, void_byte_signature, F_R) \ + do_name( byteValue_name, "byteValue") \ + do_intrinsic(_charValue, java_lang_Character, charValue_name, void_char_signature, F_R) \ + do_name( charValue_name, "charValue") \ + do_intrinsic(_shortValue, java_lang_Short, shortValue_name, void_short_signature, F_R) \ + do_name( shortValue_name, "shortValue") \ + do_intrinsic(_intValue, java_lang_Integer, intValue_name, void_int_signature, F_R) \ + do_name( intValue_name, "intValue") \ + do_intrinsic(_longValue, java_lang_Long, longValue_name, void_long_signature, F_R) \ + do_name( longValue_name, "longValue") \ + do_intrinsic(_floatValue, java_lang_Float, floatValue_name, void_float_signature, F_R) \ + do_name( floatValue_name, "floatValue") \ + do_intrinsic(_doubleValue, java_lang_Double, doubleValue_name, void_double_signature, F_R) \ + do_name( doubleValue_name, "doubleValue") \ + \ + /* boxing methods: */ \ + do_name( valueOf_name, "valueOf") \ + do_intrinsic(_Boolean_valueOf, java_lang_Boolean, valueOf_name, Boolean_valueOf_signature, F_S) \ + do_name( Boolean_valueOf_signature, "(Z)Ljava/lang/Boolean;") \ + do_intrinsic(_Byte_valueOf, java_lang_Byte, valueOf_name, Byte_valueOf_signature, F_S) \ + do_name( Byte_valueOf_signature, "(B)Ljava/lang/Byte;") \ + do_intrinsic(_Character_valueOf, java_lang_Character, valueOf_name, Character_valueOf_signature, F_S) \ + do_name( Character_valueOf_signature, "(C)Ljava/lang/Character;") \ + do_intrinsic(_Short_valueOf, java_lang_Short, valueOf_name, Short_valueOf_signature, F_S) \ + do_name( Short_valueOf_signature, "(S)Ljava/lang/Short;") \ + do_intrinsic(_Integer_valueOf, java_lang_Integer, valueOf_name, Integer_valueOf_signature, F_S) \ + do_name( Integer_valueOf_signature, "(I)Ljava/lang/Integer;") \ + do_intrinsic(_Long_valueOf, java_lang_Long, valueOf_name, Long_valueOf_signature, F_S) \ + do_name( Long_valueOf_signature, "(J)Ljava/lang/Long;") \ + do_intrinsic(_Float_valueOf, java_lang_Float, valueOf_name, Float_valueOf_signature, F_S) \ + do_name( Float_valueOf_signature, "(F)Ljava/lang/Float;") \ + do_intrinsic(_Double_valueOf, java_lang_Double, valueOf_name, Double_valueOf_signature, F_S) \ + do_name( Double_valueOf_signature, "(D)Ljava/lang/Double;") \ \ /*end*/ @@ -946,11 +1024,17 @@ class vmIntrinsics: AllStatic { enum Flags { // AccessFlags syndromes relevant to intrinsics. F_none = 0, - F_R, // !static !synchronized (R="regular") - F_S, // static !synchronized - F_RN, // !static native !synchronized - F_SN, // static native !synchronized - F_RNY // !static native synchronized + F_R, // !static ?native !synchronized (R="regular") + F_S, // static ?native !synchronized + F_Y, // !static ?native synchronized + F_RN, // !static native !synchronized + F_SN, // static native !synchronized + F_RNY, // !static native synchronized + + FLAG_LIMIT + }; + enum { + log2_FLAG_LIMIT = 4 // checked by an assert at start-up }; public: @@ -962,15 +1046,32 @@ public: static const char* name_at(ID id); +private: + static ID find_id_impl(vmSymbols::SID holder, + vmSymbols::SID name, + vmSymbols::SID sig, + jshort flags); + +public: // Given a method's class, name, signature, and access flags, report its ID. static ID find_id(vmSymbols::SID holder, vmSymbols::SID name, vmSymbols::SID sig, - jshort flags); + jshort flags) { + ID id = find_id_impl(holder, name, sig, flags); +#ifdef ASSERT + // ID _none does not hold the following asserts. + if (id == _none) return id; +#endif + assert( class_for(id) == holder, "correct id"); + assert( name_for(id) == name, "correct id"); + assert(signature_for(id) == sig, "correct id"); + return id; + } static void verify_method(ID actual_id, methodOop m) PRODUCT_RETURN; - // No need for these in the product: + // Find out the symbols behind an intrinsic: static vmSymbols::SID class_for(ID id); static vmSymbols::SID name_for(ID id); static vmSymbols::SID signature_for(ID id); @@ -980,4 +1081,11 @@ public: // Access to intrinsic methods: static methodOop method_for(ID id); + + // Wrapper object methods: + static ID for_boxing(BasicType type); + static ID for_unboxing(BasicType type); + + // Raw conversion: + static ID for_raw_conversion(BasicType src, BasicType dest); }; diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index 81acc81fcac..bbd430a14c6 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.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 @@ -102,6 +102,9 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } + // Casting + nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } + // Boundaries address header_begin() const { return (address) this; } address header_end() const { return ((address) this) + _header_size; }; @@ -201,7 +204,8 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { virtual void print_value_on(outputStream* st) const PRODUCT_RETURN; // Print the comment associated with offset on stream, if there is one - void print_block_comment(outputStream* stream, intptr_t offset) { + virtual void print_block_comment(outputStream* stream, address block_begin) { + intptr_t offset = (intptr_t)(block_begin - instructions_begin()); _comments.print_block_comment(stream, offset); } diff --git a/hotspot/src/share/vm/code/debugInfoRec.cpp b/hotspot/src/share/vm/code/debugInfoRec.cpp index fa24eb7c4c8..a1cac29439f 100644 --- a/hotspot/src/share/vm/code/debugInfoRec.cpp +++ b/hotspot/src/share/vm/code/debugInfoRec.cpp @@ -281,6 +281,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset, ciMethod* method, int bci, bool reexecute, + bool is_method_handle_invoke, DebugToken* locals, DebugToken* expressions, DebugToken* monitors) { @@ -292,8 +293,9 @@ void DebugInformationRecorder::describe_scope(int pc_offset, int stream_offset = stream()->position(); last_pd->set_scope_decode_offset(stream_offset); - // Record reexecute bit into pcDesc + // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); + last_pd->set_is_method_handle_invoke(is_method_handle_invoke); // serialize sender stream offest stream()->write_int(sender_stream_offset); diff --git a/hotspot/src/share/vm/code/debugInfoRec.hpp b/hotspot/src/share/vm/code/debugInfoRec.hpp index bb896adeae2..c67efa09b25 100644 --- a/hotspot/src/share/vm/code/debugInfoRec.hpp +++ b/hotspot/src/share/vm/code/debugInfoRec.hpp @@ -88,6 +88,7 @@ class DebugInformationRecorder: public ResourceObj { ciMethod* method, int bci, bool reexecute, + bool is_method_handle_invoke = false, DebugToken* locals = NULL, DebugToken* expressions = NULL, DebugToken* monitors = NULL); diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index 0d38dc7c2f6..aa476fd7c4e 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -1528,19 +1528,23 @@ void DepChange::print() { int nsup = 0, nint = 0; for (ContextStream str(*this); str.next(); ) { klassOop k = str.klass(); - switch (str._change_type) { + switch (str.change_type()) { case Change_new_type: tty->print_cr(" dependee = %s", instanceKlass::cast(k)->external_name()); break; case Change_new_sub: - if (!WizardMode) - ++nsup; - else tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name()); + if (!WizardMode) { + ++nsup; + } else { + tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name()); + } break; case Change_new_impl: - if (!WizardMode) - ++nint; - else tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name()); + if (!WizardMode) { + ++nint; + } else { + tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name()); + } break; } } diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index faf98b36537..ae3c077b4a8 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -470,7 +470,7 @@ class Dependencies: public ResourceObj { // super types can be context types for a relevant dependency, which the // new type could invalidate. class DepChange : public StackObj { - private: + public: enum ChangeType { NO_CHANGE = 0, // an uninvolved klass Change_new_type, // a newly loaded type @@ -480,6 +480,7 @@ class DepChange : public StackObj { Start_Klass = CHANGE_LIMIT // internal indicator for ContextStream }; + private: // each change set is rooted in exactly one new type (at present): KlassHandle _new_type; @@ -510,15 +511,15 @@ class DepChange : public StackObj { // } class ContextStream : public StackObj { private: - DepChange& _changes; + DepChange& _changes; friend class DepChange; // iteration variables: - ChangeType _change_type; - klassOop _klass; - objArrayOop _ti_base; // i.e., transitive_interfaces - int _ti_index; - int _ti_limit; + ChangeType _change_type; + klassOop _klass; + objArrayOop _ti_base; // i.e., transitive_interfaces + int _ti_index; + int _ti_limit; // start at the beginning: void start() { @@ -530,11 +531,11 @@ class DepChange : public StackObj { _ti_limit = 0; } + public: ContextStream(DepChange& changes) : _changes(changes) { start(); } - public: ContextStream(DepChange& changes, No_Safepoint_Verifier& nsv) : _changes(changes) // the nsv argument makes it safe to hold oops like _klass @@ -542,6 +543,7 @@ class DepChange : public StackObj { bool next(); + ChangeType change_type() { return _change_type; } klassOop klass() { return _klass; } }; friend class DepChange::ContextStream; diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 7f7ca11750f..82cfc7631d1 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -56,13 +56,13 @@ HS_DTRACE_PROBE_DECL6(hotspot, compiled__method__unload, #endif bool nmethod::is_compiled_by_c1() const { + if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing if (is_native_method()) return false; - assert(compiler() != NULL, "must be"); return compiler()->is_c1(); } bool nmethod::is_compiled_by_c2() const { + if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing if (is_native_method()) return false; - assert(compiler() != NULL, "must be"); return compiler()->is_c2(); } @@ -414,9 +414,8 @@ int nmethod::total_size() const { } const char* nmethod::compile_kind() const { - if (method() == NULL) return "unloaded"; - if (is_native_method()) return "c2n"; if (is_osr_method()) return "osr"; + if (method() != NULL && is_native_method()) return "c2n"; return NULL; } @@ -1127,6 +1126,9 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { } flags.state = unloaded; + // Log the unloading. + log_state_change(); + // The methodOop is gone at this point assert(_method == NULL, "Tautology"); @@ -1137,8 +1139,6 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { void nmethod::invalidate_osr_method() { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); - if (_entry_bci != InvalidOSREntryBci) - inc_decompile_count(); // Remove from list of active nmethods if (method() != NULL) instanceKlass::cast(method()->method_holder())->remove_osr_nmethod(this); @@ -1146,59 +1146,63 @@ void nmethod::invalidate_osr_method() { _entry_bci = InvalidOSREntryBci; } -void nmethod::log_state_change(int state) const { +void nmethod::log_state_change() const { if (LogCompilation) { if (xtty != NULL) { ttyLocker ttyl; // keep the following output all in one block - xtty->begin_elem("make_not_entrant %sthread='" UINTX_FORMAT "'", - (state == zombie ? "zombie='1' " : ""), - os::current_thread_id()); + if (flags.state == unloaded) { + xtty->begin_elem("make_unloaded thread='" UINTX_FORMAT "'", + os::current_thread_id()); + } else { + xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'%s", + os::current_thread_id(), + (flags.state == zombie ? " zombie='1'" : "")); + } log_identity(xtty); xtty->stamp(); xtty->end_elem(); } } - if (PrintCompilation) { - print_on(tty, state == zombie ? "made zombie " : "made not entrant "); + if (PrintCompilation && flags.state != unloaded) { + print_on(tty, flags.state == zombie ? "made zombie " : "made not entrant "); tty->cr(); } } // Common functionality for both make_not_entrant and make_zombie -void nmethod::make_not_entrant_or_zombie(int state) { +bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == zombie || state == not_entrant, "must be zombie or not_entrant"); - // Code for an on-stack-replacement nmethod is removed when a class gets unloaded. - // They never become zombie/non-entrant, so the nmethod sweeper will never remove - // them. Instead the entry_bci is set to InvalidOSREntryBci, so the osr nmethod - // will never be used anymore. That the nmethods only gets removed when class unloading - // happens, make life much simpler, since the nmethods are not just going to disappear - // out of the blue. - if (is_osr_method()) { - if (osr_entry_bci() != InvalidOSREntryBci) { - // only log this once - log_state_change(state); - } - invalidate_osr_method(); - return; + // If the method is already zombie there is nothing to do + if (is_zombie()) { + return false; } - // If the method is already zombie or set to the state we want, nothing to do - if (is_zombie() || (state == not_entrant && is_not_entrant())) { - return; - } - - log_state_change(state); - // Make sure the nmethod is not flushed in case of a safepoint in code below. nmethodLocker nml(this); { + // invalidate osr nmethod before acquiring the patching lock since + // they both acquire leaf locks and we don't want a deadlock. + // This logic is equivalent to the logic below for patching the + // verified entry point of regular methods. + if (is_osr_method()) { + // this effectively makes the osr nmethod not entrant + invalidate_osr_method(); + } + // Enter critical section. Does not block for safepoint. MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + + if (flags.state == state) { + // another thread already performed this transition so nothing + // to do, but return false to indicate this. + return false; + } + // The caller can be calling the method statically or through an inline // cache call. - if (!is_not_entrant()) { + if (!is_osr_method() && !is_not_entrant()) { NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), SharedRuntime::get_handle_wrong_method_stub()); assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, ""); @@ -1217,6 +1221,10 @@ void nmethod::make_not_entrant_or_zombie(int state) { // Change state flags.state = state; + + // Log the transition once + log_state_change(); + } // leave critical region under Patching_lock if (state == not_entrant) { @@ -1240,7 +1248,6 @@ void nmethod::make_not_entrant_or_zombie(int state) { // It's a true state change, so mark the method as decompiled. inc_decompile_count(); - // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event // and it hasn't already been reported for this nmethod then report it now. // (the event may have been reported earilier if the GC marked it for unloading). @@ -1268,7 +1275,7 @@ void nmethod::make_not_entrant_or_zombie(int state) { // Check whether method got unloaded at a safepoint before this, // if so we can skip the flushing steps below - if (method() == NULL) return; + if (method() == NULL) return true; // Remove nmethod from method. // We need to check if both the _code and _from_compiled_code_entry_point @@ -1282,6 +1289,8 @@ void nmethod::make_not_entrant_or_zombie(int state) { HandleMark hm; method()->clear_code(); } + + return true; } @@ -1715,9 +1724,9 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci()); - bool is_static = call->is_invokestatic(); + bool has_receiver = call->has_receiver(); symbolOop signature = call->signature(); - fr.oops_compiled_arguments_do(signature, is_static, reg_map, f); + fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); } } @@ -1754,6 +1763,14 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { "must end with a sentinel"); #endif //ASSERT + // Search for MethodHandle invokes and tag the nmethod. + for (int i = 0; i < count; i++) { + if (pcs[i].is_method_handle_invoke()) { + set_has_method_handle_invokes(true); + break; + } + } + int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); memcpy(scopes_pcs_begin(), pcs, size); @@ -2020,6 +2037,18 @@ bool nmethod::is_deopt_pc(address pc) { } +// ----------------------------------------------------------------------------- +// MethodHandle + +bool nmethod::is_method_handle_return(address return_pc) { + if (!has_method_handle_invokes()) return false; + PcDesc* pd = pc_desc_at(return_pc); + if (pd == NULL) + return false; + return pd->is_method_handle_invoke(); +} + + // ----------------------------------------------------------------------------- // Verification @@ -2370,6 +2399,107 @@ ScopeDesc* nmethod::scope_desc_in(address begin, address end) { return NULL; } +void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) { + if (block_begin == entry_point()) stream->print_cr("[Entry Point]"); + if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]"); + if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); + if (block_begin == stub_begin()) stream->print_cr("[Stub Code]"); + if (block_begin == consts_begin()) stream->print_cr("[Constants]"); + if (block_begin == entry_point()) { + methodHandle m = method(); + if (m.not_null()) { + stream->print(" # "); + m->print_value_on(stream); + stream->cr(); + } + if (m.not_null() && !is_osr_method()) { + ResourceMark rm; + int sizeargs = m->size_of_parameters(); + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sizeargs); + VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, sizeargs); + { + int sig_index = 0; + if (!m->is_static()) + sig_bt[sig_index++] = T_OBJECT; // 'this' + for (SignatureStream ss(m->signature()); !ss.at_return_type(); ss.next()) { + BasicType t = ss.type(); + sig_bt[sig_index++] = t; + if (type2size[t] == 2) { + sig_bt[sig_index++] = T_VOID; + } else { + assert(type2size[t] == 1, "size is 1 or 2"); + } + } + assert(sig_index == sizeargs, ""); + } + const char* spname = "sp"; // make arch-specific? + intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs, false); + int stack_slot_offset = this->frame_size() * wordSize; + int tab1 = 14, tab2 = 24; + int sig_index = 0; + int arg_index = (m->is_static() ? 0 : -1); + bool did_old_sp = false; + for (SignatureStream ss(m->signature()); !ss.at_return_type(); ) { + bool at_this = (arg_index == -1); + bool at_old_sp = false; + BasicType t = (at_this ? T_OBJECT : ss.type()); + assert(t == sig_bt[sig_index], "sigs in sync"); + if (at_this) + stream->print(" # this: "); + else + stream->print(" # parm%d: ", arg_index); + stream->move_to(tab1); + VMReg fst = regs[sig_index].first(); + VMReg snd = regs[sig_index].second(); + if (fst->is_reg()) { + stream->print("%s", fst->name()); + if (snd->is_valid()) { + stream->print(":%s", snd->name()); + } + } else if (fst->is_stack()) { + int offset = fst->reg2stack() * VMRegImpl::stack_slot_size + stack_slot_offset; + if (offset == stack_slot_offset) at_old_sp = true; + stream->print("[%s+0x%x]", spname, offset); + } else { + stream->print("reg%d:%d??", (int)(intptr_t)fst, (int)(intptr_t)snd); + } + stream->print(" "); + stream->move_to(tab2); + stream->print("= "); + if (at_this) { + m->method_holder()->print_value_on(stream); + } else { + bool did_name = false; + if (!at_this && ss.is_object()) { + symbolOop name = ss.as_symbol_or_null(); + if (name != NULL) { + name->print_value_on(stream); + did_name = true; + } + } + if (!did_name) + stream->print("%s", type2name(t)); + } + if (at_old_sp) { + stream->print(" (%s of caller)", spname); + did_old_sp = true; + } + stream->cr(); + sig_index += type2size[t]; + arg_index += 1; + if (!at_this) ss.next(); + } + if (!did_old_sp) { + stream->print(" # "); + stream->move_to(tab1); + stream->print("[%s+0x%x]", spname, stack_slot_offset); + stream->print(" (%s of caller)", spname); + stream->cr(); + } + } + } +} + void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, u_char* end) { // First, find an oopmap in (begin, end]. // We use the odd half-closed interval so that oop maps and scope descs diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index c7abdea89c8..26a7edaac81 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -81,18 +81,19 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC { struct nmFlags { friend class VMStructs; - unsigned int version:8; // version number (0 = first version) - unsigned int level:4; // optimization level - unsigned int age:4; // age (in # of sweep steps) + unsigned int version:8; // version number (0 = first version) + unsigned int level:4; // optimization level + unsigned int age:4; // age (in # of sweep steps) - unsigned int state:2; // {alive, zombie, unloaded) + unsigned int state:2; // {alive, zombie, unloaded) - unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap? - unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures - unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies - unsigned int markedForReclamation:1; // Used by NMethodSweeper + unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap? + unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures + unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies + unsigned int markedForReclamation:1; // Used by NMethodSweeper - unsigned int has_unsafe_access:1; // May fault due to unsafe access. + unsigned int has_unsafe_access:1; // May fault due to unsafe access. + unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes? void clear(); }; @@ -252,7 +253,9 @@ class nmethod : public CodeBlob { void* operator new(size_t size, int nmethod_size); const char* reloc_string_for(u_char* begin, u_char* end); - void make_not_entrant_or_zombie(int state); + // Returns true if this thread changed the state of the nmethod or + // false if another thread performed the transition. + bool make_not_entrant_or_zombie(unsigned int state); void inc_decompile_count(); // used to check that writes to nmFlags are done consistently. @@ -375,10 +378,12 @@ class nmethod : public CodeBlob { bool is_zombie() const { return flags.state == zombie; } bool is_unloaded() const { return flags.state == unloaded; } - // Make the nmethod non entrant. The nmethod will continue to be alive. - // It is used when an uncommon trap happens. - void make_not_entrant() { make_not_entrant_or_zombie(not_entrant); } - void make_zombie() { make_not_entrant_or_zombie(zombie); } + // Make the nmethod non entrant. The nmethod will continue to be + // alive. It is used when an uncommon trap happens. Returns true + // if this thread changed the state of the nmethod or false if + // another thread performed the transition. + bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } + bool make_zombie() { return make_not_entrant_or_zombie(zombie); } // used by jvmti to track if the unload event has been reported bool unload_reported() { return _unload_reported; } @@ -405,6 +410,9 @@ class nmethod : public CodeBlob { bool has_unsafe_access() const { return flags.has_unsafe_access; } void set_has_unsafe_access(bool z) { flags.has_unsafe_access = z; } + bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; } + void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; } + int level() const { return flags.level; } void set_level(int newLevel) { check_safepoint(); flags.level = newLevel; } @@ -537,6 +545,9 @@ class nmethod : public CodeBlob { address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; } + // MethodHandle + bool is_method_handle_return(address return_pc); + // jvmti support: void post_compiled_method_load_event(); @@ -563,7 +574,14 @@ class nmethod : public CodeBlob { // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; - void log_state_change(int state) const; + void log_state_change() const; + + // Prints block-level comments, including nmethod specific block labels: + virtual void print_block_comment(outputStream* stream, address block_begin) { + print_nmethod_labels(stream, block_begin); + CodeBlob::print_block_comment(stream, block_begin); + } + void print_nmethod_labels(outputStream* stream, address block_begin); // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); diff --git a/hotspot/src/share/vm/code/pcDesc.hpp b/hotspot/src/share/vm/code/pcDesc.hpp index de9334b4cee..74d3baaf2f7 100644 --- a/hotspot/src/share/vm/code/pcDesc.hpp +++ b/hotspot/src/share/vm/code/pcDesc.hpp @@ -38,6 +38,7 @@ class PcDesc VALUE_OBJ_CLASS_SPEC { int word; struct { unsigned int reexecute: 1; + unsigned int is_method_handle_invoke: 1; } bits; bool operator ==(const PcDescFlags& other) { return word == other.word; } } _flags; @@ -72,6 +73,9 @@ class PcDesc VALUE_OBJ_CLASS_SPEC { _flags == pd->_flags; } + bool is_method_handle_invoke() const { return _flags.bits.is_method_handle_invoke; } + void set_is_method_handle_invoke(bool z) { _flags.bits.is_method_handle_invoke = z; } + // Returns the real pc address real_pc(const nmethod* code) const; diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 799d9f89202..41d963a253e 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -1820,9 +1820,11 @@ void CompileBroker::print_times() { CompileBroker::_t_standard_compilation.seconds(), CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); - compiler(CompLevel_fast_compile)->print_timers(); - if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier)) { - compiler(CompLevel_highest_tier)->print_timers(); + + if (compiler(CompLevel_fast_compile)) { + compiler(CompLevel_fast_compile)->print_timers(); + if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier)) + compiler(CompLevel_highest_tier)->print_timers(); } tty->cr(); diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index 1829e044a06..73f36d7016b 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -392,18 +392,18 @@ static const char* patterns[] = { }; static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { - if (strcmp(name, "*") == 0) return MethodMatcher::Any; - int match = MethodMatcher::Exact; - if (name[0] == '*') { + while (name[0] == '*') { match |= MethodMatcher::Suffix; strcpy(name, name + 1); } + if (strcmp(name, "*") == 0) return MethodMatcher::Any; + size_t len = strlen(name); - if (len > 0 && name[len - 1] == '*') { + while (len > 0 && name[len - 1] == '*') { match |= MethodMatcher::Prefix; - name[len - 1] = '\0'; + name[--len] = '\0'; } if (strstr(name, "*") != NULL) { @@ -610,6 +610,14 @@ void compilerOracle_init() { CompilerOracle::parse_from_string(CompileCommand, CompilerOracle::parse_from_line); CompilerOracle::parse_from_string(CompileOnly, CompilerOracle::parse_compile_only); CompilerOracle::parse_from_file(); + if (lists[PrintCommand] != NULL) { + if (PrintAssembly) { + warning("CompileCommand and/or .hotspot_compiler file contains 'print' commands, but PrintAssembly is also enabled"); + } else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) { + warning("printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output"); + DebugNonSafepoints = true; + } + } } diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 3e800e9b9e7..dc33af2ee5b 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -151,8 +151,10 @@ class decode_env { outputStream* st = output(); if (_print_bytes && pc > pc0) print_insn_bytes(pc0, pc); - if (_nm != NULL) + if (_nm != NULL) { _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); + // this calls reloc_string_for which calls oop::print_value_on + } // Output pc bucket ticks if we have any if (total_ticks() != 0) { @@ -273,8 +275,15 @@ void decode_env::print_address(address adr) { oop obj; if (_nm != NULL && (obj = _nm->embeddedOop_at(cur_insn())) != NULL - && (address) obj == adr) { + && (address) obj == adr + && Universe::heap()->is_in(obj) + && Universe::heap()->is_in(obj->klass())) { + julong c = st->count(); obj->print_value_on(st); + if (st->count() == c) { + // No output. (Can happen in product builds.) + st->print("(a %s)", Klass::cast(obj->klass())->external_name()); + } return; } } @@ -286,17 +295,9 @@ void decode_env::print_address(address adr) { void decode_env::print_insn_labels() { address p = cur_insn(); outputStream* st = output(); - nmethod* nm = _nm; - if (nm != NULL) { - if (p == nm->entry_point()) st->print_cr("[Entry Point]"); - if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]"); - if (p == nm->exception_begin()) st->print_cr("[Exception Handler]"); - if (p == nm->stub_begin()) st->print_cr("[Stub Code]"); - if (p == nm->consts_begin()) st->print_cr("[Constants]"); - } CodeBlob* cb = _code; if (cb != NULL) { - cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin())); + cb->print_block_comment(st, p); } if (_print_pc) { st->print(" " INTPTR_FORMAT ": ", (intptr_t) p); diff --git a/hotspot/src/share/vm/compiler/methodLiveness.cpp b/hotspot/src/share/vm/compiler/methodLiveness.cpp index a9a90a07197..4c53bcc1829 100644 --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp @@ -782,6 +782,7 @@ void MethodLiveness::BasicBlock::compute_gen_kill_single(ciBytecodeStream *instr case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: + case Bytecodes::_invokedynamic: case Bytecodes::_newarray: case Bytecodes::_anewarray: case Bytecodes::_checkcast: diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp index eb1a1118d72..ec4caa22fc6 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp @@ -62,12 +62,13 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) { tl->link_head(tc); tl->link_tail(tc); tl->set_count(1); - tl->init_statistics(); + tl->init_statistics(true /* split_birth */); tl->setParent(NULL); tl->setLeft(NULL); tl->setRight(NULL); return tl; } + TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { TreeChunk* tc = (TreeChunk*) addr; assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk"); @@ -267,6 +268,31 @@ TreeChunk* TreeList::first_available() { return retTC; } +// Returns the block with the largest heap address amongst +// those in the list for this size; potentially slow and expensive, +// use with caution! +TreeChunk* TreeList::largest_address() { + guarantee(head() != NULL, "The head of the list cannot be NULL"); + FreeChunk* fc = head()->next(); + TreeChunk* retTC; + if (fc == NULL) { + retTC = head_as_TreeChunk(); + } else { + // walk down the list and return the one with the highest + // heap address among chunks of this size. + FreeChunk* last = fc; + while (fc->next() != NULL) { + if ((HeapWord*)last < (HeapWord*)fc) { + last = fc; + } + fc = fc->next(); + } + retTC = TreeChunk::as_TreeChunk(last); + } + assert(retTC->list() == this, "Wrong type of chunk."); + return retTC; +} + BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay): _splay(splay) { @@ -379,7 +405,7 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) break; } // The evm code reset the hint of the candidate as - // at an interrim point. Why? Seems like this leaves + // at an interim point. Why? Seems like this leaves // the hint pointing to a list that didn't work. // curTL->set_hint(hintTL->size()); } @@ -436,7 +462,7 @@ FreeChunk* BinaryTreeDictionary::findLargestDict() const { TreeList *curTL = root(); if (curTL != NULL) { while(curTL->right() != NULL) curTL = curTL->right(); - return curTL->first_available(); + return curTL->largest_address(); } else { return NULL; } @@ -664,7 +690,7 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { } } TreeChunk* tc = TreeChunk::as_TreeChunk(fc); - // This chunk is being returned to the binary try. It's embedded + // This chunk is being returned to the binary tree. Its embedded // TreeList should be unused at this point. tc->initialize(); if (curTL != NULL) { // exact match @@ -807,6 +833,8 @@ void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth) } bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { + if (FLSAlwaysCoalesceLarge) return true; + TreeList* list_of_size = findList(size); // None of requested size implies overpopulated. return list_of_size == NULL || list_of_size->coalDesired() <= 0 || @@ -854,17 +882,20 @@ class BeginSweepClosure : public AscendTreeCensusClosure { double _percentage; float _inter_sweep_current; float _inter_sweep_estimate; + float _intra_sweep_estimate; public: BeginSweepClosure(double p, float inter_sweep_current, - float inter_sweep_estimate) : + float inter_sweep_estimate, + float intra_sweep_estimate) : _percentage(p), _inter_sweep_current(inter_sweep_current), - _inter_sweep_estimate(inter_sweep_estimate) { } + _inter_sweep_estimate(inter_sweep_estimate), + _intra_sweep_estimate(intra_sweep_estimate) { } void do_list(FreeList* fl) { double coalSurplusPercent = _percentage; - fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate); + fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate); fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent)); fl->set_beforeSweep(fl->count()); fl->set_bfrSurp(fl->surplus()); @@ -939,9 +970,10 @@ FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const { } void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, - float inter_sweep_current, float inter_sweep_estimate) { + float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) { BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current, - inter_sweep_estimate); + inter_sweep_estimate, + intra_sweep_estimate); bsc.do_tree(root()); } @@ -1077,13 +1109,13 @@ void BinaryTreeDictionary::reportStatistics() const { // Print census information - counts, births, deaths, etc. // for each list in the tree. Also print some summary // information. -class printTreeCensusClosure : public AscendTreeCensusClosure { +class PrintTreeCensusClosure : public AscendTreeCensusClosure { int _print_line; size_t _totalFree; FreeList _total; public: - printTreeCensusClosure() { + PrintTreeCensusClosure() { _print_line = 0; _totalFree = 0; } @@ -1113,7 +1145,7 @@ void BinaryTreeDictionary::printDictCensus(void) const { gclog_or_tty->print("\nBinaryTree\n"); FreeList::print_labels_on(gclog_or_tty, "size"); - printTreeCensusClosure ptc; + PrintTreeCensusClosure ptc; ptc.do_tree(root()); FreeList* total = ptc.total(); @@ -1130,6 +1162,38 @@ void BinaryTreeDictionary::printDictCensus(void) const { /(total->desired() != 0 ? (double)total->desired() : 1.0)); } +class PrintFreeListsClosure : public AscendTreeCensusClosure { + outputStream* _st; + int _print_line; + + public: + PrintFreeListsClosure(outputStream* st) { + _st = st; + _print_line = 0; + } + void do_list(FreeList* fl) { + if (++_print_line >= 40) { + FreeList::print_labels_on(_st, "size"); + _print_line = 0; + } + fl->print_on(gclog_or_tty); + size_t sz = fl->size(); + for (FreeChunk* fc = fl->head(); fc != NULL; + fc = fc->next()) { + _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s", + fc, (HeapWord*)fc + sz, + fc->cantCoalesce() ? "\t CC" : ""); + } + } +}; + +void BinaryTreeDictionary::print_free_lists(outputStream* st) const { + + FreeList::print_labels_on(st, "size"); + PrintFreeListsClosure pflc(st); + pflc.do_tree(root()); +} + // Verify the following tree invariants: // . _root has no parent // . parent and child point to each other diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp index d45193be9fb..0a107da91ab 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp @@ -42,9 +42,6 @@ class TreeList: public FreeList { friend class AscendTreeCensusClosure; friend class DescendTreeCensusClosure; friend class DescendTreeSearchClosure; - TreeList* _parent; - TreeList* _left; - TreeList* _right; protected: TreeList* parent() const { return _parent; } @@ -82,6 +79,11 @@ class TreeList: public FreeList { // to a TreeChunk. TreeChunk* first_available(); + // Returns the block with the largest heap address amongst + // those in the list for this size; potentially slow and expensive, + // use with caution! + TreeChunk* largest_address(); + // removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList. // If "tc" is the first chunk in the list, it is also the // TreeList that is the node in the tree. removeChunkReplaceIfNeeded() @@ -254,8 +256,9 @@ class BinaryTreeDictionary: public FreeBlockDictionary { // Methods called at the beginning of a sweep to prepare the // statistics for the sweep. void beginSweepDictCensus(double coalSurplusPercent, - float sweep_current, - float sweep_estimate); + float inter_sweep_current, + float inter_sweep_estimate, + float intra_sweep_estimate); // Methods called after the end of a sweep to modify the // statistics for the sweep. void endSweepDictCensus(double splitSurplusPercent); @@ -269,6 +272,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary { // Print the statistcis for all the lists in the tree. Also may // print out summaries. void printDictCensus(void) const; + void print_free_lists(outputStream* st) const; // For debugging. Returns the sum of the _returnedBytes for // all lists in the tree. diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.cpp index 00ef43f6957..b0ee1e8869e 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.cpp @@ -32,7 +32,9 @@ // threads. The second argument is in support of an extra locking // check for CFL spaces' free list locks. #ifndef PRODUCT -void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { +void CMSLockVerifier::assert_locked(const Mutex* lock, + const Mutex* p_lock1, + const Mutex* p_lock2) { if (!Universe::is_fully_initialized()) { return; } @@ -40,7 +42,7 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { Thread* myThread = Thread::current(); if (lock == NULL) { // a "lock-free" structure, e.g. MUT, protected by CMS token - assert(p_lock == NULL, "Unexpected state"); + assert(p_lock1 == NULL && p_lock2 == NULL, "Unexpected caller error"); if (myThread->is_ConcurrentGC_thread()) { // This test might have to change in the future, if there can be // multiple peer CMS threads. But for now, if we're testing the CMS @@ -60,36 +62,39 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) { return; } - if (ParallelGCThreads == 0) { + if (myThread->is_VM_thread() + || myThread->is_ConcurrentGC_thread() + || myThread->is_Java_thread()) { + // Make sure that we are holding the associated lock. assert_lock_strong(lock); - } else { - if (myThread->is_VM_thread() - || myThread->is_ConcurrentGC_thread() - || myThread->is_Java_thread()) { - // Make sure that we are holding the associated lock. - assert_lock_strong(lock); - // The checking of p_lock is a spl case for CFLS' free list - // locks: we make sure that none of the parallel GC work gang - // threads are holding "sub-locks" of freeListLock(). We check only - // the parDictionaryAllocLock because the others are too numerous. - // This spl case code is somewhat ugly and any improvements - // are welcome XXX FIX ME!! - if (p_lock != NULL) { - assert(!p_lock->is_locked() || p_lock->owned_by_self(), - "Possible race between this and parallel GC threads"); - } - } else if (myThread->is_GC_task_thread()) { - // Make sure that the VM or CMS thread holds lock on our behalf - // XXX If there were a concept of a gang_master for a (set of) - // gang_workers, we could have used the identity of that thread - // for checking ownership here; for now we just disjunct. - assert(lock->owner() == VMThread::vm_thread() || - lock->owner() == ConcurrentMarkSweepThread::cmst(), - "Should be locked by VM thread or CMS thread on my behalf"); - } else { - // Make sure we didn't miss some obscure corner case - ShouldNotReachHere(); + // The checking of p_lock is a spl case for CFLS' free list + // locks: we make sure that none of the parallel GC work gang + // threads are holding "sub-locks" of freeListLock(). We check only + // the parDictionaryAllocLock because the others are too numerous. + // This spl case code is somewhat ugly and any improvements + // are welcome. + assert(p_lock1 == NULL || !p_lock1->is_locked() || p_lock1->owned_by_self(), + "Possible race between this and parallel GC threads"); + assert(p_lock2 == NULL || !p_lock2->is_locked() || p_lock2->owned_by_self(), + "Possible race between this and parallel GC threads"); + } else if (myThread->is_GC_task_thread()) { + // Make sure that the VM or CMS thread holds lock on our behalf + // XXX If there were a concept of a gang_master for a (set of) + // gang_workers, we could have used the identity of that thread + // for checking ownership here; for now we just disjunct. + assert(lock->owner() == VMThread::vm_thread() || + lock->owner() == ConcurrentMarkSweepThread::cmst(), + "Should be locked by VM thread or CMS thread on my behalf"); + if (p_lock1 != NULL) { + assert_lock_strong(p_lock1); } + if (p_lock2 != NULL) { + assert_lock_strong(p_lock2); + } + } else { + // Make sure we didn't miss some other thread type calling into here; + // perhaps as a result of future VM evolution. + ShouldNotReachHere(); } } #endif diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.hpp index f2fe4514061..943eba0374c 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsLockVerifier.hpp @@ -29,8 +29,11 @@ // the parallel threads. class CMSLockVerifier: AllStatic { public: - static void assert_locked(const Mutex* lock, const Mutex* p_lock) + static void assert_locked(const Mutex* lock, const Mutex* p_lock1, const Mutex* p_lock2) PRODUCT_RETURN; + static void assert_locked(const Mutex* lock, const Mutex* p_lock) { + assert_locked(lock, p_lock, NULL); + } static void assert_locked(const Mutex* lock) { assert_locked(lock, NULL); } diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 6b4bd36d934..9e3b6cf81cc 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -62,18 +62,15 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, // implementation, namely, the simple binary tree (splaying // temporarily disabled). switch (dictionaryChoice) { - case FreeBlockDictionary::dictionaryBinaryTree: - _dictionary = new BinaryTreeDictionary(mr); - break; case FreeBlockDictionary::dictionarySplayTree: case FreeBlockDictionary::dictionarySkipList: default: warning("dictionaryChoice: selected option not understood; using" " default BinaryTreeDictionary implementation instead."); + case FreeBlockDictionary::dictionaryBinaryTree: _dictionary = new BinaryTreeDictionary(mr); break; } - splitBirth(mr.word_size()); assert(_dictionary != NULL, "CMS dictionary initialization"); // The indexed free lists are initially all empty and are lazily // filled in on demand. Initialize the array elements to NULL. @@ -388,6 +385,105 @@ size_t CompactibleFreeListSpace::max_alloc_in_words() const { return res; } +void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st) +const { + reportIndexedFreeListStatistics(); + gclog_or_tty->print_cr("Layout of Indexed Freelists"); + gclog_or_tty->print_cr("---------------------------"); + FreeList::print_labels_on(st, "size"); + for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { + _indexedFreeList[i].print_on(gclog_or_tty); + for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL; + fc = fc->next()) { + gclog_or_tty->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s", + fc, (HeapWord*)fc + i, + fc->cantCoalesce() ? "\t CC" : ""); + } + } +} + +void CompactibleFreeListSpace::print_promo_info_blocks(outputStream* st) +const { + _promoInfo.print_on(st); +} + +void CompactibleFreeListSpace::print_dictionary_free_lists(outputStream* st) +const { + _dictionary->reportStatistics(); + st->print_cr("Layout of Freelists in Tree"); + st->print_cr("---------------------------"); + _dictionary->print_free_lists(st); +} + +class BlkPrintingClosure: public BlkClosure { + const CMSCollector* _collector; + const CompactibleFreeListSpace* _sp; + const CMSBitMap* _live_bit_map; + const bool _post_remark; + outputStream* _st; +public: + BlkPrintingClosure(const CMSCollector* collector, + const CompactibleFreeListSpace* sp, + const CMSBitMap* live_bit_map, + outputStream* st): + _collector(collector), + _sp(sp), + _live_bit_map(live_bit_map), + _post_remark(collector->abstract_state() > CMSCollector::FinalMarking), + _st(st) { } + size_t do_blk(HeapWord* addr); +}; + +size_t BlkPrintingClosure::do_blk(HeapWord* addr) { + size_t sz = _sp->block_size_no_stall(addr, _collector); + assert(sz != 0, "Should always be able to compute a size"); + if (_sp->block_is_obj(addr)) { + const bool dead = _post_remark && !_live_bit_map->isMarked(addr); + _st->print_cr(PTR_FORMAT ": %s object of size " SIZE_FORMAT "%s", + addr, + dead ? "dead" : "live", + sz, + (!dead && CMSPrintObjectsInDump) ? ":" : "."); + if (CMSPrintObjectsInDump && !dead) { + oop(addr)->print_on(_st); + _st->print_cr("--------------------------------------"); + } + } else { // free block + _st->print_cr(PTR_FORMAT ": free block of size " SIZE_FORMAT "%s", + addr, sz, CMSPrintChunksInDump ? ":" : "."); + if (CMSPrintChunksInDump) { + ((FreeChunk*)addr)->print_on(_st); + _st->print_cr("--------------------------------------"); + } + } + return sz; +} + +void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c, + outputStream* st) { + st->print_cr("\n========================="); + st->print_cr("Block layout in CMS Heap:"); + st->print_cr("========================="); + BlkPrintingClosure bpcl(c, this, c->markBitMap(), st); + blk_iterate(&bpcl); + + st->print_cr("\n======================================="); + st->print_cr("Order & Layout of Promotion Info Blocks"); + st->print_cr("======================================="); + print_promo_info_blocks(st); + + st->print_cr("\n==========================="); + st->print_cr("Order of Indexed Free Lists"); + st->print_cr("========================="); + print_indexed_free_lists(st); + + st->print_cr("\n================================="); + st->print_cr("Order of Free Lists in Dictionary"); + st->print_cr("================================="); + print_dictionary_free_lists(st); +} + + void CompactibleFreeListSpace::reportFreeListStatistics() const { assert_lock_strong(&_freelistLock); assert(PrintFLSStatistics != 0, "Reporting error"); @@ -449,37 +545,37 @@ void CompactibleFreeListSpace::set_end(HeapWord* value) { if (prevEnd != NULL) { // Resize the underlying block offset table. _bt.resize(pointer_delta(value, bottom())); - if (value <= prevEnd) { - assert(value >= unallocated_block(), "New end is below unallocated block"); - } else { - // Now, take this new chunk and add it to the free blocks. - // Note that the BOT has not yet been updated for this block. - size_t newFcSize = pointer_delta(value, prevEnd); - // XXX This is REALLY UGLY and should be fixed up. XXX - if (!_adaptive_freelists && _smallLinearAllocBlock._ptr == NULL) { - // Mark the boundary of the new block in BOT - _bt.mark_block(prevEnd, value); - // put it all in the linAB - if (ParallelGCThreads == 0) { - _smallLinearAllocBlock._ptr = prevEnd; - _smallLinearAllocBlock._word_size = newFcSize; - repairLinearAllocBlock(&_smallLinearAllocBlock); - } else { // ParallelGCThreads > 0 - MutexLockerEx x(parDictionaryAllocLock(), - Mutex::_no_safepoint_check_flag); - _smallLinearAllocBlock._ptr = prevEnd; - _smallLinearAllocBlock._word_size = newFcSize; - repairLinearAllocBlock(&_smallLinearAllocBlock); - } - // Births of chunks put into a LinAB are not recorded. Births - // of chunks as they are allocated out of a LinAB are. + if (value <= prevEnd) { + assert(value >= unallocated_block(), "New end is below unallocated block"); } else { - // Add the block to the free lists, if possible coalescing it - // with the last free block, and update the BOT and census data. - addChunkToFreeListsAtEndRecordingStats(prevEnd, newFcSize); + // Now, take this new chunk and add it to the free blocks. + // Note that the BOT has not yet been updated for this block. + size_t newFcSize = pointer_delta(value, prevEnd); + // XXX This is REALLY UGLY and should be fixed up. XXX + if (!_adaptive_freelists && _smallLinearAllocBlock._ptr == NULL) { + // Mark the boundary of the new block in BOT + _bt.mark_block(prevEnd, value); + // put it all in the linAB + if (ParallelGCThreads == 0) { + _smallLinearAllocBlock._ptr = prevEnd; + _smallLinearAllocBlock._word_size = newFcSize; + repairLinearAllocBlock(&_smallLinearAllocBlock); + } else { // ParallelGCThreads > 0 + MutexLockerEx x(parDictionaryAllocLock(), + Mutex::_no_safepoint_check_flag); + _smallLinearAllocBlock._ptr = prevEnd; + _smallLinearAllocBlock._word_size = newFcSize; + repairLinearAllocBlock(&_smallLinearAllocBlock); + } + // Births of chunks put into a LinAB are not recorded. Births + // of chunks as they are allocated out of a LinAB are. + } else { + // Add the block to the free lists, if possible coalescing it + // with the last free block, and update the BOT and census data. + addChunkToFreeListsAtEndRecordingStats(prevEnd, newFcSize); + } } } - } } class FreeListSpace_DCTOC : public Filtering_DCTOC { @@ -732,7 +828,7 @@ void CompactibleFreeListSpace::safe_object_iterate(ObjectClosure* blk) { void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { - assert_locked(); + assert_locked(freelistLock()); NOT_PRODUCT(verify_objects_initialized()); Space::object_iterate_mem(mr, cl); } @@ -1212,12 +1308,15 @@ bool CompactibleFreeListSpace::verifyChunkInFreeLists(FreeChunk* fc) const { void CompactibleFreeListSpace::assert_locked() const { CMSLockVerifier::assert_locked(freelistLock(), parDictionaryAllocLock()); } + +void CompactibleFreeListSpace::assert_locked(const Mutex* lock) const { + CMSLockVerifier::assert_locked(lock); +} #endif FreeChunk* CompactibleFreeListSpace::allocateScratch(size_t size) { // In the parallel case, the main thread holds the free list lock // on behalf the parallel threads. - assert_locked(); FreeChunk* fc; { // If GC is parallel, this might be called by several threads. @@ -1298,17 +1397,18 @@ CompactibleFreeListSpace::getChunkFromLinearAllocBlock(LinearAllocBlock *blk, res = blk->_ptr; _bt.allocated(res, blk->_word_size); } else if (size + MinChunkSize <= blk->_refillSize) { + size_t sz = blk->_word_size; // Update _unallocated_block if the size is such that chunk would be // returned to the indexed free list. All other chunks in the indexed // free lists are allocated from the dictionary so that _unallocated_block // has already been adjusted for them. Do it here so that the cost // for all chunks added back to the indexed free lists. - if (blk->_word_size < SmallForDictionary) { - _bt.allocated(blk->_ptr, blk->_word_size); + if (sz < SmallForDictionary) { + _bt.allocated(blk->_ptr, sz); } // Return the chunk that isn't big enough, and then refill below. - addChunkToFreeLists(blk->_ptr, blk->_word_size); - _bt.verify_single_block(blk->_ptr, (blk->_ptr + blk->_word_size)); + addChunkToFreeLists(blk->_ptr, sz); + splitBirth(sz); // Don't keep statistics on adding back chunk from a LinAB. } else { // A refilled block would not satisfy the request. @@ -1376,11 +1476,13 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeList(size_t size) { res = getChunkFromIndexedFreeListHelper(size); } _bt.verify_not_unallocated((HeapWord*) res, size); + assert(res == NULL || res->size() == size, "Incorrect block size"); return res; } FreeChunk* -CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) { +CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size, + bool replenish) { assert_locked(); FreeChunk* fc = NULL; if (size < SmallForDictionary) { @@ -1398,54 +1500,66 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) { // and replenishing indexed lists from the small linAB. // FreeChunk* newFc = NULL; - size_t replenish_size = CMSIndexedFreeListReplenish * size; + const size_t replenish_size = CMSIndexedFreeListReplenish * size; if (replenish_size < SmallForDictionary) { // Do not replenish from an underpopulated size. if (_indexedFreeList[replenish_size].surplus() > 0 && _indexedFreeList[replenish_size].head() != NULL) { - newFc = - _indexedFreeList[replenish_size].getChunkAtHead(); - } else { + newFc = _indexedFreeList[replenish_size].getChunkAtHead(); + } else if (bestFitFirst()) { newFc = bestFitSmall(replenish_size); } } - if (newFc != NULL) { - splitDeath(replenish_size); - } else if (replenish_size > size) { + if (newFc == NULL && replenish_size > size) { assert(CMSIndexedFreeListReplenish > 1, "ctl pt invariant"); - newFc = - getChunkFromIndexedFreeListHelper(replenish_size); + newFc = getChunkFromIndexedFreeListHelper(replenish_size, false); } + // Note: The stats update re split-death of block obtained above + // will be recorded below precisely when we know we are going to + // be actually splitting it into more than one pieces below. if (newFc != NULL) { - assert(newFc->size() == replenish_size, "Got wrong size"); - size_t i; - FreeChunk *curFc, *nextFc; - // carve up and link blocks 0, ..., CMSIndexedFreeListReplenish - 2 - // The last chunk is not added to the lists but is returned as the - // free chunk. - for (curFc = newFc, nextFc = (FreeChunk*)((HeapWord*)curFc + size), - i = 0; - i < (CMSIndexedFreeListReplenish - 1); - curFc = nextFc, nextFc = (FreeChunk*)((HeapWord*)nextFc + size), - i++) { + if (replenish || CMSReplenishIntermediate) { + // Replenish this list and return one block to caller. + size_t i; + FreeChunk *curFc, *nextFc; + size_t num_blk = newFc->size() / size; + assert(num_blk >= 1, "Smaller than requested?"); + assert(newFc->size() % size == 0, "Should be integral multiple of request"); + if (num_blk > 1) { + // we are sure we will be splitting the block just obtained + // into multiple pieces; record the split-death of the original + splitDeath(replenish_size); + } + // carve up and link blocks 0, ..., num_blk - 2 + // The last chunk is not added to the lists but is returned as the + // free chunk. + for (curFc = newFc, nextFc = (FreeChunk*)((HeapWord*)curFc + size), + i = 0; + i < (num_blk - 1); + curFc = nextFc, nextFc = (FreeChunk*)((HeapWord*)nextFc + size), + i++) { + curFc->setSize(size); + // Don't record this as a return in order to try and + // determine the "returns" from a GC. + _bt.verify_not_unallocated((HeapWord*) fc, size); + _indexedFreeList[size].returnChunkAtTail(curFc, false); + _bt.mark_block((HeapWord*)curFc, size); + splitBirth(size); + // Don't record the initial population of the indexed list + // as a split birth. + } + + // check that the arithmetic was OK above + assert((HeapWord*)nextFc == (HeapWord*)newFc + num_blk*size, + "inconsistency in carving newFc"); curFc->setSize(size); - // Don't record this as a return in order to try and - // determine the "returns" from a GC. - _bt.verify_not_unallocated((HeapWord*) fc, size); - _indexedFreeList[size].returnChunkAtTail(curFc, false); _bt.mark_block((HeapWord*)curFc, size); splitBirth(size); - // Don't record the initial population of the indexed list - // as a split birth. + fc = curFc; + } else { + // Return entire block to caller + fc = newFc; } - - // check that the arithmetic was OK above - assert((HeapWord*)nextFc == (HeapWord*)newFc + replenish_size, - "inconsistency in carving newFc"); - curFc->setSize(size); - _bt.mark_block((HeapWord*)curFc, size); - splitBirth(size); - return curFc; } } } else { @@ -1453,7 +1567,7 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) { // replenish the indexed free list. fc = getChunkFromDictionaryExact(size); } - assert(fc == NULL || fc->isFree(), "Should be returning a free chunk"); + // assert(fc == NULL || fc->isFree(), "Should be returning a free chunk"); return fc; } @@ -1512,6 +1626,11 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) { // adjust _unallocated_block downward, as necessary _bt.freed((HeapWord*)chunk, size); _dictionary->returnChunk(chunk); +#ifndef PRODUCT + if (CMSCollector::abstract_state() != CMSCollector::Sweeping) { + TreeChunk::as_TreeChunk(chunk)->list()->verify_stats(); + } +#endif // PRODUCT } void @@ -1525,6 +1644,11 @@ CompactibleFreeListSpace::returnChunkToFreeList(FreeChunk* fc) { } else { _indexedFreeList[size].returnChunkAtHead(fc); } +#ifndef PRODUCT + if (CMSCollector::abstract_state() != CMSCollector::Sweeping) { + _indexedFreeList[size].verify_stats(); + } +#endif // PRODUCT } // Add chunk to end of last block -- if it's the largest @@ -1537,7 +1661,6 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats( HeapWord* chunk, size_t size) { // check that the chunk does lie in this space! assert(chunk != NULL && is_in_reserved(chunk), "Not in this space!"); - assert_locked(); // One of the parallel gc task threads may be here // whilst others are allocating. Mutex* lock = NULL; @@ -1991,24 +2114,26 @@ double CompactibleFreeListSpace::flsFrag() const { return frag; } -#define CoalSurplusPercent 1.05 -#define SplitSurplusPercent 1.10 - void CompactibleFreeListSpace::beginSweepFLCensus( float inter_sweep_current, - float inter_sweep_estimate) { + float inter_sweep_estimate, + float intra_sweep_estimate) { assert_locked(); size_t i; for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { FreeList* fl = &_indexedFreeList[i]; - fl->compute_desired(inter_sweep_current, inter_sweep_estimate); - fl->set_coalDesired((ssize_t)((double)fl->desired() * CoalSurplusPercent)); + if (PrintFLSStatistics > 1) { + gclog_or_tty->print("size[%d] : ", i); + } + fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate); + fl->set_coalDesired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent)); fl->set_beforeSweep(fl->count()); fl->set_bfrSurp(fl->surplus()); } - _dictionary->beginSweepDictCensus(CoalSurplusPercent, + _dictionary->beginSweepDictCensus(CMSLargeCoalSurplusPercent, inter_sweep_current, - inter_sweep_estimate); + inter_sweep_estimate, + intra_sweep_estimate); } void CompactibleFreeListSpace::setFLSurplus() { @@ -2017,7 +2142,7 @@ void CompactibleFreeListSpace::setFLSurplus() { for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { FreeList *fl = &_indexedFreeList[i]; fl->set_surplus(fl->count() - - (ssize_t)((double)fl->desired() * SplitSurplusPercent)); + (ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent)); } } @@ -2048,6 +2173,11 @@ void CompactibleFreeListSpace::clearFLCensus() { } void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) { + if (PrintFLSStatistics > 0) { + HeapWord* largestAddr = (HeapWord*) dictionary()->findLargestDict(); + gclog_or_tty->print_cr("CMS: Large block " PTR_FORMAT, + largestAddr); + } setFLSurplus(); setFLHints(); if (PrintGC && PrintFLSCensus > 0) { @@ -2055,7 +2185,7 @@ void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) { } clearFLCensus(); assert_locked(); - _dictionary->endSweepDictCensus(SplitSurplusPercent); + _dictionary->endSweepDictCensus(CMSLargeSplitSurplusPercent); } bool CompactibleFreeListSpace::coalOverPopulated(size_t size) { @@ -2312,13 +2442,18 @@ void CompactibleFreeListSpace::verifyIndexedFreeLists() const { } void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const { - FreeChunk* fc = _indexedFreeList[size].head(); + FreeChunk* fc = _indexedFreeList[size].head(); + FreeChunk* tail = _indexedFreeList[size].tail(); + size_t num = _indexedFreeList[size].count(); + size_t n = 0; guarantee((size % 2 == 0) || fc == NULL, "Odd slots should be empty"); - for (; fc != NULL; fc = fc->next()) { + for (; fc != NULL; fc = fc->next(), n++) { guarantee(fc->size() == size, "Size inconsistency"); guarantee(fc->isFree(), "!free?"); guarantee(fc->next() == NULL || fc->next()->prev() == fc, "Broken list"); + guarantee((fc->next() == NULL) == (fc == tail), "Incorrect tail"); } + guarantee(n == num, "Incorrect count"); } #ifndef PRODUCT @@ -2516,11 +2651,41 @@ void PromotionInfo::startTrackingPromotions() { _tracking = true; } -void PromotionInfo::stopTrackingPromotions() { +#define CMSPrintPromoBlockInfo 1 + +void PromotionInfo::stopTrackingPromotions(uint worker_id) { assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex, "spooling inconsistency?"); _firstIndex = _nextIndex = 1; _tracking = false; + if (CMSPrintPromoBlockInfo > 1) { + print_statistics(worker_id); + } +} + +void PromotionInfo::print_statistics(uint worker_id) const { + assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex, + "Else will undercount"); + assert(CMSPrintPromoBlockInfo > 0, "Else unnecessary call"); + // Count the number of blocks and slots in the free pool + size_t slots = 0; + size_t blocks = 0; + for (SpoolBlock* cur_spool = _spareSpool; + cur_spool != NULL; + cur_spool = cur_spool->nextSpoolBlock) { + // the first entry is just a self-pointer; indices 1 through + // bufferSize - 1 are occupied (thus, bufferSize - 1 slots). + guarantee((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, + "first entry of displacedHdr should be self-referential"); + slots += cur_spool->bufferSize - 1; + blocks++; + } + if (_spoolHead != NULL) { + slots += _spoolHead->bufferSize - 1; + blocks++; + } + gclog_or_tty->print_cr(" [worker %d] promo_blocks = %d, promo_slots = %d ", + worker_id, blocks, slots); } // When _spoolTail is not NULL, then the slot <_spoolTail, _nextIndex> @@ -2584,15 +2749,84 @@ void PromotionInfo::verify() const { guarantee(numDisplacedHdrs == numObjsWithDisplacedHdrs, "Displaced hdr count"); } +void PromotionInfo::print_on(outputStream* st) const { + SpoolBlock* curSpool = NULL; + size_t i = 0; + st->print_cr("start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")", + _firstIndex, _nextIndex); + for (curSpool = _spoolHead; curSpool != _spoolTail && curSpool != NULL; + curSpool = curSpool->nextSpoolBlock) { + curSpool->print_on(st); + st->print_cr(" active "); + i++; + } + for (curSpool = _spoolTail; curSpool != NULL; + curSpool = curSpool->nextSpoolBlock) { + curSpool->print_on(st); + st->print_cr(" inactive "); + i++; + } + for (curSpool = _spareSpool; curSpool != NULL; + curSpool = curSpool->nextSpoolBlock) { + curSpool->print_on(st); + st->print_cr(" free "); + i++; + } + st->print_cr(SIZE_FORMAT " header spooling blocks", i); +} + +void SpoolBlock::print_on(outputStream* st) const { + st->print("[" PTR_FORMAT "," PTR_FORMAT "), " SIZE_FORMAT " HeapWords -> " PTR_FORMAT, + this, (HeapWord*)displacedHdr + bufferSize, + bufferSize, nextSpoolBlock); +} + +/////////////////////////////////////////////////////////////////////////// +// CFLS_LAB +/////////////////////////////////////////////////////////////////////////// + +#define VECTOR_257(x) \ + /* 1 2 3 4 5 6 7 8 9 1x 11 12 13 14 15 16 17 18 19 2x 21 22 23 24 25 26 27 28 29 3x 31 32 */ \ + { x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \ + x } + +// Initialize with default setting of CMSParPromoteBlocksToClaim, _not_ +// OldPLABSize, whose static default is different; if overridden at the +// command-line, this will get reinitialized via a call to +// modify_initialization() below. +AdaptiveWeightedAverage CFLS_LAB::_blocks_to_claim[] = + VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CMSParPromoteBlocksToClaim)); +size_t CFLS_LAB::_global_num_blocks[] = VECTOR_257(0); +int CFLS_LAB::_global_num_workers[] = VECTOR_257(0); CFLS_LAB::CFLS_LAB(CompactibleFreeListSpace* cfls) : _cfls(cfls) { - _blocks_to_claim = CMSParPromoteBlocksToClaim; + assert(CompactibleFreeListSpace::IndexSetSize == 257, "Modify VECTOR_257() macro above"); for (size_t i = CompactibleFreeListSpace::IndexSetStart; i < CompactibleFreeListSpace::IndexSetSize; i += CompactibleFreeListSpace::IndexSetStride) { _indexedFreeList[i].set_size(i); + _num_blocks[i] = 0; + } +} + +static bool _CFLS_LAB_modified = false; + +void CFLS_LAB::modify_initialization(size_t n, unsigned wt) { + assert(!_CFLS_LAB_modified, "Call only once"); + _CFLS_LAB_modified = true; + for (size_t i = CompactibleFreeListSpace::IndexSetStart; + i < CompactibleFreeListSpace::IndexSetSize; + i += CompactibleFreeListSpace::IndexSetStride) { + _blocks_to_claim[i].modify(n, wt, true /* force */); } } @@ -2607,11 +2841,9 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) { if (res == NULL) return NULL; } else { FreeList* fl = &_indexedFreeList[word_sz]; - bool filled = false; //TRAP if (fl->count() == 0) { - bool filled = true; //TRAP // Attempt to refill this local free list. - _cfls->par_get_chunk_of_blocks(word_sz, _blocks_to_claim, fl); + get_from_global_pool(word_sz, fl); // If it didn't work, give up. if (fl->count() == 0) return NULL; } @@ -2626,80 +2858,190 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) { return (HeapWord*)res; } -void CFLS_LAB::retire() { - for (size_t i = CompactibleFreeListSpace::IndexSetStart; +// Get a chunk of blocks of the right size and update related +// book-keeping stats +void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList* fl) { + // Get the #blocks we want to claim + size_t n_blks = (size_t)_blocks_to_claim[word_sz].average(); + assert(n_blks > 0, "Error"); + assert(ResizePLAB || n_blks == OldPLABSize, "Error"); + // In some cases, when the application has a phase change, + // there may be a sudden and sharp shift in the object survival + // profile, and updating the counts at the end of a scavenge + // may not be quick enough, giving rise to large scavenge pauses + // during these phase changes. It is beneficial to detect such + // changes on-the-fly during a scavenge and avoid such a phase-change + // pothole. The following code is a heuristic attempt to do that. + // It is protected by a product flag until we have gained + // enough experience with this heuristic and fine-tuned its behaviour. + // WARNING: This might increase fragmentation if we overreact to + // small spikes, so some kind of historical smoothing based on + // previous experience with the greater reactivity might be useful. + // Lacking sufficient experience, CMSOldPLABResizeQuicker is disabled by + // default. + if (ResizeOldPLAB && CMSOldPLABResizeQuicker) { + size_t multiple = _num_blocks[word_sz]/(CMSOldPLABToleranceFactor*CMSOldPLABNumRefills*n_blks); + n_blks += CMSOldPLABReactivityFactor*multiple*n_blks; + n_blks = MIN2(n_blks, CMSOldPLABMax); + } + assert(n_blks > 0, "Error"); + _cfls->par_get_chunk_of_blocks(word_sz, n_blks, fl); + // Update stats table entry for this block size + _num_blocks[word_sz] += fl->count(); +} + +void CFLS_LAB::compute_desired_plab_size() { + for (size_t i = CompactibleFreeListSpace::IndexSetStart; i < CompactibleFreeListSpace::IndexSetSize; i += CompactibleFreeListSpace::IndexSetStride) { - if (_indexedFreeList[i].count() > 0) { - MutexLockerEx x(_cfls->_indexedFreeListParLocks[i], - Mutex::_no_safepoint_check_flag); - _cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]); - // Reset this list. - _indexedFreeList[i] = FreeList(); - _indexedFreeList[i].set_size(i); + assert((_global_num_workers[i] == 0) == (_global_num_blocks[i] == 0), + "Counter inconsistency"); + if (_global_num_workers[i] > 0) { + // Need to smooth wrt historical average + if (ResizeOldPLAB) { + _blocks_to_claim[i].sample( + MAX2((size_t)CMSOldPLABMin, + MIN2((size_t)CMSOldPLABMax, + _global_num_blocks[i]/(_global_num_workers[i]*CMSOldPLABNumRefills)))); + } + // Reset counters for next round + _global_num_workers[i] = 0; + _global_num_blocks[i] = 0; + if (PrintOldPLAB) { + gclog_or_tty->print_cr("[%d]: %d", i, (size_t)_blocks_to_claim[i].average()); + } } } } -void -CompactibleFreeListSpace:: -par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { +void CFLS_LAB::retire(int tid) { + // We run this single threaded with the world stopped; + // so no need for locks and such. +#define CFLS_LAB_PARALLEL_ACCESS 0 + NOT_PRODUCT(Thread* t = Thread::current();) + assert(Thread::current()->is_VM_thread(), "Error"); + assert(CompactibleFreeListSpace::IndexSetStart == CompactibleFreeListSpace::IndexSetStride, + "Will access to uninitialized slot below"); +#if CFLS_LAB_PARALLEL_ACCESS + for (size_t i = CompactibleFreeListSpace::IndexSetSize - 1; + i > 0; + i -= CompactibleFreeListSpace::IndexSetStride) { +#else // CFLS_LAB_PARALLEL_ACCESS + for (size_t i = CompactibleFreeListSpace::IndexSetStart; + i < CompactibleFreeListSpace::IndexSetSize; + i += CompactibleFreeListSpace::IndexSetStride) { +#endif // !CFLS_LAB_PARALLEL_ACCESS + assert(_num_blocks[i] >= (size_t)_indexedFreeList[i].count(), + "Can't retire more than what we obtained"); + if (_num_blocks[i] > 0) { + size_t num_retire = _indexedFreeList[i].count(); + assert(_num_blocks[i] > num_retire, "Should have used at least one"); + { +#if CFLS_LAB_PARALLEL_ACCESS + MutexLockerEx x(_cfls->_indexedFreeListParLocks[i], + Mutex::_no_safepoint_check_flag); +#endif // CFLS_LAB_PARALLEL_ACCESS + // Update globals stats for num_blocks used + _global_num_blocks[i] += (_num_blocks[i] - num_retire); + _global_num_workers[i]++; + assert(_global_num_workers[i] <= (ssize_t)ParallelGCThreads, "Too big"); + if (num_retire > 0) { + _cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]); + // Reset this list. + _indexedFreeList[i] = FreeList(); + _indexedFreeList[i].set_size(i); + } + } + if (PrintOldPLAB) { + gclog_or_tty->print_cr("%d[%d]: %d/%d/%d", + tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average()); + } + // Reset stats for next round + _num_blocks[i] = 0; + } + } +} + +void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { assert(fl->count() == 0, "Precondition."); assert(word_sz < CompactibleFreeListSpace::IndexSetSize, "Precondition"); - // We'll try all multiples of word_sz in the indexed set (starting with - // word_sz itself), then try getting a big chunk and splitting it. - int k = 1; - size_t cur_sz = k * word_sz; - bool found = false; - while (cur_sz < CompactibleFreeListSpace::IndexSetSize && k == 1) { - FreeList* gfl = &_indexedFreeList[cur_sz]; - FreeList fl_for_cur_sz; // Empty. - fl_for_cur_sz.set_size(cur_sz); - { - MutexLockerEx x(_indexedFreeListParLocks[cur_sz], - Mutex::_no_safepoint_check_flag); - if (gfl->count() != 0) { - size_t nn = MAX2(n/k, (size_t)1); - gfl->getFirstNChunksFromList(nn, &fl_for_cur_sz); - found = true; - } - } - // Now transfer fl_for_cur_sz to fl. Common case, we hope, is k = 1. - if (found) { - if (k == 1) { - fl->prepend(&fl_for_cur_sz); - } else { - // Divide each block on fl_for_cur_sz up k ways. - FreeChunk* fc; - while ((fc = fl_for_cur_sz.getChunkAtHead()) != NULL) { - // Must do this in reverse order, so that anybody attempting to - // access the main chunk sees it as a single free block until we - // change it. - size_t fc_size = fc->size(); - for (int i = k-1; i >= 0; i--) { - FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz); - ffc->setSize(word_sz); - ffc->linkNext(NULL); - ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. - // Above must occur before BOT is updated below. - // splitting from the right, fc_size == (k - i + 1) * wordsize - _bt.mark_block((HeapWord*)ffc, word_sz); - fc_size -= word_sz; - _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); - _bt.verify_single_block((HeapWord*)fc, fc_size); - _bt.verify_single_block((HeapWord*)ffc, ffc->size()); - // Push this on "fl". - fl->returnChunkAtHead(ffc); + // We'll try all multiples of word_sz in the indexed set, starting with + // word_sz itself and, if CMSSplitIndexedFreeListBlocks, try larger multiples, + // then try getting a big chunk and splitting it. + { + bool found; + int k; + size_t cur_sz; + for (k = 1, cur_sz = k * word_sz, found = false; + (cur_sz < CompactibleFreeListSpace::IndexSetSize) && + (CMSSplitIndexedFreeListBlocks || k <= 1); + k++, cur_sz = k * word_sz) { + FreeList* gfl = &_indexedFreeList[cur_sz]; + FreeList fl_for_cur_sz; // Empty. + fl_for_cur_sz.set_size(cur_sz); + { + MutexLockerEx x(_indexedFreeListParLocks[cur_sz], + Mutex::_no_safepoint_check_flag); + if (gfl->count() != 0) { + // nn is the number of chunks of size cur_sz that + // we'd need to split k-ways each, in order to create + // "n" chunks of size word_sz each. + const size_t nn = MAX2(n/k, (size_t)1); + gfl->getFirstNChunksFromList(nn, &fl_for_cur_sz); + found = true; + if (k > 1) { + // Update split death stats for the cur_sz-size blocks list: + // we increment the split death count by the number of blocks + // we just took from the cur_sz-size blocks list and which + // we will be splitting below. + ssize_t deaths = _indexedFreeList[cur_sz].splitDeaths() + + fl_for_cur_sz.count(); + _indexedFreeList[cur_sz].set_splitDeaths(deaths); } - // TRAP - assert(fl->tail()->next() == NULL, "List invariant."); } } - return; + // Now transfer fl_for_cur_sz to fl. Common case, we hope, is k = 1. + if (found) { + if (k == 1) { + fl->prepend(&fl_for_cur_sz); + } else { + // Divide each block on fl_for_cur_sz up k ways. + FreeChunk* fc; + while ((fc = fl_for_cur_sz.getChunkAtHead()) != NULL) { + // Must do this in reverse order, so that anybody attempting to + // access the main chunk sees it as a single free block until we + // change it. + size_t fc_size = fc->size(); + for (int i = k-1; i >= 0; i--) { + FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz); + ffc->setSize(word_sz); + ffc->linkNext(NULL); + ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + // Above must occur before BOT is updated below. + // splitting from the right, fc_size == (k - i + 1) * wordsize + _bt.mark_block((HeapWord*)ffc, word_sz); + fc_size -= word_sz; + _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); + _bt.verify_single_block((HeapWord*)fc, fc_size); + _bt.verify_single_block((HeapWord*)ffc, ffc->size()); + // Push this on "fl". + fl->returnChunkAtHead(ffc); + } + // TRAP + assert(fl->tail()->next() == NULL, "List invariant."); + } + } + // Update birth stats for this block size. + size_t num = fl->count(); + MutexLockerEx x(_indexedFreeListParLocks[word_sz], + Mutex::_no_safepoint_check_flag); + ssize_t births = _indexedFreeList[word_sz].splitBirths() + num; + _indexedFreeList[word_sz].set_splitBirths(births); + return; + } } - k++; cur_sz = k * word_sz; } // Otherwise, we'll split a block from the dictionary. FreeChunk* fc = NULL; @@ -2723,17 +3065,31 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { } } if (fc == NULL) return; + assert((ssize_t)n >= 1, "Control point invariant"); // Otherwise, split up that block. - size_t nn = fc->size() / word_sz; + const size_t nn = fc->size() / word_sz; n = MIN2(nn, n); + assert((ssize_t)n >= 1, "Control point invariant"); rem = fc->size() - n * word_sz; // If there is a remainder, and it's too small, allocate one fewer. if (rem > 0 && rem < MinChunkSize) { n--; rem += word_sz; } + // Note that at this point we may have n == 0. + assert((ssize_t)n >= 0, "Control point invariant"); + + // If n is 0, the chunk fc that was found is not large + // enough to leave a viable remainder. We are unable to + // allocate even one block. Return fc to the + // dictionary and return, leaving "fl" empty. + if (n == 0) { + returnChunkToDictionary(fc); + return; + } + // First return the remainder, if any. // Note that we hold the lock until we decide if we're going to give - // back the remainder to the dictionary, since a contending allocator + // back the remainder to the dictionary, since a concurrent allocation // may otherwise see the heap as empty. (We're willing to take that // hit if the block is a small block.) if (rem > 0) { @@ -2743,18 +3099,16 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { rem_fc->linkNext(NULL); rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. // Above must occur before BOT is updated below. + assert((ssize_t)n > 0 && prefix_size > 0 && rem_fc > fc, "Error"); _bt.split_block((HeapWord*)fc, fc->size(), prefix_size); if (rem >= IndexSetSize) { returnChunkToDictionary(rem_fc); - dictionary()->dictCensusUpdate(fc->size(), - true /*split*/, - true /*birth*/); + dictionary()->dictCensusUpdate(rem, true /*split*/, true /*birth*/); rem_fc = NULL; } // Otherwise, return it to the small list below. } } - // if (rem_fc != NULL) { MutexLockerEx x(_indexedFreeListParLocks[rem], Mutex::_no_safepoint_check_flag); @@ -2762,7 +3116,7 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { _indexedFreeList[rem].returnChunkAtHead(rem_fc); smallSplitBirth(rem); } - + assert((ssize_t)n > 0 && fc != NULL, "Consistency"); // Now do the splitting up. // Must do this in reverse order, so that anybody attempting to // access the main chunk sees it as a single free block until we @@ -2792,13 +3146,15 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { _bt.verify_single_block((HeapWord*)fc, fc->size()); fl->returnChunkAtHead(fc); + assert((ssize_t)n > 0 && (ssize_t)n == fl->count(), "Incorrect number of blocks"); { + // Update the stats for this block size. MutexLockerEx x(_indexedFreeListParLocks[word_sz], Mutex::_no_safepoint_check_flag); - ssize_t new_births = _indexedFreeList[word_sz].splitBirths() + n; - _indexedFreeList[word_sz].set_splitBirths(new_births); - ssize_t new_surplus = _indexedFreeList[word_sz].surplus() + n; - _indexedFreeList[word_sz].set_surplus(new_surplus); + const ssize_t births = _indexedFreeList[word_sz].splitBirths() + n; + _indexedFreeList[word_sz].set_splitBirths(births); + // ssize_t new_surplus = _indexedFreeList[word_sz].surplus() + n; + // _indexedFreeList[word_sz].set_surplus(new_surplus); } // TRAP diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 9f16f8d2eb0..d937de86156 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -25,8 +25,6 @@ // Classes in support of keeping track of promotions into a non-Contiguous // space, in this case a CompactibleFreeListSpace. -#define CFLS_LAB_REFILL_STATS 0 - // Forward declarations class CompactibleFreeListSpace; class BlkClosure; @@ -89,6 +87,9 @@ class SpoolBlock: public FreeChunk { displacedHdr = (markOop*)&displacedHdr; nextSpoolBlock = NULL; } + + void print_on(outputStream* st) const; + void print() const { print_on(gclog_or_tty); } }; class PromotionInfo VALUE_OBJ_CLASS_SPEC { @@ -121,7 +122,7 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC { return _promoHead == NULL; } void startTrackingPromotions(); - void stopTrackingPromotions(); + void stopTrackingPromotions(uint worker_id = 0); bool tracking() const { return _tracking; } void track(PromotedObject* trackOop); // keep track of a promoted oop // The following variant must be used when trackOop is not fully @@ -161,6 +162,9 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC { _nextIndex = 0; } + + void print_on(outputStream* st) const; + void print_statistics(uint worker_id) const; }; class LinearAllocBlock VALUE_OBJ_CLASS_SPEC { @@ -243,6 +247,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { mutable Mutex _freelistLock; // locking verifier convenience function void assert_locked() const PRODUCT_RETURN; + void assert_locked(const Mutex* lock) const PRODUCT_RETURN; // Linear allocation blocks LinearAllocBlock _smallLinearAllocBlock; @@ -281,13 +286,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Locks protecting the exact lists during par promotion allocation. Mutex* _indexedFreeListParLocks[IndexSetSize]; -#if CFLS_LAB_REFILL_STATS - // Some statistics. - jint _par_get_chunk_from_small; - jint _par_get_chunk_from_large; -#endif - - // Attempt to obtain up to "n" blocks of the size "word_sz" (which is // required to be smaller than "IndexSetSize".) If successful, // adds them to "fl", which is required to be an empty free list. @@ -320,7 +318,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Helper function for getChunkFromIndexedFreeList. // Replenish the indexed free list for this "size". Do not take from an // underpopulated size. - FreeChunk* getChunkFromIndexedFreeListHelper(size_t size); + FreeChunk* getChunkFromIndexedFreeListHelper(size_t size, bool replenish = true); // Get a chunk from the indexed free list. If the indexed free list // does not have a free chunk, try to replenish the indexed free list @@ -430,10 +428,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { void initialize_sequential_subtasks_for_marking(int n_threads, HeapWord* low = NULL); -#if CFLS_LAB_REFILL_STATS - void print_par_alloc_stats(); -#endif - // Space enquiries size_t used() const; size_t free() const; @@ -617,6 +611,12 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Do some basic checks on the the free lists. void checkFreeListConsistency() const PRODUCT_RETURN; + // Printing support + void dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st); + void print_indexed_free_lists(outputStream* st) const; + void print_dictionary_free_lists(outputStream* st) const; + void print_promo_info_blocks(outputStream* st) const; + NOT_PRODUCT ( void initializeIndexedFreeListArrayReturnedBytes(); size_t sumIndexedFreeListArrayReturnedBytes(); @@ -638,8 +638,9 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Statistics functions // Initialize census for lists before the sweep. - void beginSweepFLCensus(float sweep_current, - float sweep_estimate); + void beginSweepFLCensus(float inter_sweep_current, + float inter_sweep_estimate, + float intra_sweep_estimate); // Set the surplus for each of the free lists. void setFLSurplus(); // Set the hint for each of the free lists. @@ -730,16 +731,17 @@ class CFLS_LAB : public CHeapObj { FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize]; // Initialized from a command-line arg. - size_t _blocks_to_claim; -#if CFLS_LAB_REFILL_STATS - // Some statistics. - int _refills; - int _blocksTaken; - static int _tot_refills; - static int _tot_blocksTaken; - static int _next_threshold; -#endif + // Allocation statistics in support of dynamic adjustment of + // #blocks to claim per get_from_global_pool() call below. + static AdaptiveWeightedAverage + _blocks_to_claim [CompactibleFreeListSpace::IndexSetSize]; + static size_t _global_num_blocks [CompactibleFreeListSpace::IndexSetSize]; + static int _global_num_workers[CompactibleFreeListSpace::IndexSetSize]; + size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize]; + + // Internal work method + void get_from_global_pool(size_t word_sz, FreeList* fl); public: CFLS_LAB(CompactibleFreeListSpace* cfls); @@ -748,7 +750,12 @@ public: HeapWord* alloc(size_t word_sz); // Return any unused portions of the buffer to the global pool. - void retire(); + void retire(int tid); + + // Dynamic OldPLABSize sizing + static void compute_desired_plab_size(); + // When the settings are modified from default static initialization + static void modify_initialization(size_t n, unsigned wt); }; size_t PromotionInfo::refillSize() const { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index c3d30c348b2..1ec7696bdf7 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -253,7 +253,6 @@ void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) } } - void ConcurrentMarkSweepGeneration::ref_processor_init() { assert(collector() != NULL, "no collector"); collector()->ref_processor_init(); @@ -341,6 +340,14 @@ CMSStats::CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha): _icms_duty_cycle = CMSIncrementalDutyCycle; } +double CMSStats::cms_free_adjustment_factor(size_t free) const { + // TBD: CR 6909490 + return 1.0; +} + +void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) { +} + // If promotion failure handling is on use // the padded average size of the promotion for each // young generation collection. @@ -361,7 +368,11 @@ double CMSStats::time_until_cms_gen_full() const { // Adjust by the safety factor. double cms_free_dbl = (double)cms_free; - cms_free_dbl = cms_free_dbl * (100.0 - CMSIncrementalSafetyFactor) / 100.0; + double cms_adjustment = (100.0 - CMSIncrementalSafetyFactor)/100.0; + // Apply a further correction factor which tries to adjust + // for recent occurance of concurrent mode failures. + cms_adjustment = cms_adjustment * cms_free_adjustment_factor(cms_free); + cms_free_dbl = cms_free_dbl * cms_adjustment; if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("CMSStats::time_until_cms_gen_full: cms_free " @@ -395,6 +406,8 @@ double CMSStats::time_until_cms_start() const { // late. double work = cms_duration() + gc0_period(); double deadline = time_until_cms_gen_full(); + // If a concurrent mode failure occurred recently, we want to be + // more conservative and halve our expected time_until_cms_gen_full() if (work > deadline) { if (Verbose && PrintGCDetails) { gclog_or_tty->print( @@ -556,7 +569,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, _should_unload_classes(false), _concurrent_cycles_since_last_unload(0), _roots_scanning_options(0), - _sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) + _inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), + _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) { if (ExplicitGCInvokesConcurrentAndUnloadsClasses) { ExplicitGCInvokesConcurrent = true; @@ -709,7 +723,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, // Support for parallelizing survivor space rescan if (CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) { - size_t max_plab_samples = MaxNewSize/((SurvivorRatio+2)*MinTLABSize); + size_t max_plab_samples = cp->max_gen0_size()/ + ((SurvivorRatio+2)*MinTLABSize); _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples); _cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads); @@ -772,7 +787,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;) _gc_counters = new CollectorCounters("CMS", 1); _completed_initialization = true; - _sweep_timer.start(); // start of time + _inter_sweep_timer.start(); // start of time } const char* ConcurrentMarkSweepGeneration::name() const { @@ -899,6 +914,14 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe( return result; } +// At a promotion failure dump information on block layout in heap +// (cms old generation). +void ConcurrentMarkSweepGeneration::promotion_failure_occurred() { + if (CMSDumpAtPromotionFailure) { + cmsSpace()->dump_at_safepoint_with_locks(collector(), gclog_or_tty); + } +} + CompactibleSpace* ConcurrentMarkSweepGeneration::first_compaction_space() const { return _cmsSpace; @@ -1367,12 +1390,7 @@ void ConcurrentMarkSweepGeneration:: par_promote_alloc_done(int thread_num) { CMSParGCThreadState* ps = _par_gc_thread_states[thread_num]; - ps->lab.retire(); -#if CFLS_LAB_REFILL_STATS - if (thread_num == 0) { - _cmsSpace->print_par_alloc_stats(); - } -#endif + ps->lab.retire(thread_num); } void @@ -1973,11 +1991,14 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { // We must adjust the allocation statistics being maintained // in the free list space. We do so by reading and clearing // the sweep timer and updating the block flux rate estimates below. - assert(_sweep_timer.is_active(), "We should never see the timer inactive"); - _sweep_timer.stop(); - // Note that we do not use this sample to update the _sweep_estimate. - _cmsGen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()), - _sweep_estimate.padded_average()); + assert(!_intra_sweep_timer.is_active(), "_intra_sweep_timer should be inactive"); + if (_inter_sweep_timer.is_active()) { + _inter_sweep_timer.stop(); + // Note that we do not use this sample to update the _inter_sweep_estimate. + _cmsGen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()), + _inter_sweep_estimate.padded_average(), + _intra_sweep_estimate.padded_average()); + } GenMarkSweep::invoke_at_safepoint(_cmsGen->level(), ref_processor(), clear_all_soft_refs); @@ -2014,10 +2035,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { } // Adjust the per-size allocation stats for the next epoch. - _cmsGen->cmsSpace()->endSweepFLCensus(sweepCount() /* fake */); - // Restart the "sweep timer" for next epoch. - _sweep_timer.reset(); - _sweep_timer.start(); + _cmsGen->cmsSpace()->endSweepFLCensus(sweep_count() /* fake */); + // Restart the "inter sweep timer" for the next epoch. + _inter_sweep_timer.reset(); + _inter_sweep_timer.start(); // Sample collection pause time and reset for collection interval. if (UseAdaptiveSizePolicy) { @@ -2675,7 +2696,7 @@ void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) { // Also reset promotion tracking in par gc thread states. if (ParallelGCThreads > 0) { for (uint i = 0; i < ParallelGCThreads; i++) { - _par_gc_thread_states[i]->promo.stopTrackingPromotions(); + _par_gc_thread_states[i]->promo.stopTrackingPromotions(i); } } } @@ -2770,7 +2791,7 @@ class VerifyMarkedClosure: public BitMapClosure { bool do_bit(size_t offset) { HeapWord* addr = _marks->offsetToHeapWord(offset); if (!_marks->isMarked(addr)) { - oop(addr)->print(); + oop(addr)->print_on(gclog_or_tty); gclog_or_tty->print_cr(" ("INTPTR_FORMAT" should have been marked)", addr); _failed = true; } @@ -2819,7 +2840,7 @@ bool CMSCollector::verify_after_remark() { // Clear any marks from a previous round verification_mark_bm()->clear_all(); assert(verification_mark_stack()->isEmpty(), "markStack should be empty"); - assert(overflow_list_is_empty(), "overflow list should be empty"); + verify_work_stacks_empty(); GenCollectedHeap* gch = GenCollectedHeap::heap(); gch->ensure_parsability(false); // fill TLABs, but no need to retire them @@ -2892,8 +2913,8 @@ void CMSCollector::verify_after_remark_work_1() { verification_mark_bm()->iterate(&vcl); if (vcl.failed()) { gclog_or_tty->print("Verification failed"); - Universe::heap()->print(); - fatal(" ... aborting"); + Universe::heap()->print_on(gclog_or_tty); + fatal("CMS: failed marking verification after remark"); } } @@ -3313,7 +3334,7 @@ bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) { Universe::heap()->barrier_set()->resize_covered_region(mr); // Hmmmm... why doesn't CFLS::set_end verify locking? // This is quite ugly; FIX ME XXX - _cmsSpace->assert_locked(); + _cmsSpace->assert_locked(freelistLock()); _cmsSpace->set_end((HeapWord*)_virtual_space.high()); // update the space and generation capacity counters @@ -5867,9 +5888,9 @@ void CMSCollector::sweep(bool asynch) { check_correct_thread_executing(); verify_work_stacks_empty(); verify_overflow_empty(); - incrementSweepCount(); - _sweep_timer.stop(); - _sweep_estimate.sample(_sweep_timer.seconds()); + increment_sweep_count(); + _inter_sweep_timer.stop(); + _inter_sweep_estimate.sample(_inter_sweep_timer.seconds()); size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free()); // PermGen verification support: If perm gen sweeping is disabled in @@ -5892,6 +5913,9 @@ void CMSCollector::sweep(bool asynch) { } } + assert(!_intra_sweep_timer.is_active(), "Should not be active"); + _intra_sweep_timer.reset(); + _intra_sweep_timer.start(); if (asynch) { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails); @@ -5936,8 +5960,11 @@ void CMSCollector::sweep(bool asynch) { verify_work_stacks_empty(); verify_overflow_empty(); - _sweep_timer.reset(); - _sweep_timer.start(); + _intra_sweep_timer.stop(); + _intra_sweep_estimate.sample(_intra_sweep_timer.seconds()); + + _inter_sweep_timer.reset(); + _inter_sweep_timer.start(); update_time_of_last_gc(os::javaTimeMillis()); @@ -5980,11 +6007,11 @@ void CMSCollector::sweep(bool asynch) { // FIX ME!!! Looks like this belongs in CFLSpace, with // CMSGen merely delegating to it. void ConcurrentMarkSweepGeneration::setNearLargestChunk() { - double nearLargestPercent = 0.999; + double nearLargestPercent = FLSLargestBlockCoalesceProximity; HeapWord* minAddr = _cmsSpace->bottom(); HeapWord* largestAddr = (HeapWord*) _cmsSpace->dictionary()->findLargestDict(); - if (largestAddr == 0) { + if (largestAddr == NULL) { // The dictionary appears to be empty. In this case // try to coalesce at the end of the heap. largestAddr = _cmsSpace->end(); @@ -5992,6 +6019,13 @@ void ConcurrentMarkSweepGeneration::setNearLargestChunk() { size_t largestOffset = pointer_delta(largestAddr, minAddr); size_t nearLargestOffset = (size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize; + if (PrintFLSStatistics != 0) { + gclog_or_tty->print_cr( + "CMS: Large Block: " PTR_FORMAT ";" + " Proximity: " PTR_FORMAT " -> " PTR_FORMAT, + largestAddr, + _cmsSpace->nearLargestChunk(), minAddr + nearLargestOffset); + } _cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset); } @@ -6071,9 +6105,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen, assert_lock_strong(gen->freelistLock()); assert_lock_strong(bitMapLock()); - assert(!_sweep_timer.is_active(), "Was switched off in an outer context"); - gen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()), - _sweep_estimate.padded_average()); + assert(!_inter_sweep_timer.is_active(), "Was switched off in an outer context"); + assert(_intra_sweep_timer.is_active(), "Was switched on in an outer context"); + gen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()), + _inter_sweep_estimate.padded_average(), + _intra_sweep_estimate.padded_average()); gen->setNearLargestChunk(); { @@ -6086,7 +6122,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen, // end-of-sweep-census below will be off by a little bit. } gen->cmsSpace()->sweep_completed(); - gen->cmsSpace()->endSweepFLCensus(sweepCount()); + gen->cmsSpace()->endSweepFLCensus(sweep_count()); if (should_unload_classes()) { // unloaded classes this cycle, _concurrent_cycles_since_last_unload = 0; // ... reset count } else { // did not unload classes, diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index a58217faf93..18164a58b4e 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -355,6 +355,11 @@ class CMSStats VALUE_OBJ_CLASS_SPEC { unsigned int new_duty_cycle); unsigned int icms_update_duty_cycle_impl(); + // In support of adjusting of cms trigger ratios based on history + // of concurrent mode failure. + double cms_free_adjustment_factor(size_t free) const; + void adjust_cms_free_adjustment_factor(bool fail, size_t free); + public: CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha = CMSExpAvgFactor); @@ -570,8 +575,11 @@ class CMSCollector: public CHeapObj { // appropriately. void check_gc_time_limit(); // XXX Move these to CMSStats ??? FIX ME !!! - elapsedTimer _sweep_timer; - AdaptivePaddedAverage _sweep_estimate; + elapsedTimer _inter_sweep_timer; // time between sweeps + elapsedTimer _intra_sweep_timer; // time _in_ sweeps + // padded decaying average estimates of the above + AdaptivePaddedAverage _inter_sweep_estimate; + AdaptivePaddedAverage _intra_sweep_estimate; protected: ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS) @@ -625,6 +633,7 @@ class CMSCollector: public CHeapObj { // . _collectorState <= Idling == post-sweep && pre-mark // . _collectorState in (Idling, Sweeping) == {initial,final}marking || // precleaning || abortablePrecleanb + public: enum CollectorState { Resizing = 0, Resetting = 1, @@ -636,6 +645,7 @@ class CMSCollector: public CHeapObj { FinalMarking = 7, Sweeping = 8 }; + protected: static CollectorState _collectorState; // State related to prologue/epilogue invocation for my generations @@ -655,7 +665,7 @@ class CMSCollector: public CHeapObj { int _numYields; size_t _numDirtyCards; - uint _sweepCount; + size_t _sweep_count; // number of full gc's since the last concurrent gc. uint _full_gcs_since_conc_gc; @@ -905,7 +915,7 @@ class CMSCollector: public CHeapObj { // Check that the currently executing thread is the expected // one (foreground collector or background collector). - void check_correct_thread_executing() PRODUCT_RETURN; + static void check_correct_thread_executing() PRODUCT_RETURN; // XXXPERM void print_statistics() PRODUCT_RETURN; bool is_cms_reachable(HeapWord* addr); @@ -930,8 +940,8 @@ class CMSCollector: public CHeapObj { static void set_foregroundGCShouldWait(bool v) { _foregroundGCShouldWait = v; } static bool foregroundGCIsActive() { return _foregroundGCIsActive; } static void set_foregroundGCIsActive(bool v) { _foregroundGCIsActive = v; } - uint sweepCount() const { return _sweepCount; } - void incrementSweepCount() { _sweepCount++; } + size_t sweep_count() const { return _sweep_count; } + void increment_sweep_count() { _sweep_count++; } // Timers/stats for gc scheduling and incremental mode pacing. CMSStats& stats() { return _stats; } @@ -1165,6 +1175,11 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes, bool younger_handles_promotion_failure) const; + // Inform this (non-young) generation that a promotion failure was + // encountered during a collection of a younger generation that + // promotes into this generation. + virtual void promotion_failure_occurred(); + bool should_collect(bool full, size_t size, bool tlab); virtual bool should_concurrent_collect() const; virtual bool is_too_full() const; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp index 5f9c4f22632..1a454fe68f4 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp @@ -55,7 +55,8 @@ class FreeBlockDictionary: public CHeapObj { virtual void dictCensusUpdate(size_t size, bool split, bool birth) = 0; virtual bool coalDictOverPopulated(size_t size) = 0; virtual void beginSweepDictCensus(double coalSurplusPercent, - float sweep_current, float sweep_ewstimate) = 0; + float inter_sweep_current, float inter_sweep_estimate, + float intra__sweep_current) = 0; virtual void endSweepDictCensus(double splitSurplusPercent) = 0; virtual FreeChunk* findLargestDict() const = 0; // verify that the given chunk is in the dictionary. @@ -79,6 +80,7 @@ class FreeBlockDictionary: public CHeapObj { } virtual void printDictCensus() const = 0; + virtual void print_free_lists(outputStream* st) const = 0; virtual void verify() const = 0; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp index 494c090c6fb..e709c3af6ca 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp @@ -67,3 +67,8 @@ void FreeChunk::verifyList() const { } } #endif + +void FreeChunk::print_on(outputStream* st) { + st->print_cr("Next: " PTR_FORMAT " Prev: " PTR_FORMAT " %s", + next(), prev(), cantCoalesce() ? "[can't coalesce]" : ""); +} diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp index 768614d7e2b..9e731e7ca35 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp @@ -129,6 +129,8 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC { void verifyList() const PRODUCT_RETURN; void mangleAllocated(size_t size) PRODUCT_RETURN; void mangleFreed(size_t size) PRODUCT_RETURN; + + void print_on(outputStream* st); }; // Alignment helpers etc. diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp index 79503deb81d..1ca1a4e5396 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp @@ -81,8 +81,8 @@ void FreeList::reset(size_t hint) { set_hint(hint); } -void FreeList::init_statistics() { - _allocation_stats.initialize(); +void FreeList::init_statistics(bool split_birth) { + _allocation_stats.initialize(split_birth); } FreeChunk* FreeList::getChunkAtHead() { @@ -292,14 +292,31 @@ bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const { } #ifndef PRODUCT +void FreeList::verify_stats() const { + // The +1 of the LH comparand is to allow some "looseness" in + // checking: we usually call this interface when adding a block + // and we'll subsequently update the stats; we cannot update the + // stats beforehand because in the case of the large-block BT + // dictionary for example, this might be the first block and + // in that case there would be no place that we could record + // the stats (which are kept in the block itself). + assert(_allocation_stats.prevSweep() + _allocation_stats.splitBirths() + 1 // Total Stock + 1 + >= _allocation_stats.splitDeaths() + (ssize_t)count(), "Conservation Principle"); +} + void FreeList::assert_proper_lock_protection_work() const { -#ifdef ASSERT - if (_protecting_lock != NULL && - SharedHeap::heap()->n_par_threads() > 0) { - // Should become an assert. - guarantee(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED"); + assert(_protecting_lock != NULL, "Don't call this directly"); + assert(ParallelGCThreads > 0, "Don't call this directly"); + Thread* thr = Thread::current(); + if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) { + // assert that we are holding the freelist lock + } else if (thr->is_GC_task_thread()) { + assert(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED"); + } else if (thr->is_Java_thread()) { + assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing"); + } else { + ShouldNotReachHere(); // unaccounted thread type? } -#endif } #endif diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp index 581317643c7..8dd1543ab64 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp @@ -35,18 +35,26 @@ class CompactibleFreeListSpace; // for that implementation. class Mutex; +class TreeList; class FreeList VALUE_OBJ_CLASS_SPEC { friend class CompactibleFreeListSpace; friend class VMStructs; - friend class printTreeCensusClosure; - FreeChunk* _head; // List of free chunks + friend class PrintTreeCensusClosure; + + protected: + TreeList* _parent; + TreeList* _left; + TreeList* _right; + + private: + FreeChunk* _head; // Head of list of free chunks FreeChunk* _tail; // Tail of list of free chunks - size_t _size; // Size in Heap words of each chunks + size_t _size; // Size in Heap words of each chunk ssize_t _count; // Number of entries in list size_t _hint; // next larger size list with a positive surplus - AllocationStats _allocation_stats; // statistics for smart allocation + AllocationStats _allocation_stats; // allocation-related statistics #ifdef ASSERT Mutex* _protecting_lock; @@ -63,9 +71,12 @@ class FreeList VALUE_OBJ_CLASS_SPEC { // Initialize the allocation statistics. protected: - void init_statistics(); + void init_statistics(bool split_birth = false); void set_count(ssize_t v) { _count = v;} - void increment_count() { _count++; } + void increment_count() { + _count++; + } + void decrement_count() { _count--; assert(_count >= 0, "Count should not be negative"); @@ -167,11 +178,13 @@ class FreeList VALUE_OBJ_CLASS_SPEC { _allocation_stats.set_desired(v); } void compute_desired(float inter_sweep_current, - float inter_sweep_estimate) { + float inter_sweep_estimate, + float intra_sweep_estimate) { assert_proper_lock_protection(); _allocation_stats.compute_desired(_count, inter_sweep_current, - inter_sweep_estimate); + inter_sweep_estimate, + intra_sweep_estimate); } ssize_t coalDesired() const { return _allocation_stats.coalDesired(); @@ -306,6 +319,9 @@ class FreeList VALUE_OBJ_CLASS_SPEC { // found. Return NULL if "fc" is not found. bool verifyChunkInFreeLists(FreeChunk* fc) const; + // Stats verification + void verify_stats() const PRODUCT_RETURN; + // Printing support static void print_labels_on(outputStream* st, const char* c); void print_on(outputStream* st, const char* c = NULL) const; diff --git a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp index 3000f010b17..96760517637 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp @@ -351,9 +351,16 @@ void CollectionSetChooser::printSortedHeapRegions() { gclog_or_tty->print_cr("Printing %d Heap Regions sorted by amount of known garbage", _numMarkedRegions); + + DEBUG_ONLY(int marked_count = 0;) for (int i = 0; i < _markedRegions.length(); i++) { - printHeapRegion(_markedRegions.at(i)); + HeapRegion* r = _markedRegions.at(i); + if (r != NULL) { + printHeapRegion(r); + DEBUG_ONLY(marked_count++;) + } } + assert(marked_count == _numMarkedRegions, "must be"); gclog_or_tty->print_cr("Done sorted heap region print"); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 34939de57c7..11c288073d3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -42,28 +42,49 @@ ConcurrentG1Refine::ConcurrentG1Refine() : _n_periods(0), _threads(NULL), _n_threads(0) { - if (G1ConcRefine) { - _n_threads = (int)thread_num(); - if (_n_threads > 0) { - _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads); - int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids(); - ConcurrentG1RefineThread *next = NULL; - for (int i = _n_threads - 1; i >= 0; i--) { - ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i); - assert(t != NULL, "Conc refine should have been created"); - assert(t->cg1r() == this, "Conc refine thread should refer to this"); - _threads[i] = t; - next = t; - } - } + + // Ergomonically select initial concurrent refinement parameters + if (FLAG_IS_DEFAULT(G1ConcRefineGreenZone)) { + FLAG_SET_DEFAULT(G1ConcRefineGreenZone, MAX2(ParallelGCThreads, 1)); + } + set_green_zone(G1ConcRefineGreenZone); + + if (FLAG_IS_DEFAULT(G1ConcRefineYellowZone)) { + FLAG_SET_DEFAULT(G1ConcRefineYellowZone, green_zone() * 3); + } + set_yellow_zone(MAX2(G1ConcRefineYellowZone, green_zone())); + + if (FLAG_IS_DEFAULT(G1ConcRefineRedZone)) { + FLAG_SET_DEFAULT(G1ConcRefineRedZone, yellow_zone() * 2); + } + set_red_zone(MAX2(G1ConcRefineRedZone, yellow_zone())); + _n_worker_threads = thread_num(); + // We need one extra thread to do the young gen rset size sampling. + _n_threads = _n_worker_threads + 1; + reset_threshold_step(); + + _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads); + int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids(); + ConcurrentG1RefineThread *next = NULL; + for (int i = _n_threads - 1; i >= 0; i--) { + ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i); + assert(t != NULL, "Conc refine should have been created"); + assert(t->cg1r() == this, "Conc refine thread should refer to this"); + _threads[i] = t; + next = t; } } -size_t ConcurrentG1Refine::thread_num() { - if (G1ConcRefine) { - return (G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads; +void ConcurrentG1Refine::reset_threshold_step() { + if (FLAG_IS_DEFAULT(G1ConcRefineThresholdStep)) { + _thread_threshold_step = (yellow_zone() - green_zone()) / (worker_thread_num() + 1); + } else { + _thread_threshold_step = G1ConcRefineThresholdStep; } - return 0; +} + +int ConcurrentG1Refine::thread_num() { + return MAX2((G1ParallelRSetThreads > 0) ? G1ParallelRSetThreads : ParallelGCThreads, 1); } void ConcurrentG1Refine::init() { @@ -123,6 +144,15 @@ void ConcurrentG1Refine::stop() { } } +void ConcurrentG1Refine::reinitialize_threads() { + reset_threshold_step(); + if (_threads != NULL) { + for (int i = 0; i < _n_threads; i++) { + _threads[i]->initialize(); + } + } +} + ConcurrentG1Refine::~ConcurrentG1Refine() { if (G1ConcRSLogCacheSize > 0) { assert(_card_counts != NULL, "Logic"); @@ -384,4 +414,3 @@ void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const { st->cr(); } } - diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp index 5cef3058ca4..7bcbecfbe5e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp @@ -29,6 +29,31 @@ class G1RemSet; class ConcurrentG1Refine: public CHeapObj { ConcurrentG1RefineThread** _threads; int _n_threads; + int _n_worker_threads; + /* + * The value of the update buffer queue length falls into one of 3 zones: + * green, yellow, red. If the value is in [0, green) nothing is + * done, the buffers are left unprocessed to enable the caching effect of the + * dirtied cards. In the yellow zone [green, yellow) the concurrent refinement + * threads are gradually activated. In [yellow, red) all threads are + * running. If the length becomes red (max queue length) the mutators start + * processing the buffers. + * + * There are some interesting cases (with G1AdaptiveConcRefine turned off): + * 1) green = yellow = red = 0. In this case the mutator will process all + * buffers. Except for those that are created by the deferred updates + * machinery during a collection. + * 2) green = 0. Means no caching. Can be a good way to minimize the + * amount of time spent updating rsets during a collection. + */ + int _green_zone; + int _yellow_zone; + int _red_zone; + + int _thread_threshold_step; + + // Reset the threshold step value based of the current zone boundaries. + void reset_threshold_step(); // The cache for card refinement. bool _use_cache; @@ -147,6 +172,8 @@ class ConcurrentG1Refine: public CHeapObj { void init(); // Accomplish some initialization that has to wait. void stop(); + void reinitialize_threads(); + // Iterate over the conc refine threads void threads_do(ThreadClosure *tc); @@ -178,7 +205,20 @@ class ConcurrentG1Refine: public CHeapObj { void clear_and_record_card_counts(); - static size_t thread_num(); + static int thread_num(); void print_worker_threads_on(outputStream* st) const; + + void set_green_zone(int x) { _green_zone = x; } + void set_yellow_zone(int x) { _yellow_zone = x; } + void set_red_zone(int x) { _red_zone = x; } + + int green_zone() const { return _green_zone; } + int yellow_zone() const { return _yellow_zone; } + int red_zone() const { return _red_zone; } + + int total_thread_num() const { return _n_threads; } + int worker_thread_num() const { return _n_worker_threads; } + + int thread_threshold_step() const { return _thread_threshold_step; } }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp index aaf2544fe9b..b23c287a6e5 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp @@ -25,10 +25,6 @@ #include "incls/_precompiled.incl" #include "incls/_concurrentG1RefineThread.cpp.incl" -// ======= Concurrent Mark Thread ======== - -// The CM thread is created when the G1 garbage collector is used - ConcurrentG1RefineThread:: ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next, int worker_id_offset, int worker_id) : @@ -37,19 +33,42 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex _worker_id(worker_id), _active(false), _next(next), + _monitor(NULL), _cg1r(cg1r), - _vtime_accum(0.0), - _interval_ms(5.0) + _vtime_accum(0.0) { + + // Each thread has its own monitor. The i-th thread is responsible for signalling + // to thread i+1 if the number of buffers in the queue exceeds a threashold for this + // thread. Monitors are also used to wake up the threads during termination. + // The 0th worker in notified by mutator threads and has a special monitor. + // The last worker is used for young gen rset size sampling. + if (worker_id > 0) { + _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true); + } else { + _monitor = DirtyCardQ_CBL_mon; + } + initialize(); create_and_start(); } +void ConcurrentG1RefineThread::initialize() { + if (_worker_id < cg1r()->worker_thread_num()) { + // Current thread activation threshold + _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), + cg1r()->yellow_zone()); + // A thread deactivates once the number of buffer reached a deactivation threshold + _deactivation_threshold = MAX2(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone()); + } else { + set_active(true); + } +} + void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1p = g1h->g1_policy(); if (g1p->adaptive_young_list_length()) { int regions_visited = 0; - g1h->young_list_rs_length_sampling_init(); while (g1h->young_list_rs_length_sampling_more()) { g1h->young_list_rs_length_sampling_next(); @@ -70,99 +89,121 @@ void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { } } +void ConcurrentG1RefineThread::run_young_rs_sampling() { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + _vtime_start = os::elapsedVTime(); + while(!_should_terminate) { + _sts.join(); + sample_young_list_rs_lengths(); + _sts.leave(); + + if (os::supports_vtime()) { + _vtime_accum = (os::elapsedVTime() - _vtime_start); + } else { + _vtime_accum = 0.0; + } + + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + if (_should_terminate) { + break; + } + _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefineServiceInterval); + } +} + +void ConcurrentG1RefineThread::wait_for_completed_buffers() { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + while (!_should_terminate && !is_active()) { + _monitor->wait(Mutex::_no_safepoint_check_flag); + } +} + +bool ConcurrentG1RefineThread::is_active() { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + return _worker_id > 0 ? _active : dcqs.process_completed_buffers(); +} + +void ConcurrentG1RefineThread::activate() { + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + if (_worker_id > 0) { + if (G1TraceConcurrentRefinement) { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d", + _worker_id, _threshold, (int)dcqs.completed_buffers_num()); + } + set_active(true); + } else { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + dcqs.set_process_completed(true); + } + _monitor->notify(); +} + +void ConcurrentG1RefineThread::deactivate() { + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + if (_worker_id > 0) { + if (G1TraceConcurrentRefinement) { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d", + _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num()); + } + set_active(false); + } else { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + dcqs.set_process_completed(false); + } +} + void ConcurrentG1RefineThread::run() { initialize_in_thread(); - _vtime_start = os::elapsedVTime(); wait_for_universe_init(); + if (_worker_id >= cg1r()->worker_thread_num()) { + run_young_rs_sampling(); + terminate(); + } + + _vtime_start = os::elapsedVTime(); while (!_should_terminate) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - // Wait for completed log buffers to exist. - { - MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); - while (((_worker_id == 0 && !dcqs.process_completed_buffers()) || - (_worker_id > 0 && !is_active())) && - !_should_terminate) { - DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag); - } - } + + // Wait for work + wait_for_completed_buffers(); if (_should_terminate) { - return; + break; } - // Now we take them off (this doesn't hold locks while it applies - // closures.) (If we did a full collection, then we'll do a full - // traversal. _sts.join(); - int n_logs = 0; - int lower_limit = 0; - double start_vtime_sec; // only used when G1SmoothConcRefine is on - int prev_buffer_num; // only used when G1SmoothConcRefine is on - // This thread activation threshold - int threshold = G1UpdateBufferQueueProcessingThreshold * _worker_id; - // Next thread activation threshold - int next_threshold = threshold + G1UpdateBufferQueueProcessingThreshold; - int deactivation_threshold = MAX2(threshold - G1UpdateBufferQueueProcessingThreshold / 2, 0); - if (G1SmoothConcRefine) { - lower_limit = 0; - start_vtime_sec = os::elapsedVTime(); - prev_buffer_num = (int) dcqs.completed_buffers_num(); - } else { - lower_limit = G1UpdateBufferQueueProcessingThreshold / 4; // For now. - } - while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, lower_limit)) { - double end_vtime_sec; - double elapsed_vtime_sec; - int elapsed_vtime_ms; - int curr_buffer_num = (int) dcqs.completed_buffers_num(); - - if (G1SmoothConcRefine) { - end_vtime_sec = os::elapsedVTime(); - elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; - elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0); - - if (curr_buffer_num > prev_buffer_num || - curr_buffer_num > next_threshold) { - decreaseInterval(elapsed_vtime_ms); - } else if (curr_buffer_num < prev_buffer_num) { - increaseInterval(elapsed_vtime_ms); - } + do { + int curr_buffer_num = (int)dcqs.completed_buffers_num(); + // If the number of the buffers falls down into the yellow zone, + // that means that the transition period after the evacuation pause has ended. + if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { + dcqs.set_completed_queue_padding(0); } - if (_worker_id == 0) { - sample_young_list_rs_lengths(); - } else if (curr_buffer_num < deactivation_threshold) { + + if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) { // If the number of the buffer has fallen below our threshold // we should deactivate. The predecessor will reactivate this // thread should the number of the buffers cross the threshold again. - MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); deactivate(); - if (G1TraceConcurrentRefinement) { - gclog_or_tty->print_cr("G1-Refine-deactivated worker %d", _worker_id); - } break; } // Check if we need to activate the next thread. - if (curr_buffer_num > next_threshold && _next != NULL && !_next->is_active()) { - MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); + if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) { _next->activate(); - DirtyCardQ_CBL_mon->notify_all(); - if (G1TraceConcurrentRefinement) { - gclog_or_tty->print_cr("G1-Refine-activated worker %d", _next->_worker_id); - } } + } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone())); - if (G1SmoothConcRefine) { - 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++; + // We can exit the loop above while being active if there was a yield request. + if (is_active()) { + deactivate(); } + _sts.leave(); if (os::supports_vtime()) { @@ -172,7 +213,6 @@ void ConcurrentG1RefineThread::run() { } } assert(_should_terminate, "just checking"); - terminate(); } @@ -191,8 +231,8 @@ void ConcurrentG1RefineThread::stop() { } { - MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); - DirtyCardQ_CBL_mon->notify_all(); + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + _monitor->notify(); } { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp index 167fc176ef7..b2eb5d3276e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp @@ -40,42 +40,36 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { // when the number of the rset update buffer crosses a certain threshold. A successor // would self-deactivate when the number of the buffers falls below the threshold. bool _active; - ConcurrentG1RefineThread * _next; - public: - virtual void run(); + ConcurrentG1RefineThread* _next; + Monitor* _monitor; + ConcurrentG1Refine* _cg1r; - bool is_active() { return _active; } - void activate() { _active = true; } - void deactivate() { _active = false; } + int _thread_threshold_step; + // This thread activation threshold + int _threshold; + // This thread deactivation threshold + int _deactivation_threshold; - private: - ConcurrentG1Refine* _cg1r; + void sample_young_list_rs_lengths(); + void run_young_rs_sampling(); + void wait_for_completed_buffers(); - double _interval_ms; - - void decreaseInterval(int processing_time_ms) { - double min_interval_ms = (double) processing_time_ms; - _interval_ms = 0.8 * _interval_ms; - if (_interval_ms < min_interval_ms) - _interval_ms = min_interval_ms; - } - void increaseInterval(int processing_time_ms) { - double max_interval_ms = 9.0 * (double) processing_time_ms; - _interval_ms = 1.1 * _interval_ms; - if (max_interval_ms > 0 && _interval_ms > max_interval_ms) - _interval_ms = max_interval_ms; - } - - void sleepBeforeNextCycle(); + void set_active(bool x) { _active = x; } + bool is_active(); + void activate(); + void deactivate(); // For use by G1CollectedHeap, which is a friend. static SuspendibleThreadSet* sts() { return &_sts; } - public: +public: + virtual void run(); // Constructor ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next, int worker_id_offset, int worker_id); + void initialize(); + // Printing void print() const; void print_on(outputStream* st) const; @@ -83,13 +77,10 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { // Total virtual time so far. double vtime_accum() { return _vtime_accum; } - ConcurrentG1Refine* cg1r() { return _cg1r; } - - void sample_young_list_rs_lengths(); + ConcurrentG1Refine* cg1r() { return _cg1r; } // Yield for GC - void yield(); - + void yield(); // shutdown void stop(); }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index af93ae7d231..c77af414161 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -760,7 +760,6 @@ void ConcurrentMark::checkpointRootsInitialPost() { rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - satb_mq_set.set_process_completed_threshold(G1SATBProcessCompletedThreshold); satb_mq_set.set_active_all_threads(true); // update_g1_committed() will be called at the end of an evac pause diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp index 7372a4a787c..81d8716b1b1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @@ -61,8 +61,8 @@ bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl, #pragma warning( disable:4355 ) // 'this' : used in base member initializer list #endif // _MSC_VER -DirtyCardQueueSet::DirtyCardQueueSet() : - PtrQueueSet(true /*notify_when_complete*/), +DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) : + PtrQueueSet(notify_when_complete), _closure(NULL), _shared_dirty_card_queue(this, true /*perm*/), _free_ids(NULL), @@ -77,12 +77,12 @@ size_t DirtyCardQueueSet::num_par_ids() { } void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, + int process_completed_threshold, int max_completed_queue, Mutex* lock, PtrQueueSet* fl_owner) { - PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner); + PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, + max_completed_queue, fl_owner); set_buffer_size(G1UpdateBufferSize); - set_process_completed_threshold(G1UpdateBufferQueueProcessingThreshold); - _shared_dirty_card_queue.set_lock(lock); _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon); } @@ -154,9 +154,10 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) { return b; } -DirtyCardQueueSet::CompletedBufferNode* -DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) { - CompletedBufferNode* nd = NULL; + +BufferNode* +DirtyCardQueueSet::get_completed_buffer(int stop_at) { + BufferNode* nd = NULL; MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); if ((int)_n_completed_buffers <= stop_at) { @@ -166,53 +167,31 @@ DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) { if (_completed_buffers_head != NULL) { nd = _completed_buffers_head; - _completed_buffers_head = nd->next; + _completed_buffers_head = nd->next(); if (_completed_buffers_head == NULL) _completed_buffers_tail = NULL; _n_completed_buffers--; + assert(_n_completed_buffers >= 0, "Invariant"); } debug_only(assert_completed_buffer_list_len_correct_locked()); return nd; } -// We only do this in contexts where there is no concurrent enqueueing. -DirtyCardQueueSet::CompletedBufferNode* -DirtyCardQueueSet::get_completed_buffer_CAS() { - CompletedBufferNode* nd = _completed_buffers_head; - - while (nd != NULL) { - CompletedBufferNode* next = nd->next; - CompletedBufferNode* result = - (CompletedBufferNode*)Atomic::cmpxchg_ptr(next, - &_completed_buffers_head, - nd); - if (result == nd) { - return result; - } else { - nd = _completed_buffers_head; - } - } - assert(_completed_buffers_head == NULL, "Loop post"); - _completed_buffers_tail = NULL; - return NULL; -} - bool DirtyCardQueueSet:: apply_closure_to_completed_buffer_helper(int worker_i, - CompletedBufferNode* nd) { + BufferNode* nd) { if (nd != NULL) { + void **buf = BufferNode::make_buffer_from_node(nd); + size_t index = nd->index(); bool b = - DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, - nd->index, _sz, + DirtyCardQueue::apply_closure_to_buffer(_closure, buf, + index, _sz, true, worker_i); - void** buf = nd->buf; - size_t index = nd->index; - delete nd; if (b) { deallocate_buffer(buf); return true; // In normal case, go on to next buffer. } else { - enqueue_complete_buffer(buf, index, true); + enqueue_complete_buffer(buf, index); return false; } } else { @@ -222,40 +201,36 @@ apply_closure_to_completed_buffer_helper(int worker_i, bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, int stop_at, - bool with_CAS) + bool during_pause) { - CompletedBufferNode* nd = NULL; - if (with_CAS) { - guarantee(stop_at == 0, "Precondition"); - nd = get_completed_buffer_CAS(); - } else { - nd = get_completed_buffer_lock(stop_at); - } + assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); + BufferNode* nd = get_completed_buffer(stop_at); bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); if (res) Atomic::inc(&_processed_buffers_rs_thread); return res; } void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { - CompletedBufferNode* nd = _completed_buffers_head; + BufferNode* nd = _completed_buffers_head; while (nd != NULL) { bool b = - DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, 0, _sz, - false); + DirtyCardQueue::apply_closure_to_buffer(_closure, + BufferNode::make_buffer_from_node(nd), + 0, _sz, false); guarantee(b, "Should not stop early."); - nd = nd->next; + nd = nd->next(); } } void DirtyCardQueueSet::abandon_logs() { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - CompletedBufferNode* buffers_to_delete = NULL; + BufferNode* buffers_to_delete = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); while (_completed_buffers_head != NULL) { - CompletedBufferNode* nd = _completed_buffers_head; - _completed_buffers_head = nd->next; - nd->next = buffers_to_delete; + BufferNode* nd = _completed_buffers_head; + _completed_buffers_head = nd->next(); + nd->set_next(buffers_to_delete); buffers_to_delete = nd; } _n_completed_buffers = 0; @@ -263,10 +238,9 @@ void DirtyCardQueueSet::abandon_logs() { debug_only(assert_completed_buffer_list_len_correct_locked()); } while (buffers_to_delete != NULL) { - CompletedBufferNode* nd = buffers_to_delete; - buffers_to_delete = nd->next; - deallocate_buffer(nd->buf); - delete nd; + BufferNode* nd = buffers_to_delete; + buffers_to_delete = nd->next(); + deallocate_buffer(BufferNode::make_buffer_from_node(nd)); } // Since abandon is done only at safepoints, we can safely manipulate // these queues. diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp index 7a6f3f27bbd..da2c8378451 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.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 @@ -84,11 +84,12 @@ class DirtyCardQueueSet: public PtrQueueSet { jint _processed_buffers_rs_thread; public: - DirtyCardQueueSet(); + DirtyCardQueueSet(bool notify_when_complete = true); void initialize(Monitor* cbl_mon, Mutex* fl_lock, - int max_completed_queue = 0, - Mutex* lock = NULL, PtrQueueSet* fl_owner = NULL); + int process_completed_threshold, + int max_completed_queue, + Mutex* lock, PtrQueueSet* fl_owner = NULL); // The number of parallel ids that can be claimed to allow collector or // mutator threads to do card-processing work. @@ -120,12 +121,13 @@ public: // is returned to the completed buffer set, and this call returns false. bool apply_closure_to_completed_buffer(int worker_i = 0, int stop_at = 0, - bool with_CAS = false); - bool apply_closure_to_completed_buffer_helper(int worker_i, - CompletedBufferNode* nd); + bool during_pause = false); + + bool apply_closure_to_completed_buffer_helper(int worker_i, + BufferNode* nd); + + BufferNode* get_completed_buffer(int stop_at); - CompletedBufferNode* get_completed_buffer_CAS(); - CompletedBufferNode* get_completed_buffer_lock(int stop_at); // Applies the current closure to all completed buffers, // non-consumptively. void apply_closure_to_all_completed_buffers(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 550b028ea60..c3319d13e79 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -928,6 +928,8 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); TraceTime t(full ? "Full GC (System.gc())" : "Full GC", PrintGC, true, gclog_or_tty); + TraceMemoryManagerStats tms(true /* fullGC */); + double start = os::elapsedTime(); g1_policy()->record_full_collection_start(); @@ -1001,6 +1003,8 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); + MemoryService::track_memory_usage(); + if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); @@ -1371,6 +1375,7 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) { G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : SharedHeap(policy_), _g1_policy(policy_), + _dirty_card_queue_set(false), _ref_processor(NULL), _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), @@ -1436,6 +1441,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : } jint G1CollectedHeap::initialize() { + CollectedHeap::pre_initialize(); os::enable_vtime(); // Necessary to satisfy locking discipline assertions. @@ -1456,8 +1462,6 @@ jint G1CollectedHeap::initialize() { Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); - // We allocate this in any case, but only do no work if the command line - // param is off. _cg1r = new ConcurrentG1Refine(); // Reserve the maximum. @@ -1590,18 +1594,20 @@ jint G1CollectedHeap::initialize() { JavaThread::satb_mark_queue_set().initialize(SATB_Q_CBL_mon, SATB_Q_FL_lock, - 0, + G1SATBProcessCompletedThreshold, Shared_SATB_Q_lock); JavaThread::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - G1UpdateBufferQueueMaxLength, + concurrent_g1_refine()->yellow_zone(), + concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock); if (G1DeferredRSUpdate) { dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - 0, + -1, // never trigger processing + -1, // no limit on length Shared_DirtyCardQ_lock, &JavaThread::dirty_card_queue_set()); } @@ -1732,13 +1738,6 @@ size_t G1CollectedHeap::unsafe_max_alloc() { return car->free(); } -void G1CollectedHeap::collect(GCCause::Cause cause) { - // The caller doesn't have the Heap_lock - assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - MutexLocker ml(Heap_lock); - collect_locked(cause); -} - void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { assert(Thread::current()->is_VM_thread(), "Precondition#1"); assert(Heap_lock->is_locked(), "Precondition#2"); @@ -1755,17 +1754,31 @@ void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { } } +void G1CollectedHeap::collect(GCCause::Cause cause) { + // The caller doesn't have the Heap_lock + assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); -void G1CollectedHeap::collect_locked(GCCause::Cause cause) { - // Don't want to do a GC until cleanup is completed. - wait_for_cleanup_complete(); - - // Read the GC count while holding the Heap_lock - int gc_count_before = SharedHeap::heap()->total_collections(); + int gc_count_before; { - MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_G1CollectFull op(gc_count_before, cause); - VMThread::execute(&op); + MutexLocker ml(Heap_lock); + // Read the GC count while holding the Heap_lock + gc_count_before = SharedHeap::heap()->total_collections(); + + // Don't want to do a GC until cleanup is completed. + wait_for_cleanup_complete(); + } // We give up heap lock; VMThread::execute gets it back below + switch (cause) { + case GCCause::_scavenge_alot: { + // Do an incremental pause, which might sometimes be abandoned. + VM_G1IncCollectionPause op(gc_count_before, cause); + VMThread::execute(&op); + break; + } + default: { + // In all other cases, we currently do a full gc. + VM_G1CollectFull op(gc_count_before, cause); + VMThread::execute(&op); + } } } @@ -2119,7 +2132,7 @@ size_t G1CollectedHeap::large_typearray_limit() { } size_t G1CollectedHeap::max_capacity() const { - return _g1_committed.byte_size(); + return g1_reserved_obj_bytes(); } jlong G1CollectedHeap::millis_since_last_gc() { @@ -2638,6 +2651,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { } { + ResourceMark rm; + char verbose_str[128]; sprintf(verbose_str, "GC pause "); if (g1_policy()->in_young_gc_mode()) { @@ -2649,8 +2664,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { if (g1_policy()->should_initiate_conc_mark()) strcat(verbose_str, " (initial-mark)"); - 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 // is messy if we do. @@ -2658,7 +2671,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); TraceTime t(verbose_str, PrintGC && !PrintGCDetails, true, gclog_or_tty); - ResourceMark rm; + TraceMemoryManagerStats tms(false /* fullGC */); + assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread"); guarantee(!is_gc_active(), "collection is not reentrant"); @@ -2802,6 +2816,22 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { _young_list->reset_auxilary_lists(); } } else { + if (_in_cset_fast_test != NULL) { + assert(_in_cset_fast_test_base != NULL, "Since _in_cset_fast_test isn't"); + FREE_C_HEAP_ARRAY(bool, _in_cset_fast_test_base); + // this is more for peace of mind; we're nulling them here and + // we're expecting them to be null at the beginning of the next GC + _in_cset_fast_test = NULL; + _in_cset_fast_test_base = NULL; + } + // This looks confusing, because the DPT should really be empty + // at this point -- since we have not done any collection work, + // there should not be any derived pointers in the table to update; + // however, there is some additional state in the DPT which is + // reset at the end of the (null) "gc" here via the following call. + // A better approach might be to split off that state resetting work + // into a separate method that asserts that the DPT is empty and call + // that here. That is deferred for now. COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } @@ -2838,6 +2868,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { assert(regions_accounted_for(), "Region leakage."); + MemoryService::track_memory_usage(); + if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); @@ -4209,10 +4241,11 @@ void G1CollectedHeap::evacuate_collection_set() { 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()); + + DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); + dcq.merge_bufferlists(&dirty_card_queue_set()); assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); } - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 5e07828267f..bb73eb28881 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -692,7 +692,7 @@ public: // Reserved (g1 only; super method includes perm), capacity and the used // portion in bytes. - size_t g1_reserved_obj_bytes() { return _g1_reserved.byte_size(); } + size_t g1_reserved_obj_bytes() const { return _g1_reserved.byte_size(); } virtual size_t capacity() const; virtual size_t used() const; // This should be called when we're not holding the heap lock. The @@ -1007,6 +1007,10 @@ public: return true; } + virtual bool card_mark_must_follow_store() const { + return true; + } + bool is_in_young(oop obj) { HeapRegion* hr = heap_region_containing(obj); return hr != NULL && hr->is_young(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 20e8fba5dea..487fb6d954a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1516,8 +1516,30 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { (end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0; update_recent_gc_times(end_time_sec, elapsed_ms); _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms; - // using 1.01 to account for floating point inaccuracies - assert(recent_avg_pause_time_ratio() < 1.01, "All GC?"); + if (recent_avg_pause_time_ratio() < 0.0 || + (recent_avg_pause_time_ratio() - 1.0 > 0.0)) { +#ifndef PRODUCT + // Dump info to allow post-facto debugging + gclog_or_tty->print_cr("recent_avg_pause_time_ratio() out of bounds"); + gclog_or_tty->print_cr("-------------------------------------------"); + gclog_or_tty->print_cr("Recent GC Times (ms):"); + _recent_gc_times_ms->dump(); + gclog_or_tty->print_cr("(End Time=%3.3f) Recent GC End Times (s):", end_time_sec); + _recent_prev_end_times_for_all_gcs_sec->dump(); + gclog_or_tty->print_cr("GC = %3.3f, Interval = %3.3f, Ratio = %3.3f", + _recent_gc_times_ms->sum(), interval_ms, recent_avg_pause_time_ratio()); + // In debug mode, terminate the JVM if the user wants to debug at this point. + assert(!G1FailOnFPError, "Debugging data for CR 6898948 has been dumped above"); +#endif // !PRODUCT + // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in + // CR 6902692 by redoing the manner in which the ratio is incrementally computed. + if (_recent_avg_pause_time_ratio < 0.0) { + _recent_avg_pause_time_ratio = 0.0; + } else { + assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant"); + _recent_avg_pause_time_ratio = 1.0; + } + } } if (G1PolicyVerbose > 1) { @@ -1892,6 +1914,10 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { calculate_young_list_min_length(); calculate_young_list_target_config(); + // Note that _mmu_tracker->max_gc_time() returns the time in seconds. + double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSUpdatePauseFractionPercent / 100.0; + adjust_concurrent_refinement(update_rs_time, update_rs_processed_buffers, update_rs_time_goal_ms); + // _target_pause_time_ms = -1.0; @@ -1899,6 +1925,47 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { // +void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, + double update_rs_processed_buffers, + double goal_ms) { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + ConcurrentG1Refine *cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); + + if (G1AdaptiveConcRefine) { + const int k_gy = 3, k_gr = 6; + const double inc_k = 1.1, dec_k = 0.9; + + int g = cg1r->green_zone(); + if (update_rs_time > goal_ms) { + g = (int)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. + } else { + if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { + g = (int)MAX2(g * inc_k, g + 1.0); + } + } + // Change the refinement threads params + cg1r->set_green_zone(g); + cg1r->set_yellow_zone(g * k_gy); + cg1r->set_red_zone(g * k_gr); + cg1r->reinitialize_threads(); + + int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * sigma()), 1); + int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, + cg1r->yellow_zone()); + // Change the barrier params + dcqs.set_process_completed_threshold(processing_threshold); + dcqs.set_max_completed_queue(cg1r->red_zone()); + } + + int curr_queue_size = dcqs.completed_buffers_num(); + if (curr_queue_size >= cg1r->yellow_zone()) { + dcqs.set_completed_queue_padding(curr_queue_size); + } else { + dcqs.set_completed_queue_padding(0); + } + dcqs.notify_if_necessary(); +} + double G1CollectorPolicy:: predict_young_collection_elapsed_time_ms(size_t adjustment) { @@ -2825,8 +2892,15 @@ choose_collection_set() { double non_young_start_time_sec; start_recording_regions(); - guarantee(_target_pause_time_ms > -1.0, + guarantee(_target_pause_time_ms > -1.0 + NOT_PRODUCT(|| Universe::heap()->gc_cause() == GCCause::_scavenge_alot), "_target_pause_time_ms should have been set!"); +#ifndef PRODUCT + if (_target_pause_time_ms <= -1.0) { + assert(ScavengeALot && Universe::heap()->gc_cause() == GCCause::_scavenge_alot, "Error"); + _target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; + } +#endif assert(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); @@ -2972,7 +3046,3 @@ record_collection_pause_end(bool abandoned) { G1CollectorPolicy::record_collection_pause_end(abandoned); assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end."); } - -// Local Variables: *** -// c-indentation-style: gnu *** -// End: *** diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 0dff91a0b50..2b9eb83f074 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -316,6 +316,10 @@ private: bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group); #endif // PRODUCT + void adjust_concurrent_refinement(double update_rs_time, + double update_rs_processed_buffers, + double goal_ms); + protected: double _pause_time_target_ms; double _recorded_young_cset_choice_time_ms; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp index b0d0df45dd9..492adaef6fd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp @@ -86,12 +86,22 @@ void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) { // increase the array size (:-) // remove the oldest entry (this might allow more GC time for // the time slice than what's allowed) - // concolidate the two entries with the minimum gap between them - // (this mighte allow less GC time than what's allowed) - guarantee(0, "array full, currently we can't recover"); + // consolidate the two entries with the minimum gap between them + // (this might allow less GC time than what's allowed) + guarantee(NOT_PRODUCT(ScavengeALot ||) G1ForgetfulMMUTracker, + "array full, currently we can't recover unless +G1ForgetfulMMUTracker"); + // In the case where ScavengeALot is true, such overflow is not + // uncommon; in such cases, we can, without much loss of precision + // or performance (we are GC'ing most of the time anyway!), + // simply overwrite the oldest entry in the tracker: this + // is also the behaviour when G1ForgetfulMMUTracker is enabled. + _head_index = trim_index(_head_index + 1); + assert(_head_index == _tail_index, "Because we have a full circular buffer"); + _tail_index = trim_index(_tail_index + 1); + } else { + _head_index = trim_index(_head_index + 1); + ++_no_entries; } - _head_index = trim_index(_head_index + 1); - ++_no_entries; _array[_head_index] = G1MMUTrackerQueueElem(start, end); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp index 0eff2c3867a..1030454a741 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp @@ -99,7 +99,10 @@ private: // The array is of fixed size and I don't think we'll need more than // two or three entries with the current behaviour of G1 pauses. // If the array is full, an easy fix is to look for the pauses with - // the shortest gap between them and concolidate them. + // the shortest gap between them and consolidate them. + // For now, we have taken the expedient alternative of forgetting + // the oldest entry in the event that +G1ForgetfulMMUTracker, thus + // potentially violating MMU specs for some time thereafter. G1MMUTrackerQueueElem _array[QueueLength]; int _head_index; 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 c941c8755d6..85f3841c128 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -85,7 +85,7 @@ diagnostic(bool, G1SummarizeZFStats, false, \ "Summarize zero-filling info") \ \ - develop(bool, G1TraceConcurrentRefinement, false, \ + diagnostic(bool, G1TraceConcurrentRefinement, false, \ "Trace G1 concurrent refinement") \ \ product(intx, G1MarkStackSize, 2 * 1024 * 1024, \ @@ -94,19 +94,6 @@ product(intx, G1MarkRegionStackSize, 1024 * 1024, \ "Size of the region stack for concurrent marking.") \ \ - develop(bool, G1ConcRefine, true, \ - "If true, run concurrent rem set refinement for G1") \ - \ - develop(intx, G1ConcRefineTargTraversals, 4, \ - "Number of concurrent refinement we try to achieve") \ - \ - develop(intx, G1ConcRefineInitialDelta, 4, \ - "Number of heap regions of alloc ahead of starting collection " \ - "pause to start concurrent refinement (initially)") \ - \ - develop(bool, G1SmoothConcRefine, true, \ - "Attempts to smooth out the overhead of concurrent refinement") \ - \ develop(bool, G1ConcZeroFill, true, \ "If true, run concurrent zero-filling thread") \ \ @@ -178,13 +165,38 @@ product(intx, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ \ - product(intx, G1UpdateBufferQueueProcessingThreshold, 5, \ + product(intx, G1ConcRefineYellowZone, 0, \ "Number of enqueued update buffers that will " \ - "trigger concurrent processing") \ + "trigger concurrent processing. Will be selected ergonomically " \ + "by default.") \ \ - product(intx, G1UpdateBufferQueueMaxLength, 30, \ + product(intx, G1ConcRefineRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ - "threads start processing new ones instead of enqueueing them") \ + "threads start processing new ones instead of enqueueing them. " \ + "Will be selected ergonomically by default. Zero will disable " \ + "concurrent processing.") \ + \ + product(intx, G1ConcRefineGreenZone, 0, \ + "The number of update buffers that are left in the queue by the " \ + "concurrent processing threads. Will be selected ergonomically " \ + "by default.") \ + \ + product(intx, G1ConcRefineServiceInterval, 300, \ + "The last concurrent refinement thread wakes up every " \ + "specified number of milliseconds to do miscellaneous work.") \ + \ + product(intx, G1ConcRefineThresholdStep, 0, \ + "Each time the rset update queue increases by this amount " \ + "activate the next refinement thread if available. " \ + "Will be selected ergonomically by default.") \ + \ + product(intx, G1RSUpdatePauseFractionPercent, 10, \ + "A target percentage of time that is allowed to be spend on " \ + "process RS update buffers during the collection pause.") \ + \ + product(bool, G1AdaptiveConcRefine, true, \ + "Select green, yellow and red zones adaptively to meet the " \ + "the pause requirements.") \ \ develop(intx, G1ConcRSLogCacheSize, 10, \ "Log base 2 of the length of conc RS hot-card cache.") \ @@ -242,6 +254,10 @@ product(bool, G1UseSurvivorSpaces, true, \ "When true, use survivor space.") \ \ + develop(bool, G1FailOnFPError, false, \ + "When set, G1 will fail when it encounters an FP 'error', " \ + "so as to allow debugging") \ + \ develop(bool, G1FixedTenuringThreshold, false, \ "When set, G1 will not adjust the tenuring threshold") \ \ @@ -252,6 +268,9 @@ "If non-0 is the size of the G1 survivor space, " \ "otherwise SurvivorRatio is used to determine the size") \ \ + product(bool, G1ForgetfulMMUTracker, false, \ + "If the MMU tracker's memory is full, forget the oldest entry") \ + \ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp index 060743dd38a..4a3fac2faaf 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp @@ -64,8 +64,8 @@ void PtrQueue::enqueue_known_active(void* ptr) { while (_index == 0) { handle_zero_index(); } - assert(_index > 0, "postcondition"); + assert(_index > 0, "postcondition"); _index -= oopSize; _buf[byte_index_to_index((int)_index)] = ptr; assert(0 <= _index && _index <= _sz, "Invariant."); @@ -73,7 +73,12 @@ void PtrQueue::enqueue_known_active(void* ptr) { void PtrQueue::locking_enqueue_completed_buffer(void** buf) { assert(_lock->owned_by_self(), "Required."); + + // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before + // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they + // have the same rank and we may get the "possible deadlock" message _lock->unlock(); + qset()->enqueue_complete_buffer(buf); // We must relock only because the caller will unlock, for the normal // case. @@ -99,94 +104,139 @@ void** PtrQueueSet::allocate_buffer() { assert(_sz > 0, "Didn't set a buffer size."); 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]; + void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list); + _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next(); _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; return res; } else { - return NEW_C_HEAP_ARRAY(void*, _sz); + // Allocate space for the BufferNode in front of the buffer. + char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size()); + return BufferNode::make_buffer_from_block(b); } } void PtrQueueSet::deallocate_buffer(void** buf) { assert(_sz > 0, "Didn't set a buffer size."); 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; + BufferNode *node = BufferNode::make_node_from_buffer(buf); + node->set_next(_fl_owner->_buf_free_list); + _fl_owner->_buf_free_list = node; _fl_owner->_buf_free_list_sz++; } void PtrQueueSet::reduce_free_list() { + assert(_fl_owner == this, "Free list reduction is allowed only for the owner"); // For now we'll adopt the strategy of deleting half. MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); size_t n = _buf_free_list_sz / 2; while (n > 0) { assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); - void** head = _buf_free_list; - _buf_free_list = (void**)_buf_free_list[0]; - FREE_C_HEAP_ARRAY(void*,head); + void* b = BufferNode::make_block_from_node(_buf_free_list); + _buf_free_list = _buf_free_list->next(); + FREE_C_HEAP_ARRAY(char, b); + _buf_free_list_sz --; n--; } } -void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index, bool ignore_max_completed) { - // I use explicit locking here because there's a bailout in the middle. - _cbl_mon->lock_without_safepoint_check(); +void PtrQueue::handle_zero_index() { + assert(0 == _index, "Precondition."); + // This thread records the full buffer and allocates a new one (while + // holding the lock if there is one). + if (_buf != NULL) { + if (_lock) { + assert(_lock->owned_by_self(), "Required."); - Thread* thread = Thread::current(); - assert( ignore_max_completed || - thread->is_Java_thread() || - SafepointSynchronize::is_at_safepoint(), - "invariant" ); - ignore_max_completed = ignore_max_completed || !thread->is_Java_thread(); + // The current PtrQ may be the shared dirty card queue and + // may be being manipulated by more than one worker thread + // during a pause. Since the enqueuing of the completed + // buffer unlocks the Shared_DirtyCardQ_lock more than one + // worker thread can 'race' on reading the shared queue attributes + // (_buf and _index) and multiple threads can call into this + // routine for the same buffer. This will cause the completed + // buffer to be added to the CBL multiple times. - if (!ignore_max_completed && _max_completed_queue > 0 && - _n_completed_buffers >= (size_t) _max_completed_queue) { - _cbl_mon->unlock(); - bool b = mut_process_buffer(buf); - if (b) { - deallocate_buffer(buf); - return; + // We "claim" the current buffer by caching value of _buf in + // a local and clearing the field while holding _lock. When + // _lock is released (while enqueueing the completed buffer) + // the thread that acquires _lock will skip this code, + // preventing the subsequent the multiple enqueue, and + // install a newly allocated buffer below. + + void** buf = _buf; // local pointer to completed buffer + _buf = NULL; // clear shared _buf field + + locking_enqueue_completed_buffer(buf); // enqueue completed buffer + + // While the current thread was enqueuing the buffer another thread + // may have a allocated a new buffer and inserted it into this pointer + // queue. If that happens then we just return so that the current + // thread doesn't overwrite the buffer allocated by the other thread + // and potentially losing some dirtied cards. + + if (_buf != NULL) return; + } else { + if (qset()->process_or_enqueue_complete_buffer(_buf)) { + // Recycle the buffer. No allocation. + _sz = qset()->buffer_size(); + _index = _sz; + return; + } } - - // Otherwise, go ahead and enqueue the buffer. Must reaquire the lock. - _cbl_mon->lock_without_safepoint_check(); } + // Reallocate the buffer + _buf = qset()->allocate_buffer(); + _sz = qset()->buffer_size(); + _index = _sz; + assert(0 <= _index && _index <= _sz, "Invariant."); +} - // Here we still hold the _cbl_mon. - CompletedBufferNode* cbn = new CompletedBufferNode; - cbn->buf = buf; - cbn->next = NULL; - cbn->index = index; +bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { + if (Thread::current()->is_Java_thread()) { + // We don't lock. It is fine to be epsilon-precise here. + if (_max_completed_queue == 0 || _max_completed_queue > 0 && + _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) { + bool b = mut_process_buffer(buf); + if (b) { + // True here means that the buffer hasn't been deallocated and the caller may reuse it. + return true; + } + } + } + // The buffer will be enqueued. The caller will have to get a new one. + enqueue_complete_buffer(buf); + return false; +} + +void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { + MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); + BufferNode* cbn = BufferNode::new_from_buffer(buf); + cbn->set_index(index); if (_completed_buffers_tail == NULL) { assert(_completed_buffers_head == NULL, "Well-formedness"); _completed_buffers_head = cbn; _completed_buffers_tail = cbn; } else { - _completed_buffers_tail->next = cbn; + _completed_buffers_tail->set_next(cbn); _completed_buffers_tail = cbn; } _n_completed_buffers++; - if (!_process_completed && + if (!_process_completed && _process_completed_threshold >= 0 && _n_completed_buffers >= _process_completed_threshold) { _process_completed = true; if (_notify_when_complete) - _cbl_mon->notify_all(); + _cbl_mon->notify(); } debug_only(assert_completed_buffer_list_len_correct_locked()); - _cbl_mon->unlock(); } int PtrQueueSet::completed_buffers_list_length() { int n = 0; - CompletedBufferNode* cbn = _completed_buffers_head; + BufferNode* cbn = _completed_buffers_head; while (cbn != NULL) { n++; - cbn = cbn->next; + cbn = cbn->next(); } return n; } @@ -197,7 +247,7 @@ void PtrQueueSet::assert_completed_buffer_list_len_correct() { } void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() { - guarantee((size_t)completed_buffers_list_length() == _n_completed_buffers, + guarantee(completed_buffers_list_length() == _n_completed_buffers, "Completed buffer length is wrong."); } @@ -206,12 +256,8 @@ void PtrQueueSet::set_buffer_size(size_t sz) { _sz = sz * oopSize; } -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 +// Merge lists of buffers. Notify the processing threads. +// 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"); @@ -223,7 +269,7 @@ void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { } 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->set_next(src->_completed_buffers_head); _completed_buffers_tail = src->_completed_buffers_tail; } } @@ -236,31 +282,13 @@ void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { 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) { +void PtrQueueSet::notify_if_necessary() { + MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); + if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) { _process_completed = true; if (_notify_when_complete) - _cbl_mon->notify_all(); + _cbl_mon->notify(); } } - -// 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 663dcba4fa6..ccf5b207c76 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp @@ -27,8 +27,10 @@ // the addresses of modified old-generation objects. This type supports // this operation. -class PtrQueueSet; +// The definition of placement operator new(size_t, void*) in the . +#include +class PtrQueueSet; class PtrQueue VALUE_OBJ_CLASS_SPEC { protected: @@ -77,7 +79,7 @@ public: else enqueue_known_active(ptr); } - inline void handle_zero_index(); + void handle_zero_index(); void locking_enqueue_completed_buffer(void** buf); void enqueue_known_active(void* ptr); @@ -126,34 +128,65 @@ public: }; +class BufferNode { + size_t _index; + BufferNode* _next; +public: + BufferNode() : _index(0), _next(NULL) { } + BufferNode* next() const { return _next; } + void set_next(BufferNode* n) { _next = n; } + size_t index() const { return _index; } + void set_index(size_t i) { _index = i; } + + // Align the size of the structure to the size of the pointer + static size_t aligned_size() { + static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*)); + return alignment; + } + + // BufferNode is allocated before the buffer. + // The chunk of memory that holds both of them is a block. + + // Produce a new BufferNode given a buffer. + static BufferNode* new_from_buffer(void** buf) { + return new (make_block_from_buffer(buf)) BufferNode; + } + + // The following are the required conversion routines: + static BufferNode* make_node_from_buffer(void** buf) { + return (BufferNode*)make_block_from_buffer(buf); + } + static void** make_buffer_from_node(BufferNode *node) { + return make_buffer_from_block(node); + } + static void* make_block_from_node(BufferNode *node) { + return (void*)node; + } + static void** make_buffer_from_block(void* p) { + return (void**)((char*)p + aligned_size()); + } + static void* make_block_from_buffer(void** p) { + return (void*)((char*)p - aligned_size()); + } +}; + // A PtrQueueSet represents resources common to a set of pointer queues. // In particular, the individual queues allocate buffers from this shared // set, and return completed buffers to the set. // All these variables are are protected by the TLOQ_CBL_mon. XXX ??? class PtrQueueSet VALUE_OBJ_CLASS_SPEC { - protected: - - class CompletedBufferNode: public CHeapObj { - public: - void** buf; - size_t index; - CompletedBufferNode* next; - CompletedBufferNode() : buf(NULL), - index(0), next(NULL){ } - }; - Monitor* _cbl_mon; // Protects the fields below. - CompletedBufferNode* _completed_buffers_head; - CompletedBufferNode* _completed_buffers_tail; - size_t _n_completed_buffers; - size_t _process_completed_threshold; + BufferNode* _completed_buffers_head; + BufferNode* _completed_buffers_tail; + int _n_completed_buffers; + int _process_completed_threshold; volatile bool _process_completed; // This (and the interpretation of the first element as a "next" // pointer) are protected by the TLOQ_FL_lock. Mutex* _fl_lock; - void** _buf_free_list; + BufferNode* _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. @@ -170,6 +203,7 @@ protected: // Maximum number of elements allowed on completed queue: after that, // enqueuer does the work itself. Zero indicates no maximum. int _max_completed_queue; + int _completed_queue_padding; int completed_buffers_list_length(); void assert_completed_buffer_list_len_correct_locked(); @@ -191,9 +225,12 @@ 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 process_completed_threshold, + int max_completed_queue, PtrQueueSet *fl_owner = NULL) { _max_completed_queue = max_completed_queue; + _process_completed_threshold = process_completed_threshold; + _completed_queue_padding = 0; assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?"); _cbl_mon = cbl_mon; _fl_lock = fl_lock; @@ -208,14 +245,17 @@ public: void deallocate_buffer(void** buf); // Declares that "buf" is a complete buffer. - void enqueue_complete_buffer(void** buf, size_t index = 0, - bool ignore_max_completed = false); + void enqueue_complete_buffer(void** buf, size_t index = 0); + + // To be invoked by the mutator. + bool process_or_enqueue_complete_buffer(void** buf); bool completed_buffers_exist_dirty() { return _n_completed_buffers > 0; } bool process_completed_buffers() { return _process_completed; } + void set_process_completed(bool x) { _process_completed = x; } bool active() { return _all_active; } @@ -226,15 +266,24 @@ public: // Get the buffer size. size_t buffer_size() { return _sz; } - // Set the number of completed buffers that triggers log processing. - void set_process_completed_threshold(size_t sz); + // Get/Set the number of completed buffers that triggers log processing. + void set_process_completed_threshold(int sz) { _process_completed_threshold = sz; } + int process_completed_threshold() const { return _process_completed_threshold; } // Must only be called at a safe point. Indicates that the buffer free // list size may be reduced, if that is deemed desirable. void reduce_free_list(); - size_t completed_buffers_num() { return _n_completed_buffers; } + int completed_buffers_num() { return _n_completed_buffers; } void merge_bufferlists(PtrQueueSet* src); - void merge_freelists(PtrQueueSet* src); + + void set_max_completed_queue(int m) { _max_completed_queue = m; } + int max_completed_queue() { return _max_completed_queue; } + + void set_completed_queue_padding(int padding) { _completed_queue_padding = padding; } + int completed_queue_padding() { return _completed_queue_padding; } + + // Notify the consumer if the number of buffers crossed the threshold + void notify_if_necessary(); }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp index 3cf402ce7a8..8efdc3b9c23 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp @@ -67,9 +67,9 @@ SATBMarkQueueSet::SATBMarkQueueSet() : {} void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, - int max_completed_queue, + int process_completed_threshold, Mutex* lock) { - PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue); + PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1); _shared_satb_queue.set_lock(lock); if (ParallelGCThreads > 0) { _par_closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads); @@ -122,12 +122,12 @@ void SATBMarkQueueSet::par_iterate_closure_all_threads(int worker) { bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par, int worker) { - CompletedBufferNode* nd = NULL; + BufferNode* nd = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); if (_completed_buffers_head != NULL) { nd = _completed_buffers_head; - _completed_buffers_head = nd->next; + _completed_buffers_head = nd->next(); if (_completed_buffers_head == NULL) _completed_buffers_tail = NULL; _n_completed_buffers--; if (_n_completed_buffers == 0) _process_completed = false; @@ -135,9 +135,9 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par, } ObjectClosure* cl = (par ? _par_closures[worker] : _closure); if (nd != NULL) { - ObjPtrQueue::apply_closure_to_buffer(cl, nd->buf, 0, _sz); - deallocate_buffer(nd->buf); - delete nd; + void **buf = BufferNode::make_buffer_from_node(nd); + ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); + deallocate_buffer(buf); return true; } else { return false; @@ -145,13 +145,13 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par, } void SATBMarkQueueSet::abandon_partial_marking() { - CompletedBufferNode* buffers_to_delete = NULL; + BufferNode* buffers_to_delete = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); while (_completed_buffers_head != NULL) { - CompletedBufferNode* nd = _completed_buffers_head; - _completed_buffers_head = nd->next; - nd->next = buffers_to_delete; + BufferNode* nd = _completed_buffers_head; + _completed_buffers_head = nd->next(); + nd->set_next(buffers_to_delete); buffers_to_delete = nd; } _completed_buffers_tail = NULL; @@ -159,10 +159,9 @@ void SATBMarkQueueSet::abandon_partial_marking() { DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); } while (buffers_to_delete != NULL) { - CompletedBufferNode* nd = buffers_to_delete; - buffers_to_delete = nd->next; - deallocate_buffer(nd->buf); - delete nd; + BufferNode* nd = buffers_to_delete; + buffers_to_delete = nd->next(); + deallocate_buffer(BufferNode::make_buffer_from_node(nd)); } assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); // So we can safely manipulate these queues. diff --git a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp index ed1181dd79f..76218a6363b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp @@ -60,8 +60,8 @@ public: SATBMarkQueueSet(); void initialize(Monitor* cbl_mon, Mutex* fl_lock, - int max_completed_queue = 0, - Mutex* lock = NULL); + int process_completed_threshold, + Mutex* lock); static void handle_zero_index_for_thread(JavaThread* t); 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 e59dbe483d2..2137efa4e83 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 @@ -42,7 +42,7 @@ void VM_G1CollectFull::doit() { void VM_G1IncCollectionPause::doit() { JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCCauseSetter x(g1h, GCCause::_g1_inc_collection_pause); + GCCauseSetter x(g1h, _gc_cause); g1h->do_collection_pause_at_safepoint(); } 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 6cf0605ec8c..95dda3844b7 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 @@ -68,8 +68,9 @@ class VM_G1CollectForAllocation: public VM_GC_Operation { class VM_G1IncCollectionPause: public VM_GC_Operation { public: - VM_G1IncCollectionPause(int gc_count_before) : - VM_GC_Operation(gc_count_before) {} + VM_G1IncCollectionPause(int gc_count_before, + GCCause::Cause gc_cause = GCCause::_g1_inc_collection_pause) : + VM_GC_Operation(gc_count_before) { _gc_cause = gc_cause; } virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; } virtual void doit(); virtual const char* name() const { diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep index 7ae314990c8..c5a7a386b60 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep @@ -221,6 +221,7 @@ freeList.cpp freeList.hpp freeList.cpp globals.hpp freeList.cpp mutex.hpp freeList.cpp sharedHeap.hpp +freeList.cpp vmThread.hpp freeList.hpp allocationStats.hpp diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 index 63bfbce76f9..60531af9032 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 @@ -109,7 +109,6 @@ dirtyCardQueue.cpp atomic.hpp dirtyCardQueue.cpp dirtyCardQueue.hpp dirtyCardQueue.cpp heapRegionRemSet.hpp dirtyCardQueue.cpp mutexLocker.hpp -dirtyCardQueue.cpp ptrQueue.inline.hpp dirtyCardQueue.cpp safepoint.hpp dirtyCardQueue.cpp thread.hpp dirtyCardQueue.cpp thread_.inline.hpp @@ -222,6 +221,15 @@ g1MarkSweep.hpp oop.hpp g1MarkSweep.hpp timer.hpp g1MarkSweep.hpp universe.hpp +g1MemoryPool.cpp heapRegion.hpp +g1MemoryPool.cpp g1CollectedHeap.inline.hpp +g1MemoryPool.cpp g1CollectedHeap.hpp +g1MemoryPool.cpp g1CollectorPolicy.hpp +g1MemoryPool.cpp g1MemoryPool.hpp + +g1MemoryPool.hpp memoryUsage.hpp +g1MemoryPool.hpp memoryPool.hpp + g1OopClosures.inline.hpp concurrentMark.hpp g1OopClosures.inline.hpp g1OopClosures.hpp g1OopClosures.inline.hpp g1CollectedHeap.hpp @@ -303,12 +311,13 @@ heapRegionSeq.inline.hpp heapRegionSeq.hpp klass.hpp g1OopClosures.hpp +memoryService.cpp g1MemoryPool.hpp + ptrQueue.cpp allocation.hpp ptrQueue.cpp allocation.inline.hpp ptrQueue.cpp mutex.hpp ptrQueue.cpp mutexLocker.hpp ptrQueue.cpp ptrQueue.hpp -ptrQueue.cpp ptrQueue.inline.hpp ptrQueue.cpp thread_.inline.hpp ptrQueue.hpp allocation.hpp @@ -318,7 +327,6 @@ ptrQueue.inline.hpp ptrQueue.hpp satbQueue.cpp allocation.inline.hpp satbQueue.cpp mutexLocker.hpp -satbQueue.cpp ptrQueue.inline.hpp satbQueue.cpp satbQueue.hpp satbQueue.cpp sharedHeap.hpp satbQueue.cpp thread.hpp diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_serial b/hotspot/src/share/vm/gc_implementation/includeDB_gc_serial index 6fb42f95b6f..60e41874d43 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_serial +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_serial @@ -71,6 +71,7 @@ gcUtil.cpp gcUtil.hpp gcUtil.hpp allocation.hpp gcUtil.hpp debug.hpp gcUtil.hpp globalDefinitions.hpp +gcUtil.hpp ostream.hpp gcUtil.hpp timer.hpp generationCounters.cpp generationCounters.hpp diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index 5acb923a056..07f759c9457 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -50,6 +50,7 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, work_queue_set_, &term_), _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _keep_alive_closure(&_scan_weak_ref_closure), + _promotion_failure_size(0), _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0), _strong_roots_time(0.0), _term_time(0.0) { @@ -249,6 +250,16 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, } } +void ParScanThreadState::print_and_clear_promotion_failure_size() { + if (_promotion_failure_size != 0) { + if (PrintPromotionFailure) { + gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ", + _thread_num, _promotion_failure_size); + } + _promotion_failure_size = 0; + } +} + class ParScanThreadStateSet: private ResourceArray { public: // Initializes states for the specified number of threads; @@ -260,11 +271,11 @@ public: GrowableArray** overflow_stacks_, size_t desired_plab_sz, ParallelTaskTerminator& term); - inline ParScanThreadState& thread_sate(int i); + inline ParScanThreadState& thread_state(int i); int pushes() { return _pushes; } int pops() { return _pops; } int steals() { return _steals; } - void reset(); + void reset(bool promotion_failed); void flush(); private: ParallelTaskTerminator& _term; @@ -295,22 +306,31 @@ ParScanThreadStateSet::ParScanThreadStateSet( } } -inline ParScanThreadState& ParScanThreadStateSet::thread_sate(int i) +inline ParScanThreadState& ParScanThreadStateSet::thread_state(int i) { assert(i >= 0 && i < length(), "sanity check!"); return ((ParScanThreadState*)_data)[i]; } -void ParScanThreadStateSet::reset() +void ParScanThreadStateSet::reset(bool promotion_failed) { _term.reset_for_reuse(); + if (promotion_failed) { + for (int i = 0; i < length(); ++i) { + thread_state(i).print_and_clear_promotion_failure_size(); + } + } } void ParScanThreadStateSet::flush() { + // Work in this loop should be kept as lightweight as + // possible since this might otherwise become a bottleneck + // to scaling. Should we add heavy-weight work into this + // loop, consider parallelizing the loop into the worker threads. for (int i = 0; i < length(); ++i) { - ParScanThreadState& par_scan_state = thread_sate(i); + ParScanThreadState& par_scan_state = thread_state(i); // Flush stats related to To-space PLAB activity and // retire the last buffer. @@ -362,6 +382,14 @@ void ParScanThreadStateSet::flush() } } } + if (UseConcMarkSweepGC && ParallelGCThreads > 0) { + // We need to call this even when ResizeOldPLAB is disabled + // so as to avoid breaking some asserts. While we may be able + // to avoid this by reorganizing the code a bit, I am loathe + // to do that unless we find cases where ergo leads to bad + // performance. + CFLS_LAB::compute_desired_plab_size(); + } } ParScanClosure::ParScanClosure(ParNewGeneration* g, @@ -475,7 +503,7 @@ void ParNewGenTask::work(int i) { Generation* old_gen = gch->next_gen(_gen); - ParScanThreadState& par_scan_state = _state_set->thread_sate(i); + ParScanThreadState& par_scan_state = _state_set->thread_state(i); par_scan_state.set_young_old_boundary(_young_old_boundary); par_scan_state.start_strong_roots(); @@ -659,7 +687,7 @@ void ParNewRefProcTaskProxy::work(int i) { ResourceMark rm; HandleMark hm; - ParScanThreadState& par_scan_state = _state_set.thread_sate(i); + ParScanThreadState& par_scan_state = _state_set.thread_state(i); par_scan_state.set_young_old_boundary(_young_old_boundary); _task.work(i, par_scan_state.is_alive_closure(), par_scan_state.keep_alive_closure(), @@ -693,7 +721,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(), _generation.reserved().end(), _state_set); workers->run_task(&rp_task); - _state_set.reset(); + _state_set.reset(_generation.promotion_failed()); } void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) @@ -813,7 +841,7 @@ void ParNewGeneration::collect(bool full, GenCollectedHeap::StrongRootsScope srs(gch); tsk.work(0); } - thread_state_set.reset(); + thread_state_set.reset(promotion_failed()); if (PAR_STATS_ENABLED && ParallelGCVerbose) { gclog_or_tty->print("Thread totals:\n" @@ -882,6 +910,8 @@ void ParNewGeneration::collect(bool full, swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. from()->set_next_compaction_space(to()); gch->set_incremental_collection_will_fail(); + // Inform the next generation that a promotion failure occurred. + _next_gen->promotion_failure_occurred(); // Reset the PromotionFailureALot counters. NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) @@ -1029,6 +1059,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo( new_obj = old; preserve_mark_if_necessary(old, m); + // Log the size of the maiden promotion failure + par_scan_state->log_promotion_failure(sz); } old->forward_to(new_obj); @@ -1150,6 +1182,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo( failed_to_promote = true; preserve_mark_if_necessary(old, m); + // Log the size of the maiden promotion failure + par_scan_state->log_promotion_failure(sz); } } else { // Is in to-space; do copying ourselves. diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index 3e2ab80af2e..a8dee0bbca9 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -97,6 +97,9 @@ class ParScanThreadState { int _pushes, _pops, _steals, _steal_attempts, _term_attempts; int _overflow_pushes, _overflow_refills, _overflow_refill_objs; + // Stats for promotion failure + size_t _promotion_failure_size; + // Timing numbers. double _start; double _start_strong_roots; @@ -169,6 +172,15 @@ class ParScanThreadState { // Undo the most recent allocation ("obj", of "word_sz"). void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz); + // Promotion failure stats + size_t promotion_failure_size() { return promotion_failure_size(); } + void log_promotion_failure(size_t sz) { + if (_promotion_failure_size == 0) { + _promotion_failure_size = sz; + } + } + void print_and_clear_promotion_failure_size(); + int pushes() { return _pushes; } int pops() { return _pops; } int steals() { return _steals; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index 8396e7960b1..9fe57121f14 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -51,6 +51,8 @@ static void trace_gen_sizes(const char* const str, } jint ParallelScavengeHeap::initialize() { + CollectedHeap::pre_initialize(); + // Cannot be initialized until after the flags are parsed GenerationSizer flag_parser; @@ -717,10 +719,6 @@ HeapWord* ParallelScavengeHeap::allocate_new_tlab(size_t size) { return young_gen()->allocate(size, true); } -void ParallelScavengeHeap::fill_all_tlabs(bool retire) { - CollectedHeap::fill_all_tlabs(retire); -} - void ParallelScavengeHeap::accumulate_statistics_all_tlabs() { CollectedHeap::accumulate_statistics_all_tlabs(); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp index 3bf7671b29a..46fdcc53348 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp @@ -54,7 +54,6 @@ class ParallelScavengeHeap : public CollectedHeap { protected: static inline size_t total_invocations(); HeapWord* allocate_new_tlab(size_t size); - void fill_all_tlabs(bool retire); public: ParallelScavengeHeap() : CollectedHeap() { @@ -191,6 +190,10 @@ class ParallelScavengeHeap : public CollectedHeap { return true; } + virtual bool card_mark_must_follow_store() const { + return false; + } + // Return true if we don't we need a store barrier for // initializing stores to an object at this address. virtual bool can_elide_initializing_store_barrier(oop new_obj); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp index 02c6450a7a0..26345dbc924 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp @@ -51,7 +51,7 @@ PSGCAdaptivePolicyCounters::PSGCAdaptivePolicyCounters(const char* name_arg, cname = PerfDataManager::counter_name(name_space(), "oldCapacity"); _old_capacity = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, (jlong) Arguments::initial_heap_size(), CHECK); + PerfData::U_Bytes, (jlong) InitialHeapSize, CHECK); cname = PerfDataManager::counter_name(name_space(), "boundaryMoved"); _boundary_moved = PerfDataManager::create_variable(SUN_GC, cname, diff --git a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp index 4772f7c45bc..9358688a4c9 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp @@ -31,7 +31,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { // beginning of this sweep: // Count(end_last_sweep) - Count(start_this_sweep) // + splitBirths(between) - splitDeaths(between) - // The above number divided by the time since the start [END???] of the + // The above number divided by the time since the end of the // previous sweep gives us a time rate of demand for blocks // of this size. We compute a padded average of this rate as // our current estimate for the time rate of demand for blocks @@ -41,7 +41,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { // estimates. AdaptivePaddedAverage _demand_rate_estimate; - ssize_t _desired; // Estimate computed as described above + ssize_t _desired; // Demand stimate computed as described above ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing ssize_t _surplus; // count - (desired +/- small-percent), @@ -53,9 +53,9 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ssize_t _coalDeaths; // loss from coalescing ssize_t _splitBirths; // additional chunks from splitting ssize_t _splitDeaths; // loss from splitting - size_t _returnedBytes; // number of bytes returned to list. + size_t _returnedBytes; // number of bytes returned to list. public: - void initialize() { + void initialize(bool split_birth = false) { AdaptivePaddedAverage* dummy = new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight, CMS_FLSPadding); @@ -67,7 +67,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { _beforeSweep = 0; _coalBirths = 0; _coalDeaths = 0; - _splitBirths = 0; + _splitBirths = split_birth? 1 : 0; _splitDeaths = 0; _returnedBytes = 0; } @@ -75,10 +75,12 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { AllocationStats() { initialize(); } + // The rate estimate is in blocks per second. void compute_desired(size_t count, float inter_sweep_current, - float inter_sweep_estimate) { + float inter_sweep_estimate, + float intra_sweep_estimate) { // If the latest inter-sweep time is below our granularity // of measurement, we may call in here with // inter_sweep_current == 0. However, even for suitably small @@ -88,12 +90,31 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { // vulnerable to noisy glitches. In such cases, we // ignore the current sample and use currently available // historical estimates. + // XXX NEEDS TO BE FIXED + // assert(prevSweep() + splitBirths() >= splitDeaths() + (ssize_t)count, "Conservation Principle"); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // "Total Stock" "Not used at this block size" if (inter_sweep_current > _threshold) { - ssize_t demand = prevSweep() - count + splitBirths() - splitDeaths(); + ssize_t demand = prevSweep() - (ssize_t)count + splitBirths() - splitDeaths(); + // XXX NEEDS TO BE FIXED + // assert(demand >= 0, "Demand should be non-negative"); + // Defensive: adjust for imprecision in event counting + if (demand < 0) { + demand = 0; + } + float old_rate = _demand_rate_estimate.padded_average(); float rate = ((float)demand)/inter_sweep_current; _demand_rate_estimate.sample(rate); - _desired = (ssize_t)(_demand_rate_estimate.padded_average() - *inter_sweep_estimate); + float new_rate = _demand_rate_estimate.padded_average(); + ssize_t old_desired = _desired; + _desired = (ssize_t)(new_rate * (inter_sweep_estimate + + CMSExtrapolateSweep + ? intra_sweep_estimate + : 0.0)); + if (PrintFLSStatistics > 1) { + gclog_or_tty->print_cr("demand: %d, old_rate: %f, current_rate: %f, new_rate: %f, old_desired: %d, new_desired: %d", + demand, old_rate, rate, new_rate, old_desired, _desired); + } } } diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.cpp index 9ae5e4a0d29..e18782aac55 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.cpp @@ -52,11 +52,35 @@ void AdaptiveWeightedAverage::sample(float new_sample) { _last_sample = new_sample; } +void AdaptiveWeightedAverage::print() const { + print_on(tty); +} + +void AdaptiveWeightedAverage::print_on(outputStream* st) const { + guarantee(false, "NYI"); +} + +void AdaptivePaddedAverage::print() const { + print_on(tty); +} + +void AdaptivePaddedAverage::print_on(outputStream* st) const { + guarantee(false, "NYI"); +} + +void AdaptivePaddedNoZeroDevAverage::print() const { + print_on(tty); +} + +void AdaptivePaddedNoZeroDevAverage::print_on(outputStream* st) const { + guarantee(false, "NYI"); +} + void AdaptivePaddedAverage::sample(float new_sample) { - // Compute our parent classes sample information + // Compute new adaptive weighted average based on new sample. AdaptiveWeightedAverage::sample(new_sample); - // Now compute the deviation and the new padded sample + // Now update the deviation and the padded average. float new_avg = average(); float new_dev = compute_adaptive_average(fabsd(new_sample - new_avg), deviation()); diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp index affc3e44597..1bb4fc9f852 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp @@ -54,8 +54,8 @@ class AdaptiveWeightedAverage : public CHeapObj { public: // Input weight must be between 0 and 100 - AdaptiveWeightedAverage(unsigned weight) : - _average(0.0), _sample_count(0), _weight(weight), _last_sample(0.0) { + AdaptiveWeightedAverage(unsigned weight, float avg = 0.0) : + _average(avg), _sample_count(0), _weight(weight), _last_sample(0.0) { } void clear() { @@ -64,6 +64,13 @@ class AdaptiveWeightedAverage : public CHeapObj { _last_sample = 0; } + // Useful for modifying static structures after startup. + void modify(size_t avg, unsigned wt, bool force = false) { + assert(force, "Are you sure you want to call this?"); + _average = (float)avg; + _weight = wt; + } + // Accessors float average() const { return _average; } unsigned weight() const { return _weight; } @@ -83,6 +90,10 @@ class AdaptiveWeightedAverage : public CHeapObj { // Convert to float and back to avoid integer overflow. return (size_t)exp_avg((float)avg, (float)sample, weight); } + + // Printing + void print_on(outputStream* st) const; + void print() const; }; @@ -129,6 +140,10 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage { // Override void sample(float new_sample); + + // Printing + void print_on(outputStream* st) const; + void print() const; }; // A weighted average that includes a deviation from the average, @@ -146,7 +161,12 @@ public: AdaptivePaddedAverage(weight, padding) {} // Override void sample(float new_sample); + + // Printing + void print_on(outputStream* st) const; + void print() const; }; + // Use a least squares fit to a set of data to generate a linear // equation. // y = intercept + slope * x diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index c775e6021b1..031afd57572 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -59,8 +59,18 @@ CollectedHeap::CollectedHeap() PerfDataManager::create_string_variable(SUN_GC, "lastCause", 80, GCCause::to_string(_gc_lastcause), CHECK); } + _defer_initial_card_mark = false; // strengthened by subclass in pre_initialize() below. } +void CollectedHeap::pre_initialize() { + // Used for ReduceInitialCardMarks (when COMPILER2 is used); + // otherwise remains unused. +#ifdef COMPLER2 + _defer_initial_card_mark = ReduceInitialCardMarks && (DeferInitialCardMark || card_mark_must_follow_store()); +#else + assert(_defer_initial_card_mark == false, "Who would set it?"); +#endif +} #ifndef PRODUCT void CollectedHeap::check_for_bad_heap_word_value(HeapWord* addr, size_t size) { @@ -140,12 +150,13 @@ HeapWord* CollectedHeap::allocate_from_tlab_slow(Thread* thread, size_t size) { void CollectedHeap::flush_deferred_store_barrier(JavaThread* thread) { MemRegion deferred = thread->deferred_card_mark(); if (!deferred.is_empty()) { + assert(_defer_initial_card_mark, "Otherwise should be empty"); { // Verify that the storage points to a parsable object in heap DEBUG_ONLY(oop old_obj = oop(deferred.start());) assert(is_in(old_obj), "Not in allocated heap"); assert(!can_elide_initializing_store_barrier(old_obj), - "Else should have been filtered in defer_store_barrier()"); + "Else should have been filtered in new_store_pre_barrier()"); assert(!is_in_permanent(old_obj), "Sanity: not expected"); assert(old_obj->is_oop(true), "Not an oop"); assert(old_obj->is_parsable(), "Will not be concurrently parsable"); @@ -174,9 +185,7 @@ void CollectedHeap::flush_deferred_store_barrier(JavaThread* thread) { // so long as the card-mark is completed before the next // scavenge. For all these cases, we can do a card mark // at the point at which we do a slow path allocation -// in the old gen. For uniformity, however, we end -// up using the same scheme (see below) for all three -// cases (deferring the card-mark appropriately). +// in the old gen, i.e. in this call. // (b) GenCollectedHeap(ConcurrentMarkSweepGeneration) requires // in addition that the card-mark for an old gen allocated // object strictly follow any associated initializing stores. @@ -199,12 +208,13 @@ void CollectedHeap::flush_deferred_store_barrier(JavaThread* thread) { // but, like in CMS, because of the presence of concurrent refinement // (much like CMS' precleaning), must strictly follow the oop-store. // Thus, using the same protocol for maintaining the intended -// invariants turns out, serendepitously, to be the same for all -// three collectors/heap types above. +// invariants turns out, serendepitously, to be the same for both +// G1 and CMS. // -// For each future collector, this should be reexamined with -// that specific collector in mind. -oop CollectedHeap::defer_store_barrier(JavaThread* thread, oop new_obj) { +// For any future collector, this code should be reexamined with +// that specific collector in mind, and the documentation above suitably +// extended and updated. +oop CollectedHeap::new_store_pre_barrier(JavaThread* thread, oop new_obj) { // If a previous card-mark was deferred, flush it now. flush_deferred_store_barrier(thread); if (can_elide_initializing_store_barrier(new_obj)) { @@ -212,10 +222,17 @@ oop CollectedHeap::defer_store_barrier(JavaThread* thread, oop new_obj) { // following the flush above. assert(thread->deferred_card_mark().is_empty(), "Error"); } else { - // Remember info for the newly deferred store barrier - MemRegion deferred = MemRegion((HeapWord*)new_obj, new_obj->size()); - assert(!deferred.is_empty(), "Error"); - thread->set_deferred_card_mark(deferred); + MemRegion mr((HeapWord*)new_obj, new_obj->size()); + assert(!mr.is_empty(), "Error"); + if (_defer_initial_card_mark) { + // Defer the card mark + thread->set_deferred_card_mark(mr); + } else { + // Do the card mark + BarrierSet* bs = barrier_set(); + assert(bs->has_write_region_opt(), "No write_region() on BarrierSet"); + bs->write_region(mr); + } } return new_obj; } @@ -241,9 +258,9 @@ void CollectedHeap::fill_args_check(HeapWord* start, size_t words) assert(Universe::heap()->is_in_reserved(start + words - 1), "not in heap"); } -void CollectedHeap::zap_filler_array(HeapWord* start, size_t words) +void CollectedHeap::zap_filler_array(HeapWord* start, size_t words, bool zap) { - if (ZapFillerObjects) { + if (ZapFillerObjects && zap) { Copy::fill_to_words(start + filler_array_hdr_size(), words - filler_array_hdr_size(), 0XDEAFBABE); } @@ -251,7 +268,7 @@ void CollectedHeap::zap_filler_array(HeapWord* start, size_t words) #endif // ASSERT void -CollectedHeap::fill_with_array(HeapWord* start, size_t words) +CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap) { assert(words >= filler_array_min_size(), "too small for an array"); assert(words <= filler_array_max_size(), "too big for a single object"); @@ -262,31 +279,31 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words) // Set the length first for concurrent GC. ((arrayOop)start)->set_length((int)len); post_allocation_setup_common(Universe::intArrayKlassObj(), start, words); - DEBUG_ONLY(zap_filler_array(start, words);) + DEBUG_ONLY(zap_filler_array(start, words, zap);) } void -CollectedHeap::fill_with_object_impl(HeapWord* start, size_t words) +CollectedHeap::fill_with_object_impl(HeapWord* start, size_t words, bool zap) { assert(words <= filler_array_max_size(), "too big for a single object"); if (words >= filler_array_min_size()) { - fill_with_array(start, words); + fill_with_array(start, words, zap); } else if (words > 0) { assert(words == min_fill_size(), "unaligned size"); - post_allocation_setup_common(SystemDictionary::object_klass(), start, + post_allocation_setup_common(SystemDictionary::Object_klass(), start, words); } } -void CollectedHeap::fill_with_object(HeapWord* start, size_t words) +void CollectedHeap::fill_with_object(HeapWord* start, size_t words, bool zap) { DEBUG_ONLY(fill_args_check(start, words);) HandleMark hm; // Free handles before leaving. - fill_with_object_impl(start, words); + fill_with_object_impl(start, words, zap); } -void CollectedHeap::fill_with_objects(HeapWord* start, size_t words) +void CollectedHeap::fill_with_objects(HeapWord* start, size_t words, bool zap) { DEBUG_ONLY(fill_args_check(start, words);) HandleMark hm; // Free handles before leaving. @@ -299,13 +316,13 @@ void CollectedHeap::fill_with_objects(HeapWord* start, size_t words) const size_t max = filler_array_max_size(); while (words > max) { const size_t cur = words - max >= min ? max : max - min; - fill_with_array(start, cur); + fill_with_array(start, cur, zap); start += cur; words -= cur; } #endif - fill_with_object_impl(start, words); + fill_with_object_impl(start, words, zap); } HeapWord* CollectedHeap::allocate_new_tlab(size_t size) { @@ -313,22 +330,6 @@ HeapWord* CollectedHeap::allocate_new_tlab(size_t size) { return NULL; } -void CollectedHeap::fill_all_tlabs(bool retire) { - assert(UseTLAB, "should not reach here"); - // See note in ensure_parsability() below. - assert(SafepointSynchronize::is_at_safepoint() || - !is_init_completed(), - "should only fill tlabs at safepoint"); - // The main thread starts allocating via a TLAB even before it - // has added itself to the threads list at vm boot-up. - assert(Threads::first() != NULL, - "Attempt to fill tlabs before main thread has been added" - " to threads list is doomed to failure!"); - for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { - thread->tlab().make_parsable(retire); - } -} - void CollectedHeap::ensure_parsability(bool retire_tlabs) { // The second disjunct in the assertion below makes a concession // for the start-up verification done while the VM is being @@ -343,8 +344,24 @@ void CollectedHeap::ensure_parsability(bool retire_tlabs) { "Should only be called at a safepoint or at start-up" " otherwise concurrent mutator activity may make heap " " unparsable again"); - if (UseTLAB) { - fill_all_tlabs(retire_tlabs); + const bool use_tlab = UseTLAB; + const bool deferred = _defer_initial_card_mark; + // The main thread starts allocating via a TLAB even before it + // has added itself to the threads list at vm boot-up. + assert(!use_tlab || Threads::first() != NULL, + "Attempt to fill tlabs before main thread has been added" + " to threads list is doomed to failure!"); + for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) { + if (use_tlab) thread->tlab().make_parsable(retire_tlabs); +#ifdef COMPILER2 + // The deferred store barriers must all have been flushed to the + // card-table (or other remembered set structure) before GC starts + // processing the card-table (or other remembered set). + if (deferred) flush_deferred_store_barrier(thread); +#else + assert(!deferred, "Should be false"); + assert(thread->deferred_card_mark().is_empty(), "Should be empty"); +#endif } } diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index 18148c8a30f..2bc210a4717 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -51,6 +51,9 @@ class CollectedHeap : public CHeapObj { // Used for filler objects (static, but initialized in ctor). static size_t _filler_array_max_size; + // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used + bool _defer_initial_card_mark; + protected: MemRegion _reserved; BarrierSet* _barrier_set; @@ -70,13 +73,16 @@ class CollectedHeap : public CHeapObj { // Constructor CollectedHeap(); + // Do common initializations that must follow instance construction, + // for example, those needing virtual calls. + // This code could perhaps be moved into initialize() but would + // be slightly more awkward because we want the latter to be a + // pure virtual. + void pre_initialize(); + // Create a new tlab virtual HeapWord* allocate_new_tlab(size_t size); - // Fix up tlabs to make the heap well-formed again, - // optionally retiring the tlabs. - virtual void fill_all_tlabs(bool retire); - // Accumulate statistics on all tlabs. virtual void accumulate_statistics_all_tlabs(); @@ -127,14 +133,14 @@ class CollectedHeap : public CHeapObj { static inline size_t filler_array_max_size(); DEBUG_ONLY(static void fill_args_check(HeapWord* start, size_t words);) - DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words);) + DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words, bool zap = true);) // Fill with a single array; caller must ensure filler_array_min_size() <= // words <= filler_array_max_size(). - static inline void fill_with_array(HeapWord* start, size_t words); + static inline void fill_with_array(HeapWord* start, size_t words, bool zap = true); // Fill with a single object (either an int array or a java.lang.Object). - static inline void fill_with_object_impl(HeapWord* start, size_t words); + static inline void fill_with_object_impl(HeapWord* start, size_t words, bool zap = true); // Verification functions virtual void check_for_bad_heap_word_value(HeapWord* addr, size_t size) @@ -338,14 +344,14 @@ class CollectedHeap : public CHeapObj { return size_t(align_object_size(oopDesc::header_size())); } - static void fill_with_objects(HeapWord* start, size_t words); + static void fill_with_objects(HeapWord* start, size_t words, bool zap = true); - static void fill_with_object(HeapWord* start, size_t words); - static void fill_with_object(MemRegion region) { - fill_with_object(region.start(), region.word_size()); + static void fill_with_object(HeapWord* start, size_t words, bool zap = true); + static void fill_with_object(MemRegion region, bool zap = true) { + fill_with_object(region.start(), region.word_size(), zap); } - static void fill_with_object(HeapWord* start, HeapWord* end) { - fill_with_object(start, pointer_delta(end, start)); + static void fill_with_object(HeapWord* start, HeapWord* end, bool zap = true) { + fill_with_object(start, pointer_delta(end, start), zap); } // Some heaps may offer a contiguous region for shared non-blocking @@ -431,14 +437,25 @@ class CollectedHeap : public CHeapObj { // promises to call this function on such a slow-path-allocated // object before performing initializations that have elided // store barriers. Returns new_obj, or maybe a safer copy thereof. - virtual oop defer_store_barrier(JavaThread* thread, oop new_obj); + virtual oop new_store_pre_barrier(JavaThread* thread, oop new_obj); // Answers whether an initializing store to a new object currently - // allocated at the given address doesn't need a (deferred) store + // allocated at the given address doesn't need a store // barrier. Returns "true" if it doesn't need an initializing // store barrier; answers "false" if it does. virtual bool can_elide_initializing_store_barrier(oop new_obj) = 0; + // If a compiler is eliding store barriers for TLAB-allocated objects, + // we will be informed of a slow-path allocation by a call + // to new_store_pre_barrier() above. Such a call precedes the + // initialization of the object itself, and no post-store-barriers will + // be issued. Some heap types require that the barrier strictly follows + // the initializing stores. (This is currently implemented by deferring the + // barrier until the next slow-path allocation or gc-related safepoint.) + // This interface answers whether a particular heap type needs the card + // mark to be thus strictly sequenced after the stores. + virtual bool card_mark_must_follow_store() const = 0; + // If the CollectedHeap was asked to defer a store barrier above, // this informs it to flush such a deferred store barrier to the // remembered set. diff --git a/hotspot/src/share/vm/includeDB_compiler2 b/hotspot/src/share/vm/includeDB_compiler2 index 6ba7bfaf867..34c84d72200 100644 --- a/hotspot/src/share/vm/includeDB_compiler2 +++ b/hotspot/src/share/vm/includeDB_compiler2 @@ -149,11 +149,15 @@ c2compiler.cpp runtime.hpp c2compiler.hpp abstractCompiler.hpp callGenerator.cpp addnode.hpp +callGenerator.cpp bcEscapeAnalyzer.hpp callGenerator.cpp callGenerator.hpp callGenerator.cpp callnode.hpp callGenerator.cpp cfgnode.hpp callGenerator.cpp compileLog.hpp callGenerator.cpp connode.hpp +callGenerator.cpp ciCPCache.hpp +callGenerator.cpp ciMethodHandle.hpp +callGenerator.cpp javaClasses.hpp callGenerator.cpp parse.hpp callGenerator.cpp rootnode.hpp callGenerator.cpp runtime.hpp @@ -321,6 +325,7 @@ compile.cpp phaseX.hpp compile.cpp rootnode.hpp compile.cpp runtime.hpp compile.cpp signature.hpp +compile.cpp stringopts.hpp compile.cpp stubRoutines.hpp compile.cpp systemDictionary.hpp compile.cpp timer.hpp @@ -389,6 +394,9 @@ divnode.hpp type.hpp doCall.cpp addnode.hpp doCall.cpp callGenerator.hpp +doCall.cpp ciCallSite.hpp +doCall.cpp ciCPCache.hpp +doCall.cpp ciMethodHandle.hpp doCall.cpp cfgnode.hpp doCall.cpp compileLog.hpp doCall.cpp linkResolver.hpp @@ -476,12 +484,16 @@ graphKit.cpp rootnode.hpp graphKit.cpp runtime.hpp graphKit.cpp sharedRuntime.hpp +graphKit.hpp addnode.hpp graphKit.hpp callnode.hpp graphKit.hpp cfgnode.hpp graphKit.hpp ciEnv.hpp +graphKit.hpp divnode.hpp graphKit.hpp compile.hpp graphKit.hpp deoptimization.hpp graphKit.hpp phaseX.hpp +graphKit.hpp mulnode.hpp +graphKit.hpp subnode.hpp graphKit.hpp type.hpp idealKit.cpp addnode.hpp @@ -490,7 +502,10 @@ idealKit.cpp cfgnode.hpp idealKit.cpp idealKit.hpp idealKit.cpp runtime.hpp +idealKit.hpp addnode.hpp +idealKit.hpp cfgnode.hpp idealKit.hpp connode.hpp +idealKit.hpp divnode.hpp idealKit.hpp mulnode.hpp idealKit.hpp phaseX.hpp idealKit.hpp subnode.hpp @@ -586,6 +601,7 @@ locknode.hpp subnode.hpp loopTransform.cpp addnode.hpp loopTransform.cpp allocation.inline.hpp +loopTransform.cpp callnode.hpp loopTransform.cpp connode.hpp loopTransform.cpp compileLog.hpp loopTransform.cpp divnode.hpp @@ -641,6 +657,7 @@ macro.cpp addnode.hpp macro.cpp callnode.hpp macro.cpp cfgnode.hpp macro.cpp compile.hpp +macro.cpp compileLog.hpp macro.cpp connode.hpp macro.cpp locknode.hpp macro.cpp loopnode.hpp @@ -993,6 +1010,21 @@ split_if.cpp callnode.hpp split_if.cpp connode.hpp split_if.cpp loopnode.hpp +stringopts.hpp phaseX.hpp +stringopts.hpp node.hpp + +stringopts.cpp addnode.hpp +stringopts.cpp callnode.hpp +stringopts.cpp callGenerator.hpp +stringopts.cpp compileLog.hpp +stringopts.cpp divnode.hpp +stringopts.cpp idealKit.hpp +stringopts.cpp graphKit.hpp +stringopts.cpp rootnode.hpp +stringopts.cpp runtime.hpp +stringopts.cpp subnode.hpp +stringopts.cpp stringopts.hpp + stubGenerator_.cpp runtime.hpp stubRoutines.cpp runtime.hpp diff --git a/hotspot/src/share/vm/includeDB_core b/hotspot/src/share/vm/includeDB_core index e96a5e9be1a..ec068b6aeeb 100644 --- a/hotspot/src/share/vm/includeDB_core +++ b/hotspot/src/share/vm/includeDB_core @@ -1,5 +1,5 @@ // -// Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -289,7 +289,7 @@ attachListener.hpp allocation.hpp attachListener.hpp debug.hpp attachListener.hpp ostream.hpp -barrierSet.cpp barrierSet.hpp +barrierSet.cpp barrierSet.inline.hpp barrierSet.cpp collectedHeap.hpp barrierSet.cpp universe.hpp @@ -516,6 +516,11 @@ ciArrayKlassKlass.hpp ciKlassKlass.hpp ciCallProfile.hpp ciClassList.hpp +ciCallSite.cpp ciCallSite.hpp +ciCallSite.cpp ciUtilities.hpp + +ciCallSite.hpp ciInstance.hpp + ciConstant.cpp allocation.hpp ciConstant.cpp allocation.inline.hpp ciConstant.cpp ciConstant.hpp @@ -532,6 +537,12 @@ ciConstantPoolCache.cpp ciUtilities.hpp ciConstantPoolCache.hpp growableArray.hpp ciConstantPoolCache.hpp resourceArea.hpp +ciCPCache.cpp cpCacheOop.hpp +ciCPCache.cpp ciCPCache.hpp + +ciCPCache.hpp ciClassList.hpp +ciCPCache.hpp ciObject.hpp + ciEnv.cpp allocation.inline.hpp ciEnv.cpp ciConstant.hpp ciEnv.cpp ciEnv.hpp @@ -570,6 +581,7 @@ ciEnv.hpp debugInfoRec.hpp ciEnv.hpp dependencies.hpp ciEnv.hpp exceptionHandlerTable.hpp ciEnv.hpp oopMap.hpp +ciEnv.hpp systemDictionary.hpp ciEnv.hpp thread.hpp ciExceptionHandler.cpp ciExceptionHandler.hpp @@ -592,6 +604,7 @@ ciField.cpp universe.inline.hpp ciField.hpp ciClassList.hpp ciField.hpp ciConstant.hpp ciField.hpp ciFlags.hpp +ciField.hpp ciInstance.hpp ciFlags.cpp ciFlags.hpp @@ -678,6 +691,7 @@ ciMethod.hpp ciFlags.hpp ciMethod.hpp ciInstanceKlass.hpp ciMethod.hpp ciObject.hpp ciMethod.hpp ciSignature.hpp +ciMethod.hpp methodHandles.hpp ciMethod.hpp methodLiveness.hpp ciMethodBlocks.cpp bytecode.hpp @@ -709,6 +723,15 @@ ciMethodKlass.cpp ciUtilities.hpp ciMethodKlass.hpp ciKlass.hpp ciMethodKlass.hpp ciSymbol.hpp +ciMethodHandle.cpp ciClassList.hpp +ciMethodHandle.cpp ciInstance.hpp +ciMethodHandle.cpp ciMethodHandle.hpp +ciMethodHandle.cpp ciUtilities.hpp +ciMethodHandle.cpp methodHandles.hpp +ciMethodHandle.cpp methodHandleWalk.hpp + +ciMethodHandle.hpp methodHandles.hpp + ciNullObject.cpp ciNullObject.hpp ciNullObject.hpp ciClassList.hpp @@ -754,11 +777,14 @@ ciObject.hpp handles.hpp ciObject.hpp jniHandles.hpp ciObjectFactory.cpp allocation.inline.hpp +ciObjectFactory.cpp ciCallSite.hpp +ciObjectFactory.cpp ciCPCache.hpp ciObjectFactory.cpp ciInstance.hpp ciObjectFactory.cpp ciInstanceKlass.hpp ciObjectFactory.cpp ciInstanceKlassKlass.hpp ciObjectFactory.cpp ciMethod.hpp ciObjectFactory.cpp ciMethodData.hpp +ciObjectFactory.cpp ciMethodHandle.hpp ciObjectFactory.cpp ciMethodKlass.hpp ciObjectFactory.cpp ciNullObject.hpp ciObjectFactory.cpp ciObjArray.hpp @@ -792,6 +818,7 @@ ciSignature.hpp ciSymbol.hpp ciSignature.hpp globalDefinitions.hpp ciSignature.hpp growableArray.hpp +ciStreams.cpp ciCallSite.hpp ciStreams.cpp ciConstant.hpp ciStreams.cpp ciField.hpp ciStreams.cpp ciStreams.hpp @@ -1291,6 +1318,7 @@ cpCacheOop.cpp jvmtiRedefineClassesTrace.hpp cpCacheOop.cpp markSweep.inline.hpp cpCacheOop.cpp objArrayOop.hpp cpCacheOop.cpp oop.inline.hpp +cpCacheOop.cpp rewriter.hpp cpCacheOop.cpp universe.inline.hpp cpCacheOop.hpp allocation.hpp @@ -1497,6 +1525,7 @@ disassembler.cpp disassembler.hpp disassembler.cpp fprofiler.hpp disassembler.cpp handles.inline.hpp disassembler.cpp hpi.hpp +disassembler.cpp javaClasses.hpp disassembler.cpp stubCodeGenerator.hpp disassembler.cpp stubRoutines.hpp @@ -2812,6 +2841,12 @@ methodDataOop.hpp oop.hpp methodDataOop.hpp orderAccess.hpp methodDataOop.hpp universe.hpp +methodHandleWalk.hpp methodHandles.hpp + +methodHandleWalk.cpp methodHandleWalk.hpp +methodHandleWalk.cpp oopFactory.hpp +methodHandleWalk.cpp rewriter.hpp + methodHandles.hpp frame.inline.hpp methodHandles.hpp globals.hpp methodHandles.hpp interfaceSupport.hpp @@ -3469,6 +3504,7 @@ reflection.cpp javaCalls.hpp reflection.cpp javaClasses.hpp reflection.cpp jvm.h reflection.cpp linkResolver.hpp +reflection.cpp methodHandleWalk.hpp reflection.cpp objArrayKlass.hpp reflection.cpp objArrayOop.hpp reflection.cpp oopFactory.hpp diff --git a/hotspot/src/share/vm/includeDB_gc_parallel b/hotspot/src/share/vm/includeDB_gc_parallel index 5f089b7d7f1..2d1c45a0c9b 100644 --- a/hotspot/src/share/vm/includeDB_gc_parallel +++ b/hotspot/src/share/vm/includeDB_gc_parallel @@ -21,6 +21,8 @@ // have any questions. // +arguments.cpp compactibleFreeListSpace.hpp + assembler_.cpp g1SATBCardTableModRefBS.hpp assembler_.cpp g1CollectedHeap.inline.hpp assembler_.cpp heapRegion.hpp diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 78323ee2aee..8ab9e40d32b 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,8 @@ class AbstractInterpreter: AllStatic { static void print_method_kind(MethodKind kind) PRODUCT_RETURN; + static bool can_be_compiled(methodHandle m); + // Runtime support // length = invoke bytecode length (to advance to next bytecode) diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp index 0cc8a728950..4e8d9053615 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.cpp +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp @@ -102,7 +102,9 @@ methodHandle Bytecode_invoke::static_target(TRAPS) { KlassHandle resolved_klass; constantPoolHandle constants(THREAD, _method->constants()); - if (adjusted_invoke_code() != Bytecodes::_invokeinterface) { + if (adjusted_invoke_code() == Bytecodes::_invokedynamic) { + LinkResolver::resolve_dynamic_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); + } else if (adjusted_invoke_code() != Bytecodes::_invokeinterface) { LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); } else { LinkResolver::resolve_interface_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp index 49e70e8c1f3..7069081028f 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.hpp +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp @@ -205,12 +205,14 @@ class Bytecode_invoke: public ResourceObj { bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; } bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; } + bool has_receiver() const { return !is_invokestatic() && !is_invokedynamic(); } bool has_giant_index() const { return is_invokedynamic(); } bool is_valid() const { return is_invokeinterface() || is_invokevirtual() || is_invokestatic() || - is_invokespecial(); } + is_invokespecial() || + is_invokedynamic(); } // Creation inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index ac46f4ab5e1..1f0adb487ed 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -281,7 +281,7 @@ #define DO_BACKEDGE_CHECKS(skip, branch_pc) \ if ((skip) <= 0) { \ - if (UseCompiler && UseLoopCounter) { \ + if (UseLoopCounter) { \ bool do_OSR = UseOnStackReplacement; \ BACKEDGE_COUNT->increment(); \ if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit(); \ @@ -289,16 +289,12 @@ nmethod* osr_nmethod; \ OSR_REQUEST(osr_nmethod, branch_pc); \ if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \ - intptr_t* buf; \ - CALL_VM(buf=SharedRuntime::OSR_migration_begin(THREAD), handle_exception); \ + intptr_t* buf = SharedRuntime::OSR_migration_begin(THREAD); \ istate->set_msg(do_osr); \ istate->set_osr_buf((address)buf); \ istate->set_osr_entry(osr_nmethod->osr_entry()); \ return; \ } \ - } else { \ - INCR_INVOCATION_COUNT; \ - SAFEPOINT; \ } \ } /* UseCompiler ... */ \ INCR_INVOCATION_COUNT; \ @@ -1281,12 +1277,7 @@ run: jfloat f; jdouble r; f = STACK_FLOAT(-1); -#ifdef IA64 - // IA64 gcc bug - r = ( f == 0.0f ) ? (jdouble) f : (jdouble) f + ia64_double_zero; -#else r = (jdouble) f; -#endif MORE_STACK(-1); // POP SET_STACK_DOUBLE(r, 1); UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2); diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index 79cee762daa..c7a874ac4df 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -270,6 +270,8 @@ void BytecodePrinter::print_constant(int i, outputStream* st) { st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name()); } else if (tag.is_unresolved_klass()) { st->print_cr(" ", i); + } else if (tag.is_object()) { + st->print_cr(" " PTR_FORMAT, constants->object_at(i)); } else { st->print_cr(" bad tag=%d at %d", tag.value(), i); } @@ -282,18 +284,21 @@ void BytecodePrinter::print_field_or_method(int i, outputStream* st) { constantPoolOop constants = method()->constants(); constantTag tag = constants->tag_at(i); + int nt_index = -1; + switch (tag.value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_Fieldref: + case JVM_CONSTANT_NameAndType: break; default: st->print_cr(" bad tag=%d at %d", tag.value(), i); return; } - symbolOop name = constants->name_ref_at(orig_i); - symbolOop signature = constants->signature_ref_at(orig_i); + symbolOop name = constants->uncached_name_ref_at(i); + symbolOop signature = constants->uncached_signature_ref_at(i); st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string()); } diff --git a/hotspot/src/share/vm/interpreter/bytecodes.cpp b/hotspot/src/share/vm/interpreter/bytecodes.cpp index e55c9ff3851..cb2a7ecb234 100644 --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp @@ -357,7 +357,7 @@ void Bytecodes::initialize() { def(_invokespecial , "invokespecial" , "bjj" , NULL , T_ILLEGAL, -1, true); def(_invokestatic , "invokestatic" , "bjj" , NULL , T_ILLEGAL, 0, true); def(_invokeinterface , "invokeinterface" , "bjj__", NULL , T_ILLEGAL, -1, true); - def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, -1, true ); + def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, 0, true ); def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true ); def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true ); def(_anewarray , "anewarray" , "bii" , NULL , T_OBJECT , 0, true ); diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index b4f1007bc6c..484a47f7d42 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -314,6 +314,20 @@ address AbstractInterpreter::deopt_continue_after_entry(methodOop method, addres break; } + case Bytecodes::_invokedynamic: { + Thread *thread = Thread::current(); + ResourceMark rm(thread); + methodHandle mh(thread, method); + type = Bytecode_invoke_at(mh, bci)->result_type(thread); + // since the cache entry might not be initialized: + // (NOT needed for the old calling convension) + if (!is_top_frame) { + int index = Bytes::get_native_u4(bcp+1); + method->constants()->cache()->secondary_entry_at(index)->set_parameter_size(callee_parameters); + } + break; + } + case Bytecodes::_ldc : type = constant_pool_type( method, *(bcp+1) ); break; diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index c8e19944de7..bd9fc8d7c98 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -353,7 +353,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea assert(h_exception.not_null(), "NULL exceptions should be handled by athrow"); assert(h_exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError - if (!(h_exception->is_a(SystemDictionary::throwable_klass()))) { + if (!(h_exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); ShouldNotReachHere(); } @@ -585,7 +585,7 @@ IRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThre Handle exception(thread, thread->vm_result()); assert(exception() != NULL, "vm result should be set"); thread->set_vm_result(NULL); // clear vm result before continuing (may cause memory leaks and assert failures) - if (!exception->is_a(SystemDictionary::threaddeath_klass())) { + if (!exception->is_a(SystemDictionary::ThreadDeath_klass())) { exception = get_preinitialized_exception( SystemDictionary::IllegalMonitorStateException_klass(), CATCH); @@ -660,7 +660,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string()); } if (info.resolved_method()->method_holder() == - SystemDictionary::object_klass()) { + SystemDictionary::Object_klass()) { // NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec // (see also cpCacheOop.cpp for details) methodHandle rm = info.resolved_method(); @@ -681,7 +681,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes IRT_END -// First time execution: Resolve symbols, create a permanent CallSiteImpl object. +// First time execution: Resolve symbols, create a permanent CallSite object. IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { ResourceMark rm(thread); @@ -708,21 +708,16 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { constantPoolHandle pool(thread, caller_method->constants()); pool->set_invokedynamic(); // mark header to flag active call sites - int raw_index = four_byte_index(thread); - assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "invokedynamic indexes marked specially"); - - // there are two CPC entries that are of interest: - int site_index = constantPoolCacheOopDesc::decode_secondary_index(raw_index); - int main_index = pool->cache()->entry_at(site_index)->main_entry_index(); - // and there is one CP entry, a NameAndType: - int nt_index = pool->map_instruction_operand_to_index(raw_index); + int site_index = four_byte_index(thread); + // there is a second CPC entries that is of interest; it caches signature info: + int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index(); // first resolve the signature to a MH.invoke methodOop if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) { JvmtiHideSingleStepping jhss(thread); CallInfo info; LinkResolver::resolve_invoke(info, Handle(), pool, - raw_index, bytecode, CHECK); + site_index, bytecode, CHECK); // The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves // as a common reference point for all invokedynamic call sites with // that exact call descriptor. We will link it in the CP cache exactly @@ -741,7 +736,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { assert(mh_invdyn.not_null() && mh_invdyn->is_method() && mh_invdyn->is_method_handle_invoke(), "correct result from LinkResolver::resolve_invokedynamic"); - symbolHandle call_site_name(THREAD, pool->nt_name_ref_at(nt_index)); + symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index)); Handle call_site = SystemDictionary::make_dynamic_call_site(caller_method->method_holder(), caller_method->method_idnum(), @@ -753,61 +748,11 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { // In the secondary entry, the f1 field is the call site, and the f2 (index) // field is some data about the invoke site. int extra_data = 0; - pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), extra_data); + pool->cache()->secondary_entry_at(site_index)->set_dynamic_call(call_site(), extra_data); } IRT_END -// Called on first time execution, and also whenever the CallSite.target is null. -// FIXME: Do more of this in Java code. -IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) { - methodHandle mh_invdyn(thread, (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site)); - Handle mh_type(thread, mh_invdyn->method_handle_type()); - objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type())); - - // squish the arguments down to a single array - int nargs = mh_ptypes->length(); - objArrayHandle arg_array; - { - objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK); - arg_array = objArrayHandle(thread, aaoop); - } - frame fr = thread->last_frame(); - assert(fr.interpreter_frame_bcp() != NULL, "sanity"); - int tos_offset = 0; - for (int i = nargs; --i >= 0; ) { - intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++); - oop ptype = mh_ptypes->obj_at(i); - oop arg = NULL; - if (!java_lang_Class::is_primitive(ptype)) { - arg = *(oop*) slot_addr; - } else { - BasicType bt = java_lang_Class::primitive_type(ptype); - assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code"); - jvalue value; - Interpreter::get_jvalue_in_slot(slot_addr, bt, &value); - tos_offset += type2size[bt]-1; - arg = java_lang_boxing_object::create(bt, &value, CHECK); - // FIXME: These boxing objects are not canonicalized under - // the Java autoboxing rules. They should be... - // The best approach would be to push the arglist creation into Java. - // The JVM should use a lower-level interface to communicate argument lists. - } - arg_array->obj_at_put(i, arg); - } - - // now find the bootstrap method - oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method(); - assert(bootstrap_mh_oop != NULL, "resolve_invokedynamic ensures a BSM"); - - // return the bootstrap method and argument array via vm_result/_2 - thread->set_vm_result(bootstrap_mh_oop); - thread->set_vm_result_2(arg_array()); -} -IRT_END - - - //------------------------------------------------------------------------------------------------------------------------ // Miscellaneous @@ -1305,7 +1250,7 @@ IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* threa methodHandle mh(thread, fr.interpreter_frame_method()); Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci); ArgumentSizeComputer asc(invoke->signature()); - int size_of_arguments = (asc.size() + (invoke->is_invokestatic() ? 0 : 1)); // receiver + int size_of_arguments = (asc.size() + (invoke->has_receiver() ? 1 : 0)); // receiver Copy::conjoint_bytes(src_address, dest_address, size_of_arguments * Interpreter::stackElementSize()); IRT_END diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp index 76b9e9c2191..b0a616308e4 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp @@ -91,7 +91,6 @@ class InterpreterRuntime: AllStatic { // Calls static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode); static void resolve_invokedynamic(JavaThread* thread); - static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site); // Breakpoints static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp); diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index c9a2c13c5b1..4c5fd690393 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -55,7 +55,7 @@ void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_kl // we should pick the vtable index from the resolved method. // Other than that case, there is no valid vtable index to specify. int vtable_index = methodOopDesc::invalid_vtable_index; - if (resolved_method->method_holder() == SystemDictionary::object_klass()) { + if (resolved_method->method_holder() == SystemDictionary::Object_klass()) { assert(resolved_method->vtable_index() == selected_method->vtable_index(), "sanity check"); vtable_index = resolved_method->vtable_index(); } @@ -75,6 +75,8 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass _selected_method = selected_method; _vtable_index = vtable_index; if (CompilationPolicy::mustBeCompiled(selected_method)) { + // This path is unusual, mostly used by the '-Xcomp' stress test mode. + // Note: with several active threads, the mustBeCompiled may be true // while canBeCompiled is false; remove assert // assert(CompilationPolicy::canBeCompiled(selected_method), "cannot compile"); @@ -82,6 +84,16 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass // don't force compilation, resolve was on behalf of compiler return; } + if (instanceKlass::cast(selected_method->method_holder())->is_not_initialized()) { + // 'is_not_initialized' means not only '!is_initialized', but also that + // initialization has not been started yet ('!being_initialized') + // Do not force compilation of methods in uninitialized classes. + // Note that doing this would throw an assert later, + // in CompileBroker::compile_method. + // We sometimes use the link resolver to do reflective lookups + // even before classes are initialized. + return; + } CompileBroker::compile_method(selected_method, InvocationEntryBci, methodHandle(), 0, "mustBeCompiled", CHECK); } @@ -181,7 +193,7 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass, // We'll check for the method name first, as that's most likely // to be false (so we'll short-circuit out of these tests). if (sel_method->name() == vmSymbols::clone_name() && - sel_klass() == SystemDictionary::object_klass() && + sel_klass() == SystemDictionary::Object_klass() && resolved_klass->oop_is_array()) { // We need to change "protected" to "public". assert(flags.is_protected(), "clone not protected?"); @@ -223,6 +235,18 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle& re resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); } +void LinkResolver::resolve_dynamic_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { + // The class is java.dyn.MethodHandle + resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); + + symbolHandle method_name = vmSymbolHandles::invoke_name(); + + symbolHandle method_signature(THREAD, pool->signature_ref_at(index)); + KlassHandle current_klass (THREAD, pool->pool_holder()); + + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); +} + void LinkResolver::resolve_interface_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { // resolve klass @@ -1015,11 +1039,8 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po // This guy is reached from InterpreterRuntime::resolve_invokedynamic. - assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "must be secondary index"); - int nt_index = pool->map_instruction_operand_to_index(raw_index); - // At this point, we only need the signature, and can ignore the name. - symbolHandle method_signature(THREAD, pool->nt_signature_ref_at(nt_index)); + symbolHandle method_signature(THREAD, pool->signature_ref_at(raw_index)); // raw_index works directly symbolHandle method_name = vmSymbolHandles::invoke_name(); KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index a95873b4c90..efc1b53f5f3 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -133,6 +133,7 @@ class LinkResolver: AllStatic { // static resolving for all calls except interface calls static void resolve_method (methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS); + static void resolve_dynamic_method (methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS); static void resolve_interface_method(methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS); // runtime/static resolving for fields diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index c70c0c0356f..8ff99109349 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -48,16 +48,6 @@ void Rewriter::compute_index_maps() { } -int Rewriter::add_extra_cp_cache_entry(int main_entry) { - // Hack: We put it on the map as an encoded value. - // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state - int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry); - int plain_secondary_index = _cp_cache_map.append(encoded); - return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index); -} - - - // Creates a constant pool cache given a CPC map // This creates the constant pool cache initially in a state // that is unsafe for concurrent GC processing but sets it to @@ -127,7 +117,7 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, int delete_me) { assert(p[-1] == Bytecodes::_invokedynamic, ""); int cp_index = Bytes::get_Java_u2(p); int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily - int cpc2 = add_extra_cp_cache_entry(cpc); + int cpc2 = add_secondary_cp_cache_entry(cpc); // Replace the trailing four bytes with a CPC index for the dynamic // call site. Unlike other CPC entries, there is one per bytecode, @@ -137,7 +127,7 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, int delete_me) { // all these entries. That is the main reason invokedynamic // must have a five-byte instruction format. (Of course, other JVM // implementations can use the bytes for other purposes.) - Bytes::put_native_u4(p, cpc2); + Bytes::put_native_u4(p, constantPoolCacheOopDesc::encode_secondary_index(cpc2)); // Note: We use native_u4 format exclusively for 4-byte indexes. } @@ -257,15 +247,22 @@ methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) { void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { ResourceMark rm(THREAD); - Rewriter rw(klass, CHECK); + Rewriter rw(klass, klass->constants(), klass->methods(), CHECK); // (That's all, folks.) } -Rewriter::Rewriter(instanceKlassHandle klass, TRAPS) + +void Rewriter::rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS) { + ResourceMark rm(THREAD); + Rewriter rw(klass, cpool, methods, CHECK); + // (That's all, folks.) +} + + +Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS) : _klass(klass), - // gather starting points - _pool( THREAD, klass->constants()), - _methods(THREAD, klass->methods()) + _pool(cpool), + _methods(methods) { assert(_pool->cache() == NULL, "constant pool cache must not be set yet"); diff --git a/hotspot/src/share/vm/interpreter/rewriter.hpp b/hotspot/src/share/vm/interpreter/rewriter.hpp index 2546b57ef37..39325e743aa 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.hpp +++ b/hotspot/src/share/vm/interpreter/rewriter.hpp @@ -43,16 +43,21 @@ class Rewriter: public StackObj { bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; } int maybe_add_cp_cache_entry(int i) { return has_cp_cache(i) ? _cp_map[i] : add_cp_cache_entry(i); } int add_cp_cache_entry(int cp_index) { + assert((cp_index & _secondary_entry_tag) == 0, "bad tag"); assert(_cp_map[cp_index] == -1, "not twice on same cp_index"); int cache_index = _cp_cache_map.append(cp_index); _cp_map.at_put(cp_index, cache_index); assert(cp_entry_to_cp_cache(cp_index) == cache_index, ""); return cache_index; } - int add_extra_cp_cache_entry(int main_entry); + int add_secondary_cp_cache_entry(int main_cpc_entry) { + assert(main_cpc_entry < _cp_cache_map.length(), "must be earlier CP cache entry"); + int cache_index = _cp_cache_map.append(main_cpc_entry | _secondary_entry_tag); + return cache_index; + } // All the work goes in here: - Rewriter(instanceKlassHandle klass, TRAPS); + Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS); void compute_index_maps(); void make_constant_pool_cache(TRAPS); @@ -65,4 +70,9 @@ class Rewriter: public StackObj { public: // Driver routine: static void rewrite(instanceKlassHandle klass, TRAPS); + static void rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS); + + enum { + _secondary_entry_tag = nth_bit(30) + }; }; diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 9f12f44e3a5..e617623506b 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -178,14 +178,12 @@ EntryPoint TemplateInterpreter::_trace_code; #endif // !PRODUCT EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries]; EntryPoint TemplateInterpreter::_earlyret_entry; -EntryPoint TemplateInterpreter::_return_unbox_entry; EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ]; EntryPoint TemplateInterpreter::_continuation_entry; EntryPoint TemplateInterpreter::_safept_entry; address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; -address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; DispatchTable TemplateInterpreter::_active_table; DispatchTable TemplateInterpreter::_normal_table; @@ -253,22 +251,6 @@ void TemplateInterpreterGenerator::generate_all() { } } - if (EnableInvokeDynamic) { - CodeletMark cm(_masm, "unboxing return entry points"); - Interpreter::_return_unbox_entry = - EntryPoint( - generate_return_unbox_entry_for(btos, 5), - generate_return_unbox_entry_for(ctos, 5), - generate_return_unbox_entry_for(stos, 5), - generate_return_unbox_entry_for(atos, 5), // cast conversion - generate_return_unbox_entry_for(itos, 5), - generate_return_unbox_entry_for(ltos, 5), - generate_return_unbox_entry_for(ftos, 5), - generate_return_unbox_entry_for(dtos, 5), - Interpreter::_return_entry[5].entry(vtos) // no unboxing for void - ); - } - { CodeletMark cm(_masm, "earlyret entry points"); Interpreter::_earlyret_entry = EntryPoint( @@ -319,8 +301,6 @@ void TemplateInterpreterGenerator::generate_all() { int index = Interpreter::TosState_as_index(states[j]); Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3); Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5); - if (EnableInvokeDynamic) - Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5); } { CodeletMark cm(_masm, "continuation entry points"); @@ -485,9 +465,11 @@ void TemplateInterpreterGenerator::set_wide_entry_point(Template* t, address& we void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) { assert(t->is_valid(), "template must exist"); switch (t->tos_in()) { - case btos: vep = __ pc(); __ pop(btos); bep = __ pc(); generate_and_dispatch(t); break; - case ctos: vep = __ pc(); __ pop(ctos); sep = __ pc(); generate_and_dispatch(t); break; - case stos: vep = __ pc(); __ pop(stos); sep = __ pc(); generate_and_dispatch(t); break; + case btos: + case ctos: + case stos: + ShouldNotReachHere(); // btos/ctos/stos should use itos. + break; case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break; case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break; case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break; @@ -547,18 +529,6 @@ address TemplateInterpreter::return_entry(TosState state, int length) { } -address TemplateInterpreter::return_unbox_entry(TosState state, int length) { - assert(EnableInvokeDynamic, ""); - if (state == vtos) { - // no unboxing to do, actually - return return_entry(state, length); - } else { - assert(length == 5, "unboxing entries generated for invokedynamic only"); - return _return_unbox_entry.entry(state); - } -} - - address TemplateInterpreter::deopt_entry(TosState state, int length) { guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length"); return _deopt_entry[length].entry(state); diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp index 7de665b882f..b3eed1c3a4e 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp @@ -110,14 +110,12 @@ class TemplateInterpreter: public AbstractInterpreter { #endif // !PRODUCT static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call static EntryPoint _earlyret_entry; // entry point to return early from a call - static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization static EntryPoint _continuation_entry; static EntryPoint _safept_entry; static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries - static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch) static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode) @@ -159,12 +157,10 @@ class TemplateInterpreter: public AbstractInterpreter { // Support for invokes static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; } static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; } - static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; } static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table static address return_entry (TosState state, int length); static address deopt_entry (TosState state, int length); - static address return_unbox_entry(TosState state, int length); // Safepoint support static void notice_safepoints(); // stops the thread when reaching a safepoint diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp index 9d5b694049e..676e762725d 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp @@ -51,10 +51,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { address generate_WrongMethodType_handler(); address generate_ArrayIndexOutOfBounds_handler(const char* name); address generate_continuation_for(TosState state); - address generate_return_entry_for(TosState state, int step, bool unbox = false); - address generate_return_unbox_entry_for(TosState state, int step) { - return generate_return_entry_for(state, step, true); - } + address generate_return_entry_for(TosState state, int step); address generate_earlyret_entry_for(TosState state); address generate_deopt_entry_for(TosState state, int step); address generate_safept_entry_for(TosState state, address runtime_entry); diff --git a/hotspot/src/share/vm/memory/barrierSet.cpp b/hotspot/src/share/vm/memory/barrierSet.cpp index 07ff7a0fc21..8cd80b7c437 100644 --- a/hotspot/src/share/vm/memory/barrierSet.cpp +++ b/hotspot/src/share/vm/memory/barrierSet.cpp @@ -41,11 +41,6 @@ void BarrierSet::static_write_ref_array_pre(HeapWord* start, size_t count) { // count is number of array elements being written void BarrierSet::static_write_ref_array_post(HeapWord* start, size_t count) { - assert(count <= (size_t)max_intx, "count too large"); - HeapWord* end = start + objArrayOopDesc::array_size((int)count); -#if 0 - warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t", - start, count, start, end); -#endif - Universe::heap()->barrier_set()->write_ref_array_work(MemRegion(start, end)); + // simply delegate to instance method + Universe::heap()->barrier_set()->write_ref_array(start, count); } diff --git a/hotspot/src/share/vm/memory/barrierSet.hpp b/hotspot/src/share/vm/memory/barrierSet.hpp index 0fc6a006140..c624f2506e2 100644 --- a/hotspot/src/share/vm/memory/barrierSet.hpp +++ b/hotspot/src/share/vm/memory/barrierSet.hpp @@ -121,17 +121,20 @@ public: virtual void read_ref_array(MemRegion mr) = 0; virtual void read_prim_array(MemRegion mr) = 0; + // Below length is the # array elements being written virtual void write_ref_array_pre( oop* dst, int length) {} virtual void write_ref_array_pre(narrowOop* dst, int length) {} + // Below MemRegion mr is expected to be HeapWord-aligned inline void write_ref_array(MemRegion mr); + // Below count is the # array elements being written, starting + // at the address "start", which may not necessarily be HeapWord-aligned + inline void write_ref_array(HeapWord* start, size_t count); - // Static versions, suitable for calling from generated code. + // Static versions, suitable for calling from generated code; + // count is # array elements being written, starting with "start", + // which may not necessarily be HeapWord-aligned. static void static_write_ref_array_pre(HeapWord* start, size_t count); static void static_write_ref_array_post(HeapWord* start, size_t count); - // Narrow oop versions of the above; count is # of array elements being written, - // starting with "start", which is HeapWord-aligned. - static void static_write_ref_array_pre_narrow(HeapWord* start, size_t count); - static void static_write_ref_array_post_narrow(HeapWord* start, size_t count); protected: virtual void write_ref_array_work(MemRegion mr) = 0; diff --git a/hotspot/src/share/vm/memory/barrierSet.inline.hpp b/hotspot/src/share/vm/memory/barrierSet.inline.hpp index edcb551bdcd..ddc398348ca 100644 --- a/hotspot/src/share/vm/memory/barrierSet.inline.hpp +++ b/hotspot/src/share/vm/memory/barrierSet.inline.hpp @@ -43,6 +43,8 @@ void BarrierSet::write_ref_field(void* field, oop new_val) { } void BarrierSet::write_ref_array(MemRegion mr) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start() , "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); if (kind() == CardTableModRef) { ((CardTableModRefBS*)this)->inline_write_ref_array(mr); } else { @@ -50,6 +52,34 @@ void BarrierSet::write_ref_array(MemRegion mr) { } } +// count is number of array elements being written +void BarrierSet::write_ref_array(HeapWord* start, size_t count) { + assert(count <= (size_t)max_intx, "count too large"); + HeapWord* end = (HeapWord*)((char*)start + (count*heapOopSize)); + // In the case of compressed oops, start and end may potentially be misaligned; + // so we need to conservatively align the first downward (this is not + // strictly necessary for current uses, but a case of good hygiene and, + // if you will, aesthetics) and the second upward (this is essential for + // current uses) to a HeapWord boundary, so we mark all cards overlapping + // this write. In the event that this evolves in the future to calling a + // logging barrier of narrow oop granularity, like the pre-barrier for G1 + // (mentioned here merely by way of example), we will need to change this + // interface, much like the pre-barrier one above, so it is "exactly precise" + // (if i may be allowed the adverbial redundancy for emphasis) and does not + // include narrow oop slots not included in the original write interval. + HeapWord* aligned_start = (HeapWord*)align_size_down((uintptr_t)start, HeapWordSize); + HeapWord* aligned_end = (HeapWord*)align_size_up ((uintptr_t)end, HeapWordSize); + // If compressed oops were not being used, these should already be aligned + assert(UseCompressedOops || (aligned_start == start && aligned_end == end), + "Expected heap word alignment of start and end"); +#if 0 + warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t", + start, count, aligned_start, aligned_end); +#endif + write_ref_array_work(MemRegion(aligned_start, aligned_end)); +} + + void BarrierSet::write_region(MemRegion mr) { if (kind() == CardTableModRef) { ((CardTableModRefBS*)this)->inline_write_region(mr); diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp index c036a355514..2deb7da83f0 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp @@ -511,6 +511,8 @@ void CardTableModRefBS::mod_oop_in_space_iterate(Space* sp, } void CardTableModRefBS::dirty_MemRegion(MemRegion mr) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); jbyte* cur = byte_for(mr.start()); jbyte* last = byte_after(mr.last()); while (cur < last) { @@ -520,6 +522,8 @@ void CardTableModRefBS::dirty_MemRegion(MemRegion mr) { } void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); for (int i = 0; i < _cur_covered_regions; i++) { MemRegion mri = mr.intersection(_covered[i]); if (!mri.is_empty()) dirty_MemRegion(mri); diff --git a/hotspot/src/share/vm/memory/classify.cpp b/hotspot/src/share/vm/memory/classify.cpp index 0cb6a572cb3..bc4fecd74ff 100644 --- a/hotspot/src/share/vm/memory/classify.cpp +++ b/hotspot/src/share/vm/memory/classify.cpp @@ -49,7 +49,7 @@ object_type ClassifyObjectClosure::classify_object(oop obj, bool count) { Klass* k = obj->blueprint(); - if (k->as_klassOop() == SystemDictionary::object_klass()) { + if (k->as_klassOop() == SystemDictionary::Object_klass()) { tty->print_cr("Found the class!"); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index 3f885d9ecba..ebb886fbad8 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -55,7 +55,7 @@ void CollectorPolicy::initialize_flags() { void CollectorPolicy::initialize_size_info() { // User inputs from -mx and ms are aligned - set_initial_heap_byte_size(Arguments::initial_heap_size()); + set_initial_heap_byte_size(InitialHeapSize); if (initial_heap_byte_size() == 0) { set_initial_heap_byte_size(NewSize + OldSize); } diff --git a/hotspot/src/share/vm/memory/defNewGeneration.cpp b/hotspot/src/share/vm/memory/defNewGeneration.cpp index 7db8b9dea97..875cf00817b 100644 --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp @@ -609,7 +609,7 @@ void DefNewGeneration::collect(bool full, remove_forwarding_pointers(); if (PrintGCDetails) { - gclog_or_tty->print(" (promotion failed)"); + gclog_or_tty->print(" (promotion failed) "); } // Add to-space to the list of space to compact // when a promotion failure has occurred. In that @@ -620,6 +620,9 @@ void DefNewGeneration::collect(bool full, from()->set_next_compaction_space(to()); gch->set_incremental_collection_will_fail(); + // Inform the next generation that a promotion failure occurred. + _next_gen->promotion_failure_occurred(); + // Reset the PromotionFailureALot counters. NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) } @@ -679,6 +682,11 @@ void DefNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) { void DefNewGeneration::handle_promotion_failure(oop old) { preserve_mark_if_necessary(old, old->mark()); + if (!_promotion_failed && PrintPromotionFailure) { + gclog_or_tty->print(" (promotion failure size = " SIZE_FORMAT ") ", + old->size()); + } + // forward to self old->forward_to(old); _promotion_failed = true; diff --git a/hotspot/src/share/vm/memory/dump.cpp b/hotspot/src/share/vm/memory/dump.cpp index 658e8347665..09ab997de10 100644 --- a/hotspot/src/share/vm/memory/dump.cpp +++ b/hotspot/src/share/vm/memory/dump.cpp @@ -63,7 +63,7 @@ public: void do_oop(oop* p) { if (p != NULL) { oop obj = *p; - if (obj->klass() == SystemDictionary::string_klass()) { + if (obj->klass() == SystemDictionary::String_klass()) { int hash; typeArrayOop value = java_lang_String::value(obj); @@ -625,11 +625,11 @@ public: if (obj->is_klass() || obj->is_instance()) { if (obj->is_klass() || - obj->is_a(SystemDictionary::class_klass()) || - obj->is_a(SystemDictionary::throwable_klass())) { + obj->is_a(SystemDictionary::Class_klass()) || + obj->is_a(SystemDictionary::Throwable_klass())) { // Do nothing } - else if (obj->is_a(SystemDictionary::string_klass())) { + else if (obj->is_a(SystemDictionary::String_klass())) { // immutable objects. } else { // someone added an object we hadn't accounted for. diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 5bff1597062..f85fe142156 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -51,6 +51,8 @@ GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : } jint GenCollectedHeap::initialize() { + CollectedHeap::pre_initialize(); + int i; _n_gens = gen_policy()->number_of_generations(); @@ -129,6 +131,7 @@ jint GenCollectedHeap::initialize() { _rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions); set_barrier_set(rem_set()->bs()); + _gch = this; for (i = 0; i < _n_gens; i++) { @@ -925,6 +928,8 @@ bool GenCollectedHeap::is_in(const void* p) const { guarantee(VerifyBeforeGC || VerifyDuringGC || VerifyBeforeExit || + PrintAssembly || + tty->count() != 0 || // already printing VerifyAfterGC, "too expensive"); #endif // This might be sped up with a cache of the last generation that diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index 9004e0d842c..8295d078bfa 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -260,6 +260,10 @@ public: return true; } + virtual bool card_mark_must_follow_store() const { + return UseConcMarkSweepGC; + } + // We don't need barriers for stores to objects in the // young gen and, a fortiori, for initializing stores to // objects therein. This applies to {DefNew,ParNew}+{Tenured,CMS} diff --git a/hotspot/src/share/vm/memory/generation.hpp b/hotspot/src/share/vm/memory/generation.hpp index 985e9db1028..e39be059506 100644 --- a/hotspot/src/share/vm/memory/generation.hpp +++ b/hotspot/src/share/vm/memory/generation.hpp @@ -181,6 +181,12 @@ class Generation: public CHeapObj { virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes, bool younger_handles_promotion_failure) const; + // For a non-young generation, this interface can be used to inform a + // generation that a promotion attempt into that generation failed. + // Typically used to enable diagnostic output for post-mortem analysis, + // but other uses of the interface are not ruled out. + virtual void promotion_failure_occurred() { /* does nothing */ } + // Return an estimate of the maximum allocation that could be performed // in the generation without triggering any collection or expansion // activity. It is "unsafe" because no locks are taken; the result diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index 4f638fda468..2d355ca6800 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -464,7 +464,7 @@ void CodeHeap::verify() { } // Verify that freelist contains the right amount of free space - guarantee(len == _free_segments, "wrong freelist"); + // guarantee(len == _free_segments, "wrong freelist"); // Verify that the number of free blocks is not out of hand. static int free_block_threshold = 10000; @@ -479,5 +479,5 @@ void CodeHeap::verify() { for(HeapBlock *h = first_block(); h != NULL; h = next_block(h)) { if (h->free()) count--; } - guarantee(count == 0, "missing free blocks"); + // guarantee(count == 0, "missing free blocks"); } diff --git a/hotspot/src/share/vm/memory/referenceProcessor.cpp b/hotspot/src/share/vm/memory/referenceProcessor.cpp index 134181c45db..ac1b53c30b6 100644 --- a/hotspot/src/share/vm/memory/referenceProcessor.cpp +++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp @@ -71,7 +71,7 @@ void ReferenceProcessor::init_statics() { assert(_sentinelRef == NULL, "should be initialized precisely once"); EXCEPTION_MARK; _sentinelRef = instanceKlass::cast( - SystemDictionary::reference_klass())-> + SystemDictionary::Reference_klass())-> allocate_permanent_instance(THREAD); // Initialize the master soft ref clock. @@ -299,8 +299,8 @@ void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive, template -static bool enqueue_discovered_ref_helper(ReferenceProcessor* ref, - AbstractRefProcTaskExecutor* task_executor) { +bool enqueue_discovered_ref_helper(ReferenceProcessor* ref, + AbstractRefProcTaskExecutor* task_executor) { // Remember old value of pending references list T* pending_list_addr = (T*)java_lang_ref_Reference::pending_list_addr(); diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index 0bf863fb133..6094387241b 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -224,10 +224,6 @@ public: CodeBlobClosure* code_roots, OopClosure* non_root_closure); - - // Like CollectedHeap::collect, but assume that the caller holds the Heap_lock. - virtual void collect_locked(GCCause::Cause cause) = 0; - // The functions below are helper functions that a subclass of // "SharedHeap" can use in the implementation of its virtual // functions. diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 53c3c2600e1..38e58ba6886 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -876,7 +876,7 @@ void ContiguousSpace::allocate_temporary_filler(int factor) { instanceOop obj = (instanceOop) allocate(size); obj->set_mark(markOopDesc::prototype()); obj->set_klass_gap(0); - obj->set_klass(SystemDictionary::object_klass()); + obj->set_klass(SystemDictionary::Object_klass()); } } diff --git a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp index be7538604ff..5aa36245cde 100644 --- a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp @@ -100,7 +100,7 @@ void ThreadLocalAllocBuffer::accumulate_statistics() { void ThreadLocalAllocBuffer::make_parsable(bool retire) { if (end() != NULL) { invariants(); - CollectedHeap::fill_with_object(top(), hard_end()); + CollectedHeap::fill_with_object(top(), hard_end(), retire); if (retire || ZeroTLAB) { // "Reset" the TLAB set_start(NULL); diff --git a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.inline.hpp b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.inline.hpp index 68b2d92a1e3..361ae3aecb1 100644 --- a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.inline.hpp +++ b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.inline.hpp @@ -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 @@ -27,8 +27,13 @@ inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) { HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { // successful thread-local allocation - - DEBUG_ONLY(Copy::fill_to_words(obj, size, badHeapWordVal)); +#ifdef ASSERT + // Skip mangling the space corresponding to the object header to + // ensure that the returned space is not considered parsable by + // any concurrent GC thread. + size_t hdr_size = CollectedHeap::min_fill_size(); + Copy::fill_to_words(obj + hdr_size, size - hdr_size, badHeapWordVal); +#endif // ASSERT // This addition is safe because we know that top is // at least size below end, so the add can't wrap. set_top(obj + size); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 5043f9e2599..5803a4d356e 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -67,6 +67,8 @@ typeArrayOop Universe::_the_empty_int_array = NULL; objArrayOop Universe::_the_empty_system_obj_array = NULL; objArrayOop Universe::_the_empty_class_klass_array = NULL; objArrayOop Universe::_the_array_interfaces_array = NULL; +oop Universe::_the_null_string = NULL; +oop Universe::_the_min_jint_string = NULL; LatestMethodOopCache* Universe::_finalizer_register_cache = NULL; LatestMethodOopCache* Universe::_loader_addClass_cache = NULL; ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL; @@ -187,6 +189,8 @@ void Universe::oops_do(OopClosure* f, bool do_all) { f->do_oop((oop*)&_the_empty_system_obj_array); f->do_oop((oop*)&_the_empty_class_klass_array); f->do_oop((oop*)&_the_array_interfaces_array); + f->do_oop((oop*)&_the_null_string); + f->do_oop((oop*)&_the_min_jint_string); _finalizer_register_cache->oops_do(f); _loader_addClass_cache->oops_do(f); _reflect_invoke_cache->oops_do(f); @@ -287,14 +291,17 @@ void Universe::genesis(TRAPS) { SystemDictionary::initialize(CHECK); - klassOop ok = SystemDictionary::object_klass(); + klassOop ok = SystemDictionary::Object_klass(); + + _the_null_string = StringTable::intern("null", CHECK); + _the_min_jint_string = StringTable::intern("-2147483648", CHECK); if (UseSharedSpaces) { // Verify shared interfaces array. assert(_the_array_interfaces_array->obj_at(0) == - SystemDictionary::cloneable_klass(), "u3"); + SystemDictionary::Cloneable_klass(), "u3"); assert(_the_array_interfaces_array->obj_at(1) == - SystemDictionary::serializable_klass(), "u3"); + SystemDictionary::Serializable_klass(), "u3"); // Verify element klass for system obj array klass assert(objArrayKlass::cast(_systemObjArrayKlassObj)->element_klass() == ok, "u1"); @@ -313,8 +320,8 @@ void Universe::genesis(TRAPS) { assert(Klass::cast(systemObjArrayKlassObj())->super() == ok, "u3"); } else { // Set up shared interfaces array. (Do this before supers are set up.) - _the_array_interfaces_array->obj_at_put(0, SystemDictionary::cloneable_klass()); - _the_array_interfaces_array->obj_at_put(1, SystemDictionary::serializable_klass()); + _the_array_interfaces_array->obj_at_put(0, SystemDictionary::Cloneable_klass()); + _the_array_interfaces_array->obj_at_put(1, SystemDictionary::Serializable_klass()); // Set element klass for system obj array klass objArrayKlass::cast(_systemObjArrayKlassObj)->set_element_klass(ok); @@ -358,7 +365,7 @@ void Universe::genesis(TRAPS) { // Initialize _objectArrayKlass after core bootstraping to make // sure the super class is set up properly for _objectArrayKlass. _objectArrayKlassObj = instanceKlass:: - cast(SystemDictionary::object_klass())->array_klass(1, CHECK); + cast(SystemDictionary::Object_klass())->array_klass(1, CHECK); // Add the class to the class hierarchy manually to make sure that // its vtable is initialized after core bootstrapping is completed. Klass::cast(_objectArrayKlassObj)->append_to_sibling_list(); @@ -419,11 +426,11 @@ void Universe::genesis(TRAPS) { while (i < size) { if (!UseConcMarkSweepGC) { // Allocate dummy in old generation - oop dummy = instanceKlass::cast(SystemDictionary::object_klass())->allocate_instance(CHECK); + oop dummy = instanceKlass::cast(SystemDictionary::Object_klass())->allocate_instance(CHECK); dummy_array->obj_at_put(i++, dummy); } // Allocate dummy in permanent generation - oop dummy = instanceKlass::cast(SystemDictionary::object_klass())->allocate_permanent_instance(CHECK); + oop dummy = instanceKlass::cast(SystemDictionary::Object_klass())->allocate_permanent_instance(CHECK); dummy_array->obj_at_put(i++, dummy); } { @@ -533,7 +540,7 @@ void Universe::fixup_mirrors(TRAPS) { // but we cannot do that for classes created before java.lang.Class is loaded. Here we simply // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note // that the number of objects allocated at this point is very small. - assert(SystemDictionary::class_klass_loaded(), "java.lang.Class should be loaded"); + assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded"); FixupMirrorClosure blk; Universe::heap()->permanent_object_iterate(&blk); } @@ -549,7 +556,7 @@ void Universe::run_finalizers_on_exit() { if (TraceReferenceGC) tty->print_cr("Callback to run finalizers on exit"); { PRESERVE_EXCEPTION_MARK; - KlassHandle finalizer_klass(THREAD, SystemDictionary::finalizer_klass()); + KlassHandle finalizer_klass(THREAD, SystemDictionary::Finalizer_klass()); JavaValue result(T_VOID); JavaCalls::call_static( &result, @@ -744,22 +751,22 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1); static const uint64_t OopEncodingHeapMax = NarrowOopHeapMax << LogMinObjAlignmentInBytes; char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { + size_t base = 0; #ifdef _LP64 if (UseCompressedOops) { assert(mode == UnscaledNarrowOop || mode == ZeroBasedNarrowOop || mode == HeapBasedNarrowOop, "mode is invalid"); + const size_t total_size = heap_size + HeapBaseMinAddress; // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { - return (char*)HeapBaseMinAddress; - } - const size_t total_size = heap_size + HeapBaseMinAddress; - if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { + base = HeapBaseMinAddress; + } else 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); + base = (NarrowOopHeapMax - heap_size); } else { // Can't reserve with NarrowOopShift == 0 Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); @@ -768,16 +775,38 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { // 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); + base = (OopEncodingHeapMax - heap_size); } } } else { // Can't reserve below 32Gb. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } + // Set narrow_oop_base and narrow_oop_use_implicit_null_checks + // used in ReservedHeapSpace() constructors. + // The final values will be set in initialize_heap() below. + if (base != 0 && (base + heap_size) <= OopEncodingHeapMax) { + // Use zero based compressed oops + Universe::set_narrow_oop_base(NULL); + // 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); + } else { + // Set to a non-NULL value so the ReservedSpace ctor computes + // the correct no-access prefix. + // The final value will be set in initialize_heap() below. + Universe::set_narrow_oop_base((address)NarrowOopHeapMax); +#ifdef _WIN64 + if (UseLargePages) { + // Cannot allocate guard pages for implicit checks in indexed + // addressing mode when large pages are specified on windows. + Universe::set_narrow_oop_use_implicit_null_checks(false); + } +#endif // _WIN64 + } } #endif - return NULL; // also return NULL (don't care) for 32-bit VM + return (char*)base; // also return NULL (don't care) for 32-bit VM } jint Universe::initialize_heap() { @@ -921,7 +950,7 @@ bool universe_post_init() { { ResourceMark rm; Interpreter::initialize(); // needed for interpreter entry points if (!UseSharedSpaces) { - KlassHandle ok_h(THREAD, SystemDictionary::object_klass()); + KlassHandle ok_h(THREAD, SystemDictionary::Object_klass()); Universe::reinitialize_vtable_of(ok_h, CHECK_false); Universe::reinitialize_itables(CHECK_false); } @@ -931,7 +960,7 @@ bool universe_post_init() { instanceKlassHandle k_h; if (!UseSharedSpaces) { // Setup preallocated empty java.lang.Class array - Universe::_the_empty_class_klass_array = oopFactory::new_objArray(SystemDictionary::class_klass(), 0, CHECK_false); + Universe::_the_empty_class_klass_array = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_false); // Setup preallocated OutOfMemoryError errors k = SystemDictionary::resolve_or_fail(vmSymbolHandles::java_lang_OutOfMemoryError(), true, CHECK_false); k_h = instanceKlassHandle(THREAD, k); @@ -998,8 +1027,8 @@ bool universe_post_init() { // Setup static method for registering finalizers // The finalizer klass must be linked before looking up the method, in // case it needs to get rewritten. - instanceKlass::cast(SystemDictionary::finalizer_klass())->link_class(CHECK_false); - methodOop m = instanceKlass::cast(SystemDictionary::finalizer_klass())->find_method( + instanceKlass::cast(SystemDictionary::Finalizer_klass())->link_class(CHECK_false); + methodOop m = instanceKlass::cast(SystemDictionary::Finalizer_klass())->find_method( vmSymbols::register_method_name(), vmSymbols::register_method_signature()); if (m == NULL || !m->is_static()) { @@ -1007,7 +1036,7 @@ bool universe_post_init() { "java.lang.ref.Finalizer.register", false); } Universe::_finalizer_register_cache->init( - SystemDictionary::finalizer_klass(), m, CHECK_false); + SystemDictionary::Finalizer_klass(), m, CHECK_false); // Resolve on first use and initialize class. // Note: No race-condition here, since a resolve will always return the same result @@ -1024,14 +1053,14 @@ bool universe_post_init() { Universe::_reflect_invoke_cache->init(k_h(), m, CHECK_false); // Setup method for registering loaded classes in class loader vector - instanceKlass::cast(SystemDictionary::classloader_klass())->link_class(CHECK_false); - m = instanceKlass::cast(SystemDictionary::classloader_klass())->find_method(vmSymbols::addClass_name(), vmSymbols::class_void_signature()); + instanceKlass::cast(SystemDictionary::ClassLoader_klass())->link_class(CHECK_false); + m = instanceKlass::cast(SystemDictionary::ClassLoader_klass())->find_method(vmSymbols::addClass_name(), vmSymbols::class_void_signature()); if (m == NULL || m->is_static()) { THROW_MSG_(vmSymbols::java_lang_NoSuchMethodException(), "java.lang.ClassLoader.addClass", false); } Universe::_loader_addClass_cache->init( - SystemDictionary::classloader_klass(), m, CHECK_false); + SystemDictionary::ClassLoader_klass(), m, CHECK_false); // The folowing is initializing converter functions for serialization in // JVM.cpp. If we clean up the StrictMath code above we may want to find diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index b22a1eba6c9..97044e161d4 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -169,6 +169,8 @@ class Universe: AllStatic { static objArrayOop _the_empty_system_obj_array; // Canonicalized system obj array static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class static objArrayOop _the_array_interfaces_array; // Canonicalized 2-array of cloneable & serializable klasses + static oop _the_null_string; // A cache of "null" as a Java string + static oop _the_min_jint_string; // A cache of "-2147483648" as a Java string static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks @@ -310,6 +312,8 @@ class Universe: AllStatic { static objArrayOop the_empty_system_obj_array () { return _the_empty_system_obj_array; } static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; } static objArrayOop the_array_interfaces_array() { return _the_array_interfaces_array; } + static oop the_null_string() { return _the_null_string; } + static oop the_min_jint_string() { return _the_min_jint_string; } static methodOop finalizer_register_method() { return _finalizer_register_cache->get_methodOop(); } static methodOop loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); } static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; } diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index 7ff6d2f2f57..ac50c258663 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -43,7 +43,7 @@ klassOop arrayKlass::java_super() const { if (super() == NULL) return NULL; // bootstrap case // Array klasses have primary supertypes which are not reported to Java. // Example super chain: String[][] -> Object[][] -> Object[] -> Object - return SystemDictionary::object_klass(); + return SystemDictionary::Object_klass(); } @@ -82,7 +82,7 @@ const Klass_vtbl& cplusplus_vtbl, int header_size, KlassHandle klass, TRAPS) { k = arrayKlassHandle(THREAD, base_klass()); assert(!k()->is_parsable(), "not expecting parsability yet."); - k->set_super(Universe::is_bootstrapping() ? (klassOop)NULL : SystemDictionary::object_klass()); + k->set_super(Universe::is_bootstrapping() ? (klassOop)NULL : SystemDictionary::Object_klass()); k->set_layout_helper(Klass::_lh_neutral_value); k->set_dimension(1); k->set_higher_dimension(NULL); @@ -117,9 +117,9 @@ objArrayOop arrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) { bool arrayKlass::compute_is_subtype_of(klassOop k) { // An array is a subtype of Serializable, Clonable, and Object - return k == SystemDictionary::object_klass() - || k == SystemDictionary::cloneable_klass() - || k == SystemDictionary::serializable_klass(); + return k == SystemDictionary::Object_klass() + || k == SystemDictionary::Cloneable_klass() + || k == SystemDictionary::Serializable_klass(); } diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index b2bc0862c73..40280501b8d 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -67,7 +67,7 @@ class arrayKlass: public Klass { // Compiler/Interpreter offset static ByteSize component_mirror_offset() { return byte_offset_of(arrayKlass, _component_mirror); } - virtual klassOop java_super() const;//{ return SystemDictionary::object_klass(); } + virtual klassOop java_super() const;//{ return SystemDictionary::Object_klass(); } // Allocation // Sizes points to the first dimension of the array, subsequent dimensions diff --git a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp index 1757aae8a1f..918a7dd9bee 100644 --- a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp @@ -159,7 +159,7 @@ void arrayKlassKlass::oop_print_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); klassKlass::oop_print_on(obj, st); } - +#endif //PRODUCT void arrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); @@ -168,7 +168,6 @@ void arrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("[]"); } } -#endif const char* arrayKlassKlass::internal_name() const { diff --git a/hotspot/src/share/vm/oops/arrayKlassKlass.hpp b/hotspot/src/share/vm/oops/arrayKlassKlass.hpp index 1d98d21745a..75a2becd1c9 100644 --- a/hotspot/src/share/vm/oops/arrayKlassKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlassKlass.hpp @@ -55,14 +55,13 @@ class arrayKlassKlass : public klassKlass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT public: // Printing - void oop_print_on(oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on(oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp index 434205d3ed3..cbca7fbe202 100644 --- a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp +++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp @@ -166,12 +166,12 @@ void compiledICHolderKlass::oop_print_on(oop obj, outputStream* st) { st->print(" - klass: "); c->holder_klass()->print_value_on(st); st->cr(); } +#endif //PRODUCT void compiledICHolderKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_compiledICHolder(), "must be compiledICHolder"); Klass::oop_print_value_on(obj, st); } -#endif const char* compiledICHolderKlass::internal_name() const { return "{compiledICHolder}"; diff --git a/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp b/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp index 3d704773945..93f187faee6 100644 --- a/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp +++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp @@ -68,14 +68,13 @@ class compiledICHolderKlass : public Klass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/constMethodKlass.cpp b/hotspot/src/share/vm/oops/constMethodKlass.cpp index c1ad90c1d57..ca48fe3eb2b 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.cpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.cpp @@ -216,6 +216,7 @@ void constMethodKlass::oop_print_on(oop obj, outputStream* st) { } } +#endif //PRODUCT // Short version of printing constMethodOop - just print the name of the // method it belongs to. @@ -226,8 +227,6 @@ void constMethodKlass::oop_print_value_on(oop obj, outputStream* st) { m->method()->print_value_on(st); } -#endif // PRODUCT - const char* constMethodKlass::internal_name() const { return "{constMethod}"; } diff --git a/hotspot/src/share/vm/oops/constMethodKlass.hpp b/hotspot/src/share/vm/oops/constMethodKlass.hpp index 2387d0210a6..69eebb74444 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.hpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.hpp @@ -77,15 +77,13 @@ public: int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT -#endif - - public: // Verify operations const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/constMethodOop.hpp b/hotspot/src/share/vm/oops/constMethodOop.hpp index c6d373946e1..91d01167246 100644 --- a/hotspot/src/share/vm/oops/constMethodOop.hpp +++ b/hotspot/src/share/vm/oops/constMethodOop.hpp @@ -258,6 +258,11 @@ public: LocalVariableTableElement* localvariable_table_start() const; // byte codes + void set_code(address code) { + if (code_size() > 0) { + memcpy(code_base(), code, code_size()); + } + } address code_base() const { return (address) (this+1); } address code_end() const { return code_base() + code_size(); } bool contains(address bcp) const { return code_base() <= bcp diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp index 44b16435f31..f46963fd305 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp @@ -387,9 +387,19 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) { cp->set_cache(cache()); } - #endif +void constantPoolKlass::oop_print_value_on(oop obj, outputStream* st) { + assert(obj->is_constantPool(), "must be constantPool"); + constantPoolOop cp = constantPoolOop(obj); + st->print("constant pool [%d]", cp->length()); + if (cp->has_pseudo_string()) st->print("/pseudo_string"); + if (cp->has_invokedynamic()) st->print("/invokedynamic"); + cp->print_address_on(st); + st->print(" for "); + cp->pool_holder()->print_value_on(st); +} + const char* constantPoolKlass::internal_name() const { return "{constant pool}"; } diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.hpp b/hotspot/src/share/vm/oops/constantPoolKlass.hpp index a01edbab42c..47a80d2b20e 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.hpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.hpp @@ -65,9 +65,10 @@ class constantPoolKlass : public Klass { juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } -#ifndef PRODUCT public: // Printing + void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); #endif diff --git a/hotspot/src/share/vm/oops/constantPoolOop.cpp b/hotspot/src/share/vm/oops/constantPoolOop.cpp index af72333b0b0..a324b7ae6aa 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp @@ -110,7 +110,7 @@ klassOop constantPoolOopDesc::klass_at_impl(constantPoolHandle this_oop, int whi } if (!PENDING_EXCEPTION-> - is_a(SystemDictionary::linkageError_klass())) { + is_a(SystemDictionary::LinkageError_klass())) { // Just throw the exception and don't prevent these classes from // being loaded due to virtual machine errors like StackOverflow // and OutOfMemoryError, etc, or if the thread was hit by stop() @@ -262,25 +262,48 @@ symbolOop constantPoolOopDesc::impl_signature_ref_at(int which, bool uncached) { int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncached) { - jint ref_index = field_or_method_at(which, uncached); + int i = which; + if (!uncached && cache() != NULL) { + if (constantPoolCacheOopDesc::is_secondary_index(which)) + // Invokedynamic indexes are always processed in native order + // so there is no question of reading a native u2 in Java order here. + return cache()->main_entry_at(which)->constant_pool_index(); + // change byte-ordering and go via cache + i = remap_instruction_operand_from_cache(which); + } else { + if (tag_at(which).is_name_and_type()) + // invokedynamic index is a simple name-and-type + return which; + } + assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(i); return extract_high_short_from_int(ref_index); } int constantPoolOopDesc::impl_klass_ref_index_at(int which, bool uncached) { - jint ref_index = field_or_method_at(which, uncached); + guarantee(!constantPoolCacheOopDesc::is_secondary_index(which), + "an invokedynamic instruction does not have a klass"); + int i = which; + if (!uncached && cache() != NULL) { + // change byte-ordering and go via cache + i = remap_instruction_operand_from_cache(which); + } + assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(i); return extract_low_short_from_int(ref_index); } -int constantPoolOopDesc::map_instruction_operand_to_index(int operand) { - if (constantPoolCacheOopDesc::is_secondary_index(operand)) { - return cache()->main_entry_at(operand)->constant_pool_index(); - } +int constantPoolOopDesc::remap_instruction_operand_from_cache(int operand) { + // Operand was fetched by a stream using get_Java_u2, yet was stored + // by Rewriter::rewrite_member_reference in native order. + // So now we have to fix the damage by swapping back to native order. assert((int)(u2)operand == operand, "clean u2"); - int index = Bytes::swap_u2(operand); - return cache()->entry_at(index)->constant_pool_index(); + int cpc_index = Bytes::swap_u2(operand); + int member_index = cache()->entry_at(cpc_index)->constant_pool_index(); + return member_index; } diff --git a/hotspot/src/share/vm/oops/constantPoolOop.hpp b/hotspot/src/share/vm/oops/constantPoolOop.hpp index 72bec650014..fb50c6a2949 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp @@ -191,6 +191,16 @@ class constantPoolOopDesc : public oopDesc { } } + void object_at_put(int which, oop str) { + oop_store((volatile oop*) obj_at_addr(which), str); + release_tag_at_put(which, JVM_CONSTANT_Object); + if (UseConcMarkSweepGC) { + // In case the earlier card-mark was consumed by a concurrent + // marking thread before the tag was updated, redirty the card. + oop_store_without_check((volatile oop*) obj_at_addr(which), str); + } + } + // For temporary use while constructing constant pool void string_index_at_put(int which, int string_index) { tag_at_put(which, JVM_CONSTANT_StringIndex); @@ -228,7 +238,8 @@ class constantPoolOopDesc : public oopDesc { tag.is_unresolved_klass() || tag.is_symbol() || tag.is_unresolved_string() || - tag.is_string(); + tag.is_string() || + tag.is_object(); } // Fetching constants @@ -291,6 +302,11 @@ class constantPoolOopDesc : public oopDesc { return string_at_impl(h_this, which, CHECK_NULL); } + oop object_at(int which) { + assert(tag_at(which).is_object(), "Corrupted constant pool"); + return *obj_at_addr(which); + } + // A "pseudo-string" is an non-string oop that has found is way into // a String entry. // Under AnonymousClasses this can happen if the user patches a live @@ -342,12 +358,14 @@ class constantPoolOopDesc : public oopDesc { } // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, - // name_and_type_ref_index_at) all expect constant pool indices - // from the bytecodes to be passed in, which are actually potentially byte-swapped - // or rewritten constant pool cache indices. They all call map_instruction_operand_to_index. - int map_instruction_operand_to_index(int operand); + // name_and_type_ref_index_at) all expect to be passed indices obtained + // directly from the bytecode, and extracted according to java byte order. + // If the indices are meant to refer to fields or methods, they are + // actually potentially byte-swapped, rewritten constant pool cache indices. + // The routine remap_instruction_operand_from_cache manages the adjustment + // of these values back to constant pool indices. - // There are also "uncached" versions which do not map the operand index; see below. + // There are also "uncached" versions which do not adjust the operand index; see below. // Lookup for entries consisting of (klass_index, name_and_type index) klassOop klass_ref_at(int which, TRAPS); @@ -361,8 +379,6 @@ class constantPoolOopDesc : public oopDesc { // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) - symbolOop nt_name_ref_at(int which_nt) { return symbol_at(name_ref_index_at(which_nt)); } - symbolOop nt_signature_ref_at(int which_nt) { return symbol_at(signature_ref_index_at(which_nt)); } BasicType basic_type_for_signature_at(int which); @@ -425,18 +441,7 @@ class constantPoolOopDesc : public oopDesc { int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - // Takes either a constant pool cache index in possibly byte-swapped - // byte order (which comes from the bytecodes after rewriting) or, - // if "uncached" is true, a vanilla constant pool index - jint field_or_method_at(int which, bool uncached) { - int i = which; - if (!uncached && cache() != NULL) { - // change byte-ordering and go via cache - i = map_instruction_operand_to_index(which); - } - assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); - return *int_at_addr(i); - } + int remap_instruction_operand_from_cache(int operand); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.cpp b/hotspot/src/share/vm/oops/cpCacheKlass.cpp index 5a85e88d46e..b922dc8f2ea 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.cpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.cpp @@ -261,6 +261,15 @@ void constantPoolCacheKlass::oop_print_on(oop obj, outputStream* st) { #endif +void constantPoolCacheKlass::oop_print_value_on(oop obj, outputStream* st) { + assert(obj->is_constantPoolCache(), "obj must be constant pool cache"); + constantPoolCacheOop cache = (constantPoolCacheOop)obj; + st->print("cache [%d]", cache->length()); + cache->print_address_on(st); + st->print(" for "); + cache->constant_pool()->print_value_on(st); +} + void constantPoolCacheKlass::oop_verify_on(oop obj, outputStream* st) { guarantee(obj->is_constantPoolCache(), "obj must be constant pool cache"); constantPoolCacheOop cache = (constantPoolCacheOop)obj; diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.hpp b/hotspot/src/share/vm/oops/cpCacheKlass.hpp index 859f64a46f5..e49b52d75a1 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.hpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.hpp @@ -61,9 +61,10 @@ class constantPoolCacheKlass: public Klass { juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } -#ifndef PRODUCT public: // Printing + void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); #endif diff --git a/hotspot/src/share/vm/oops/cpCacheOop.cpp b/hotspot/src/share/vm/oops/cpCacheOop.cpp index 6f549afbe38..36380c88903 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.cpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp @@ -28,21 +28,17 @@ // Implememtation of ConstantPoolCacheEntry -void ConstantPoolCacheEntry::set_initial_state(int index) { - if (constantPoolCacheOopDesc::is_secondary_index(index)) { - // Hack: The rewriter is trying to say that this entry itself - // will be a secondary entry. - int main_index = constantPoolCacheOopDesc::decode_secondary_index(index); - assert(0 <= main_index && main_index < 0x10000, "sanity check"); - _indices = (main_index << 16); - assert(main_entry_index() == main_index, ""); - return; - } +void ConstantPoolCacheEntry::initialize_entry(int index) { assert(0 < index && index < 0x10000, "sanity check"); _indices = index; assert(constant_pool_index() == index, ""); } +void ConstantPoolCacheEntry::initialize_secondary_entry(int main_index) { + assert(0 <= main_index && main_index < 0x10000, "sanity check"); + _indices = (main_index << 16); + assert(main_entry_index() == main_index, ""); +} int ConstantPoolCacheEntry::as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile, @@ -223,10 +219,10 @@ void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, int extra_data) { - methodOop method = (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site()); + methodOop method = (methodOop) java_dyn_CallSite::vmmethod(call_site()); assert(method->is_method(), "must be initialized properly"); int param_size = method->size_of_parameters(); - assert(param_size > 1, "method argument size must include MH.this & initial dynamic receiver"); + assert(param_size >= 1, "method argument size must include MH.this"); param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic if (Atomic::cmpxchg_ptr(call_site(), &_f1, NULL) == NULL) { // racing threads might be trying to install their own favorites @@ -439,7 +435,18 @@ void ConstantPoolCacheEntry::verify(outputStream* st) const { void constantPoolCacheOopDesc::initialize(intArray& inverse_index_map) { assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache"); - for (int i = 0; i < length(); i++) entry_at(i)->set_initial_state(inverse_index_map[i]); + for (int i = 0; i < length(); i++) { + ConstantPoolCacheEntry* e = entry_at(i); + int original_index = inverse_index_map[i]; + if ((original_index & Rewriter::_secondary_entry_tag) != 0) { + int main_index = (original_index - Rewriter::_secondary_entry_tag); + assert(!entry_at(main_index)->is_secondary_entry(), "valid main index"); + e->initialize_secondary_entry(main_index); + } else { + e->initialize_entry(original_index); + } + assert(entry_at(i) == e, "sanity"); + } } // RedefineClasses() API support: diff --git a/hotspot/src/share/vm/oops/cpCacheOop.hpp b/hotspot/src/share/vm/oops/cpCacheOop.hpp index ec25b87352b..6fb7a635e56 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp @@ -154,7 +154,8 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { }; // Initialization - void set_initial_state(int index); // sets entry to initial state + void initialize_entry(int original_index); // initialize primary entry + void initialize_secondary_entry(int main_index); // initialize secondary entry void set_field( // sets entry to resolved field state Bytecodes::Code get_code, // the bytecode used for reading the field @@ -251,6 +252,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { // Code generation support static WordSize size() { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); } + static ByteSize size_in_bytes() { return in_ByteSize(sizeof(ConstantPoolCacheEntry)); } static ByteSize indices_offset() { return byte_offset_of(ConstantPoolCacheEntry, _indices); } static ByteSize f1_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f1); } static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); } @@ -321,6 +323,7 @@ class constantPoolCacheOopDesc: public oopDesc { ConstantPoolCacheEntry* base() const { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); } friend class constantPoolCacheKlass; + friend class ConstantPoolCacheEntry; public: // Initialization @@ -329,7 +332,8 @@ class constantPoolCacheOopDesc: public oopDesc { // Secondary indexes. // They must look completely different from normal indexes. // The main reason is that byte swapping is sometimes done on normal indexes. - // Also, it is helpful for debugging to tell the two apart. + // Also, some of the CP accessors do different things for secondary indexes. + // Finally, it is helpful for debugging to tell the two apart. static bool is_secondary_index(int i) { return (i < 0); } static int decode_secondary_index(int i) { assert(is_secondary_index(i), ""); return ~i; } static int encode_secondary_index(int i) { assert(!is_secondary_index(i), ""); return ~i; } @@ -337,18 +341,35 @@ class constantPoolCacheOopDesc: public oopDesc { // Accessors void set_constant_pool(constantPoolOop pool) { oop_store_without_check((oop*)&_constant_pool, (oop)pool); } constantPoolOop constant_pool() const { return _constant_pool; } - ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; } + // Fetches the entry at the given index. + // The entry may be either primary or secondary. + // In either case the index must not be encoded or byte-swapped in any way. + ConstantPoolCacheEntry* entry_at(int i) const { + assert(0 <= i && i < length(), "index out of bounds"); + return base() + i; + } + // Fetches the secondary entry referred to by index. + // The index may be a secondary index, and must not be byte-swapped. + ConstantPoolCacheEntry* secondary_entry_at(int i) const { + int raw_index = i; + if (is_secondary_index(i)) { // correct these on the fly + raw_index = decode_secondary_index(i); + } + assert(entry_at(raw_index)->is_secondary_entry(), "not a secondary entry"); + return entry_at(raw_index); + } + // Given a primary or secondary index, fetch the corresponding primary entry. + // Indirect through the secondary entry, if the index is encoded as a secondary index. + // The index must not be byte-swapped. ConstantPoolCacheEntry* main_entry_at(int i) const { - ConstantPoolCacheEntry* e; + int primary_index = i; if (is_secondary_index(i)) { // run through an extra level of indirection: - i = decode_secondary_index(i); - e = entry_at(i); - i = e->main_entry_index(); + int raw_index = decode_secondary_index(i); + primary_index = entry_at(raw_index)->main_entry_index(); } - e = entry_at(i); - assert(!e->is_secondary_entry(), "only one level of indirection"); - return e; + assert(!entry_at(primary_index)->is_secondary_entry(), "only one level of indirection"); + return entry_at(primary_index); } // GC support @@ -359,6 +380,12 @@ class constantPoolCacheOopDesc: public oopDesc { // Code generation static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); } + static ByteSize entry_offset(int raw_index) { + int index = raw_index; + if (is_secondary_index(raw_index)) + index = decode_secondary_index(raw_index); + return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index); + } // RedefineClasses() API support: // If any entry of this constantPoolCache points to any of diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index eb533a81e6f..845f1ec22b6 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -1559,7 +1559,7 @@ void GenerateOopMap::interp1(BytecodeStream *itr) { case Bytecodes::_invokevirtual: case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break; case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break; - case Bytecodes::_invokedynamic: do_method(false, true, itr->get_index_int(), itr->bci()); break; + case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break; case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break; case Bytecodes::_newarray: case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break; @@ -1830,12 +1830,8 @@ void GenerateOopMap::do_jsr(int targ_bci) { void GenerateOopMap::do_ldc(int idx, int bci) { - constantPoolOop cp = method()->constants(); - constantTag tag = cp->tag_at(idx); - - CellTypeState cts = (tag.is_string() || tag.is_unresolved_string() || - tag.is_klass() || tag.is_unresolved_klass()) - ? CellTypeState::make_line_ref(bci) : valCTS; + constantPoolOop cp = method()->constants(); + CellTypeState cts = cp->is_pointer_entry(idx) ? CellTypeState::make_line_ref(bci) : valCTS; ppush1(cts); } @@ -1900,11 +1896,9 @@ void GenerateOopMap::do_field(int is_get, int is_static, int idx, int bci) { } void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci) { - // Dig up signature for field in constant pool - constantPoolOop cp = _method->constants(); - int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); - int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); // @@@@@ - symbolOop signature = cp->symbol_at(signatureIdx); + // Dig up signature for field in constant pool + constantPoolOop cp = _method->constants(); + symbolOop signature = cp->signature_ref_at(idx); // Parse method signature CellTypeState out[4]; diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index aaa2bfe876e..ae57e59143b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -383,7 +383,7 @@ void instanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { this_oop->set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below } - if (e->is_a(SystemDictionary::error_klass())) { + if (e->is_a(SystemDictionary::Error_klass())) { THROW_OOP(e()); } else { JavaCallArguments args(e); @@ -568,7 +568,7 @@ void instanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) { THROW_MSG(throwError ? vmSymbols::java_lang_InstantiationError() : vmSymbols::java_lang_InstantiationException(), external_name()); } - if (as_klassOop() == SystemDictionary::class_klass()) { + if (as_klassOop() == SystemDictionary::Class_klass()) { ResourceMark rm(THREAD); THROW_MSG(throwError ? vmSymbols::java_lang_IllegalAccessError() : vmSymbols::java_lang_IllegalAccessException(), external_name()); @@ -2045,8 +2045,9 @@ bool instanceKlass::is_same_package_member_impl(instanceKlassHandle class1, // 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); + bool ignore_inner_is_member; + klassOop next = outer1->compute_enclosing_class(&ignore_inner_is_member, + CHECK_false); if (next == NULL) break; if (next == class2()) return true; outer1 = instanceKlassHandle(THREAD, next); @@ -2055,8 +2056,9 @@ bool instanceKlass::is_same_package_member_impl(instanceKlassHandle class1, // Now do the same for class2. instanceKlassHandle outer2 = class2; for (;;) { - symbolOop ignore_name; - klassOop next = outer2->compute_enclosing_class(ignore_name, CHECK_false); + bool ignore_inner_is_member; + klassOop next = outer2->compute_enclosing_class(&ignore_inner_is_member, + CHECK_false); if (next == NULL) break; // Might as well check the new outer against all available values. if (next == class1()) return true; @@ -2223,7 +2225,7 @@ void FieldPrinter::do_field(fieldDescriptor* fd) { void instanceKlass::oop_print_on(oop obj, outputStream* st) { Klass::oop_print_on(obj, st); - if (as_klassOop() == SystemDictionary::string_klass()) { + if (as_klassOop() == SystemDictionary::String_klass()) { typeArrayOop value = java_lang_String::value(obj); juint offset = java_lang_String::offset(obj); juint length = java_lang_String::length(obj); @@ -2243,7 +2245,7 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) { FieldPrinter print_nonstatic_field(st, obj); do_nonstatic_fields(&print_nonstatic_field); - if (as_klassOop() == SystemDictionary::class_klass()) { + if (as_klassOop() == SystemDictionary::Class_klass()) { st->print(BULLET"signature: "); java_lang_Class::print_signature(obj, st); st->cr(); @@ -2266,11 +2268,13 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) { } } +#endif //PRODUCT + 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() + if (as_klassOop() == SystemDictionary::String_klass() && java_lang_String::value(obj) != NULL) { ResourceMark rm; int len = java_lang_String::length(obj); @@ -2279,7 +2283,7 @@ void instanceKlass::oop_print_value_on(oop obj, outputStream* st) { st->print(" = \"%s\"", str); if (len > plen) st->print("...[%d]", len); - } else if (as_klassOop() == SystemDictionary::class_klass()) { + } else if (as_klassOop() == SystemDictionary::Class_klass()) { klassOop k = java_lang_Class::as_klassOop(obj); st->print(" = "); if (k != NULL) { @@ -2297,8 +2301,6 @@ void instanceKlass::oop_print_value_on(oop obj, outputStream* st) { } } -#endif // ndef PRODUCT - const char* instanceKlass::internal_name() const { return external_name(); } @@ -2346,7 +2348,7 @@ void instanceKlass::verify_class_klass_nonstatic_oop_maps(klassOop k) { // Check that we have the right class static bool first_time = true; - guarantee(k == SystemDictionary::class_klass() && first_time, "Invalid verify of maps"); + guarantee(k == SystemDictionary::Class_klass() && first_time, "Invalid verify of maps"); first_time = false; const int extra = java_lang_Class::number_of_fake_oop_fields; guarantee(ik->nonstatic_field_size() == extra, "just checking"); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 9147892b1ea..798a3808931 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -337,12 +337,12 @@ class instanceKlass: public Klass { 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) { + klassOop compute_enclosing_class(bool* inner_is_member, TRAPS) { instanceKlassHandle self(THREAD, this->as_klassOop()); - return compute_enclosing_class_impl(self, simple_name_result, THREAD); + return compute_enclosing_class_impl(self, inner_is_member, THREAD); } static klassOop compute_enclosing_class_impl(instanceKlassHandle self, - symbolOop& simple_name_result, TRAPS); + bool* inner_is_member, TRAPS); // tell if two classes have the same enclosing class (at package level) bool is_same_package_member(klassOop class2, TRAPS) { @@ -839,17 +839,16 @@ public: // JVMTI support jint jvmti_class_status() const; -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); void print_dependent_nmethods(bool verbose = false); bool is_dependent_nmethod(nmethod* nm); #endif - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp index 18a6d7addf8..05748104d3b 100644 --- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp @@ -317,6 +317,11 @@ void instanceKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { pm->claim_or_forward_breadth(sg_addr); } + oop* bsm_addr = ik->adr_bootstrap_method(); + if (PSScavenge::should_scavenge(bsm_addr)) { + pm->claim_or_forward_breadth(bsm_addr); + } + klassKlass::oop_copy_contents(pm, obj); } @@ -345,6 +350,11 @@ void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { pm->claim_or_forward_depth(sg_addr); } + oop* bsm_addr = ik->adr_bootstrap_method(); + if (PSScavenge::should_scavenge(bsm_addr)) { + pm->claim_or_forward_depth(bsm_addr); + } + klassKlass::oop_copy_contents(pm, obj); } @@ -628,6 +638,7 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { st->cr(); } +#endif //PRODUCT void instanceKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); @@ -635,8 +646,6 @@ void instanceKlassKlass::oop_print_value_on(oop obj, outputStream* st) { ik->name()->print_value_on(st); } -#endif // PRODUCT - const char* instanceKlassKlass::internal_name() const { return "{instance class}"; } diff --git a/hotspot/src/share/vm/oops/instanceKlassKlass.hpp b/hotspot/src/share/vm/oops/instanceKlassKlass.hpp index d736ca5eb23..79a93b63910 100644 --- a/hotspot/src/share/vm/oops/instanceKlassKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlassKlass.hpp @@ -69,14 +69,13 @@ private: // Apply closure to the InstanceKlass oops that are outside the java heap. inline void iterate_c_heap_oops(instanceKlass* ik, OopClosure* closure); -#ifndef PRODUCT public: // Printing - void oop_print_on(oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT + void oop_print_on(oop obj, outputStream* st); #endif - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index a8c7baf5214..a8f1ebeeca3 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -78,9 +78,9 @@ void instanceRefKlass::oop_follow_contents(oop obj) { #ifndef SERIALGC template -static void specialized_oop_follow_contents(instanceRefKlass* ref, - ParCompactionManager* cm, - oop obj) { +void specialized_oop_follow_contents(instanceRefKlass* ref, + ParCompactionManager* cm, + oop obj) { T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); T heap_oop = oopDesc::load_heap_oop(referent_addr); debug_only( @@ -397,7 +397,7 @@ void instanceRefKlass::update_nonstatic_oop_maps(klassOop k) { // Check that we have the right class debug_only(static bool first_time = true); - assert(k == SystemDictionary::reference_klass() && first_time, + assert(k == SystemDictionary::Reference_klass() && first_time, "Invalid update of maps"); debug_only(first_time = false); assert(ik->nonstatic_oop_map_count() == 1, "just checking"); diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index a842709649e..8260ee274b5 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -217,8 +217,8 @@ void Klass::initialize_supers(klassOop k, TRAPS) { set_super(NULL); oop_store_without_check((oop*) &_primary_supers[0], (oop) this->as_klassOop()); assert(super_depth() == 0, "Object must already be initialized properly"); - } else if (k != super() || k == SystemDictionary::object_klass()) { - assert(super() == NULL || super() == SystemDictionary::object_klass(), + } else if (k != super() || k == SystemDictionary::Object_klass()) { + assert(super() == NULL || super() == SystemDictionary::Object_klass(), "initialize this only once to a non-trivial value"); set_super(k); Klass* sup = k->klass_part(); @@ -370,7 +370,7 @@ void Klass::append_to_sibling_list() { void Klass::remove_from_sibling_list() { // remove receiver from sibling list instanceKlass* super = superklass(); - assert(super != NULL || as_klassOop() == SystemDictionary::object_klass(), "should have super"); + assert(super != NULL || as_klassOop() == SystemDictionary::Object_klass(), "should have super"); if (super == NULL) return; // special case: class Object if (super->subklass() == this) { // first subklass @@ -541,6 +541,7 @@ void Klass::oop_print_on(oop obj, outputStream* st) { st->cr(); } +#endif //PRODUCT void Klass::oop_print_value_on(oop obj, outputStream* st) { // print title @@ -549,8 +550,6 @@ void Klass::oop_print_value_on(oop obj, outputStream* st) { obj->print_address_on(st); } -#endif - // Verification void Klass::oop_verify_on(oop obj, outputStream* st) { diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index c4436d6554f..427d24c7755 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -776,14 +776,13 @@ class Klass : public Klass_vtbl { // JVMTI support virtual jint jvmti_class_status() const; -#ifndef PRODUCT public: // Printing - virtual void oop_print_on (oop obj, outputStream* st); virtual void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + virtual void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification virtual const char* internal_name() const = 0; virtual void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/klassKlass.cpp b/hotspot/src/share/vm/oops/klassKlass.cpp index b38d55cf4e8..78b5c797099 100644 --- a/hotspot/src/share/vm/oops/klassKlass.cpp +++ b/hotspot/src/share/vm/oops/klassKlass.cpp @@ -202,13 +202,12 @@ void klassKlass::oop_print_on(oop obj, outputStream* st) { Klass::oop_print_on(obj, st); } +#endif //PRODUCT void klassKlass::oop_print_value_on(oop obj, outputStream* st) { Klass::oop_print_value_on(obj, st); } -#endif - const char* klassKlass::internal_name() const { return "{other class}"; } diff --git a/hotspot/src/share/vm/oops/klassKlass.hpp b/hotspot/src/share/vm/oops/klassKlass.hpp index c8b5a9a6510..04b4ed958f3 100644 --- a/hotspot/src/share/vm/oops/klassKlass.hpp +++ b/hotspot/src/share/vm/oops/klassKlass.hpp @@ -67,14 +67,13 @@ class klassKlass: public Klass { juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/methodDataKlass.cpp b/hotspot/src/share/vm/oops/methodDataKlass.cpp index 56592b0ee24..04823a30831 100644 --- a/hotspot/src/share/vm/oops/methodDataKlass.cpp +++ b/hotspot/src/share/vm/oops/methodDataKlass.cpp @@ -214,6 +214,8 @@ void methodDataKlass::oop_print_on(oop obj, outputStream* st) { m->print_data_on(st); } +#endif //PRODUCT + void methodDataKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_methodData(), "should be method data"); methodDataOop m = methodDataOop(obj); @@ -221,8 +223,6 @@ void methodDataKlass::oop_print_value_on(oop obj, outputStream* st) { m->method()->print_value_on(st); } -#endif // !PRODUCT - const char* methodDataKlass::internal_name() const { return "{method data}"; } diff --git a/hotspot/src/share/vm/oops/methodDataKlass.hpp b/hotspot/src/share/vm/oops/methodDataKlass.hpp index 0b78000d46f..14eaf35b229 100644 --- a/hotspot/src/share/vm/oops/methodDataKlass.hpp +++ b/hotspot/src/share/vm/oops/methodDataKlass.hpp @@ -71,14 +71,13 @@ class methodDataKlass : public Klass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif // !PRODUCT +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verify operations const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/methodKlass.cpp b/hotspot/src/share/vm/oops/methodKlass.cpp index 2879529bb9f..1b788c63b13 100644 --- a/hotspot/src/share/vm/oops/methodKlass.cpp +++ b/hotspot/src/share/vm/oops/methodKlass.cpp @@ -308,6 +308,7 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) { } } +#endif //PRODUCT void methodKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_method(), "must be method"); @@ -323,8 +324,6 @@ void methodKlass::oop_print_value_on(oop obj, outputStream* st) { if (WizardMode && m->code() != NULL) st->print(" ((nmethod*)%p)", m->code()); } -#endif // PRODUCT - const char* methodKlass::internal_name() const { return "{method}"; } diff --git a/hotspot/src/share/vm/oops/methodKlass.hpp b/hotspot/src/share/vm/oops/methodKlass.hpp index 7c26114f744..abd1cbf4741 100644 --- a/hotspot/src/share/vm/oops/methodKlass.hpp +++ b/hotspot/src/share/vm/oops/methodKlass.hpp @@ -68,14 +68,13 @@ class methodKlass : public Klass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verify operations const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index cd575e5c488..e6f361ad7a1 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -456,12 +456,12 @@ objArrayHandle methodOopDesc::resolved_checked_exceptions_impl(methodOop this_oo return objArrayHandle(THREAD, Universe::the_empty_class_klass_array()); } else { methodHandle h_this(THREAD, this_oop); - objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::class_klass(), length, CHECK_(objArrayHandle())); + objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::Class_klass(), length, CHECK_(objArrayHandle())); objArrayHandle mirrors (THREAD, m_oop); for (int i = 0; i < length; i++) { CheckedExceptionElement* table = h_this->checked_exceptions_start(); // recompute on each iteration, not gc safe klassOop k = h_this->constants()->klass_at(table[i].class_cp_index, CHECK_(objArrayHandle())); - assert(Klass::cast(k)->is_subclass_of(SystemDictionary::throwable_klass()), "invalid exception class"); + assert(Klass::cast(k)->is_subclass_of(SystemDictionary::Throwable_klass()), "invalid exception class"); mirrors->obj_at_put(i, Klass::cast(k)->java_mirror()); } return mirrors; @@ -821,6 +821,18 @@ jint* methodOopDesc::method_type_offsets_chain() { return pchase; } +//------------------------------------------------------------------------------ +// methodOopDesc::is_method_handle_adapter +// +// Tests if this method is an internal adapter frame from the +// MethodHandleCompiler. +bool methodOopDesc::is_method_handle_adapter() const { + return ((name() == vmSymbols::invoke_name() && + method_holder() == SystemDictionary::MethodHandle_klass()) + || + method_holder() == SystemDictionary::InvokeDynamic_klass()); +} + methodHandle methodOopDesc::make_invoke_method(KlassHandle holder, symbolHandle signature, Handle method_type, TRAPS) { @@ -1032,8 +1044,8 @@ bool methodOopDesc::load_signature_classes(methodHandle m, TRAPS) { // We are loading classes eagerly. If a ClassNotFoundException or // a LinkageError was generated, be sure to ignore it. if (HAS_PENDING_EXCEPTION) { - if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass()) || - PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) { + if (PENDING_EXCEPTION->is_a(SystemDictionary::ClassNotFoundException_klass()) || + PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { CLEAR_PENDING_EXCEPTION; } else { return false; diff --git a/hotspot/src/share/vm/oops/methodOop.hpp b/hotspot/src/share/vm/oops/methodOop.hpp index fc3d3451ca4..4c9a6f05172 100644 --- a/hotspot/src/share/vm/oops/methodOop.hpp +++ b/hotspot/src/share/vm/oops/methodOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,6 +365,7 @@ class methodOopDesc : public oopDesc { #endif // byte codes + void set_code(address code) { return constMethod()->set_code(code); } address code_base() const { return constMethod()->code_base(); } bool contains(address bcp) const { return constMethod()->contains(bcp); } @@ -524,6 +525,9 @@ class methodOopDesc : public oopDesc { // JSR 292 support bool is_method_handle_invoke() const { return access_flags().is_method_handle_invoke(); } + // Tests if this method is an internal adapter frame from the + // MethodHandleCompiler. + bool is_method_handle_adapter() const; static methodHandle make_invoke_method(KlassHandle holder, symbolHandle signature, Handle method_type, @@ -537,6 +541,7 @@ class methodOopDesc : public oopDesc { // all without checking for a stack overflow static int extra_stack_entries() { return (EnableMethodHandles ? (int)MethodHandlePushLimit : 0) + (EnableInvokeDynamic ? 3 : 0); } static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize() + // RedefineClasses() support: bool is_old() const { return access_flags().is_old(); } void set_is_old() { _access_flags.set_is_old(); } diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 212126490cd..cb6884a9c01 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -127,16 +127,14 @@ template void objArrayKlass::do_copy(arrayOop s, T* src, // pointer delta is scaled to number of elements (length field in // objArrayOop) which we assume is 32 bit. assert(pd == (size_t)(int)pd, "length field overflow"); - const size_t done_word_len = objArrayOopDesc::array_size((int)pd); - bs->write_ref_array(MemRegion((HeapWord*)dst, done_word_len)); + bs->write_ref_array((HeapWord*)dst, pd); THROW(vmSymbols::java_lang_ArrayStoreException()); return; } } } } - const size_t word_len = objArrayOopDesc::array_size(length); - bs->write_ref_array(MemRegion((HeapWord*)dst, word_len)); + bs->write_ref_array((HeapWord*)dst, length); } void objArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, @@ -248,8 +246,8 @@ objArrayOop objArrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) } else { objArrayOop sec_oop = oopFactory::new_system_objArray(num_secondaries, CHECK_NULL); objArrayHandle secondaries(THREAD, sec_oop); - secondaries->obj_at_put(num_extra_slots+0, SystemDictionary::cloneable_klass()); - secondaries->obj_at_put(num_extra_slots+1, SystemDictionary::serializable_klass()); + secondaries->obj_at_put(num_extra_slots+0, SystemDictionary::Cloneable_klass()); + secondaries->obj_at_put(num_extra_slots+1, SystemDictionary::Serializable_klass()); for (int i = 0; i < num_elem_supers; i++) { klassOop elem_super = (klassOop) elem_supers->obj_at(i); klassOop array_super = elem_super->klass_part()->array_klass_or_null(); @@ -501,6 +499,8 @@ void objArrayKlass::oop_print_on(oop obj, outputStream* st) { } } +#endif //PRODUCT + static int max_objArray_print_length = 4; void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) { @@ -510,7 +510,7 @@ void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) { int len = objArrayOop(obj)->length(); st->print("[%d] ", len); obj->print_address_on(st); - if (PrintOopAddress || PrintMiscellaneous && (WizardMode || Verbose)) { + if (NOT_PRODUCT(PrintOopAddress ||) PrintMiscellaneous && (WizardMode || Verbose)) { st->print("{"); for (int i = 0; i < len; i++) { if (i > max_objArray_print_length) { @@ -522,8 +522,6 @@ void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) { } } -#endif // PRODUCT - const char* objArrayKlass::internal_name() const { return external_name(); } diff --git a/hotspot/src/share/vm/oops/objArrayKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlass.hpp index fcc62aad5b9..fba1069b3d0 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp @@ -119,14 +119,13 @@ class objArrayKlass : public arrayKlass { private: static klassOop array_klass_impl (objArrayKlassHandle this_oop, bool or_null, int n, TRAPS); -#ifndef PRODUCT public: // Printing - void oop_print_on (oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp index 06c7f39f5eb..67626975c3c 100644 --- a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp @@ -99,7 +99,7 @@ klassOop objArrayKlassKlass::allocate_objArray_klass_impl(objArrayKlassKlassHand } } else { // The element type is already Object. Object[] has direct super of Object. - super_klass = KlassHandle(THREAD, SystemDictionary::object_klass()); + super_klass = KlassHandle(THREAD, SystemDictionary::Object_klass()); } } @@ -278,6 +278,7 @@ void objArrayKlassKlass::oop_print_on(oop obj, outputStream* st) { st->cr(); } +#endif //PRODUCT void objArrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); @@ -287,8 +288,6 @@ void objArrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("[]"); } -#endif - const char* objArrayKlassKlass::internal_name() const { return "{object array class}"; } diff --git a/hotspot/src/share/vm/oops/objArrayKlassKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlassKlass.hpp index ff3e94a6016..b428cf3f54c 100644 --- a/hotspot/src/share/vm/oops/objArrayKlassKlass.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlassKlass.hpp @@ -64,14 +64,13 @@ class objArrayKlassKlass : public arrayKlassKlass { // helpers static klassOop allocate_objArray_klass_impl(objArrayKlassKlassHandle this_oop, int n, KlassHandle element_klass, TRAPS); -#ifndef PRODUCT public: // Printing - void oop_print_on(oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif +#ifndef PRODUCT + void oop_print_on(oop obj, outputStream* st); +#endif //PRODUCT - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/objArrayOop.hpp b/hotspot/src/share/vm/oops/objArrayOop.hpp index 626f398a6be..1c1764a8751 100644 --- a/hotspot/src/share/vm/oops/objArrayOop.hpp +++ b/hotspot/src/share/vm/oops/objArrayOop.hpp @@ -37,6 +37,32 @@ class objArrayOopDesc : public arrayOopDesc { return &((T*)base())[index]; } +private: + // Give size of objArrayOop in HeapWords minus the header + static int array_size(int length) { + const int OopsPerHeapWord = HeapWordSize/heapOopSize; + assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0), + "Else the following (new) computation would be in error"); +#ifdef ASSERT + // The old code is left in for sanity-checking; it'll + // go away pretty soon. XXX + // Without UseCompressedOops, this is simply: + // oop->length() * HeapWordsPerOop; + // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer. + // The oop elements are aligned up to wordSize + const int HeapWordsPerOop = heapOopSize/HeapWordSize; + int old_res; + if (HeapWordsPerOop > 0) { + old_res = length * HeapWordsPerOop; + } else { + old_res = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord; + } +#endif // ASSERT + int res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord; + assert(res == old_res, "Inconsistency between old and new."); + return res; + } + public: // Returns the offset of the first element. static int base_offset_in_bytes() { @@ -67,27 +93,14 @@ class objArrayOopDesc : public arrayOopDesc { // Sizing static int header_size() { return arrayOopDesc::header_size(T_OBJECT); } int object_size() { return object_size(length()); } - int array_size() { return array_size(length()); } static int object_size(int length) { // This returns the object size in HeapWords. - return align_object_size(header_size() + array_size(length)); - } - - // Give size of objArrayOop in HeapWords minus the header - static int array_size(int length) { - // Without UseCompressedOops, this is simply: - // oop->length() * HeapWordsPerOop; - // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer. - // The oop elements are aligned up to wordSize - const int HeapWordsPerOop = heapOopSize/HeapWordSize; - if (HeapWordsPerOop > 0) { - return length * HeapWordsPerOop; - } else { - const int OopsPerHeapWord = HeapWordSize/heapOopSize; - int word_len = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord; - return word_len; - } + uint asz = array_size(length); + uint osz = align_object_size(header_size() + asz); + assert(osz >= asz, "no overflow"); + assert((int)osz > 0, "no overflow"); + return (int)osz; } // special iterators for index ranges, returns size of object diff --git a/hotspot/src/share/vm/oops/oop.cpp b/hotspot/src/share/vm/oops/oop.cpp index da787bed038..96b04d051cd 100644 --- a/hotspot/src/share/vm/oops/oop.cpp +++ b/hotspot/src/share/vm/oops/oop.cpp @@ -31,14 +31,13 @@ BarrierSet* oopDesc::_bs = NULL; #ifdef PRODUCT void oopDesc::print_on(outputStream* st) const {} -void oopDesc::print_value_on(outputStream* st) const {} void oopDesc::print_address_on(outputStream* st) const {} -char* oopDesc::print_value_string() { return NULL; } char* oopDesc::print_string() { return NULL; } void oopDesc::print() {} -void oopDesc::print_value() {} void oopDesc::print_address() {} -#else + +#else //PRODUCT + void oopDesc::print_on(outputStream* st) const { if (this == NULL) { st->print_cr("NULL"); @@ -47,22 +46,6 @@ void oopDesc::print_on(outputStream* st) const { } } -void oopDesc::print_value_on(outputStream* st) const { - oop obj = oop(this); - if (this == NULL) { - st->print("NULL"); - } else if (java_lang_String::is_instance(obj)) { - java_lang_String::print(obj, st); - if (PrintOopAddress) print_address_on(st); -#ifdef ASSERT - } else if (!Universe::heap()->is_in(obj) || !Universe::heap()->is_in(klass())) { - st->print("### BAD OOP %p ###", (address)obj); -#endif - } else { - blueprint()->oop_print_value_on(obj, st); - } -} - void oopDesc::print_address_on(outputStream* st) const { if (PrintOopAddress) { st->print("{"INTPTR_FORMAT"}", this); @@ -71,24 +54,48 @@ void oopDesc::print_address_on(outputStream* st) const { void oopDesc::print() { print_on(tty); } -void oopDesc::print_value() { print_value_on(tty); } - void oopDesc::print_address() { print_address_on(tty); } char* oopDesc::print_string() { - stringStream* st = new stringStream(); - print_on(st); - return st->as_string(); -} - -char* oopDesc::print_value_string() { - stringStream* st = new stringStream(); - print_value_on(st); - return st->as_string(); + stringStream st; + print_on(&st); + return st.as_string(); } #endif // PRODUCT +// The print_value functions are present in all builds, to support the disassembler. + +void oopDesc::print_value() { + print_value_on(tty); +} + +char* oopDesc::print_value_string() { + char buf[100]; + stringStream st(buf, sizeof(buf)); + print_value_on(&st); + return st.as_string(); +} + +void oopDesc::print_value_on(outputStream* st) const { + oop obj = oop(this); + if (this == NULL) { + st->print("NULL"); + } else if (java_lang_String::is_instance(obj)) { + java_lang_String::print(obj, st); +#ifndef PRODUCT + if (PrintOopAddress) print_address_on(st); +#endif //PRODUCT +#ifdef ASSERT + } else if (!Universe::heap()->is_in(obj) || !Universe::heap()->is_in(klass())) { + st->print("### BAD OOP %p ###", (address)obj); +#endif //ASSERT + } else { + blueprint()->oop_print_value_on(obj, st); + } +} + + void oopDesc::verify_on(outputStream* st) { if (this != NULL) { blueprint()->oop_verify_on(this, st); diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index 9b7e9baf5c0..c67220a26e6 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -30,13 +30,12 @@ // no virtual functions allowed // store into oop with store check -template void oop_store(T* p, oop v); -template void oop_store(volatile T* p, oop v); +template inline void oop_store(T* p, oop v); +template inline void oop_store(volatile T* p, oop v); // store into oop without store check -template void oop_store_without_check(T* p, oop v); -template void oop_store_without_check(volatile T* p, oop v); - +template inline void oop_store_without_check(T* p, oop v); +template inline void oop_store_without_check(volatile T* p, oop v); extern bool always_do_update_barrier; diff --git a/hotspot/src/share/vm/oops/symbolKlass.cpp b/hotspot/src/share/vm/oops/symbolKlass.cpp index d0b6e2f33b5..4307beb8897 100644 --- a/hotspot/src/share/vm/oops/symbolKlass.cpp +++ b/hotspot/src/share/vm/oops/symbolKlass.cpp @@ -213,6 +213,8 @@ void symbolKlass::oop_print_on(oop obj, outputStream* st) { st->print("'"); } +#endif //PRODUCT + void symbolKlass::oop_print_value_on(oop obj, outputStream* st) { symbolOop sym = symbolOop(obj); st->print("'"); @@ -222,8 +224,6 @@ void symbolKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("'"); } -#endif //PRODUCT - const char* symbolKlass::internal_name() const { return "{symbol}"; } diff --git a/hotspot/src/share/vm/oops/symbolKlass.hpp b/hotspot/src/share/vm/oops/symbolKlass.hpp index aca3e27175b..c03f2080fcc 100644 --- a/hotspot/src/share/vm/oops/symbolKlass.hpp +++ b/hotspot/src/share/vm/oops/symbolKlass.hpp @@ -65,10 +65,10 @@ class symbolKlass : public Klass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); -#ifndef PRODUCT // Printing void oop_print_value_on(oop obj, outputStream* st); +#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); -#endif +#endif //PRODUCT const char* internal_name() const; }; diff --git a/hotspot/src/share/vm/oops/symbolOop.cpp b/hotspot/src/share/vm/oops/symbolOop.cpp index 6308735223d..b99a303f490 100644 --- a/hotspot/src/share/vm/oops/symbolOop.cpp +++ b/hotspot/src/share/vm/oops/symbolOop.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 @@ -25,6 +25,11 @@ # include "incls/_precompiled.incl" # include "incls/_symbolOop.cpp.incl" + +// ------------------------------------------------------------------ +// symbolOopDesc::equals +// +// Compares the symbol with a string of the given length. bool symbolOopDesc::equals(const char* str, int len) const { int l = utf8_length(); if (l != len) return false; @@ -36,6 +41,48 @@ bool symbolOopDesc::equals(const char* str, int len) const { return true; } + +// ------------------------------------------------------------------ +// symbolOopDesc::starts_with +// +// Tests if the symbol starts with the specified prefix of the given +// length. +bool symbolOopDesc::starts_with(const char* prefix, int len) const { + if (len > utf8_length()) return false; + while (len-- > 0) { + if (prefix[len] != (char) byte_at(len)) + return false; + } + assert(len == -1, "we should be at the beginning"); + return true; +} + + +// ------------------------------------------------------------------ +// symbolOopDesc::index_of +// +// Finds if the given string is a substring of this symbol's utf8 bytes. +// Return -1 on failure. Otherwise return the first index where str occurs. +int symbolOopDesc::index_of_at(int i, const char* str, int len) const { + assert(i >= 0 && i <= utf8_length(), "oob"); + if (len <= 0) return 0; + char first_char = str[0]; + address bytes = (address) ((symbolOopDesc*)this)->base(); + address limit = bytes + utf8_length() - len; // inclusive limit + address scan = bytes + i; + if (scan > limit) + return -1; + for (;;) { + scan = (address) memchr(scan, first_char, (limit + 1 - scan)); + if (scan == NULL) + return -1; // not found + assert(scan >= bytes+i && scan <= limit, "scan oob"); + if (memcmp(scan, str, len) == 0) + return (int)(scan - bytes); + } +} + + char* symbolOopDesc::as_C_string(char* buf, int size) const { if (size > 0) { int len = MIN2(size - 1, utf8_length()); diff --git a/hotspot/src/share/vm/oops/symbolOop.hpp b/hotspot/src/share/vm/oops/symbolOop.hpp index 49f95ec510d..15a4b0a8504 100644 --- a/hotspot/src/share/vm/oops/symbolOop.hpp +++ b/hotspot/src/share/vm/oops/symbolOop.hpp @@ -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 @@ -70,8 +70,21 @@ class symbolOopDesc : public oopDesc { void set_utf8_length(int len) { _length = len; } - // Compares the symbol with a string + // Compares the symbol with a string. bool equals(const char* str, int len) const; + bool equals(const char* str) const { return equals(str, (int) strlen(str)); } + + // Tests if the symbol starts with the given prefix. + bool starts_with(const char* prefix, int len) const; + bool starts_with(const char* prefix) const { + return starts_with(prefix, (int) strlen(prefix)); + } + + // Tests if the symbol starts with the given prefix. + int index_of_at(int i, const char* str, int len) const; + int index_of_at(int i, const char* str) const { + return index_of_at(i, str, (int) strlen(str)); + } // Three-way compare for sorting; returns -1/0/1 if receiver is than arg // note that the ordering is not alfabetical diff --git a/hotspot/src/share/vm/oops/typeArrayKlassKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlassKlass.cpp index d987f0d14be..da19938fe83 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlassKlass.cpp @@ -45,6 +45,7 @@ void typeArrayKlassKlass::oop_print_on(oop obj, outputStream* st) { Klass:: oop_print_on(obj, st); } +#endif //PRODUCT void typeArrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); @@ -63,8 +64,6 @@ void typeArrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("}"); } -#endif - const char* typeArrayKlassKlass::internal_name() const { return "{type array class}"; } diff --git a/hotspot/src/share/vm/oops/typeArrayKlassKlass.hpp b/hotspot/src/share/vm/oops/typeArrayKlassKlass.hpp index fabda84467a..01b0f9def74 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlassKlass.hpp +++ b/hotspot/src/share/vm/oops/typeArrayKlassKlass.hpp @@ -47,12 +47,12 @@ class typeArrayKlassKlass : public arrayKlassKlass { static int header_size() { return oopDesc::header_size() + sizeof(typeArrayKlassKlass)/HeapWordSize; } int object_size() const { return align_object_size(header_size()); } -#ifndef PRODUCT public: // Printing - void oop_print_on(oop obj, outputStream* st); void oop_print_value_on(oop obj, outputStream* st); -#endif - public: +#ifndef PRODUCT + void oop_print_on(oop obj, outputStream* st); +#endif //PRODUCT + const char* internal_name() const; }; diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index eeb1658913a..b199d7c7047 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -27,11 +27,16 @@ //============================================================================= //------------------------------InlineTree------------------------------------- -InlineTree::InlineTree( Compile* c, const InlineTree *caller_tree, ciMethod* callee, JVMState* caller_jvms, int caller_bci, float site_invoke_ratio ) +InlineTree::InlineTree( Compile* c, + const InlineTree *caller_tree, ciMethod* callee, + JVMState* caller_jvms, int caller_bci, + float site_invoke_ratio, int site_depth_adjust) : C(c), _caller_jvms(caller_jvms), _caller_tree((InlineTree*)caller_tree), _method(callee), _site_invoke_ratio(site_invoke_ratio), - _count_inline_bcs(method()->code_size()) { + _site_depth_adjust(site_depth_adjust), + _count_inline_bcs(method()->code_size()) +{ NOT_PRODUCT(_count_inlines = 0;) if (_caller_jvms != NULL) { // Keep a private copy of the caller_jvms: @@ -40,7 +45,7 @@ InlineTree::InlineTree( Compile* c, const InlineTree *caller_tree, ciMethod* cal assert(!caller_jvms->should_reexecute(), "there should be no reexecute bytecode with inlining"); } assert(_caller_jvms->same_calls_as(caller_jvms), "consistent JVMS"); - assert((caller_tree == NULL ? 0 : caller_tree->inline_depth() + 1) == inline_depth(), "correct (redundant) depth parameter"); + assert((caller_tree == NULL ? 0 : caller_tree->stack_depth() + 1) == stack_depth(), "correct (redundant) depth parameter"); assert(caller_bci == this->caller_bci(), "correct (redundant) bci parameter"); if (UseOldInlining) { // Update hierarchical counts, count_inline_bcs() and count_inlines() @@ -52,10 +57,13 @@ InlineTree::InlineTree( Compile* c, const InlineTree *caller_tree, ciMethod* cal } } -InlineTree::InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio) +InlineTree::InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, + float site_invoke_ratio, int site_depth_adjust) : C(c), _caller_jvms(caller_jvms), _caller_tree(NULL), _method(callee_method), _site_invoke_ratio(site_invoke_ratio), - _count_inline_bcs(method()->code_size()) { + _site_depth_adjust(site_depth_adjust), + _count_inline_bcs(method()->code_size()) +{ NOT_PRODUCT(_count_inlines = 0;) assert(!UseOldInlining, "do not use for old stuff"); } @@ -180,6 +188,10 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle return NULL; } + // Always inline MethodHandle methods. + if (callee_method->is_method_handle_invoke()) + return NULL; + // First check all inlining restrictions which are required for correctness if (callee_method->is_abstract()) return "abstract method"; // note: we allow ik->is_abstract() @@ -265,10 +277,13 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_ return msg; } - bool is_accessor = InlineAccessors && callee_method->is_accessor(); + if (InlineAccessors && callee_method->is_accessor()) { + // accessor methods are not subject to any of the following limits. + return NULL; + } // suppress a few checks for accessors and trivial methods - if (!is_accessor && callee_method->code_size() > MaxTrivialSize) { + if (callee_method->code_size() > MaxTrivialSize) { // don't inline into giant methods if (C->unique() > (uint)NodeCountInliningCutoff) { @@ -287,7 +302,7 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_ } } - if (!C->do_inlining() && InlineAccessors && !is_accessor) { + if (!C->do_inlining() && InlineAccessors) { return "not an accessor"; } if( inline_depth() > MaxInlineLevel ) { @@ -322,14 +337,17 @@ bool pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* call // stricter than callee_holder->is_initialized() ciBytecodeStream iter(caller_method); iter.force_bci(caller_bci); - int index = iter.get_index_int(); - if( !caller_method->is_klass_loaded(index, true) ) { - return false; - } - // Try to do constant pool resolution if running Xcomp Bytecodes::Code call_bc = iter.cur_bc(); - if( !caller_method->check_call(index, call_bc == Bytecodes::_invokestatic) ) { - return false; + // An invokedynamic instruction does not have a klass. + if (call_bc != Bytecodes::_invokedynamic) { + int index = iter.get_index_int(); + if (!caller_method->is_klass_loaded(index, true)) { + return false; + } + // Try to do constant pool resolution if running Xcomp + if( !caller_method->check_call(index, call_bc == Bytecodes::_invokestatic) ) { + return false; + } } } // We will attempt to see if a class/field/etc got properly loaded. If it @@ -457,7 +475,30 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J if (old_ilt != NULL) { return old_ilt; } - InlineTree *ilt = new InlineTree( C, this, callee_method, caller_jvms, caller_bci, recur_frequency ); + int new_depth_adjust = 0; + if (caller_jvms->method() != NULL) { + if ((caller_jvms->method()->name() == ciSymbol::invoke_name() && + caller_jvms->method()->holder()->name() == ciSymbol::java_dyn_MethodHandle()) + || caller_jvms->method()->holder()->name() == ciSymbol::java_dyn_InvokeDynamic()) + /* @@@ FIXME: + if (caller_jvms->method()->is_method_handle_adapter()) + */ + new_depth_adjust -= 1; // don't count actions in MH or indy adapter frames + else if (callee_method->is_method_handle_invoke()) { + new_depth_adjust -= 1; // don't count method handle calls from java.dyn implem + } + if (new_depth_adjust != 0 && PrintInlining) { + stringStream nm1; caller_jvms->method()->print_name(&nm1); + stringStream nm2; callee_method->print_name(&nm2); + tty->print_cr("discounting inlining depth from %s to %s", nm1.base(), nm2.base()); + } + if (new_depth_adjust != 0 && C->log()) { + int id1 = C->log()->identify(caller_jvms->method()); + int id2 = C->log()->identify(callee_method); + C->log()->elem("inline_depth_discount caller='%d' callee='%d'", id1, id2); + } + } + InlineTree *ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _site_depth_adjust + new_depth_adjust); _subtrees.append( ilt ); NOT_PRODUCT( _count_inlines += 1; ) @@ -483,7 +524,7 @@ InlineTree *InlineTree::build_inline_tree_root() { Compile* C = Compile::current(); // Root of inline tree - InlineTree *ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F); + InlineTree *ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F, 0); return ilt; } diff --git a/hotspot/src/share/vm/opto/c2_globals.cpp b/hotspot/src/share/vm/opto/c2_globals.cpp index 5715b24ba57..40594bf940e 100644 --- a/hotspot/src/share/vm/opto/c2_globals.cpp +++ b/hotspot/src/share/vm/opto/c2_globals.cpp @@ -25,4 +25,4 @@ # include "incls/_precompiled.incl" # include "incls/_c2_globals.cpp.incl" -C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) +C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 091ad4a9bb4..fd3256ade33 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -26,7 +26,7 @@ // Defines all globals flags used by the server compiler. // -#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ +#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \ \ notproduct(intx, CompileZapFirst, 0, \ "If +ZapDeadCompiledLocals, " \ @@ -154,6 +154,12 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseLoopPredicate, true, \ + "Generate a predicate to select fast/slow loop versions") \ + \ + develop(bool, TraceLoopPredicate, false, \ + "Trace generation of loop predicates") \ + \ develop(bool, OptoCoalesce, true, \ "Use Conservative Copy Coalescing in the Register Allocator") \ \ @@ -394,6 +400,12 @@ product(bool, UseOptoBiasInlining, true, \ "Generate biased locking code in C2 ideal graph") \ \ + product(bool, OptimizeStringConcat, false, \ + "Optimize the construction of Strings by StringBuilder") \ + \ + notproduct(bool, PrintOptimizeStringConcat, false, \ + "Print information about transformations performed on Strings") \ + \ product(intx, ValueSearchLimit, 1000, \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ \ @@ -413,4 +425,4 @@ 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) +C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index 8ce7c0ce57d..37272feb19e 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.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 @@ -98,12 +98,21 @@ JVMState* ParseGenerator::generate(JVMState* jvms) { //---------------------------DirectCallGenerator------------------------------ // Internal class which handles all out-of-line calls w/o receiver type checks. class DirectCallGenerator : public CallGenerator { -public: - DirectCallGenerator(ciMethod* method) - : CallGenerator(method) + private: + CallStaticJavaNode* _call_node; + // Force separate memory and I/O projections for the exceptional + // paths to facilitate late inlinig. + bool _separate_io_proj; + + public: + DirectCallGenerator(ciMethod* method, bool separate_io_proj) + : CallGenerator(method), + _separate_io_proj(separate_io_proj) { } virtual JVMState* generate(JVMState* jvms); + + CallStaticJavaNode* call_node() const { return _call_node; } }; JVMState* DirectCallGenerator::generate(JVMState* jvms) { @@ -127,14 +136,82 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { } // Mark the call node as virtual, sort of: call->set_optimized_virtual(true); + if (method()->is_method_handle_invoke()) + call->set_method_handle_invoke(true); } kit.set_arguments_for_java_call(call); + kit.set_edges_for_java_call(call, false, _separate_io_proj); + Node* ret = kit.set_results_for_java_call(call, _separate_io_proj); + kit.push_node(method()->return_type()->basic_type(), ret); + _call_node = call; // Save the call node in case we need it later + return kit.transfer_exceptions_into_jvms(); +} + +//---------------------------DynamicCallGenerator----------------------------- +// Internal class which handles all out-of-line invokedynamic calls. +class DynamicCallGenerator : public CallGenerator { +public: + DynamicCallGenerator(ciMethod* method) + : CallGenerator(method) + { + } + virtual JVMState* generate(JVMState* jvms); +}; + +JVMState* DynamicCallGenerator::generate(JVMState* jvms) { + GraphKit kit(jvms); + + if (kit.C->log() != NULL) { + kit.C->log()->elem("dynamic_call bci='%d'", jvms->bci()); + } + + // Get the constant pool cache from the caller class. + ciMethod* caller_method = jvms->method(); + ciBytecodeStream str(caller_method); + str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. + assert(str.cur_bc() == Bytecodes::_invokedynamic, "wrong place to issue a dynamic call!"); + ciCPCache* cpcache = str.get_cpcache(); + + // Get the offset of the CallSite from the constant pool cache + // pointer. + int index = str.get_method_index(); + size_t call_site_offset = cpcache->get_f1_offset(index); + + // Load the CallSite object from the constant pool cache. + const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); + Node* cpcache_adr = kit.makecon(cpcache_ptr); + Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); + Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); + + // Load the target MethodHandle from the CallSite object. + Node* target_mh_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes()); + Node* target_mh = kit.make_load(kit.control(), target_mh_adr, TypeInstPtr::BOTTOM, T_OBJECT); + + address resolve_stub = SharedRuntime::get_resolve_opt_virtual_call_stub(); + + CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), resolve_stub, method(), kit.bci()); + // invokedynamic is treated as an optimized invokevirtual. + call->set_optimized_virtual(true); + // Take extra care (in the presence of argument motion) not to trash the SP: + call->set_method_handle_invoke(true); + + // Pass the target MethodHandle as first argument and shift the + // other arguments. + call->init_req(0 + TypeFunc::Parms, target_mh); + uint nargs = call->method()->arg_size(); + for (uint i = 1; i < nargs; i++) { + Node* arg = kit.argument(i - 1); + call->init_req(i + TypeFunc::Parms, arg); + } + kit.set_edges_for_java_call(call); Node* ret = kit.set_results_for_java_call(call); kit.push_node(method()->return_type()->basic_type(), ret); return kit.transfer_exceptions_into_jvms(); } +//--------------------------VirtualCallGenerator------------------------------ +// Internal class which handles all out-of-line calls checking receiver type. class VirtualCallGenerator : public CallGenerator { private: int _vtable_index; @@ -149,8 +226,6 @@ public: virtual JVMState* generate(JVMState* jvms); }; -//--------------------------VirtualCallGenerator------------------------------ -// Internal class which handles all out-of-line calls checking receiver type. JVMState* VirtualCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); Node* receiver = kit.argument(0); @@ -238,16 +313,124 @@ CallGenerator* CallGenerator::for_osr(ciMethod* m, int osr_bci) { return new ParseGenerator(m, expected_uses, true); } -CallGenerator* CallGenerator::for_direct_call(ciMethod* m) { +CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) { assert(!m->is_abstract(), "for_direct_call mismatch"); - return new DirectCallGenerator(m); + return new DirectCallGenerator(m, separate_io_proj); +} + +CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) { + assert(m->is_method_handle_invoke(), "for_dynamic_call mismatch"); + return new DynamicCallGenerator(m); } CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { assert(!m->is_static(), "for_virtual_call mismatch"); + assert(!m->is_method_handle_invoke(), "should be a direct call"); return new VirtualCallGenerator(m, vtable_index); } +// Allow inlining decisions to be delayed +class LateInlineCallGenerator : public DirectCallGenerator { + CallGenerator* _inline_cg; + + public: + LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) : + DirectCallGenerator(method, true), _inline_cg(inline_cg) {} + + virtual bool is_late_inline() const { return true; } + + // Convert the CallStaticJava into an inline + virtual void do_late_inline(); + + JVMState* generate(JVMState* jvms) { + // Record that this call site should be revisited once the main + // parse is finished. + Compile::current()->add_late_inline(this); + + // Emit the CallStaticJava and request separate projections so + // that the late inlining logic can distinguish between fall + // through and exceptional uses of the memory and io projections + // as is done for allocations and macro expansion. + return DirectCallGenerator::generate(jvms); + } + +}; + + +void LateInlineCallGenerator::do_late_inline() { + // Can't inline it + if (call_node() == NULL || call_node()->outcnt() == 0 || + call_node()->in(0) == NULL || call_node()->in(0)->is_top()) + return; + + CallStaticJavaNode* call = call_node(); + + // Make a clone of the JVMState that appropriate to use for driving a parse + Compile* C = Compile::current(); + JVMState* jvms = call->jvms()->clone_shallow(C); + uint size = call->req(); + SafePointNode* map = new (C, size) SafePointNode(size, jvms); + for (uint i1 = 0; i1 < size; i1++) { + map->init_req(i1, call->in(i1)); + } + + // Make sure the state is a MergeMem for parsing. + if (!map->in(TypeFunc::Memory)->is_MergeMem()) { + map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); + } + + // Make enough space for the expression stack and transfer the incoming arguments + int nargs = method()->arg_size(); + jvms->set_map(map); + map->ensure_stack(jvms, jvms->method()->max_stack()); + if (nargs > 0) { + for (int i1 = 0; i1 < nargs; i1++) { + map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1)); + } + } + + CompileLog* log = C->log(); + if (log != NULL) { + log->head("late_inline method='%d'", log->identify(method())); + JVMState* p = jvms; + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("late_inline"); + } + + // Setup default node notes to be picked up by the inlining + Node_Notes* old_nn = C->default_node_notes(); + if (old_nn != NULL) { + Node_Notes* entry_nn = old_nn->clone(C); + entry_nn->set_jvms(jvms); + C->set_default_node_notes(entry_nn); + } + + // Now perform the inling using the synthesized JVMState + JVMState* new_jvms = _inline_cg->generate(jvms); + if (new_jvms == NULL) return; // no change + if (C->failing()) return; + + // Capture any exceptional control flow + GraphKit kit(new_jvms); + + // Find the result object + Node* result = C->top(); + int result_size = method()->return_type()->size(); + if (result_size != 0 && !kit.stopped()) { + result = (result_size == 1) ? kit.pop() : kit.pop_pair(); + } + + kit.replace_call(call, result); +} + + +CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) { + return new LateInlineCallGenerator(method, inline_cg); +} + //---------------------------WarmCallGenerator-------------------------------- // Internal class which handles initial deferral of inlining decisions. @@ -315,70 +498,7 @@ JVMState* WarmCallGenerator::generate(JVMState* jvms) { } void WarmCallInfo::make_hot() { - Compile* C = Compile::current(); - // Replace the callnode with something better. - CallJavaNode* call = this->call()->as_CallJava(); - ciMethod* method = call->method(); - int nargs = method->arg_size(); - JVMState* jvms = call->jvms()->clone_shallow(C); - uint size = TypeFunc::Parms + MAX2(2, nargs); - SafePointNode* map = new (C, size) SafePointNode(size, jvms); - for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) { - map->init_req(i1, call->in(i1)); - } - jvms->set_map(map); - jvms->set_offsets(map->req()); - jvms->set_locoff(TypeFunc::Parms); - jvms->set_stkoff(TypeFunc::Parms); - GraphKit kit(jvms); - - JVMState* new_jvms = _hot_cg->generate(kit.jvms()); - if (new_jvms == NULL) return; // no change - if (C->failing()) return; - - kit.set_jvms(new_jvms); - Node* res = C->top(); - int res_size = method->return_type()->size(); - if (res_size != 0) { - kit.inc_sp(-res_size); - res = kit.argument(0); - } - GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms()); - - // Replace the call: - for (DUIterator i = call->outs(); call->has_out(i); i++) { - Node* n = call->out(i); - Node* nn = NULL; // replacement - if (n->is_Proj()) { - ProjNode* nproj = n->as_Proj(); - assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj"); - if (nproj->_con == TypeFunc::Parms) { - nn = res; - } else { - nn = kit.map()->in(nproj->_con); - } - if (nproj->_con == TypeFunc::I_O) { - for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) { - Node* e = nproj->out(j); - if (e->Opcode() == Op_CreateEx) { - e->replace_by(ekit.argument(0)); - } else if (e->Opcode() == Op_Catch) { - for (DUIterator k = e->outs(); e->has_out(k); k++) { - CatchProjNode* p = e->out(j)->as_CatchProj(); - if (p->is_handler_proj()) { - p->replace_by(ekit.control()); - } else { - p->replace_by(kit.control()); - } - } - } - } - } - } - NOT_PRODUCT(if (!nn) n->dump(2)); - assert(nn != NULL, "don't know what to do with this user"); - n->replace_by(nn); - } + Unimplemented(); } void WarmCallInfo::make_cold() { @@ -527,6 +647,155 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) { } +//------------------------PredictedDynamicCallGenerator----------------------- +// Internal class which handles all out-of-line calls checking receiver type. +class PredictedDynamicCallGenerator : public CallGenerator { + ciMethodHandle* _predicted_method_handle; + CallGenerator* _if_missed; + CallGenerator* _if_hit; + float _hit_prob; + +public: + PredictedDynamicCallGenerator(ciMethodHandle* predicted_method_handle, + CallGenerator* if_missed, + CallGenerator* if_hit, + float hit_prob) + : CallGenerator(if_missed->method()), + _predicted_method_handle(predicted_method_handle), + _if_missed(if_missed), + _if_hit(if_hit), + _hit_prob(hit_prob) + {} + + virtual bool is_inline() const { return _if_hit->is_inline(); } + virtual bool is_deferred() const { return _if_hit->is_deferred(); } + + virtual JVMState* generate(JVMState* jvms); +}; + + +CallGenerator* CallGenerator::for_predicted_dynamic_call(ciMethodHandle* predicted_method_handle, + CallGenerator* if_missed, + CallGenerator* if_hit, + float hit_prob) { + return new PredictedDynamicCallGenerator(predicted_method_handle, if_missed, if_hit, hit_prob); +} + + +JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) { + GraphKit kit(jvms); + PhaseGVN& gvn = kit.gvn(); + + CompileLog* log = kit.C->log(); + if (log != NULL) { + log->elem("predicted_dynamic_call bci='%d'", jvms->bci()); + } + + // Get the constant pool cache from the caller class. + ciMethod* caller_method = jvms->method(); + ciBytecodeStream str(caller_method); + str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. + ciCPCache* cpcache = str.get_cpcache(); + + // Get the offset of the CallSite from the constant pool cache + // pointer. + int index = str.get_method_index(); + size_t call_site_offset = cpcache->get_f1_offset(index); + + // Load the CallSite object from the constant pool cache. + const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); + Node* cpcache_adr = kit.makecon(cpcache_ptr); + Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); + Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); + + // Load the target MethodHandle from the CallSite object. + Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes()); + Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT); + + // Check if the MethodHandle is still the same. + const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true); + Node* predicted_mh = kit.makecon(predicted_mh_ptr); + + Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh)); + Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); + IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN); + kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff))); + Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff)); + + SafePointNode* slow_map = NULL; + JVMState* slow_jvms; + { PreserveJVMState pjvms(&kit); + kit.set_control(slow_ctl); + if (!kit.stopped()) { + slow_jvms = _if_missed->generate(kit.sync_jvms()); + assert(slow_jvms != NULL, "miss path must not fail to generate"); + kit.add_exception_states_from(slow_jvms); + kit.set_map(slow_jvms->map()); + if (!kit.stopped()) + slow_map = kit.stop(); + } + } + + if (kit.stopped()) { + // Instance exactly does not matches the desired type. + kit.set_jvms(slow_jvms); + return kit.transfer_exceptions_into_jvms(); + } + + // Make the hot call: + JVMState* new_jvms = _if_hit->generate(kit.sync_jvms()); + if (new_jvms == NULL) { + // Inline failed, so make a direct call. + assert(_if_hit->is_inline(), "must have been a failed inline"); + CallGenerator* cg = CallGenerator::for_direct_call(_if_hit->method()); + new_jvms = cg->generate(kit.sync_jvms()); + } + kit.add_exception_states_from(new_jvms); + kit.set_jvms(new_jvms); + + // Need to merge slow and fast? + if (slow_map == NULL) { + // The fast path is the only path remaining. + return kit.transfer_exceptions_into_jvms(); + } + + if (kit.stopped()) { + // Inlined method threw an exception, so it's just the slow path after all. + kit.set_jvms(slow_jvms); + return kit.transfer_exceptions_into_jvms(); + } + + // Finish the diamond. + kit.C->set_has_split_ifs(true); // Has chance for split-if optimization + RegionNode* region = new (kit.C, 3) RegionNode(3); + region->init_req(1, kit.control()); + region->init_req(2, slow_map->control()); + kit.set_control(gvn.transform(region)); + Node* iophi = PhiNode::make(region, kit.i_o(), Type::ABIO); + iophi->set_req(2, slow_map->i_o()); + kit.set_i_o(gvn.transform(iophi)); + kit.merge_memory(slow_map->merged_memory(), region, 2); + uint tos = kit.jvms()->stkoff() + kit.sp(); + uint limit = slow_map->req(); + for (uint i = TypeFunc::Parms; i < limit; i++) { + // Skip unused stack slots; fast forward to monoff(); + if (i == tos) { + i = kit.jvms()->monoff(); + if( i >= limit ) break; + } + Node* m = kit.map()->in(i); + Node* n = slow_map->in(i); + if (m != n) { + const Type* t = gvn.type(m)->meet(gvn.type(n)); + Node* phi = PhiNode::make(region, m, t); + phi->set_req(2, n); + kit.map()->set_req(i, gvn.transform(phi)); + } + } + return kit.transfer_exceptions_into_jvms(); +} + + //-------------------------UncommonTrapCallGenerator----------------------------- // Internal class which handles all out-of-line calls checking receiver type. class UncommonTrapCallGenerator : public CallGenerator { diff --git a/hotspot/src/share/vm/opto/callGenerator.hpp b/hotspot/src/share/vm/opto/callGenerator.hpp index bbd47ca4aab..ecc7a4ac2e4 100644 --- a/hotspot/src/share/vm/opto/callGenerator.hpp +++ b/hotspot/src/share/vm/opto/callGenerator.hpp @@ -57,6 +57,13 @@ class CallGenerator : public ResourceObj { // is_trap: Does not return to the caller. (E.g., uncommon trap.) virtual bool is_trap() const { return false; } + // is_late_inline: supports conversion of call into an inline + virtual bool is_late_inline() const { return false; } + // Replace the call with an inline version of the code + virtual void do_late_inline() { ShouldNotReachHere(); } + + virtual CallStaticJavaNode* call_node() const { ShouldNotReachHere(); return NULL; } + // Note: It is possible for a CG to be both inline and virtual. // (The hashCode intrinsic does a vtable check and an inlined fast path.) @@ -92,9 +99,13 @@ class CallGenerator : public ResourceObj { static CallGenerator* for_osr(ciMethod* m, int osr_bci); // How to generate vanilla out-of-line call sites: - static CallGenerator* for_direct_call(ciMethod* m); // static, special + static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special + static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface + // How to generate a replace a direct call with an inline version + static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg); + // How to make a call but defer the decision whether to inline or not. static CallGenerator* for_warm_call(WarmCallInfo* ci, CallGenerator* if_cold, @@ -106,6 +117,12 @@ class CallGenerator : public ResourceObj { CallGenerator* if_hit, float hit_prob); + // How to make a call that optimistically assumes a MethodHandle target: + static CallGenerator* for_predicted_dynamic_call(ciMethodHandle* predicted_method_handle, + CallGenerator* if_missed, + CallGenerator* if_hit, + float hit_prob); + // How to make a call that gives up and goes back to the interpreter: static CallGenerator* for_uncommon_trap(ciMethod* m, Deoptimization::DeoptReason reason, diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 5c69109b8fe..a5902713111 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -693,6 +693,84 @@ Node *CallNode::result_cast() { } +void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj) { + projs->fallthrough_proj = NULL; + projs->fallthrough_catchproj = NULL; + projs->fallthrough_ioproj = NULL; + projs->catchall_ioproj = NULL; + projs->catchall_catchproj = NULL; + projs->fallthrough_memproj = NULL; + projs->catchall_memproj = NULL; + projs->resproj = NULL; + projs->exobj = NULL; + + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + ProjNode *pn = fast_out(i)->as_Proj(); + if (pn->outcnt() == 0) continue; + switch (pn->_con) { + case TypeFunc::Control: + { + // For Control (fallthrough) and I_O (catch_all_index) we have CatchProj -> Catch -> Proj + projs->fallthrough_proj = pn; + DUIterator_Fast jmax, j = pn->fast_outs(jmax); + const Node *cn = pn->fast_out(j); + if (cn->is_Catch()) { + ProjNode *cpn = NULL; + for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) { + cpn = cn->fast_out(k)->as_Proj(); + assert(cpn->is_CatchProj(), "must be a CatchProjNode"); + if (cpn->_con == CatchProjNode::fall_through_index) + projs->fallthrough_catchproj = cpn; + else { + assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index."); + projs->catchall_catchproj = cpn; + } + } + } + break; + } + case TypeFunc::I_O: + if (pn->_is_io_use) + projs->catchall_ioproj = pn; + else + projs->fallthrough_ioproj = pn; + for (DUIterator j = pn->outs(); pn->has_out(j); j++) { + Node* e = pn->out(j); + if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj()) { + assert(projs->exobj == NULL, "only one"); + projs->exobj = e; + } + } + break; + case TypeFunc::Memory: + if (pn->_is_io_use) + projs->catchall_memproj = pn; + else + projs->fallthrough_memproj = pn; + break; + case TypeFunc::Parms: + projs->resproj = pn; + break; + default: + assert(false, "unexpected projection from allocation node."); + } + } + + // The resproj may not exist because the result couuld be ignored + // and the exception object may not exist if an exception handler + // swallows the exception but all the other must exist and be found. + assert(projs->fallthrough_proj != NULL, "must be found"); + assert(projs->fallthrough_catchproj != NULL, "must be found"); + assert(projs->fallthrough_memproj != NULL, "must be found"); + assert(projs->fallthrough_ioproj != NULL, "must be found"); + assert(projs->catchall_catchproj != NULL, "must be found"); + if (separate_io_proj) { + assert(projs->catchall_memproj != NULL, "must be found"); + assert(projs->catchall_ioproj != NULL, "must be found"); + } +} + + //============================================================================= uint CallJavaNode::size_of() const { return sizeof(*this); } uint CallJavaNode::cmp( const Node &n ) const { diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index ac886f3ba99..e3bd8906d95 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -470,6 +470,23 @@ public: #endif }; + +// Simple container for the outgoing projections of a call. Useful +// for serious surgery on calls. +class CallProjections : public StackObj { +public: + Node* fallthrough_proj; + Node* fallthrough_catchproj; + Node* fallthrough_memproj; + Node* fallthrough_ioproj; + Node* catchall_catchproj; + Node* catchall_memproj; + Node* catchall_ioproj; + Node* resproj; + Node* exobj; +}; + + //------------------------------CallNode--------------------------------------- // Call nodes now subsume the function of debug nodes at callsites, so they // contain the functionality of a full scope chain of debug nodes. @@ -521,6 +538,11 @@ public: // or returns NULL if there is no one. Node *result_cast(); + // Collect all the interesting edges from a call for use in + // replacing the call by something else. Used by macro expansion + // and the late inlining support. + void extract_projections(CallProjections* projs, bool separate_io_proj); + virtual uint match_edge(uint idx) const; #ifndef PRODUCT @@ -529,6 +551,7 @@ public: #endif }; + //------------------------------CallJavaNode----------------------------------- // Make a static or dynamic subroutine call node using Java calling // convention. (The "Java" calling convention is the compiler's calling @@ -539,12 +562,15 @@ protected: virtual uint size_of() const; // Size is bigger bool _optimized_virtual; + bool _method_handle_invoke; ciMethod* _method; // Method being direct called public: const int _bci; // Byte Code Index of call byte code CallJavaNode(const TypeFunc* tf , address addr, ciMethod* method, int bci) : CallNode(tf, addr, TypePtr::BOTTOM), - _method(method), _bci(bci), _optimized_virtual(false) + _method(method), _bci(bci), + _optimized_virtual(false), + _method_handle_invoke(false) { init_class_id(Class_CallJava); } @@ -554,6 +580,8 @@ public: void set_method(ciMethod *m) { _method = m; } void set_optimized_virtual(bool f) { _optimized_virtual = f; } bool is_optimized_virtual() const { return _optimized_virtual; } + void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } + bool is_method_handle_invoke() const { return _method_handle_invoke; } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index ecffd2f4e6a..84102e1553c 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -224,6 +224,32 @@ bool Compile::valid_bundle_info(const Node *n) { } +void Compile::gvn_replace_by(Node* n, Node* nn) { + for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) { + Node* use = n->last_out(i); + bool is_in_table = initial_gvn()->hash_delete(use); + uint uses_found = 0; + for (uint j = 0; j < use->len(); j++) { + if (use->in(j) == n) { + if (j < use->req()) + use->set_req(j, nn); + else + use->set_prec(j, nn); + uses_found++; + } + } + if (is_in_table) { + // reinsert into table + initial_gvn()->hash_find_insert(use); + } + record_for_igvn(use); + i -= uses_found; // we deleted 1 or more copies of this edge + } +} + + + + // Identify all nodes that are reachable from below, useful. // Use breadth-first pass that records state in a Unique_Node_List, // recursive traversal is slower. @@ -554,6 +580,28 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr rethrow_exceptions(kit.transfer_exceptions_into_jvms()); } + if (!failing() && has_stringbuilder()) { + { + // remove useless nodes to make the usage analysis simpler + ResourceMark rm; + PhaseRemoveUseless pru(initial_gvn(), &for_igvn); + } + + { + ResourceMark rm; + print_method("Before StringOpts", 3); + PhaseStringOpts pso(initial_gvn(), &for_igvn); + print_method("After StringOpts", 3); + } + + // now inline anything that we skipped the first time around + while (_late_inlines.length() > 0) { + CallGenerator* cg = _late_inlines.pop(); + cg->do_late_inline(); + } + } + assert(_late_inlines.length() == 0, "should have been processed"); + print_method("Before RemoveUseless", 3); // Remove clutter produced by parsing. @@ -820,6 +868,7 @@ void Compile::Init(int aliaslevel) { _fixed_slots = 0; set_has_split_ifs(false); set_has_loops(has_method() && method()->has_loops()); // first approximation + set_has_stringbuilder(false); _deopt_happens = true; // start out assuming the worst _trap_can_recompile = false; // no traps emitted yet _major_progress = true; // start out assuming good things will happen @@ -883,6 +932,7 @@ void Compile::Init(int aliaslevel) { _intrinsics = NULL; _macro_nodes = new GrowableArray(comp_arena(), 8, 0, NULL); + _predicate_opaqs = new GrowableArray(comp_arena(), 8, 0, NULL); register_library_intrinsics(); } @@ -1504,6 +1554,19 @@ void Compile::Finish_Warm() { } } +//---------------------cleanup_loop_predicates----------------------- +// Remove the opaque nodes that protect the predicates so that all unused +// checks and uncommon_traps will be eliminated from the ideal graph +void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) { + if (predicate_count()==0) return; + for (int i = predicate_count(); i > 0; i--) { + Node * n = predicate_opaque1_node(i-1); + assert(n->Opcode() == Op_Opaque1, "must be"); + igvn.replace_node(n, n->in(1)); + } + assert(predicate_count()==0, "should be clean!"); + igvn.optimize(); +} //------------------------------Optimize--------------------------------------- // Given a graph, optimize it. @@ -1545,7 +1608,7 @@ void Compile::Optimize() { if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) { { TracePhase t2("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, true ); + PhaseIdealLoop ideal_loop( igvn, true, UseLoopPredicate); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 1", 2); if (failing()) return; @@ -1553,7 +1616,7 @@ void Compile::Optimize() { // Loop opts pass if partial peeling occurred in previous pass if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) { TracePhase t3("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, false ); + PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 2", 2); if (failing()) return; @@ -1561,7 +1624,7 @@ void Compile::Optimize() { // Loop opts pass for loop-unrolling before CCP if(major_progress() && (loop_opts_cnt > 0)) { TracePhase t4("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, false ); + PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 3", 2); } @@ -1599,13 +1662,21 @@ void Compile::Optimize() { // peeling, unrolling, etc. if(loop_opts_cnt > 0) { debug_only( int cnt = 0; ); + bool loop_predication = UseLoopPredicate; while(major_progress() && (loop_opts_cnt > 0)) { TracePhase t2("idealLoop", &_t_idealLoop, true); assert( cnt++ < 40, "infinite cycle in loop optimization" ); - PhaseIdealLoop ideal_loop( igvn, true ); + PhaseIdealLoop ideal_loop( igvn, true, loop_predication); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop iterations", 2); if (failing()) return; + // Perform loop predication optimization during first iteration after CCP. + // After that switch it off and cleanup unused loop predicates. + if (loop_predication) { + loop_predication = false; + cleanup_loop_predicates(igvn); + if (failing()) return; + } } } @@ -1803,6 +1874,7 @@ void Compile::dump_asm(int *pcs, uint pc_limit) { !n->is_Phi() && // a few noisely useless nodes !n->is_Proj() && !n->is_MachTemp() && + !n->is_SafePointScalarObject() && !n->is_Catch() && // Would be nice to print exception table targets !n->is_MergeMem() && // Not very interesting !n->is_top() && // Debug info table constants @@ -2240,6 +2312,30 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) { break; } + case Op_Proj: { + if (OptimizeStringConcat) { + ProjNode* p = n->as_Proj(); + if (p->_is_io_use) { + // Separate projections were used for the exception path which + // are normally removed by a late inline. If it wasn't inlined + // then they will hang around and should just be replaced with + // the original one. + Node* proj = NULL; + // Replace with just one + for (SimpleDUIterator i(p->in(0)); i.has_next(); i.next()) { + Node *use = i.get(); + if (use->is_Proj() && p != use && use->as_Proj()->_con == p->_con) { + proj = use; + break; + } + } + assert(p != NULL, "must be found"); + p->subsume_by(proj); + } + } + break; + } + case Op_Phi: if (n->as_Phi()->bottom_type()->isa_narrowoop()) { // The EncodeP optimization may create Phi with the same edges diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 4bd1900fc70..c683110355d 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -38,6 +38,7 @@ class Node_Notes; class OptoReg; class PhaseCFG; class PhaseGVN; +class PhaseIterGVN; class PhaseRegAlloc; class PhaseCCP; class PhaseCCP_DCE; @@ -149,6 +150,7 @@ class Compile : public Phase { bool _has_loops; // True if the method _may_ have some loops bool _has_split_ifs; // True if the method _may_ have some split-if bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores. + bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated uint _trap_hist[trapHistLength]; // Cumulative traps bool _trap_can_recompile; // Have we emitted a recompiling trap? uint _decompile_count; // Cumulative decompilation counts. @@ -171,6 +173,7 @@ class Compile : public Phase { const char* _failure_reason; // for record_failure/failing pattern GrowableArray* _intrinsics; // List of intrinsics. GrowableArray* _macro_nodes; // List of nodes which need to be expanded before matching. + GrowableArray* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates. ConnectionGraph* _congraph; #ifndef PRODUCT IdealGraphPrinter* _printer; @@ -219,6 +222,9 @@ class Compile : public Phase { Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN WarmCallInfo* _warm_calls; // Sorted work-list for heat-based inlining. + GrowableArray _late_inlines; // List of CallGenerators to be revisited after + // main parsing has finished. + // Matching, CFG layout, allocation, code generation PhaseCFG* _cfg; // Results of CFG finding bool _select_24_bit_instr; // We selected an instruction with a 24-bit result @@ -298,6 +304,8 @@ class Compile : public Phase { void set_has_split_ifs(bool z) { _has_split_ifs = z; } bool has_unsafe_access() const { return _has_unsafe_access; } void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } + bool has_stringbuilder() const { return _has_stringbuilder; } + void set_has_stringbuilder(bool z) { _has_stringbuilder = z; } void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; } uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; } bool trap_can_recompile() const { return _trap_can_recompile; } @@ -345,7 +353,9 @@ class Compile : public Phase { } int macro_count() { return _macro_nodes->length(); } + int predicate_count() { return _predicate_opaqs->length();} Node* macro_node(int idx) { return _macro_nodes->at(idx); } + Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);} ConnectionGraph* congraph() { return _congraph;} void add_macro_node(Node * n) { //assert(n->is_macro(), "must be a macro node"); @@ -357,7 +367,19 @@ class Compile : public Phase { // that the node is in the array before attempting to remove it if (_macro_nodes->contains(n)) _macro_nodes->remove(n); + // remove from _predicate_opaqs list also if it is there + if (predicate_count() > 0 && _predicate_opaqs->contains(n)){ + _predicate_opaqs->remove(n); + } } + void add_predicate_opaq(Node * n) { + assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1"); + assert(_macro_nodes->contains(n), "should have already been in macro list"); + _predicate_opaqs->append(n); + } + // remove the opaque nodes that protect the predicates so that the unused checks and + // uncommon traps will be eliminated from the graph. + void cleanup_loop_predicates(PhaseIterGVN &igvn); // Compilation environment. Arena* comp_arena() { return &_comp_arena; } @@ -475,6 +497,7 @@ class Compile : public Phase { // Decide how to build a call. // The profile factor is a discount to apply to this site's interp. profile. CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor); + bool should_delay_inlining(ciMethod* call_method, JVMState* jvms); // Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. @@ -495,6 +518,11 @@ class Compile : public Phase { void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; } void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; } + // Replace n by nn using initial_gvn, calling hash_delete and + // record_for_igvn as needed. + void gvn_replace_by(Node* n, Node* nn); + + void identify_useful_nodes(Unique_Node_List &useful); void remove_useless_nodes (Unique_Node_List &useful); @@ -502,6 +530,9 @@ class Compile : public Phase { void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; } WarmCallInfo* pop_warm_call(); + // Record this CallGenerator for inlining at the end of parsing. + void add_late_inline(CallGenerator* cg) { _late_inlines.push(cg); } + // Matching, CFG layout, allocation, code generation PhaseCFG* cfg() { return _cfg; } bool select_24_bit_instr() const { return _select_24_bit_instr; } diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index a81e3b1942f..bc3c5ac9f7e 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -114,7 +114,8 @@ static Node *transform_int_divide( PhaseGVN *phase, Node *dividend, jint divisor if( andconi_t && andconi_t->is_con() ) { jint andconi = andconi_t->get_con(); if( andconi < 0 && is_power_of_2(-andconi) && (-andconi) >= d ) { - dividend = dividend->in(1); + if( (-andconi) == d ) // Remove AND if it clears bits which will be shifted + dividend = dividend->in(1); needs_rounding = false; } } @@ -356,7 +357,8 @@ static Node *transform_long_divide( PhaseGVN *phase, Node *dividend, jlong divis if( andconl_t && andconl_t->is_con() ) { jlong andconl = andconl_t->get_con(); if( andconl < 0 && is_power_of_2_long(-andconl) && (-andconl) >= d ) { - dividend = dividend->in(1); + if( (-andconl) == d ) // Remove AND if it clears bits which will be shifted + dividend = dividend->in(1); needs_rounding = false; } } diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index 5104e648aa6..c000a7e80fb 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -43,7 +43,9 @@ void trace_type_profile(ciMethod *method, int depth, int bci, ciMethod *prof_met } #endif -CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float prof_factor) { +CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, + JVMState* jvms, bool allow_inline, + float prof_factor) { CallGenerator* cg; // Dtrace currently doesn't work unless all calls are vanilla @@ -116,7 +118,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, // TO DO: When UseOldInlining is removed, copy the ILT code elsewhere. float site_invoke_ratio = prof_factor; // Note: ilt is for the root of this parse, not the present call site. - ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio); + ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, 0); } WarmCallInfo scratch_ci; if (!UseOldInlining) @@ -128,6 +130,12 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, if (allow_inline) { CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses); + if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) { + // Delay the inlining of this method to give us the + // opportunity to perform some high level optimizations + // first. + return CallGenerator::for_late_inline(call_method, cg); + } if (cg == NULL) { // Fall through. } else if (require_inline || !InlineWarmCalls) { @@ -218,6 +226,57 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, } } + // Do MethodHandle calls. + if (call_method->is_method_handle_invoke()) { + if (jvms->method()->java_code_at_bci(jvms->bci()) != Bytecodes::_invokedynamic) { + GraphKit kit(jvms); + Node* n = kit.argument(0); + + if (n->Opcode() == Op_ConP) { + const TypeOopPtr* oop_ptr = n->bottom_type()->is_oopptr(); + ciObject* const_oop = oop_ptr->const_oop(); + ciMethodHandle* method_handle = const_oop->as_method_handle(); + + // Set the actually called method to have access to the class + // and signature in the MethodHandleCompiler. + method_handle->set_callee(call_method); + + // Get an adapter for the MethodHandle. + ciMethod* target_method = method_handle->get_method_handle_adapter(); + + CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + if (hit_cg != NULL && hit_cg->is_inline()) + return hit_cg; + } + + return CallGenerator::for_direct_call(call_method); + } + else { + // Get the MethodHandle from the CallSite. + ciMethod* caller_method = jvms->method(); + ciBytecodeStream str(caller_method); + str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. + ciCallSite* call_site = str.get_call_site(); + ciMethodHandle* method_handle = call_site->get_target(); + + // Set the actually called method to have access to the class + // and signature in the MethodHandleCompiler. + method_handle->set_callee(call_method); + + // Get an adapter for the MethodHandle. + ciMethod* target_method = method_handle->get_invokedynamic_adapter(); + + CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + if (hit_cg != NULL && hit_cg->is_inline()) { + CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method); + return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor); + } + + // If something failed, generate a normal dynamic call. + return CallGenerator::for_dynamic_call(call_method); + } + } + // There was no special inlining tactic, or it bailed out. // Use a more generic tactic, like a simple call. if (call_is_virtual) { @@ -225,10 +284,63 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, } else { // Class Hierarchy Analysis or Type Profile reveals a unique target, // or it is a static or special call. - return CallGenerator::for_direct_call(call_method); + return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms)); } } +// Return true for methods that shouldn't be inlined early so that +// they are easier to analyze and optimize as intrinsics. +bool Compile::should_delay_inlining(ciMethod* call_method, JVMState* jvms) { + if (has_stringbuilder()) { + + if ((call_method->holder() == C->env()->StringBuilder_klass() || + call_method->holder() == C->env()->StringBuffer_klass()) && + (jvms->method()->holder() == C->env()->StringBuilder_klass() || + jvms->method()->holder() == C->env()->StringBuffer_klass())) { + // Delay SB calls only when called from non-SB code + return false; + } + + switch (call_method->intrinsic_id()) { + case vmIntrinsics::_StringBuilder_void: + case vmIntrinsics::_StringBuilder_int: + case vmIntrinsics::_StringBuilder_String: + case vmIntrinsics::_StringBuilder_append_char: + case vmIntrinsics::_StringBuilder_append_int: + case vmIntrinsics::_StringBuilder_append_String: + case vmIntrinsics::_StringBuilder_toString: + case vmIntrinsics::_StringBuffer_void: + case vmIntrinsics::_StringBuffer_int: + case vmIntrinsics::_StringBuffer_String: + case vmIntrinsics::_StringBuffer_append_char: + case vmIntrinsics::_StringBuffer_append_int: + case vmIntrinsics::_StringBuffer_append_String: + case vmIntrinsics::_StringBuffer_toString: + case vmIntrinsics::_Integer_toString: + return true; + + case vmIntrinsics::_String_String: + { + Node* receiver = jvms->map()->in(jvms->argoff() + 1); + if (receiver->is_Proj() && receiver->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = receiver->in(0)->as_CallStaticJava(); + ciMethod* m = csj->method(); + if (m != NULL && + (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || + m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) + // Delay String.(new SB()) + return true; + } + return false; + } + + default: + return false; + } + } + return false; +} + // uncommon-trap call-sites where callee is unloaded, uninitialized or will not link bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) { @@ -240,7 +352,7 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl // Interface classes can be loaded & linked and never get around to // being initialized. Uncommon-trap for not-initialized static or // v-calls. Let interface calls happen. - ciInstanceKlass* holder_klass = dest_method->holder(); + ciInstanceKlass* holder_klass = dest_method->holder(); if (!holder_klass->is_initialized() && !holder_klass->is_interface()) { uncommon_trap(Deoptimization::Reason_uninitialized, @@ -248,14 +360,6 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl holder_klass); return true; } - if (dest_method->is_method_handle_invoke() - && holder_klass->name() == ciSymbol::java_dyn_Dynamic()) { - // FIXME: NYI - uncommon_trap(Deoptimization::Reason_unhandled, - Deoptimization::Action_none, - holder_klass); - return true; - } assert(dest_method->will_link(method()->holder(), klass, bc()), "dest_method: typeflow responsibility"); return false; @@ -274,6 +378,7 @@ void Parse::do_call() { bool is_virtual = bc() == Bytecodes::_invokevirtual; bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface; bool has_receiver = is_virtual_or_interface || bc() == Bytecodes::_invokespecial; + bool is_invokedynamic = bc() == Bytecodes::_invokedynamic; // Find target being called bool will_link; @@ -282,7 +387,8 @@ void Parse::do_call() { ciKlass* holder = iter().get_declared_method_holder(); ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - int nargs = dest_method->arg_size(); + int nargs = dest_method->arg_size(); + if (is_invokedynamic) nargs -= 1; // uncommon-trap when callee is unloaded, uninitialized or will not link // bailout when too many arguments for register representation @@ -296,7 +402,7 @@ void Parse::do_call() { return; } assert(holder_klass->is_loaded(), ""); - assert(dest_method->is_static() == !has_receiver, "must match bc"); + assert((dest_method->is_static() || is_invokedynamic) == !has_receiver , "must match bc"); // Note: this takes into account invokeinterface of methods declared in java/lang/Object, // which should be invokevirtuals but according to the VM spec may be invokeinterfaces assert(holder_klass->is_interface() || holder_klass->super() == NULL || (bc() != Bytecodes::_invokeinterface), "must match bc"); diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index b22f4814a57..111443cd1ae 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -537,11 +537,13 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) { } const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr(); - // Do NOT remove the next call: ensure an new alias index is allocated - // for the instance type + // Do NOT remove the next line: ensure a new alias index is allocated + // for the instance type. Note: C++ will not remove it since the call + // has side effect. int alias_idx = _compile->get_alias_index(tinst); igvn->set_type(addp, tinst); // record the allocation in the node map + assert(ptnode_adr(addp->_idx)->_node != NULL, "should be registered"); set_map(addp->_idx, get_map(base->_idx)); // Set addp's Base and Address to 'base'. @@ -617,9 +619,14 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro const TypePtr *atype = C->get_adr_type(alias_idx); result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype); C->copy_node_notes_to(result, orig_phi); - set_map_phi(orig_phi->_idx, result); igvn->set_type(result, result->bottom_type()); record_for_optimizer(result); + + debug_only(Node* pn = ptnode_adr(orig_phi->_idx)->_node;) + assert(pn == NULL || pn == orig_phi, "wrong node"); + set_map(orig_phi->_idx, result); + ptnode_adr(orig_phi->_idx)->_node = orig_phi; + new_created = true; return result; } @@ -709,6 +716,81 @@ static Node *step_through_mergemem(MergeMemNode *mmem, int alias_idx, const Type return mem; } +// +// Move memory users to their memory slices. +// +void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phis, PhaseGVN *igvn) { + Compile* C = _compile; + + const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr(); + assert(tp != NULL, "ptr type"); + int alias_idx = C->get_alias_index(tp); + int general_idx = C->get_general_index(alias_idx); + + // Move users first + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); + if (use->is_MergeMem()) { + MergeMemNode* mmem = use->as_MergeMem(); + assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice"); + if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) { + continue; // Nothing to do + } + // Replace previous general reference to mem node. + uint orig_uniq = C->unique(); + Node* m = find_inst_mem(n, general_idx, orig_phis, igvn); + assert(orig_uniq == C->unique(), "no new nodes"); + mmem->set_memory_at(general_idx, m); + --imax; + --i; + } else if (use->is_MemBar()) { + assert(!use->is_Initialize(), "initializing stores should not be moved"); + if (use->req() > MemBarNode::Precedent && + use->in(MemBarNode::Precedent) == n) { + // Don't move related membars. + record_for_optimizer(use); + continue; + } + tp = use->as_MemBar()->adr_type()->isa_ptr(); + if (tp != NULL && C->get_alias_index(tp) == alias_idx || + alias_idx == general_idx) { + continue; // Nothing to do + } + // Move to general memory slice. + uint orig_uniq = C->unique(); + Node* m = find_inst_mem(n, general_idx, orig_phis, igvn); + assert(orig_uniq == C->unique(), "no new nodes"); + igvn->hash_delete(use); + imax -= use->replace_edge(n, m); + igvn->hash_insert(use); + record_for_optimizer(use); + --i; +#ifdef ASSERT + } else if (use->is_Mem()) { + if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { + // Don't move related cardmark. + continue; + } + // Memory nodes should have new memory input. + tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); + assert(tp != NULL, "ptr type"); + int idx = C->get_alias_index(tp); + assert(get_map(use->_idx) != NULL || idx == alias_idx, + "Following memory nodes should have new memory input or be on the same memory slice"); + } else if (use->is_Phi()) { + // Phi nodes should be split and moved already. + tp = use->as_Phi()->adr_type()->isa_ptr(); + assert(tp != NULL, "ptr type"); + int idx = C->get_alias_index(tp); + assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice"); + } else { + use->dump(); + assert(false, "should not be here"); +#endif + } + } +} + // // Search memory chain of "mem" to find a MemNode whose address // is the specified alias index. @@ -774,10 +856,18 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) { Node *un = result->as_Phi()->unique_input(phase); if (un != NULL) { + orig_phis.append_if_missing(result->as_Phi()); result = un; } else { break; } + } else if (result->is_ClearArray()) { + if (!ClearArrayNode::step_through(&result, (uint)tinst->instance_id(), phase)) { + // Can not bypass initialization of the instance + // we are looking for. + break; + } + // Otherwise skip it (the call updated 'result' value). } else if (result->Opcode() == Op_SCMemProj) { assert(result->in(0)->is_LoadStore(), "sanity"); const Type *at = phase->type(result->in(0)->in(MemNode::Address)); @@ -807,7 +897,6 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra return result; } - // // Convert the types of unescaped object to instance types where possible, // propagate the new type information through the graph, and update memory @@ -899,12 +988,13 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra // void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) { GrowableArray memnode_worklist; - GrowableArray mergemem_worklist; GrowableArray orig_phis; + PhaseGVN *igvn = _compile->initial_gvn(); uint new_index_start = (uint) _compile->num_alias_types(); - VectorSet visited(Thread::current()->resource_area()); - VectorSet ptset(Thread::current()->resource_area()); + Arena* arena = Thread::current()->resource_area(); + VectorSet visited(arena); + VectorSet ptset(arena); // Phase 1: Process possible allocations from alloc_worklist. @@ -980,6 +1070,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) // - non-escaping // - eligible to be a unique type // - not determined to be ineligible by escape analysis + assert(ptnode_adr(alloc->_idx)->_node != NULL && + ptnode_adr(n->_idx)->_node != NULL, "should be registered"); set_map(alloc->_idx, n); set_map(n->_idx, alloc); const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); @@ -1024,7 +1116,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) alloc_worklist.append_if_missing(addp2); } alloc_worklist.append_if_missing(use); - } else if (use->is_Initialize()) { + } else if (use->is_MemBar()) { memnode_worklist.append_if_missing(use); } } @@ -1034,10 +1126,12 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) PointsTo(ptset, get_addp_base(n), igvn); assert(ptset.Size() == 1, "AddP address is unique"); uint elem = ptset.getelem(); // Allocation node's index - if (elem == _phantom_object) + if (elem == _phantom_object) { + assert(false, "escaped allocation"); continue; // Assume the value was set outside this method. + } Node *base = get_map(elem); // CheckCastPP node - if (!split_AddP(n, base, igvn)) continue; // wrong type + if (!split_AddP(n, base, igvn)) continue; // wrong type from dead path tinst = igvn->type(base)->isa_oopptr(); } else if (n->is_Phi() || n->is_CheckCastPP() || @@ -1052,8 +1146,10 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) PointsTo(ptset, n, igvn); if (ptset.Size() == 1) { uint elem = ptset.getelem(); // Allocation node's index - if (elem == _phantom_object) + if (elem == _phantom_object) { + assert(false, "escaped allocation"); continue; // Assume the value was set outside this method. + } Node *val = get_map(elem); // CheckCastPP node TypeNode *tn = n->as_Type(); tinst = igvn->type(val)->isa_oopptr(); @@ -1068,8 +1164,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) tn_t = tn_type->isa_oopptr(); } - if (tn_t != NULL && - tinst->cast_to_instance_id(TypeOopPtr::InstanceBot)->higher_equal(tn_t)) { + if (tn_t != NULL && tinst->klass()->is_subtype_of(tn_t->klass())) { if (tn_type->isa_narrowoop()) { tn_type = tinst->make_narrowoop(); } else { @@ -1081,33 +1176,25 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) igvn->hash_insert(tn); record_for_optimizer(n); } else { - continue; // wrong type + assert(tn_type == TypePtr::NULL_PTR || + tn_t != NULL && !tinst->klass()->is_subtype_of(tn_t->klass()), + "unexpected type"); + continue; // Skip dead path with different type } } } else { + debug_only(n->dump();) + assert(false, "EA: unexpected node"); continue; } - // push users on appropriate worklist + // push allocation's users on appropriate worklist for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node *use = n->fast_out(i); if(use->is_Mem() && use->in(MemNode::Address) == n) { + // Load/store to instance's field memnode_worklist.append_if_missing(use); - } else if (use->is_Initialize()) { + } else if (use->is_MemBar()) { memnode_worklist.append_if_missing(use); - } else if (use->is_MergeMem()) { - mergemem_worklist.append_if_missing(use); - } else if (use->is_SafePoint() && tinst != NULL) { - // Look for MergeMem nodes for calls which reference unique allocation - // (through CheckCastPP nodes) even for debug info. - Node* m = use->in(TypeFunc::Memory); - uint iid = tinst->instance_id(); - while (m->is_Proj() && m->in(0)->is_SafePoint() && - m->in(0) != use && !m->in(0)->_idx != iid) { - m = m->in(0)->in(TypeFunc::Memory); - } - if (m->is_MergeMem()) { - mergemem_worklist.append_if_missing(m); - } } else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes Node* addp2 = find_second_addp(use, n); if (addp2 != NULL) { @@ -1120,6 +1207,29 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) use->is_DecodeN() || (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) { alloc_worklist.append_if_missing(use); +#ifdef ASSERT + } else if (use->is_Mem()) { + assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path"); + } else if (use->is_MergeMem()) { + assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist"); + } else if (use->is_SafePoint()) { + // Look for MergeMem nodes for calls which reference unique allocation + // (through CheckCastPP nodes) even for debug info. + Node* m = use->in(TypeFunc::Memory); + if (m->is_MergeMem()) { + assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist"); + } + } else { + uint op = use->Opcode(); + if (!(op == Op_CmpP || op == Op_Conv2B || + op == Op_CastP2X || op == Op_StoreCM || + op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || + op == Op_StrEquals || op == Op_StrIndexOf)) { + n->dump(); + use->dump(); + assert(false, "EA: missing allocation reference path"); + } +#endif } } @@ -1137,19 +1247,16 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) Node *n = memnode_worklist.pop(); if (visited.test_set(n->_idx)) continue; - if (n->is_Phi()) { - assert(n->as_Phi()->adr_type() != TypePtr::BOTTOM, "narrow memory slice required"); - // we don't need to do anything, but the users must be pushed if we haven't processed - // this Phi before - } else if (n->is_Initialize()) { - // we don't need to do anything, but the users of the memory projection must be pushed - n = n->as_Initialize()->proj_out(TypeFunc::Memory); + if (n->is_Phi() || n->is_ClearArray()) { + // we don't need to do anything, but the users must be pushed + } else if (n->is_MemBar()) { // Initialize, MemBar nodes + // we don't need to do anything, but the users must be pushed + n = n->as_MemBar()->proj_out(TypeFunc::Memory); if (n == NULL) continue; } else { assert(n->is_Mem(), "memory node required."); Node *addr = n->in(MemNode::Address); - assert(addr->is_AddP(), "AddP required"); const Type *addr_t = igvn->type(addr); if (addr_t == Type::TOP) continue; @@ -1161,6 +1268,10 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) return; } if (mem != n->in(MemNode::Memory)) { + // We delay the memory edge update since we need old one in + // MergeMem code below when instances memory slices are separated. + debug_only(Node* pn = ptnode_adr(n->_idx)->_node;) + assert(pn == NULL || pn == n, "wrong node"); set_map(n->_idx, mem); ptnode_adr(n->_idx)->_node = n; } @@ -1181,36 +1292,55 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) // push user on appropriate worklist for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node *use = n->fast_out(i); - if (use->is_Phi()) { + if (use->is_Phi() || use->is_ClearArray()) { memnode_worklist.append_if_missing(use); } else if(use->is_Mem() && use->in(MemNode::Memory) == n) { + if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores + continue; memnode_worklist.append_if_missing(use); - } else if (use->is_Initialize()) { + } else if (use->is_MemBar()) { memnode_worklist.append_if_missing(use); +#ifdef ASSERT + } else if(use->is_Mem()) { + assert(use->in(MemNode::Memory) != n, "EA: missing memory path"); } else if (use->is_MergeMem()) { - mergemem_worklist.append_if_missing(use); + assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist"); + } else { + uint op = use->Opcode(); + if (!(op == Op_StoreCM || + (op == Op_CallLeaf && use->as_CallLeaf()->_name != NULL && + strcmp(use->as_CallLeaf()->_name, "g1_wb_pre") == 0) || + op == Op_AryEq || op == Op_StrComp || + op == Op_StrEquals || op == Op_StrIndexOf)) { + n->dump(); + use->dump(); + assert(false, "EA: missing memory path"); + } +#endif } } } // Phase 3: Process MergeMem nodes from mergemem_worklist. - // Walk each memory moving the first node encountered of each + // Walk each memory slice moving the first node encountered of each // instance type to the the input corresponding to its alias index. - while (mergemem_worklist.length() != 0) { - Node *n = mergemem_worklist.pop(); - assert(n->is_MergeMem(), "MergeMem node required."); - if (visited.test_set(n->_idx)) - continue; - MergeMemNode *nmm = n->as_MergeMem(); + uint length = _mergemem_worklist.length(); + for( uint next = 0; next < length; ++next ) { + MergeMemNode* nmm = _mergemem_worklist.at(next); + assert(!visited.test_set(nmm->_idx), "should not be visited before"); // Note: we don't want to use MergeMemStream here because we only want to - // scan inputs which exist at the start, not ones we add during processing. - uint nslices = nmm->req(); + // scan inputs which exist at the start, not ones we add during processing. + // Note 2: MergeMem may already contains instance memory slices added + // during find_inst_mem() call when memory nodes were processed above. igvn->hash_delete(nmm); + uint nslices = nmm->req(); for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) { Node* mem = nmm->in(i); Node* cur = NULL; if (mem == NULL || mem->is_top()) continue; + // First, update mergemem by moving memory nodes to corresponding slices + // if their type became more precise since this mergemem was created. while (mem->is_Mem()) { const Type *at = igvn->type(mem->in(MemNode::Address)); if (at != Type::TOP) { @@ -1229,7 +1359,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) } nmm->set_memory_at(i, (cur != NULL) ? cur : mem); // Find any instance of the current type if we haven't encountered - // a value of the instance along the chain. + // already a memory slice of the instance along the memory chain. for (uint ni = new_index_start; ni < new_index_end; ni++) { if((uint)_compile->get_general_index(ni) == i) { Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); @@ -1245,11 +1375,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) } // Find the rest of instances values for (uint ni = new_index_start; ni < new_index_end; ni++) { - const TypeOopPtr *tinst = igvn->C->get_adr_type(ni)->isa_oopptr(); + const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr(); Node* result = step_through_mergemem(nmm, ni, tinst); if (result == nmm->base_memory()) { // Didn't find instance memory, search through general slice recursively. - result = nmm->memory_at(igvn->C->get_general_index(ni)); + result = nmm->memory_at(_compile->get_general_index(ni)); result = find_inst_mem(result, ni, orig_phis, igvn); if (_compile->failing()) { return; @@ -1259,41 +1389,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) } igvn->hash_insert(nmm); record_for_optimizer(nmm); - - // Propagate new memory slices to following MergeMem nodes. - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->is_Call()) { - CallNode* in = use->as_Call(); - if (in->proj_out(TypeFunc::Memory) != NULL) { - Node* m = in->proj_out(TypeFunc::Memory); - for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) { - Node* mm = m->fast_out(j); - if (mm->is_MergeMem()) { - mergemem_worklist.append_if_missing(mm); - } - } - } - if (use->is_Allocate()) { - use = use->as_Allocate()->initialization(); - if (use == NULL) { - continue; - } - } - } - if (use->is_Initialize()) { - InitializeNode* in = use->as_Initialize(); - if (in->proj_out(TypeFunc::Memory) != NULL) { - Node* m = in->proj_out(TypeFunc::Memory); - for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) { - Node* mm = m->fast_out(j); - if (mm->is_MergeMem()) { - mergemem_worklist.append_if_missing(mm); - } - } - } - } - } } // Phase 4: Update the inputs of non-instance memory Phis and @@ -1322,19 +1417,48 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) } // Update the memory inputs of MemNodes with the value we computed - // in Phase 2. + // in Phase 2 and move stores memory users to corresponding memory slices. +#ifdef ASSERT + visited.Clear(); + Node_Stack old_mems(arena, _compile->unique() >> 2); +#endif for (uint i = 0; i < nodes_size(); i++) { Node *nmem = get_map(i); if (nmem != NULL) { Node *n = ptnode_adr(i)->_node; - if (n != NULL && n->is_Mem()) { + assert(n != NULL, "sanity"); + if (n->is_Mem()) { +#ifdef ASSERT + Node* old_mem = n->in(MemNode::Memory); + if (!visited.test_set(old_mem->_idx)) { + old_mems.push(old_mem, old_mem->outcnt()); + } +#endif + assert(n->in(MemNode::Memory) != nmem, "sanity"); + if (!n->is_Load()) { + // Move memory users of a store first. + move_inst_mem(n, orig_phis, igvn); + } + // Now update memory input igvn->hash_delete(n); n->set_req(MemNode::Memory, nmem); igvn->hash_insert(n); record_for_optimizer(n); + } else { + assert(n->is_Allocate() || n->is_CheckCastPP() || + n->is_AddP() || n->is_Phi(), "unknown node used for set_map()"); } } } +#ifdef ASSERT + // Verify that memory was split correctly + while (old_mems.is_nonempty()) { + Node* old_mem = old_mems.node(); + uint old_cnt = old_mems.index(); + old_mems.pop(); + assert(old_cnt = old_mem->outcnt(), "old mem could be lost"); + } +#endif } bool ConnectionGraph::has_candidates(Compile *C) { @@ -1381,8 +1505,20 @@ bool ConnectionGraph::compute_escape() { ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { has_allocations = true; } - if(n->is_AddP()) - cg_worklist.append(n->_idx); + if(n->is_AddP()) { + // Collect address nodes which directly reference an allocation. + // Use them during stage 3 below to build initial connection graph + // field edges. Other field edges could be added after StoreP/LoadP + // nodes are processed during stage 4 below. + Node* base = get_addp_base(n); + if(base->is_Proj() && base->in(0)->is_Allocate()) { + cg_worklist.append(n->_idx); + } + } else if (n->is_MergeMem()) { + // Collect all MergeMem nodes to add memory slices for + // scalar replaceable objects in split_unique_types(). + _mergemem_worklist.append(n->as_MergeMem()); + } for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Get user worklist_init.push(m); @@ -1423,12 +1559,13 @@ bool ConnectionGraph::compute_escape() { } } - VectorSet ptset(Thread::current()->resource_area()); + Arena* arena = Thread::current()->resource_area(); + VectorSet ptset(arena); GrowableArray deferred_edges; - VectorSet visited(Thread::current()->resource_area()); + VectorSet visited(arena); - // 5. Remove deferred edges from the graph and collect - // information needed for type splitting. + // 5. Remove deferred edges from the graph and adjust + // escape state of nonescaping objects. cg_length = cg_worklist.length(); for( uint next = 0; next < cg_length; ++next ) { int ni = cg_worklist.at(next); @@ -1438,98 +1575,9 @@ bool ConnectionGraph::compute_escape() { remove_deferred(ni, &deferred_edges, &visited); Node *n = ptn->_node; if (n->is_AddP()) { - // Search for objects which are not scalar replaceable. - // Mark their escape state as ArgEscape to propagate the state - // to referenced objects. - // Note: currently there are no difference in compiler optimizations - // for ArgEscape objects and NoEscape objects which are not - // scalar replaceable. - - int offset = ptn->offset(); - Node *base = get_addp_base(n); - ptset.Clear(); - PointsTo(ptset, base, igvn); - int ptset_size = ptset.Size(); - - // Check if a field's initializing value is recorded and add - // a corresponding NULL field's value if it is not recorded. - // Connection Graph does not record a default initialization by NULL - // captured by Initialize node. - // - // Note: it will disable scalar replacement in some cases: - // - // Point p[] = new Point[1]; - // p[0] = new Point(); // Will be not scalar replaced - // - // but it will save us from incorrect optimizations in next cases: - // - // Point p[] = new Point[1]; - // if ( x ) p[0] = new Point(); // Will be not scalar replaced - // - // Without a control flow analysis we can't distinguish above cases. - // - if (offset != Type::OffsetBot && ptset_size == 1) { - uint elem = ptset.getelem(); // Allocation node's index - // It does not matter if it is not Allocation node since - // only non-escaping allocations are scalar replaced. - if (ptnode_adr(elem)->_node->is_Allocate() && - ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) { - AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate(); - InitializeNode* ini = alloc->initialization(); - Node* value = NULL; - if (ini != NULL) { - BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT; - Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn); - if (store != NULL && store->is_Store()) - value = store->in(MemNode::ValueIn); - } - if (value == NULL || value != ptnode_adr(value->_idx)->_node) { - // A field's initializing value was not recorded. Add NULL. - uint null_idx = UseCompressedOops ? _noop_null : _oop_null; - add_pointsto_edge(ni, null_idx); - } - } - } - - // An object is not scalar replaceable if the field which may point - // to it has unknown offset (unknown element of an array of objects). - // - if (offset == Type::OffsetBot) { - uint e_cnt = ptn->edge_count(); - for (uint ei = 0; ei < e_cnt; ei++) { - uint npi = ptn->edge_target(ei); - set_escape_state(npi, PointsToNode::ArgEscape); - ptnode_adr(npi)->_scalar_replaceable = false; - } - } - - // Currently an object is not scalar replaceable if a LoadStore node - // access its field since the field value is unknown after it. - // - bool has_LoadStore = false; - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->is_LoadStore()) { - has_LoadStore = true; - break; - } - } - // An object is not scalar replaceable if the address points - // to unknown field (unknown element for arrays, offset is OffsetBot). - // - // Or the address may point to more then one object. This may produce - // the false positive result (set scalar_replaceable to false) - // since the flow-insensitive escape analysis can't separate - // the case when stores overwrite the field's value from the case - // when stores happened on different control branches. - // - if (ptset_size > 1 || ptset_size != 0 && - (has_LoadStore || offset == Type::OffsetBot)) { - for( VectorSetI j(&ptset); j.test(); ++j ) { - set_escape_state(j.elem, PointsToNode::ArgEscape); - ptnode_adr(j.elem)->_scalar_replaceable = false; - } - } + // Search for objects which are not scalar replaceable + // and adjust their escape state. + verify_escape_state(ni, ptset, igvn); } } } @@ -1646,6 +1694,150 @@ bool ConnectionGraph::compute_escape() { return has_non_escaping_obj; } +// Search for objects which are not scalar replaceable. +void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase) { + PointsToNode* ptn = ptnode_adr(nidx); + Node* n = ptn->_node; + assert(n->is_AddP(), "Should be called for AddP nodes only"); + // Search for objects which are not scalar replaceable. + // Mark their escape state as ArgEscape to propagate the state + // to referenced objects. + // Note: currently there are no difference in compiler optimizations + // for ArgEscape objects and NoEscape objects which are not + // scalar replaceable. + + Compile* C = _compile; + + int offset = ptn->offset(); + Node* base = get_addp_base(n); + ptset.Clear(); + PointsTo(ptset, base, phase); + int ptset_size = ptset.Size(); + + // Check if a oop field's initializing value is recorded and add + // a corresponding NULL field's value if it is not recorded. + // Connection Graph does not record a default initialization by NULL + // captured by Initialize node. + // + // Note: it will disable scalar replacement in some cases: + // + // Point p[] = new Point[1]; + // p[0] = new Point(); // Will be not scalar replaced + // + // but it will save us from incorrect optimizations in next cases: + // + // Point p[] = new Point[1]; + // if ( x ) p[0] = new Point(); // Will be not scalar replaced + // + // Do a simple control flow analysis to distinguish above cases. + // + if (offset != Type::OffsetBot && ptset_size == 1) { + uint elem = ptset.getelem(); // Allocation node's index + // It does not matter if it is not Allocation node since + // only non-escaping allocations are scalar replaced. + if (ptnode_adr(elem)->_node->is_Allocate() && + ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) { + AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate(); + InitializeNode* ini = alloc->initialization(); + + // Check only oop fields. + const Type* adr_type = n->as_AddP()->bottom_type(); + BasicType basic_field_type = T_INT; + if (adr_type->isa_instptr()) { + ciField* field = C->alias_type(adr_type->isa_instptr())->field(); + if (field != NULL) { + basic_field_type = field->layout_type(); + } else { + // Ignore non field load (for example, klass load) + } + } else if (adr_type->isa_aryptr()) { + const Type* elemtype = adr_type->isa_aryptr()->elem(); + basic_field_type = elemtype->array_element_basic_type(); + } else { + // Raw pointers are used for initializing stores so skip it. + assert(adr_type->isa_rawptr() && base->is_Proj() && + (base->in(0) == alloc),"unexpected pointer type"); + } + if (basic_field_type == T_OBJECT || + basic_field_type == T_NARROWOOP || + basic_field_type == T_ARRAY) { + Node* value = NULL; + if (ini != NULL) { + BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT; + Node* store = ini->find_captured_store(offset, type2aelembytes(ft), phase); + if (store != NULL && store->is_Store()) { + value = store->in(MemNode::ValueIn); + } else if (ptn->edge_count() > 0) { // Are there oop stores? + // Check for a store which follows allocation without branches. + // For example, a volatile field store is not collected + // by Initialize node. TODO: it would be nice to use idom() here. + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + store = n->fast_out(i); + if (store->is_Store() && store->in(0) != NULL) { + Node* ctrl = store->in(0); + while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || + ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || + ctrl->is_IfTrue() || ctrl->is_IfFalse())) { + ctrl = ctrl->in(0); + } + if (ctrl == ini || ctrl == alloc) { + value = store->in(MemNode::ValueIn); + break; + } + } + } + } + } + if (value == NULL || value != ptnode_adr(value->_idx)->_node) { + // A field's initializing value was not recorded. Add NULL. + uint null_idx = UseCompressedOops ? _noop_null : _oop_null; + add_pointsto_edge(nidx, null_idx); + } + } + } + } + + // An object is not scalar replaceable if the field which may point + // to it has unknown offset (unknown element of an array of objects). + // + if (offset == Type::OffsetBot) { + uint e_cnt = ptn->edge_count(); + for (uint ei = 0; ei < e_cnt; ei++) { + uint npi = ptn->edge_target(ei); + set_escape_state(npi, PointsToNode::ArgEscape); + ptnode_adr(npi)->_scalar_replaceable = false; + } + } + + // Currently an object is not scalar replaceable if a LoadStore node + // access its field since the field value is unknown after it. + // + bool has_LoadStore = false; + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node *use = n->fast_out(i); + if (use->is_LoadStore()) { + has_LoadStore = true; + break; + } + } + // An object is not scalar replaceable if the address points + // to unknown field (unknown element for arrays, offset is OffsetBot). + // + // Or the address may point to more then one object. This may produce + // the false positive result (set scalar_replaceable to false) + // since the flow-insensitive escape analysis can't separate + // the case when stores overwrite the field's value from the case + // when stores happened on different control branches. + // + if (ptset_size > 1 || ptset_size != 0 && + (has_LoadStore || offset == Type::OffsetBot)) { + for( VectorSetI j(&ptset); j.test(); ++j ) { + set_escape_state(j.elem, PointsToNode::ArgEscape); + ptnode_adr(j.elem)->_scalar_replaceable = false; + } + } +} + void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { switch (call->Opcode()) { @@ -1657,6 +1849,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha assert(false, "should be done already"); break; #endif + case Op_CallLeaf: case Op_CallLeafNoFP: { // Stub calls, objects do not escape but they are not scale replaceable. @@ -1667,9 +1860,23 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha const Type* at = d->field_at(i); Node *arg = call->in(i)->uncast(); const Type *aat = phase->type(arg); - if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr()) { + if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && + ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) { + assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || aat->isa_ptr() != NULL, "expecting an Ptr"); +#ifdef ASSERT + if (!(call->Opcode() == Op_CallLeafNoFP && + call->as_CallLeaf()->_name != NULL && + (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) || + call->as_CallLeaf()->_name != NULL && + (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || + strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) + ) { + call->dump(); + assert(false, "EA: unexpected CallLeaf"); + } +#endif set_escape_state(arg->_idx, PointsToNode::ArgEscape); if (arg->is_AddP()) { // @@ -1706,9 +1913,10 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { const Type* at = d->field_at(i); int k = i - TypeFunc::Parms; + Node *arg = call->in(i)->uncast(); - if (at->isa_oopptr() != NULL) { - Node *arg = call->in(i)->uncast(); + if (at->isa_oopptr() != NULL && + ptnode_adr(arg->_idx)->escape_state() < PointsToNode::GlobalEscape) { bool global_escapes = false; bool fields_escapes = false; @@ -1942,20 +2150,23 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase) record_for_optimizer(n); _processed.set(n->_idx); } else { - // Have to process call's arguments first. + // Don't mark as processed since call's arguments have to be processed. PointsToNode::NodeType nt = PointsToNode::UnknownType; + PointsToNode::EscapeState es = PointsToNode::UnknownEscape; // Check if a call returns an object. const TypeTuple *r = n->as_Call()->tf()->range(); - if (n->is_CallStaticJava() && r->cnt() > TypeFunc::Parms && + if (r->cnt() > TypeFunc::Parms && + r->field_at(TypeFunc::Parms)->isa_ptr() && n->as_Call()->proj_out(TypeFunc::Parms) != NULL) { - // Note: use isa_ptr() instead of isa_oopptr() here because - // the _multianewarray functions return a TypeRawPtr. - if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) { - nt = PointsToNode::JavaObject; + nt = PointsToNode::JavaObject; + if (!n->is_CallStaticJava()) { + // Since the called mathod is statically unknown assume + // the worst case that the returned value globally escapes. + es = PointsToNode::GlobalEscape; } } - add_node(n, nt, PointsToNode::UnknownEscape, false); + add_node(n, nt, es, false); } return; } @@ -2088,18 +2299,27 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase) } case Op_Proj: { - // we are only interested in the result projection from a call + // we are only interested in the oop result projection from a call if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) { - add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false); - process_call_result(n->as_Proj(), phase); - if (!_processed.test(n->_idx)) { - // The call's result may need to be processed later if the call - // returns it's argument and the argument is not processed yet. - _delayed_worklist.push(n); + const TypeTuple *r = n->in(0)->as_Call()->tf()->range(); + assert(r->cnt() > TypeFunc::Parms, "sanity"); + if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) { + add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false); + int ti = n->in(0)->_idx; + // The call may not be registered yet (since not all its inputs are registered) + // if this is the projection from backbranch edge of Phi. + if (ptnode_adr(ti)->node_type() != PointsToNode::UnknownType) { + process_call_result(n->as_Proj(), phase); + } + if (!_processed.test(n->_idx)) { + // The call's result may need to be processed later if the call + // returns it's argument and the argument is not processed yet. + _delayed_worklist.push(n); + } + break; } - } else { - _processed.set(n->_idx); } + _processed.set(n->_idx); break; } case Op_Return: @@ -2160,6 +2380,15 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase) } break; } + case Op_AryEq: + case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: + { + // char[] arrays passed to string intrinsics are not scalar replaceable. + add_node(n, PointsToNode::UnknownType, PointsToNode::UnknownEscape, false); + break; + } case Op_ThreadLocal: { add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true); @@ -2174,6 +2403,7 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase) void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { uint n_idx = n->_idx; + assert(ptnode_adr(n_idx)->_node != NULL, "node should be registered"); // Don't set processed bit for AddP, LoadP, StoreP since // they may need more then one pass to process. @@ -2211,6 +2441,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { case Op_DecodeN: { int ti = n->in(1)->_idx; + assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "all nodes should be registered"); if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) { add_pointsto_edge(n_idx, ti); } else { @@ -2250,7 +2481,6 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { #endif Node* adr = n->in(MemNode::Address)->uncast(); - const Type *adr_type = phase->type(adr); Node* adr_base; if (adr->is_AddP()) { adr_base = get_addp_base(adr); @@ -2302,13 +2532,19 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { } case Op_Proj: { - // we are only interested in the result projection from a call + // we are only interested in the oop result projection from a call if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) { - process_call_result(n->as_Proj(), phase); - assert(_processed.test(n_idx), "all call results should be processed"); - } else { - assert(false, "Op_Proj"); + assert(ptnode_adr(n->in(0)->_idx)->node_type() != PointsToNode::UnknownType, + "all nodes should be registered"); + const TypeTuple *r = n->in(0)->as_Call()->tf()->range(); + assert(r->cnt() > TypeFunc::Parms, "sanity"); + if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) { + process_call_result(n->as_Proj(), phase); + assert(_processed.test(n_idx), "all call results should be processed"); + break; + } } + assert(false, "Op_Proj"); break; } case Op_Return: @@ -2320,6 +2556,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { } #endif int ti = n->in(TypeFunc::Parms)->_idx; + assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "node should be registered"); if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) { add_pointsto_edge(n_idx, ti); } else { @@ -2354,14 +2591,38 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { } break; } + case Op_AryEq: + case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: + { + // char[] arrays passed to string intrinsic do not escape but + // they are not scalar replaceable. Adjust escape state for them. + // Start from in(2) edge since in(1) is memory edge. + for (uint i = 2; i < n->req(); i++) { + Node* adr = n->in(i)->uncast(); + const Type *at = phase->type(adr); + if (!adr->is_top() && at->isa_ptr()) { + assert(at == Type::TOP || at == TypePtr::NULL_PTR || + at->isa_ptr() != NULL, "expecting an Ptr"); + if (adr->is_AddP()) { + adr = get_addp_base(adr); + } + // Mark as ArgEscape everything "adr" could point to. + set_escape_state(adr->_idx, PointsToNode::ArgEscape); + } + } + _processed.set(n_idx); + break; + } case Op_ThreadLocal: { assert(false, "Op_ThreadLocal"); break; } default: - ; - // nothing to do + // This method should be called only for EA specific nodes. + ShouldNotReachHere(); } } diff --git a/hotspot/src/share/vm/opto/escape.hpp b/hotspot/src/share/vm/opto/escape.hpp index 1ce0cc9cf29..576043beb45 100644 --- a/hotspot/src/share/vm/opto/escape.hpp +++ b/hotspot/src/share/vm/opto/escape.hpp @@ -210,6 +210,8 @@ private: Unique_Node_List _delayed_worklist; // Nodes to be processed before // the call build_connection_graph(). + GrowableArray _mergemem_worklist; // List of all MergeMem nodes + VectorSet _processed; // Records which nodes have been // processed. @@ -289,7 +291,7 @@ private: bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn); PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn, bool &new_created); PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn); - Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn); + void move_inst_mem(Node* n, GrowableArray &orig_phis, PhaseGVN *igvn); Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray &orig_phi_worklist, PhaseGVN *igvn); // Propagate unique types created for unescaped allocated objects @@ -298,7 +300,6 @@ private: // manage entries in _node_map void set_map(int idx, Node *n) { _node_map.map(idx, n); } - void set_map_phi(int idx, PhiNode *p) { _node_map.map(idx, (Node *) p); } Node *get_map(int idx) { return _node_map[idx]; } PhiNode *get_map_phi(int idx) { Node *phi = _node_map[idx]; @@ -315,6 +316,9 @@ private: // Set the escape state of a node void set_escape_state(uint ni, PointsToNode::EscapeState es); + // Search for objects which are not scalar replaceable. + void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase); + public: ConnectionGraph(Compile *C); diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index b63aae489ff..57fea648024 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -981,14 +981,19 @@ bool GraphKit::compute_stack_effects(int& inputs, int& depth) { case Bytecodes::_invokedynamic: case Bytecodes::_invokeinterface: { - bool is_static = (depth == 0); bool ignore; ciBytecodeStream iter(method()); iter.reset_to_bci(bci()); iter.next(); ciMethod* method = iter.get_method(ignore); inputs = method->arg_size_no_receiver(); - if (!is_static) inputs += 1; + // Add a receiver argument, maybe: + if (code != Bytecodes::_invokestatic && + code != Bytecodes::_invokedynamic) + inputs += 1; + // (Do not use ciMethod::arg_size(), because + // it might be an unloaded method, which doesn't + // know whether it is static or not.) int size = method->return_type()->size(); depth = size - inputs; } @@ -1351,8 +1356,8 @@ void GraphKit::set_all_memory(Node* newmem) { } //------------------------------set_all_memory_call---------------------------- -void GraphKit::set_all_memory_call(Node* call) { - Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ); +void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) { + Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) ); set_all_memory(newmem); } @@ -1573,7 +1578,7 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { //---------------------------set_edges_for_java_call--------------------------- // Connect a newly created call into the current JVMS. // A return value node (if any) is returned from set_edges_for_java_call. -void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) { +void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw, bool separate_io_proj) { // Add the predefined inputs: call->init_req( TypeFunc::Control, control() ); @@ -1595,13 +1600,13 @@ void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) { // Re-use the current map to produce the result. set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control))); - set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O ))); - set_all_memory_call(xcall); + set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O , separate_io_proj))); + set_all_memory_call(xcall, separate_io_proj); //return xcall; // no need, caller already has it } -Node* GraphKit::set_results_for_java_call(CallJavaNode* call) { +Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) { if (stopped()) return top(); // maybe the call folded up? // Capture the return value, if any. @@ -1614,8 +1619,15 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call) { // Note: Since any out-of-line call can produce an exception, // we always insert an I_O projection from the call into the result. - make_slow_call_ex(call, env()->Throwable_klass(), false); + make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj); + if (separate_io_proj) { + // The caller requested separate projections be used by the fall + // through and exceptional paths, so replace the projections for + // the fall through path. + set_i_o(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::I_O) )); + set_all_memory(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) )); + } return ret; } @@ -1678,6 +1690,64 @@ void GraphKit::set_predefined_output_for_runtime_call(Node* call, } } + +// Replace the call with the current state of the kit. +void GraphKit::replace_call(CallNode* call, Node* result) { + JVMState* ejvms = NULL; + if (has_exceptions()) { + ejvms = transfer_exceptions_into_jvms(); + } + + SafePointNode* final_state = stop(); + + // Find all the needed outputs of this call + CallProjections callprojs; + call->extract_projections(&callprojs, true); + + // Replace all the old call edges with the edges from the inlining result + C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control)); + C->gvn_replace_by(callprojs.fallthrough_memproj, final_state->in(TypeFunc::Memory)); + C->gvn_replace_by(callprojs.fallthrough_ioproj, final_state->in(TypeFunc::I_O)); + + // Replace the result with the new result if it exists and is used + if (callprojs.resproj != NULL && result != NULL) { + C->gvn_replace_by(callprojs.resproj, result); + } + + if (ejvms == NULL) { + // No exception edges to simply kill off those paths + C->gvn_replace_by(callprojs.catchall_catchproj, C->top()); + C->gvn_replace_by(callprojs.catchall_memproj, C->top()); + C->gvn_replace_by(callprojs.catchall_ioproj, C->top()); + + // Replace the old exception object with top + if (callprojs.exobj != NULL) { + C->gvn_replace_by(callprojs.exobj, C->top()); + } + } else { + GraphKit ekit(ejvms); + + // Load my combined exception state into the kit, with all phis transformed: + SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states(); + + Node* ex_oop = ekit.use_exception_state(ex_map); + + C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control()); + C->gvn_replace_by(callprojs.catchall_memproj, ekit.reset_memory()); + C->gvn_replace_by(callprojs.catchall_ioproj, ekit.i_o()); + + // Replace the old exception object with the newly created one + if (callprojs.exobj != NULL) { + C->gvn_replace_by(callprojs.exobj, ex_oop); + } + } + + // Disconnect the call from the graph + call->disconnect_inputs(NULL); + C->gvn_replace_by(call, C->top()); +} + + //------------------------------increment_counter------------------------------ // for statistics: increment a VM counter by 1 @@ -3189,9 +3259,10 @@ void GraphKit::write_barrier_post(Node* oop_store, if (use_ReduceInitialCardMarks() && obj == just_allocated_object(control())) { // We can skip marks on a freshly-allocated object in Eden. - // Keep this code in sync with maybe_defer_card_mark() in runtime.cpp. - // That routine informs GC to take appropriate compensating steps - // so as to make this card-mark elision safe. + // Keep this code in sync with new_store_pre_barrier() in runtime.cpp. + // That routine informs GC to take appropriate compensating steps, + // upon a slow-path allocation, so as to make this card-mark + // elision safe. return; } @@ -3459,4 +3530,3 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, sync_kit(ideal); } #undef __ - diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index b127789b5f3..8135aca2d39 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -279,6 +279,34 @@ class GraphKit : public Phase { } Node* basic_plus_adr(Node* base, Node* ptr, Node* offset); + + // Some convenient shortcuts for common nodes + Node* IfTrue(IfNode* iff) { return _gvn.transform(new (C,1) IfTrueNode(iff)); } + Node* IfFalse(IfNode* iff) { return _gvn.transform(new (C,1) IfFalseNode(iff)); } + + Node* AddI(Node* l, Node* r) { return _gvn.transform(new (C,3) AddINode(l, r)); } + Node* SubI(Node* l, Node* r) { return _gvn.transform(new (C,3) SubINode(l, r)); } + Node* MulI(Node* l, Node* r) { return _gvn.transform(new (C,3) MulINode(l, r)); } + Node* DivI(Node* ctl, Node* l, Node* r) { return _gvn.transform(new (C,3) DivINode(ctl, l, r)); } + + Node* AndI(Node* l, Node* r) { return _gvn.transform(new (C,3) AndINode(l, r)); } + Node* OrI(Node* l, Node* r) { return _gvn.transform(new (C,3) OrINode(l, r)); } + Node* XorI(Node* l, Node* r) { return _gvn.transform(new (C,3) XorINode(l, r)); } + + Node* MaxI(Node* l, Node* r) { return _gvn.transform(new (C,3) MaxINode(l, r)); } + Node* MinI(Node* l, Node* r) { return _gvn.transform(new (C,3) MinINode(l, r)); } + + Node* LShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) LShiftINode(l, r)); } + Node* RShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) RShiftINode(l, r)); } + Node* URShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) URShiftINode(l, r)); } + + Node* CmpI(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpINode(l, r)); } + Node* CmpL(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpLNode(l, r)); } + Node* CmpP(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpPNode(l, r)); } + Node* Bool(Node* cmp, BoolTest::mask relop) { return _gvn.transform(new (C,2) BoolNode(cmp, relop)); } + + Node* AddP(Node* b, Node* a, Node* o) { return _gvn.transform(new (C,4) AddPNode(b, a, o)); } + // Convert between int and long, and size_t. // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) Node* ConvI2L(Node* offset); @@ -400,7 +428,7 @@ class GraphKit : public Phase { void set_all_memory(Node* newmem); // Create a memory projection from the call, then set_all_memory. - void set_all_memory_call(Node* call); + void set_all_memory_call(Node* call, bool separate_io_proj = false); // Create a LoadNode, reading from the parser's memory state. // (Note: require_atomic_access is useful only with T_LONG.) @@ -543,12 +571,12 @@ class GraphKit : public Phase { // Transform the call, and update the basics: control, i_o, memory. // (The next step is usually to call set_results_for_java_call.) void set_edges_for_java_call(CallJavaNode* call, - bool must_throw = false); + bool must_throw = false, bool separate_io_proj = false); // Finish up a java call that was started by set_edges_for_java_call. // Call add_exception on any throw arising from the call. // Return the call result (transformed). - Node* set_results_for_java_call(CallJavaNode* call); + Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false); // Similar to set_edges_for_java_call, but simplified for runtime calls. void set_predefined_output_for_runtime_call(Node* call) { @@ -559,6 +587,11 @@ class GraphKit : public Phase { const TypePtr* hook_mem); Node* set_predefined_input_for_runtime_call(SafePointNode* call); + // Replace the call with the current state of the kit. Requires + // that the call was generated with separate io_projs so that + // exceptional control flow can be handled properly. + void replace_call(CallNode* call, Node* result); + // helper functions for statistics void increment_counter(address counter_addr); // increment a debug counter void increment_counter(Node* counter_addr); // increment a debug counter diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index 51ca8fe28ad..a026fceef47 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -531,6 +531,9 @@ Node* IfNode::up_one_dom(Node *curr, bool linear_only) { if (linear_only) return NULL; + if( dom->is_Root() ) + return NULL; + // Else hit a Region. Check for a loop header if( dom->is_Loop() ) return dom->in(1); // Skip up thru loops diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 31de55a5435..4f1d6b670e2 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -120,6 +120,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe case Op_LoadRange: case Op_LoadD_unaligned: case Op_LoadL_unaligned: + assert(mach->in(2) == val, "should be address"); break; case Op_StoreB: case Op_StoreC: @@ -146,6 +147,21 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe default: // Also check for embedded loads if( !mach->needs_anti_dependence_check() ) continue; // Not an memory op; skip it + { + // Check that value is used in memory address. + Node* base; + Node* index; + const MachOper* oper = mach->memory_inputs(base, index); + if (oper == NULL || oper == (MachOper*)-1) { + continue; // Not an memory op; skip it + } + if (val == base || + val == index && val->bottom_type()->isa_narrowoop()) { + break; // Found it + } else { + continue; // Skip it + } + } break; } // check if the offset is not too high for implicit exception @@ -542,6 +558,16 @@ uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_ // pointers as far as the kill mask goes. bool exclude_soe = op == Op_CallRuntime; + // If the call is a MethodHandle invoke, we need to exclude the + // register which is used to save the SP value over MH invokes from + // the mask. Otherwise this register could be used for + // deoptimization information. + if (op == Op_CallStaticJava) { + MachCallStaticJavaNode* mcallstaticjava = (MachCallStaticJavaNode*) mcall; + if (mcallstaticjava->_method_handle_invoke) + proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); + } + // Fill in the kill mask for the call for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) { if( !regs.Member(r) ) { // Not already defined by the call @@ -616,8 +642,9 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark"); } } - if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire && - n->req() > TypeFunc::Parms ) { + if( n->is_Mach() && n->req() > TypeFunc::Parms && + (n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire || + n->as_Mach()->ideal_Opcode() == Op_MemBarVolatile) ) { // MemBarAcquire could be created without Precedent edge. // del_req() replaces the specified edge with the last input edge // and then removes the last edge. If the specified edge > number of diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 1be04de6acf..8f69208911e 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-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3697,12 +3697,14 @@ bool LibraryCallKit::inline_native_Reflection_getCallerClass() { // Helper routine for above bool LibraryCallKit::is_method_invoke_or_aux_frame(JVMState* jvms) { + ciMethod* method = jvms->method(); + // Is this the Method.invoke method itself? - if (jvms->method()->intrinsic_id() == vmIntrinsics::_invoke) + if (method->intrinsic_id() == vmIntrinsics::_invoke) return true; // Is this a helper, defined somewhere underneath MethodAccessorImpl. - ciKlass* k = jvms->method()->holder(); + ciKlass* k = method->holder(); if (k->is_instance_klass()) { ciInstanceKlass* ik = k->as_instance_klass(); for (; ik != NULL; ik = ik->super()) { @@ -3712,6 +3714,10 @@ bool LibraryCallKit::is_method_invoke_or_aux_frame(JVMState* jvms) { } } } + else if (method->is_method_handle_adapter()) { + // This is an internal adapter frame from the MethodHandleCompiler -- skip it + return true; + } return false; } diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 0d4bf7869ea..809f47472c6 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -549,6 +549,10 @@ bool IdealLoopTree::policy_range_check( PhaseIdealLoop *phase ) const { // Comparing trip+off vs limit Node *bol = iff->in(1); if( bol->req() != 2 ) continue; // dead constant test + if (!bol->is_Bool()) { + assert(UseLoopPredicate && bol->Opcode() == Op_Conv2B, "predicate check only"); + continue; + } Node *cmp = bol->in(1); Node *rc_exp = cmp->in(1); @@ -875,7 +879,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ //------------------------------is_invariant----------------------------- // Return true if n is invariant bool IdealLoopTree::is_invariant(Node* n) const { - Node *n_c = _phase->get_ctrl(n); + Node *n_c = _phase->has_ctrl(n) ? _phase->get_ctrl(n) : n; if (n_c->is_top()) return false; return !is_member(_phase->get_loop(n_c)); } @@ -1594,7 +1598,7 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) { bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_new ) { // Check and remove empty loops (spam micro-benchmarks) if( policy_do_remove_empty_loop(phase) ) - return true; // Here we removed an empty loop + return true; // Here we removed an empty loop bool should_peel = policy_peeling(phase); // Should we peel? @@ -1688,8 +1692,8 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_ // an even number of trips). If we are peeling, we might enable some RCE // and we'd rather unroll the post-RCE'd loop SO... do not unroll if // peeling. - if( should_unroll && !should_peel ) - phase->do_unroll(this,old_new, true); + if( should_unroll && !should_peel ) + phase->do_unroll(this,old_new, true); // Adjust the pre-loop limits to align the main body // iterations. @@ -1731,9 +1735,9 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) _allow_optimizations && !tail()->is_top() ) { // Also ignore the occasional dead backedge if (!_has_call) { - if (!iteration_split_impl( phase, old_new )) { - return false; - } + if (!iteration_split_impl( phase, old_new )) { + return false; + } } else if (policy_unswitching(phase)) { phase->do_unswitching(this, old_new); } @@ -1746,3 +1750,576 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) return false; return true; } + +//-------------------------------is_uncommon_trap_proj---------------------------- +// Return true if proj is the form of "proj->[region->..]call_uct" +bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate) { + int path_limit = 10; + assert(proj, "invalid argument"); + Node* out = proj; + for (int ct = 0; ct < path_limit; ct++) { + out = out->unique_ctrl_out(); + if (out == NULL || out->is_Root() || out->is_Start()) + return false; + if (out->is_CallStaticJava()) { + int req = out->as_CallStaticJava()->uncommon_trap_request(); + if (req != 0) { + Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(req); + if (!must_reason_predicate || reason == Deoptimization::Reason_predicate){ + return true; + } + } + return false; // don't do further after call + } + } + return false; +} + +//-------------------------------is_uncommon_trap_if_pattern------------------------- +// Return true for "if(test)-> proj -> ... +// | +// V +// other_proj->[region->..]call_uct" +// +// "must_reason_predicate" means the uct reason must be Reason_predicate +bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, bool must_reason_predicate) { + Node *in0 = proj->in(0); + if (!in0->is_If()) return false; + IfNode* iff = in0->as_If(); + + // we need "If(Conv2B(Opaque1(...)))" pattern for must_reason_predicate + if (must_reason_predicate) { + if (iff->in(1)->Opcode() != Op_Conv2B || + iff->in(1)->in(1)->Opcode() != Op_Opaque1) { + return false; + } + } + + ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); + return is_uncommon_trap_proj(other_proj, must_reason_predicate); +} + +//------------------------------create_new_if_for_predicate------------------------ +// create a new if above the uct_if_pattern for the predicate to be promoted. +// +// before after +// ---------- ---------- +// ctrl ctrl +// | | +// | | +// v v +// iff new_iff +// / \ / \ +// / \ / \ +// v v v v +// uncommon_proj cont_proj if_uct if_cont +// \ | | | | +// \ | | | | +// v v v | v +// rgn loop | iff +// | | / \ +// | | / \ +// v | v v +// uncommon_trap | uncommon_proj cont_proj +// \ \ | | +// \ \ | | +// v v v v +// rgn loop +// | +// | +// v +// uncommon_trap +// +// +// We will create a region to guard the uct call if there is no one there. +// The true projecttion (if_cont) of the new_iff is returned. +ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj) { + assert(is_uncommon_trap_if_pattern(cont_proj, true), "must be a uct if pattern!"); + IfNode* iff = cont_proj->in(0)->as_If(); + + ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); + Node *rgn = uncommon_proj->unique_ctrl_out(); + assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); + + if (!rgn->is_Region()) { // create a region to guard the call + assert(rgn->is_Call(), "must be call uct"); + CallNode* call = rgn->as_Call(); + rgn = new (C, 1) RegionNode(1); + _igvn.set_type(rgn, rgn->bottom_type()); + rgn->add_req(uncommon_proj); + set_idom(rgn, idom(uncommon_proj), dom_depth(uncommon_proj)+1); + _igvn.hash_delete(call); + call->set_req(0, rgn); + } + + // Create new_iff + uint iffdd = dom_depth(iff); + IdealLoopTree* lp = get_loop(iff); + IfNode *new_iff = new (C, 2) IfNode(iff->in(0), NULL, iff->_prob, iff->_fcnt); + register_node(new_iff, lp, idom(iff), iffdd); + Node *if_cont = new (C, 1) IfTrueNode(new_iff); + Node *if_uct = new (C, 1) IfFalseNode(new_iff); + if (cont_proj->is_IfFalse()) { + // Swap + Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; + } + register_node(if_cont, lp, new_iff, iffdd); + register_node(if_uct, get_loop(rgn), new_iff, iffdd); + + // if_cont to iff + _igvn.hash_delete(iff); + iff->set_req(0, if_cont); + set_idom(iff, if_cont, dom_depth(iff)); + + // if_uct to rgn + _igvn.hash_delete(rgn); + rgn->add_req(if_uct); + Node* ridom = idom(rgn); + Node* nrdom = dom_lca(ridom, new_iff); + set_idom(rgn, nrdom, dom_depth(rgn)); + + // rgn must have no phis + assert(!rgn->as_Region()->has_phi(), "region must have no phis"); + + return if_cont->as_Proj(); +} + +//------------------------------find_predicate_insertion_point-------------------------- +// Find a good location to insert a predicate +ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c) { + if (start_c == C->root() || !start_c->is_Proj()) + return NULL; + if (is_uncommon_trap_if_pattern(start_c->as_Proj(), true/*Reason_Predicate*/)) { + return start_c->as_Proj(); + } + return NULL; +} + +//------------------------------Invariance----------------------------------- +// Helper class for loop_predication_impl to compute invariance on the fly and +// clone invariants. +class Invariance : public StackObj { + VectorSet _visited, _invariant; + Node_Stack _stack; + VectorSet _clone_visited; + Node_List _old_new; // map of old to new (clone) + IdealLoopTree* _lpt; + PhaseIdealLoop* _phase; + + // Helper function to set up the invariance for invariance computation + // If n is a known invariant, set up directly. Otherwise, look up the + // the possibility to push n onto the stack for further processing. + void visit(Node* use, Node* n) { + if (_lpt->is_invariant(n)) { // known invariant + _invariant.set(n->_idx); + } else if (!n->is_CFG()) { + Node *n_ctrl = _phase->ctrl_or_self(n); + Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG + if (_phase->is_dominator(n_ctrl, u_ctrl)) { + _stack.push(n, n->in(0) == NULL ? 1 : 0); + } + } + } + + // Compute invariance for "the_node" and (possibly) all its inputs recursively + // on the fly + void compute_invariance(Node* n) { + assert(_visited.test(n->_idx), "must be"); + visit(n, n); + while (_stack.is_nonempty()) { + Node* n = _stack.node(); + uint idx = _stack.index(); + if (idx == n->req()) { // all inputs are processed + _stack.pop(); + // n is invariant if it's inputs are all invariant + bool all_inputs_invariant = true; + for (uint i = 0; i < n->req(); i++) { + Node* in = n->in(i); + if (in == NULL) continue; + assert(_visited.test(in->_idx), "must have visited input"); + if (!_invariant.test(in->_idx)) { // bad guy + all_inputs_invariant = false; + break; + } + } + if (all_inputs_invariant) { + _invariant.set(n->_idx); // I am a invariant too + } + } else { // process next input + _stack.set_index(idx + 1); + Node* m = n->in(idx); + if (m != NULL && !_visited.test_set(m->_idx)) { + visit(n, m); + } + } + } + } + + // Helper function to set up _old_new map for clone_nodes. + // If n is a known invariant, set up directly ("clone" of n == n). + // Otherwise, push n onto the stack for real cloning. + void clone_visit(Node* n) { + assert(_invariant.test(n->_idx), "must be invariant"); + if (_lpt->is_invariant(n)) { // known invariant + _old_new.map(n->_idx, n); + } else{ // to be cloned + assert (!n->is_CFG(), "should not see CFG here"); + _stack.push(n, n->in(0) == NULL ? 1 : 0); + } + } + + // Clone "n" and (possibly) all its inputs recursively + void clone_nodes(Node* n, Node* ctrl) { + clone_visit(n); + while (_stack.is_nonempty()) { + Node* n = _stack.node(); + uint idx = _stack.index(); + if (idx == n->req()) { // all inputs processed, clone n! + _stack.pop(); + // clone invariant node + Node* n_cl = n->clone(); + _old_new.map(n->_idx, n_cl); + _phase->register_new_node(n_cl, ctrl); + for (uint i = 0; i < n->req(); i++) { + Node* in = n_cl->in(i); + if (in == NULL) continue; + n_cl->set_req(i, _old_new[in->_idx]); + } + } else { // process next input + _stack.set_index(idx + 1); + Node* m = n->in(idx); + if (m != NULL && !_clone_visited.test_set(m->_idx)) { + clone_visit(m); // visit the input + } + } + } + } + + public: + Invariance(Arena* area, IdealLoopTree* lpt) : + _lpt(lpt), _phase(lpt->_phase), + _visited(area), _invariant(area), _stack(area, 10 /* guess */), + _clone_visited(area), _old_new(area) + {} + + // Map old to n for invariance computation and clone + void map_ctrl(Node* old, Node* n) { + assert(old->is_CFG() && n->is_CFG(), "must be"); + _old_new.map(old->_idx, n); // "clone" of old is n + _invariant.set(old->_idx); // old is invariant + _clone_visited.set(old->_idx); + } + + // Driver function to compute invariance + bool is_invariant(Node* n) { + if (!_visited.test_set(n->_idx)) + compute_invariance(n); + return (_invariant.test(n->_idx) != 0); + } + + // Driver function to clone invariant + Node* clone(Node* n, Node* ctrl) { + assert(ctrl->is_CFG(), "must be"); + assert(_invariant.test(n->_idx), "must be an invariant"); + if (!_clone_visited.test(n->_idx)) + clone_nodes(n, ctrl); + return _old_new[n->_idx]; + } +}; + +//------------------------------is_range_check_if ----------------------------------- +// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format +// Note: this function is particularly designed for loop predication. We require load_range +// and offset to be loop invariant computed on the fly by "invar" +bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const { + if (!is_loop_exit(iff)) { + return false; + } + if (!iff->in(1)->is_Bool()) { + return false; + } + const BoolNode *bol = iff->in(1)->as_Bool(); + if (bol->_test._test != BoolTest::lt) { + return false; + } + if (!bol->in(1)->is_Cmp()) { + return false; + } + const CmpNode *cmp = bol->in(1)->as_Cmp(); + if (cmp->Opcode() != Op_CmpU ) { + return false; + } + if (cmp->in(2)->Opcode() != Op_LoadRange) { + return false; + } + LoadRangeNode* lr = (LoadRangeNode*)cmp->in(2); + if (!invar.is_invariant(lr)) { // loadRange must be invariant + return false; + } + Node *iv = _head->as_CountedLoop()->phi(); + int scale = 0; + Node *offset = NULL; + if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) { + return false; + } + if(offset && !invar.is_invariant(offset)) { // offset must be invariant + return false; + } + return true; +} + +//------------------------------rc_predicate----------------------------------- +// Create a range check predicate +// +// for (i = init; i < limit; i += stride) { +// a[scale*i+offset] +// } +// +// Compute max(scale*i + offset) for init <= i < limit and build the predicate +// as "max(scale*i + offset) u< a.length". +// +// There are two cases for max(scale*i + offset): +// (1) stride*scale > 0 +// max(scale*i + offset) = scale*(limit-stride) + offset +// (2) stride*scale < 0 +// max(scale*i + offset) = scale*init + offset +BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl, + int scale, Node* offset, + Node* init, Node* limit, Node* stride, + Node* range) { + Node* max_idx_expr = init; + int stride_con = stride->get_int(); + if ((stride_con > 0) == (scale > 0)) { + max_idx_expr = new (C, 3) SubINode(limit, stride); + register_new_node(max_idx_expr, ctrl); + } + + if (scale != 1) { + ConNode* con_scale = _igvn.intcon(scale); + max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); + register_new_node(max_idx_expr, ctrl); + } + + if (offset && (!offset->is_Con() || offset->get_int() != 0)){ + max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); + register_new_node(max_idx_expr, ctrl); + } + + CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); + register_new_node(cmp, ctrl); + BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); + register_new_node(bol, ctrl); + return bol; +} + +//------------------------------ loop_predication_impl-------------------------- +// Insert loop predicates for null checks and range checks +bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { + if (!UseLoopPredicate) return false; + + // Too many traps seen? + bool tmt = C->too_many_traps(C->method(), 0, Deoptimization::Reason_predicate); + int tc = C->trap_count(Deoptimization::Reason_predicate); + if (tmt || tc > 0) { + if (TraceLoopPredicate) { + tty->print_cr("too many predicate traps: %d", tc); + C->method()->print(); // which method has too many predicate traps + tty->print_cr(""); + } + return false; + } + + CountedLoopNode *cl = NULL; + if (loop->_head->is_CountedLoop()) { + cl = loop->_head->as_CountedLoop(); + // do nothing for iteration-splitted loops + if(!cl->is_normal_loop()) return false; + } + + LoopNode *lpn = loop->_head->as_Loop(); + Node* entry = lpn->in(LoopNode::EntryControl); + + ProjNode *predicate_proj = find_predicate_insertion_point(entry); + if (!predicate_proj){ +#ifndef PRODUCT + if (TraceLoopPredicate) { + tty->print("missing predicate:"); + loop->dump_head(); + } +#endif + return false; + } + + ConNode* zero = _igvn.intcon(0); + set_ctrl(zero, C->root()); + Node *cond_false = new (C, 2) Conv2BNode(zero); + register_new_node(cond_false, C->root()); + ConNode* one = _igvn.intcon(1); + set_ctrl(one, C->root()); + Node *cond_true = new (C, 2) Conv2BNode(one); + register_new_node(cond_true, C->root()); + + ResourceArea *area = Thread::current()->resource_area(); + Invariance invar(area, loop); + + // Create list of if-projs such that a newer proj dominates all older + // projs in the list, and they all dominate loop->tail() + Node_List if_proj_list(area); + LoopNode *head = loop->_head->as_Loop(); + Node *current_proj = loop->tail(); //start from tail + while ( current_proj != head ) { + if (loop == get_loop(current_proj) && // still in the loop ? + current_proj->is_Proj() && // is a projection ? + current_proj->in(0)->Opcode() == Op_If) { // is a if projection ? + if_proj_list.push(current_proj); + } + current_proj = idom(current_proj); + } + + bool hoisted = false; // true if at least one proj is promoted + while (if_proj_list.size() > 0) { + // Following are changed to nonnull when a predicate can be hoisted + ProjNode* new_predicate_proj = NULL; + BoolNode* new_predicate_bol = NULL; + + ProjNode* proj = if_proj_list.pop()->as_Proj(); + IfNode* iff = proj->in(0)->as_If(); + + if (!is_uncommon_trap_if_pattern(proj)) { + if (loop->is_loop_exit(iff)) { + // stop processing the remaining projs in the list because the execution of them + // depends on the condition of "iff" (iff->in(1)). + break; + } else { + // Both arms are inside the loop. There are two cases: + // (1) there is one backward branch. In this case, any remaining proj + // in the if_proj list post-dominates "iff". So, the condition of "iff" + // does not determine the execution the remining projs directly, and we + // can safely continue. + // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj" + // does not dominate loop->tail(), so it can not be in the if_proj list. + continue; + } + } + + Node* test = iff->in(1); + if (!test->is_Bool()){ //Conv2B, ... + continue; + } + BoolNode* bol = test->as_Bool(); + if (invar.is_invariant(bol)) { + // Invariant test + new_predicate_proj = create_new_if_for_predicate(predicate_proj); + Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); + new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); + if (TraceLoopPredicate) tty->print("invariant"); + } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { + // Range check (only for counted loops) + new_predicate_proj = create_new_if_for_predicate(predicate_proj); + Node *ctrl = new_predicate_proj->in(0)->as_If()->in(0); + const Node* cmp = bol->in(1)->as_Cmp(); + Node* idx = cmp->in(1); + assert(!invar.is_invariant(idx), "index is variant"); + assert(cmp->in(2)->Opcode() == Op_LoadRange, "must be"); + LoadRangeNode* ld_rng = (LoadRangeNode*)cmp->in(2); // LoadRangeNode + assert(invar.is_invariant(ld_rng), "load range must be invariant"); + ld_rng = (LoadRangeNode*)invar.clone(ld_rng, ctrl); + int scale = 1; + Node* offset = zero; + bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); + assert(ok, "must be index expression"); + if (offset && offset != zero) { + assert(invar.is_invariant(offset), "offset must be loop invariant"); + offset = invar.clone(offset, ctrl); + } + Node* init = cl->init_trip(); + Node* limit = cl->limit(); + Node* stride = cl->stride(); + new_predicate_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, ld_rng); + if (TraceLoopPredicate) tty->print("range check"); + } + + if (new_predicate_proj == NULL) { + // The other proj of the "iff" is a uncommon trap projection, and we can assume + // the other proj will not be executed ("executed" means uct raised). + continue; + } else { + // Success - attach condition (new_predicate_bol) to predicate if + invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate + IfNode* new_iff = new_predicate_proj->in(0)->as_If(); + + // Negate test if necessary + if (proj->_con != predicate_proj->_con) { + new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); + register_new_node(new_predicate_bol, new_iff->in(0)); + if (TraceLoopPredicate) tty->print_cr(" if negated: %d", iff->_idx); + } else { + if (TraceLoopPredicate) tty->print_cr(" if: %d", iff->_idx); + } + + _igvn.hash_delete(new_iff); + new_iff->set_req(1, new_predicate_bol); + + _igvn.hash_delete(iff); + iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); + + Node* ctrl = new_predicate_proj; // new control + ProjNode* dp = proj; // old control + assert(get_loop(dp) == loop, "guarenteed at the time of collecting proj"); + // Find nodes (depends only on the test) off the surviving projection; + // move them outside the loop with the control of proj_clone + for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { + Node* cd = dp->fast_out(i); // Control-dependent node + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); + cd->set_req(0, ctrl); // ctrl, not NULL + set_early_ctrl(cd); + _igvn._worklist.push(cd); + IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); + if (new_loop != loop) { + if (!loop->_child) loop->_body.yank(cd); + if (!new_loop->_child ) new_loop->_body.push(cd); + } + --i; + --imax; + } + } + + hoisted = true; + C->set_major_progress(); + } + } // end while + +#ifndef PRODUCT + // report that the loop predication has been actually performed + // for this loop + if (TraceLoopPredicate && hoisted) { + tty->print("Loop Predication Performed:"); + loop->dump_head(); + } +#endif + + return hoisted; +} + +//------------------------------loop_predication-------------------------------- +// driver routine for loop predication optimization +bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { + bool hoisted = false; + // Recursively promote predicates + if ( _child ) { + hoisted = _child->loop_predication( phase); + } + + // self + if (!_irreducible && !tail()->is_top()) { + hoisted |= phase->loop_predication_impl(this); + } + + if ( _next ) { //sibling + hoisted |= _next->loop_predication( phase); + } + + return hoisted; +} diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index a1d87225203..b662aa29328 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1279,7 +1279,8 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { // Visit all children, looking for Phis for (DUIterator i = cl->outs(); cl->has_out(i); i++) { Node *out = cl->out(i); - if (!out->is_Phi() || out == phi) continue; // Looking for other phis + // Look for other phis (secondary IVs). Skip dead ones + if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue; PhiNode* phi2 = out->as_Phi(); Node *incr2 = phi2->in( LoopNode::LoopBackControl ); // Look for induction variables of the form: X += constant @@ -1419,11 +1420,57 @@ static void log_loop_tree(IdealLoopTree* root, IdealLoopTree* loop, CompileLog* } } +//---------------------collect_potentially_useful_predicates----------------------- +// Helper function to collect potentially useful predicates to prevent them from +// being eliminated by PhaseIdealLoop::eliminate_useless_predicates +void PhaseIdealLoop::collect_potentially_useful_predicates( + IdealLoopTree * loop, Unique_Node_List &useful_predicates) { + if (loop->_child) { // child + collect_potentially_useful_predicates(loop->_child, useful_predicates); + } + + // self (only loops that we can apply loop predication may use their predicates) + if (loop->_head->is_Loop() && + !loop->_irreducible && + !loop->tail()->is_top()) { + LoopNode *lpn = loop->_head->as_Loop(); + Node* entry = lpn->in(LoopNode::EntryControl); + ProjNode *predicate_proj = find_predicate_insertion_point(entry); + if (predicate_proj != NULL ) { // right pattern that can be used by loop predication + assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one + } + } + + if ( loop->_next ) { // sibling + collect_potentially_useful_predicates(loop->_next, useful_predicates); + } +} + +//------------------------eliminate_useless_predicates----------------------------- +// Eliminate all inserted predicates if they could not be used by loop predication. +void PhaseIdealLoop::eliminate_useless_predicates() { + if (C->predicate_count() == 0) return; // no predicate left + + Unique_Node_List useful_predicates; // to store useful predicates + if (C->has_loops()) { + collect_potentially_useful_predicates(_ltree_root->_child, useful_predicates); + } + + for (int i = C->predicate_count(); i > 0; i--) { + Node * n = C->predicate_opaque1_node(i-1); + assert(n->Opcode() == Op_Opaque1, "must be"); + if (!useful_predicates.member(n)) { // not in the useful list + _igvn.replace_node(n, n->in(1)); + } + } +} + //============================================================================= //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to // its corresponding LoopNode. If 'optimize' is true, do some loop cleanups. -void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { +void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) { int old_progress = C->major_progress(); // Reset major-progress flag for the driver's heuristics @@ -1576,6 +1623,12 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { return; } + // some parser-inserted loop predicates could never be used by loop + // predication. Eliminate them before loop optimization + if (UseLoopPredicate) { + eliminate_useless_predicates(); + } + // clear out the dead code while(_deadlist.size()) { _igvn.remove_globally_dead_node(_deadlist.pop()); @@ -1602,7 +1655,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { // Because RCE opportunities can be masked by split_thru_phi, // look for RCE candidates and inhibit split_thru_phi // on just their loop-phi's for this pass of loop opts - if( SplitIfBlocks && do_split_ifs ) { + if (SplitIfBlocks && do_split_ifs) { if (lpt->policy_range_check(this)) { lpt->_rce_candidate = 1; // = true } @@ -1618,12 +1671,17 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { NOT_PRODUCT( if( VerifyLoopOptimizations ) verify(); ); } + // Perform loop predication before iteration splitting + if (do_loop_pred && C->has_loops() && !C->major_progress()) { + _ltree_root->_child->loop_predication(this); + } + // Perform iteration-splitting on inner loops. Split iterations to avoid // range checks or one-shot null checks. // If split-if's didn't hack the graph too bad (no CFG changes) // then do loop opts. - if( C->has_loops() && !C->major_progress() ) { + if (C->has_loops() && !C->major_progress()) { memset( worklist.adr(), 0, worklist.Size()*sizeof(Node*) ); _ltree_root->_child->iteration_split( this, worklist ); // No verify after peeling! GCM has hoisted code out of the loop. @@ -1635,7 +1693,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { // Do verify graph edges in any case NOT_PRODUCT( C->verify_graph_edges(); ); - if( !do_split_ifs ) { + if (!do_split_ifs) { // We saw major progress in Split-If to get here. We forced a // pass with unrolling and not split-if, however more split-if's // might make progress. If the unrolling didn't make progress @@ -2762,6 +2820,22 @@ void PhaseIdealLoop::build_loop_late_post( Node *n ) { Node *legal = LCA; // Walk 'legal' up the IDOM chain Node *least = legal; // Best legal position so far while( early != legal ) { // While not at earliest legal +#ifdef ASSERT + if (legal->is_Start() && !early->is_Root()) { + // Bad graph. Print idom path and fail. + tty->print_cr( "Bad graph detected in build_loop_late"); + tty->print("n: ");n->dump(); tty->cr(); + tty->print("early: ");early->dump(); tty->cr(); + int ct = 0; + Node *dbg_legal = LCA; + while(!dbg_legal->is_Start() && ct < 100) { + tty->print("idom[%d] ",ct); dbg_legal->dump(); tty->cr(); + ct++; + dbg_legal = idom(dbg_legal); + } + assert(false, "Bad graph detected in build_loop_late"); + } +#endif // Find least loop nesting depth legal = idom(legal); // Bump up the IDOM tree // Check for lower nesting depth diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 892095595ed..e34cfcb18a3 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -30,6 +30,7 @@ class LoopNode; class Node; class PhaseIdealLoop; class VectorSet; +class Invariance; struct small_cache; // @@ -325,6 +326,10 @@ public: // Returns TRUE if loop tree is structurally changed. bool beautify_loops( PhaseIdealLoop *phase ); + // Perform optimization to use the loop predicates for null checks and range checks. + // Applies to any loop level (not just the innermost one) + bool loop_predication( PhaseIdealLoop *phase); + // Perform iteration-splitting on inner loops. Split iterations to // avoid range checks or one-shot null checks. Returns false if the // current round of loop opts should stop. @@ -395,6 +400,9 @@ public: // into longer memory ops, we may want to increase alignment. bool policy_align( PhaseIdealLoop *phase ) const; + // Return TRUE if "iff" is a range check. + bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const; + // Compute loop trip count from profile data void compute_profile_trip_cnt( PhaseIdealLoop *phase ); @@ -521,9 +529,6 @@ class PhaseIdealLoop : public PhaseTransform { } Node *dom_lca_for_get_late_ctrl_internal( Node *lca, Node *n, Node *tag ); - // true if CFG node d dominates CFG node n - bool is_dominator(Node *d, Node *n); - // Helper function for directing control inputs away from CFG split // points. Node *find_non_split_ctrl( Node *ctrl ) const { @@ -572,6 +577,17 @@ public: assert(n == find_non_split_ctrl(n), "must return legal ctrl" ); return n; } + // true if CFG node d dominates CFG node n + bool is_dominator(Node *d, Node *n); + // return get_ctrl for a data node and self(n) for a CFG node + Node* ctrl_or_self(Node* n) { + if (has_ctrl(n)) + return get_ctrl(n); + else { + assert (n->is_CFG(), "must be a CFG node"); + return n; + } + } private: Node *get_ctrl_no_update( Node *i ) const { @@ -600,7 +616,7 @@ private: // Lazy-dazy update of 'get_ctrl' and 'idom_at' mechanisms. Replace // the 'old_node' with 'new_node'. Kill old-node. Add a reference // from old_node to new_node to support the lazy update. Reference - // replaces loop reference, since that is not neede for dead node. + // replaces loop reference, since that is not needed for dead node. public: void lazy_update( Node *old_node, Node *new_node ) { assert( old_node != new_node, "no cycles please" ); @@ -679,11 +695,11 @@ private: _dom_lca_tags(C->comp_arena()), _verify_me(NULL), _verify_only(true) { - build_and_optimize(false); + build_and_optimize(false, false); } // build the loop tree and perform any requested optimizations - void build_and_optimize(bool do_split_if); + void build_and_optimize(bool do_split_if, bool do_loop_pred); public: // Dominators for the sea of nodes @@ -694,13 +710,13 @@ public: Node *dom_lca_internal( Node *n1, Node *n2 ) const; // Compute the Ideal Node to Loop mapping - PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) : + PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs, bool do_loop_pred) : PhaseTransform(Ideal_Loop), _igvn(igvn), _dom_lca_tags(C->comp_arena()), _verify_me(NULL), _verify_only(false) { - build_and_optimize(do_split_ifs); + build_and_optimize(do_split_ifs, do_loop_pred); } // Verify that verify_me made the same decisions as a fresh run. @@ -710,7 +726,7 @@ public: _dom_lca_tags(C->comp_arena()), _verify_me(verify_me), _verify_only(false) { - build_and_optimize(false); + build_and_optimize(false, false); } // Build and verify the loop tree without modifying the graph. This @@ -790,6 +806,30 @@ public: // Return true if exp is a scaled induction var plus (or minus) constant bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0); + // Return true if proj is for "proj->[region->..]call_uct" + bool is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate = false); + // Return true for "if(test)-> proj -> ... + // | + // V + // other_proj->[region->..]call_uct" + bool is_uncommon_trap_if_pattern(ProjNode* proj, bool must_reason_predicate = false); + // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted + ProjNode* create_new_if_for_predicate(ProjNode* cont_proj); + // Find a good location to insert a predicate + ProjNode* find_predicate_insertion_point(Node* start_c); + // Construct a range check for a predicate if + BoolNode* rc_predicate(Node* ctrl, + int scale, Node* offset, + Node* init, Node* limit, Node* stride, + Node* range); + + // Implementation of the loop predication to promote checks outside the loop + bool loop_predication_impl(IdealLoopTree *loop); + + // Helper function to collect predicate for eliminating the useless ones + void collect_potentially_useful_predicates(IdealLoopTree *loop, Unique_Node_List &predicate_opaque1); + void eliminate_useless_predicates(); + // Eliminate range-checks and other trip-counter vs loop-invariant tests. void do_range_check( IdealLoopTree *loop, Node_List &old_new ); @@ -906,7 +946,6 @@ private: const TypeInt* filtered_type_from_dominators( Node* val, Node *val_ctrl); // Helper functions - void register_new_node( Node *n, Node *blk ); Node *spinup( Node *iff, Node *new_false, Node *new_true, Node *region, Node *phi, small_cache *cache ); Node *find_use_block( Node *use, Node *def, Node *old_false, Node *new_false, Node *old_true, Node *new_true ); void handle_use( Node *use, Node *def, small_cache *cache, Node *region_dom, Node *new_false, Node *new_true, Node *old_false, Node *old_true ); @@ -918,6 +957,7 @@ private: public: void set_created_loop_node() { _created_loop_node = true; } bool created_loop_node() { return _created_loop_node; } + void register_new_node( Node *n, Node *blk ); #ifndef PRODUCT void dump( ) const; diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index 76121704b5f..0e9d4c6e819 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -636,7 +636,9 @@ uint MachCallJavaNode::cmp( const Node &n ) const { } #ifndef PRODUCT void MachCallJavaNode::dump_spec(outputStream *st) const { - if( _method ) { + if (_method_handle_invoke) + st->print("MethodHandle "); + if (_method) { _method->print_short_name(st); st->print(" "); } @@ -644,6 +646,20 @@ void MachCallJavaNode::dump_spec(outputStream *st) const { } #endif +//------------------------------Registers-------------------------------------- +const RegMask &MachCallJavaNode::in_RegMask(uint idx) const { + // Values in the domain use the users calling convention, embodied in the + // _in_rms array of RegMasks. + if (idx < tf()->domain()->cnt()) return _in_rms[idx]; + // Values outside the domain represent debug info + Matcher* m = Compile::current()->matcher(); + // If this call is a MethodHandle invoke we have to use a different + // debugmask which does not include the register we use to save the + // SP over MH invokes. + RegMask** debugmask = _method_handle_invoke ? m->idealreg2mhdebugmask : m->idealreg2debugmask; + return *debugmask[in(idx)->ideal_reg()]; +} + //============================================================================= uint MachCallStaticJavaNode::size_of() const { return sizeof(*this); } uint MachCallStaticJavaNode::cmp( const Node &n ) const { diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index 3c24a3e5c65..67d6965b628 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -662,9 +662,13 @@ public: ciMethod* _method; // Method being direct called int _bci; // Byte Code index of call byte code bool _optimized_virtual; // Tells if node is a static call or an optimized virtual + bool _method_handle_invoke; // Tells if the call has to preserve SP MachCallJavaNode() : MachCallNode() { init_class_id(Class_MachCallJava); } + + virtual const RegMask &in_RegMask(uint) const; + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index e2421a7f3d3..2fdc335b918 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -316,6 +316,21 @@ 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->is_ClearArray()) { + if (!ClearArrayNode::step_through(&mem, alloc->_idx, phase)) { + // Can not bypass initialization of the instance + // we are looking. + debug_only(intptr_t offset;) + assert(alloc == AllocateNode::Ideal_allocation(mem->in(3), phase, offset), "sanity"); + InitializeNode* init = alloc->as_Allocate()->initialization(); + // We are looking for stored value, return Initialize node + // or memory edge from Allocate node. + if (init != NULL) + return init; + else + return alloc->in(TypeFunc::Memory); // It will produce zero value (see callers). + } + // Otherwise skip it (the call updated 'mem' value). } 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(); @@ -823,6 +838,18 @@ void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) { Node *n = use->last_out(k); uint oc2 = use->outcnt(); if (n->is_Store()) { +#ifdef ASSERT + // Verify that there is no dependent MemBarVolatile nodes, + // they should be removed during IGVN, see MemBarNode::Ideal(). + for (DUIterator_Fast pmax, p = n->fast_outs(pmax); + p < pmax; p++) { + Node* mb = n->fast_out(p); + assert(mb->is_Initialize() || !mb->is_MemBar() || + mb->req() <= MemBarNode::Precedent || + mb->in(MemBarNode::Precedent) != n, + "MemBarVolatile should be eliminated for non-escaping object"); + } +#endif _igvn.replace_node(n, n->in(MemNode::Memory)); } else { eliminate_card_mark(n); @@ -912,15 +939,29 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { return false; } + CompileLog* log = C->log(); + if (log != NULL) { + Node* klass = alloc->in(AllocateNode::KlassNode); + const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr(); + log->head("eliminate_allocation type='%d'", + log->identify(tklass->klass())); + JVMState* p = alloc->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("eliminate_allocation"); + } + process_users_of_allocation(alloc); #ifndef PRODUCT -if (PrintEliminateAllocations) { - if (alloc->is_AllocateArray()) - tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx); - else - tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx); -} + if (PrintEliminateAllocations) { + if (alloc->is_AllocateArray()) + tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx); + else + tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx); + } #endif return true; @@ -1639,6 +1680,18 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) { } // if (!oldbox->is_eliminated()) } // if (alock->is_Lock() && !lock->is_coarsened()) + CompileLog* log = C->log(); + if (log != NULL) { + log->head("eliminate_lock lock='%d'", + alock->is_Lock()); + JVMState* p = alock->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("eliminate_lock"); + } + #ifndef PRODUCT if (PrintEliminateLocks) { if (alock->is_Lock()) { diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 57d2c5e72ae..d535df05c76 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -70,19 +70,27 @@ Matcher::Matcher( Node_List &proj_list ) : _dontcare(&_states_arena) { C->set_matcher(this); - idealreg2spillmask[Op_RegI] = NULL; - idealreg2spillmask[Op_RegN] = NULL; - idealreg2spillmask[Op_RegL] = NULL; - idealreg2spillmask[Op_RegF] = NULL; - idealreg2spillmask[Op_RegD] = NULL; - idealreg2spillmask[Op_RegP] = NULL; + idealreg2spillmask [Op_RegI] = NULL; + idealreg2spillmask [Op_RegN] = NULL; + idealreg2spillmask [Op_RegL] = NULL; + idealreg2spillmask [Op_RegF] = NULL; + idealreg2spillmask [Op_RegD] = NULL; + idealreg2spillmask [Op_RegP] = NULL; + + idealreg2debugmask [Op_RegI] = NULL; + idealreg2debugmask [Op_RegN] = NULL; + idealreg2debugmask [Op_RegL] = NULL; + idealreg2debugmask [Op_RegF] = NULL; + idealreg2debugmask [Op_RegD] = NULL; + idealreg2debugmask [Op_RegP] = NULL; + + idealreg2mhdebugmask[Op_RegI] = NULL; + idealreg2mhdebugmask[Op_RegN] = NULL; + idealreg2mhdebugmask[Op_RegL] = NULL; + idealreg2mhdebugmask[Op_RegF] = NULL; + idealreg2mhdebugmask[Op_RegD] = NULL; + idealreg2mhdebugmask[Op_RegP] = NULL; - idealreg2debugmask[Op_RegI] = NULL; - idealreg2debugmask[Op_RegN] = NULL; - idealreg2debugmask[Op_RegL] = NULL; - idealreg2debugmask[Op_RegF] = NULL; - idealreg2debugmask[Op_RegD] = NULL; - idealreg2debugmask[Op_RegP] = NULL; debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node } @@ -389,19 +397,28 @@ static RegMask *init_input_masks( uint size, RegMask &ret_adr, RegMask &fp ) { void Matcher::init_first_stack_mask() { // Allocate storage for spill masks as masks for the appropriate load type. - RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask)*12); - idealreg2spillmask[Op_RegN] = &rms[0]; - idealreg2spillmask[Op_RegI] = &rms[1]; - idealreg2spillmask[Op_RegL] = &rms[2]; - idealreg2spillmask[Op_RegF] = &rms[3]; - idealreg2spillmask[Op_RegD] = &rms[4]; - idealreg2spillmask[Op_RegP] = &rms[5]; - idealreg2debugmask[Op_RegN] = &rms[6]; - idealreg2debugmask[Op_RegI] = &rms[7]; - idealreg2debugmask[Op_RegL] = &rms[8]; - idealreg2debugmask[Op_RegF] = &rms[9]; - idealreg2debugmask[Op_RegD] = &rms[10]; - idealreg2debugmask[Op_RegP] = &rms[11]; + RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * 3*6); + + idealreg2spillmask [Op_RegN] = &rms[0]; + idealreg2spillmask [Op_RegI] = &rms[1]; + idealreg2spillmask [Op_RegL] = &rms[2]; + idealreg2spillmask [Op_RegF] = &rms[3]; + idealreg2spillmask [Op_RegD] = &rms[4]; + idealreg2spillmask [Op_RegP] = &rms[5]; + + idealreg2debugmask [Op_RegN] = &rms[6]; + idealreg2debugmask [Op_RegI] = &rms[7]; + idealreg2debugmask [Op_RegL] = &rms[8]; + idealreg2debugmask [Op_RegF] = &rms[9]; + idealreg2debugmask [Op_RegD] = &rms[10]; + idealreg2debugmask [Op_RegP] = &rms[11]; + + idealreg2mhdebugmask[Op_RegN] = &rms[12]; + idealreg2mhdebugmask[Op_RegI] = &rms[13]; + idealreg2mhdebugmask[Op_RegL] = &rms[14]; + idealreg2mhdebugmask[Op_RegF] = &rms[15]; + idealreg2mhdebugmask[Op_RegD] = &rms[16]; + idealreg2mhdebugmask[Op_RegP] = &rms[17]; OptoReg::Name i; @@ -442,12 +459,19 @@ void Matcher::init_first_stack_mask() { // Make up debug masks. Any spill slot plus callee-save registers. // Caller-save registers are assumed to be trashable by the various // inline-cache fixup routines. - *idealreg2debugmask[Op_RegN]= *idealreg2spillmask[Op_RegN]; - *idealreg2debugmask[Op_RegI]= *idealreg2spillmask[Op_RegI]; - *idealreg2debugmask[Op_RegL]= *idealreg2spillmask[Op_RegL]; - *idealreg2debugmask[Op_RegF]= *idealreg2spillmask[Op_RegF]; - *idealreg2debugmask[Op_RegD]= *idealreg2spillmask[Op_RegD]; - *idealreg2debugmask[Op_RegP]= *idealreg2spillmask[Op_RegP]; + *idealreg2debugmask [Op_RegN]= *idealreg2spillmask[Op_RegN]; + *idealreg2debugmask [Op_RegI]= *idealreg2spillmask[Op_RegI]; + *idealreg2debugmask [Op_RegL]= *idealreg2spillmask[Op_RegL]; + *idealreg2debugmask [Op_RegF]= *idealreg2spillmask[Op_RegF]; + *idealreg2debugmask [Op_RegD]= *idealreg2spillmask[Op_RegD]; + *idealreg2debugmask [Op_RegP]= *idealreg2spillmask[Op_RegP]; + + *idealreg2mhdebugmask[Op_RegN]= *idealreg2spillmask[Op_RegN]; + *idealreg2mhdebugmask[Op_RegI]= *idealreg2spillmask[Op_RegI]; + *idealreg2mhdebugmask[Op_RegL]= *idealreg2spillmask[Op_RegL]; + *idealreg2mhdebugmask[Op_RegF]= *idealreg2spillmask[Op_RegF]; + *idealreg2mhdebugmask[Op_RegD]= *idealreg2spillmask[Op_RegD]; + *idealreg2mhdebugmask[Op_RegP]= *idealreg2spillmask[Op_RegP]; // Prevent stub compilations from attempting to reference // callee-saved registers from debug info @@ -458,14 +482,31 @@ void Matcher::init_first_stack_mask() { if( _register_save_policy[i] == 'C' || _register_save_policy[i] == 'A' || (_register_save_policy[i] == 'E' && exclude_soe) ) { - idealreg2debugmask[Op_RegN]->Remove(i); - idealreg2debugmask[Op_RegI]->Remove(i); // Exclude save-on-call - idealreg2debugmask[Op_RegL]->Remove(i); // registers from debug - idealreg2debugmask[Op_RegF]->Remove(i); // masks - idealreg2debugmask[Op_RegD]->Remove(i); - idealreg2debugmask[Op_RegP]->Remove(i); + idealreg2debugmask [Op_RegN]->Remove(i); + idealreg2debugmask [Op_RegI]->Remove(i); // Exclude save-on-call + idealreg2debugmask [Op_RegL]->Remove(i); // registers from debug + idealreg2debugmask [Op_RegF]->Remove(i); // masks + idealreg2debugmask [Op_RegD]->Remove(i); + idealreg2debugmask [Op_RegP]->Remove(i); + + idealreg2mhdebugmask[Op_RegN]->Remove(i); + idealreg2mhdebugmask[Op_RegI]->Remove(i); + idealreg2mhdebugmask[Op_RegL]->Remove(i); + idealreg2mhdebugmask[Op_RegF]->Remove(i); + idealreg2mhdebugmask[Op_RegD]->Remove(i); + idealreg2mhdebugmask[Op_RegP]->Remove(i); } } + + // Subtract the register we use to save the SP for MethodHandle + // invokes to from the debug mask. + const RegMask save_mask = method_handle_invoke_SP_save_mask(); + idealreg2mhdebugmask[Op_RegN]->SUBTRACT(save_mask); + idealreg2mhdebugmask[Op_RegI]->SUBTRACT(save_mask); + idealreg2mhdebugmask[Op_RegL]->SUBTRACT(save_mask); + idealreg2mhdebugmask[Op_RegF]->SUBTRACT(save_mask); + idealreg2mhdebugmask[Op_RegD]->SUBTRACT(save_mask); + idealreg2mhdebugmask[Op_RegP]->SUBTRACT(save_mask); } //---------------------------is_save_on_entry---------------------------------- @@ -989,6 +1030,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { CallNode *call; const TypeTuple *domain; ciMethod* method = NULL; + bool is_method_handle_invoke = false; // for special kill effects if( sfpt->is_Call() ) { call = sfpt->as_Call(); domain = call->tf()->domain(); @@ -1013,6 +1055,8 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { mcall_java->_method = method; mcall_java->_bci = call_java->_bci; mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); + is_method_handle_invoke = call_java->is_method_handle_invoke(); + mcall_java->_method_handle_invoke = is_method_handle_invoke; if( mcall_java->is_MachCallStaticJava() ) mcall_java->as_MachCallStaticJava()->_name = call_java->as_CallStaticJava()->_name; @@ -1126,6 +1170,15 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { mcall->_argsize = out_arg_limit_per_call - begin_out_arg_area; } + if (is_method_handle_invoke) { + // Kill some extra stack space in case method handles want to do + // a little in-place argument insertion. + int regs_per_word = NOT_LP64(1) LP64_ONLY(2); // %%% make a global const! + out_arg_limit_per_call += MethodHandlePushLimit * regs_per_word; + // Do not update mcall->_argsize because (a) the extra space is not + // pushed as arguments and (b) _argsize is dead (not used anywhere). + } + // Compute the max stack slot killed by any call. These will not be // available for debug info, and will be used to adjust FIRST_STACK_mask // after all call sites have been visited. @@ -1832,67 +1885,23 @@ void Matcher::find_shared( Node *n ) { case Op_Binary: // These are introduced in the Post_Visit state. ShouldNotReachHere(); break; - case Op_StoreB: // Do match these, despite no ideal reg - case Op_StoreC: - case Op_StoreCM: - case Op_StoreD: - case Op_StoreF: - case Op_StoreI: - case Op_StoreL: - case Op_StoreP: - case Op_StoreN: - case Op_Store16B: - case Op_Store8B: - case Op_Store4B: - case Op_Store8C: - case Op_Store4C: - case Op_Store2C: - case Op_Store4I: - case Op_Store2I: - case Op_Store2L: - case Op_Store4F: - case Op_Store2F: - case Op_Store2D: case Op_ClearArray: case Op_SafePoint: mem_op = true; break; - case Op_LoadB: - case Op_LoadUS: - case Op_LoadD: - case Op_LoadF: - case Op_LoadI: - case Op_LoadKlass: - case Op_LoadNKlass: - case Op_LoadL: - case Op_LoadS: - case Op_LoadP: - case Op_LoadN: - case Op_LoadRange: - case Op_LoadD_unaligned: - case Op_LoadL_unaligned: - case Op_Load16B: - case Op_Load8B: - case Op_Load4B: - case Op_Load4C: - case Op_Load2C: - case Op_Load8C: - case Op_Load8S: - case Op_Load4S: - case Op_Load2S: - case Op_Load4I: - case Op_Load2I: - case Op_Load2L: - case Op_Load4F: - case Op_Load2F: - case Op_Load2D: - mem_op = true; - // Must be root of match tree due to prior load conflict - if( C->subsume_loads() == false ) { - set_shared(n); + default: + if( n->is_Store() ) { + // Do match stores, despite no ideal reg + mem_op = true; + break; + } + if( n->is_Mem() ) { // Loads and LoadStores + mem_op = true; + // Loads must be root of match tree due to prior load conflict + if( C->subsume_loads() == false ) + set_shared(n); } // Fall into default case - default: if( !n->ideal_reg() ) set_dontcare(n); // Unmatchable Nodes } // end_switch @@ -1913,15 +1922,15 @@ void Matcher::find_shared( Node *n ) { continue; // for(int i = ...) } - // Clone addressing expressions as they are "free" in most instructions - if( mem_op && i == MemNode::Address && mop == Op_AddP ) { - if (m->in(AddPNode::Base)->Opcode() == Op_DecodeN) { - // Bases used in addresses must be shared but since - // they are shared through a DecodeN they may appear - // to have a single use so force sharing here. - set_shared(m->in(AddPNode::Base)->in(1)); - } + if( mop == Op_AddP && m->in(AddPNode::Base)->Opcode() == Op_DecodeN ) { + // Bases used in addresses must be shared but since + // they are shared through a DecodeN they may appear + // to have a single use so force sharing here. + set_shared(m->in(AddPNode::Base)->in(1)); + } + // Clone addressing expressions as they are "free" in memory access instructions + if( mem_op && i == MemNode::Address && mop == Op_AddP ) { // 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. diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp index fe657c53421..b48303baa87 100644 --- a/hotspot/src/share/vm/opto/matcher.hpp +++ b/hotspot/src/share/vm/opto/matcher.hpp @@ -117,8 +117,9 @@ public: static const int base2reg[]; // Map Types to machine register types // Convert ideal machine register to a register mask for spill-loads static const RegMask *idealreg2regmask[]; - RegMask *idealreg2spillmask[_last_machine_leaf]; - RegMask *idealreg2debugmask[_last_machine_leaf]; + RegMask *idealreg2spillmask [_last_machine_leaf]; + RegMask *idealreg2debugmask [_last_machine_leaf]; + RegMask *idealreg2mhdebugmask[_last_machine_leaf]; void init_spill_mask( Node *ret ); // Convert machine register number to register mask static uint mreg2regmask_max; @@ -297,6 +298,8 @@ public: // Register for MODL projection of divmodL static RegMask modL_proj_mask(); + static const RegMask method_handle_invoke_SP_save_mask(); + // Java-Interpreter calling convention // (what you use when calling between compiled-Java and Interpreted-Java diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index b80f18c2e7d..4698add456b 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -123,6 +123,13 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, } else { assert(false, "unexpected projection"); } + } else if (result->is_ClearArray()) { + if (!ClearArrayNode::step_through(&result, instance_id, phase)) { + // Can not bypass initialization of the instance + // we are looking for. + break; + } + // Otherwise skip it (the call updated 'result' value). } else if (result->is_MergeMem()) { result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty); } @@ -255,6 +262,13 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { return NodeSentinel; // caller will return NULL } + // Do NOT remove or optimize the next lines: ensure a new alias index + // is allocated for an oop pointer type before Escape Analysis. + // Note: C++ will not remove it since the call has side effect. + if ( t_adr->isa_oopptr() ) { + int alias_idx = phase->C->get_alias_index(t_adr->is_ptr()); + } + #ifdef ASSERT Node* base = NULL; if (address->is_AddP()) @@ -530,6 +544,15 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) { } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { mem = mem->in(0)->in(TypeFunc::Memory); continue; // (a) advance through independent MemBar memory + } else if (mem->is_ClearArray()) { + if (ClearArrayNode::step_through(&mem, (uint)addr_t->instance_id(), phase)) { + // (the call updated 'mem' value) + continue; // (a) advance through independent allocation memory + } else { + // Can not bypass initialization of the instance + // we are looking for. + return mem; + } } else if (mem->is_MergeMem()) { int alias_idx = phase->C->get_alias_index(adr_type()); mem = mem->as_MergeMem()->memory_at(alias_idx); @@ -1496,6 +1519,8 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { } } } else if (tp->base() == Type::InstPtr) { + const TypeInstPtr* tinst = tp->is_instptr(); + ciKlass* klass = tinst->klass(); assert( off != Type::OffsetBot || // arrays can be cast to Objects tp->is_oopptr()->klass()->is_java_lang_Object() || @@ -1503,6 +1528,25 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { phase->C->has_unsafe_access(), "Field accesses must be precise" ); // For oop loads, we expect the _type to be precise + if (OptimizeStringConcat && klass == phase->C->env()->String_klass() && + adr->is_AddP() && off != Type::OffsetBot) { + // For constant Strings treat the fields as compile time constants. + Node* base = adr->in(AddPNode::Base); + if (base->Opcode() == Op_ConP) { + const TypeOopPtr* t = phase->type(base)->isa_oopptr(); + ciObject* string = t->const_oop(); + ciConstant constant = string->as_instance()->field_value_by_offset(off); + if (constant.basic_type() == T_INT) { + return TypeInt::make(constant.as_int()); + } else if (constant.basic_type() == T_ARRAY) { + if (adr->bottom_type()->is_ptr_to_narrowoop()) { + return TypeNarrowOop::make_from_constant(constant.as_object()); + } else { + return TypeOopPtr::make_from_constant(constant.as_object()); + } + } + } + } } else if (tp->base() == Type::KlassPtr) { assert( off != Type::OffsetBot || // arrays can be cast to Objects @@ -2426,6 +2470,31 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){ return mem; } +//----------------------------step_through---------------------------------- +// Return allocation input memory edge if it is different instance +// or itself if it is the one we are looking for. +bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* phase) { + Node* n = *np; + assert(n->is_ClearArray(), "sanity"); + intptr_t offset; + AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset); + // This method is called only before Allocate nodes are expanded during + // macro nodes expansion. Before that ClearArray nodes are only generated + // in LibraryCallKit::generate_arraycopy() which follows allocations. + assert(alloc != NULL, "should have allocation"); + if (alloc->_idx == instance_id) { + // Can not bypass initialization of the instance we are looking for. + return false; + } + // Otherwise skip it. + InitializeNode* init = alloc->initialization(); + if (init != NULL) + *np = init->in(TypeFunc::Memory); + else + *np = alloc->in(TypeFunc::Memory); + return true; +} + //----------------------------clear_memory------------------------------------- // Generate code to initialize object storage to zero. Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, @@ -2599,7 +2668,30 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) { // Return a node which is more "ideal" than the current node. Strip out // control copies Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return remove_dead_region(phase, can_reshape) ? this : NULL; + if (remove_dead_region(phase, can_reshape)) return this; + + // Eliminate volatile MemBars for scalar replaced objects. + if (can_reshape && req() == (Precedent+1) && + (Opcode() == Op_MemBarAcquire || Opcode() == Op_MemBarVolatile)) { + // Volatile field loads and stores. + Node* my_mem = in(MemBarNode::Precedent); + if (my_mem != NULL && my_mem->is_Mem()) { + const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr(); + // Check for scalar replaced object reference. + if( t_oop != NULL && t_oop->is_known_instance_field() && + t_oop->offset() != Type::OffsetBot && + t_oop->offset() != Type::OffsetTop) { + // Replace MemBar projections by its inputs. + PhaseIterGVN* igvn = phase->is_IterGVN(); + igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory)); + igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control)); + // Must return either the original node (now dead) or a new node + // (Do not return a top here, since that would break the uniqueness of top.) + return new (phase->C, 1) ConINode(TypeInt::ZERO); + } + } + } + return NULL; } //------------------------------Value------------------------------------------ diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index a71df7d406a..cd0e60d971e 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -717,7 +717,10 @@ public: //------------------------------ClearArray------------------------------------- class ClearArrayNode: public Node { public: - ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base ) : Node(ctrl,arymem,word_cnt,base) {} + ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base ) + : Node(ctrl,arymem,word_cnt,base) { + init_class_id(Class_ClearArray); + } virtual int Opcode() const; virtual const Type *bottom_type() const { return Type::MEMORY; } // ClearArray modifies array elements, and so affects only the @@ -743,6 +746,9 @@ public: Node* start_offset, Node* end_offset, PhaseGVN* phase); + // Return allocation input memory edge if it is different instance + // or itself if it is the one we are looking for. + static bool step_through(Node** np, uint instance_id, PhaseTransform* phase); }; //------------------------------StrComp------------------------------------- diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index bad1607058e..92da96b40a2 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -47,6 +47,7 @@ class CallStaticJavaNode; class CatchNode; class CatchProjNode; class CheckCastPPNode; +class ClearArrayNode; class CmpNode; class CodeBuffer; class ConstraintCastNode; @@ -599,8 +600,9 @@ public: DEFINE_CLASS_ID(BoxLock, Node, 10) DEFINE_CLASS_ID(Add, Node, 11) DEFINE_CLASS_ID(Mul, Node, 12) + DEFINE_CLASS_ID(ClearArray, Node, 13) - _max_classes = ClassMask_Mul + _max_classes = ClassMask_ClearArray }; #undef DEFINE_CLASS_ID @@ -661,18 +663,25 @@ public: return (_flags & Flag_is_Call) != 0; } + CallNode* isa_Call() const { + return is_Call() ? as_Call() : NULL; + } + CallNode *as_Call() const { // Only for CallNode (not for MachCallNode) assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class"); return (CallNode*)this; } - #define DEFINE_CLASS_QUERY(type) \ - bool is_##type() const { \ + #define DEFINE_CLASS_QUERY(type) \ + bool is_##type() const { \ return ((_class_id & ClassMask_##type) == Class_##type); \ - } \ - type##Node *as_##type() const { \ - assert(is_##type(), "invalid node class"); \ - return (type##Node*)this; \ + } \ + type##Node *as_##type() const { \ + assert(is_##type(), "invalid node class"); \ + return (type##Node*)this; \ + } \ + type##Node* isa_##type() const { \ + return (is_##type()) ? as_##type() : NULL; \ } DEFINE_CLASS_QUERY(AbstractLock) @@ -691,6 +700,7 @@ public: DEFINE_CLASS_QUERY(CatchProj) DEFINE_CLASS_QUERY(CheckCastPP) DEFINE_CLASS_QUERY(ConstraintCast) + DEFINE_CLASS_QUERY(ClearArray) DEFINE_CLASS_QUERY(CMove) DEFINE_CLASS_QUERY(Cmp) DEFINE_CLASS_QUERY(CountedLoop) @@ -1249,6 +1259,24 @@ Node* Node::last_out(DUIterator_Last& i) const { #undef I_VDUI_ONLY #undef VDUI_ONLY +// An Iterator that truly follows the iterator pattern. Doesn't +// support deletion but could be made to. +// +// for (SimpleDUIterator i(n); i.has_next(); i.next()) { +// Node* m = i.get(); +// +class SimpleDUIterator : public StackObj { + private: + Node* node; + DUIterator_Fast i; + DUIterator_Fast imax; + public: + SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {} + bool has_next() { return i < imax; } + void next() { i++; } + Node* get() { return node->fast_out(i); } +}; + //----------------------------------------------------------------------------- // Map dense integer indices to Nodes. Uses classic doubling-array trick. @@ -1290,6 +1318,12 @@ class Node_List : public Node_Array { public: Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {} Node_List(Arena *a) : Node_Array(a), _cnt(0) {} + bool contains(Node* n) { + for (uint e = 0; e < size(); e++) { + if (at(e) == n) return true; + } + return false; + } void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; } void remove( uint i ) { Node_Array::remove(i); _cnt--; } void push( Node *b ) { map(_cnt++,b); } diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 3274fd4d9df..c762808b63c 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -794,6 +794,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) { #endif int safepoint_pc_offset = current_offset; + bool is_method_handle_invoke = false; // Add the safepoint in the DebugInfoRecorder if( !mach->is_MachCall() ) { @@ -801,6 +802,11 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) { debug_info()->add_safepoint(safepoint_pc_offset, sfn->_oop_map); } else { mcall = mach->as_MachCall(); + + // Is the call a MethodHandle call? + if (mcall->is_MachCallJava()) + is_method_handle_invoke = mcall->as_MachCallJava()->_method_handle_invoke; + safepoint_pc_offset += mcall->ret_addr_offset(); debug_info()->add_safepoint(safepoint_pc_offset, mcall->_oop_map); } @@ -911,9 +917,9 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) { ciMethod* scope_method = method ? method : _method; // Describe the scope here assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); - assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); + assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset,scope_method,jvms->bci(),jvms->should_reexecute(),locvals,expvals,monvals); + debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, locvals, expvals, monvals); } // End jvms loop // Mark the end of the scope set. diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index 37f7b629fbe..d48b21971b7 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -39,6 +39,7 @@ class InlineTree : public ResourceObj { // Always between 0.0 and 1.0. Represents the percentage of the method's // total execution time used at this call site. const float _site_invoke_ratio; + const int _site_depth_adjust; float compute_callee_frequency( int caller_bci ) const; GrowableArray _subtrees; @@ -50,7 +51,8 @@ protected: ciMethod* callee_method, JVMState* caller_jvms, int caller_bci, - float site_invoke_ratio); + float site_invoke_ratio, + int site_depth_adjust); InlineTree *build_inline_tree_for_callee(ciMethod* callee_method, JVMState* caller_jvms, int caller_bci); @@ -61,14 +63,15 @@ protected: InlineTree *caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; - int inline_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } + int inline_depth() const { return stack_depth() + _site_depth_adjust; } + int stack_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } public: static InlineTree* build_inline_tree_root(); static InlineTree* find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee, bool create_if_not_found = false); // For temporary (stack-allocated, stateless) ilts: - InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio); + InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int site_depth_adjust); // InlineTree enum enum InlineStyle { @@ -427,6 +430,11 @@ class Parse : public GraphKit { } } + // Return true if the parser should add a loop predicate + bool should_add_predicate(int target_bci); + // Insert a loop predicate into the graph + void add_predicate(); + // Note: Intrinsic generation routines may be found in library_call.cpp. // Helper function to setup Ideal Call nodes @@ -488,7 +496,7 @@ class Parse : public GraphKit { void do_ifnull(BoolTest::mask btest, Node* c); void do_if(BoolTest::mask btest, Node* c); - void repush_if_args(); + int repush_if_args(); void adjust_map_after_if(BoolTest::mask btest, Node* c, float prob, Block* path, Block* other_path); IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 9633c5e270b..169cdc9754b 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -231,12 +231,13 @@ void Parse::load_interpreter_state(Node* osr_buf) { // Use the raw liveness computation to make sure that unexpected // values don't propagate into the OSR frame. - MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci()); + MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci()); if (!live_locals.is_valid()) { // Degenerate or breakpointed method. C->record_method_not_compilable("OSR in empty or breakpointed method"); return; } + MethodLivenessResult raw_live_locals = method()->raw_liveness_at_bci(osr_bci()); // Extract the needed locals from the interpreter frame. Node *locals_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals-1)*wordSize); @@ -316,6 +317,10 @@ void Parse::load_interpreter_state(Node* osr_buf) { continue; } } + if (type->basic_type() == T_ADDRESS && !raw_live_locals.at(index)) { + // Skip type check for dead address locals + continue; + } set_local(index, check_interpreter_type(l, type, bad_type_exit)); } @@ -1378,6 +1383,10 @@ void Parse::do_one_block() { set_parse_bci(iter().cur_bci()); if (bci() == block()->limit()) { + // insert a predicate if it falls through to a loop head block + if (should_add_predicate(bci())){ + add_predicate(); + } // Do not walk into the next block until directed by do_all_blocks. merge(bci()); break; @@ -2078,6 +2087,37 @@ void Parse::add_safepoint() { } } +//------------------------------should_add_predicate-------------------------- +bool Parse::should_add_predicate(int target_bci) { + if (!UseLoopPredicate) return false; + Block* target = successor_for_bci(target_bci); + if (target != NULL && + target->is_loop_head() && + block()->rpo() < target->rpo()) { + return true; + } + return false; +} + +//------------------------------add_predicate--------------------------------- +void Parse::add_predicate() { + assert(UseLoopPredicate,"use only for loop predicate"); + Node *cont = _gvn.intcon(1); + Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); + Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); + IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); + Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); + C->add_predicate_opaq(opq); + { + PreserveJVMState pjvms(this); + set_control(iffalse); + uncommon_trap(Deoptimization::Reason_predicate, + Deoptimization::Action_maybe_recompile); + } + Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); + set_control(iftrue); +} + #ifndef PRODUCT //------------------------show_parse_info-------------------------------------- void Parse::show_parse_info() { diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 5457d966b6f..869266c1769 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -278,6 +278,11 @@ void Parse::do_tableswitch() { if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); + if (should_add_predicate(default_dest)){ + _sp += 1; // set original stack for use by uncommon_trap + add_predicate(); + _sp -= 1; + } merge(default_dest); return; } @@ -324,6 +329,11 @@ void Parse::do_lookupswitch() { if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); + if (should_add_predicate(default_dest)){ + _sp += 1; // set original stack for use by uncommon_trap + add_predicate(); + _sp -= 1; + } merge(default_dest); return; } @@ -731,6 +741,9 @@ void Parse::do_jsr() { push(_gvn.makecon(ret_addr)); // Flow to the jsr. + if (should_add_predicate(jsr_bci)){ + add_predicate(); + } merge(jsr_bci); } @@ -881,7 +894,7 @@ bool Parse::seems_never_taken(float prob) { //-------------------------------repush_if_args-------------------------------- // Push arguments of an "if" bytecode back onto the stack by adjusting _sp. -inline void Parse::repush_if_args() { +inline int Parse::repush_if_args() { #ifndef PRODUCT if (PrintOpto && WizardMode) { tty->print("defending against excessive implicit null exceptions on %s @%d in ", @@ -895,6 +908,7 @@ inline void Parse::repush_if_args() { assert(argument(0) != NULL, "must exist"); assert(bc_depth == 1 || argument(1) != NULL, "two must exist"); _sp += bc_depth; + return bc_depth; } //----------------------------------do_ifnull---------------------------------- @@ -954,8 +968,14 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { // Update method data profile_taken_branch(target_bci); adjust_map_after_if(btest, c, prob, branch_block, next_block); - if (!stopped()) + if (!stopped()) { + if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop + int nargs = repush_if_args(); // set original stack for uncommon_trap + add_predicate(); + _sp -= nargs; + } merge(target_bci); + } } } @@ -1076,8 +1096,14 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { // Update method data profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); - if (!stopped()) + if (!stopped()) { + if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop + int nargs = repush_if_args(); // set original stack for the uncommon_trap + add_predicate(); + _sp -= nargs; + } merge(target_bci); + } } } @@ -2080,6 +2106,10 @@ void Parse::do_one_bytecode() { // Update method data profile_taken_branch(target_bci); + // Add loop predicate if it goes to a loop + if (should_add_predicate(target_bci)){ + add_predicate(); + } // Merge the current control into the target basic block merge(target_bci); diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 7125cb5d619..40f9940bd71 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -125,7 +125,25 @@ void Parse::do_field_access(bool is_get, bool is_field) { void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) { // Does this field have a constant value? If so, just push the value. - if (field->is_constant() && push_constant(field->constant_value())) return; + if (field->is_constant()) { + if (field->is_static()) { + // final static field + if (push_constant(field->constant_value())) + return; + } + else { + // final non-static field of a trusted class ({java,sun}.dyn + // classes). + if (obj->is_Con()) { + const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr(); + ciObject* constant_oop = oop_ptr->const_oop(); + ciConstant constant = field->constant_value_of(constant_oop); + + if (push_constant(constant, true)) + return; + } + } + } ciType* field_klass = field->type(); bool is_vol = field->is_volatile(); @@ -145,7 +163,7 @@ void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool if (!field->type()->is_loaded()) { type = TypeInstPtr::BOTTOM; must_assert_null = true; - } else if (field->is_constant()) { + } else if (field->is_constant() && field->is_static()) { // This can happen if the constant oop is non-perm. ciObject* con = field->constant_value().as_object(); // Do not "join" in the previous type; it doesn't add value, @@ -240,19 +258,19 @@ void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool // membar is dependent on the store, keeping any other membars generated // below from floating up past the store. int adr_idx = C->get_alias_index(adr_type); - insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx); + insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx, store); // Now place a membar for AliasIdxBot for the unknown yet-to-be-parsed // volatile alias indices. Skip this if the membar is redundant. if (adr_idx != Compile::AliasIdxBot) { - insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot); + insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot, store); } // Finally, place alias-index-specific membars for each volatile index // that isn't the adr_idx membar. Typically there's only 1 or 2. for( int i = Compile::AliasIdxRaw; i < C->num_alias_types(); i++ ) { if (i != adr_idx && C->alias_type(i)->is_volatile()) { - insert_mem_bar_volatile(Op_MemBarVolatile, i); + insert_mem_bar_volatile(Op_MemBarVolatile, i, store); } } } diff --git a/hotspot/src/share/vm/opto/parseHelper.cpp b/hotspot/src/share/vm/opto/parseHelper.cpp index 6b3f432eae7..ab7883fd8ff 100644 --- a/hotspot/src/share/vm/opto/parseHelper.cpp +++ b/hotspot/src/share/vm/opto/parseHelper.cpp @@ -221,6 +221,14 @@ void Parse::do_new() { // Push resultant oop onto stack push(obj); + + // Keep track of whether opportunities exist for StringBuilder + // optimizations. + if (OptimizeStringConcat && + (klass == C->env()->StringBuilder_klass() || + klass == C->env()->StringBuffer_klass())) { + C->set_has_stringbuilder(true); + } } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/phase.hpp b/hotspot/src/share/vm/opto/phase.hpp index d0d54e1d900..9df5500fd5e 100644 --- a/hotspot/src/share/vm/opto/phase.hpp +++ b/hotspot/src/share/vm/opto/phase.hpp @@ -44,6 +44,7 @@ public: BlockLayout, // Linear ordering of blocks Register_Allocation, // Register allocation, duh LIVE, // Dragon-book LIVE range problem + StringOpts, // StringBuilder related optimizations Interference_Graph, // Building the IFG Coalesce, // Coalescing copies Ideal_Loop, // Find idealized trip-counted loops diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index b9391ba1d97..33ff56f0ee4 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -345,7 +345,11 @@ public: Node *hash_find(const Node *n) { return _table.hash_find(n); } // Used after parsing to eliminate values that are no longer in program - void remove_useless_nodes(VectorSet &useful) { _table.remove_useless_nodes(useful); } + void remove_useless_nodes(VectorSet &useful) { + _table.remove_useless_nodes(useful); + // this may invalidate cached cons so reset the cache + init_con_caches(); + } virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 2b3851961ee..f0d0c217088 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.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 @@ -143,7 +143,7 @@ const char* OptoRuntime::stub_name(address entry) { // We failed the fast-path allocation. Now we need to do a scavenge or GC // and try allocation again. -void OptoRuntime::maybe_defer_card_mark(JavaThread* thread) { +void OptoRuntime::new_store_pre_barrier(JavaThread* thread) { // After any safepoint, just before going back to compiled code, // we inform the GC that we will be doing initializing writes to // this object in the future without emitting card-marks, so @@ -156,7 +156,7 @@ void OptoRuntime::maybe_defer_card_mark(JavaThread* thread) { assert(Universe::heap()->can_elide_tlab_store_barriers(), "compiler must check this first"); // GC may decide to give back a safer copy of new_obj. - new_obj = Universe::heap()->defer_store_barrier(thread, new_obj); + new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj); thread->set_vm_result(new_obj); } @@ -200,7 +200,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_instance_C(klassOopDesc* klass, JavaThrea if (GraphKit::use_ReduceInitialCardMarks()) { // inform GC that we won't do card marks for initializing writes. - maybe_defer_card_mark(thread); + new_store_pre_barrier(thread); } JRT_END @@ -239,7 +239,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(klassOopDesc* array_type, int len if (GraphKit::use_ReduceInitialCardMarks()) { // inform GC that we won't do card marks for initializing writes. - maybe_defer_card_mark(thread); + new_store_pre_barrier(thread); } JRT_END @@ -790,7 +790,7 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t NOT_PRODUCT(Exceptions::debug_check_abort(exception)); #ifdef ASSERT - if (!(exception->is_a(SystemDictionary::throwable_klass()))) { + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { // should throw an exception here ShouldNotReachHere(); } @@ -858,6 +858,9 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t thread->set_exception_pc(pc); thread->set_exception_handler_pc(handler_address); thread->set_exception_stack_size(0); + + // Check if the exception PC is a MethodHandle call. + thread->set_is_method_handle_exception(nm->is_method_handle_return(pc)); } // Restore correct return pc. Was saved above. @@ -936,7 +939,7 @@ address OptoRuntime::rethrow_C(oopDesc* exception, JavaThread* thread, address r #endif assert (exception != NULL, "should have thrown a NULLPointerException"); #ifdef ASSERT - if (!(exception->is_a(SystemDictionary::throwable_klass()))) { + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { // should throw an exception here ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index c3d8238ae1e..2c0c49880e4 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -133,8 +133,9 @@ class OptoRuntime : public AllStatic { // Allocate storage for a objArray or typeArray static void new_array_C(klassOopDesc* array_klass, int len, JavaThread *thread); - // Post-slow-path-allocation step for implementing ReduceInitialCardMarks: - static void maybe_defer_card_mark(JavaThread* thread); + // Post-slow-path-allocation, pre-initializing-stores step for + // implementing ReduceInitialCardMarks + static void new_store_pre_barrier(JavaThread* thread); // Allocate storage for a multi-dimensional arrays // Note: needs to be fixed for arbitrary number of dimensions diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp index a7a6baaa925..75ba440a6bd 100644 --- a/hotspot/src/share/vm/opto/split_if.cpp +++ b/hotspot/src/share/vm/opto/split_if.cpp @@ -219,6 +219,7 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { //------------------------------register_new_node------------------------------ void PhaseIdealLoop::register_new_node( Node *n, Node *blk ) { + assert(!n->is_CFG(), "must be data node"); _igvn.register_new_node_with_optimizer(n); set_ctrl(n, blk); IdealLoopTree *loop = get_loop(blk); diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp new file mode 100644 index 00000000000..192d31f8257 --- /dev/null +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -0,0 +1,1395 @@ +/* + * 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. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_stringopts.cpp.incl" + +#define __ kit. + +class StringConcat : public ResourceObj { + private: + PhaseStringOpts* _stringopts; + Node* _string_alloc; + AllocateNode* _begin; // The allocation the begins the pattern + CallStaticJavaNode* _end; // The final call of the pattern. Will either be + // SB.toString or or String.(SB.toString) + bool _multiple; // indicates this is a fusion of two or more + // separate StringBuilders + + Node* _arguments; // The list of arguments to be concatenated + GrowableArray _mode; // into a String along with a mode flag + // indicating how to treat the value. + + Node_List _control; // List of control nodes that will be deleted + Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten + // to restart at the initial JVMState. + public: + // Mode for converting arguments to Strings + enum { + StringMode, + IntMode, + CharMode + }; + + StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end): + _end(end), + _begin(NULL), + _multiple(false), + _string_alloc(NULL), + _stringopts(stringopts) { + _arguments = new (_stringopts->C, 1) Node(1); + _arguments->del_req(0); + } + + bool validate_control_flow(); + + void merge_add() { +#if 0 + // XXX This is place holder code for reusing an existing String + // allocation but the logic for checking the state safety is + // probably inadequate at the moment. + CallProjections endprojs; + sc->end()->extract_projections(&endprojs, false); + if (endprojs.resproj != NULL) { + for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) { + CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); + if (use != NULL && use->method() != NULL && + use->method()->holder() == C->env()->String_klass() && + use->method()->name() == ciSymbol::object_initializer_name() && + use->in(TypeFunc::Parms + 1) == endprojs.resproj) { + // Found useless new String(sb.toString()) so reuse the newly allocated String + // when creating the result instead of allocating a new one. + sc->set_string_alloc(use->in(TypeFunc::Parms)); + sc->set_end(use); + } + } + } +#endif + } + + StringConcat* merge(StringConcat* other, Node* arg); + + void set_allocation(AllocateNode* alloc) { + _begin = alloc; + } + + void append(Node* value, int mode) { + _arguments->add_req(value); + _mode.append(mode); + } + void push(Node* value, int mode) { + _arguments->ins_req(0, value); + _mode.insert_before(0, mode); + } + void push_string(Node* value) { + push(value, StringMode); + } + void push_int(Node* value) { + push(value, IntMode); + } + void push_char(Node* value) { + push(value, CharMode); + } + + Node* argument(int i) { + return _arguments->in(i); + } + void set_argument(int i, Node* value) { + _arguments->set_req(i, value); + } + int num_arguments() { + return _mode.length(); + } + int mode(int i) { + return _mode.at(i); + } + void add_control(Node* ctrl) { + assert(!_control.contains(ctrl), "only push once"); + _control.push(ctrl); + } + CallStaticJavaNode* end() { return _end; } + AllocateNode* begin() { return _begin; } + Node* string_alloc() { return _string_alloc; } + + void eliminate_unneeded_control(); + void eliminate_initialize(InitializeNode* init); + void eliminate_call(CallNode* call); + + void maybe_log_transform() { + CompileLog* log = _stringopts->C->log(); + if (log != NULL) { + log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'", + num_arguments(), + _string_alloc != NULL, + _multiple); + JVMState* p = _begin->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("replace_string_concat"); + } + } + + void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) { + for (uint u = 0; u < _uncommon_traps.size(); u++) { + Node* uct = _uncommon_traps.at(u); + + // Build a new call using the jvms state of the allocate + address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin(); + const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); + int size = call_type->domain()->cnt(); + const TypePtr* no_memory_effects = NULL; + Compile* C = _stringopts->C; + CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap", + jvms->bci(), no_memory_effects); + for (int e = 0; e < TypeFunc::Parms; e++) { + call->init_req(e, uct->in(e)); + } + // Set the trap request to record intrinsic failure if this trap + // is taken too many times. Ideally we would handle then traps by + // doing the original bookkeeping in the MDO so that if it caused + // the code to be thrown out we could still recompile and use the + // optimization. Failing the uncommon traps doesn't really mean + // that the optimization is a bad idea but there's no other way to + // do the MDO updates currently. + int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + call->init_req(TypeFunc::Parms, __ intcon(trap_request)); + kit.add_safepoint_edges(call); + + _stringopts->gvn()->transform(call); + C->gvn_replace_by(uct, call); + uct->disconnect_inputs(NULL); + } + } + + void cleanup() { + // disconnect the hook node + _arguments->disconnect_inputs(NULL); + } +}; + + +void StringConcat::eliminate_unneeded_control() { + eliminate_initialize(begin()->initialization()); + for (uint i = 0; i < _control.size(); i++) { + Node* n = _control.at(i); + if (n->is_Call()) { + if (n != _end) { + eliminate_call(n->as_Call()); + } + } else if (n->is_IfTrue()) { + Compile* C = _stringopts->C; + C->gvn_replace_by(n, n->in(0)->in(0)); + C->gvn_replace_by(n->in(0), C->top()); + } + } +} + + +StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { + StringConcat* result = new StringConcat(_stringopts, _end); + for (uint x = 0; x < _control.size(); x++) { + Node* n = _control.at(x); + if (n->is_Call()) { + result->_control.push(n); + } + } + for (uint x = 0; x < other->_control.size(); x++) { + Node* n = other->_control.at(x); + if (n->is_Call()) { + result->_control.push(n); + } + } + assert(result->_control.contains(other->_end), "what?"); + assert(result->_control.contains(_begin), "what?"); + for (int x = 0; x < num_arguments(); x++) { + if (argument(x) == arg) { + // replace the toString result with the all the arguments that + // made up the other StringConcat + for (int y = 0; y < other->num_arguments(); y++) { + result->append(other->argument(y), other->mode(y)); + } + } else { + result->append(argument(x), mode(x)); + } + } + result->set_allocation(other->_begin); + result->_multiple = true; + return result; +} + + +void StringConcat::eliminate_call(CallNode* call) { + Compile* C = _stringopts->C; + CallProjections projs; + call->extract_projections(&projs, false); + if (projs.fallthrough_catchproj != NULL) { + C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control)); + } + if (projs.fallthrough_memproj != NULL) { + C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory)); + } + if (projs.catchall_memproj != NULL) { + C->gvn_replace_by(projs.catchall_memproj, C->top()); + } + if (projs.fallthrough_ioproj != NULL) { + C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O)); + } + if (projs.catchall_ioproj != NULL) { + C->gvn_replace_by(projs.catchall_ioproj, C->top()); + } + if (projs.catchall_catchproj != NULL) { + // EA can't cope with the partially collapsed graph this + // creates so put it on the worklist to be collapsed later. + for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) { + Node *use = i.get(); + int opc = use->Opcode(); + if (opc == Op_CreateEx || opc == Op_Region) { + _stringopts->record_dead_node(use); + } + } + C->gvn_replace_by(projs.catchall_catchproj, C->top()); + } + if (projs.resproj != NULL) { + C->gvn_replace_by(projs.resproj, C->top()); + } + C->gvn_replace_by(call, C->top()); +} + +void StringConcat::eliminate_initialize(InitializeNode* init) { + Compile* C = _stringopts->C; + + // Eliminate Initialize node. + assert(init->outcnt() <= 2, "only a control and memory projection expected"); + assert(init->req() <= InitializeNode::RawStores, "no pending inits"); + Node *ctrl_proj = init->proj_out(TypeFunc::Control); + if (ctrl_proj != NULL) { + C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control)); + } + Node *mem_proj = init->proj_out(TypeFunc::Memory); + if (mem_proj != NULL) { + Node *mem = init->in(TypeFunc::Memory); + C->gvn_replace_by(mem_proj, mem); + } + C->gvn_replace_by(init, C->top()); + init->disconnect_inputs(NULL); +} + +Node_List PhaseStringOpts::collect_toString_calls() { + Node_List string_calls; + Node_List worklist; + + _visited.Clear(); + + // Prime the worklist + for (uint i = 1; i < C->root()->len(); i++) { + Node* n = C->root()->in(i); + if (n != NULL && !_visited.test_set(n->_idx)) { + worklist.push(n); + } + } + + while (worklist.size() > 0) { + Node* ctrl = worklist.pop(); + if (ctrl->is_CallStaticJava()) { + CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); + ciMethod* m = csj->method(); + if (m != NULL && + (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || + m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) { + string_calls.push(csj); + } + } + if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { + worklist.push(ctrl->in(0)); + } + if (ctrl->is_Region()) { + for (uint i = 1; i < ctrl->len(); i++) { + if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) { + worklist.push(ctrl->in(i)); + } + } + } + } + return string_calls; +} + + +StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { + ciMethod* m = call->method(); + ciSymbol* string_sig; + ciSymbol* int_sig; + ciSymbol* char_sig; + if (m->holder() == C->env()->StringBuilder_klass()) { + string_sig = ciSymbol::String_StringBuilder_signature(); + int_sig = ciSymbol::int_StringBuilder_signature(); + char_sig = ciSymbol::char_StringBuilder_signature(); + } else if (m->holder() == C->env()->StringBuffer_klass()) { + string_sig = ciSymbol::String_StringBuffer_signature(); + int_sig = ciSymbol::int_StringBuffer_signature(); + char_sig = ciSymbol::char_StringBuffer_signature(); + } else { + return NULL; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("considering toString call in "); + call->jvms()->dump_spec(tty); tty->cr(); + } +#endif + + StringConcat* sc = new StringConcat(this, call); + + AllocateNode* alloc = NULL; + InitializeNode* init = NULL; + + // possible opportunity for StringBuilder fusion + CallStaticJavaNode* cnode = call; + while (cnode) { + Node* recv = cnode->in(TypeFunc::Parms)->uncast(); + if (recv->is_Proj()) { + recv = recv->in(0); + } + cnode = recv->isa_CallStaticJava(); + if (cnode == NULL) { + alloc = recv->isa_Allocate(); + if (alloc == NULL) { + break; + } + // Find the constructor call + Node* result = alloc->result_cast(); + if (result == NULL || !result->is_CheckCastPP()) { + // strange looking allocation +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because allocation looks strange "); + alloc->jvms()->dump_spec(tty); tty->cr(); + } +#endif + break; + } + Node* constructor = NULL; + for (SimpleDUIterator i(result); i.has_next(); i.next()) { + CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); + if (use != NULL && use->method() != NULL && + use->method()->name() == ciSymbol::object_initializer_name() && + use->method()->holder() == m->holder()) { + // Matched the constructor. + ciSymbol* sig = use->method()->signature()->as_symbol(); + if (sig == ciSymbol::void_method_signature() || + sig == ciSymbol::int_void_signature() || + sig == ciSymbol::string_void_signature()) { + if (sig == ciSymbol::string_void_signature()) { + // StringBuilder(String) so pick this up as the first argument + assert(use->in(TypeFunc::Parms + 1) != NULL, "what?"); + sc->push_string(use->in(TypeFunc::Parms + 1)); + } + // The int variant takes an initial size for the backing + // array so just treat it like the void version. + constructor = use; + } else { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("unexpected constructor signature: %s", sig->as_utf8()); + } +#endif + } + break; + } + } + if (constructor == NULL) { + // couldn't find constructor +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because couldn't find constructor "); + alloc->jvms()->dump_spec(tty); + } +#endif + break; + } + + // Walked all the way back and found the constructor call so see + // if this call converted into a direct string concatenation. + sc->add_control(call); + sc->add_control(constructor); + sc->add_control(alloc); + sc->set_allocation(alloc); + if (sc->validate_control_flow()) { + return sc; + } else { + return NULL; + } + } else if (cnode->method() == NULL) { + break; + } else if (cnode->method()->holder() == m->holder() && + cnode->method()->name() == ciSymbol::append_name() && + (cnode->method()->signature()->as_symbol() == string_sig || + cnode->method()->signature()->as_symbol() == char_sig || + cnode->method()->signature()->as_symbol() == int_sig)) { + sc->add_control(cnode); + Node* arg = cnode->in(TypeFunc::Parms + 1); + if (cnode->method()->signature()->as_symbol() == int_sig) { + sc->push_int(arg); + } else if (cnode->method()->signature()->as_symbol() == char_sig) { + sc->push_char(arg); + } else { + if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); + if (csj->method() != NULL && + csj->method()->holder() == C->env()->Integer_klass() && + csj->method()->name() == ciSymbol::toString_name()) { + sc->add_control(csj); + sc->push_int(csj->in(TypeFunc::Parms)); + continue; + } + } + sc->push_string(arg); + } + continue; + } else { + // some unhandled signature +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because encountered unexpected signature "); + cnode->tf()->dump(); tty->cr(); + cnode->in(TypeFunc::Parms + 1)->dump(); + } +#endif + break; + } + } + return NULL; +} + + +PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): + Phase(StringOpts), + _gvn(gvn), + _visited(Thread::current()->resource_area()) { + + assert(OptimizeStringConcat, "shouldn't be here"); + + size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), + ciSymbol::make("[I"), true); + if (size_table_field == NULL) { + // Something wrong so give up. + assert(false, "why can't we find Integer.sizeTable?"); + return; + } + + // Collect the types needed to talk about the various slices of memory + const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), + false, NULL, 0); + + const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes()); + const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes()); + const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes()); + + value_field_idx = C->get_alias_index(value_field_type); + count_field_idx = C->get_alias_index(count_field_type); + offset_field_idx = C->get_alias_index(offset_field_type); + char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS); + + // For each locally allocated StringBuffer see if the usages can be + // collapsed into a single String construction. + + // Run through the list of allocation looking for SB.toString to see + // if it's possible to fuse the usage of the SB into a single String + // construction. + GrowableArray concats; + Node_List toStrings = collect_toString_calls(); + while (toStrings.size() > 0) { + StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava()); + if (sc != NULL) { + concats.push(sc); + } + } + + // try to coalesce separate concats + restart: + for (int c = 0; c < concats.length(); c++) { + StringConcat* sc = concats.at(c); + for (int i = 0; i < sc->num_arguments(); i++) { + Node* arg = sc->argument(i); + if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); + if (csj->method() != NULL && + (csj->method()->holder() == C->env()->StringBuffer_klass() || + csj->method()->holder() == C->env()->StringBuilder_klass()) && + csj->method()->name() == ciSymbol::toString_name()) { + for (int o = 0; o < concats.length(); o++) { + if (c == o) continue; + StringConcat* other = concats.at(o); + if (other->end() == csj) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("considering stacked concats"); + } +#endif + + StringConcat* merged = sc->merge(other, arg); + if (merged->validate_control_flow()) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("stacking would succeed"); + } +#endif + if (c < o) { + concats.remove_at(o); + concats.at_put(c, merged); + } else { + concats.remove_at(c); + concats.at_put(o, merged); + } + goto restart; + } else { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("stacking would fail"); + } +#endif + } + } + } + } + } + } + } + + + for (int c = 0; c < concats.length(); c++) { + StringConcat* sc = concats.at(c); + replace_string_concat(sc); + } + + remove_dead_nodes(); +} + +void PhaseStringOpts::record_dead_node(Node* dead) { + dead_worklist.push(dead); +} + +void PhaseStringOpts::remove_dead_nodes() { + // Delete any dead nodes to make things clean enough that escape + // analysis doesn't get unhappy. + while (dead_worklist.size() > 0) { + Node* use = dead_worklist.pop(); + int opc = use->Opcode(); + switch (opc) { + case Op_Region: { + uint i = 1; + for (i = 1; i < use->req(); i++) { + if (use->in(i) != C->top()) { + break; + } + } + if (i >= use->req()) { + for (SimpleDUIterator i(use); i.has_next(); i.next()) { + Node* m = i.get(); + if (m->is_Phi()) { + dead_worklist.push(m); + } + } + C->gvn_replace_by(use, C->top()); + } + break; + } + case Op_AddP: + case Op_CreateEx: { + // Recurisvely clean up references to CreateEx so EA doesn't + // get unhappy about the partially collapsed graph. + for (SimpleDUIterator i(use); i.has_next(); i.next()) { + Node* m = i.get(); + if (m->is_AddP()) { + dead_worklist.push(m); + } + } + C->gvn_replace_by(use, C->top()); + break; + } + case Op_Phi: + if (use->in(0) == C->top()) { + C->gvn_replace_by(use, C->top()); + } + break; + } + } +} + + +bool StringConcat::validate_control_flow() { + // We found all the calls and arguments now lets see if it's + // safe to transform the graph as we would expect. + + // Check to see if this resulted in too many uncommon traps previously + if (Compile::current()->too_many_traps(_begin->jvms()->method(), _begin->jvms()->bci(), + Deoptimization::Reason_intrinsic)) { + return false; + } + + // Walk backwards over the control flow from toString to the + // allocation and make sure all the control flow is ok. This + // means it's either going to be eliminated once the calls are + // removed or it can safely be transformed into an uncommon + // trap. + + int null_check_count = 0; + Unique_Node_List ctrl_path; + + assert(_control.contains(_begin), "missing"); + assert(_control.contains(_end), "missing"); + + // Collect the nodes that we know about and will eliminate into ctrl_path + for (uint i = 0; i < _control.size(); i++) { + // Push the call and it's control projection + Node* n = _control.at(i); + if (n->is_Allocate()) { + AllocateNode* an = n->as_Allocate(); + InitializeNode* init = an->initialization(); + ctrl_path.push(init); + ctrl_path.push(init->as_Multi()->proj_out(0)); + } + if (n->is_Call()) { + CallNode* cn = n->as_Call(); + ctrl_path.push(cn); + ctrl_path.push(cn->proj_out(0)); + ctrl_path.push(cn->proj_out(0)->unique_out()); + ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0)); + } else { + ShouldNotReachHere(); + } + } + + // Skip backwards through the control checking for unexpected contro flow + Node* ptr = _end; + bool fail = false; + while (ptr != _begin) { + if (ptr->is_Call() && ctrl_path.member(ptr)) { + ptr = ptr->in(0); + } else if (ptr->is_CatchProj() && ctrl_path.member(ptr)) { + ptr = ptr->in(0)->in(0)->in(0); + assert(ctrl_path.member(ptr), "should be a known piece of control"); + } else if (ptr->is_IfTrue()) { + IfNode* iff = ptr->in(0)->as_If(); + BoolNode* b = iff->in(1)->isa_Bool(); + Node* cmp = b->in(1); + Node* v1 = cmp->in(1); + Node* v2 = cmp->in(2); + Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con); + + // Null check of the return of append which can simply be eliminated + if (b->_test._test == BoolTest::ne && + v2->bottom_type() == TypePtr::NULL_PTR && + v1->is_Proj() && ctrl_path.member(v1->in(0))) { + // NULL check of the return value of the append + null_check_count++; + if (otherproj->outcnt() == 1) { + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); + if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { + ctrl_path.push(call); + } + } + _control.push(ptr); + ptr = ptr->in(0)->in(0); + continue; + } + + // A test which leads to an uncommon trap which should be safe. + // Later this trap will be converted into a trap that restarts + // at the beginning. + if (otherproj->outcnt() == 1) { + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); + if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { + // control flow leads to uct so should be ok + _uncommon_traps.push(call); + ctrl_path.push(call); + ptr = ptr->in(0)->in(0); + continue; + } + } + +#ifndef PRODUCT + // Some unexpected control flow we don't know how to handle. + if (PrintOptimizeStringConcat) { + tty->print_cr("failing with unknown test"); + b->dump(); + cmp->dump(); + v1->dump(); + v2->dump(); + tty->cr(); + } +#endif + break; + } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) { + ptr = ptr->in(0)->in(0); + } else if (ptr->is_Region()) { + Node* copy = ptr->as_Region()->is_copy(); + if (copy != NULL) { + ptr = copy; + continue; + } + if (ptr->req() == 3 && + ptr->in(1) != NULL && ptr->in(1)->is_Proj() && + ptr->in(2) != NULL && ptr->in(2)->is_Proj() && + ptr->in(1)->in(0) == ptr->in(2)->in(0) && + ptr->in(1)->in(0) != NULL && ptr->in(1)->in(0)->is_If()) { + // Simple diamond. + // XXX should check for possibly merging stores. simple data merges are ok. + ptr = ptr->in(1)->in(0)->in(0); + continue; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("fusion would fail for region"); + _begin->dump(); + ptr->dump(2); + } +#endif + fail = true; + break; + } else { + // other unknown control + if (!fail) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("fusion would fail for"); + _begin->dump(); + } +#endif + fail = true; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + ptr->dump(); + } +#endif + ptr = ptr->in(0); + } + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat && fail) { + tty->cr(); + } +#endif + if (fail) return !fail; + + // Validate that all these results produced are contained within + // this cluster of objects. First collect all the results produced + // by calls in the region. + _stringopts->_visited.Clear(); + Node_List worklist; + Node* final_result = _end->proj_out(TypeFunc::Parms); + for (uint i = 0; i < _control.size(); i++) { + CallNode* cnode = _control.at(i)->isa_Call(); + if (cnode != NULL) { + _stringopts->_visited.test_set(cnode->_idx); + } + Node* result = cnode != NULL ? cnode->proj_out(TypeFunc::Parms) : NULL; + if (result != NULL && result != final_result) { + worklist.push(result); + } + } + + Node* last_result = NULL; + while (worklist.size() > 0) { + Node* result = worklist.pop(); + if (_stringopts->_visited.test_set(result->_idx)) + continue; + for (SimpleDUIterator i(result); i.has_next(); i.next()) { + Node *use = i.get(); + if (ctrl_path.member(use)) { + // already checked this + continue; + } + int opc = use->Opcode(); + if (opc == Op_CmpP || opc == Op_Node) { + ctrl_path.push(use); + continue; + } + if (opc == Op_CastPP || opc == Op_CheckCastPP) { + for (SimpleDUIterator j(use); j.has_next(); j.next()) { + worklist.push(j.get()); + } + worklist.push(use->in(1)); + ctrl_path.push(use); + continue; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + if (result != last_result) { + last_result = result; + tty->print_cr("extra uses for result:"); + last_result->dump(); + } + use->dump(); + } +#endif + fail = true; + break; + } + } + +#ifndef PRODUCT + if (PrintOptimizeStringConcat && !fail) { + ttyLocker ttyl; + tty->cr(); + tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); + _begin->jvms()->dump_spec(tty); tty->cr(); + for (int i = 0; i < num_arguments(); i++) { + argument(i)->dump(); + } + _control.dump(); + tty->cr(); + } +#endif + + return !fail; +} + +Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) { + const TypeKlassPtr* klass_type = TypeKlassPtr::make(field->holder()); + Node* klass_node = __ makecon(klass_type); + BasicType bt = field->layout_type(); + ciType* field_klass = field->type(); + + const Type *type; + if( bt == T_OBJECT ) { + if (!field->type()->is_loaded()) { + type = TypeInstPtr::BOTTOM; + } else if (field->is_constant()) { + // This can happen if the constant oop is non-perm. + ciObject* con = field->constant_value().as_object(); + // Do not "join" in the previous type; it doesn't add value, + // and may yield a vacuous result if the field is of interface type. + type = TypeOopPtr::make_from_constant(con)->isa_oopptr(); + assert(type != NULL, "field singleton type must be consistent"); + } else { + type = TypeOopPtr::make_from_klass(field_klass->as_klass()); + } + } else { + type = Type::get_const_basic_type(bt); + } + + return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()), + type, T_OBJECT, + C->get_alias_index(klass_type->add_offset(field->offset_in_bytes()))); +} + +Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) { + RegionNode *final_merge = new (C, 3) RegionNode(3); + kit.gvn().set_type(final_merge, Type::CONTROL); + Node* final_size = new (C, 3) PhiNode(final_merge, TypeInt::INT); + kit.gvn().set_type(final_size, TypeInt::INT); + + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + Node* is_min = __ IfFalse(iff); + final_merge->init_req(1, is_min); + final_size->init_req(1, __ intcon(11)); + + kit.set_control(__ IfTrue(iff)); + if (kit.stopped()) { + final_merge->init_req(2, C->top()); + final_size->init_req(2, C->top()); + } else { + + // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); + RegionNode *r = new (C, 3) RegionNode(3); + kit.gvn().set_type(r, Type::CONTROL); + Node *phi = new (C, 3) PhiNode(r, TypeInt::INT); + kit.gvn().set_type(phi, TypeInt::INT); + Node *size = new (C, 3) PhiNode(r, TypeInt::INT); + kit.gvn().set_type(size, TypeInt::INT); + Node* chk = __ CmpI(arg, __ intcon(0)); + Node* p = __ Bool(chk, BoolTest::lt); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN); + Node* lessthan = __ IfTrue(iff); + Node* greaterequal = __ IfFalse(iff); + r->init_req(1, lessthan); + phi->init_req(1, __ SubI(__ intcon(0), arg)); + size->init_req(1, __ intcon(1)); + r->init_req(2, greaterequal); + phi->init_req(2, arg); + size->init_req(2, __ intcon(0)); + kit.set_control(r); + C->record_for_igvn(r); + C->record_for_igvn(phi); + C->record_for_igvn(size); + + // for (int i=0; ; i++) + // if (x <= sizeTable[i]) + // return i+1; + RegionNode *loop = new (C, 3) RegionNode(3); + loop->init_req(1, kit.control()); + kit.gvn().set_type(loop, Type::CONTROL); + + Node *index = new (C, 3) PhiNode(loop, TypeInt::INT); + index->init_req(1, __ intcon(0)); + kit.gvn().set_type(index, TypeInt::INT); + kit.set_control(loop); + Node* sizeTable = fetch_static_field(kit, size_table_field); + + Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS); + C->record_for_igvn(value); + Node* limit = __ CmpI(phi, value); + Node* limitb = __ Bool(limit, BoolTest::le); + IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN); + Node* lessEqual = __ IfTrue(iff2); + Node* greater = __ IfFalse(iff2); + + loop->init_req(2, greater); + index->init_req(2, __ AddI(index, __ intcon(1))); + + kit.set_control(lessEqual); + C->record_for_igvn(loop); + C->record_for_igvn(index); + + final_merge->init_req(2, kit.control()); + final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1))); + } + + kit.set_control(final_merge); + C->record_for_igvn(final_merge); + C->record_for_igvn(final_size); + + return final_size; +} + +void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) { + RegionNode *final_merge = new (C, 4) RegionNode(4); + kit.gvn().set_type(final_merge, Type::CONTROL); + Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); + kit.gvn().set_type(final_mem, Type::MEMORY); + + // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive + { + // i == MIN_VALUE + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + + Node* old_mem = kit.memory(char_adr_idx); + + kit.set_control(__ IfFalse(iff)); + if (kit.stopped()) { + // Statically not equal to MIN_VALUE so this path is dead + final_merge->init_req(3, kit.control()); + } else { + copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())), + char_array, start); + final_merge->init_req(3, kit.control()); + final_mem->init_req(3, kit.memory(char_adr_idx)); + } + + kit.set_control(__ IfTrue(iff)); + kit.set_memory(old_mem, char_adr_idx); + } + + + // Simplified version of Integer.getChars + + // int q, r; + // int charPos = index; + Node* charPos = end; + + // char sign = 0; + + Node* i = arg; + Node* sign = __ intcon(0); + + // if (i < 0) { + // sign = '-'; + // i = -i; + // } + { + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt), + PROB_FAIR, COUNT_UNKNOWN); + + RegionNode *merge = new (C, 3) RegionNode(3); + kit.gvn().set_type(merge, Type::CONTROL); + i = new (C, 3) PhiNode(merge, TypeInt::INT); + kit.gvn().set_type(i, TypeInt::INT); + sign = new (C, 3) PhiNode(merge, TypeInt::INT); + kit.gvn().set_type(sign, TypeInt::INT); + + merge->init_req(1, __ IfTrue(iff)); + i->init_req(1, __ SubI(__ intcon(0), arg)); + sign->init_req(1, __ intcon('-')); + merge->init_req(2, __ IfFalse(iff)); + i->init_req(2, arg); + sign->init_req(2, __ intcon(0)); + + kit.set_control(merge); + + C->record_for_igvn(merge); + C->record_for_igvn(i); + C->record_for_igvn(sign); + } + + // for (;;) { + // q = i / 10; + // r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... + // buf [--charPos] = digits [r]; + // i = q; + // if (i == 0) break; + // } + + { + RegionNode *head = new (C, 3) RegionNode(3); + head->init_req(1, kit.control()); + kit.gvn().set_type(head, Type::CONTROL); + Node *i_phi = new (C, 3) PhiNode(head, TypeInt::INT); + i_phi->init_req(1, i); + kit.gvn().set_type(i_phi, TypeInt::INT); + charPos = PhiNode::make(head, charPos); + kit.gvn().set_type(charPos, TypeInt::INT); + Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); + kit.gvn().set_type(mem, Type::MEMORY); + kit.set_control(head); + kit.set_memory(mem, char_adr_idx); + + Node* q = __ DivI(kit.null(), i_phi, __ intcon(10)); + Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)), + __ LShiftI(q, __ intcon(1)))); + Node* m1 = __ SubI(charPos, __ intcon(1)); + Node* ch = __ AddI(r, __ intcon('0')); + + Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), + ch, T_CHAR, char_adr_idx); + + + IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + Node* ne = __ IfTrue(iff); + Node* eq = __ IfFalse(iff); + + head->init_req(2, ne); + mem->init_req(2, st); + i_phi->init_req(2, q); + charPos->init_req(2, m1); + + charPos = m1; + + kit.set_control(eq); + kit.set_memory(st, char_adr_idx); + + C->record_for_igvn(head); + C->record_for_igvn(mem); + C->record_for_igvn(i_phi); + C->record_for_igvn(charPos); + } + + { + // if (sign != 0) { + // buf [--charPos] = sign; + // } + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + + final_merge->init_req(2, __ IfFalse(iff)); + final_mem->init_req(2, kit.memory(char_adr_idx)); + + kit.set_control(__ IfTrue(iff)); + if (kit.stopped()) { + final_merge->init_req(1, C->top()); + final_mem->init_req(1, C->top()); + } else { + Node* m1 = __ SubI(charPos, __ intcon(1)); + Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), + sign, T_CHAR, char_adr_idx); + + final_merge->init_req(1, kit.control()); + final_mem->init_req(1, st); + } + + kit.set_control(final_merge); + kit.set_memory(final_mem, char_adr_idx); + + C->record_for_igvn(final_merge); + C->record_for_igvn(final_mem); + } +} + + +Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) { + Node* string = str; + Node* offset = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::offset_offset_in_bytes()), + TypeInt::INT, T_INT, offset_field_idx); + Node* count = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::count_offset_in_bytes()), + TypeInt::INT, T_INT, count_field_idx); + const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, + TypeAry::make(TypeInt::CHAR,TypeInt::POS), + ciTypeArrayKlass::make(T_CHAR), true, 0); + Node* value = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::value_offset_in_bytes()), + value_type, T_OBJECT, value_field_idx); + + // copy the contents + if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) { + // For small constant strings just emit individual stores. + // A length of 6 seems like a good space/speed tradeof. + int c = count->get_int(); + int o = offset->get_int(); + const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr(); + ciTypeArray* value_array = t->const_oop()->as_type_array(); + for (int e = 0; e < c; e++) { + __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), + __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx); + start = __ AddI(start, __ intcon(1)); + } + } else { + Node* src_ptr = kit.array_element_address(value, offset, T_CHAR); + Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR); + Node* c = count; + Node* extra = NULL; +#ifdef _LP64 + c = __ ConvI2L(c); + extra = C->top(); +#endif + Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP, + OptoRuntime::fast_arraycopy_Type(), + CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()), + "jshort_disjoint_arraycopy", TypeAryPtr::CHARS, + src_ptr, dst_ptr, c, extra); + start = __ AddI(start, count); + } + return start; +} + + +void PhaseStringOpts::replace_string_concat(StringConcat* sc) { + // Log a little info about the transformation + sc->maybe_log_transform(); + + // pull the JVMState of the allocation into a SafePointNode to serve as + // as a shim for the insertion of the new code. + JVMState* jvms = sc->begin()->jvms()->clone_shallow(C); + uint size = sc->begin()->req(); + SafePointNode* map = new (C, size) SafePointNode(size, jvms); + + // copy the control and memory state from the final call into our + // new starting state. This allows any preceeding tests to feed + // into the new section of code. + for (uint i1 = 0; i1 < TypeFunc::Parms; i1++) { + map->init_req(i1, sc->end()->in(i1)); + } + // blow away old allocation arguments + for (uint i1 = TypeFunc::Parms; i1 < jvms->debug_start(); i1++) { + map->init_req(i1, C->top()); + } + // Copy the rest of the inputs for the JVMState + for (uint i1 = jvms->debug_start(); i1 < sc->begin()->req(); i1++) { + map->init_req(i1, sc->begin()->in(i1)); + } + // Make sure the memory state is a MergeMem for parsing. + if (!map->in(TypeFunc::Memory)->is_MergeMem()) { + map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); + } + + jvms->set_map(map); + map->ensure_stack(jvms, jvms->method()->max_stack()); + + + // disconnect all the old StringBuilder calls from the graph + sc->eliminate_unneeded_control(); + + // At this point all the old work has been completely removed from + // the graph and the saved JVMState exists at the point where the + // final toString call used to be. + GraphKit kit(jvms); + + // There may be uncommon traps which are still using the + // intermediate states and these need to be rewritten to point at + // the JVMState at the beginning of the transformation. + sc->convert_uncommon_traps(kit, jvms); + + // Now insert the logic to compute the size of the string followed + // by all the logic to construct array and resulting string. + + Node* null_string = __ makecon(TypeInstPtr::make(C->env()->the_null_string())); + + // Create a region for the overflow checks to merge into. + int args = MAX2(sc->num_arguments(), 1); + RegionNode* overflow = new (C, args) RegionNode(args); + kit.gvn().set_type(overflow, Type::CONTROL); + + // Create a hook node to hold onto the individual sizes since they + // are need for the copying phase. + Node* string_sizes = new (C, args) Node(args); + + Node* length = __ intcon(0); + for (int argi = 0; argi < sc->num_arguments(); argi++) { + Node* arg = sc->argument(argi); + switch (sc->mode(argi)) { + case StringConcat::IntMode: { + Node* string_size = int_stringSize(kit, arg); + + // accumulate total + length = __ AddI(length, string_size); + + // Cache this value for the use by int_toString + string_sizes->init_req(argi, string_size); + break; + } + case StringConcat::StringMode: { + const Type* type = kit.gvn().type(arg); + if (type == TypePtr::NULL_PTR) { + // replace the argument with the null checked version + arg = null_string; + sc->set_argument(argi, arg); + } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { + // s = s != null ? s : "null"; + // length = length + (s.count - s.offset); + RegionNode *r = new (C, 3) RegionNode(3); + kit.gvn().set_type(r, Type::CONTROL); + Node *phi = new (C, 3) PhiNode(r, type->join(TypeInstPtr::NOTNULL)); + kit.gvn().set_type(phi, phi->bottom_type()); + Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN); + Node* notnull = __ IfTrue(iff); + Node* isnull = __ IfFalse(iff); + r->init_req(1, notnull); + phi->init_req(1, arg); + r->init_req(2, isnull); + phi->init_req(2, null_string); + kit.set_control(r); + C->record_for_igvn(r); + C->record_for_igvn(phi); + // replace the argument with the null checked version + arg = phi; + sc->set_argument(argi, arg); + } + // Node* offset = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, offset_offset), + // TypeInt::INT, T_INT, offset_field_idx); + Node* count = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()), + TypeInt::INT, T_INT, count_field_idx); + length = __ AddI(length, count); + string_sizes->init_req(argi, NULL); + break; + } + case StringConcat::CharMode: { + // one character only + length = __ AddI(length, __ intcon(1)); + break; + } + default: + ShouldNotReachHere(); + } + if (argi > 0) { + // Check that the sum hasn't overflowed + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(length, __ intcon(0)), BoolTest::lt), + PROB_MIN, COUNT_UNKNOWN); + kit.set_control(__ IfFalse(iff)); + overflow->set_req(argi, __ IfTrue(iff)); + } + } + + { + // Hook + PreserveJVMState pjvms(&kit); + kit.set_control(overflow); + kit.uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + } + + // length now contains the number of characters needed for the + // char[] so create a new AllocateArray for the char[] + Node* char_array = NULL; + { + PreserveReexecuteState preexecs(&kit); + // The original jvms is for an allocation of either a String or + // StringBuffer so no stack adjustment is necessary for proper + // reexecution. If we deoptimize in the slow path the bytecode + // will be reexecuted and the char[] allocation will be thrown away. + kit.jvms()->set_should_reexecute(true); + char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))), + length, 1); + } + + // Mark the allocation so that zeroing is skipped since the code + // below will overwrite the entire array + AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn); + char_alloc->maybe_set_complete(_gvn); + + // Now copy the string representations into the final char[] + Node* start = __ intcon(0); + for (int argi = 0; argi < sc->num_arguments(); argi++) { + Node* arg = sc->argument(argi); + switch (sc->mode(argi)) { + case StringConcat::IntMode: { + Node* end = __ AddI(start, string_sizes->in(argi)); + // getChars words backwards so pass the ending point as well as the start + int_getChars(kit, arg, char_array, start, end); + start = end; + break; + } + case StringConcat::StringMode: { + start = copy_string(kit, arg, char_array, start); + break; + } + case StringConcat::CharMode: { + __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), + arg, T_CHAR, char_adr_idx); + start = __ AddI(start, __ intcon(1)); + break; + } + default: + ShouldNotReachHere(); + } + } + + // If we're not reusing an existing String allocation then allocate one here. + Node* result = sc->string_alloc(); + if (result == NULL) { + PreserveReexecuteState preexecs(&kit); + // The original jvms is for an allocation of either a String or + // StringBuffer so no stack adjustment is necessary for proper + // reexecution. + kit.jvms()->set_should_reexecute(true); + result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass()))); + } + + // Intialize the string + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()), + __ intcon(0), T_INT, offset_field_idx); + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()), + length, T_INT, count_field_idx); + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::value_offset_in_bytes()), + char_array, T_OBJECT, value_field_idx); + + // hook up the outgoing control and result + kit.replace_call(sc->end(), result); + + // Unhook any hook nodes + string_sizes->disconnect_inputs(NULL); + sc->cleanup(); +} diff --git a/hotspot/src/share/vm/opto/stringopts.hpp b/hotspot/src/share/vm/opto/stringopts.hpp new file mode 100644 index 00000000000..417e08a9185 --- /dev/null +++ b/hotspot/src/share/vm/opto/stringopts.hpp @@ -0,0 +1,83 @@ +/* + * 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. + * + */ + +class StringConcat; + +class PhaseStringOpts : public Phase { + friend class StringConcat; + + private: + PhaseGVN* _gvn; + + // List of dead nodes to clean up aggressively at the end + Unique_Node_List dead_worklist; + + // Memory slices needed for code gen + int char_adr_idx; + int value_field_idx; + int count_field_idx; + int offset_field_idx; + + // Integer.sizeTable - used for int to String conversion + ciField* size_table_field; + + // A set for use by various stages + VectorSet _visited; + + // Collect a list of all SB.toString calls + Node_List collect_toString_calls(); + + // Examine the use of the SB alloc to see if it can be replace with + // a single string construction. + StringConcat* build_candidate(CallStaticJavaNode* call); + + // Replace all the SB calls in concat with an optimization String allocation + void replace_string_concat(StringConcat* concat); + + // Load the value of a static field, performing any constant folding. + Node* fetch_static_field(GraphKit& kit, ciField* field); + + // Compute the number of characters required to represent the int value + Node* int_stringSize(GraphKit& kit, Node* value); + + // Copy the characters representing value into char_array starting at start + void int_getChars(GraphKit& kit, Node* value, Node* char_array, Node* start, Node* end); + + // Copy of the contents of the String str into char_array starting at index start. + Node* copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start); + + // Clean up any leftover nodes + void record_dead_node(Node* node); + void remove_dead_nodes(); + + PhaseGVN* gvn() { return _gvn; } + + enum { + // max length of constant string copy unrolling in copy_string + unroll_string_copy_length = 6 + }; + + public: + PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist); +}; diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index 81e033f2769..1a8c2f60e66 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1244,8 +1244,7 @@ const Type *CosDNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dcos( d ) ); + return TypeD::make( StubRoutines::intrinsic_cos( d ) ); } //============================================================================= @@ -1256,8 +1255,7 @@ const Type *SinDNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dsin( d ) ); + return TypeD::make( StubRoutines::intrinsic_sin( d ) ); } //============================================================================= @@ -1268,8 +1266,7 @@ const Type *TanDNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dtan( d ) ); + return TypeD::make( StubRoutines::intrinsic_tan( d ) ); } //============================================================================= @@ -1280,8 +1277,7 @@ const Type *LogDNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dlog( d ) ); + return TypeD::make( StubRoutines::intrinsic_log( d ) ); } //============================================================================= @@ -1292,8 +1288,7 @@ const Type *Log10DNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dlog10( d ) ); + return TypeD::make( StubRoutines::intrinsic_log10( d ) ); } //============================================================================= @@ -1304,8 +1299,7 @@ const Type *ExpDNode::Value( PhaseTransform *phase ) const { if( t1 == Type::TOP ) return Type::TOP; if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; double d = t1->getd(); - if( d < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dexp( d ) ); + return TypeD::make( StubRoutines::intrinsic_exp( d ) ); } @@ -1323,5 +1317,5 @@ const Type *PowDNode::Value( PhaseTransform *phase ) const { double d2 = t2->getd(); if( d1 < 0.0 ) return Type::DOUBLE; if( d2 < 0.0 ) return Type::DOUBLE; - return TypeD::make( SharedRuntime::dpow( d1, d2 ) ); + return TypeD::make( StubRoutines::intrinsic_pow( d1, d2 ) ); } diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index bc62f30c3d3..83d359d31f1 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -1921,6 +1921,11 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp) : } // Match AddP(base, AddP(ptr, k*iv [+ invariant]), constant) Node* base = adr->in(AddPNode::Base); + //unsafe reference could not be aligned appropriately without runtime checking + if (base == NULL || base->bottom_type() == Type::TOP) { + assert(!valid(), "unsafe access"); + return; + } for (int i = 0; i < 3; i++) { if (!scaled_iv_plus_offset(adr->in(AddPNode::Offset))) { assert(!valid(), "too complex"); diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index c22d1e8f6b0..289835af4c8 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -2431,7 +2431,7 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ //------------------------------make_from_constant----------------------------- // Make a java pointer from an oop constant const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) { - if (o->is_method_data() || o->is_method()) { + if (o->is_method_data() || o->is_method() || o->is_cpcache()) { // Treat much like a typeArray of bytes, like below, but fake the type... const Type* etype = (Type*)get_const_basic_type(T_BYTE); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); @@ -3966,7 +3966,7 @@ const TypeFunc *TypeFunc::make(ciMethod* method) { const TypeFunc* tf = C->last_tf(method); // check cache if (tf != NULL) return tf; // The hit rate here is almost 50%. const TypeTuple *domain; - if (method->flags().is_static()) { + if (method->is_static()) { domain = TypeTuple::make_domain(NULL, method->signature()); } else { domain = TypeTuple::make_domain(method->holder(), method->signature()); diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index 9b11f9ca595..03f81532c41 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -847,9 +847,6 @@ public: // Constant pointer to array static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot); - // Convenience - static const TypeAryPtr *make(ciObject* o); - // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 20484da07a9..fbf66099a79 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -396,11 +396,11 @@ JNI_ENTRY(jmethodID, jni_FromReflectedMethod(JNIEnv *env, jobject method)) oop mirror = NULL; int slot = 0; - if (reflected->klass() == SystemDictionary::reflect_constructor_klass()) { + if (reflected->klass() == SystemDictionary::reflect_Constructor_klass()) { mirror = java_lang_reflect_Constructor::clazz(reflected); slot = java_lang_reflect_Constructor::slot(reflected); } else { - assert(reflected->klass() == SystemDictionary::reflect_method_klass(), "wrong type"); + assert(reflected->klass() == SystemDictionary::reflect_Method_klass(), "wrong type"); mirror = java_lang_reflect_Method::clazz(reflected); slot = java_lang_reflect_Method::slot(reflected); } @@ -496,7 +496,7 @@ JNI_ENTRY(jclass, jni_GetSuperclass(JNIEnv *env, jclass sub)) klassOop super = Klass::cast(k)->java_super(); // super2 is the value computed by the compiler's getSuperClass intrinsic: debug_only(klassOop super2 = ( Klass::cast(k)->oop_is_javaArray() - ? SystemDictionary::object_klass() + ? SystemDictionary::Object_klass() : Klass::cast(k)->super() ) ); assert(super == super2, "java_super computation depends on interface, array, other super"); @@ -584,7 +584,7 @@ JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env)) if (thread->has_pending_exception()) { Handle ex(thread, thread->pending_exception()); thread->clear_pending_exception(); - if (ex->is_a(SystemDictionary::threaddeath_klass())) { + if (ex->is_a(SystemDictionary::ThreadDeath_klass())) { // Don't print anything if we are being killed. } else { jio_fprintf(defaultStream::error_stream(), "Exception "); @@ -593,12 +593,12 @@ JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env)) jio_fprintf(defaultStream::error_stream(), "in thread \"%s\" ", thread->get_thread_name()); } - if (ex->is_a(SystemDictionary::throwable_klass())) { + if (ex->is_a(SystemDictionary::Throwable_klass())) { JavaValue result(T_VOID); JavaCalls::call_virtual(&result, ex, KlassHandle(THREAD, - SystemDictionary::throwable_klass()), + SystemDictionary::Throwable_klass()), vmSymbolHandles::printStackTrace_name(), vmSymbolHandles::void_method_signature(), THREAD); @@ -3231,6 +3231,21 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v jint result = JNI_ERR; DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result); + // We're about to use Atomic::xchg for synchronization. Some Zero + // platforms use the GCC builtin __sync_lock_test_and_set for this, + // but __sync_lock_test_and_set is not guaranteed to do what we want + // on all architectures. So we check it works before relying on it. +#if defined(ZERO) && defined(ASSERT) + { + jint a = 0xcafebabe; + jint b = Atomic::xchg(0xdeadbeef, &a); + void *c = &a; + void *d = Atomic::xchg_ptr(&b, &c); + assert(a == (jint) 0xdeadbeef && b == (jint) 0xcafebabe, "Atomic::xchg() works"); + assert(c == &b && d == &a, "Atomic::xchg_ptr() works"); + } +#endif // ZERO && ASSERT + // At the moment it's only possible to have one Java VM, // since some of the runtime state is in global variables. diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index 0e3baac47ed..43c17cc392b 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -341,7 +341,7 @@ klassOop jniCheck::validate_class(JavaThread* thr, jclass clazz, bool allow_prim ReportJNIFatalError(thr, fatal_received_null_class); } - if (mirror->klass() != SystemDictionary::class_klass()) { + if (mirror->klass() != SystemDictionary::Class_klass()) { ReportJNIFatalError(thr, fatal_class_not_a_class); } @@ -358,7 +358,7 @@ void jniCheck::validate_throwable_klass(JavaThread* thr, klassOop klass) { assert(klass != NULL, "klass argument must have a value"); if (!Klass::cast(klass)->oop_is_instance() || - !instanceKlass::cast(klass)->is_subclass_of(SystemDictionary::throwable_klass())) { + !instanceKlass::cast(klass)->is_subclass_of(SystemDictionary::Throwable_klass())) { ReportJNIFatalError(thr, fatal_class_not_a_throwable_class); } } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 36c6507ee72..7ddb08d9967 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -80,7 +80,7 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { while (!vfst.at_end()) { methodOop m = vfst.method(); - if (!vfst.method()->method_holder()->klass_part()->is_subclass_of(SystemDictionary::classloader_klass())&& + if (!vfst.method()->method_holder()->klass_part()->is_subclass_of(SystemDictionary::ClassLoader_klass())&& !vfst.method()->method_holder()->klass_part()->is_subclass_of(access_controller_klass) && !vfst.method()->method_holder()->klass_part()->is_subclass_of(privileged_action_klass)) { break; @@ -257,7 +257,7 @@ static void set_property(Handle props, const char* key, const char* value, TRAPS Handle value_str = java_lang_String::create_from_platform_dependent_str((value != NULL ? value : ""), CHECK); JavaCalls::call_virtual(&r, props, - KlassHandle(THREAD, SystemDictionary::properties_klass()), + KlassHandle(THREAD, SystemDictionary::Properties_klass()), vmSymbolHandles::put_name(), vmSymbolHandles::object_object_object_signature(), key_str, @@ -495,7 +495,7 @@ JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) guarantee(klass->is_cloneable(), "all arrays are cloneable"); } else { guarantee(obj->is_instance(), "should be instanceOop"); - bool cloneable = klass->is_subtype_of(SystemDictionary::cloneable_klass()); + bool cloneable = klass->is_subtype_of(SystemDictionary::Cloneable_klass()); guarantee(cloneable == klass->is_cloneable(), "incorrect cloneable flag"); } #endif @@ -908,7 +908,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) // Special handling for primitive objects if (java_lang_Class::is_primitive(mirror)) { // Primitive objects does not have any interfaces - objArrayOop r = oopFactory::new_objArray(SystemDictionary::class_klass(), 0, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_NULL); return (jobjectArray) JNIHandles::make_local(env, r); } @@ -923,7 +923,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) } // Allocate result array - objArrayOop r = oopFactory::new_objArray(SystemDictionary::class_klass(), size, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(), size, CHECK_NULL); objArrayHandle result (THREAD, r); // Fill in result if (klass->oop_is_instance()) { @@ -934,8 +934,8 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) } } else { // All arrays implement java.lang.Cloneable and java.io.Serializable - result->obj_at_put(0, Klass::cast(SystemDictionary::cloneable_klass())->java_mirror()); - result->obj_at_put(1, Klass::cast(SystemDictionary::serializable_klass())->java_mirror()); + result->obj_at_put(0, Klass::cast(SystemDictionary::Cloneable_klass())->java_mirror()); + result->obj_at_put(1, Klass::cast(SystemDictionary::Serializable_klass())->java_mirror()); } return (jobjectArray) JNIHandles::make_local(env, result()); JVM_END @@ -1098,8 +1098,8 @@ JVM_ENTRY(jobject, JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, job pending_exception = Handle(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - if ( pending_exception->is_a(SystemDictionary::exception_klass()) && - !pending_exception->is_a(SystemDictionary::runtime_exception_klass())) { + if ( pending_exception->is_a(SystemDictionary::Exception_klass()) && + !pending_exception->is_a(SystemDictionary::RuntimeException_klass())) { // Throw a java.security.PrivilegedActionException(Exception e) exception JavaCallArguments args(pending_exception); THROW_ARG_0(vmSymbolHandles::java_security_PrivilegedActionException(), @@ -1190,7 +1190,7 @@ JVM_ENTRY(jobject, JVM_GetStackAccessControlContext(JNIEnv *env, jclass cls)) // the resource area must be registered in case of a gc RegisterArrayForGC ragc(thread, local_array); - objArrayOop context = oopFactory::new_objArray(SystemDictionary::protectionDomain_klass(), + objArrayOop context = oopFactory::new_objArray(SystemDictionary::ProtectionDomain_klass(), local_array->length(), CHECK_NULL); objArrayHandle h_context(thread, context); for (int index = 0; index < local_array->length(); index++) { @@ -1251,7 +1251,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) 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()) { - oop result = oopFactory::new_objArray(SystemDictionary::class_klass(), 0, CHECK_NULL); + oop result = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_NULL); return (jobjectArray)JNIHandles::make_local(env, result); } @@ -1259,7 +1259,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) if (k->inner_classes()->length() == 0) { // Neither an inner nor outer class - oop result = oopFactory::new_objArray(SystemDictionary::class_klass(), 0, CHECK_NULL); + oop result = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_NULL); return (jobjectArray)JNIHandles::make_local(env, result); } @@ -1269,7 +1269,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) int length = icls->length(); // Allocate temp. result array - objArrayOop r = oopFactory::new_objArray(SystemDictionary::class_klass(), length/4, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(), length/4, CHECK_NULL); objArrayHandle result (THREAD, r); int members = 0; @@ -1299,7 +1299,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) if (members != length) { // Return array of right length - objArrayOop res = oopFactory::new_objArray(SystemDictionary::class_klass(), members, CHECK_NULL); + objArrayOop res = oopFactory::new_objArray(SystemDictionary::Class_klass(), members, CHECK_NULL); for(int i = 0; i < members; i++) { res->obj_at_put(i, result->obj_at(i)); } @@ -1318,19 +1318,20 @@ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass)) return NULL; } - symbolOop simple_name = NULL; + bool inner_is_member = false; klassOop outer_klass = instanceKlass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)) - )->compute_enclosing_class(simple_name, CHECK_NULL); + )->compute_enclosing_class(&inner_is_member, 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) + if (!inner_is_member) 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) { + bool* inner_is_member, + 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; @@ -1347,8 +1348,7 @@ klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, bool found = false; klassOop ok; instanceKlassHandle outer_klass; - bool inner_is_member = false; - int simple_name_index = 0; + *inner_is_member = false; // Find inner_klass attribute for (int i = 0; i < i_length && !found; i += inner_class_next_offset) { @@ -1364,8 +1364,7 @@ klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, 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; + *inner_is_member = true; } } } @@ -1377,7 +1376,7 @@ klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, 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; + *inner_is_member = false; } } @@ -1387,9 +1386,7 @@ klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, // Throws an exception if outer klass has not declared k as an inner klass // 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)); + Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL); return outer_klass(); } @@ -1473,11 +1470,11 @@ static methodOop jvm_get_method_common(jobject method, TRAPS) { oop mirror = NULL; int slot = 0; - if (reflected->klass() == SystemDictionary::reflect_constructor_klass()) { + if (reflected->klass() == SystemDictionary::reflect_Constructor_klass()) { mirror = java_lang_reflect_Constructor::clazz(reflected); slot = java_lang_reflect_Constructor::slot(reflected); } else { - assert(reflected->klass() == SystemDictionary::reflect_method_klass(), + assert(reflected->klass() == SystemDictionary::reflect_Method_klass(), "wrong type"); mirror = java_lang_reflect_Method::clazz(reflected); slot = java_lang_reflect_Method::slot(reflected); @@ -1533,7 +1530,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, 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_javaArray()) { // Return empty array - oop res = oopFactory::new_objArray(SystemDictionary::reflect_field_klass(), 0, CHECK_NULL); + oop res = oopFactory::new_objArray(SystemDictionary::reflect_Field_klass(), 0, CHECK_NULL); return (jobjectArray) JNIHandles::make_local(env, res); } @@ -1561,13 +1558,13 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, } else { num_fields = fields_len / instanceKlass::next_offset; - if (k() == SystemDictionary::throwable_klass()) { + if (k() == SystemDictionary::Throwable_klass()) { num_fields--; skip_backtrace = true; } } - objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_field_klass(), num_fields, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Field_klass(), num_fields, CHECK_NULL); objArrayHandle result (THREAD, r); int out_idx = 0; @@ -1601,7 +1598,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, 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_javaArray()) { // Return empty array - oop res = oopFactory::new_objArray(SystemDictionary::reflect_method_klass(), 0, CHECK_NULL); + oop res = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), 0, CHECK_NULL); return (jobjectArray) JNIHandles::make_local(env, res); } @@ -1625,7 +1622,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, } // Allocate result - objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_method_klass(), num_methods, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), num_methods, CHECK_NULL); objArrayHandle result (THREAD, r); int out_idx = 0; @@ -1653,7 +1650,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofC 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_javaArray()) { // Return empty array - oop res = oopFactory::new_objArray(SystemDictionary::reflect_constructor_klass(), 0 , CHECK_NULL); + oop res = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0 , CHECK_NULL); return (jobjectArray) JNIHandles::make_local(env, res); } @@ -1677,7 +1674,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofC } // Allocate result - objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_constructor_klass(), num_constructors, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), num_constructors, CHECK_NULL); objArrayHandle result(THREAD, r); int out_idx = 0; @@ -1890,7 +1887,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject symbolHandle klass_name (THREAD, cp->klass_name_at(klass_ref)); symbolHandle member_name(THREAD, cp->uncached_name_ref_at(index)); symbolHandle member_sig (THREAD, cp->uncached_signature_ref_at(index)); - objArrayOop dest_o = oopFactory::new_objArray(SystemDictionary::string_klass(), 3, CHECK_NULL); + objArrayOop dest_o = oopFactory::new_objArray(SystemDictionary::String_klass(), 3, CHECK_NULL); objArrayHandle dest(THREAD, dest_o); Handle str = java_lang_String::create_from_symbol(klass_name, CHECK_NULL); dest->obj_at_put(0, str()); @@ -2257,10 +2254,8 @@ JVM_ENTRY(const char*, JVM_GetCPMethodNameUTF(JNIEnv *env, jclass cls, jint cp_i switch (cp->tag_at(cp_index).value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_NameAndType: // for invokedynamic return cp->uncached_name_ref_at(cp_index)->as_utf8(); - case JVM_CONSTANT_NameAndType: - // for invokedynamic - return cp->nt_name_ref_at(cp_index)->as_utf8(); default: fatal("JVM_GetCPMethodNameUTF: illegal constant"); } @@ -2277,10 +2272,8 @@ JVM_ENTRY(const char*, JVM_GetCPMethodSignatureUTF(JNIEnv *env, jclass cls, jint switch (cp->tag_at(cp_index).value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_NameAndType: // for invokedynamic return cp->uncached_signature_ref_at(cp_index)->as_utf8(); - case JVM_CONSTANT_NameAndType: - // for invokedynamic - return cp->nt_signature_ref_at(cp_index)->as_utf8(); default: fatal("JVM_GetCPMethodSignatureUTF: illegal constant"); } @@ -2582,7 +2575,7 @@ static void thread_entry(JavaThread* thread, TRAPS) { JavaValue result(T_VOID); JavaCalls::call_virtual(&result, obj, - KlassHandle(THREAD, SystemDictionary::thread_klass()), + KlassHandle(THREAD, SystemDictionary::Thread_klass()), vmSymbolHandles::run_method_name(), vmSymbolHandles::void_method_signature(), THREAD); @@ -2680,7 +2673,7 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable)) // Fix for 4314342, 4145910, perhaps others: it now doesn't have // any effect on the "liveness" of a thread; see // JVM_IsThreadAlive, below. - if (java_throwable->is_a(SystemDictionary::threaddeath_klass())) { + if (java_throwable->is_a(SystemDictionary::ThreadDeath_klass())) { java_lang_Thread::set_stillborn(java_thread); } THROW_OOP(java_throwable); @@ -3035,7 +3028,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassContext(JNIEnv *env)) } // Create result array of type [Ljava/lang/Class; - objArrayOop result = oopFactory::new_objArray(SystemDictionary::class_klass(), depth, CHECK_NULL); + objArrayOop result = oopFactory::new_objArray(SystemDictionary::Class_klass(), depth, CHECK_NULL); // Fill in mirrors corresponding to method holders int index = 0; while (first != NULL) { @@ -4331,7 +4324,7 @@ JVM_ENTRY(jobjectArray, JVM_GetAllThreads(JNIEnv *env, jclass dummy)) JvmtiVMObjectAllocEventCollector oam; int num_threads = tle.num_threads(); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::thread_klass(), num_threads, CHECK_NULL); + objArrayOop r = oopFactory::new_objArray(SystemDictionary::Thread_klass(), num_threads, CHECK_NULL); objArrayHandle threads_ah(THREAD, r); for (int i = 0; i < num_threads; i++) { @@ -4365,7 +4358,7 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject // check if threads is not an array of objects of Thread class klassOop k = objArrayKlass::cast(ah->klass())->element_klass(); - if (k != SystemDictionary::thread_klass()) { + if (k != SystemDictionary::Thread_klass()) { THROW_(vmSymbols::java_lang_IllegalArgumentException(), 0); } @@ -4425,7 +4418,7 @@ JVM_ENTRY(jobjectArray, JVM_GetEnclosingMethodInfo(JNIEnv *env, jclass ofClass)) if (encl_method_class_idx == 0) { return NULL; } - objArrayOop dest_o = oopFactory::new_objArray(SystemDictionary::object_klass(), 3, CHECK_NULL); + objArrayOop dest_o = oopFactory::new_objArray(SystemDictionary::Object_klass(), 3, CHECK_NULL); objArrayHandle dest(THREAD, dest_o); klassOop enc_k = ik_h->constants()->klass_at(encl_method_class_idx, CHECK_NULL); dest->obj_at_put(0, Klass::cast(enc_k)->java_mirror()); @@ -4539,7 +4532,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, values_h->int_at(0) == java_lang_Thread::NEW, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 1, /* only 1 substate */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4552,7 +4545,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, values_h->int_at(0) == java_lang_Thread::RUNNABLE, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 1, /* only 1 substate */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4565,7 +4558,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, values_h->int_at(0) == java_lang_Thread::BLOCKED_ON_MONITOR_ENTER, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 1, /* only 1 substate */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4578,7 +4571,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, values_h->int_at(0) == java_lang_Thread::IN_OBJECT_WAIT && values_h->int_at(1) == java_lang_Thread::PARKED, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 2, /* number of substates */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4596,7 +4589,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, values_h->int_at(1) == java_lang_Thread::IN_OBJECT_WAIT_TIMED && values_h->int_at(2) == java_lang_Thread::PARKED_TIMED, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 3, /* number of substates */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4615,7 +4608,7 @@ JVM_ENTRY(jobjectArray, JVM_GetThreadStateNames(JNIEnv* env, assert(values_h->length() == 1 && values_h->int_at(0) == java_lang_Thread::TERMINATED, "Invalid threadStatus value"); - objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(), + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), 1, /* only 1 substate */ CHECK_NULL); names_h = objArrayHandle(THREAD, r); @@ -4650,4 +4643,3 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i #endif // KERNEL } JVM_END - diff --git a/hotspot/src/share/vm/prims/jvmtiEnter.xsl b/hotspot/src/share/vm/prims/jvmtiEnter.xsl index 6380ca3ee0a..28044aafd75 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl +++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl @@ -773,7 +773,7 @@ static jvmtiError JNICALL } - if (!thread_oop->is_a(SystemDictionary::thread_klass())) { + if (!thread_oop->is_a(SystemDictionary::Thread_klass())) { JVMTI_ERROR_INVALID_THREAD @@ -857,7 +857,7 @@ static jvmtiError JNICALL } - if (!k_mirror->is_a(SystemDictionary::class_klass())) { + if (!k_mirror->is_a(SystemDictionary::Class_klass())) { JVMTI_ERROR_INVALID_CLASS diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index 95977f0092e..4ad9996baae 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.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 @@ -32,15 +32,15 @@ // FIXLATER: hook into JvmtiTrace #define TraceJVMTICalls false -JvmtiEnv::JvmtiEnv() : JvmtiEnvBase() { +JvmtiEnv::JvmtiEnv(jint version) : JvmtiEnvBase(version) { } JvmtiEnv::~JvmtiEnv() { } JvmtiEnv* -JvmtiEnv::create_a_jvmti() { - return new JvmtiEnv(); +JvmtiEnv::create_a_jvmti(jint version) { + return new JvmtiEnv(version); } // VM operation class to copy jni function table at safepoint. @@ -133,7 +133,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { if (thread_oop == NULL) { return JVMTI_ERROR_INVALID_THREAD; } - if (!thread_oop->is_a(SystemDictionary::thread_klass())) { + if (!thread_oop->is_a(SystemDictionary::Thread_klass())) { return JVMTI_ERROR_INVALID_THREAD; } JavaThread* java_thread = java_lang_Thread::thread(thread_oop); @@ -199,7 +199,7 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { if (k_mirror == NULL) { return JVMTI_ERROR_INVALID_CLASS; } - if (!k_mirror->is_a(SystemDictionary::class_klass())) { + if (!k_mirror->is_a(SystemDictionary::Class_klass())) { return JVMTI_ERROR_INVALID_CLASS; } @@ -266,7 +266,7 @@ JvmtiEnv::GetObjectSize(jobject object, jlong* size_ptr) { oop mirror = JNIHandles::resolve_external_guard(object); NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT); - if (mirror->klass() == SystemDictionary::class_klass()) { + if (mirror->klass() == SystemDictionary::Class_klass()) { if (!java_lang_Class::is_primitive(mirror)) { mirror = java_lang_Class::as_klassOop(mirror); assert(mirror != NULL, "class for non-primitive mirror must exist"); @@ -327,7 +327,7 @@ JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, j if (thread_oop == NULL) { return JVMTI_ERROR_INVALID_THREAD; } - if (!thread_oop->is_a(SystemDictionary::thread_klass())) { + if (!thread_oop->is_a(SystemDictionary::Thread_klass())) { return JVMTI_ERROR_INVALID_THREAD; } java_thread = java_lang_Thread::thread(thread_oop); @@ -411,8 +411,15 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) { if (phase == JVMTI_PHASE_ONLOAD) { Arguments::append_sysclasspath(segment); return JVMTI_ERROR_NONE; - } else { - assert(phase == JVMTI_PHASE_LIVE, "sanity check"); + } else if (use_version_1_0_semantics()) { + // This JvmtiEnv requested version 1.0 semantics and this function + // is only allowed in the ONLOAD phase in version 1.0 so we need to + // return an error here. + return JVMTI_ERROR_WRONG_PHASE; + } else if (phase == JVMTI_PHASE_LIVE) { + // The phase is checked by the wrapper that called this function, + // but this thread could be racing with the thread that is + // terminating the VM so we check one more time. // create the zip entry ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); @@ -433,6 +440,8 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) { } ClassLoader::add_to_list(zip_entry); return JVMTI_ERROR_NONE; + } else { + return JVMTI_ERROR_WRONG_PHASE; } } /* end AddToBootstrapClassLoaderSearch */ @@ -451,11 +460,12 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) { } } return JVMTI_ERROR_NONE; - } else { + } else if (phase == JVMTI_PHASE_LIVE) { + // The phase is checked by the wrapper that called this function, + // but this thread could be racing with the thread that is + // terminating the VM so we check one more time. HandleMark hm; - assert(phase == JVMTI_PHASE_LIVE, "sanity check"); - // create the zip entry (which will open the zip file and hence // check that the segment is indeed a zip file). ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); @@ -504,6 +514,8 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) { } return JVMTI_ERROR_NONE; + } else { + return JVMTI_ERROR_WRONG_PHASE; } } /* end AddToSystemClassLoaderSearch */ @@ -580,7 +592,6 @@ JvmtiEnv::SetVerboseFlag(jvmtiVerboseFlag flag, jboolean value) { break; case JVMTI_VERBOSE_GC: PrintGC = value != 0; - TraceClassUnloading = value != 0; break; case JVMTI_VERBOSE_JNI: PrintJNIResolving = value != 0; @@ -620,7 +631,7 @@ JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) { thread_oop = JNIHandles::resolve_external_guard(thread); } - if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::thread_klass())) { + if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) { return JVMTI_ERROR_INVALID_THREAD; } @@ -858,7 +869,7 @@ JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) { jvmtiError JvmtiEnv::InterruptThread(jthread thread) { oop thread_oop = JNIHandles::resolve_external_guard(thread); - if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::thread_klass())) + if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) return JVMTI_ERROR_INVALID_THREAD; JavaThread* current_thread = JavaThread::current(); @@ -895,7 +906,7 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) { } else { thread_oop = JNIHandles::resolve_external_guard(thread); } - if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::thread_klass())) + if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) return JVMTI_ERROR_INVALID_THREAD; Handle thread_obj(current_thread, thread_oop); @@ -1061,7 +1072,7 @@ JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_p jvmtiError JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) { oop thread_oop = JNIHandles::resolve_external_guard(thread); - if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::thread_klass())) { + if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) { return JVMTI_ERROR_INVALID_THREAD; } if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) { @@ -2863,6 +2874,14 @@ JvmtiEnv::IsMethodSynthetic(methodOop method_oop, jboolean* is_synthetic_ptr) { // is_obsolete_ptr - pre-checked for NULL jvmtiError JvmtiEnv::IsMethodObsolete(methodOop method_oop, jboolean* is_obsolete_ptr) { + if (use_version_1_0_semantics() && + get_capabilities()->can_redefine_classes == 0) { + // This JvmtiEnv requested version 1.0 semantics and this function + // requires the can_redefine_classes capability in version 1.0 so + // we need to return an error here. + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; + } + if (method_oop == NULL || method_oop->is_obsolete()) { *is_obsolete_ptr = true; } else { diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index c6526995912..24311492bee 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp @@ -123,7 +123,26 @@ JvmtiEnvBase::is_valid() { } -JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() { +bool +JvmtiEnvBase::use_version_1_0_semantics() { + int major, minor, micro; + + JvmtiExport::decode_version_values(_version, &major, &minor, µ); + return major == 1 && minor == 0; // micro version doesn't matter here +} + + +bool +JvmtiEnvBase::use_version_1_1_semantics() { + int major, minor, micro; + + JvmtiExport::decode_version_values(_version, &major, &minor, µ); + return major == 1 && minor == 1; // micro version doesn't matter here +} + + +JvmtiEnvBase::JvmtiEnvBase(jint version) : _env_event_enable() { + _version = version; _env_local_storage = NULL; _tag_map = NULL; _native_method_prefix_count = 0; @@ -508,7 +527,7 @@ JvmtiEnvBase::new_jthreadGroupArray(int length, Handle *handles) { JavaThread * JvmtiEnvBase::get_JavaThread(jthread jni_thread) { oop t = JNIHandles::resolve_external_guard(jni_thread); - if (t == NULL || !t->is_a(SystemDictionary::thread_klass())) { + if (t == NULL || !t->is_a(SystemDictionary::Thread_klass())) { return NULL; } // The following returns NULL if the thread has not yet run or is in @@ -1250,7 +1269,7 @@ VM_GetThreadListStackTraces::doit() { for (int i = 0; i < _thread_count; ++i) { jthread jt = _thread_list[i]; oop thread_oop = JNIHandles::resolve_external_guard(jt); - if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::thread_klass())) { + if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) { set_result(JVMTI_ERROR_INVALID_THREAD); return; } diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp index e6dd31e5870..8ad31f9ebf8 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.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 @@ -76,6 +76,7 @@ class JvmtiEnvBase : public CHeapObj { jvmtiEnv _jvmti_external; jint _magic; + jint _version; // version value passed to JNI GetEnv() JvmtiEnvBase* _next; bool _is_retransformable; const void *_env_local_storage; // per env agent allocated data. @@ -91,7 +92,7 @@ class JvmtiEnvBase : public CHeapObj { int _native_method_prefix_count; protected: - JvmtiEnvBase(); + JvmtiEnvBase(jint version); ~JvmtiEnvBase(); void dispose(); void env_dispose(); @@ -122,6 +123,9 @@ class JvmtiEnvBase : public CHeapObj { bool is_valid(); + bool use_version_1_0_semantics(); // agent asked for version 1.0 + bool use_version_1_1_semantics(); // agent asked for version 1.1 + bool is_retransformable() { return _is_retransformable; } static ByteSize jvmti_external_offset() { diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 7a5068b43b3..12af0d9f4f2 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -319,7 +319,27 @@ address JvmtiExport::get_field_modification_count_addr() { jint JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { - /* To Do: add version checks */ + // The JVMTI_VERSION_INTERFACE_JVMTI part of the version number + // has already been validated in JNI GetEnv(). + int major, minor, micro; + + // micro version doesn't matter here (yet?) + decode_version_values(version, &major, &minor, µ); + switch (major) { + case 1: + switch (minor) { + case 0: // version 1.0. is recognized + case 1: // version 1.1. is recognized + break; + + default: + return JNI_EVERSION; // unsupported minor version number + } + break; + + default: + return JNI_EVERSION; // unsupported major version number + } if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) { JavaThread* current_thread = (JavaThread*) ThreadLocalStorage::thread(); @@ -328,13 +348,13 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { __ENTRY(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread) debug_only(VMNativeEntryWrapper __vew;) - JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(); + JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version); *penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv* return JNI_OK; } else if (JvmtiEnv::get_phase() == JVMTI_PHASE_ONLOAD) { // not live, no thread to transition - JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(); + JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version); *penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv* return JNI_OK; @@ -345,6 +365,15 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { } } + +void +JvmtiExport::decode_version_values(jint version, int * major, int * minor, + int * micro) { + *major = (version & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR; + *minor = (version & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR; + *micro = (version & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO; +} + void JvmtiExport::enter_primordial_phase() { JvmtiEnvBase::set_phase(JVMTI_PHASE_PRIMORDIAL); } @@ -627,7 +656,7 @@ static inline klassOop oop_to_klassOop(oop obj) { klassOop k = obj->klass(); // if the object is a java.lang.Class then return the java mirror - if (k == SystemDictionary::class_klass()) { + if (k == SystemDictionary::Class_klass()) { if (!java_lang_Class::is_primitive(obj)) { k = java_lang_Class::as_klassOop(obj); assert(k != NULL, "class for non-primitive mirror must exist"); @@ -1896,7 +1925,7 @@ void JvmtiExport::record_vm_internal_object_allocation(oop obj) { if (collector != NULL && collector->is_enabled()) { // Don't record classes as these will be notified via the ClassLoad // event. - if (obj->klass() != SystemDictionary::class_klass()) { + if (obj->klass() != SystemDictionary::Class_klass()) { collector->record_allocation(obj); } } diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp index 54a9416f425..20214aecf9c 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.hpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.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 @@ -236,6 +236,8 @@ class JvmtiExport : public AllStatic { static bool is_jvmti_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMTI_VERSION_VALUE; } static bool is_jvmdi_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMDI_VERSION_VALUE; } static jint get_jvmti_interface(JavaVM *jvm, void **penv, jint version); + static void decode_version_values(jint version, int * major, int * minor, + int * micro); // single stepping management methods static void at_single_stepping_point(JavaThread *thread, methodOop method, address location) KERNEL_RETURN; diff --git a/hotspot/src/share/vm/prims/jvmtiHpp.xsl b/hotspot/src/share/vm/prims/jvmtiHpp.xsl index 3b3b23e90f6..e5dd49ffc6c 100644 --- a/hotspot/src/share/vm/prims/jvmtiHpp.xsl +++ b/hotspot/src/share/vm/prims/jvmtiHpp.xsl @@ -1,6 +1,6 @@ + + + diff --git a/jdk/make/modules/tools/nbproject/project.properties b/jdk/make/modules/tools/nbproject/project.properties new file mode 100644 index 00000000000..84df879f82b --- /dev/null +++ b/jdk/make/modules/tools/nbproject/project.properties @@ -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. +# + +application.title=classanalyzer +application.vendor=mchung +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form + +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources + +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results + +cp.extra=${tools.jar} + +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} + +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/classanalyzer.jar +dist.javadoc.dir=${dist.dir}/javadoc + +excludes= + +file.reference.tools.jar=${jdk.home}/lib/tools.jar +file.reference.tools-src=src +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.tools.jar} +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath= +javadoc.author=false +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=false +javadoc.use=false +javadoc.version=false +main.class=com.sun.classanalyzer.ClassAnalyzer +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=JDK_1.6 +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs=-Xmx256m +run.test.classpath= +source.encoding=UTF-8 +src.dir=${file.reference.tools-src} diff --git a/jdk/make/modules/tools/nbproject/project.xml b/jdk/make/modules/tools/nbproject/project.xml new file mode 100644 index 00000000000..bd83ccaeb9b --- /dev/null +++ b/jdk/make/modules/tools/nbproject/project.xml @@ -0,0 +1,39 @@ + + + + + org.netbeans.modules.java.j2seproject + + + classanalyzer + + + + + + + + diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java new file mode 100644 index 00000000000..72b21d9949e --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java @@ -0,0 +1,627 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.Map; + +import com.sun.classanalyzer.Module.Reference; +import java.util.LinkedList; +import java.util.TreeMap; + +/** + * + * @author Mandy Chung + */ +public abstract class AnnotatedDependency implements Comparable { + + final Klass from; + final List classes; + protected boolean optional; + String description; + Klass.Method method; + private List filters = null; + + public AnnotatedDependency(Klass klass) { + this(klass, false); + } + + public AnnotatedDependency(Klass klass, boolean optional) { + this.from = klass; + this.classes = new ArrayList(); + this.optional = optional; + } + + abstract String getTag(); + + abstract boolean isDynamic(); + + void setMethod(Klass.Method m) { + this.method = m; + } + + void addElement(String element, List value) { + if (element.equals("value")) { + addValue(value); + } else if (element.equals("description")) { + description = value.get(0); + } else if (element.equals("optional")) { + optional = value.get(0).equals("1") || Boolean.parseBoolean(value.get(0)); + } + } + + void addValue(List value) { + for (String s : value) { + if ((s = s.trim()).length() > 0) { + classes.add(s); + } + } + } + + List getValue() { + return classes; + } + + boolean isOptional() { + return optional; + } + + boolean isEmpty() { + return classes.isEmpty(); + } + + boolean matches(String classname) { + synchronized (this) { + // initialize filters + if (filters == null) { + filters = new ArrayList(); + for (String pattern : classes) { + filters.add(new Filter(pattern)); + } + + } + } + + for (Filter f : filters) { + if (f.matches(classname)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String v : getValue()) { + if (sb.length() == 0) { + sb.append(getTag()); + sb.append("\n"); + } else { + sb.append("\n"); + } + sb.append(" "); + sb.append(from.getClassName()).append(" -> "); + sb.append(v); + } + return sb.toString(); + } + + @Override + public int compareTo(AnnotatedDependency o) { + if (from == o.from) { + if (this.getClass().getName().equals(o.getClass().getName())) { + String s1 = classes.isEmpty() ? "" : classes.get(0); + String s2 = o.classes.isEmpty() ? "" : o.classes.get(0); + return s1.compareTo(s2); + } else { + return this.getClass().getName().compareTo(o.getClass().getName()); + } + + } else { + return from.compareTo(o.from); + } + } + + @Override + public int hashCode() { + int hashcode = 7 + 73 * from.hashCode(); + for (String s : classes) { + hashcode ^= s.hashCode(); + } + return hashcode; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AnnotatedDependency)) { + return false; + } + AnnotatedDependency other = (AnnotatedDependency) obj; + boolean ret = this.from.equals(other.from) && this.classes.size() == other.classes.size(); + if (ret == true) { + for (int i = 0; i < this.classes.size(); i++) { + ret = ret && this.classes.get(i).equals(other.classes.get(i)); + } + } + return ret; + } + + static class ClassForName extends AnnotatedDependency { + + public ClassForName(Klass klass, boolean optional) { + super(klass, optional); + } + + @Override + String getTag() { + if (this.optional) { + return TAG + "(optional)"; + } else { + return TAG; + } + } + + @Override + boolean isDynamic() { + return true; + } + static final String TYPE = "sun.annotation.ClassForName"; + static final String TAG = "@ClassForName"; + } + + static class NativeFindClass extends AnnotatedDependency { + + public NativeFindClass(Klass klass, boolean optional) { + super(klass, optional); + } + + @Override + String getTag() { + if (this.optional) { + return TAG + "(optional)"; + } else { + return TAG; + } + } + + @Override + boolean isDynamic() { + return true; + } + static final String TYPE = "sun.annotation.NativeFindClass"; + static final String TAG = "@NativeFindClass"; + } + + static class Provider extends AnnotatedDependency { + + private List services = new ArrayList(); + + Provider(Klass klass) { + super(klass, true); + } + + @Override + boolean isDynamic() { + return true; + } + + public List services() { + return services; + } + + @Override + void addElement(String element, List value) { + if (element.equals("service")) { + List configFiles = new ArrayList(); + for (String s : value) { + if ((s = s.trim()).length() > 0) { + configFiles.add(metaInfPath + s); + } + } + addValue(configFiles); + } + } + + @Override + void addValue(List value) { + for (String s : value) { + if ((s = s.trim()).length() > 0) { + if (s.startsWith("META-INF")) { + services.add(s); + readServiceConfiguration(s, classes); + } else { + throw new RuntimeException("invalid value" + s); + } + } + } + } + + boolean isEmpty() { + return services.isEmpty(); + } + static final String metaInfPath = + "META-INF" + File.separator + "services" + File.separator; + + static void readServiceConfiguration(String config, List names) { + BufferedReader br = null; + try { + InputStream is = ClassPath.open(config); + if (is != null) { + // Properties doesn't perserve the order of the input file + br = new BufferedReader(new InputStreamReader(is, "utf-8")); + int lc = 1; + while ((lc = parseLine(br, lc, names)) >= 0); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + } + + // Parse a single line from the given configuration file, adding the name + // on the line to the names list. + // + private static int parseLine(BufferedReader r, int lc, List names) throws IOException { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) { + ln = ln.substring(0, ci); + } + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { + throw new RuntimeException("Illegal configuration-file syntax"); + } + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + } + if (!names.contains(ln)) { + names.add(ln); + } + } + return lc + 1; + } + + @Override + String getTag() { + return TAG; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AnnotatedDependency)) { + return false; + } + Provider other = (Provider) obj; + boolean ret = this.from.equals(other.from) && + this.services.size() == other.services.size(); + if (ret == true) { + for (int i = 0; i < this.services.size(); i++) { + ret = ret && this.services.get(i).equals(other.services.get(i)); + } + } + return ret; + } + + @Override + public int hashCode() { + int hashcode = 7 + 73 * from.hashCode(); + for (String s : services) { + hashcode ^= s.hashCode(); + } + return hashcode; + } + + @Override + public List getValue() { + List result = new ArrayList(); + result.addAll(services); + return result; + } + static final String TYPE = "sun.annotation.Provider"; + static final String TAG = "@Provider"; + } + + static class OptionalDependency extends AnnotatedDependency { + + static boolean isOptional(Klass from, Klass to) { + synchronized (OptionalDependency.class) { + if (optionalDepsMap == null) { + // Build a map of classes to its optional dependencies + initDependencies(); + } + } + for (Reference ref : optionalDepsMap.keySet()) { + if (ref.referrer() == from && ref.referree() == to) { + return true; + } + } + return false; + } + + OptionalDependency(Klass klass) { + super(klass, true); + } + + @Override + boolean isDynamic() { + return false; + } + + @Override + String getTag() { + return TAG; + } + static final String TYPE = "sun.annotation.Optional"; + static final String TAG = "@Optional"; + } + + static class CompilerInline extends AnnotatedDependency { + + public CompilerInline(Klass klass) { + super(klass); + } + + @Override + String getTag() { + return TAG; + } + + @Override + boolean isDynamic() { + return false; + } + static final String TYPE = "sun.annotation.Inline"; + static final String TAG = "@Inline"; + } + + static class Filter { + + final String pattern; + final String regex; + + Filter(String pattern) { + this.pattern = pattern; + + boolean isRegex = false; + for (int i = 0; i < pattern.length(); i++) { + char p = pattern.charAt(i); + if (p == '*' || p == '[' || p == ']') { + isRegex = true; + break; + } + } + + if (isRegex) { + this.regex = convertToRegex(pattern); + } else { + this.regex = null; + } + } + + private String convertToRegex(String pattern) { + StringBuilder sb = new StringBuilder(); + int i = 0; + int index = 0; + int plen = pattern.length(); + while (i < plen) { + char p = pattern.charAt(i); + if (p == '*') { + sb.append("(").append(pattern.substring(index, i)).append(")"); + if (i + 1 < plen && pattern.charAt(i + 1) == '*') { + sb.append(".*"); + index = i + 2; + } else { + sb.append("[^\\.]*"); + index = i + 1; + } + } else if (p == '[') { + int j = i + 1; + while (j < plen) { + if (pattern.charAt(j) == ']') { + break; + } + j++; + } + if (j >= plen || pattern.charAt(j) != ']') { + throw new RuntimeException("Malformed pattern " + pattern); + } + sb.append("(").append(pattern.substring(index, i)).append(")"); + sb.append(pattern.substring(i, j + 1)); + index = j + 1; + i = j; + } + i++; + } + if (index < plen) { + sb.append("(").append(pattern.substring(index, plen)).append(")"); + } + return sb.toString(); + } + + boolean matches(String name) { + if (regex == null) { + // the pattern is not a regex + return name.equals(pattern); + } else { + return name.matches(regex); + } + } + } + + static boolean isValidType(String type) { + if (type.endsWith("(optional)")) { + int len = type.length() - "(optional)".length(); + type = type.substring(0, len); + } + return type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG) || + type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG) || + type.equals(Provider.TYPE) || type.equals(Provider.TAG) || + type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG) || + type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG); + } + + static AnnotatedDependency newAnnotatedDependency(String tag, String value, Klass klass) { + AnnotatedDependency dep = newAnnotatedDependency(tag, klass); + if (dep != null) { + dep.addValue(Collections.singletonList(value)); + } + return dep; + } + static List annotatedDependencies = new LinkedList(); + static List optionalDependencies = new LinkedList(); + + static AnnotatedDependency newAnnotatedDependency(String type, Klass klass) { + boolean optional = false; + if (type.endsWith("(optional)")) { + optional = true; + int len = type.length() - "(optional)".length(); + type = type.substring(0, len); + } + + if (type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG)) { + return newOptionalDependency(klass); + } + + AnnotatedDependency dep; + if (type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG)) { + dep = new ClassForName(klass, optional); + } else if (type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG)) { + dep = new NativeFindClass(klass, optional); + } else if (type.equals(Provider.TYPE) || type.equals(Provider.TAG)) { + dep = new Provider(klass); + } else if (type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG)) { + dep = new CompilerInline(klass); + } else { + return null; + } + klass.addAnnotatedDep(dep); + annotatedDependencies.add(dep); + return dep; + } + + static OptionalDependency newOptionalDependency(Klass klass) { + OptionalDependency dep = new OptionalDependency(klass); + optionalDependencies.add(dep); + return dep; + } + static Map> annotatedDepsMap = null; + static Map> optionalDepsMap = null; + + static Map> getReferences(Module m) { + // ensure it's initialized + initDependencies(); + + Map> result = new TreeMap>(); + for (Reference ref : annotatedDepsMap.keySet()) { + if (m.contains(ref.referrer()) && m.isModuleDependence(ref.referree())) { + result.put(ref, annotatedDepsMap.get(ref)); + } + } + return result; + } + + static Set getDependencies(Module m) { + // ensure it's initialized + initDependencies(); + + Set deps = new TreeSet(); + for (Reference ref : annotatedDepsMap.keySet()) { + if (m.contains(ref.referrer())) { + Module other = m.getModuleDependence(ref.referree()); + if (other != null) { + for (AnnotatedDependency ad : annotatedDepsMap.get(ref)) { + Module.Dependency d = new Module.Dependency(other, ad.isOptional(), ad.isDynamic()); + deps.add(d); + } + } + } + } + return deps; + } + + synchronized static void initDependencies() { + if (annotatedDepsMap != null) { + return; + } + + // Build a map of references to its dependencies + annotatedDepsMap = new TreeMap>(); + optionalDepsMap = new TreeMap>(); + + for (Klass k : Klass.getAllClasses()) { + for (AnnotatedDependency ad : annotatedDependencies) { + if (ad.matches(k.getClassName())) { + Reference ref = new Reference(ad.from, k); + Set set = annotatedDepsMap.get(ref); + if (set == null) { + set = new TreeSet(); + annotatedDepsMap.put(ref, set); + } + set.add(ad); + } + } + + for (AnnotatedDependency ad : optionalDependencies) { + if (ad.matches(k.getClassName())) { + Reference ref = new Reference(ad.from, k); + Set set = optionalDepsMap.get(ref); + if (set == null) { + set = new TreeSet(); + optionalDepsMap.put(ref, set); + } + set.add(ad); + } + } + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java new file mode 100644 index 00000000000..7d984aa2e74 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java @@ -0,0 +1,293 @@ +/* + * 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.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Annotation; +import com.sun.tools.classfile.ExtendedAnnotation; +import com.sun.tools.classfile.Annotation.Annotation_element_value; +import com.sun.tools.classfile.Annotation.Array_element_value; +import com.sun.tools.classfile.Annotation.Class_element_value; +import com.sun.tools.classfile.Annotation.Enum_element_value; +import com.sun.tools.classfile.Annotation.Primitive_element_value; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Descriptor; +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; +import java.util.ArrayList; +import java.util.List; + +import com.sun.classanalyzer.AnnotatedDependency.*; +import java.io.File; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Set; + +/** + * + * @author Mandy Chung + */ +public class AnnotationParser { + + static boolean parseAnnotation = false; + static void setParseAnnotation(boolean newValue) { + parseAnnotation = newValue; + } + + private final ClassFileParser cfparser; + public AnnotationParser(ClassFileParser cfparser) { + this.cfparser = cfparser; + } + + private AnnotatedDependency addAnnotation(Annotation annot, Klass.Method method) { + String type = getType(annot.type_index); + AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, cfparser.this_klass); + if (dep != null) { + for (int i = 0; i < annot.num_element_value_pairs; i++) { + Element element = getElement(annot.element_value_pairs[i]); + dep.addElement(element.name, element.value); + } + dep.setMethod(method); + } + return dep; + } + + private AnnotatedDependency addAnnotation(ExtendedAnnotation annot, Klass.Method method) { + return addAnnotation(annot.annotation, method); + } + + class Element { + + String name; + List value; + + Element(String name) { + this.name = name; + this.value = new ArrayList(); + } + + void add(String v) { + value.add(v); + } + } + + Element getElement(Annotation.element_value_pair pair) { + Element element = new Element(getName(pair.element_name_index)); + evp.parse(pair.value, element); + return element; + } + + private String getType(int index) { + try { + Descriptor d = new Descriptor(index); + return d.getFieldType(cfparser.classfile.constant_pool); + } catch (ConstantPoolException ignore) { + } catch (InvalidDescriptor ignore) { + } + return "Unknown"; + } + + private String getName(int index) { + return cfparser.constantPoolParser.stringValue(index); + } + element_value_Parser evp = new element_value_Parser(); + + class element_value_Parser implements Annotation.element_value.Visitor { + + public Void parse(Annotation.element_value value, Element element) { + value.accept(this, element); + return null; + } + + public Void visitPrimitive(Primitive_element_value ev, Element element) { + String value = getName(ev.const_value_index); + element.add(value); + return null; + } + + public Void visitEnum(Enum_element_value ev, Element element) { + String value = getName(ev.type_name_index) + "." + getName(ev.const_name_index); + element.add(value); + return null; + } + + public Void visitClass(Class_element_value ev, Element element) { + String value = getName(ev.class_info_index) + ".class"; + element.add(value); + return null; + } + + public Void visitAnnotation(Annotation_element_value ev, Element element) { + // AnnotationParser.this.addAnnotation(ev.annotation_value); + throw new UnsupportedOperationException("Not supported: " + ev); + } + + public Void visitArray(Array_element_value ev, Element element) { + for (int i = 0; i < ev.num_values; i++) { + parse(ev.values[i], element); + } + return null; + } + } + + void parseAttributes(Attributes attributes, Klass.Method method) { + if (!parseAnnotation) { + return; + } + + visitRuntimeAnnotations((RuntimeVisibleAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleAnnotations), method); + visitRuntimeAnnotations((RuntimeInvisibleAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleAnnotations), method); + visitRuntimeTypeAnnotations((RuntimeVisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleTypeAnnotations), method); + visitRuntimeTypeAnnotations((RuntimeInvisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleTypeAnnotations), method); + visitRuntimeParameterAnnotations((RuntimeVisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleParameterAnnotations), method); + visitRuntimeParameterAnnotations((RuntimeInvisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleParameterAnnotations), method); + } + + public void visitRuntimeAnnotations(RuntimeAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int i = 0; i < attr.annotations.length; i++) { + addAnnotation(attr.annotations[i], method); + } + } + + public void visitRuntimeTypeAnnotations(RuntimeTypeAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int i = 0; i < attr.annotations.length; i++) { + addAnnotation(attr.annotations[i], method); + } + } + + public void visitRuntimeParameterAnnotations(RuntimeParameterAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int param = 0; param < attr.parameter_annotations.length; param++) { + for (int i = 0; i < attr.parameter_annotations[param].length; i++) { + addAnnotation(attr.parameter_annotations[param][i], method); + } + } + } + + void parseAttributes(Attributes attributes) { + parseAttributes(attributes, null); + } + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String output = "."; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-output")) { + output = args[i++]; + } else { + usage(); + } + } + if (jdkhome == null) { + usage(); + } + + // parse annotation and code attribute to find all references + // to Class.forName etc + CodeAttributeParser.setParseCodeAttribute(true); + AnnotationParser.setParseAnnotation(true); + + ClassPath.setJDKHome(jdkhome); + ClassPath.parseAllClassFiles(); + + PrintWriter writer = new PrintWriter(new File(output, "jdk7.depconfig")); + + try { + for (Klass k : Klass.getAllClasses()) { + for (AnnotatedDependency dep : k.getAnnotatedDeps()) { + if (dep.isEmpty()) { + continue; + } + writer.format("# %s \n", dep.method == null ? dep.from : dep.method); + writer.format("%s\n\n", dep); + } + } + } finally { + writer.close(); + } + + writer = new PrintWriter(new File(output, "optional.depconfig")); + try { + AnnotatedDependency prev = null; + for (AnnotatedDependency dep : AnnotatedDependency.optionalDependencies) { + if (prev != null && !dep.equals(prev)) { + writer.format("%s\n\n", prev); + } + writer.format("# %s \n", dep.method == null ? dep.from : dep.method); + prev = dep; + } + if (prev != null) { + writer.format("%s\n\n", prev); + } + } finally { + writer.close(); + } + + writer = new PrintWriter(new File(output, "runtime.references")); + try { + for (Map.Entry> entry : CodeAttributeParser.runtimeReferences.entrySet()) { + writer.format("References to %s\n", entry.getKey()); + Klass prev = null; + for (Klass.Method m : entry.getValue()) { + if (prev == null || prev != m.getKlass()) { + writer.format(" %-50s # %s\n", m.getKlass(), m); + } else if (prev == m.getKlass()) { + writer.format(" %-50s # %s\n", "", m); + } + prev = m.getKlass(); + } + } + } finally { + writer.close(); + } + } + + private static void usage() { + System.out.println("Usage: AnnotationParser "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-depconfig "); + System.out.println("\t-optional "); + System.exit(-1); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java new file mode 100644 index 00000000000..06e332ace7c --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java @@ -0,0 +1,819 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.File; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; +import static com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Instruction.TypeKind; +import com.sun.tools.classfile.Type.*; + +/** + * Generate the module config for the boot module with + * a given set of roots (classes or methods) and exclude list. + * + * This tool does method-level dependency analysis starting + * from the root set and follows references transitively as follows: + *

+ * + * Limitation: + * + * + * @author Mandy Chung + */ +public class BootAnalyzer { + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String config = null; + String output = "."; + boolean printClassList = false; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-config")) { + config = args[i++]; + } else if (arg.equals("-output")) { + output = args[i++]; + } else if (arg.equals("-classlist")) { + printClassList = true; + } else { + usage(); + } + } + + + + if (jdkhome == null || config == null) { + usage(); + } + + File jre = new File(jdkhome, "jre"); + if (jre.exists()) { + ClassPath.setJDKHome(jdkhome); + } else { + File classes = new File(jdkhome, "classes"); + if (classes.exists()) { + ClassPath.setClassPath(classes.getCanonicalPath()); + } else { + throw new RuntimeException("Invalid jdkhome: " + jdkhome); + } + } + + parseConfigFile(config); + followRoots(); + + // create output directory if it doesn't exist + File dir = new File(output); + if (!dir.isDirectory()) { + if (!dir.exists()) { + boolean created = dir.mkdir(); + if (!created) { + throw new RuntimeException("Unable to create `" + dir + "'"); + } + } + } + + String bootmodule = "boot"; + String bootconfig = resolve(dir, bootmodule, "config"); + printBootConfig(bootconfig, bootmodule); + + List list = ModuleConfig.readConfigurationFile(bootconfig); + Module module = Module.addModule(list.get(0)); + for (Klass k : Klass.getAllClasses()) { + module.addKlass(k); + } + module.fixupDependencies(); + + if (printClassList) { + module.printClassListTo(resolve(dir, bootmodule, "classlist")); + module.printSummaryTo(resolve(dir, bootmodule, "summary")); + } + } + + // print boot.config file as an input to the ClassAnalyzer + private static void printBootConfig(String output, String bootmodule) throws IOException { + + File f = new File(output); + PrintWriter writer = new PrintWriter(f); + try { + int count = 0; + writer.format("module %s {%n", bootmodule); + for (Klass k : Klass.getAllClasses()) { + if (count++ == 0) { + writer.format("%4s%7s %s", "", "include", k); + } else { + writer.format(",%n"); + writer.format("%4s%7s %s", "", "", k); + } + } + writer.format(";%n}%n"); + } finally { + writer.close(); + } + } + + private static String resolve(File dir, String mname, String suffix) { + File f = new File(dir, mname + "." + suffix); + return f.toString(); + + } + static List methods = new LinkedList(); + static Deque pending = new ArrayDeque(); + static Deque interfaceMethodRefs = new ArrayDeque(); + static Filter filter = new Filter(); + + private static void followRoots() throws IOException { + MethodDescriptor md = null; + + while ((md = pending.poll()) != null) { + if (!methods.contains(md)) { + methods.add(md); + if (md.classname.isEmpty()) { + trace("Warning: class missing %s%n", md); + continue; + } + + if (filter.isExcluded(md.classname)) { + trace("excluded %s%n", md); + } else { + KlassInfo kinfo = getKlassInfo(md.classname); + if (kinfo.classname.contains("$")) { + int pos = kinfo.classname.lastIndexOf('$'); + String outer = kinfo.classname.substring(0, pos); + if (!cache.containsKey(outer)) { + trace(" include outer class %s%n", outer); + getKlassInfo(outer).ensureParse(); + } + } + + kinfo.ensureParse(); + if (md.methodname.length() > 0) { + if (filter.isExcluded(md.name)) { + trace("excluded %s%n", md); + } else { + if (md.interfaceMethodRef) { + trace("interface methodref %s%n", md); + interfaceMethodRefs.add(md); + } else { + List descriptors = kinfo.parse(md); + if (descriptors.isEmpty()) { + if (kinfo.getSuperclass() != null) { + String sn = kinfo.getSuperclass().classname; + MethodDescriptor superMD = new MethodDescriptor(sn + "." + md.methodname, md.descriptor, false); + if (!methods.contains(superMD) && !pending.contains(superMD)) { + trace(" delegated %s to %s%n", md, superMD); + pending.add(superMD); + } + } else if (kinfo.isClass()) { + trace(" %s (not found)%n", md); + } else { + trace(" %s (interface)%n", md); + } + } else { + if (md.descriptor.equals("*")) { + trace(" parsed %s : ", md.name); + for (String s : descriptors) { + trace(" %s", s); + } + trace("%n"); + } + } + } + } + } + } + } + if (pending.isEmpty()) { + for (Klass k : Klass.getAllClasses()) { + if (k.getFileSize() == 0) { + getKlassInfo(k.getClassName()).ensureParse(); + } + } + while ((md = interfaceMethodRefs.poll()) != null) { + addSubClassMethods(md); + } + } + } + } + + static void addSubClassMethods(MethodDescriptor md) throws IOException { + for (KlassInfo kinfo : getSubClasses(md.classname)) { + String methodname = kinfo.classname + "." + md.methodname; + MethodDescriptor other = new MethodDescriptor(methodname, md.descriptor, false); + if (!methods.contains(other) && !pending.contains(other)) { + trace("Warning: subclass from %s to %s%n", md.classname, other); + pending.add(other); + } + } + } + private final static String privilegedActionInterf = "java.security.PrivilegedAction"; + private final static String privilegedExceptionActionInterf = "java.security.PrivilegedExceptionAction"; + + static boolean isPrivilegedAction(String classname) { + if (classname.isEmpty()) { + return false; + } + KlassInfo kinfo = getKlassInfo(classname); + for (KlassInfo ki : kinfo.getInterfaces()) { + String interf = ki.classname; + if (interf.equals(privilegedActionInterf) || + interf.equals(privilegedExceptionActionInterf)) { + return true; + } + } + return false; + } + static Map cache = new HashMap(); + + static KlassInfo getKlassInfo(String classname) { + classname = classname.replace('/', '.'); + + KlassInfo kinfo = cache.get(classname); + if (kinfo == null) { + kinfo = new KlassInfo(classname); + cache.put(classname, kinfo); + } + return kinfo; + } + + static class KlassInfo { + + final String classname; + private ClassFileParser parser; + private KlassInfo superclass; + private List interfaces = new LinkedList(); + + KlassInfo(String classname) { + this.classname = classname; + } + + boolean isClass() { + ensureParse(); + return parser.classfile.isClass(); + } + + KlassInfo getSuperclass() { + ensureParse(); + return superclass; + } + + List getInterfaces() { + ensureParse(); + return java.util.Collections.unmodifiableList(interfaces); + } + + void ensureParse() { + try { + getClassFileParser(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + synchronized ClassFileParser getClassFileParser() throws IOException { + if (parser == null) { + parser = ClassPath.parserForClass(classname); + if (parser != null) { + parseClassFile(); + List descriptors = parse(new MethodDescriptor(classname + ".", "()V", false)); + } + } + return parser; + } + + List parse(MethodDescriptor md) { + ensureParse(); + try { + List descriptors = new LinkedList(); + for (Method m : parser.classfile.methods) { + String name = m.getName(parser.classfile.constant_pool); + String desc = parser.constantPoolParser.getDescriptor(m.descriptor.index); + if (name.equals(md.methodname)) { + if (md.descriptor.equals("*") || md.descriptor.equals(desc)) { + parseMethod(parser, m); + descriptors.add(desc); + } + } + } + return descriptors; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private void parseClassFile() throws IOException { + parser.parseClassInfo(); + + ClassFile classfile = parser.classfile; + try { + if (classfile.super_class > 0) { + superclass = getKlassInfo(classfile.getSuperclassName()); + } + if (classfile.interfaces != null) { + for (int i = 0; i < classfile.interfaces.length; i++) { + interfaces.add(getKlassInfo(classfile.getInterfaceName(i))); + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + } + + static List getSubClasses(String classname) throws IOException { + List result = new LinkedList(); + List list = new LinkedList(); + list.addAll(cache.values()); + for (KlassInfo kinfo : list) { + if (kinfo.getSuperclass() != null && classname.equals(kinfo.getSuperclass().classname)) { + result.add(kinfo); + } + for (KlassInfo interf : kinfo.getInterfaces()) { + if (classname.equals(interf.classname)) { + result.add(kinfo); + } + } + } + return result; + } + + private static void parseConfigFile(String config) throws IOException { + FileInputStream in = new FileInputStream(config); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + int lineNumber = 0; + while ((line = reader.readLine()) != null) { + lineNumber++; + if ((line = line.trim()).length() > 0) { + if (line.startsWith("#")) { + continue; + } + + String[] s = line.split("\\s+"); + if ("exclude".equals(s[0])) { + filter.exclude(s[1]); + } else { + String name = s[0].replace('/', '.'); + if (name.length() > 0) { + String classname = name.replace('/', '.'); + if (s.length == 2) { + // method name + int pos = classname.lastIndexOf('.'); + classname = classname.substring(0, pos); + } + + KlassInfo kinfo = getKlassInfo(classname); + if (kinfo.getClassFileParser() != null) { + // class exists + MethodDescriptor md = (s.length == 1) ? new MethodDescriptor(name) : new MethodDescriptor(name, s[1], false); + if (!pending.contains(md)) { + pending.add(md); + } + } else { + // class not found + trace("Class %s not found%n", classname); + } + } + } + } + } + + } finally { + in.close(); + } + } + + private static void parseMethod(ClassFileParser cfparser, Method m) { + Klass.Method kmethod = cfparser.parseMethod(m); + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + LineNumberTable_attribute lineNumTable = + (LineNumberTable_attribute) c_attr.attributes.get(Attribute.LineNumberTable); + InstructorVisitor visitor = new InstructorVisitor(cfparser, lineNumTable); + trace("parseMethod %s %s %n", cfparser.this_klass, kmethod); + for (Instruction instr : c_attr.getInstructions()) { + try { + instr.accept(visitor, kmethod); + } catch (ArrayIndexOutOfBoundsException e) { + throw new RuntimeException("error at or after byte " + instr.getPC()); + } + + } + + if (c_attr.exception_table_langth > 0) { + for (int i = 0; i < + c_attr.exception_table.length; i++) { + Code_attribute.Exception_data handler = c_attr.exception_table[i]; + int catch_type = handler.catch_type; + if (catch_type > 0) { + visitor.addConstantPoolRef(catch_type, kmethod, handler.start_pc); + } + + } + } + } + } + + static class MethodDescriptor { + + final String name; + final String classname; + final String methodname; + final String descriptor; + final boolean interfaceMethodRef; + + MethodDescriptor(String classname) { + this.classname = classname.replace('/', '.'); + this.name = this.classname; + this.methodname = ""; + this.descriptor = ""; + this.interfaceMethodRef = false; + if (this.classname.length() == 1) { + throw new RuntimeException("invalid " + this); + } + } + + MethodDescriptor(String name, String descriptor, boolean interfaceMethodRef) { + name = name.replace('/', '.'); + this.name = name; + int pos = name.lastIndexOf('.'); + this.classname = name.substring(0, pos); + this.methodname = name.substring(pos + 1, name.length()); + this.descriptor = descriptor; + this.interfaceMethodRef = interfaceMethodRef; + if (this.classname.length() == 1) { + throw new RuntimeException("invalid " + this); + } + } + + @Override + public boolean equals(Object obj) { + MethodDescriptor m = (MethodDescriptor) obj; + + return this.name.equals(m.name) && + this.descriptor.equals(m.descriptor); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + hash = 97 * hash + (this.descriptor != null ? this.descriptor.hashCode() : 0); + return hash; + } + + public String toString() { + if (descriptor.isEmpty()) { + return name; + } else { + return name + " : " + descriptor; + } + } + } + + static class Filter { + + private Set excludes = new TreeSet(); + + Filter exclude(String pattern) { + excludes.add(pattern); + return this; + } + + boolean isExcluded(String klass) { + for (String pattern : excludes) { + if (matches(klass, pattern)) { + return true; + } + } + return false; + } + + private boolean matches(String klass, String pattern) { + int pos = klass.lastIndexOf('.'); + String packageName = pos > 0 ? klass.substring(0, pos) : ""; + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return klass.startsWith(p); + } else if (pattern.endsWith("*")) { + pos = pattern.lastIndexOf('.'); + String pkg = pos > 0 ? pattern.substring(0, pos) : ""; + if (packageName.equals(pkg)) { + // package name has to be exact match + String p = pattern.substring(0, pattern.length() - 1); + return klass.startsWith(p); + } else { + return false; + } + } else { + // exact match or inner class + return klass.equals(pattern) || klass.startsWith(pattern + "$"); + } + } + } + + static class InstructorVisitor implements Instruction.KindVisitor { + + private final ClassFileParser parser; + private final LineNumberTable_attribute lineNumTable; + + InstructorVisitor(ClassFileParser parser, LineNumberTable_attribute lineNumTable) { + this.parser = parser; + this.lineNumTable = lineNumTable; + } + + int getLineNumber(int pc) { + if (lineNumTable != null) { + int start_pc = 0; + int lineno = 0; + for (int i = 0; i < lineNumTable.line_number_table_length; i++) { + int cur_start_pc = lineNumTable.line_number_table[i].start_pc; + if (pc == 0 && cur_start_pc == 0) { + return lineNumTable.line_number_table[i].line_number; + } else if (pc >= start_pc && pc < cur_start_pc) { + return lineno; + } + start_pc = cur_start_pc; + lineno = lineNumTable.line_number_table[i].line_number; + } + } + return 0; + } + + void addConstantPoolRef(int index, Klass.Method m, int pc) { + try { + CPInfo cpInfo = parser.classfile.constant_pool.get(index); + String name = cpInfo.accept(typeFinder, null); + if (name != null) { + trace(" %s %s at line %d%n", parser.constantPoolParser.tagName(index), name, getLineNumber(pc)); + } + } catch (InvalidIndex ex) { + throw new RuntimeException(ex); + } + } + + public Void visitNoOperands(Instruction instr, Klass.Method m) { + return null; + } + + public Void visitArrayType(Instruction instr, TypeKind kind, Klass.Method m) { + return null; + } + + public Void visitBranch(Instruction instr, int offset, Klass.Method m) { + return null; + } + + public Void visitConstantPoolRef(Instruction instr, int index, Klass.Method m) { + addConstantPoolRef(index, m, instr.getPC()); + return null; + } + + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Klass.Method m) { + addConstantPoolRef(index, m, instr.getPC()); + return null; + } + + public Void visitLocal(Instruction instr, int index, Klass.Method m) { + return null; + } + + public Void visitLocalAndValue(Instruction instr, int index, int value, Klass.Method m) { + return null; + } + + public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitValue(Instruction instr, int value, Klass.Method m) { + return null; + } + + public Void visitUnknown(Instruction instr, Klass.Method m) { + return null; + } + private ConstantPool.Visitor typeFinder = new ConstantPool.Visitor() { + + String getClassName(CPRefInfo info, Void p) { + try { + return parser.checkClassName(info.getClassName()).replace('/', '.'); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + boolean addReferencedClass(String name) { + if (Klass.findKlass(name) == null) { + MethodDescriptor md = new MethodDescriptor(name); + if (!methods.contains(md) && !pending.contains(md)) { + pending.add(md); + } + return true; + } + return false; + } + private String privilegedActionClass = ""; + + void cachePrivilegedAction(String classname) { + trace(" found PrivilegedAction %s%n", classname); + privilegedActionClass = classname; + } + + void doPrivilegedCall(String method) { + if (privilegedActionClass.length() > 0) { + MethodDescriptor md = new MethodDescriptor(privilegedActionClass + ".run", "*", false); + if (!methods.contains(md) && !pending.contains(md)) { + trace(" doPrivileged %s%n", md); + pending.add(md); + } + } + } + + private String addMethodDescriptor(CPRefInfo info, Void p) { + try { + String classname = getClassName(info, null); + String method = classname + "." + info.getNameAndTypeInfo().getName(); + String descriptor = info.getNameAndTypeInfo().getType(); + + if (method.endsWith(".") && isPrivilegedAction(classname)) { + cachePrivilegedAction(classname); + } + if (method.equals("java.security.AccessController.doPrivileged")) { + doPrivilegedCall(method); + return method; + } + + boolean interfaceMethodRef = info instanceof CONSTANT_InterfaceMethodref_info; + MethodDescriptor md = new MethodDescriptor(method, descriptor, interfaceMethodRef); + if (!methods.contains(md) && !pending.contains(md)) { + pending.add(md); + } + return method; + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitClass(CONSTANT_Class_info info, Void p) { + try { + String classname = parser.checkClassName(info.getName()).replace('/', '.'); + if (classname.length() > 0) { + addReferencedClass(classname); + } + return classname; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + public String visitDouble(CONSTANT_Double_info info, Void p) { + // skip + return null; + } + + public String visitFieldref(CONSTANT_Fieldref_info info, Void p) { + try { + String classname = getClassName(info, p); + if (classname.length() > 0) { + addReferencedClass(classname); + } + + String type = info.getNameAndTypeInfo().getType(); + String fieldType = parser.checkClassName(type).replace('/', '.'); + if (fieldType.length() > 0) { + addReferencedClass(classname); + } + return parser.constantPoolParser.stringValue(info); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitFloat(CONSTANT_Float_info info, Void p) { + // skip + return null; + } + + public String visitInteger(CONSTANT_Integer_info info, Void p) { + // skip + return null; + } + + public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return addMethodDescriptor(info, p); + } + + public String visitLong(CONSTANT_Long_info info, Void p) { + // skip + return null; + } + + public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + // skip + return null; + } + + public String visitMethodref(CONSTANT_Methodref_info info, Void p) { + return addMethodDescriptor(info, p); + } + + public String visitString(CONSTANT_String_info info, Void p) { + // skip + return null; + } + + public String visitUtf8(CONSTANT_Utf8_info info, Void p) { + return null; + } + }; + } + static boolean traceOn = System.getProperty("classanalyzer.debug") != null; + + private static void trace(String format, Object... args) { + if (traceOn) { + System.out.format(format, args); + } + } + + private static void usage() { + System.out.println("Usage: BootAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-config "); + System.out.println("\t-output "); + System.out.println("\t-classlist print class list and summary"); + System.exit(-1); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java new file mode 100644 index 00000000000..ea73b43e3fc --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java @@ -0,0 +1,181 @@ +/* + * 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.classanalyzer; + +import java.io.*; +import java.util.*; + +/** + * A simple tool to check module dependencies against a known list of + * dependencies. The tool fails (by throwing a RuntimeException) is an + * unexpected dependency is detected. + */ + +public class CheckDeps { + + /** + * Represents a dependency from one module to another module. The dependency + * may be optional. + */ + static class Dependency { + private final String module; + private final String other; + private final boolean optional; + + private Dependency(String module, String other, boolean optional) { + this.module = module; + this.other = other; + this.optional = optional; + } + + String module() { return module; } + String other() { return other; } + boolean isOptional() { return optional; } + + /** + * Parses a dependency in one of the following forms: + * a -> b + * [optional] a -> b + */ + static Dependency fromString(String s) { + String[] components = s.split(" "); + int count = components.length; + if (count != 3 && count != 4) + throw new IllegalArgumentException(s); + boolean optional = (count == 4); + if (optional && !components[0].equals("[optional]")) + throw new IllegalArgumentException(s); + String arrow = optional ? components[2] : components[1]; + if (!arrow.equals("->")) + throw new IllegalArgumentException(s); + String module = optional ? components[1] : components[0]; + String other = optional ? components[3] : components[2]; + return new Dependency(module, other, optional); + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder(); + if (optional) + sb.append("[optional] "); + sb.append(module); + sb.append(" -> "); + sb.append(other); + return sb.toString(); + } + } + + /** + * Represents the "tail" + */ + static class DependencyTail { + private final String module; + private final boolean optional; + + DependencyTail(String module, boolean optional) { + this.module = module; + this.optional = optional; + } + String module() { return module; } + boolean isOptional() { return optional; } + } + + static void usage() { + System.out.println("java CheckDeps file1 file2"); + System.out.println(" where file1 is the expected dependencies and file2 is"); + System.out.println(" the actual dependencies. Both files are assumed to be"); + System.out.println(" in modules.summary format (see ClassAnalyzer tool)."); + System.out.println(); + System.out.println("Example usages:"); + System.out.println(" java CheckDeps make/modules/modules.summary " + + "$(OUTPUTDIR)/modules.summary"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length != 2) + usage(); + + // maps a module to the list of modules that it depends on + Map> expected = + new HashMap>(); + + // parse the expected dependencies file + Scanner s; + s = new Scanner(new FileInputStream(args[0])); + try { + while (s.hasNextLine()) { + Dependency ref = Dependency.fromString(s.nextLine()); + if (ref != null) { + String module = ref.module(); + List list = expected.get(module); + if (list == null) { + list = new ArrayList(); + expected.put(module, list); + } + list.add(new DependencyTail(ref.other(), ref.isOptional())); + } + } + } finally { + s.close(); + } + + // parse the actual dependencies file, checking each dependency + // against the expected list. + boolean fail = false; + s = new Scanner(new FileInputStream(args[1])); + try { + while (s.hasNextLine()) { + Dependency dep = Dependency.fromString(s.nextLine()); + + // check if this dependency is expected + List list = expected.get(dep.module()); + DependencyTail tail = null; + if (list != null) { + for (DependencyTail t: list) { + if (t.module().equals(dep.other())) { + tail = t; + break; + } + } + } + if (tail == null) { + System.err.println("Unexpected dependency: " + dep); + fail = true; + } else { + // hard dependency when optional dependency is expected + if (tail.isOptional() != dep.isOptional()) { + if (tail.isOptional()) { + System.err.println("Unexpected dependency: " + dep); + fail = true; + } + } + } + } + } finally { + s.close(); + } + + if (fail) + throw new RuntimeException("Unexpected dependencies found"); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java new file mode 100644 index 00000000000..fd570a7c0b1 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java @@ -0,0 +1,354 @@ +/* + * 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.classanalyzer; + +import com.sun.classanalyzer.AnnotatedDependency.*; +import com.sun.classanalyzer.Module.Dependency; +import com.sun.classanalyzer.Module.PackageInfo; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.io.File; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ClassAnalyzer { + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String cpath = null; + List configs = new ArrayList(); + List depconfigs = new ArrayList(); + String output = "."; + boolean mergeModules = true; + boolean showDynamic = false; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-cpath")) { + if (i < args.length) { + cpath = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-config")) { + if (i < args.length) { + configs.add(args[i++]); + } else { + usage(); + } + } else if (arg.equals("-depconfig")) { + if (i < args.length) { + depconfigs.add(args[i++]); + } else { + usage(); + } + } else if (arg.equals("-output")) { + if (i < args.length) { + output = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-base")) { + ModuleConfig.setBaseModule(args[i++]); + } else if (arg.equals("-nomerge")) { + // analyze the fine-grained module dependencies + mergeModules = false; + } else if (arg.equals("-showdynamic")) { + showDynamic = true; + } else { + System.err.println("Invalid option: " + arg); + usage(); + } + } + + if ((jdkhome == null && cpath == null) || (jdkhome != null && cpath != null)) { + usage(); + } + if (configs.isEmpty()) { + usage(); + } + + if (jdkhome != null) { + ClassPath.setJDKHome(jdkhome); + } else if (cpath != null) { + ClassPath.setClassPath(cpath); + } + + // create output directory if it doesn't exist + File dir = new File(output); + if (!dir.isDirectory()) { + if (!dir.exists()) { + boolean created = dir.mkdir(); + if (!created) { + throw new RuntimeException("Unable to create `" + dir + "'"); + } + } + } + + buildModules(configs, depconfigs, mergeModules); + + // generate output files + for (Module m : modules) { + // only generate reports for top-level modules + if (m.group() == m) { + m.printClassListTo(resolve(dir, m.name(), "classlist")); + m.printResourceListTo(resolve(dir, m.name(), "resources")); + m.printSummaryTo(resolve(dir, m.name(), "summary")); + m.printDependenciesTo(resolve(dir, m.name(), "dependencies"), showDynamic); + } + } + + // Generate other summary reports + printModulesSummary(dir, showDynamic); + printModulesDot(dir, showDynamic); + printModulesList(dir); + printPackagesSummary(dir); + } + private static List modules = new ArrayList(); + + static void buildModules(List configs, + List depconfigs, + boolean mergeModules) throws IOException { + // create modules based on the input config files + for (String file : configs) { + for (ModuleConfig mconfig : ModuleConfig.readConfigurationFile(file)) { + modules.add(Module.addModule(mconfig)); + } + } + + // parse class files + ClassPath.parseAllClassFiles(); + + // Add additional dependencies if specified + if (depconfigs != null && depconfigs.size() > 0) { + DependencyConfig.parse(depconfigs); + } + + // process the roots and dependencies to get the classes for each module + for (Module m : modules) { + m.processRootsAndReferences(); + } + + // update the dependencies for classes that were subsequently allocated + // to modules + for (Module m : modules) { + m.fixupDependencies(); + } + + if (mergeModules) { + Module.buildModuleMembers(); + } + } + + private static void printModulesSummary(File dir, boolean showDynamic) throws IOException { + // print summary of dependencies + PrintWriter writer = new PrintWriter(new File(dir, "modules.summary")); + try { + for (Module m : modules) { + // only show top-level module dependencies + if (m.group() == m) { + for (Dependency dep : m.dependents()) { + if (!showDynamic && dep.dynamic && dep.optional) { + continue; + } + if (dep.module == null || !dep.module.isBase()) { + + String prefix = ""; + if (dep.optional) { + if (dep.dynamic) { + prefix = "[dynamic] "; + } else { + prefix = "[optional] "; + } + } + + Module other = dep != null ? dep.module : null; + writer.format("%s%s -> %s%n", prefix, m, other); + } + } + } + } + } finally { + writer.close(); + } + } + + private static void printModulesDot(File dir, boolean showDynamic) throws IOException { + PrintWriter writer = new PrintWriter(new File(dir, "modules.dot")); + try { + writer.println("digraph jdk {"); + for (Module m : modules) { + if (m.group() == m) { + for (Dependency dep : m.dependents()) { + if (!showDynamic && dep.dynamic && dep.optional) { + continue; + } + if (dep.module == null || !dep.module.isBase()) { + String style = ""; + String color = ""; + String property = ""; + if (dep.optional) { + style = "style=dotted"; + } + if (dep.dynamic) { + color = "color=red"; + } + if (style.length() > 0 || color.length() > 0) { + String comma = ""; + if (style.length() > 0 && color.length() > 0) { + comma = ", "; + } + property = String.format(" [%s%s%s]", style, comma, color); + } + Module other = dep != null ? dep.module : null; + writer.format(" \"%s\" -> \"%s\"%s;%n", m, other, property); + } + } + } + } + writer.println("}"); + } finally { + writer.close(); + } + } + + private static void printMembers(Module m, PrintWriter writer) { + for (Module member : m.members()) { + if (!member.isEmpty()) { + writer.format("%s ", member); + printMembers(member, writer); + } + } + } + + private static void printModulesList(File dir) throws IOException { + // print module group / members relationship + PrintWriter writer = new PrintWriter(new File(dir, "modules.list")); + try { + for (Module m : modules) { + if (m.group() == m && !m.isEmpty()) { + writer.format("%s ", m); + printMembers(m, writer); + writer.println(); + } + } + } finally { + writer.close(); + } + } + + private static void printPackagesSummary(File dir) throws IOException { + // print package / module relationship + PrintWriter writer = new PrintWriter(new File(dir, "modules.pkginfo")); + try { + Map> packages = new TreeMap>(); + Set splitPackages = new TreeSet(); + + for (Module m : modules) { + if (m.group() == m) { + for (PackageInfo info : m.getPackageInfos()) { + Set value = packages.get(info.pkgName); + if (value == null) { + value = new TreeSet(); + packages.put(info.pkgName, value); + } else { + // package in more than one module + splitPackages.add(info.pkgName); + } + value.add(m); + } + } + } + + // packages that are splitted among multiple modules + writer.println("Packages splitted across modules:-\n"); + writer.format("%-60s %s\n", "Package", "Module"); + + for (String pkgname : splitPackages) { + writer.format("%-60s", pkgname); + for (Module m : packages.get(pkgname)) { + writer.format(" %s", m); + } + writer.println(); + } + + writer.println("\nPackage-private dependencies:-"); + for (String pkgname : splitPackages) { + for (Klass k : Klass.getAllClasses()) { + if (k.getPackageName().equals(pkgname)) { + Module m = k.getModule(); + // check if this klass references a package-private + // class that is in a different module + for (Klass other : k.getReferencedClasses()) { + if (other.getModule() != m && + !other.isPublic() && + other.getPackageName().equals(pkgname)) { + String from = k.getClassName() + " (" + m + ")"; + writer.format("%-60s -> %s (%s)\n", from, other, other.getModule()); + } + } + } + } + } + } finally { + writer.close(); + } + + } + + private static String resolve(File dir, String mname, String suffix) { + File f = new File(dir, mname + "." + suffix); + return f.toString(); + + } + + private static void usage() { + System.out.println("Usage: ClassAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-cpath where classes and jars will be parsed"); + System.out.println("\t Either -jdkhome or -cpath option can be used."); + System.out.println("\t-config "); + System.out.println("\t This option can be repeated for multiple module config files"); + System.out.println("\t-output "); + System.out.println("\t-nomerge specify not to merge modules"); + System.out.println("\t-showdynamic show dynamic dependencies in the reports"); + System.exit(-1); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java new file mode 100644 index 00000000000..bbbeda7407f --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java @@ -0,0 +1,629 @@ +/* + * 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.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Type.*; +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; +import static com.sun.tools.classfile.AccessFlags.*; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ClassFileParser { + + final Klass this_klass; + final ClassFile classfile; + final ConstantPoolParser constantPoolParser; + final AnnotationParser annotationParser; + final CodeAttributeParser codeAttributeParser; + private final boolean buildDeps; + + protected ClassFileParser(InputStream in, long size, boolean buildDeps) throws IOException { + try { + this.classfile = ClassFile.read(in); + this.this_klass = getKlass(this.classfile); + this.buildDeps = buildDeps; + this.constantPoolParser = new ConstantPoolParser(this); + this.annotationParser = new AnnotationParser(this); + this.codeAttributeParser = new CodeAttributeParser(this); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private Klass getKlass(ClassFile cf) throws ConstantPoolException { + Klass k = Klass.getKlass(cf.getName()); + k.setAccessFlags(cf.access_flags.flags); + k.setFileSize(cf.byteLength()); + return k; + } + + public static ClassFileParser newParser(InputStream in, long size, boolean buildDeps) throws IOException { + return new ClassFileParser(in, size, buildDeps); + } + + public static ClassFileParser newParser(String classPathname, boolean buildDeps) throws IOException { + return newParser(new File(classPathname), buildDeps); + } + + public static ClassFileParser newParser(File f, boolean buildDeps) throws IOException { + BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); + try { + return newParser(in, f.length(), buildDeps); + } finally { + in.close(); + } + } + + public void parseDependency(boolean publicAPIs) throws IOException { + if (publicAPIs && !classfile.access_flags.is(ACC_PUBLIC)) { + // process public APIs only + return; + } + + parseClassInfo(); + if (!publicAPIs) { + // parse all references in the classfile + constantPoolParser.parseDependency(); + } + parseMethods(publicAPIs); + parseFields(publicAPIs); + } + + void parseClassInfo() throws IOException { + ConstantPool cpool = classfile.constant_pool; + try { + Signature_attribute sigAttr = (Signature_attribute) classfile.attributes.get(Attribute.Signature); + if (sigAttr == null) { + // use info from class file header + if (classfile.isClass() && classfile.super_class != 0) { + String sn = classfile.getSuperclassName(); + addExtends(sn); + } + for (int i = 0; i < classfile.interfaces.length; i++) { + String interf = classfile.getInterfaceName(i); + if (classfile.isClass()) { + addImplements(interf); + } else { + addExtends(interf); + } + } + } else { + Type t = sigAttr.getParsedSignature().getType(cpool); + // The signature parser cannot disambiguate between a + // FieldType and a ClassSignatureType that only contains a superclass type. + if (t instanceof Type.ClassSigType) { + Type.ClassSigType cst = Type.ClassSigType.class.cast(t); + if (cst.superclassType != null) { + for (Klass k : getKlass(cst.superclassType)) { + addExtends(k); + } + } + if (cst.superinterfaceTypes != null) { + for (Type t1 : cst.superinterfaceTypes) { + for (Klass k : getKlass(t1)) { + addImplements(k); + } + } + } + } else { + for (Klass k : getKlass(t)) { + addExtends(k); + } + } + } + // parse attributes + annotationParser.parseAttributes(classfile.attributes); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private void parseFields(boolean publicAPIs) throws IOException { + ConstantPool cpool = classfile.constant_pool; + for (Field f : classfile.fields) { + try { + AccessFlags flags = f.access_flags; + if (publicAPIs && !flags.is(ACC_PUBLIC) && !flags.is(ACC_PROTECTED)) { + continue; + } + String fieldname = f.getName(cpool); + Signature_attribute sigAttr = (Signature_attribute) f.attributes.get(Attribute.Signature); + + if (sigAttr == null) { + Set types = parseDescriptor(f.descriptor); + String info = getFlag(flags) + " " + f.descriptor.getFieldType(cpool) + " " + fieldname; + addFieldTypes(types, info, flags); + } else { + Type t = sigAttr.getParsedSignature().getType(cpool); + String info = getFlag(flags) + " " + t + " " + fieldname; + addFieldTypes(getKlass(t), info, flags); + } + // parse attributes + annotationParser.parseAttributes(f.attributes); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (InvalidDescriptor ex) { + throw new RuntimeException(ex); + } + } + } + + private void parseMethods(boolean publicAPIs) { + for (Method m : classfile.methods) { + if (publicAPIs && !m.access_flags.is(ACC_PUBLIC) && !m.access_flags.is(ACC_PROTECTED)) { + // only interest in the API level + return; + } + + parseMethod(m); + } + } + + String checkClassName(String classname) { + int i = 0; + while (i < classname.length()) { + switch (classname.charAt(i)) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'J': + case 'F': + case 'D': + return ""; + case 'L': + if (!classname.endsWith(";")) { + throw new RuntimeException("Invalid classname " + classname); + } + return classname.substring(i + 1, classname.length() - 1); + case '[': + i++; + break; + default: + if (classname.endsWith(";")) { + throw new RuntimeException("Invalid classname " + classname); + } + return classname; + + } + } + throw new RuntimeException("Invalid classname " + classname); + } + + private void addExtends(String classname) throws IOException { + if (!buildDeps) { + return; + } + + addExtends(Klass.getKlass(classname)); + } + + private void addExtends(Klass k) { + if (!buildDeps) { + return; + } + + ResolutionInfo resInfo = ResolutionInfo.resolvedExtends(this_klass, k); + resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); + this_klass.addDep(k, resInfo); + k.addReferrer(this_klass, resInfo); + } + + private void addImplements(String classname) throws IOException { + if (!buildDeps) { + return; + } + + addImplements(Klass.getKlass(classname)); + } + + private void addImplements(Klass k) { + if (!buildDeps) { + return; + } + + ResolutionInfo resInfo = ResolutionInfo.resolvedImplements(this_klass, k); + resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); + + this_klass.addDep(k, resInfo); + + k.addReferrer(this_klass, resInfo); + } + + private Set getKlass(Type type) throws IOException { + Set refTypes = new TreeSet(); + if (!buildDeps) { + return refTypes; + } + + type.accept(typevisitor, refTypes); + return refTypes; + } + private Type.Visitor> typevisitor = new Type.Visitor>() { + + public Void visitSimpleType(SimpleType type, Set klasses) { + // nop + return null; + } + + public Void visitArrayType(ArrayType type, Set klasses) { + try { + klasses.addAll(getKlass(type.elemType)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return null; + + } + + public Void visitMethodType(MethodType type, Set klasses) { + throw new InternalError("Unexpected type " + type); + } + + public Void visitClassSigType(ClassSigType type, Set klasses) { + try { + if (type.superclassType != null) { + klasses.addAll(getKlass(type.superclassType)); + } + if (type.superinterfaceTypes != null) { + for (Type t : type.superinterfaceTypes) { + klasses.addAll(getKlass(t)); + } + } + if (type.typeParamTypes != null) { + for (Type t : type.typeParamTypes) { + klasses.addAll(getKlass(t)); + } + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return null; + } + + public Void visitClassType(ClassType type, Set klasses) { + klasses.add(Klass.getKlass(type.getBinaryName())); + if (type.typeArgs != null) { + for (Type t : type.typeArgs) { + try { + klasses.addAll(getKlass(t)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + return null; + + } + + public Void visitTypeParamType(TypeParamType type, Set klasses) { + try { + if (type.classBound != null) { + klasses.addAll(getKlass(type.classBound)); + } + if (type.interfaceBounds != null) { + for (Type t : type.interfaceBounds) { + klasses.addAll(getKlass(t)); + } + } + + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + return null; + + } + + public Void visitWildcardType(WildcardType type, Set klasses) { + if (type.boundType != null) { + try { + klasses.addAll(getKlass(type.boundType)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return null; + + } + }; + + private void printMethod(Method m) { + try { + System.out.println("parsing " + m.getName(classfile.constant_pool) + "(" + + m.descriptor.getParameterTypes(classfile.constant_pool) + ") return type " + + m.descriptor.getReturnType(classfile.constant_pool)); + + } catch (ConstantPoolException ex) { + } catch (InvalidDescriptor ex) { + } + } + + private static StringBuilder appendWord(StringBuilder sb, String word) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append(word); + return sb; + } + + private static String getFlag(AccessFlags flags) { + StringBuilder modifier = new StringBuilder(); + if (flags.is(ACC_PUBLIC)) { + modifier.append("public"); + } + if (flags.is(ACC_PRIVATE)) { + modifier.append("private"); + } + if (flags.is(ACC_PROTECTED)) { + modifier.append("protected"); + } + if (flags.is(ACC_STATIC)) { + appendWord(modifier, "static"); + } + if (flags.is(ACC_FINAL)) { + appendWord(modifier, "final"); + } + if (flags.is(ACC_SYNCHRONIZED)) { + // return "synchronized"; + } + if (flags.is(0x80)) { + // return (t == Type.Field ? "transient" : null); + // return "transient"; + } + if (flags.is(ACC_VOLATILE)) { + // return "volatile"; + } + if (flags.is(ACC_NATIVE)) { + // return "native"; + } + if (flags.is(ACC_ABSTRACT)) { + appendWord(modifier, "abstract"); + } + if (flags.is(ACC_STRICT)) { + // return "strictfp"; + } + if (flags.is(ACC_MODULE)) { + appendWord(modifier, "module"); + } + return modifier.toString(); + } + + private Klass.Method toKlassMethod(Method m, Descriptor d) { + try { + ConstantPool cpool = classfile.constant_pool; + String methodname = m.getName(cpool); + StringBuilder sb = new StringBuilder(); + sb.append(getFlag(m.access_flags)); + if (methodname.equals("")) { + String s = this_klass.getBasename() + d.getParameterTypes(cpool); + appendWord(sb, s); + } else if (methodname.equals("")) { + // + appendWord(sb, methodname); + } else { + String s = d.getReturnType(cpool) + " " + methodname + d.getParameterTypes(cpool); + appendWord(sb, s); + } + String signature = sb.toString().replace('/', '.'); + return this_klass.getMethod(methodname, signature); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (InvalidDescriptor ex) { + throw new RuntimeException(ex); + } + } + + Klass.Method parseMethod(Method m) { + AccessFlags flags = m.access_flags; + Descriptor d; + List methodExceptions = null; + try { + ConstantPool cpool = classfile.constant_pool; + Klass.Method kmethod; + Signature_attribute sigAttr = (Signature_attribute) m.attributes.get(Attribute.Signature); + if (sigAttr == null) { + d = m.descriptor; + Set types = parseDescriptor(d); + + kmethod = toKlassMethod(m, d); + addMethodTypes(types, kmethod, flags); + } else { + Type.MethodType methodType; + Signature methodSig = sigAttr.getParsedSignature(); + d = methodSig; + try { + kmethod = toKlassMethod(m, d); + methodType = (Type.MethodType) methodSig.getType(cpool); + addMethodTypes(getKlass(methodType.returnType), kmethod, flags); + if (methodType.paramTypes != null) { + for (Type t : methodType.paramTypes) { + addMethodTypes(getKlass(t), kmethod, flags); + } + } + if (methodType.typeParamTypes != null) { + for (Type t : methodType.typeParamTypes) { + addMethodTypes(getKlass(t), kmethod, flags); + } + } + + methodExceptions = methodType.throwsTypes; + if (methodExceptions != null) { + if (methodExceptions.size() == 0) { + methodExceptions = null; + } else { + for (Type t : methodExceptions) { + addCheckedExceptionTypes(getKlass(t), kmethod, flags); + } + } + } + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + Attribute e_attr = m.attributes.get(Attribute.Exceptions); + if (e_attr != null && methodExceptions == null) { + // if there are generic exceptions, there must be erased exceptions + if (e_attr instanceof Exceptions_attribute) { + Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; + for (int i = 0; i < exceptions.number_of_exceptions; i++) { + String classname = checkClassName(exceptions.getException(i, classfile.constant_pool)); + if (classname.length() > 0 && buildDeps) { + Klass to = Klass.getKlass(classname); + ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, kmethod); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + } else { + throw new RuntimeException("Invalid attribute: " + e_attr); + } + } + + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + codeAttributeParser.parse(c_attr, kmethod); + } + kmethod.isAbstract = classfile.access_flags.is(ACC_ABSTRACT); + kmethod.setCodeLength(m.byteLength()); + + // parse annotation attributes + annotationParser.parseAttributes(m.attributes, kmethod); + return kmethod; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private void addFieldTypes(Set types, String info, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedField(this_klass, to, info); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private void addReferencedTypes(Method m, Descriptor d, AccessFlags flags) { + Set types = parseDescriptor(d); + + Klass.Method method = toKlassMethod(m, d); + addMethodTypes(types, method, flags); + } + + private void addMethodTypes(Set types, Klass.Method method, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedMethodSignature(this_klass, to, method); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private void addCheckedExceptionTypes(Set types, Klass.Method method, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, method); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private Set parseDescriptor(Descriptor d) { + Set types = new TreeSet(); + try { + String desc = d.getValue(classfile.constant_pool); + int p = 0; + while (p < desc.length()) { + String type; + char ch; + switch (ch = desc.charAt(p++)) { + case '(': + case ')': + case '[': + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': + case 'V': + continue; + case 'L': + int sep = desc.indexOf(';', p); + if (sep == -1) { + throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); + } + type = checkClassName(desc.substring(p, sep)); + p = sep + 1; + break; + default: + throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); + } + + if (!type.isEmpty() && buildDeps) { + Klass to = Klass.getKlass(type); + types.add(to); + + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + return types; + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java new file mode 100644 index 00000000000..bfdcdd97f59 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java @@ -0,0 +1,275 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * + * @author mchung + */ +public class ClassPath { + + public class FileInfo { + + File file; + JarFile jarfile; + int classCount; + long filesize; + + FileInfo(File f) throws IOException { + this.file = f; + this.classCount = 0; + if (file.getName().endsWith(".jar")) { + this.filesize = file.length(); + jarfile = new JarFile(f); + } + } + + File getFile() { + return file; + } + + JarFile getJarFile() { + return jarfile; + } + + String getName() throws IOException { + return file.getCanonicalPath(); + } + } + private List fileList = new ArrayList(); + private static ClassPath instance = new ClassPath(); + + static List getFileInfos() { + return instance.fileList; + } + + static ClassPath setJDKHome(String jdkhome) throws IOException { + List files = new ArrayList(); + File jre = new File(jdkhome, "jre"); + File lib = new File(jdkhome, "lib"); + if (jre.exists() && jre.isDirectory()) { + listFiles(new File(jre, "lib"), ".jar", files); + } else if (lib.exists() && lib.isDirectory()) { + // either a JRE or a jdk build image + listFiles(lib, ".jar", files); + + File classes = new File(jdkhome, "classes"); + if (classes.exists() && classes.isDirectory()) { + // jdk build outputdir + instance.add(classes); + } + } else { + throw new RuntimeException("\"" + jdkhome + "\" not a JDK home"); + } + + for (File f : files) { + instance.add(f); + } + return instance; + } + + static ClassPath setClassPath(String path) throws IOException { + if (path.endsWith(".class")) { + // one class file + File f = new File(path); + if (!f.exists()) { + throw new RuntimeException("Classfile \"" + f + "\" doesn't exist"); + } + + instance.add(f); + } else { + List jarFiles = new ArrayList(); + String[] locs = path.split(File.pathSeparator); + for (String p : locs) { + File f = new File(p); + if (!f.exists()) { + throw new RuntimeException("\"" + f + "\" doesn't exist"); + } + + if (f.isDirectory()) { + instance.add(f); // add the directory to look up .class files + listFiles(f, ".jar", jarFiles); + } else if (p.endsWith(".jar")) { + // jar files + jarFiles.add(f); + } else { + throw new RuntimeException("Invalid file \"" + f); + } + } + // add jarFiles if any + for (File f : jarFiles) { + instance.add(f); + } + } + + return instance; + } + + private void add(File f) throws IOException { + fileList.add(new FileInfo(f)); + } + + public static InputStream open(String pathname) throws IOException { + for (FileInfo fi : instance.fileList) { + if (fi.getName().endsWith(".jar")) { + String path = pathname.replace(File.separatorChar, '/'); + JarEntry e = fi.jarfile.getJarEntry(path); + if (e != null) { + return fi.jarfile.getInputStream(e); + } + } else if (fi.getFile().isDirectory()) { + File f = new File(fi.getFile(), pathname); + if (f.exists()) { + return new FileInputStream(f); + } + } else if (fi.file.isFile()) { + if (fi.getName().endsWith(File.separator + pathname)) { + return new FileInputStream(fi.file); + } + } + } + return null; + } + + static ClassFileParser parserForClass(String classname) throws IOException { + String pathname = classname.replace('.', File.separatorChar) + ".class"; + + ClassFileParser cfparser = null; + for (FileInfo fi : instance.fileList) { + if (fi.getName().endsWith(".class")) { + if (fi.getName().endsWith(File.separator + pathname)) { + cfparser = ClassFileParser.newParser(fi.getFile(), true); + break; + } + } else if (fi.getName().endsWith(".jar")) { + JarEntry e = fi.jarfile.getJarEntry(classname.replace('.', '/') + ".class"); + if (e != null) { + cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); + break; + } + } else if (fi.getFile().isDirectory()) { + File f = new File(fi.getFile(), pathname); + if (f.exists()) { + cfparser = ClassFileParser.newParser(f, true); + break; + } + } + } + return cfparser; + } + + public static void parseAllClassFiles() throws IOException { + instance.parseFiles(); + } + + private void parseFiles() throws IOException { + Set classes = new HashSet(); + + int count = 0; + for (FileInfo fi : fileList) { + // filter out public generated classes (i.e. not public API) + // javax.management.remote.rmi._RMIConnectionImpl_Tie + // javax.management.remote.rmi._RMIServerImpl_Tie + if (fi.getName().endsWith(".class")) { + parseClass(fi); + } else if (fi.getName().endsWith(".jar")) { + Enumeration entries = fi.jarfile.entries(); + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + if (e.getName().endsWith(".class")) { + ClassFileParser cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); + cfparser.parseDependency(false); + fi.classCount++; + } else if (!e.isDirectory() && ResourceFile.isResource(e.getName())) { + ResourceFile.addResource(e.getName(), fi.jarfile.getInputStream(e)); + } + } + } else if (fi.getFile().isDirectory()) { + List files = new ArrayList(); + listFiles(fi.getFile(), "", files); + for (File f : files) { + if (f.getName().endsWith(".class")) { + parseClass(fi, f); + } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) { + String pathname = f.getCanonicalPath(); + String dir = fi.getName(); + if (!pathname.startsWith(dir)) { + throw new RuntimeException("Incorrect pathname " + pathname); + } + String name = pathname.substring(dir.length() + 1, pathname.length()); + BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); + try { + ResourceFile.addResource(name, in); + } finally { + in.close(); + } + } + } + } else { + // should not reach here + throw new RuntimeException("Unexpected class path: " + fi.getFile()); + } + } + } + + private void parseClass(FileInfo fi) throws IOException { + parseClass(fi, fi.getFile()); + } + + private void parseClass(FileInfo fi, File f) throws IOException { + ClassFileParser cfparser = ClassFileParser.newParser(f, true); + cfparser.parseDependency(false); + fi.classCount++; + // need to update the filesize for this directory + fi.filesize += fi.getFile().length(); + + } + + public static void listFiles(File path, String suffix, List result) { + if (path.isDirectory()) { + File[] children = path.listFiles(); + for (File c : children) { + listFiles(c, suffix, result); + } + + } else { + if (suffix.isEmpty() || path.getName().endsWith(suffix)) { + result.add(path); + } + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java new file mode 100644 index 00000000000..98ff1a49277 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java @@ -0,0 +1,157 @@ +/* + * 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.classanalyzer; + +import com.sun.classanalyzer.Klass.Method; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Instruction.*; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class CodeAttributeParser { + private final ClassFileParser cfparser; + private final ConstantPool cpool; + private final ConstantPoolParser constantPoolParser; + + + static final Map> runtimeReferences = + new HashMap>(); + + + CodeAttributeParser(ClassFileParser parser) { + this.cfparser = parser; + this.cpool = cfparser.classfile.constant_pool; + this.constantPoolParser = cfparser.constantPoolParser; + } + + static boolean parseCodeAttribute = false; // by default don't parse code attribute + static void setParseCodeAttribute(boolean newValue) { + parseCodeAttribute = newValue; + } + + void parse(Code_attribute attr, Klass.Method method) { + if (!parseCodeAttribute) { + return; + } + + for (Instruction instr : attr.getInstructions()) { + try { + instr.accept(instructionVisitor, method); + } catch (ArrayIndexOutOfBoundsException e) { + throw new RuntimeException("error at or after byte " + instr.getPC()); + } + + } + + if (attr.exception_table_langth > 0) { + for (int i = 0; i < + attr.exception_table.length; i++) { + Code_attribute.Exception_data handler = attr.exception_table[i]; + int catch_type = handler.catch_type; + if (catch_type > 0) { + addMethodReference(catch_type, method); + } + + } + } + + } + + + private void addMethodReference(int index, Klass.Method m) { + String method = constantPoolParser.getMethodName(index); + + if (method != null && + (method.equals("java.lang.Class.forName") || + method.equals("java.lang.Class.loadClass") || + method.startsWith("java.util.ServiceLoader.load") || + method.equals("sun.misc.Service.providers"))) { + Set refs = runtimeReferences.get(method); + if (refs == null) { + refs = new TreeSet(); + runtimeReferences.put(method, refs); + } + refs.add(m); + } + } + + Instruction.KindVisitor instructionVisitor = + new Instruction.KindVisitor() { + + public Void visitNoOperands(Instruction instr, Klass.Method m) { + return null; + } + + public Void visitArrayType(Instruction instr, TypeKind kind, Klass.Method m) { + return null; + } + + public Void visitBranch(Instruction instr, int offset, Klass.Method m) { + return null; + } + + public Void visitConstantPoolRef(Instruction instr, int index, Klass.Method m) { + addMethodReference(index, m); + return null; + } + + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Klass.Method m) { + addMethodReference(index, m); + return null; + } + + public Void visitLocal(Instruction instr, int index, Klass.Method m) { + return null; + } + + public Void visitLocalAndValue(Instruction instr, int index, int value, Klass.Method m) { + return null; + } + + public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitValue(Instruction instr, int value, Klass.Method m) { + return null; + } + + public Void visitUnknown(Instruction instr, Klass.Method m) { + return null; + } + }; +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.java new file mode 100644 index 00000000000..f79f2bf6c36 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.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.classanalyzer; + +/** + * + * @author Mandy Chung + */ +public class ConstantPoolAnalyzer { + public static void main(String[] args) throws Exception { + String jdkhome = null; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } + } + if (jdkhome == null) { + usage(); + } + ClassPath.setJDKHome(jdkhome); + ClassPath.parseAllClassFiles(); + } + + private static void usage() { + System.out.println("Usage: ConstantPoolAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-cpath where classes and jars will be parsed"); + System.exit(-1); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java new file mode 100644 index 00000000000..33e593df875 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java @@ -0,0 +1,377 @@ +/* + * 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.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; +import static com.sun.tools.classfile.ConstantPool.*; + +/** + * + * @author Mandy Chung + */ +public class ConstantPoolParser { + + private final ClassFileParser cfparser; + private final StringValueVisitor visitor; + private final ConstantPool cpool; + + ConstantPoolParser(ClassFileParser parser) { + this.cfparser = parser; + this.cpool = cfparser.classfile.constant_pool; + this.visitor = new StringValueVisitor(); + } + + public String stringValue(CPInfo cpInfo) { + return visitor.visit(cpInfo); + } + + public String stringValue(int constant_pool_index) { + try { + return stringValue(cpool.get(constant_pool_index)); + } catch (ConstantPool.InvalidIndex e) { + throw new RuntimeException(e); + } + } + + public void parseDependency() { + ConstantPool.Visitor v = new ConstantPool.Visitor() { + + public Integer visitClass(CONSTANT_Class_info info, Void p) { + try { + String classname = cfparser.checkClassName(info.getName()); + if (classname.isEmpty()) { + return 1; + } + + Klass from = cfparser.this_klass; + Klass to = Klass.getKlass(classname); + ResolutionInfo resInfo = ResolutionInfo.resolvedConstantPool(from, to, info.name_index); + + from.addDep(to, resInfo); + to.addReferrer(from, resInfo); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + return 1; + } + + public Integer visitDouble(CONSTANT_Double_info info, Void p) { + // skip + return 2; + } + + public Integer visitFieldref(CONSTANT_Fieldref_info info, Void p) { + // skip + return 1; + } + + public Integer visitFloat(CONSTANT_Float_info info, Void p) { + // skip + return 1; + } + + public Integer visitInteger(CONSTANT_Integer_info info, Void p) { + // skip + return 1; + } + + public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + // skip + return 1; + } + + public Integer visitLong(CONSTANT_Long_info info, Void p) { + // skip + return 2; + } + + public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + // skip + return 1; + } + + public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) { + // skip + return 1; + } + + public Integer visitString(CONSTANT_String_info info, Void p) { + // skip + return 1; + } + + public Integer visitUtf8(CONSTANT_Utf8_info info, Void p) { + // skip + return 1; + } + }; + int cpx = 1; + while (cpx < cpool.size()) { + try { + CPInfo cpInfo = cpool.get(cpx); + cpx += cpInfo.accept(v, null); + } catch (ConstantPool.InvalidIndex ex) { + throw new RuntimeException(ex); + } + } + } + + int getTag(int index) { + try { + return cpool.get(index).getTag(); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + String getDescriptor(int index) { + CPInfo cpInfo; + try { + cpInfo = cpool.get(index); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + + int tag = cpInfo.getTag(); + switch (tag) { + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Fieldref: + // simplify references within this class + CPRefInfo ref = (CPRefInfo) cpInfo; + try { + return ref.getNameAndTypeInfo().getType(); + } catch (ConstantPoolException ex) { + } + } + return stringValue(cpInfo); + } + + String getMethodName(int index) { + try { + CPInfo cpInfo = cpool.get(index); + if (cpInfo.getTag() == CONSTANT_Methodref || + cpInfo.getTag() == CONSTANT_InterfaceMethodref) { + + // simplify references within this class + CPRefInfo ref = (CPRefInfo) cpInfo; + String classname; + if (ref.class_index == cfparser.classfile.this_class) { + classname = cfparser.this_klass.getClassName(); + } else { + classname = cfparser.checkClassName(ref.getClassName()).replace('/', '.'); + } + String methodname = ref.getNameAndTypeInfo().getName(); + return classname + "." + methodname; + } else { + return null; + } + } catch (InvalidIndex ex) { + throw new RuntimeException(ex); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + + } + + class StringValueVisitor implements ConstantPool.Visitor { + + public StringValueVisitor() { + } + + public String visit(CPInfo info) { + return info.accept(this, null); + } + + public String visitClass(CONSTANT_Class_info info, Void p) { + return getCheckedName(info); + } + + String getCheckedName(CONSTANT_Class_info info) { + try { + return checkName(info.getName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitDouble(CONSTANT_Double_info info, Void p) { + return info.value + "d"; + } + + public String visitFieldref(CONSTANT_Fieldref_info info, Void p) { + return visitRef(info, p); + } + + public String visitFloat(CONSTANT_Float_info info, Void p) { + return info.value + "f"; + } + + public String visitInteger(CONSTANT_Integer_info info, Void p) { + return String.valueOf(info.value); + } + + public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return visitRef(info, p); + } + + public String visitLong(CONSTANT_Long_info info, Void p) { + return info.value + "l"; + } + + public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + return getCheckedName(info) + ":" + getType(info); + } + + String getCheckedName(CONSTANT_NameAndType_info info) { + try { + return checkName(info.getName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + String getType(CONSTANT_NameAndType_info info) { + try { + return info.getType(); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitMethodref(CONSTANT_Methodref_info info, Void p) { + return visitRef(info, p); + } + + public String visitString(CONSTANT_String_info info, Void p) { + try { + int string_index = info.string_index; + return cpool.getUTF8Info(string_index).accept(this, p); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitUtf8(CONSTANT_Utf8_info info, Void p) { + String s = info.value; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '\t': + sb.append('\\').append('t'); + break; + case '\n': + sb.append('\\').append('n'); + break; + case '\r': + sb.append('\\').append('r'); + break; + case '\"': + sb.append('\\').append('\"'); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + + String visitRef(CPRefInfo info, Void p) { + String cn = getCheckedClassName(info); + String nat; + try { + nat = info.getNameAndTypeInfo().accept(this, p); + } catch (ConstantPoolException e) { + nat = e.getMessage(); + } + return cn + "." + nat; + } + + String getCheckedClassName(CPRefInfo info) { + try { + return checkName(info.getClassName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + } + /* If name is a valid binary name, return it; otherwise quote it. */ + + private static String checkName(String name) { + if (name == null) { + return "null"; + } + + int len = name.length(); + if (len == 0) { + return "\"\""; + } + + int cc = '/'; + int cp; + for (int k = 0; k < len; k += Character.charCount(cp)) { + cp = name.codePointAt(k); + if ((cc == '/' && !Character.isJavaIdentifierStart(cp)) || (cp != '/' && !Character.isJavaIdentifierPart(cp))) { + return "\"" + name + "\""; + } + cc = cp; + } + return name; + } + + String tagName(int index) { + try { + int tag = cpool.get(index).getTag(); + switch (tag) { + case CONSTANT_Utf8: + return "Utf8"; + case CONSTANT_Integer: + return "int"; + case CONSTANT_Float: + return "float"; + case CONSTANT_Long: + return "long"; + case CONSTANT_Double: + return "double"; + case CONSTANT_Class: + return "class"; + case CONSTANT_String: + return "String"; + case CONSTANT_Fieldref: + return "Field"; + case CONSTANT_Methodref: + return "Method"; + case CONSTANT_InterfaceMethodref: + return "InterfaceMethod"; + case CONSTANT_NameAndType: + return "NameAndType"; + default: + return "(unknown tag)"; + } + } catch (InvalidIndex e) { + throw new RuntimeException(e); + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java new file mode 100644 index 00000000000..107e1d10c85 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java @@ -0,0 +1,99 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +/** + * Config file specifying additional dependency + * Each line consists of: + * -> + * where can be: + * @ClassForName and is its dependency + * @Provider and is the service name + * @Providers and is the list of the service names + * + * @author Mandy Chung + */ +public class DependencyConfig { + private DependencyConfig() { + } + + static void parse(List configs) throws IOException { + for (String s : configs) { + parse(s); + } + } + + private static void parse(String config) throws IOException { + // parse configuration file + FileInputStream in = new FileInputStream(config); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + int lineNumber = 0; + String type = null; + while ((line = reader.readLine()) != null) { + lineNumber++; + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + if (line.charAt(0) == '@') { + if (AnnotatedDependency.isValidType(line)) { + type = line; + continue; + } else { + throw new RuntimeException(config + ", line " + + lineNumber + ", invalid annotation type."); + } + } + String[] s = line.split("\\s+"); + if (s.length < 3 || !s[1].equals("->")) { + throw new RuntimeException(config + ", line " + + lineNumber + ", is malformed"); + } + String classname = s[0].trim(); + String value = s[2].trim(); + + Klass k = Klass.findKlass(classname); + if (k == null) { + // System.out.println("Warning: " + classname + " cannot be found"); + continue; + } + AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, value, k); + if (dep == null) { + throw new RuntimeException(config + ", line " + + lineNumber + ", is malformed. Fail to construct the dependency."); + } + } + + } finally { + in.close(); + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/Klass.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/Klass.java new file mode 100644 index 00000000000..a4d2eb27775 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/Klass.java @@ -0,0 +1,357 @@ +/* + * 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.classanalyzer; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; + +import com.sun.tools.classfile.AccessFlags; + +/** + * + * @author Mandy Chung + */ +public class Klass implements Comparable { + private final String classname; + private final String packagename; + private Module module; + private boolean isJavaLangObject; + private String[] paths; + private Map> methods; + private AccessFlags accessFlags; + private long filesize; + + private SortedMap> deps; + private SortedMap> referrers; + private List annotatedDeps; + private Set classForNameRefs; + + private Klass(String classname) { + this.classname = classname; + this.paths = classname.replace('.', '/').split("/"); + this.isJavaLangObject = classname.equals("java.lang.Object"); + this.deps = new TreeMap>(); + this.referrers = new TreeMap>(); + this.methods = new HashMap>(); + this.annotatedDeps = new ArrayList(); + this.classForNameRefs = new TreeSet(); + + int pos = classname.lastIndexOf('.'); + this.packagename = (pos > 0) ? classname.substring(0, pos) : ""; + } + + String getBasename() { + return paths[paths.length - 1]; + } + + String getClassName() { + return classname; + } + + String getPackageName() { + return packagename; + } + + String getClassFilePathname() { + StringBuilder sb = new StringBuilder(paths[0]); + for (int i = 1; i < paths.length; i++) { + String p = paths[i]; + sb.append(File.separator).append(p); + } + return sb.append(".class").toString(); + } + + boolean isPublic() { + return accessFlags == null || accessFlags.is(AccessFlags.ACC_PUBLIC); + } + + Module getModule() { + return module; + } + + void setModule(Module m) { + if (module != null) { + throw new RuntimeException("Module for " + this + " already set"); + } + this.module = m; + } + + Set getReferencedClasses() { + return deps.keySet(); + } + + Set getReferencingClasses() { + return referrers.keySet(); + } + + void setAccessFlags(int flags) { + this.accessFlags = new AccessFlags(flags); + } + + void setFileSize(long size) { + this.filesize = size; + } + + long getFileSize() { + return this.filesize; + } + + boolean exists() { + return filesize > 0; + } + + boolean skip(Klass k) { + // skip if either class is a root or same class + return k.isJavaLangObject || this == k || k.classname.equals(classname); + } + + void addDep(Method callee, ResolutionInfo resInfo) { + addDep(callee.getKlass(), resInfo); + } + + void addDep(Klass ref, ResolutionInfo ri) { + if (skip(ref)) { + return; + } + Set resInfos; + if (!deps.containsKey(ref)) { + resInfos = new TreeSet(); + deps.put(ref, resInfos); + } else { + resInfos = deps.get(ref); + } + resInfos.add(ri); + } + + void addReferrer(Method caller, ResolutionInfo resInfo) { + addReferrer(caller.getKlass(), resInfo); + } + + void addReferrer(Klass k, ResolutionInfo ri) { + if (skip(k)) { + return; + } + Set resInfos; + if (!referrers.containsKey(k)) { + resInfos = new TreeSet(); + referrers.put(k, resInfos); + } else { + resInfos = referrers.get(k); + } + resInfos.add(ri); + } + + Method getMethod(String name) { + return getMethod(name, ""); + } + + Method getMethod(String name, String signature) { + Set set; + if (methods.containsKey(name)) { + set = methods.get(name); + } else { + set = new TreeSet(); + methods.put(name, set); + } + + for (Method m : set) { + if (m.getName().equals(name) && m.getSignature().equals(signature)) { + return m; + } + } + Method m = new Method(this, name, signature); + set.add(m); + return m; + } + + @Override + public String toString() { + return classname; + } + + @Override + public int compareTo(Klass o) { + return classname.compareTo(o.classname); + } + + void addAnnotatedDep(AnnotatedDependency dep) { + annotatedDeps.add(dep); + } + + void addClassForNameReference(String method) { + classForNameRefs.add(method); + } + + List getAnnotatedDeps() { + return annotatedDeps; + } + + private static Map classes = new TreeMap(); + static Set getAllClasses() { + return new TreeSet(classes.values()); + } + + static Klass findKlassFromPathname(String filename) { + String name = filename; + if (filename.endsWith(".class")) { + name = filename.substring(0, filename.length() - 6); + } + + // trim ".class" + name = name.replace('/', '.'); + for (Klass k : classes.values()) { + if (name.endsWith(k.getClassName())) { + return k; + } + } + return null; + } + + static Klass findKlass(String classname) { + return classes.get(classname); + } + + static Klass getKlass(String name) { + Klass k; + String classname = name.replace('/', '.'); + if (classname.charAt(classname.length() - 1) == ';') { + classname = classname.substring(0, classname.length() - 1); + } + if (classes.containsKey(classname)) { + k = classes.get(classname); + } else { + k = new Klass(classname); + classes.put(classname, k); + } + return k; + } + + public class Method implements Comparable { + + private final Klass k; + private final String method; + private final String signature; + private long codeLength; + // non-primitive types only + private final List argTypes; + private final Klass returnType; + boolean isAbstract = false; + boolean marked = false; + + public Method(Klass k, String method, String signature) { + this(k, method, signature, null, null); + } + + public Method(Klass k, String method, String signature, Klass returnType, List argTypes) { + this.k = k; + this.method = method; + this.signature = signature; + this.argTypes = argTypes; + this.returnType = returnType; + this.codeLength = 0; + } + + public Klass getKlass() { + return k; + } + + public String getName() { + return method; + } + + public String getSignature() { + return signature; + } + + public Klass getReturnType() { + return returnType; + } + + public List argTypes() { + return argTypes; + } + + public void setCodeLength(long len) { + this.codeLength = len; + } + + public long getCodeLength() { + return codeLength; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Method) { + return compareTo((Method) o) == 0; + } else { + return false; + } + } + + @Override + public int hashCode() { + int hash = 3; + hash = 71 * hash + (this.k != null ? this.k.hashCode() : 0); + hash = 71 * hash + (this.method != null ? this.method.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + if (signature.isEmpty()) { + return k.classname + "." + method; + } else { + return signature; + } + } + + public String toHtmlString() { + return toString().replace("<", "<").replace(">", ">"); + } + + boolean isClinit() { + return method.equals(""); + } + + public int compareTo(Method m) { + if (k == m.getKlass()) { + if (method.equals(m.method)) { + return signature.compareTo(m.signature); + } else { + return method.compareTo(m.method); + } + } else { + return k.compareTo(m.getKlass()); + } + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/Module.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/Module.java new file mode 100644 index 00000000000..0fdc5b145fa --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/Module.java @@ -0,0 +1,693 @@ +/* + * 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.classanalyzer; + +import com.sun.classanalyzer.AnnotatedDependency.OptionalDependency; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class Module implements Comparable { + + private static Map modules = new LinkedHashMap(); + + public static Module addModule(ModuleConfig config) { + String name = config.module; + if (modules.containsKey(name)) { + throw new RuntimeException("module \"" + name + "\" already exists"); + } + + Module m = new Module(config); + modules.put(name, m); + return m; + } + + public static Module findModule(String name) { + return modules.get(name); + } + + static Collection getAllModules() { + return Collections.unmodifiableCollection(modules.values()); + } + private final String name; + private final ModuleConfig config; + private final Set classes; + private final Set resources; + private final Set unresolved; + private final Set dependents; + private final Map packages; + private final Set members; + private Module group; + private boolean isBaseModule; + + private Module(ModuleConfig config) { + this.name = config.module; + this.isBaseModule = config.isBase; + this.classes = new TreeSet(); + this.resources = new TreeSet(); + this.config = config; + this.unresolved = new HashSet(); + this.dependents = new TreeSet(); + this.packages = new TreeMap(); + this.members = new TreeSet(); + this.group = this; // initialize to itself + } + + String name() { + return name; + } + + Module group() { + return group; + } + + boolean isBase() { + return isBaseModule; + } + + Set members() { + return members; + } + + boolean contains(Klass k) { + return k != null && classes.contains(k); + } + + boolean isEmpty() { + return classes.isEmpty() && resources.isEmpty(); + } + + /** + * Returns an Iterable of Dependency, only one for each dependent + * module of the strongest dependency (i.e. + * hard static > hard dynamic > optional static > optional dynamic + */ + Iterable dependents() { + Map deps = new LinkedHashMap(); + for (Dependency dep : dependents) { + Dependency d = deps.get(dep.module); + if (d == null || dep.compareTo(d) > 0) { + deps.put(dep.module, dep); + } + } + return deps.values(); + } + + @Override + public int compareTo(Module o) { + if (o == null) { + return -1; + } + return name.compareTo(o.name); + } + + @Override + public String toString() { + return name; + } + + void addKlass(Klass k) { + classes.add(k); + k.setModule(this); + + // update package statistics + String pkg = k.getPackageName(); + PackageInfo pkginfo = packages.get(pkg); + if (pkginfo == null) { + pkginfo = new PackageInfo(pkg); + packages.put(pkg, pkginfo); + } + if (k.exists()) { + // only count the class that is parsed + pkginfo.add(k.getFileSize()); + } + } + + void addResource(ResourceFile res) { + resources.add(res); + res.setModule(this); + } + + void processRootsAndReferences() { + // start with the root set + Deque pending = new ArrayDeque(); + for (Klass k : Klass.getAllClasses()) { + if (k.getModule() != null) { + continue; + } + String classname = k.getClassName(); + if (config.matchesRoot(classname) && !config.isExcluded(classname)) { + addKlass(k); + pending.add(k); + } + } + + // follow all references + Klass k; + while ((k = pending.poll()) != null) { + if (!classes.contains(k)) { + addKlass(k); + } + for (Klass other : k.getReferencedClasses()) { + Module otherModule = other.getModule(); + if (otherModule != null && otherModule != this) { + // this module is dependent on otherModule + addDependency(k, other); + continue; + } + + if (!classes.contains(other)) { + if (config.isExcluded(other.getClassName())) { + // reference to an excluded class + unresolved.add(new Reference(k, other)); + } else { + pending.add(other); + } + } + } + } + + // add other matching classes that don't require dependency analysis + for (Klass c : Klass.getAllClasses()) { + if (c.getModule() == null) { + String classname = c.getClassName(); + if (config.matchesIncludes(classname) && !config.isExcluded(classname)) { + addKlass(c); + // dependencies + for (Klass other : c.getReferencedClasses()) { + Module otherModule = other.getModule(); + if (otherModule == null) { + unresolved.add(new Reference(c, other)); + } else { + if (otherModule != this) { + // this module is dependent on otherModule + addDependency(c, other); + } + } + } + } + } + } + + + // add other matching classes that don't require dependency analysis + for (ResourceFile res : ResourceFile.getAllResources()) { + if (res.getModule() == null) { + String name = res.getName(); + if (config.matchesIncludes(name) && !config.isExcluded(name)) { + addResource(res); + } + } + } + } + + void addDependency(Klass from, Klass to) { + Dependency dep = new Dependency(from, to); + dependents.add(dep); + } + + void fixupDependencies() { + // update dependencies for classes that were allocated to modules after + // this module was processed. + for (Reference ref : unresolved) { + Module m = ref.referree().getModule(); + if (m == null || m != this) { + addDependency(ref.referrer, ref.referree); + } + } + + fixupAnnotatedDependencies(); + } + + private void fixupAnnotatedDependencies() { + // add dependencies that this klass may depend on due to the AnnotatedDependency + dependents.addAll(AnnotatedDependency.getDependencies(this)); + } + + boolean isModuleDependence(Klass k) { + Module m = k.getModule(); + return m == null || (!classes.contains(k) && !m.isBase()); + } + + Module getModuleDependence(Klass k) { + if (isModuleDependence(k)) { + Module m = k.getModule(); + if (group == this && m != null) { + // top-level module + return m.group; + } else { + return m; + } + } + return null; + } + +

void visit(Set visited, Visitor

visitor, P p) { + if (!visited.contains(this)) { + visited.add(this); + visitor.preVisit(this, p); + for (Module m : members) { + m.visit(visited, visitor, p); + visitor.postVisit(this, m, p); + } + } else { + throw new RuntimeException("Cycle detected: module " + this.name); + } + } + + void addMember(Module m) { + // merge class list + for (Klass k : m.classes) { + classes.add(k); + } + + // merge resource list + for (ResourceFile res : m.resources) { + resources.add(res); + } + + // merge the package statistics + for (PackageInfo pinfo : m.getPackageInfos()) { + String packageName = pinfo.pkgName; + PackageInfo pkginfo = packages.get(packageName); + if (pkginfo == null) { + pkginfo = new PackageInfo(packageName); + packages.put(packageName, pkginfo); + } + pkginfo.add(pinfo); + } + } + + static void buildModuleMembers() { + // set up module member relationship + for (Module m : modules.values()) { + m.group = m; // initialize to itself + for (String name : m.config.members()) { + Module member = modules.get(name); + if (member == null) { + throw new RuntimeException("module \"" + name + "\" doesn't exist"); + } + m.members.add(member); + } + } + + // set up the top-level module + Visitor groupSetter = new Visitor() { + + public void preVisit(Module m, Module p) { + m.group = p; + if (p.isBaseModule) { + // all members are also base + m.isBaseModule = true; + } + } + + public void postVisit(Module m, Module child, Module p) { + // nop - breadth-first search + } + }; + + // propagate the top-level module to all its members + for (Module p : modules.values()) { + for (Module m : p.members) { + if (m.group == m) { + m.visit(new TreeSet(), groupSetter, p); + } + } + } + + Visitor mergeClassList = new Visitor() { + + public void preVisit(Module m, Module p) { + // nop - depth-first search + } + + public void postVisit(Module m, Module child, Module p) { + m.addMember(child); + } + }; + + Set visited = new TreeSet(); + for (Module m : modules.values()) { + if (m.group() == m) { + if (m.members().size() > 0) { + // merge class list from all its members + m.visit(visited, mergeClassList, m); + } + + // clear the dependencies before fixup + m.dependents.clear(); + + // fixup dependencies + for (Klass k : m.classes) { + for (Klass other : k.getReferencedClasses()) { + if (m.isModuleDependence(other)) { + // this module is dependent on otherModule + m.addDependency(k, other); + } + } + } + + // add dependencies that this klass may depend on due to the AnnotatedDependency + m.fixupAnnotatedDependencies(); + } + } + } + + class PackageInfo implements Comparable { + + final String pkgName; + int count; + long filesize; + + PackageInfo(String name) { + this.pkgName = name; + this.count = 0; + this.filesize = 0; + } + + void add(PackageInfo pkg) { + this.count += pkg.count; + this.filesize += pkg.filesize; + } + + void add(long size) { + count++; + filesize += size; + + } + + @Override + public int compareTo(Object o) { + return pkgName.compareTo(((PackageInfo) o).pkgName); + } + } + + Set getPackageInfos() { + return new TreeSet(packages.values()); + } + + void printSummaryTo(String output) throws IOException { + PrintWriter writer = new PrintWriter(output); + try { + long total = 0L; + int count = 0; + writer.format("%10s\t%10s\t%s\n", "Bytes", "Classes", "Package name"); + for (String pkg : packages.keySet()) { + PackageInfo info = packages.get(pkg); + if (info.count > 0) { + writer.format("%10d\t%10d\t%s\n", info.filesize, info.count, pkg); + total += info.filesize; + count += info.count; + } + } + + writer.format("\nTotal: %d bytes (uncompressed) %d classes\n", total, count); + } finally { + writer.close(); + } + + } + + void printClassListTo(String output) throws IOException { + // no file created if the module doesn't have any class nor resource + if (isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + for (Klass c : classes) { + if (c.exists()) { + writer.format("%s\n", c.getClassFilePathname()); + } else { + trace("%s in module %s missing\n", c, this); + } + } + + } finally { + writer.close(); + } + } + + void printResourceListTo(String output) throws IOException { + // no file created if the module doesn't have any resource file + if (resources.isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + for (ResourceFile res : resources) { + writer.format("%s\n", res.getPathname()); + } + } finally { + writer.close(); + } + } + + void printDependenciesTo(String output, boolean showDynamic) throws IOException { + // no file created if the module doesn't have any class + if (isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + // classes that this klass may depend on due to the AnnotatedDependency + Map> annotatedDeps = AnnotatedDependency.getReferences(this); + + for (Klass klass : classes) { + Set references = klass.getReferencedClasses(); + for (Klass other : references) { + String classname = klass.getClassName(); + boolean optional = OptionalDependency.isOptional(klass, other); + if (optional) { + classname = "[optional] " + classname; + } + + Module m = getModuleDependence(other); + if (m != null || other.getModule() == null) { + writer.format("%-40s -> %s (%s)", classname, other, m); + Reference ref = new Reference(klass, other); + if (annotatedDeps.containsKey(ref)) { + for (AnnotatedDependency ad : annotatedDeps.get(ref)) { + writer.format(" %s", ad.getTag()); + } + // printed; so remove the dependency from the annotated deps list + annotatedDeps.remove(ref); + } + writer.format("\n"); + } + } + } + + + // print remaining dependencies specified in AnnotatedDependency list + if (annotatedDeps.size() > 0) { + for (Map.Entry> entry : annotatedDeps.entrySet()) { + Reference ref = entry.getKey(); + Module m = getModuleDependence(ref.referree); + if (m != null || ref.referree.getModule() == null) { + String classname = ref.referrer.getClassName(); + boolean optional = true; + boolean dynamic = true; + String tag = ""; + for (AnnotatedDependency ad : entry.getValue()) { + if (optional && !ad.isOptional()) { + optional = false; + tag = ad.getTag(); + } + if (!ad.isDynamic()) { + dynamic = false; + } + } + if (!showDynamic && optional && dynamic) { + continue; + } + if (optional) { + if (dynamic) { + classname = "[dynamic] " + classname; + } else { + classname = "[optional] " + classname; + } + } + writer.format("%-40s -> %s (%s) %s%n", classname, ref.referree, m, tag); + } + } + } + + } finally { + writer.close(); + } + } + + static class Dependency implements Comparable { + + final Module module; + final boolean optional; + final boolean dynamic; + + Dependency(Klass from, Klass to) { + // static dependency + this.module = to.getModule() != null ? to.getModule().group() : null; + this.optional = OptionalDependency.isOptional(from, to); + this.dynamic = false; + } + + Dependency(Module m, boolean optional, boolean dynamic) { + this.module = m != null ? m.group() : null; + this.optional = optional; + this.dynamic = dynamic; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Dependency)) { + return false; + } + if (this == obj) { + return true; + } + + Dependency d = (Dependency) obj; + if (this.module != d.module) { + return false; + } else { + return this.optional == d.optional && this.dynamic == d.dynamic; + } + } + + @Override + public int hashCode() { + int hash = 3; + hash = 19 * hash + (this.module != null ? this.module.hashCode() : 0); + hash = 19 * hash + (this.optional ? 1 : 0); + hash = 19 * hash + (this.dynamic ? 1 : 0); + return hash; + } + + @Override + public int compareTo(Dependency d) { + if (this.equals(d)) { + return 0; + } + + // Hard static > hard dynamic > optional static > optional dynamic + if (this.module == d.module) { + if (this.optional == d.optional) { + return this.dynamic ? -1 : 1; + } else { + return this.optional ? -1 : 1; + } + } else if (this.module != null && d.module != null) { + return (this.module.compareTo(d.module)); + } else { + return (this.module == null) ? -1 : 1; + } + } + + @Override + public String toString() { + String s = module.name(); + if (dynamic && optional) { + s += " (dynamic)"; + } else if (optional) { + s += " (optional)"; + } + return s; + } + } + + static class Reference implements Comparable { + + private final Klass referrer, referree; + + Reference(Klass referrer, Klass referree) { + this.referrer = referrer; + this.referree = referree; + } + + Klass referrer() { + return referrer; + } + + Klass referree() { + return referree; + } + + @Override + public int hashCode() { + return referrer.hashCode() ^ referree.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Reference)) { + return false; + } + if (this == obj) { + return true; + } + + Reference r = (Reference) obj; + return (this.referrer.equals(r.referrer) && + this.referree.equals(r.referree)); + } + + @Override + public int compareTo(Reference r) { + int ret = referrer.compareTo(r.referrer); + if (ret == 0) { + ret = referree.compareTo(r.referree); + } + return ret; + } + } + + interface Visitor

{ + + public void preVisit(Module m, P param); + + public void postVisit(Module m, Module child, P param); + } + private static boolean traceOn = System.getProperty("classanalyzer.debug") != null; + + private static void trace(String format, Object... params) { + System.err.format(format, params); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java new file mode 100644 index 00000000000..d5ead840e01 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java @@ -0,0 +1,562 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +/** + * + * @author Mandy Chung + */ +public class ModuleConfig { + + private static String baseModuleName = "base"; + private final Set roots; + private final Set includes; + private final Filter filter; + private List members; + final String module; + final boolean isBase; + + private ModuleConfig(String name) throws IOException { + this.roots = new TreeSet(); + this.includes = new TreeSet(); + this.module = name; + this.isBase = name.equals(baseModuleName); + this.filter = new Filter(this); + } + + List members() { + if (members == null) { + members = new LinkedList(); + + for (String s : includes) { + if (!s.contains("*") && Module.findModule(s) != null) { + // module member + members.add(s); + } + } + } + return members; + } + + boolean matchesRoot(String name) { + for (String pattern : roots) { + if (matches(name, pattern)) { + return true; + } + } + return false; + } + + boolean matchesIncludes(String name) { + for (String pattern : includes) { + if (matches(name, pattern)) { + return true; + } + } + return false; + } + + boolean isExcluded(String name) { + return filter.isExcluded(name); + } + + boolean matchesPackage(String packageName, String pattern) { + int pos = pattern.lastIndexOf('.'); + String pkg = pos > 0 ? pattern.substring(0, pos) : ""; + return packageName.equals(pkg); + } + + + boolean matches(String name, String pattern) { + if (pattern.contains("**") && !pattern.endsWith("**")) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + String javaName = name; + + boolean isResourceFile = name.indexOf('/') >= 0; + if (isResourceFile) { + // it's a resource file; convert the name as a java + javaName = name.replace('/', '.'); + } + if (pattern.indexOf('/') < 0) { + // if the pattern doesn't contain '/ + return matchesJavaName(javaName, pattern); + } else { + if (isResourceFile) { + // the pattern is for matching resource file + return matchesNameWithSlash(name, pattern); + } else { + return false; + } + } + } + + boolean matchesJavaName(String name, String pattern) { + int pos = name.lastIndexOf('.'); + String packageName = pos > 0 ? name.substring(0, pos) : ""; + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return name.startsWith(p); + } else if (pattern.endsWith("*") && pattern.indexOf('*') == pattern.lastIndexOf('*')) { + if (matchesPackage(packageName, pattern)) { + // package name has to be exact match + String p = pattern.substring(0, pattern.length() - 1); + return name.startsWith(p); + } else { + return false; + } + } else if (pattern.contains("*")) { + String basename = pos > 0 ? name.substring(pos + 1, name.length()) : name; + pos = pattern.indexOf('*'); + String prefix = pattern.substring(0, pos); + String suffix = pattern.substring(pos + 1, pattern.length()); + if (name.startsWith(prefix) && matchesPackage(packageName, prefix)) { + // package name has to be exact match + if (suffix.contains("*")) { + return name.matches(convertToRegex(pattern)); + } else { + return basename.endsWith(suffix); + } + } else { + // we don't support wildcard be used in the package name + return false; + } + } else { + // exact match or inner class + return name.equals(pattern) || name.startsWith(pattern + "$"); + } + } + + boolean matchesNameWithSlash(String name, String pattern) { + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return name.startsWith(p); + } else if (pattern.contains("*")) { + int pos = pattern.indexOf('*'); + String prefix = pattern.substring(0, pos); + String suffix = pattern.substring(pos + 1, pattern.length()); + String tail = name.substring(pos, name.length()); + + if (!name.startsWith(prefix)) { + // prefix has to exact match + return false; + } + + if (pattern.indexOf('*') == pattern.lastIndexOf('*')) { + // exact match prefix with no '/' in the tail string + String wildcard = tail.substring(0, tail.length() - suffix.length()); + return tail.indexOf('/') < 0 && tail.endsWith(suffix); + } + + if (suffix.contains("*")) { + return matchesNameWithSlash(tail, suffix); + } else { + // tail ends with the suffix while no '/' in the wildcard matched string + String any = tail.substring(0, tail.length() - suffix.length()); + return tail.endsWith(suffix) && any.indexOf('/') < 0; + } + } else { + // exact match + return name.equals(pattern); + } + } + + private String convertToRegex(String pattern) { + StringBuilder sb = new StringBuilder(); + int i = 0; + int index = 0; + int plen = pattern.length(); + while (i < plen) { + char p = pattern.charAt(i); + if (p == '*') { + sb.append("(").append(pattern.substring(index, i)).append(")"); + if (i + 1 < plen && pattern.charAt(i + 1) == '*') { + sb.append(".*"); + index = i + 2; + } else { + sb.append("[^\\.]*"); + index = i + 1; + } + } + i++; + } + if (index < plen) { + sb.append("(").append(pattern.substring(index, plen)).append(")"); + } + return sb.toString(); + } + + static class Filter { + + final ModuleConfig config; + final Set exclude = new TreeSet(); + final Set allow = new TreeSet(); + + Filter(ModuleConfig config) { + this.config = config; + } + + Filter exclude(String pattern) { + exclude.add(pattern); + return this; + } + + Filter allow(String pattern) { + allow.add(pattern); + return this; + } + + String allowedBy(String name) { + String allowedBy = null; + for (String pattern : allow) { + if (config.matches(name, pattern)) { + if (name.equals(pattern)) { + return pattern; // exact match + } + if (allowedBy == null) { + allowedBy = pattern; + } else { + if (pattern.length() > allowedBy.length()) { + allowedBy = pattern; + } + } + } + } + return allowedBy; + } + + String excludedBy(String name) { + String allowedBy = allowedBy(name); + String excludedBy = null; + + if (allowedBy != null && name.equals(allowedBy)) { + return null; // exact match + } + for (String pattern : exclude) { + if (config.matches(name, pattern)) { + // not matched by allowed rule or exact match + if (allowedBy == null || name.equals(pattern)) { + return pattern; + } + if (excludedBy == null) { + excludedBy = pattern; + } else { + if (pattern.length() > excludedBy.length()) { + excludedBy = pattern; + } + } + } + } + return excludedBy; + } + + boolean isExcluded(String name) { + String allowedBy = allowedBy(name); + String excludedBy = excludedBy(name); + + if (excludedBy == null) { + return false; + } + // not matched by allowed rule or exact match + if (allowedBy == null || name.equals(excludedBy)) { + return true; + } + + if (allowedBy == null) { + return true; + } + if (allowedBy != null && + excludedBy.length() > allowedBy.length()) { + return true; + } + return false; + } + } + + private static String trimComment(String line) { + StringBuilder sb = new StringBuilder(); + + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c1 = line.indexOf("//", pos); + if (c1 > 0 && !Character.isWhitespace(line.charAt(c1-1))) { + // not a comment + c1 = -1; + } + + int c2 = line.indexOf("/*", pos); + if (c2 > 0 && !Character.isWhitespace(line.charAt(c2-1))) { + // not a comment + c2 = -1; + } + + int c = line.length(); + int n = line.length(); + if (c1 >= 0 || c2 >= 0) { + if (c1 >= 0) { + c = c1; + } + if (c2 >= 0 && c2 < c) { + c = c2; + } + int c3 = line.indexOf("*/", c2 + 2); + if (c == c2 && c3 > c2) { + n = c3 + 2; + } + } + if (c > 0) { + if (sb.length() > 0) { + // add a whitespace if multiple comments on one line + sb.append(" "); + } + sb.append(line.substring(pos, c)); + } + pos = n; + } + return sb.toString(); + } + + private static boolean beginBlockComment(String line) { + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c = line.indexOf("/*", pos); + if (c < 0) { + return false; + } + + if (c > 0 && !Character.isWhitespace(line.charAt(c-1))) { + return false; + } + + int c1 = line.indexOf("//", pos); + if (c1 >= 0 && c1 < c) { + return false; + } + + int c2 = line.indexOf("*/", c + 2); + if (c2 < 0) { + return true; + } + pos = c + 2; + } + return false; + } + + static void setBaseModule(String name) { + baseModuleName = name; + } + // TODO: we shall remove "-" from the regex once we define + // the naming convention for the module names without dashes + static final Pattern classNamePattern = Pattern.compile("[\\w\\.\\*_$-/]+"); + + static List readConfigurationFile(String file) throws IOException { + List result = new ArrayList(); + // parse configuration file + FileInputStream in = new FileInputStream(file); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + + int lineNumber = 0; + boolean inRoots = false; + boolean inIncludes = false; + boolean inAllows = false; + boolean inExcludes = false; + boolean inBlockComment = false; + ModuleConfig config = null; + + while ((line = reader.readLine()) != null) { + lineNumber++; + + if (inBlockComment) { + int c = line.indexOf("*/"); + if (c >= 0) { + line = line.substring(c + 2, line.length()); + inBlockComment = false; + } else { + // skip lines until end of comment block + continue; + } + } + + inBlockComment = beginBlockComment(line); + + line = trimComment(line).trim(); + // ignore empty lines + if (line.length() == 0) { + continue; + } + + String values; + if (inRoots || inIncludes || inExcludes || inAllows) { + values = line; + } else { + String[] s = line.split("\\s+"); + String keyword = s[0].trim(); + if (keyword.equals("module")) { + if (s.length != 3 || !s[2].trim().equals("{")) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed"); + } + config = new ModuleConfig(s[1].trim()); + result.add(config); + // switch to a new module; so reset the flags + inRoots = false; + inIncludes = false; + inExcludes = false; + inAllows = false; + continue; + } else if (keyword.equals("roots")) { + inRoots = true; + } else if (keyword.equals("include")) { + inIncludes = true; + } else if (keyword.equals("exclude")) { + inExcludes = true; + } else if (keyword.equals("allow")) { + inAllows = true; + } else if (keyword.equals("}")) { + if (config == null || s.length != 1) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed"); + } else { + // end of a module + config = null; + continue; + } + } else { + throw new RuntimeException(file + ", \"" + keyword + "\" on line " + + lineNumber + ", is not recognized"); + } + values = line.substring(keyword.length(), line.length()).trim(); + } + + if (config == null) { + throw new RuntimeException(file + ", module not specified"); + } + + int len = values.length(); + if (len == 0) { + continue; + } + char lastchar = values.charAt(len - 1); + if (lastchar != ',' && lastchar != ';') { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed:" + + " ',' or ';' is missing."); + } + + values = values.substring(0, len - 1); + // parse the values specified for a keyword specified + for (String s : values.split(",")) { + s = s.trim(); + if (s.length() > 0) { + if (!classNamePattern.matcher(s).matches()) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed: \"" + s + "\""); + } + if (inRoots) { + config.roots.add(s); + } else if (inIncludes) { + config.includes.add(s); + } else if (inExcludes) { + config.filter.exclude(s); + } else if (inAllows) { + config.filter.allow(s); + } + + } + } + if (lastchar == ';') { + inRoots = false; + inIncludes = false; + inExcludes = false; + inAllows = false; + } + } + + if (inBlockComment) { + throw new RuntimeException(file + ", line " + + lineNumber + ", missing \"*/\" to end a block comment"); + } + if (config != null) { + throw new RuntimeException(file + ", line " + + lineNumber + ", missing \"}\" to end module definition" + + " for \"" + config.module + "\""); + } + + } finally { + in.close(); + } + + return result; + } + + private String format(String keyword, Collection values) { + if (values.size() == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + String format = "%4s%-9s"; + String spaces = String.format(format, "", ""); + sb.append(String.format(format, "", keyword)); + int count = 0; + for (String s : values) { + if (count > 0) { + sb.append(",\n").append(spaces); + } else if (count++ > 0) { + sb.append(", "); + } + sb.append(s); + } + if (count > 0) { + sb.append(";\n"); + } + return sb.toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("module " + module).append(" {\n"); + sb.append(format("include", includes)); + sb.append(format("root", roots)); + sb.append(format("allow", filter.allow)); + sb.append(format("exclude", filter.exclude)); + sb.append("}\n"); + return sb.toString(); + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java new file mode 100644 index 00000000000..19746a49648 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java @@ -0,0 +1,201 @@ +/* + * 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.classanalyzer; + +import com.sun.classanalyzer.Klass.Method; + +/** + * + * @author mchung + */ +public class ResolutionInfo implements Comparable { + + enum Type { + + REFLECTION("reflection", true), + NATIVE("native", true), + INTERFACE("interface", false), + SUPER("super", false), + EXPLICIT("explicit", false), + VERIFICATION("verification", false), + METHODTRACE("method trace", true), + CONSTANT_POOL("constant pool", true), + CHECKED_EXCEPTION("throws", true), + METHOD("method", true), + FIELD("field", true), + EXTENDS("extends", true), + IMPLEMENTS("implements", true), + NOINFO("No info", false); + + private final String name; + private final boolean hasInfo; + + private Type(String name, boolean hasInfo) { + this.name = name; + this.hasInfo = hasInfo; + } + + public String getName() { + return name; + } + + public boolean hasInfo() { + return hasInfo; + } + + public static Type getType(String s) { + if (s.isEmpty()) { + return NOINFO; + } + for (Type t : values()) { + if (s.equals(t.name)) { + return t; + } + } + // Need to fix the VM output to add "native" + // throw new IllegalArgumentException("Invalid ResolutionInfo.type \"" + s + "\""); + System.out.println("WARNING: Invalid ResolutionInfo.type \"" + s + "\""); + return null; + } + } + final Klass fromClass; + final Method method; + final Klass toClass; + final int linenumber; + final Type type; + final String info; + private boolean isPublic = false; + + private ResolutionInfo(Klass from, Klass to, int linenumber, Type type, String info) { + this.fromClass = from; + this.method = null; + this.toClass = to; + this.linenumber = linenumber; + this.type = type; + this.info = info; + } + + private ResolutionInfo(Klass from, Method m, Klass to, int linenumber, Type type) { + this.fromClass = from; + this.method = m; + this.toClass = to; + this.linenumber = linenumber; + this.type = type; + this.info = m.toString(); + } + + public boolean isPublic() { + return isPublic; + } + + public void setPublicAccess(boolean value) { + isPublic = value; + } + static ResolutionInfo resolved(Klass from, Klass to) { + return new ResolutionInfo(from, to, 0, Type.NOINFO, ""); + } + + static ResolutionInfo resolved(Klass from, Klass to, int linenumber) { + return new ResolutionInfo(from, to, linenumber, Type.NOINFO, ""); + } + + static ResolutionInfo resolved(Klass from, Klass to, int linenumber, String reason) { + String[] ss = reason.split("\\s+"); + Type type; + String info; + if (linenumber == -1) { + type = Type.NATIVE; + info = ss[0]; // native method name + } else { + info = ss.length == 2 ? ss[1] : ""; + type = Type.getType(ss[0]); + if (type == null) { + if (reason.isEmpty()) { + throw new IllegalArgumentException("Invalid type: " + reason + " (" + ss[0] + ")" + ss.length); + } + // assume it's native + type = Type.NATIVE; + info = reason.isEmpty() ? ss[0] : reason; + } + } + + return new ResolutionInfo(from, to, linenumber, type, info); + } + + static ResolutionInfo resolved(Klass from, Klass to, Method callee) { + return new ResolutionInfo(from, callee, to, 0, Type.METHODTRACE); + } + + static ResolutionInfo resolvedConstantPool(Klass from, Klass to, int index) { + return new ResolutionInfo(from, to, 0, Type.CONSTANT_POOL, "#" + index); + } + + static ResolutionInfo resolvedField(Klass from, Klass to, String fieldname) { + return new ResolutionInfo(from, to, 0, Type.FIELD, fieldname); + } + + static ResolutionInfo resolvedMethodSignature(Klass from, Klass to, Method m) { + return new ResolutionInfo(from, m, to, 0, Type.METHOD); + } + + static ResolutionInfo resolvedCheckedException(Klass from, Klass to, Method m) { + return new ResolutionInfo(from, m, to, 0, Type.CHECKED_EXCEPTION); + } + + static ResolutionInfo resolvedExtends(Klass from, Klass to) { + String info = from.getClassName() + " implements " + to.getClassName(); + return new ResolutionInfo(from, to, 0, Type.EXTENDS, info); + } + + static ResolutionInfo resolvedImplements(Klass from, Klass to) { + String info = from.getClassName() + " implements " + to.getClassName(); + return new ResolutionInfo(from, to, 0, Type.IMPLEMENTS, info); + } + + @Override + public int compareTo(ResolutionInfo ri) { + if (this.fromClass == ri.fromClass && + this.toClass == ri.toClass && + this.linenumber == ri.linenumber && + this.type == ri.type && + this.info.equals(ri.info)) { + return 0; + } else if (this.fromClass == ri.fromClass) { + if (this.linenumber > ri.linenumber) { + return 1; + } else if (this.linenumber < ri.linenumber) { + return -1; + } else if (this.type != ri.type) { + return this.type.getName().compareTo(ri.type.getName()); + } else if (this.toClass != ri.toClass) { + return this.toClass.compareTo(ri.toClass); + } else { + return this.info.compareTo(ri.info); + } + } else { + return this.fromClass.compareTo(ri.fromClass); + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java new file mode 100644 index 00000000000..8c6714085a6 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java @@ -0,0 +1,186 @@ +/* + * 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.classanalyzer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ResourceFile implements Comparable { + + private final String pathname; + private Module module; + + ResourceFile(String pathname) { + this.pathname = pathname.replace(File.separatorChar, '/'); + } + + Module getModule() { + return module; + } + + void setModule(Module m) { + if (module != null) { + throw new RuntimeException("Module for " + this + " already set"); + } + this.module = m; + } + + String getName() { + return pathname; + } + + String getPathname() { + return pathname; + } + + @Override + public String toString() { + return pathname; + } + + @Override + public int compareTo(ResourceFile o) { + return pathname.compareTo(o.pathname); + } + static Set resources = new TreeSet(); + + static boolean isResource(String pathname) { + String name = pathname.replace(File.separatorChar, '/'); + + if (name.endsWith("META-INF/MANIFEST.MF")) { + return false; + } + if (name.contains("META-INF/JCE_RSA.")) { + return false; + } + + return true; + } + + static void addResource(String name, InputStream in) { + ResourceFile res; + name = name.replace(File.separatorChar, '/'); + if (name.startsWith("META-INF/services")) { + res = new ServiceProviderConfigFile(name, in); + } else { + res = new ResourceFile(name); + } + resources.add(res); + } + + static Set getAllResources() { + return Collections.unmodifiableSet(resources); + } + + static class ServiceProviderConfigFile extends ResourceFile { + + private final List providers = new ArrayList(); + private final String service; + ServiceProviderConfigFile(String pathname, InputStream in) { + super(pathname); + readServiceConfiguration(in, providers); + this.service = pathname.substring("META-INF/services".length() + 1, pathname.length()); + } + + @Override + String getName() { + if (providers.isEmpty()) { + return service; + } else { + // just use the first one for matching + return providers.get(0); + } + } + + @SuppressWarnings("empty-statement") + void readServiceConfiguration(InputStream in, List names) { + BufferedReader br = null; + try { + if (in != null) { + // Properties doesn't perserve the order of the input file + br = new BufferedReader(new InputStreamReader(in, "utf-8")); + int lc = 1; + while ((lc = parseLine(br, lc, names)) >= 0); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + } + + // Parse a single line from the given configuration file, adding the name + // on the line to the names list. + // + private int parseLine(BufferedReader r, int lc, List names) throws IOException { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) { + ln = ln.substring(0, ci); + } + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { + throw new RuntimeException("Illegal configuration-file syntax"); + } + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + } + if (!names.contains(ln)) { + names.add(ln); + } + } + return lc + 1; + } + } +} diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java new file mode 100644 index 00000000000..ce585553ba6 --- /dev/null +++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java @@ -0,0 +1,100 @@ +/* + * 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.classanalyzer; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * A simple tool to print out the static dependencies for a given set of JAR, + * class files, or combinations of. The tools supports an -ignore option to + * ignore references to classes listed in the file (including .classlists + * created by the ClassAnalyzer tool). + */ + +public class ShowDeps { + + static void usage() { + System.out.println("java ShowDeps [-ignore ] file..."); + System.out.println(" where is a class or JAR file, or a directory"); + System.out.println(); + System.out.println("Example usages:"); + System.out.println(" java ShowDeps Foo.jar"); + System.out.println(" java ShowDeps -ignore base.classlist Foo.jar"); + System.out.println(" java ShowDeps -ignore base.classlist -ignore " + + "jaxp-parsers.classlist

"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // process -ignore options + int argi = 0; + Set ignore = new HashSet(); + while (argi < args.length && args[argi].equals("-ignore")) { + argi++; + Scanner s = new Scanner(new File(args[argi++])); + try { + while (s.hasNextLine()) { + String line = s.nextLine(); + if (!line.endsWith(".class")) + continue; + int len = line.length(); + // convert to class names + String clazz = line.replace('\\', '.').replace('/', '.') + .substring(0, len-6); + ignore.add(clazz); + } + } finally { + s.close(); + } + } + + if (argi >= args.length) + usage(); + + // parse all classes + while (argi < args.length) + ClassPath.setClassPath(args[argi++]); + ClassPath.parseAllClassFiles(); + + // find the classes that don't exist + Set unresolved = new TreeSet(); + for (Klass k : Klass.getAllClasses()) { + if (k.getFileSize() == 0) + unresolved.add(k); + } + + // print references to classes that don't exist + for (Klass k: Klass.getAllClasses()) { + for (Klass other : k.getReferencedClasses()) { + if (unresolved.contains(other)) { + String name = other.toString(); + if (!ignore.contains(name)) { + System.out.format("%s -> %s\n", k, other); + } + } + } + } + } +} diff --git a/jdk/make/sun/applet/Makefile b/jdk/make/sun/applet/Makefile index 415db17ddfb..83902ab7d86 100644 --- a/jdk/make/sun/applet/Makefile +++ b/jdk/make/sun/applet/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = applet PACKAGE = sun.applet PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/awt/Makefile b/jdk/make/sun/awt/Makefile index c3c1745ff54..0a8ad9c5fe1 100644 --- a/jdk/make/sun/awt/Makefile +++ b/jdk/make/sun/awt/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = awt PACKAGE = sun.awt LIBRARY = awt PRODUCT = sun @@ -312,15 +313,15 @@ dgalibs: $(DGALIBS) $(LIBDIR)/$(LIBARCH)/libxinerama.so: $(CLOSED_SRC)/solaris/lib/$(ARCH)/libxinerama.so $(install-file) - $(CHMOD) a+x $@ + $(call chmod-file, a+x) $(LIBDIR)/$(LIBARCH)/libjdgaSUNW%.so: $(CLOSED_SRC)/solaris/lib/$(ARCH)/libjdgaSUNW%.so $(install-file) - $(CHMOD) a+x $@ + $(call chmod-file, a+x) $(LIBDIR)/$(LIBARCH)/libjdgaSUNWafb.so: $(LIBDIR)/$(LIBARCH)/libjdgaSUNWffb.so $(prep-target) - $(LN) -s libjdgaSUNWffb.so $(LIBDIR)/$(LIBARCH)/libjdgaSUNWafb.so + $(call install-sym-link, libjdgaSUNWffb.so) clean:: dgalib.clean @@ -404,7 +405,8 @@ $(LIBDIR)/%.bfc: $(FONTCONFIGS_SRC)/$(FONTCONFIGS_SRC_PREFIX)%.properties \ $(COMPILEFONTCONFIG_JARFILE) $(prep-target) $(BOOT_JAVA_CMD) -jar $(COMPILEFONTCONFIG_JARFILE) $< $@ - $(CHMOD) 444 $(@) + $(install-module-file) + $(call chmod-file, 444) @$(java-vm-cleanup) fontconfigs.clean : diff --git a/jdk/make/sun/cmm/Makefile b/jdk/make/sun/cmm/Makefile index bbed857654c..dc8a87b6e69 100644 --- a/jdk/make/sun/cmm/Makefile +++ b/jdk/make/sun/cmm/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = java2d PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -45,34 +46,24 @@ iccprofiles: $(ICCPROFILE_DEST_DIR)/sRGB.pf $(ICCPROFILE_DEST_DIR)/GRAY.pf \ $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf $(ICCPROFILE_DEST_DIR)/sRGB.pf: $(ICCPROFILE_SRC_DIR)/sRGB.pf - $(RM) $(ICCPROFILE_DEST_DIR)/sRGB.pf - -$(MKDIR) -p $(ICCPROFILE_DEST_DIR) - $(CP) $(ICCPROFILE_SRC_DIR)/sRGB.pf $(ICCPROFILE_DEST_DIR) - $(CHMOD) 444 $(ICCPROFILE_DEST_DIR)/sRGB.pf + $(install-file) + $(call chmod-file, 444) $(ICCPROFILE_DEST_DIR)/GRAY.pf: $(ICCPROFILE_SRC_DIR)/GRAY.pf - $(RM) $(ICCPROFILE_DEST_DIR)/GRAY.pf - -$(MKDIR) -p $(ICCPROFILE_DEST_DIR) - $(CP) $(ICCPROFILE_SRC_DIR)/GRAY.pf $(ICCPROFILE_DEST_DIR) - $(CHMOD) 444 $(ICCPROFILE_DEST_DIR)/GRAY.pf + $(install-file) + $(call chmod-file, 444) $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf: $(ICCPROFILE_SRC_DIR)/CIEXYZ.pf - $(RM) $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf - -$(MKDIR) -p $(ICCPROFILE_DEST_DIR) - $(CP) $(ICCPROFILE_SRC_DIR)/CIEXYZ.pf $(ICCPROFILE_DEST_DIR) - $(CHMOD) 444 $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf + $(install-file) + $(call chmod-file, 444) $(ICCPROFILE_DEST_DIR)/PYCC.pf: $(ICCPROFILE_SRC_DIR)/PYCC.pf - $(RM) $(ICCPROFILE_DEST_DIR)/PYCC.pf - -$(MKDIR) -p $(ICCPROFILE_DEST_DIR) - $(CP) $(ICCPROFILE_SRC_DIR)/PYCC.pf $(ICCPROFILE_DEST_DIR) - $(CHMOD) 444 $(ICCPROFILE_DEST_DIR)/PYCC.pf + $(install-file) + $(call chmod-file, 444) $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf: $(ICCPROFILE_SRC_DIR)/LINEAR_RGB.pf - $(RM) $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf - -$(MKDIR) -p $(ICCPROFILE_DEST_DIR) - $(CP) $(ICCPROFILE_SRC_DIR)/LINEAR_RGB.pf $(ICCPROFILE_DEST_DIR) - $(CHMOD) 444 $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf + $(install-file) + $(call chmod-file, 444) iccprofiles.clean: $(RM) -r $(ICCPROFILE_DEST_DIR) diff --git a/jdk/make/sun/cmm/kcms/Makefile b/jdk/make/sun/cmm/kcms/Makefile index 10ff72b4f57..a7250f74b87 100644 --- a/jdk/make/sun/cmm/kcms/Makefile +++ b/jdk/make/sun/cmm/kcms/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = java2d PACKAGE = sun.java2d.cmm.kcms LIBRARY = kcms PRODUCT = sun diff --git a/jdk/make/sun/cmm/lcms/Makefile b/jdk/make/sun/cmm/lcms/Makefile index ba595507b7a..ac8746af7b2 100644 --- a/jdk/make/sun/cmm/lcms/Makefile +++ b/jdk/make/sun/cmm/lcms/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = java2d PACKAGE = sun.java2d.cmm.lcms LIBRARY = lcms PRODUCT = sun diff --git a/jdk/make/sun/dcpr/Makefile b/jdk/make/sun/dcpr/Makefile index e49db2af23a..4dc39f93b9f 100644 --- a/jdk/make/sun/dcpr/Makefile +++ b/jdk/make/sun/dcpr/Makefile @@ -26,6 +26,7 @@ # WARNING: Make sure the OPENJDK plugs are up-to-date, see make/common/internal/BinaryPlugs.gmk BUILDDIR = ../.. +MODULE = java2d PACKAGE = sun.dc LIBRARY = dcpr PRODUCT = sun diff --git a/jdk/make/sun/font/Makefile b/jdk/make/sun/font/Makefile index f513a64bd46..c95e52f458e 100644 --- a/jdk/make/sun/font/Makefile +++ b/jdk/make/sun/font/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = font PACKAGE = sun.font LIBRARY = fontmanager PRODUCT = sun @@ -121,16 +122,21 @@ FILES_m=mapfile-vers.openjdk # #TODO: rework this to avoid hardcoding library name in the makefile # -library:: $(LIB_LOCATION)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX) - -$(LIB_LOCATION)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX): ifeq ($(PLATFORM), windows) - $(CP) $(FREETYPE_LIB_PATH)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX) $@ + FREETYPE_LIB = $(LIB_LOCATION)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX) + OTHER_LDLIBS += $(FREETYPE_LIB_PATH)/freetype.lib else ifeq ($(USING_SYSTEM_FT_LIB), false) - $(CP) $(FREETYPE_LIB_PATH)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX) $@.6 + FREETYPE_LIB = $(LIB_LOCATION)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX).6 endif + OTHER_LDLIBS += -L$(FREETYPE_LIB_PATH) -lfreetype endif + +library:: $(FREETYPE_LIB) + +$(FREETYPE_LIB): + $(CP) $(FREETYPE_LIB_PATH)/$(LIB_PREFIX)freetype.$(LIBRARY_SUFFIX) $@ + $(install-module-file) endif #ifeq ($(PLATFORM), solaris) @@ -158,7 +164,6 @@ ifndef OPENJDK CPPFLAGS += -I$(CLOSED_SRC)/share/native/$(PKGDIR)/t2k else CPPFLAGS += -I$(FREETYPE_HEADERS_PATH) -I$(FREETYPE_HEADERS_PATH)/freetype2 - OTHER_LDLIBS += $(FREETYPE_LIB) endif ifeq ($(PLATFORM), windows) diff --git a/jdk/make/sun/font/t2k/Makefile b/jdk/make/sun/font/t2k/Makefile index d01e825159b..651eea84d2c 100644 --- a/jdk/make/sun/font/t2k/Makefile +++ b/jdk/make/sun/font/t2k/Makefile @@ -30,6 +30,7 @@ # BUILDDIR = ../../.. +MODULE = font PACKAGE = sun.font LIBRARY = t2k PRODUCT = sun diff --git a/jdk/make/sun/headless/Makefile b/jdk/make/sun/headless/Makefile index b1e1ebf6d5b..ee853eae746 100644 --- a/jdk/make/sun/headless/Makefile +++ b/jdk/make/sun/headless/Makefile @@ -30,6 +30,7 @@ MOTIF_VERSION = none MOTIF_VERSION_STRING=none LIB_LOCATION = $(LIBDIR)/$(LIBARCH)/headless +MODULE = awt PACKAGE = sun.awt LIBRARY = mawt LIBRARY_OUTPUT = headless diff --git a/jdk/make/sun/image/generic/Makefile b/jdk/make/sun/image/generic/Makefile index 5caedf6d7d0..446209f8667 100644 --- a/jdk/make/sun/image/generic/Makefile +++ b/jdk/make/sun/image/generic/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../.. +MODULE = media PACKAGE = sun.awt.medialib LIBRARY = mlib_image PRODUCT = sun diff --git a/jdk/make/sun/image/vis/Makefile b/jdk/make/sun/image/vis/Makefile index b0e399b0878..2bc891a5cf6 100644 --- a/jdk/make/sun/image/vis/Makefile +++ b/jdk/make/sun/image/vis/Makefile @@ -27,6 +27,7 @@ # Makefile for building the VIS (solaris-only) version of medialib # BUILDDIR = ../../.. +MODULE = media PACKAGE = sun.awt.medialib LIBRARY = mlib_image_v PRODUCT = sun diff --git a/jdk/make/sun/jar/Makefile b/jdk/make/sun/jar/Makefile index b90d738900c..7dd586e2ff7 100644 --- a/jdk/make/sun/jar/Makefile +++ b/jdk/make/sun/jar/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = jar-tool PACKAGE = sun.tools PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/javazic/Makefile b/jdk/make/sun/javazic/Makefile index 96a2df1e0d9..10c2b1a8565 100644 --- a/jdk/make/sun/javazic/Makefile +++ b/jdk/make/sun/javazic/Makefile @@ -27,6 +27,7 @@ BUILDDIR = ../.. +MODULE = base PACKAGE = sun.javazic PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -69,6 +70,7 @@ $(INSTALLDIR)/$(MAPFILE): $(WORKDIR)/$(MAPFILE) $(RM) -r $(@D) $(prep-target) $(CP) -r $(WORKDIR)/* $(@D) + $(install-module-dir) clean clobber:: $(RM) -r $(TEMPDIR) $(INSTALLDIR) diff --git a/jdk/make/sun/jawt/Makefile b/jdk/make/sun/jawt/Makefile index 45d337258a4..424a20d1c41 100644 --- a/jdk/make/sun/jawt/Makefile +++ b/jdk/make/sun/jawt/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = awt PACKAGE = sun.awt LIBRARY = jawt PRODUCT = sun diff --git a/jdk/make/sun/jconsole/Makefile b/jdk/make/sun/jconsole/Makefile index dc61227fe62..42f624e38b2 100644 --- a/jdk/make/sun/jconsole/Makefile +++ b/jdk/make/sun/jconsole/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = jconsole PACKAGE = sun.tools.jconsole PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -79,7 +80,7 @@ $(CLASSBINDIR)/$(PKGDIR)/resources/%: $(SHARE_SRC)/classes/$(PKGDIR)/resources/% $(install-file) $(TEMPDIR)/manifest: $(SHARE_SRC)/classes/$(PKGDIR)/manifest - $(install-file) + $(install-manifest-file) # # Extra rule to build jconsole.jar diff --git a/jdk/make/sun/jdbc/Makefile b/jdk/make/sun/jdbc/Makefile index d7e7eaf1530..4b241b9174e 100644 --- a/jdk/make/sun/jdbc/Makefile +++ b/jdk/make/sun/jdbc/Makefile @@ -33,6 +33,7 @@ # BUILDDIR = ../.. +MODULE = jdbc-odbc PACKAGE = sun.jdbc.odbc LIBRARY = JdbcOdbc PRODUCT = sun diff --git a/jdk/make/sun/jdga/Makefile b/jdk/make/sun/jdga/Makefile index 257996d7721..d9a6db65565 100644 --- a/jdk/make/sun/jdga/Makefile +++ b/jdk/make/sun/jdga/Makefile @@ -25,6 +25,7 @@ BUILDDIR = ../.. +MODULE = java2d PACKAGE = sun.jdga LIBRARY = sunwjdga PRODUCT = sun diff --git a/jdk/make/sun/jkernel/Makefile b/jdk/make/sun/jkernel/Makefile index 97f2f38aca5..7a7a6a3645f 100644 --- a/jdk/make/sun/jkernel/Makefile +++ b/jdk/make/sun/jkernel/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = jkernel PACKAGE = sun.jkernel LIBRARY = jkernel PRODUCT = sun diff --git a/jdk/make/sun/jpeg/Makefile b/jdk/make/sun/jpeg/Makefile index f97e2cd08b8..99d36a9b257 100644 --- a/jdk/make/sun/jpeg/Makefile +++ b/jdk/make/sun/jpeg/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = java2d PACKAGE = sun.awt LIBRARY = jpeg PRODUCT = sun diff --git a/jdk/make/sun/launcher/Makefile b/jdk/make/sun/launcher/Makefile index 1346bc4e200..32b2ec7aa1b 100644 --- a/jdk/make/sun/launcher/Makefile +++ b/jdk/make/sun/launcher/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = base PACKAGE = sun.launcher PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/management/Makefile b/jdk/make/sun/management/Makefile index bb7ad8935c9..a54b1dd0be9 100644 --- a/jdk/make/sun/management/Makefile +++ b/jdk/make/sun/management/Makefile @@ -28,6 +28,8 @@ # BUILDDIR = ../.. +MODULE = management + include $(BUILDDIR)/common/Defs.gmk MGMT_LIBDIR = $(LIBDIR)/management @@ -56,17 +58,17 @@ jmxremotefiles: $(MGMT_LIBDIR)/jmxremote.password.template $(MGMT_LIBDIR)/jmxrem $(MGMT_LIBDIR)/management.properties: $(MGMT_LIB_SRC)/management.properties $(install-file) - $(CHMOD) 644 $@ + $(call chmod-file, 644) $(MGMT_LIBDIR)/snmp.acl.template: $(MGMT_LIB_SRC)/snmp.acl.template $(install-file) - $(CHMOD) 444 $@ + $(call chmod-file, 444) $(MGMT_LIBDIR)/jmxremote.password.template: $(MGMT_LIB_SRC)/jmxremote.password.template $(install-file) - $(CHMOD) 444 $@ + $(call chmod-file, 444) $(MGMT_LIBDIR)/jmxremote.access: $(MGMT_LIB_SRC)/jmxremote.access $(install-file) - $(CHMOD) 644 $@ + $(call chmod-file, 644) diff --git a/jdk/make/sun/native2ascii/Makefile b/jdk/make/sun/native2ascii/Makefile index 766e90fc545..1cd1ab9b155 100644 --- a/jdk/make/sun/native2ascii/Makefile +++ b/jdk/make/sun/native2ascii/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = tools PACKAGE = sun.tools.native2ascii PRODUCT = sun OTHER_JAVACFLAGS += -Xlint:serial -Werror diff --git a/jdk/make/sun/net/others/Makefile b/jdk/make/sun/net/others/Makefile index 2adf6048b7b..0896c7ef679 100644 --- a/jdk/make/sun/net/others/Makefile +++ b/jdk/make/sun/net/others/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = base PACKAGE = sun.net PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/net/spi/nameservice/dns/Makefile b/jdk/make/sun/net/spi/nameservice/dns/Makefile index d86a3c69f00..746f168b457 100644 --- a/jdk/make/sun/net/spi/nameservice/dns/Makefile +++ b/jdk/make/sun/net/spi/nameservice/dns/Makefile @@ -28,6 +28,9 @@ # BUILDDIR = ../../../../.. + +# dns should probably be its own module +MODULE = net-dns PACKAGE = sun.net.spi.nameservice.dns PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/nio/Makefile b/jdk/make/sun/nio/Makefile index 4b46a1fb76d..76051c1b17a 100644 --- a/jdk/make/sun/nio/Makefile +++ b/jdk/make/sun/nio/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1996-2008 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,88 +23,12 @@ # have any questions. # -# -# Makefile for character converters. -# - BUILDDIR = ../.. - PACKAGE = sun.nio PRODUCT = sun - -# This re-directs all the class files to a separate location -CLASSDESTDIR = $(TEMPDIR)/classes - -OTHER_JAVACFLAGS += -Xlint:serial -Werror include $(BUILDDIR)/common/Defs.gmk -# -# Files -# -include FILES_java.gmk -AUTO_FILES_JAVA_DIRS = sun/nio/cs/ext +SUBDIRS = cs +all build clean clobber:: + $(SUBDIRS-loop) -# For Cygwin, command line arguments that are paths must be converted to -# windows style paths. These paths cannot be used as targets, however, because -# the ":" in them will interfere with GNU Make rules, generating "multiple -# target pattern" errors. - -# this define is for the rule: -CHARSETS_JAR = $(LIBDIR)/charsets.jar - -# extcs -FILES_genout_extcs = $(FILES_gen_extcs:%.java=$(GENSRCDIR)/%.java) - -# -# Rules -# -include $(BUILDDIR)/common/Classes.gmk - -build: $(FILES_genout_extcs) $(CHARSETS_JAR) - -# -# Extra rules to build character converters. - -SERVICE_DESCRIPTION = java.nio.charset.spi.CharsetProvider -SERVICE_DESCRIPTION_PATH = META-INF/services/$(SERVICE_DESCRIPTION) - -GENCSDATASRC = $(BUILDDIR)/tools/CharsetMapping -GENCSSRCDIR = $(BUILDDIR)/tools/src/build/tools/charsetmapping -GENCSEXT = $(GENSRCDIR)/sun/nio/cs/ext - -FILES_MAP = $(GENCSDATASRC)/sjis0213.map -FILES_DAT = $(CLASSDESTDIR)/sun/nio/cs/ext/sjis0213.dat -CHARSETMAPPING_JARFILE = $(BUILDTOOLJARDIR)/charsetmapping.jar - -$(FILES_DAT): $(FILES_MAP) - @$(prep-target) - $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) \ - $(FILES_MAP) $(FILES_DAT) sjis0213 - - -$(FILES_genout_extcs): \ - $(GENCSDATASRC)/SingleByte-X.java.template \ - $(GENCSDATASRC)/DoubleByte-X.java.template \ - $(GENCSDATASRC)/extsbcs $(GENCSDATASRC)/dbcs - @$(prep-target) - $(RM) -r $(GENCSEXT) - $(MKDIR) -p $(GENCSEXT) - $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) extsbcs - $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) euctw \ - $(GENCSSRCDIR)/GenerateEUC_TW.java - $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) dbcs - -$(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH): \ - $(SHARE_SRC)/classes/sun/nio/cs/ext/$(SERVICE_DESCRIPTION_PATH) - $(install-file) - -$(CHARSETS_JAR): $(FILES_class) $(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH) $(FILES_DAT) - $(BOOT_JAR_CMD) cf0 $(CHARSETS_JAR) \ - -C $(CLASSDESTDIR) sun \ - -C $(CLASSDESTDIR) $(SERVICE_DESCRIPTION_PATH) \ - $(BOOT_JAR_JFLAGS) - @$(java-vm-cleanup) - -clean:: - $(RM) -r $(CLASSDESTDIR) - $(RM) $(CHARSETS_JAR) diff --git a/jdk/make/sun/nio/FILES_java.gmk b/jdk/make/sun/nio/cs/FILES_java.gmk similarity index 100% rename from jdk/make/sun/nio/FILES_java.gmk rename to jdk/make/sun/nio/cs/FILES_java.gmk diff --git a/jdk/make/sun/nio/cs/Makefile b/jdk/make/sun/nio/cs/Makefile new file mode 100644 index 00000000000..c2e9c0b8ef2 --- /dev/null +++ b/jdk/make/sun/nio/cs/Makefile @@ -0,0 +1,112 @@ +# +# Copyright 1996-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 for character converters. +# + +BUILDDIR = ../../.. + +# charsets should be separated from nio module +MODULE = charsets +PACKAGE = sun.nio +PRODUCT = sun + +# This re-directs all the class files to a separate location +CLASSDESTDIR = $(TEMPDIR)/classes + +OTHER_JAVACFLAGS += -Xlint:serial -Werror +include $(BUILDDIR)/common/Defs.gmk + +# +# Files +# +include FILES_java.gmk +AUTO_FILES_JAVA_DIRS = sun/nio/cs/ext + +# For Cygwin, command line arguments that are paths must be converted to +# windows style paths. These paths cannot be used as targets, however, because +# the ":" in them will interfere with GNU Make rules, generating "multiple +# target pattern" errors. + +# this define is for the rule: +CHARSETS_JAR = $(LIBDIR)/charsets.jar + +# extcs +FILES_genout_extcs = $(FILES_gen_extcs:%.java=$(GENSRCDIR)/%.java) + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +build: $(FILES_genout_extcs) $(CHARSETS_JAR) + +# +# Extra rules to build character converters. + +SERVICE_DESCRIPTION = java.nio.charset.spi.CharsetProvider +SERVICE_DESCRIPTION_PATH = META-INF/services/$(SERVICE_DESCRIPTION) + +GENCSDATASRC = $(BUILDDIR)/tools/CharsetMapping +GENCSSRCDIR = $(BUILDDIR)/tools/src/build/tools/charsetmapping +GENCSEXT = $(GENSRCDIR)/sun/nio/cs/ext + +FILES_MAP = $(GENCSDATASRC)/sjis0213.map +FILES_DAT = $(CLASSDESTDIR)/sun/nio/cs/ext/sjis0213.dat +CHARSETMAPPING_JARFILE = $(BUILDTOOLJARDIR)/charsetmapping.jar + +$(FILES_DAT): $(FILES_MAP) + @$(prep-target) + $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) \ + $(FILES_MAP) $(FILES_DAT) sjis0213 + + +$(FILES_genout_extcs): \ + $(GENCSDATASRC)/SingleByte-X.java.template \ + $(GENCSDATASRC)/DoubleByte-X.java.template \ + $(GENCSDATASRC)/extsbcs $(GENCSDATASRC)/dbcs + @$(prep-target) + $(RM) -r $(GENCSEXT) + $(MKDIR) -p $(GENCSEXT) + $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) extsbcs + $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) euctw \ + $(GENCSSRCDIR)/GenerateEUC_TW.java + $(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) dbcs + +$(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH): \ + $(SHARE_SRC)/classes/sun/nio/cs/ext/$(SERVICE_DESCRIPTION_PATH) + $(install-file) + +$(CHARSETS_JAR): $(FILES_class) $(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH) $(FILES_DAT) + $(BOOT_JAR_CMD) cf0 $(CHARSETS_JAR) \ + -C $(CLASSDESTDIR) sun \ + -C $(CLASSDESTDIR) $(SERVICE_DESCRIPTION_PATH) \ + $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) + +clean:: + $(RM) -r $(CLASSDESTDIR) + $(RM) $(CHARSETS_JAR) diff --git a/jdk/make/sun/org/mozilla/javascript/Makefile b/jdk/make/sun/org/mozilla/javascript/Makefile index 2e74c02fdd5..1750fadc6cb 100644 --- a/jdk/make/sun/org/mozilla/javascript/Makefile +++ b/jdk/make/sun/org/mozilla/javascript/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../../.. +MODULE = scripting-rhino PACKAGE = sun.org.mozilla.javascript.internal PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/pisces/Makefile b/jdk/make/sun/pisces/Makefile index 3f3a3228b95..73f07f5090b 100644 --- a/jdk/make/sun/pisces/Makefile +++ b/jdk/make/sun/pisces/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = java2d PACKAGE = sun.pisces PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/rmi/cgi/Makefile b/jdk/make/sun/rmi/cgi/Makefile index 0ed90ca2bd5..4b69bc0a523 100644 --- a/jdk/make/sun/rmi/cgi/Makefile +++ b/jdk/make/sun/rmi/cgi/Makefile @@ -28,6 +28,8 @@ # BUILDDIR = ../../.. +# java-rmi.cgi is a JDK tool +MODULE = tools PACKAGE = sun.rmi PRODUCT = sun PROGRAM = java-rmi diff --git a/jdk/make/sun/rmi/oldtools/Makefile b/jdk/make/sun/rmi/oldtools/Makefile index ad610ffca41..b59d4fcf077 100644 --- a/jdk/make/sun/rmi/oldtools/Makefile +++ b/jdk/make/sun/rmi/oldtools/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../.. +MODULE = oldjavac PRODUCT = oldjavac include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/rmi/registry/Makefile b/jdk/make/sun/rmi/registry/Makefile index c5254a7f3c9..bfb6cb55ed8 100644 --- a/jdk/make/sun/rmi/registry/Makefile +++ b/jdk/make/sun/rmi/registry/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../.. +MODULE = rmi PACKAGE = sun.rmi.registry PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -48,3 +49,7 @@ RESOURCE_BUNDLES_UNCOMPILED_PROPERTIES = $(PKGDIR)/resources/rmiregistry.propert # include $(BUILDDIR)/common/Classes.gmk +build: rmiregistry + +rmiregistry: + $(call make-launcher, rmiregistry, sun.rmi.registry.RegistryImpl, , ) diff --git a/jdk/make/sun/rmi/rmi/Makefile b/jdk/make/sun/rmi/rmi/Makefile index c351d87f0eb..844f51bcc34 100644 --- a/jdk/make/sun/rmi/rmi/Makefile +++ b/jdk/make/sun/rmi/rmi/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../.. +MODULE = rmi PACKAGE = sun.rmi PRODUCT = sun LIBRARY = rmi @@ -124,7 +125,7 @@ bin: $(BINDIR)/java-rmi.cgi $(BINDIR)/java-rmi.cgi: $(PLATFORM_SRC)/bin/java-rmi.cgi.sh $(install-file) - $(CHMOD) a+x $@ + $(call chmod-file, a+x) bin.clean: $(RM) $(BINDIR)/java-rmi.cgi diff --git a/jdk/make/sun/rmi/rmic/Makefile b/jdk/make/sun/rmi/rmic/Makefile index a09a170f86f..ae73a2d28e3 100644 --- a/jdk/make/sun/rmi/rmic/Makefile +++ b/jdk/make/sun/rmi/rmic/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../../.. +MODULE = rmic PACKAGE = sun.rmi.rmic PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/rmi/rmid/Makefile b/jdk/make/sun/rmi/rmid/Makefile index 845b103220d..23f223ec66b 100644 --- a/jdk/make/sun/rmi/rmid/Makefile +++ b/jdk/make/sun/rmi/rmid/Makefile @@ -29,11 +29,12 @@ # BUILDDIR = ../../.. +MODULE = rmi-activation PACKAGE = sun.rmi.activation PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk -build: stubs +build: stubs rmid # # Resources @@ -75,4 +76,5 @@ stubs: $(FILES_stubs) # include $(BUILDDIR)/common/Classes.gmk - +rmid: + $(call make-launcher, rmid, sun.rmi.server.Activation, , ) diff --git a/jdk/make/sun/security/ec/Makefile b/jdk/make/sun/security/ec/Makefile index 53a3e3e9e51..95b9e8d30d6 100644 --- a/jdk/make/sun/security/ec/Makefile +++ b/jdk/make/sun/security/ec/Makefile @@ -89,6 +89,7 @@ # BUILDDIR = ../../.. +MODULE = security-sunec PACKAGE = sun.security.ec PRODUCT = sun @@ -308,7 +309,7 @@ $(JAR_DESTFILE): $(UNSIGNED_DIR)/sunec.jar else $(JAR_DESTFILE): $(SIGNED_DIR)/sunec.jar endif - $(install-file) + $(install-non-module-file) ifndef OPENJDK install-prebuilt: diff --git a/jdk/make/sun/security/jgss/wrapper/Makefile b/jdk/make/sun/security/jgss/wrapper/Makefile index f5b75dbeb48..8be00aa6c20 100644 --- a/jdk/make/sun/security/jgss/wrapper/Makefile +++ b/jdk/make/sun/security/jgss/wrapper/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../../.. +MODULE = security-kerberos PACKAGE = sun.security.jgss.wrapper PRODUCT = sun diff --git a/jdk/make/sun/security/krb5/Makefile b/jdk/make/sun/security/krb5/Makefile index aac29eb5611..c835666ea9e 100644 --- a/jdk/make/sun/security/krb5/Makefile +++ b/jdk/make/sun/security/krb5/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = security-kerberos PACKAGE = sun.security.krb5 PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -77,3 +78,10 @@ ifeq ($(PLATFORM), windows) else OTHER_LDLIBS = -ldl $(JVMLIB) endif + +build: +ifeq ($(PLATFORM),windows) + $(call make-launcher, kinit, sun.security.krb5.internal.tools.Kinit, , ) + $(call make-launcher, klist, sun.security.krb5.internal.tools.Klist, , ) + $(call make-launcher, ktab, sun.security.krb5.internal.tools.Ktab, , ) +endif diff --git a/jdk/make/sun/security/mscapi/Makefile b/jdk/make/sun/security/mscapi/Makefile index c16d130504f..2cc8ea53614 100644 --- a/jdk/make/sun/security/mscapi/Makefile +++ b/jdk/make/sun/security/mscapi/Makefile @@ -89,6 +89,7 @@ # BUILDDIR = ../../.. +MODULE = security-sunmscapi PACKAGE = sun.security.mscapi LIBRARY = sunmscapi PRODUCT = sun @@ -271,7 +272,7 @@ $(JAR_DESTFILE): $(UNSIGNED_DIR)/sunmscapi.jar else $(JAR_DESTFILE): $(SIGNED_DIR)/sunmscapi.jar endif - $(install-file) + $(install-non-module-file) ifndef OPENJDK install-prebuilt: diff --git a/jdk/make/sun/security/pkcs11/Makefile b/jdk/make/sun/security/pkcs11/Makefile index 9a4a4089be4..f4be8d7a507 100644 --- a/jdk/make/sun/security/pkcs11/Makefile +++ b/jdk/make/sun/security/pkcs11/Makefile @@ -89,6 +89,7 @@ # BUILDDIR = ../../.. +MODULE = security-sunpkcs11 PACKAGE = sun.security.pkcs11 LIBRARY = j2pkcs11 PRODUCT = sun @@ -161,6 +162,16 @@ else OTHER_LDLIBS = -ldl $(JVMLIB) endif +# Other config files +SUNPKCS11_CFG = + +ifeq ($(PLATFORM), solaris) +SUNPKCS11_CFG = sunpkcs11-cfg +endif # PLATFORM + +SUNPKCS11_CFG_SRC = $(TOPDIR)/src/share/lib/security/sunpkcs11-solaris.cfg +SUNPKCS11_CFG_BUILD = $(LIBDIR)/security/sunpkcs11-solaris.cfg + # # We use a variety of subdirectories in the $(TEMPDIR) depending on what # part of the build we're doing. Both OPENJDK/JDK builds are initially @@ -174,12 +185,17 @@ UNSIGNED_DIR = $(TEMPDIR)/unsigned # ifdef OPENJDK -all: build-jar install-jar +all: $(SUNPKCS11_CFG) build-jar install-jar else -all: build-jar install-prebuilt +all: $(SUNPKCS11_CFG) build-jar install-prebuilt $(build-warning) endif +sunpkcs11-cfg: $(SUNPKCS11_CFG_BUILD) + +$(SUNPKCS11_CFG_BUILD): $(SUNPKCS11_CFG_SRC) + $(install-file) + include $(BUILDDIR)/javax/crypto/Defs-jce.gmk @@ -271,7 +287,7 @@ $(JAR_DESTFILE): $(UNSIGNED_DIR)/sunpkcs11.jar else $(JAR_DESTFILE): $(SIGNED_DIR)/sunpkcs11.jar endif - $(install-file) + $(install-non-module-file) ifndef OPENJDK install-prebuilt: @@ -287,6 +303,7 @@ endif clobber clean:: $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR) + $(RM) $(SUNPKCS11_CFG_BUILD) .PHONY: build-jar jar install-jar ifndef OPENJDK diff --git a/jdk/make/sun/security/smartcardio/Makefile b/jdk/make/sun/security/smartcardio/Makefile index 55686411967..097cd40c7a9 100644 --- a/jdk/make/sun/security/smartcardio/Makefile +++ b/jdk/make/sun/security/smartcardio/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = security-smartcardio PACKAGE = sun.security.smartcardio LIBRARY = j2pcsc PRODUCT = sun diff --git a/jdk/make/sun/security/tools/Makefile b/jdk/make/sun/security/tools/Makefile index 0a8ffabe15c..3380d20e6d8 100644 --- a/jdk/make/sun/security/tools/Makefile +++ b/jdk/make/sun/security/tools/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../../.. +MODULE = security-tools PACKAGE = sun.security.tools PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk @@ -44,3 +45,7 @@ RESOURCE_BUNDLES_JAVA = sun/security/tools/JarSignerResources.java # include $(BUILDDIR)/common/Classes.gmk +build: + $(call make-launcher, keytool, sun.security.tools.KeyTool, , ) + $(call make-launcher, policytool, sun.security.tools.PolicyTool, , ) + diff --git a/jdk/make/sun/serialver/Makefile b/jdk/make/sun/serialver/Makefile index 0906d3e3e14..29c3cceba48 100644 --- a/jdk/make/sun/serialver/Makefile +++ b/jdk/make/sun/serialver/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = serialver PACKAGE = sun.tools.serialver PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/splashscreen/Makefile b/jdk/make/sun/splashscreen/Makefile index 305df2fc2e0..65b3fc388cc 100644 --- a/jdk/make/sun/splashscreen/Makefile +++ b/jdk/make/sun/splashscreen/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = awt PACKAGE = sun.awt LIBRARY = splashscreen PRODUCT = sun diff --git a/jdk/make/sun/text/Makefile b/jdk/make/sun/text/Makefile index 37b8522156a..005587df7a1 100644 --- a/jdk/make/sun/text/Makefile +++ b/jdk/make/sun/text/Makefile @@ -29,6 +29,7 @@ BUILDDIR = ../.. +MODULE = localedata PACKAGE = sun.text PRODUCT = sun diff --git a/jdk/make/sun/tools/Makefile b/jdk/make/sun/tools/Makefile index 3c4d4c98d7d..a6e926daf40 100644 --- a/jdk/make/sun/tools/Makefile +++ b/jdk/make/sun/tools/Makefile @@ -28,6 +28,7 @@ # BUILDDIR = ../.. +MODULE = tools PACKAGE = sun.tools PRODUCT = sun include $(BUILDDIR)/common/Defs.gmk diff --git a/jdk/make/sun/tracing/dtrace/Makefile b/jdk/make/sun/tracing/dtrace/Makefile index cf0dc9a978f..16f09e71978 100644 --- a/jdk/make/sun/tracing/dtrace/Makefile +++ b/jdk/make/sun/tracing/dtrace/Makefile @@ -27,6 +27,7 @@ # Makefile for building dtrace extension # BUILDDIR = ../../.. +MODULE = tracing PACKAGE = sun.tracing.dtrace LIBRARY = jsdt PRODUCT = sun diff --git a/jdk/make/sun/xawt/Makefile b/jdk/make/sun/xawt/Makefile index 3cb408d9907..f9636cd3e66 100644 --- a/jdk/make/sun/xawt/Makefile +++ b/jdk/make/sun/xawt/Makefile @@ -24,6 +24,7 @@ # BUILDDIR = ../.. +MODULE = awt PACKAGE = sun.awt.X11 LIBRARY = mawt LIBRARY_OUTPUT = xawt diff --git a/jdk/src/share/bin/java.c b/jdk/src/share/bin/java.c index 2494ce1ea2e..8f9d2edee1c 100644 --- a/jdk/src/share/bin/java.c +++ b/jdk/src/share/bin/java.c @@ -93,6 +93,7 @@ static int numOptions, maxOptions; * Prototypes for functions internal to launcher. */ static void SetClassPath(const char *s); +static void SetModulesBootClassPath(const char *s); static void SelectVersion(int argc, char **argv, char **main_class); static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile, char **pclassname, int *pret, const char *jvmpath); @@ -277,6 +278,9 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ return(ret); } + /* Set bootclasspath for modules */ + SetModulesBootClassPath(jrepath); + /* Override class path if -jar flag was specified */ if (jarfile != 0) { SetClassPath(jarfile); @@ -693,6 +697,44 @@ SetClassPath(const char *s) JLI_MemFree((char *) s); } +/* + * Set the bootclasspath for modules. + * A temporary workaround until jigsaw is integrated into JDK 7. + */ +static void +SetModulesBootClassPath(const char *jrepath) +{ + char *def, *s; + char pathname[MAXPATHLEN]; + const char separator[] = { FILE_SEPARATOR, '\0' }; + const char *orig = jrepath; + static const char format[] = "-Xbootclasspath/p:%s"; + struct stat statbuf; + + /* return if jre/lib/rt.jar exists */ + sprintf(pathname, "%s%slib%srt.jar", jrepath, separator, separator); + if (stat(pathname, &statbuf) == 0) { + return; + } + + /* return if jre/classes exists */ + sprintf(pathname, "%s%sclasses", jrepath, separator); + if (stat(pathname, &statbuf) == 0) { + return; + } + + /* modularized jre */ + sprintf(pathname, "%s%slib%s*", jrepath, separator, separator); + s = (char *) JLI_WildcardExpandClasspath(pathname); + def = JLI_MemAlloc(sizeof(format) + - 2 /* strlen("%s") */ + + JLI_StrLen(s)); + sprintf(def, format, s); + AddOption(def, NULL); + if (s != orig) + JLI_MemFree((char *) s); +} + /* * The SelectVersion() routine ensures that an appropriate version of * the JRE is running. The specification for the appropriate version diff --git a/jdk/src/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java b/jdk/src/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java index 00cdf1ee6a7..b56aea82e42 100644 --- a/jdk/src/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java +++ b/jdk/src/share/classes/com/sun/jndi/toolkit/corba/CorbaUtils.java @@ -33,10 +33,10 @@ import java.lang.reflect.InvocationTargetException; import java.util.Hashtable; import java.util.Properties; import java.util.Enumeration; -import java.applet.Applet; import org.omg.CORBA.ORB; +import javax.naming.Context; import javax.naming.ConfigurationException; /** @@ -191,16 +191,48 @@ public class CorbaUtils { } // Get Applet from environment - Applet applet = null; if (env != null) { - applet = (Applet) env.get("java.naming.applet"); + Object applet = env.get(Context.APPLET); + if (applet != null) { + // Create ORBs for an applet + return initAppletORB(applet, orbProp); + } } - // Create ORBs using applet and orbProp - if (applet != null) { - return ORB.init(applet, orbProp); - } else { - return ORB.init(new String[0], orbProp); + // Create ORBs using orbProp for a standalone application + return ORB.init(new String[0], orbProp); + } + + /** + * This method returns a new ORB instance for the given applet + * without creating a static dependency on java.applet. + */ + private static ORB initAppletORB(Object applet, Properties orbProp) { + try { + Class appletClass = Class.forName("java.applet.Applet", true, null); + if (!appletClass.isInstance(applet)) { + throw new ClassCastException(applet.getClass().getName()); + } + + // invoke the static method ORB.init(applet, orbProp); + Method method = ORB.class.getMethod("init", appletClass, Properties.class); + return (ORB) method.invoke(null, applet, orbProp); + } catch (ClassNotFoundException e) { + // java.applet.Applet doesn't exist and the applet parameter is + // non-null; so throw CCE + throw new ClassCastException(applet.getClass().getName()); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } else if (cause instanceof Error) { + throw (Error) cause; + } + throw new AssertionError(e); + } catch (IllegalAccessException iae) { + throw new AssertionError(iae); } } diff --git a/jdk/src/share/classes/java/dyn/CallSite.java b/jdk/src/share/classes/java/dyn/CallSite.java index 34624a5a170..b0e5b915579 100644 --- a/jdk/src/share/classes/java/dyn/CallSite.java +++ b/jdk/src/share/classes/java/dyn/CallSite.java @@ -26,6 +26,9 @@ package java.dyn; import sun.dyn.util.BytecodeName; +import sun.dyn.Access; +import sun.dyn.CallSiteImpl; +import sun.dyn.MethodHandleImpl; /** * An {@code invokedynamic} call site, as reified by the @@ -52,15 +55,25 @@ import sun.dyn.util.BytecodeName; * @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle) * @author John Rose, JSR 292 EG */ -public class CallSite { +public class CallSite + // Note: This is an implementation inheritance hack, and will be removed + // with a JVM change which moves the required hidden state onto this class. + extends CallSiteImpl +{ + private static final Access IMPL_TOKEN = Access.getToken(); + + /* + // Fields used only by the JVM. Do not use or change. private Object vmmethod; int callerMID, callerBCI; // supplied by the JVM - MethodHandle target; + private MethodHandle target; + final Object caller; // usually a class final String name; final MethodType type; + */ /** * Make a call site given the parameters from a call to the bootstrap method. @@ -72,16 +85,21 @@ public class CallSite { * @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction */ public CallSite(Object caller, String name, MethodType type) { - this.caller = caller; - this.name = name; - this.type = type; + super(IMPL_TOKEN, caller, name, type); } private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) { site.callerMID = callerMID; site.callerBCI = callerBCI; - if (site.target == null) - site.setTarget(site.initialTarget()); + site.ensureTarget(); + } + private void ensureTarget() { + // Note use of super, which accesses the field directly, + // without deferring to possible subclass overrides. + if (super.getTarget() == null) { + super.setTarget(this.initialTarget()); + super.getTarget().type(); // provoke NPE if still null + } } /** @@ -102,10 +120,11 @@ public class CallSite { /** * Report the current linkage state of the call site. (This is mutable.) - * The value maybe null only if the call site is currently unlinked. - * When a linked call site is invoked, the target method is used directly. - * When an unlinked call site is invoked, its bootstrap method receives - * the call, as if via {@link Linkage#bootstrapInvokeDynamic}. + * The value may not be null after the {@code CallSite} object is returned + * from the bootstrap method of the {@code invokedynamic} instruction. + * When an {@code invokedynamic} instruction is executed, the target method + * of its associated {@code call site} object is invoked directly, + * as if via {@link MethodHandle}{@code .invoke}. *

* The interactions of {@code getTarget} with memory are the same * as of a read from an ordinary variable, such as an array element or a @@ -118,7 +137,7 @@ public class CallSite { * @see #setTarget */ public MethodHandle getTarget() { - return target; + return super.getTarget(); } /** @@ -140,13 +159,13 @@ public class CallSite { */ public void setTarget(MethodHandle target) { checkTarget(target); - this.target = target; + super.setTarget(target); } protected void checkTarget(MethodHandle target) { target.type(); // provoke NPE if (!canSetTarget(target)) - throw new WrongMethodTypeException(String.valueOf(target)); + throw new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type()); } protected boolean canSetTarget(MethodHandle target) { @@ -219,6 +238,10 @@ public class CallSite { @Override public String toString() { - return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]"; + return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]"; } + + // Package-local constant: + static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN). + findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); } diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamic.java b/jdk/src/share/classes/java/dyn/InvokeDynamic.java index 2bec7b7dfe6..bd92f8c5446 100644 --- a/jdk/src/share/classes/java/dyn/InvokeDynamic.java +++ b/jdk/src/share/classes/java/dyn/InvokeDynamic.java @@ -45,6 +45,24 @@ package java.dyn; * class or interface supertype, or an object type; it can never be instantiated. * Logically, it denotes a source of all dynamically typed methods. * It may be viewed as a pure syntactic marker (an importable one) of static calls. + *

+ * Here are some examples of usage: + *

+ * Object x; String s; int i;
+ * x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
+ * s = InvokeDynamic.<String>hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
+ * InvokeDynamic.<void>cogito(); // cogito()V
+ * i = InvokeDynamic.<int>#"op:+"(2, 3); // "op:+"(II)I
+ * 
+ * Each of the above calls generates a single invokedynamic instruction + * with the name-and-type descriptors indicated in the comments. + * The argument types are taken directly from the actual arguments, + * while the return type is taken from the type parameter. + * (This type parameter may be a primtive, and it defaults to {@code Object}.) + * The final example uses a special syntax for uttering non-Java names. + * Any name legal to the JVM may be given between the double quotes. + * None of these calls is complete without a bootstrap method, + * which must be registered by the static initializer of the enclosing class. * @author John Rose, JSR 292 EG */ public final class InvokeDynamic { diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java index 975ba7d3a2d..b6678c386ee 100644 --- a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java +++ b/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java @@ -52,4 +52,16 @@ public class InvokeDynamicBootstrapError extends LinkageError { public InvokeDynamicBootstrapError(String s) { super(s); } + + /** + * Constructs a {@code InvokeDynamicBootstrapError} with the specified + * detail message and cause. + * + * @param s the detail message. + * @param cause the cause. + */ + public InvokeDynamicBootstrapError(String s, Throwable cause) { + super(s); + this.initCause(cause); + } } diff --git a/jdk/src/share/classes/java/dyn/JavaMethodHandle.java b/jdk/src/share/classes/java/dyn/JavaMethodHandle.java index b7432a77521..4c883a53c91 100644 --- a/jdk/src/share/classes/java/dyn/JavaMethodHandle.java +++ b/jdk/src/share/classes/java/dyn/JavaMethodHandle.java @@ -25,6 +25,8 @@ package java.dyn; +import sun.dyn.Access; + /** * A Java method handle extends the basic method handle type with additional * programmer defined methods and fields. @@ -39,31 +41,105 @@ package java.dyn; * of the entry point method handle, with the leading parameter type * omitted. *

- * Here is an example of usage: + * Here is an example of usage, creating a hybrid object/functional datum: *

- *     class Greeter extends JavaMethodHandle {
- *         public void run() { System.out.println("hello, "+greetee); }
- *         private final String greetee;
- *         Greeter(String greetee) {
- *             super(RUN);
- *             this.greetee = greetee;
- *         }
- *         // the entry point function is computed once:
- *         private static final MethodHandle RUN
- *             = MethodHandles.findVirtual(MyMethodHandle.class, "run",
- *                   MethodType.make(void.class));
+ * class Greeter extends JavaMethodHandle {
+ *     private String greeting = "hello";
+ *     public void setGreeting(String s) { greeting = s; }
+ *     public void run() { System.out.println(greeting+", "+greetee); }
+ *     private final String greetee;
+ *     Greeter(String greetee) {
+ *         super(RUN); // alternatively, super("run")
+ *         this.greetee = greetee;
  *     }
- *     Greeter greeter = new Greeter("world");
- *     greeter.run();  // prints "hello, world"
- *     MethodHandle mh = greeter;
- *     mh.invoke();  // also prints "hello, world"
+ *     // the entry point function is computed once:
+ *     private static final MethodHandle RUN
+ *         = MethodHandles.lookup().findVirtual(Greeter.class, "run",
+ *               MethodType.make(void.class));
+ * }
+ * // class Main { public static void main(String... av) { ...
+ * Greeter greeter = new Greeter("world");
+ * greeter.run();  // prints "hello, world"
+ * // Statically typed method handle invocation (most direct):
+ * MethodHandle mh = greeter;
+ * mh.<void>invoke();  // also prints "hello, world"
+ * // Dynamically typed method handle invocation:
+ * MethodHandles.invoke(greeter);  // also prints "hello, world"
+ * greeter.setGreeting("howdy");
+ * mh.invoke();  // prints "howdy, world" (object-like mutable behavior)
  * 
*

- * In this example, the method {@code run} provides the entry point. + * In the example of {@code Greeter}, the method {@code run} provides the entry point. * The entry point need not be a constant value; it may be independently * computed in each call to the constructor. The entry point does not - * even need to be a method on the Java method handle class, though + * even need to be a method on the {@code Greeter} class, though * that is the typical case. + *

+ * The entry point may also be provided symbolically, in which case the the + * {@code JavaMethodHandle} constructor performs the lookup of the entry point. + * This makes it possible to use {@code JavaMethodHandle} to create an anonymous + * inner class: + *

+ * // We can also do this with symbolic names and/or inner classes:
+ * MethodHandles.invoke(new JavaMethodHandle("yow") {
+ *     void yow() { System.out.println("yow, world"); }
+ * });
+ * 
+ *

+ * Here is similar lower-level code which works in terms of a bound method handle. + *

+ *     class Greeter {
+ *         public void run() { System.out.println("hello, "+greetee); }
+ *         private final String greetee;
+ *         Greeter(String greetee) { this.greetee = greetee; }
+ *         // the entry point function is computed once:
+ *         private static final MethodHandle RUN
+ *             = MethodHandles.findVirtual(Greeter.class, "run",
+ *                   MethodType.make(void.class));
+ *     }
+ *     // class Main { public static void main(String... av) { ...
+ *     Greeter greeter = new Greeter("world");
+ *     greeter.run();  // prints "hello, world"
+ *     MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
+ *     mh.invoke();  // also prints "hello, world"
+ * 
+ * Note that the method handle must be separately created as a view on the base object. + * This increases footprint, complexity, and dynamic indirections. + *

+ * Here is a pure functional value expressed most concisely as an anonymous inner class: + *

+ *     // class Main { public static void main(String... av) { ...
+ *     final String greetee = "world";
+ *     MethodHandle greeter = new JavaMethodHandle("run") {
+ *         private void run() { System.out.println("hello, "+greetee); }
+ *     }
+ *     greeter.invoke();  // prints "hello, world"
+ * 
+ *

+ * Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle, + * and instantiated as an anonymous class. The data structure is a handle to 1-D array, + * with a specialized index type (long). It is created by inner class, and uses + * signature-polymorphic APIs throughout. + *

+ *     abstract class AssignableMethodHandle extends JavaMethodHandle {
+ *       private final MethodHandle setter;
+ *       public MethodHandle setter() { return setter; }
+ *       public AssignableMethodHandle(String get, String set) {
+ *         super(get);
+ *         MethodType getType = this.type();
+ *         MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
+ *         this.setter = MethodHandles.publicLookup().bind(this, set, setType);
+ *       }
+ *     }
+ *     // class Main { public static void main(String... av) { ...
+ *     final Number[] stuff = { 123, 456 };
+ *     AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
+ *         public Number get(long i)           { return stuff[(int)i]; }
+ *         public void   set(long i, Object x) {        stuff[(int)i] = x; }
+ *     }
+ *     int x = (Integer) stuffPtr.<Number>invoke(1L);  // 456
+ *     stuffPtr.setter().<void>invoke(0L, (Number) 789);  // replaces 123 with 789
+ * 
* @see MethodHandle * @author John Rose, JSR 292 EG */ @@ -72,12 +148,87 @@ public abstract class JavaMethodHandle // with a JVM change which moves the required hidden behavior onto this class. extends sun.dyn.BoundMethodHandle { + private static final Access IMPL_TOKEN = Access.getToken(); + /** - * When creating a, pass in {@code entryPoint}, any method handle which - * can take the current object - * @param entryPoint + * When creating a {@code JavaMethodHandle}, the actual method handle + * invocation behavior will be delegated to the specified {@code entryPoint}. + * This may be any method handle which can take the newly constructed object + * as a leading parameter. + *

+ * The method handle type of {@code this} (i.e, the fully constructed object) + * will be {@code entryPoint}, minus the leading argument. + * The leading argument will be bound to {@code this} on every method + * handle invocation. + * @param entryPoint the method handle to handle calls */ protected JavaMethodHandle(MethodHandle entryPoint) { - super(entryPoint, 0); + super(entryPoint); + } + + /** + * Create a method handle whose entry point is a non-static method + * visible in the exact (most specific) class of + * the newly constructed object. + *

+ * The method is specified by name and type, as if via this expression: + * {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}. + * The class defining the method might be an anonymous inner class. + *

+ * The method handle type of {@code this} (i.e, the fully constructed object) + * will be the given method handle type. + * A call to {@code this} will invoke the selected method. + * The receiver argument will be bound to {@code this} on every method + * handle invocation. + *

+ * Rationale: + * Although this constructor may seem to be a mere luxury, + * it is not subsumed by the more general constructor which + * takes any {@code MethodHandle} as the entry point argument. + * In order to convert an entry point name to a method handle, + * the self-class of the object is required (in order to do + * the lookup). The self-class, in turn, is generally not + * available at the time of the constructor invocation, + * due to the rules of Java and the JVM verifier. + * One cannot call {@code this.getClass()}, because + * the value of {@code this} is inaccessible at the point + * of the constructor call. (Changing this would require + * change to the Java language, verifiers, and compilers.) + * In particular, this constructor allows {@code JavaMethodHandle}s + * to be created in combination with the anonymous inner class syntax. + * @param entryPointName the name of the entry point method + * @param type (optional) the desired type of the method handle + */ + protected JavaMethodHandle(String entryPointName, MethodType type) { + super(entryPointName, type, true); + + } + + /** + * Create a method handle whose entry point is a non-static method + * visible in the exact (most specific) class of + * the newly constructed object. + *

+ * The method is specified only by name. + * There must be exactly one method of that name visible in the object class, + * either inherited or locally declared. + * (That is, the method must not be overloaded.) + *

+ * The method handle type of {@code this} (i.e, the fully constructed object) + * will be the same as the type of the selected non-static method. + * The receiver argument will be bound to {@code this} on every method + * handle invocation. + *

ISSUE: This signature wildcarding feature does not correspond to + * any MethodHandles.Lookup API element. Can we eliminate it? + * Alternatively, it is useful for naming non-overloaded methods. + * Shall we make type arguments optional in the Lookup methods, + * throwing an error in cases of ambiguity? + *

+ * For this method's rationale, see the documentation + * for {@link #JavaMethodHandle(String,MethodType)}. + * @param entryPointName the name of the entry point method + */ + protected JavaMethodHandle(String entryPointName) { + super(entryPointName, (MethodType) null, false); } } diff --git a/jdk/src/share/classes/java/dyn/Linkage.java b/jdk/src/share/classes/java/dyn/Linkage.java index cbeeb3351de..ed3e35e9594 100644 --- a/jdk/src/share/classes/java/dyn/Linkage.java +++ b/jdk/src/share/classes/java/dyn/Linkage.java @@ -25,7 +25,9 @@ package java.dyn; +import java.dyn.MethodHandles.Lookup; import java.util.WeakHashMap; +import sun.dyn.Access; import sun.reflect.Reflection; import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; @@ -34,6 +36,8 @@ import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; * @author John Rose, JSR 292 EG */ public class Linkage { + private static final Access IMPL_TOKEN = Access.getToken(); + private Linkage() {} // do not instantiate /** @@ -53,19 +57,23 @@ public class Linkage { * call to this method. *

  • The given class is already fully initialized. *
  • The given class is in the process of initialization, in another thread. + *
  • The same {@code CallSite} object has already been returned from + * a bootstrap method call to another {@code invokedynamic} call site. * * Because of these rules, a class may install its own bootstrap method in * a static initializer. + * @param callerClass a class that may have {@code invokedynamic} sites + * @param bootstrapMethod the method to use to bootstrap all such sites */ public static - void registerBootstrapMethod(Class callerClass, MethodHandle mh) { + void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) { Class callc = Reflection.getCallerClass(2); checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod"); - checkBSM(mh); + checkBSM(bootstrapMethod); synchronized (bootstrapMethods) { if (bootstrapMethods.containsKey(callerClass)) throw new IllegalStateException("bootstrap method already declared in "+callerClass); - bootstrapMethods.put(callerClass, mh); + bootstrapMethods.put(callerClass, bootstrapMethod); } } @@ -88,8 +96,9 @@ public class Linkage { public static void registerBootstrapMethod(Class runtime, String name) { Class callc = Reflection.getCallerClass(2); + Lookup lookup = new Lookup(IMPL_TOKEN, callc); MethodHandle bootstrapMethod = - MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE); + lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE); // FIXME: exception processing wrong here checkBSM(bootstrapMethod); Linkage.registerBootstrapMethod(callc, bootstrapMethod); @@ -106,8 +115,9 @@ public class Linkage { public static void registerBootstrapMethod(String name) { Class callc = Reflection.getCallerClass(2); + Lookup lookup = new Lookup(IMPL_TOKEN, callc); MethodHandle bootstrapMethod = - MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE); + lookup.findStatic(callc, name, BOOTSTRAP_METHOD_TYPE); // FIXME: exception processing wrong here checkBSM(bootstrapMethod); Linkage.registerBootstrapMethod(callc, bootstrapMethod); @@ -116,8 +126,7 @@ public class Linkage { /** * PROVISIONAL API, WORK IN PROGRESS: * Report the bootstrap method registered for a given class. - * Returns null if the class has never yet registered a bootstrap method, - * or if the class has explicitly registered a null bootstrap method. + * Returns null if the class has never yet registered a bootstrap method. * Only callers privileged to set the bootstrap method may inquire * about it, because a bootstrap method is potentially a back-door entry * point into its class. @@ -137,12 +146,12 @@ public class Linkage { * {@code (Class, String, MethodType)} returning a {@code CallSite}. */ public static final MethodType BOOTSTRAP_METHOD_TYPE - = MethodType.make(CallSite.class, - Class.class, String.class, MethodType.class); + = MethodType.methodType(CallSite.class, + Class.class, String.class, MethodType.class); private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE - = MethodType.make(Object.class, - CallSite.class, Object[].class); + = MethodType.methodType(Object.class, + CallSite.class, Object[].class); private static final WeakHashMap bootstrapMethods = new WeakHashMap(); @@ -173,8 +182,8 @@ public class Linkage { /** * PROVISIONAL API, WORK IN PROGRESS: - * Invalidate all invokedynamic call sites associated - * with the given class. + * Invalidate all invokedynamic call sites in the bytecodes + * of any methods of the given class. * (These are exactly those sites which report the given class * via the {@link CallSite#callerClass()} method.) *

    diff --git a/jdk/src/share/classes/java/dyn/LinkagePermission.java b/jdk/src/share/classes/java/dyn/LinkagePermission.java index 6ea86f8b555..b2b2031272d 100644 --- a/jdk/src/share/classes/java/dyn/LinkagePermission.java +++ b/jdk/src/share/classes/java/dyn/LinkagePermission.java @@ -88,7 +88,7 @@ public final class LinkagePermission extends BasicPermission { /** * Create a new LinkagePermission with the given name. * The name is the symbolic name of the LinkagePermission, such as - * "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk + * "registerBootstrapMethod", "invalidateCallerClass.*", etc. An asterisk * may appear at the end of the name, following a ".", or by itself, to * signify a wildcard match. * diff --git a/jdk/src/share/classes/java/dyn/MethodHandle.java b/jdk/src/share/classes/java/dyn/MethodHandle.java index 688a9d3fd70..25aa9862e4c 100644 --- a/jdk/src/share/classes/java/dyn/MethodHandle.java +++ b/jdk/src/share/classes/java/dyn/MethodHandle.java @@ -30,6 +30,9 @@ package java.dyn; import sun.dyn.Access; import sun.dyn.MethodHandleImpl; +import static java.dyn.MethodHandles.invokers; // package-private API +import static sun.dyn.MemberName.newIllegalArgumentException; // utility + /** * A method handle is a typed reference to the entry point of a method. *

    @@ -45,8 +48,9 @@ import sun.dyn.MethodHandleImpl; * Every method handle appears as an object containing a method named * invoke, whose signature exactly matches * the method handle's type. - * A normal Java method call (using the invokevirtual instruction) - * can invoke this method from Java source code (if language support is present). + * A Java method call expression, which compiles to an + * invokevirtual instruction, + * can invoke this method from Java source code. *

    * Every call to a method handle specifies an intended method type, * which must exactly match the type of the method handle. @@ -57,6 +61,10 @@ import sun.dyn.MethodHandleImpl; * The call fails with a {@link WrongMethodTypeException} * if the method does not exist, even if there is an invoke * method of a closely similar signature. + * As with other kinds + * of methods in the JVM, signature matching during method linkage + * is exact, and does not allow for language-level implicit conversions + * such as {@code String} to {@code Object} or {@code short} to {@code int}. *

    * A method handle is an unrestricted capability to call a method. * A method handle can be formed on a non-public method by a class @@ -74,6 +82,15 @@ import sun.dyn.MethodHandleImpl; * (after resolving symbolic type names) must exactly match the method type * of the target method. *

    + * Every invoke method always throws {@link Exception}, + * which is to say that there is no static restriction on what a method handle + * can throw. Since the JVM does not distinguish between checked + * and unchecked exceptions (other than by their class, of course), + * there is no particular effect on bytecode shape from ascribing + * checked exceptions to method handle invocations. But in Java source + * code, methods which perform method handle calls must either explicitly + * throw {@code Exception}, or else must catch all checked exceptions locally. + *

    * Bytecode in an extended JVM can directly obtain a method handle * for any accessible method from a ldc instruction * which refers to a CONSTANT_Methodref or @@ -97,6 +114,59 @@ import sun.dyn.MethodHandleImpl; * can also be created. These do not perform virtual lookup based on * receiver type. Such a method handle simulates the effect of * an invokespecial instruction to the same method. + *

    + * Here are some examples of usage: + *

    + * Object x, y; String s; int i;
    + * MethodType mt; MethodHandle mh;
    + * MethodHandles.Lookup lookup = MethodHandles.lookup();
    + * // mt is {(char,char) => String}
    + * mt = MethodType.make(String.class, char.class, char.class);
    + * mh = lookup.findVirtual(String.class, "replace", mt);
    + * // (Ljava/lang/String;CC)Ljava/lang/String;
    + * s = mh.<String>invoke("daddy",'d','n');
    + * assert(s.equals("nanny"));
    + * // weakly typed invocation (using MHs.invoke)
    + * s = (String) MethodHandles.invoke(mh, "sappy", 'p', 'v');
    + * assert(s.equals("savvy"));
    + * // mt is {Object[] => List}
    + * mt = MethodType.make(java.util.List.class, Object[].class);
    + * mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
    + * // mt is {(Object,Object,Object) => Object}
    + * mt = MethodType.makeGeneric(3);
    + * mh = MethodHandles.collectArguments(mh, mt);
    + * // mt is {(Object,Object,Object) => Object}
    + * // (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    + * x = mh.invoke((Object)1, (Object)2, (Object)3);
    + * assert(x.equals(java.util.Arrays.asList(1,2,3)));
    + * // mt is { => int}
    + * mt = MethodType.make(int.class);
    + * mh = lookup.findVirtual(java.util.List.class, "size", mt);
    + * // (Ljava/util/List;)I
    + * i = mh.<int>invoke(java.util.Arrays.asList(1,2,3));
    + * assert(i == 3);
    + * 
    + * Each of the above calls generates a single invokevirtual instruction + * with the name {@code invoke} and the type descriptors indicated in the comments. + * The argument types are taken directly from the actual arguments, + * while the return type is taken from the type parameter. + * (This type parameter may be a primitive, and it defaults to {@code Object}.) + *

    + * A note on generic typing: Method handles do not represent + * their function types in terms of Java parameterized (generic) types, + * because there are three mismatches between function types and parameterized + * Java types. + *

      + *
    1. Method types range over all possible arities, + * from no arguments to an arbitrary number of arguments. + * Generics are not variadic, and so cannot represent this.
    2. + *
    3. Method types can specify arguments of primitive types, + * which Java generic types cannot range over.
    4. + *
    5. Higher order functions over method handles (combinators) are + * often generic across a wide range of function types, including + * those of multiple arities. It is impossible to represent such + * genericity with a Java type parameter.
    6. + *
    * * @see MethodType * @see MethodHandles @@ -107,17 +177,19 @@ public abstract class MethodHandle // with a JVM change which moves the required hidden state onto this class. extends MethodHandleImpl { - // interface MethodHandle> - // { T type(); public R invoke(A...); } + private static Access IMPL_TOKEN = Access.getToken(); - final private MethodType type; + // interface MethodHandle + // { MethodType type(); public R invoke(A...) throws X; } + + private MethodType type; /** * Report the type of this method handle. * Every invocation of this method handle must exactly match this type. * @return the method handle type */ - public MethodType type() { + public final MethodType type() { return type; } @@ -130,6 +202,369 @@ public abstract class MethodHandle */ protected MethodHandle(Access token, MethodType type) { super(token); + Access.check(token); this.type = type; } + + private void initType(MethodType type) { + type.getClass(); // elicit NPE + if (this.type != null) throw new InternalError(); + this.type = type; + } + + static { + // This hack allows the implementation package special access to + // the internals of MethodHandle. In particular, the MTImpl has all sorts + // of cached information useful to the implementation code. + MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() { + public void initType(MethodHandle mh, MethodType type) { mh.initType(type); } + }); + } + + /** The string of a direct method handle is the simple name of its target method. + * The string of an adapter or bound method handle is the string of its + * target method handle. + * The string of a Java method handle is the string of its entry point method, + * unless the Java method handle overrides the toString method. + */ + @Override + public String toString() { + return MethodHandleImpl.getNameString(IMPL_TOKEN, this); + } + + //// First draft of the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009. + //// Implementations here currently delegate to statics in MethodHandles. Some of those statics + //// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom + //// not present in the Kernel API. + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Perform an exact invocation. The signature at the call site of {@code invokeExact} must + * exactly match this method handle's {@code type}. + * No conversions are allowed on arguments or return values. + * This is not yet implemented, pending required compiler and JVM support. + */ + public final T invokeExact(Object... arguments) throws Throwable { + // This is an approximate implementation, which discards the caller's signature and refuses the call. + throw new InternalError("not yet implemented"); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Perform a generic invocation. The signature at the call site of {@code invokeExact} must + * have the same arity as this method handle's {@code type}. + * The same conversions are allowed on arguments or return values as are supported by + * by {@link MethodHandles#convertArguments}. + * If the call site signature exactly matches this method handle's {@code type}, + * the call proceeds as if by {@link #invokeExact}. + * This is not fully implemented, pending required compiler and JVM support. + */ + // This is an approximate implementation, which discards the caller's signature. + // When it is made signature polymorphic, the overloadings will disappear. + public final T invokeGeneric() throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this); + } + public final T invokeGeneric(Object a0) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0); + } + public final T invokeGeneric(Object a0, Object a1) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1); + } + public final T invokeGeneric(Object a0, Object a1, Object a2) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4, a5); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { + MethodHandle invoker = invokers(this.type()).genericInvoker(); + return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Perform a varargs invocation, passing the arguments in the given array + * to the method handle, as if via {@link #invokeGeneric} from a call site + * which mentions only the type {@code Object}, and whose arity is the length + * of the argument array. + *

    + * The length of the arguments array must equal the parameter count + * of the target's type. + * The arguments array is spread into separate arguments. + *

    + * In order to match the type of the target, the following argument + * conversions are applied as necessary: + *

      + *
    • reference casting + *
    • unboxing + *
    + * The following conversions are not applied: + *
      + *
    • primitive conversions (e.g., {@code byte} to {@code int} + *
    • varargs conversions other than the initial spread + *
    • any application-specific conversions (e.g., string to number) + *
    + * The result returned by the call is boxed if it is a primitive, + * or forced to null if the return type is void. + *

    + * This call is equivalent to the following code: + *

    +     *   MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true);
    +     *   Object result = invoker.invoke(this, arguments);
    +     * 
    + * @param arguments the arguments to pass to the target + * @return the result returned by the target + * @see MethodHandles#genericInvoker + */ + public final Object invokeVarargs(Object[] arguments) throws Throwable { + int argc = arguments == null ? 0 : arguments.length; + MethodType type = type(); + if (argc <= 10) { + MethodHandle invoker = MethodHandles.invokers(type).genericInvoker(); + switch (argc) { + case 0: return invoker.invoke(this); + case 1: return invoker.invoke(this, + arguments[0]); + case 2: return invoker.invoke(this, + arguments[0], arguments[1]); + case 3: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2]); + case 4: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3]); + case 5: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4]); + case 6: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4], arguments[5]); + case 7: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4], arguments[5], + arguments[6]); + case 8: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4], arguments[5], + arguments[6], arguments[7]); + case 9: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4], arguments[5], + arguments[6], arguments[7], arguments[8]); + case 10: return invoker.invoke(this, + arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4], arguments[5], + arguments[6], arguments[7], arguments[8], + arguments[9]); + } + } + + // more than ten arguments get boxed in a varargs list: + MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0); + return invoker.invoke(this, arguments); + } + /** Equivalent to {@code invokeVarargs(arguments.toArray())}. */ + public final Object invokeVarargs(java.util.List arguments) throws Throwable { + return invokeVarargs(arguments.toArray()); + } + + /* --- this is intentionally NOT a javadoc yet --- + * PROVISIONAL API, WORK IN PROGRESS: + * Produce an adapter method handle which adapts the type of the + * current method handle to a new type by pairwise argument conversion. + * The original type and new type must have the same number of arguments. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type. + *

    + * If the original type and new type are equal, returns {@code this}. + *

    + * The following conversions are applied as needed both to + * arguments and return types. Let T0 and T1 be the differing + * new and old parameter types (or old and new return types) + * for corresponding values passed by the new and old method types. + * Given those types T0, T1, one of the following conversions is applied + * if possible: + *

      + *
    • If T0 and T1 are references, and T1 is not an interface type, + * then a cast to T1 is applied. + * (The types do not need to be related in any particular way.) + *
    • If T0 and T1 are references, and T1 is an interface type, + * then the value of type T0 is passed as a T1 without a cast. + * (This treatment of interfaces follows the usage of the bytecode verifier.) + *
    • If T0 and T1 are primitives, then a Java casting + * conversion (JLS 5.5) is applied, if one exists. + *
    • If T0 and T1 are primitives and one is boolean, + * the boolean is treated as a one-bit unsigned integer. + * (This treatment follows the usage of the bytecode verifier.) + * A conversion from another primitive type behaves as if + * it first converts to byte, and then masks all but the low bit. + *
    • If T0 is a primitive and T1 a reference, a boxing + * conversion is applied if one exists, possibly followed by + * an reference conversion to a superclass. + * T1 must be a wrapper class or a supertype of one. + * If T1 is a wrapper class, T0 is converted if necessary + * to T1's primitive type by one of the preceding conversions. + * Otherwise, T0 is boxed, and its wrapper converted to T1. + *
    • If T0 is a reference and T1 a primitive, an unboxing + * conversion is applied if one exists, possibly preceded by + * a reference conversion to a wrapper class. + * T0 must be a wrapper class or a supertype of one. + * If T0 is a wrapper class, its primitive value is converted + * if necessary to T1 by one of the preceding conversions. + * Otherwise, T0 is converted directly to the wrapper type for T1, + * which is then unboxed. + *
    • If the return type T1 is void, any returned value is discarded + *
    • If the return type T0 is void and T1 a reference, a null value is introduced. + *
    • If the return type T0 is void and T1 a primitive, a zero value is introduced. + *
    + *

    + */ + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce an adapter method handle which adapts the type of the + * current method handle to a new type by pairwise argument conversion. + * The original type and new type must have the same number of arguments. + * The resulting method handle is guaranteed to confess a type + * which is equal to the desired new type. + *

    + * If the original type and new type are equal, returns {@code this}. + *

    + * This method is equivalent to {@link MethodHandles#convertArguments}. + * @param newType the expected type of the new method handle + * @return a method handle which delegates to {@code this} after performing + * any necessary argument conversions, and arranges for any + * necessary return value conversions + * @throws IllegalArgumentException if the conversion cannot be made + * @see MethodHandles#convertArguments + */ + public final MethodHandle asType(MethodType newType) { + return MethodHandles.convertArguments(this, newType); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts, as its target, + * the current method handle. The type of the adapter will be + * the same as the type of the target, except that all but the first + * {@code keepPosArgs} parameters of the target's type are replaced + * by a single array parameter of type {@code Object[]}. + * Thus, if {@code keepPosArgs} is zero, the adapter will take all + * arguments in a single object array. + *

    + * When called, the adapter replaces a trailing array argument + * by the array's elements, each as its own argument to the target. + * (The order of the arguments is preserved.) + * They are converted pairwise by casting and/or unboxing + * (as if by {@link MethodHandles#convertArguments}) + * to the types of the trailing parameters of the target. + * Finally the target is called. + * What the target eventually returns is returned unchanged by the adapter. + *

    + * Before calling the target, the adapter verifies that the array + * contains exactly enough elements to provide a correct argument count + * to the target method handle. + * (The array may also be null when zero elements are required.) + * @param keepPosArgs the number of leading positional arguments to preserve + * @return a new method handle which spreads its final argument, + * before calling the original method handle + * @throws IllegalArgumentException if target does not have at least + * {@code keepPosArgs} parameter types + */ + public final MethodHandle asSpreader(int keepPosArgs) { + MethodType oldType = type(); + int nargs = oldType.parameterCount(); + MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs); + newType = newType.insertParameterTypes(keepPosArgs, Object[].class); + return MethodHandles.spreadArguments(this, newType); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which adapts, as its target, + * the current method handle. The type of the adapter will be + * the same as the type of the target, except that a single trailing + * array parameter of type {@code Object[]} is replaced by + * {@code spreadArrayArgs} parameters of type {@code Object}. + *

    + * When called, the adapter replaces its trailing {@code spreadArrayArgs} + * arguments by a single new {@code Object} array, whose elements + * comprise (in order) the replaced arguments. + * Finally the target is called. + * What the target eventually returns is returned unchanged by the adapter. + *

    + * (The array may also be a shared constant when {@code spreadArrayArgs} is zero.) + * @param spreadArrayArgs the number of arguments to spread from the trailing array + * @return a new method handle which collects some trailing argument + * into an array, before calling the original method handle + * @throws IllegalArgumentException if the last argument of the target + * is not {@code Object[]} + * @throws IllegalArgumentException if {@code spreadArrayArgs} is not + * a legal array size + * @deprecated Provisional and unstable; use {@link MethodHandles#collectArguments}. + */ + public final MethodHandle asCollector(int spreadArrayArgs) { + MethodType oldType = type(); + int nargs = oldType.parameterCount(); + MethodType newType = oldType.dropParameterTypes(nargs-1, nargs); + newType = newType.insertParameterTypes(nargs-1, MethodType.genericMethodType(spreadArrayArgs).parameterArray()); + return MethodHandles.collectArguments(this, newType); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which binds the given argument + * to the current method handle as target. + * The type of the bound handle will be + * the same as the type of the target, except that a single leading + * reference parameter will be omitted. + *

    + * When called, the bound handle inserts the given value {@code x} + * as a new leading argument to the target. The other arguments are + * also passed unchanged. + * What the target eventually returns is returned unchanged by the bound handle. + *

    + * The reference {@code x} must be convertible to the first parameter + * type of the target. + * @param x the value to bind to the first argument of the target + * @return a new method handle which collects some trailing argument + * into an array, before calling the original method handle + * @throws IllegalArgumentException if the target does not have a + * leading parameter type that is a reference type + * @throws ClassCastException if {@code x} cannot be converted + * to the leading parameter type of the target + * @deprecated Provisional and unstable; use {@link MethodHandles#insertArguments}. + */ + public final MethodHandle bindTo(Object x) { + return MethodHandles.insertArguments(this, 0, x); + } } diff --git a/jdk/src/share/classes/java/dyn/MethodHandles.java b/jdk/src/share/classes/java/dyn/MethodHandles.java index 3a9f7ed3e97..06ac809a974 100644 --- a/jdk/src/share/classes/java/dyn/MethodHandles.java +++ b/jdk/src/share/classes/java/dyn/MethodHandles.java @@ -34,6 +34,7 @@ import sun.dyn.util.Wrapper; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.List; import java.util.ArrayList; import java.util.Arrays; import sun.dyn.Invokers; @@ -44,17 +45,14 @@ import static sun.dyn.MemberName.newNoAccessException; /** * Fundamental operations and utilities for MethodHandle. + * They fall into several categories: + *

      + *
    • Reifying methods and fields. This is subject to access checks. + *
    • Invoking method handles on dynamically typed arguments and/or varargs arrays. + *
    • Combining or transforming pre-existing method handles into new ones. + *
    • Miscellaneous emulation of common JVM operations or control flow patterns. + *
    *

    - * API Note: The matching of method types in this API cannot - * be completely checked by Java's generic type system for three reasons: - *

      - *
    1. Method types range over all possible arities, - * from no arguments to an arbitrary number of arguments. - * Generics are not variadic, and so cannot represent this.
    2. - *
    3. Method types can specify arguments of primitive types, - * which Java generic types cannot range over.
    4. - *
    5. Method types can optionally specify varargs (ellipsis).
    6. - *
    * @author John Rose, JSR 292 EG */ public class MethodHandles { @@ -68,12 +66,22 @@ public class MethodHandles { //// Method handle creation from ordinary methods. + /** Create a {@link Lookup} lookup object on the caller. + * + */ public static Lookup lookup() { return new Lookup(); } + /** Version of lookup which is trusted minimally. + * It can only be used to create method handles to + * publicly accessible members. + */ + public static Lookup publicLookup() { + return Lookup.PUBLIC_LOOKUP; + } + /** - * PROVISIONAL API, WORK IN PROGRESS: * A factory object for creating method handles, when the creation * requires access checking. Method handles do not perform * access checks when they are called; this is a major difference @@ -121,7 +129,8 @@ public class MethodHandles { /** Which class is performing the lookup? It is this class against * which checks are performed for visibility and access permissions. *

    - * This value is null if and only if this lookup is {@link #PUBLIC_LOOKUP}. + * This value is null if and only if this lookup was produced + * by {@link MethodHandles#publicLookup}. */ public Class lookupClass() { return lookupClass; @@ -135,23 +144,46 @@ public class MethodHandles { * an access$N method. */ Lookup() { - Class caller = getCallerClassAtEntryPoint(); - // make sure we haven't accidentally picked up this class: - checkUnprivilegedlookupClass(caller); - this.lookupClass = caller; + this(IMPL_TOKEN, getCallerClassAtEntryPoint()); + } + + Lookup(Access token, Class lookupClass) { + // make sure we haven't accidentally picked up a privileged class: + checkUnprivilegedlookupClass(lookupClass); + this.lookupClass = lookupClass; + } + + /** + * Create a lookup on the specified class. + * The result is guaranteed to have no more access privileges + * than the original. + */ + public Lookup in(Class newLookupClass) { + if (this == PUBLIC_LOOKUP) return PUBLIC_LOOKUP; + if (newLookupClass == null) return PUBLIC_LOOKUP; + if (newLookupClass == lookupClass) return this; + if (this != IMPL_LOOKUP) { + if (!VerifyAccess.isSamePackage(lookupClass, newLookupClass)) + throw newNoAccessException(new MemberName(newLookupClass), this); + checkUnprivilegedlookupClass(newLookupClass); + } + return new Lookup(newLookupClass); } private Lookup(Class lookupClass) { this.lookupClass = lookupClass; } + // Make sure outer class is initialized first. + static { IMPL_TOKEN.getClass(); } + private static final Class PUBLIC_ONLY = sun.dyn.empty.Empty.class; /** Version of lookup which is trusted minimally. * It can only be used to create method handles to * publicly accessible members. */ - public static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY); + static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY); /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(null); @@ -178,12 +210,16 @@ public class MethodHandles { // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint, // 2: Lookup., 3: MethodHandles.*, 4: caller // Note: This should be the only use of getCallerClass in this file. + assert(Reflection.getCallerClass(CALLER_DEPTH-1) == MethodHandles.class); return Reflection.getCallerClass(CALLER_DEPTH); } /** * Produce a method handle for a static method. * The type of the method handle will be that of the method. + * (Since static methods do not take receivers, there is no + * additional receiver argument inserted into the method handle type, + * as there would be with {@linkplain #findVirtual} or {@linkplain #findSpecial}.) * The method and all its argument types must be accessible to the lookup class. * If the method's class has not yet been initialized, that is done * immediately, before the method handle is returned. @@ -196,10 +232,11 @@ public class MethodHandles { */ public MethodHandle findStatic(Class defc, String name, MethodType type) throws NoAccessException { - MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass); - checkStatic(true, method, lookupClass); + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass()); + VerifyAccess.checkName(method, this); + checkStatic(true, method, this); //throw NoSuchMethodException - return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass()); } /** @@ -228,9 +265,10 @@ public class MethodHandles { * @exception NoAccessException if the method does not exist or access checking fails */ public MethodHandle findVirtual(Class defc, String name, MethodType type) throws NoAccessException { - MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass); - checkStatic(false, method, lookupClass); - return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass); + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), true, lookupClass()); + VerifyAccess.checkName(method, this); + checkStatic(false, method, this); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass()); } /** @@ -259,15 +297,17 @@ public class MethodHandles { */ public MethodHandle findSpecial(Class defc, String name, MethodType type, Class specialCaller) throws NoAccessException { - checkSpecialCaller(specialCaller, lookupClass); - MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller); - checkStatic(false, method, lookupClass); + checkSpecialCaller(specialCaller, this); + Lookup slookup = this.in(specialCaller); + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, slookup.lookupClass()); + VerifyAccess.checkName(method, this); + checkStatic(false, method, this); if (name.equals("")) { throw newNoAccessException("cannot directly invoke a constructor", method, null); } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) { - throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass); + throw newNoAccessException("method must be in a superclass of lookup class", method, slookup.lookupClass()); } - return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, slookup.lookupClass()); } /** @@ -275,13 +315,19 @@ public class MethodHandles { * The receiver must have a supertype {@code defc} in which a method * of the given name and type is accessible to the lookup class. * The method and all its argument types must be accessible to the lookup class. - * The type of the method handle will be that of the method. - * The given receiver will be bound into the method handle. + * The type of the method handle will be that of the method, + * without any insertion of an additional receiver parameter. + * The given receiver will be bound into the method handle, + * so that every call to the method handle will invoke the + * requested method on the given receiver. *

    - * Equivalent to the following expression: + * This is equivalent to the following expression: * - * {@link #insertArgument}({@link #findVirtual}(defc, name, type), receiver) + * {@link #insertArguments}({@link #findVirtual}(defc, name, type), receiver) * + * where {@code defc} is either {@code receiver.getClass()} or a super + * type of that class, in which the requested method is accessible + * to the lookup class. * @param receiver the object from which the method is accessed * @param name the name of the method * @param type the type of the method, with the receiver argument omitted @@ -292,16 +338,18 @@ public class MethodHandles { public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { Class rcvc = receiver.getClass(); // may get NPE MemberName reference = new MemberName(rcvc, name, type); - MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass); - checkStatic(false, method, lookupClass); - MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass); + MemberName method = IMPL_NAMES.resolveOrFail(reference, true, lookupClass()); + VerifyAccess.checkName(method, this); + checkStatic(false, method, this); + MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClass()); MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); if (bmh == null) - throw newNoAccessException(method, lookupClass); + throw newNoAccessException(method, this); return bmh; } /** + * PROVISIONAL API, WORK IN PROGRESS: * Make a direct method handle to m, if the lookup class has permission. * If m is non-static, the receiver argument is treated as an initial argument. * If m is virtual, overriding is respected on every call. @@ -316,10 +364,11 @@ public class MethodHandles { * @exception NoAccessException if access checking fails */ public MethodHandle unreflect(Method m) throws NoAccessException { - return unreflectImpl(new MemberName(m), m.isAccessible(), true, lookupClass); + return unreflectImpl(new MemberName(m), m.isAccessible(), true, false, this); } /** + * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle for a reflected method. * It will bypass checks for overriding methods on the receiver, * as if by the {@code invokespecial} instruction. @@ -333,37 +382,41 @@ public class MethodHandles { * @exception NoAccessException if access checking fails */ public MethodHandle unreflectSpecial(Method m, Class specialCaller) throws NoAccessException { - checkSpecialCaller(specialCaller, lookupClass); + checkSpecialCaller(specialCaller, this); + Lookup slookup = this.in(specialCaller); MemberName mname = new MemberName(m); - checkStatic(false, mname, lookupClass); - return unreflectImpl(mname, m.isAccessible(), false, specialCaller); + checkStatic(false, mname, this); + return unreflectImpl(mname, m.isAccessible(), false, false, slookup); } /** + * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle for a reflected constructor. - * The type of the method handle will be that of the constructor. + * The type of the method handle will be that of the constructor, + * with the return type changed to the declaring class. * The method handle will perform a {@code newInstance} operation, * creating a new instance of the constructor's class on the * arguments passed to the method handle. *

    * If the constructor's {@code accessible} flag is not set, - * access checking is performed immediately on behalf of the lookup class, - * as if {@code invokespecial} instruction were being linked. + * access checking is performed immediately on behalf of the lookup class. * @param ctor the reflected constructor * @return a method handle which can invoke the reflected constructor * @exception NoAccessException if access checking fails */ public MethodHandle unreflectConstructor(Constructor ctor) throws NoAccessException { MemberName m = new MemberName(ctor); - return unreflectImpl(m, ctor.isAccessible(), false, lookupClass); + return unreflectImpl(m, ctor.isAccessible(), false, false, this); } /** * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle giving read access to a reflected field. * The type of the method handle will have a return type of the field's - * value type. Its sole argument will be the field's containing class - * (but only if it is non-static). + * value type. + * If the field is static, the method handle will take no arguments. + * Otherwise, its single argument will be the instance containing + * the field. * If the method's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. * @param f the reflected field @@ -371,16 +424,18 @@ public class MethodHandles { * @exception NoAccessException if access checking fails */ public MethodHandle unreflectGetter(Field f) throws NoAccessException { - return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), false, lookupClass); + MemberName m = new MemberName(f); + return unreflectImpl(m, f.isAccessible(), false, false, this); } /** * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle giving write access to a reflected field. * The type of the method handle will have a void return type. - * Its last argument will be the field's value type. - * Its other argument will be the field's containing class - * (but only if it is non-static). + * If the field is static, the method handle will take a single + * argument, of the field's value type, the value to be stored. + * Otherwise, the two arguments will be the instance containing + * the field, and the value to be stored. * If the method's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. * @param f the reflected field @@ -388,59 +443,75 @@ public class MethodHandles { * @exception NoAccessException if access checking fails */ public MethodHandle unreflectSetter(Field f) throws NoAccessException { - return MethodHandleImpl.accessField(IMPL_TOKEN, new MemberName(f), true, lookupClass); + MemberName m = new MemberName(f); + return unreflectImpl(m, f.isAccessible(), false, true, this); } } static /*must not be public*/ - MethodHandle findStaticFrom(Class lookupClass, + MethodHandle findStaticFrom(Lookup lookup, Class defc, String name, MethodType type) throws NoAccessException { - MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookupClass); - checkStatic(true, method, lookupClass); - return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClass); + MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type, Modifier.STATIC), true, lookup.lookupClass()); + VerifyAccess.checkName(method, lookup); + checkStatic(true, method, lookup); + return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookup.lookupClass()); } - static void checkStatic(boolean wantStatic, MemberName m, Class lookupClass) { + static void checkStatic(boolean wantStatic, MemberName m, Lookup lookup) { if (wantStatic != m.isStatic()) { String message = wantStatic ? "expected a static method" : "expected a non-static method"; - throw newNoAccessException(message, m, lookupClass); + throw newNoAccessException(message, m, lookup.lookupClass()); } } - static void checkSpecialCaller(Class specialCaller, Class lookupClass) { - if (lookupClass == Lookup.IMPL_LOOKUP.lookupClass()) + static void checkSpecialCaller(Class specialCaller, Lookup lookup) { + if (lookup == Lookup.IMPL_LOOKUP) return; // privileged action - if (lookupClass == null || // public-only access - !VerifyAccess.isSamePackageMember(specialCaller, lookupClass)) - throw newNoAccessException("no private access", new MemberName(specialCaller), lookupClass); + assert(lookup.lookupClass() != null); + if (!VerifyAccess.isSamePackageMember(specialCaller, lookup.lookupClass())) + throw newNoAccessException("no private access", new MemberName(specialCaller), lookup.lookupClass()); } // Helper for creating handles on reflected methods and constructors. static MethodHandle unreflectImpl(MemberName m, boolean isAccessible, - boolean doDispatch, Class lookupClass) { - MethodType mtype = m.getInvocationType(); + boolean doDispatch, boolean isSetter, Lookup lookup) { + MethodType narrowMethodType = null; Class defc = m.getDeclaringClass(); + boolean isSpecialInvoke = m.isInvocable() && !doDispatch; int mods = m.getModifiers(); if (m.isStatic()) { if (!isAccessible && - VerifyAccess.isAccessible(defc, mods, false, lookupClass) == null) - throw newNoAccessException(m, lookupClass); + VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), false) == null) + throw newNoAccessException(m, lookup); } else { Class constraint; if (isAccessible) { // abbreviated access check for "unlocked" method - constraint = doDispatch ? defc : lookupClass; + constraint = doDispatch ? defc : lookup.lookupClass(); } else { - constraint = VerifyAccess.isAccessible(defc, mods, doDispatch, lookupClass); + constraint = VerifyAccess.isAccessible(defc, mods, lookup.lookupClass(), isSpecialInvoke); + } + if (constraint == null) { + throw newNoAccessException(m, lookup); } if (constraint != defc && !constraint.isAssignableFrom(defc)) { if (!defc.isAssignableFrom(constraint)) - throw newNoAccessException("receiver must be in caller class", m, lookupClass); - mtype = mtype.changeParameterType(0, constraint); + throw newNoAccessException("receiver must be in caller class", m, lookup.lookupClass()); + if (m.isInvocable()) + narrowMethodType = m.getInvocationType().changeParameterType(0, constraint); + else if (m.isField()) + narrowMethodType = (!isSetter + ? MethodType.methodType(m.getFieldType(), constraint) + : MethodType.methodType(void.class, constraint, m.getFieldType())); } } - return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookupClass); + if (m.isInvocable()) + return MethodHandleImpl.findMethod(IMPL_TOKEN, m, doDispatch, lookup.lookupClass()); + else if (m.isField()) + return MethodHandleImpl.accessField(IMPL_TOKEN, m, isSetter, lookup.lookupClass()); + else + throw new InternalError(); } /** @@ -472,138 +543,104 @@ public class MethodHandles { return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true); } - /// method handle invocation (reflective style) /** - * PROVISIONAL API, WORK IN PROGRESS: - * Call the {@code invoke} method of a given method handle, - * with arguments that exactly match the parameter types of the method handle. - * The length of the arguments array must equal the parameter count - * of the target's type. - * The arguments array is spread into separate arguments, and - * basic reference and unboxing conversions are applied. - *

    - * In order to match the type of the target, the following argument - * conversions are applied as necessary: - *

      - *
    • reference casting - *
    • unboxing - *
    - * The following conversions are not applied: - *
      - *
    • primitive conversions (e.g., {@code byte} to {@code int} - *
    • varargs conversions other than the initial spread - *
    • any application-specific conversions (e.g., string to number) - *
    - * The result returned by the call is boxed if it is a primitive, - * or forced to null if the return type is void. - *

    - * This call is a convenience method for the following code: - *

    -     *   MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
    -     *   Object result = invoker.invoke(arguments);
    -     * 
    - * @param target the method handle to invoke - * @param arguments the arguments to pass to the target - * @return the result returned by the target + * @deprecated Alias for MethodHandle.invokeVarargs. */ + @Deprecated public static - Object invoke(MethodHandle target, Object... arguments) { - int argc = arguments == null ? 0 : arguments.length; - MethodType type = target.type(); - if (argc <= 4) { - MethodHandle invoker = invokers(type).genericInvoker(); - switch (argc) { - case 0: return invoker.invoke(target); - case 1: return invoker.invoke(target, - arguments[0]); - case 2: return invoker.invoke(target, - arguments[0], arguments[1]); - case 3: return invoker.invoke(target, - arguments[0], arguments[1], arguments[2]); - case 4: return invoker.invoke(target, - arguments[0], arguments[1], arguments[2], arguments[3]); - } - } - MethodHandle invoker = invokers(type).varargsInvoker(); - return invoker.invoke(target, arguments); + Object invokeVarargs(MethodHandle target, Object... arguments) throws Throwable { + return target.invokeVarargs(arguments); } + /** + * @deprecated Alias for MethodHandle.invokeVarargs. + */ + @Deprecated public static - Object invoke_0(MethodHandle target) { - MethodHandle invoker = invokers(target.type()).genericInvoker(); - return invoker.invoke(target); - } - public static - Object invoke_1(MethodHandle target, Object a0) { - MethodHandle invoker = invokers(target.type()).genericInvoker(); - return invoker.invoke(target, a0); - } - public static - Object invoke_2(MethodHandle target, Object a0, Object a1) { - MethodHandle invoker = invokers(target.type()).genericInvoker(); - return invoker.invoke(target, a0, a1); - } - public static - Object invoke_3(MethodHandle target, Object a0, Object a1, Object a2) { - MethodHandle invoker = invokers(target.type()).genericInvoker(); - return invoker.invoke(target, a0, a1, a2); - } - public static - Object invoke_4(MethodHandle target, Object a0, Object a1, Object a2, Object a3) { - MethodHandle invoker = invokers(target.type()).genericInvoker(); - return invoker.invoke(target, a0, a1, a2, a3); + Object invoke(MethodHandle target, Object... arguments) throws Throwable { + return target.invokeVarargs(arguments); } /** * PROVISIONAL API, WORK IN PROGRESS: - * Give a method handle which will invoke any method handle of the + * Produce a method handle which will invoke any method handle of the * given type on a standard set of {@code Object} type arguments. - * The the resulting invoker will be a method handle with the following + * The resulting invoker will be a method handle with the following * arguments: *
      *
    • a single {@code MethodHandle} target - *
    • zero or more {@code Object} values - *
    • an optional {@code Object[]} array containing more arguments + *
    • zero or more {@code Object} values (one for each argument in {@code type}) *
    - * The invoker will spread the varargs array (if present), apply - * reference casts as necessary, and unbox primitive arguments. + * The invoker will apply reference casts as necessary and unbox primitive arguments, + * as if by {@link #convertArguments}. * The return value of the invoker will be an {@code Object} reference, * boxing a primitive value if the original type returns a primitive, * and always null if the original type returns void. *

    - * This is a convenience method equivalent to the following code: - *

    +     * This method is equivalent to the following code (though it may be more efficient):
    +     * 

          * MethodHandle invoker = exactInvoker(type);
    -     * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
    +     * MethodType genericType = type.generic();
          * genericType = genericType.insertParameterType(0, MethodHandle.class);
    -     * if (!varargs)
    -     *     return convertArguments(invoker, genericType);
    -     * else
    -     *     return spreadArguments(invoker, genericType);
    -     * 
    - * @param type the desired target type - * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments - * @param varargs if true, the invoker will accept a final {@code Object[]} argument + * return convertArguments(invoker, genericType); + *
    + * @param type the type of target methods which the invoker will apply to * @return a method handle suitable for invoking any method handle of the given type */ static public - MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) { + MethodHandle genericInvoker(MethodType type) { return invokers(type).genericInvoker(); } /** * PROVISIONAL API, WORK IN PROGRESS: - * Give a method handle which will take a invoke any method handle of the + * Produce a method handle which will invoke any method handle of the + * given type on a standard set of {@code Object} type arguments + * and a single trailing {@code Object[]} array. + * The resulting invoker will be a method handle with the following + * arguments: + *
      + *
    • a single {@code MethodHandle} target + *
    • zero or more {@code Object} values (counted by {@code objectArgCount}) + *
    • an {@code Object[]} array containing more arguments + *
    + * The invoker will spread the varargs array, apply + * reference casts as necessary, and unbox primitive arguments. + * The return value of the invoker will be an {@code Object} reference, + * boxing a primitive value if the original type returns a primitive, + * and always null if the original type returns void. + *

    + * This method is equivalent to the following code (though it may be more efficient): + *

    +     * MethodHandle invoker = exactInvoker(type);
    +     * MethodType vaType = MethodType.makeGeneric(objectArgCount, true);
    +     * vaType = vaType.insertParameterType(0, MethodHandle.class);
    +     * return spreadArguments(invoker, vaType);
    +     * 
    + * @param type the desired target type + * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments + * @return a method handle suitable for invoking any method handle of the given type + */ + static public + MethodHandle varargsInvoker(MethodType type, int objectArgCount) { + if (objectArgCount < 0 || objectArgCount > type.parameterCount()) + throw new IllegalArgumentException("bad argument count "+objectArgCount); + return invokers(type).varargsInvoker(objectArgCount); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle which will take a invoke any method handle of the * given type. The resulting invoker will have a type which is * exactly equal to the desired type, except that it will accept * an additional leading argument of type {@code MethodHandle}. *

    - * This is a convenience method equivalent to the following code: - *

    -     *     MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
    -     * 
    + * This method is equivalent to the following code (though it may be more efficient): + *

    +     * lookup().findVirtual(MethodHandle.class, "invoke", type);
    +     * 
    * @param type the desired target type * @return a method handle suitable for invoking any method handle of the given type */ @@ -612,7 +649,30 @@ public class MethodHandles { return invokers(type).exactInvoker(); } - static private Invokers invokers(MethodType type) { + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Produce a method handle equivalent to an invokedynamic instruction + * which has been linked to the given call site. + * Along with {@link Lookup#findVirtual}, {@link Lookup#findStatic}, + * and {@link Lookup#findSpecial}, this completes the emulation + * of the JVM's {@code invoke} instructions. + *

    This method is equivalent to the following code: + *

    +     * MethodHandle getTarget, invoker, result;
    +     * getTarget = lookup().bind(site, "getTarget", methodType(MethodHandle.class));
    +     * invoker = exactInvoker(site.type());
    +     * result = foldArguments(invoker, getTarget)
    +     * 
    + * @return a method handle which always invokes the call site's target + */ + public static + MethodHandle dynamicInvoker(CallSite site) { + MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, CallSite.GET_TARGET, site); + MethodHandle invoker = exactInvoker(site.type()); + return foldArguments(invoker, getTarget); + } + + static Invokers invokers(MethodType type) { return MethodTypeImpl.invokers(IMPL_TOKEN, type); } @@ -688,14 +748,11 @@ public class MethodHandles { /// method handle modification (creation from other method handles) /** - * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle which adapts the type of the - * given method handle to a new type, by pairwise argument conversion, - * and/or varargs conversion. - * The original type and new type must have the same number of - * arguments, or else one or both them the must be varargs types. + * given method handle to a new type by pairwise argument conversion. + * The original type and new type must have the same number of arguments. * The resulting method handle is guaranteed to confess a type - * which is equal to the desired new type, with any varargs property erased. + * which is equal to the desired new type. *

    * If the original type and new type are equal, returns target. *

    @@ -703,26 +760,15 @@ public class MethodHandles { * arguments and return types. Let T0 and T1 be the differing * new and old parameter types (or old and new return types) * for corresponding values passed by the new and old method types. - *

    - * If an ordinary (non-varargs) parameter of the new type is - * to be boxed in a varargs parameter of the old type of type T1[], - * then T1 is the element type of the varargs array. - * Otherwise, if a varargs parameter of the new type of type T0[] - * is to be spread into one or more outgoing old type parameters, - * then T0 is the element type of the - * If the new type is varargs and the old type is not, the varargs - * argument will be checked and must be a non-null array of exactly - * the right length. If there are no parameters in the old type - * corresponding to the new varargs parameter, the varargs argument - * is also allowed to be null. - *

    * Given those types T0, T1, one of the following conversions is applied * if possible: *

      - *
    • If T0 and T1 are references, then a cast to T2 is applied, - * where T2 is Object if T1 is an interface, else T1. - * (The types do not need to be related in any particular way. - * The treatment of interfaces follows the usage of the bytecode verifier.) + *
    • If T0 and T1 are references, and T1 is not an interface type, + * then a cast to T1 is applied. + * (The types do not need to be related in any particular way.) + *
    • If T0 and T1 are references, and T1 is an interface type, + * then the value of type T0 is passed as a T1 without a cast. + * (This treatment of interfaces follows the usage of the bytecode verifier.) *
    • If T0 and T1 are primitives, then a Java casting * conversion (JLS 5.5) is applied, if one exists. *
    • If T0 and T1 are primitives and one is boolean, @@ -745,16 +791,17 @@ public class MethodHandles { * if necessary to T1 by one of the preceding conversions. * Otherwise, T0 is converted directly to the wrapper type for T1, * which is then unboxed. - *
    • If T1 is void, any returned value is discarded - *
    • If T0 is void and T1 a reference, a null value is introduced. - *
    • If T0 is void and T1 a primitive, a zero value is introduced. + *
    • If the return type T1 is void, any returned value is discarded + *
    • If the return type T0 is void and T1 a reference, a null value is introduced. + *
    • If the return type T0 is void and T1 a primitive, a zero value is introduced. *
    * @param target the method handle to invoke after arguments are retyped * @param newType the expected type of the new method handle * @return a method handle which delegates to {@code target} after performing * any necessary argument conversions, and arranges for any * necessary return value conversions - * @throws WrongMethodTypeException if the conversion cannot be made + * @throws IllegalArgumentException if the conversion cannot be made + * @see MethodHandle#asType */ public static MethodHandle convertArguments(MethodHandle target, MethodType newType) { @@ -872,23 +919,17 @@ public class MethodHandles { * PROVISIONAL API, WORK IN PROGRESS: * Produce a method handle which adapts the type of the * given method handle to a new type, by collecting a series of - * trailing arguments into an array. - * The resulting method handle is guaranteed to confess a type - * which is equal to the desired new type. + * trailing arguments as elements to a single argument array. *

    - * This method is inverse to {@link #spreadArguments}. + * This method may be used as an inverse to {@link #spreadArguments}. * The final parameter type of the old type must be an array type T[], * which is the type of what is called the spread argument. * The trailing arguments of the new type which correspond to * the spread argument are all converted to type T and collected * into an array before the original method is called. - *

    - * ISSUE: Unify this with combineArguments. CollectArguments - * is combineArguments with (a) new Object[]{...} as a combiner, - * and (b) the combined arguments dropped, in favor of the combined result. * @param target the method handle to invoke after the argument is prepended * @param newType the expected type of the new method handle - * @return a new method handle which collects some trailings argument + * @return a new method handle which collects some trailing argument * into an array, before calling the original method handle */ public static @@ -900,50 +941,72 @@ public class MethodHandles { int numCollect = (inargs - collectPos); if (collectPos < 0 || numCollect < 0) throw newIllegalArgumentException("wrong number of arguments"); - return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos); + MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null); + if (res == null) { + throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType); + } + return res; } /** * PROVISIONAL API, WORK IN PROGRESS: - * Produce a method handle which calls the original method handle, - * after inserting the given argument at the given position. - * The type of the new method handle will drop the corresponding argument - * type from the original handle's type. + * Produce a method handle which calls the original method handle {@code target}, + * after inserting the given argument(s) at the given position. + * The formal parameters to {@code target} which will be supplied by those + * arguments are called bound parameters, because the new method + * will contain bindings for those parameters take from {@code values}. + * The type of the new method handle will drop the types for the bound + * parameters from the original target type, since the new method handle + * will no longer require those arguments to be supplied by its callers. *

    - * The given argument object must match the dropped argument type. - * If the dropped argument type is a primitive, the argument object - * must be a wrapper, and is unboxed to produce the primitive. + * Each given argument object must match the corresponding bound parameter type. + * If a bound parameter type is a primitive, the argument object + * must be a wrapper, and will be unboxed to produce the primitive value. *

    * The pos may range between zero and N (inclusively), - * where N is the number of argument types in target, - * meaning to insert the new argument as the first or last (respectively), - * or somewhere in between. + * where N is the number of argument types in resulting method handle + * (after bound parameter types are dropped). * @param target the method handle to invoke after the argument is inserted * @param pos where to insert the argument (zero for the first) - * @param value the argument to insert + * @param values the series of arguments to insert * @return a new method handle which inserts an additional argument, * before calling the original method handle */ public static - MethodHandle insertArgument(MethodHandle target, int pos, Object value) { + MethodHandle insertArguments(MethodHandle target, int pos, Object... values) { + int insCount = values.length; MethodType oldType = target.type(); ArrayList> ptypes = new ArrayList>(oldType.parameterList()); int outargs = oldType.parameterCount(); - int inargs = outargs - 1; - if (pos < 0 || pos >= outargs) + int inargs = outargs - insCount; + if (inargs < 0) + throw newIllegalArgumentException("too many values to insert"); + if (pos < 0 || pos > inargs) throw newIllegalArgumentException("no argument type to append"); - Class valueType = ptypes.remove(pos); - value = checkValue(valueType, value); - if (pos == 0 && !valueType.isPrimitive()) { - // At least for now, make bound method handles a special case. - // This lets us get by with minimal JVM support, at the expense - // of generating signature-specific adapters as Java bytecodes. - MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, target, value); - if (bmh != null) return bmh; - // else fall through to general adapter machinery + MethodHandle result = target; + for (int i = 0; i < insCount; i++) { + Object value = values[i]; + Class valueType = oldType.parameterType(pos+i); + value = checkValue(valueType, value); + if (pos == 0 && !valueType.isPrimitive()) { + // At least for now, make bound method handles a special case. + MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value); + if (bmh != null) { + result = bmh; + continue; + } + // else fall through to general adapter machinery + } + result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value); } - return MethodHandleImpl.bindArgument(IMPL_TOKEN, target, pos, value); + return result; + } + + @Deprecated // "use MethodHandles.insertArguments instead" + public static + MethodHandle insertArgument(MethodHandle target, int pos, Object value) { + return insertArguments(target, pos, value); } /** @@ -953,10 +1016,25 @@ public class MethodHandles { * The type of the new method handle will insert the given argument * type(s), at that position, into the original handle's type. *

    - * The pos may range between zero and N-1, + * The pos may range between zero and N, * where N is the number of argument types in target, * meaning to drop the first or last argument (respectively), * or an argument somewhere in between. + *

    + * Example: + *

    +     *   MethodHandle cat = MethodHandles.lookup().
    +     *     findVirtual(String.class, "concat", String.class, String.class);
    +     *   System.out.println(cat.<String>invoke("x", "y")); // xy
    +     *   MethodHandle d0 = dropArguments(cat, 0, String.class);
    +     *   System.out.println(d0.<String>invoke("x", "y", "z")); // xy
    +     *   MethodHandle d1 = dropArguments(cat, 1, String.class);
    +     *   System.out.println(d1.<String>invoke("x", "y", "z")); // xz
    +     *   MethodHandle d2 = dropArguments(cat, 2, String.class);
    +     *   System.out.println(d2.<String>invoke("x", "y", "z")); // yz
    +     *   MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
    +     *   System.out.println(d12.<String>invoke("w", "x", "y", "z")); // wz
    +     * 
    * @param target the method handle to invoke after the argument is dropped * @param valueTypes the type(s) of the argument to drop * @param pos which argument to drop (zero for the first) @@ -964,20 +1042,150 @@ public class MethodHandles { * before calling the original method handle */ public static - MethodHandle dropArguments(MethodHandle target, int pos, Class... valueTypes) { - if (valueTypes.length == 0) return target; + MethodHandle dropArguments(MethodHandle target, int pos, List> valueTypes) { + if (valueTypes.size() == 0) return target; MethodType oldType = target.type(); int outargs = oldType.parameterCount(); - int inargs = outargs + valueTypes.length; + int inargs = outargs + valueTypes.size(); if (pos < 0 || pos >= inargs) throw newIllegalArgumentException("no argument type to remove"); ArrayList> ptypes = new ArrayList>(oldType.parameterList()); - ptypes.addAll(pos, Arrays.asList(valueTypes)); - MethodType newType = MethodType.make(oldType.returnType(), ptypes); + ptypes.addAll(pos, valueTypes); + MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos); } + public static + MethodHandle dropArguments(MethodHandle target, int pos, Class... valueTypes) { + return dropArguments(target, pos, Arrays.asList(valueTypes)); + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Adapt a target method handle {@code target} by pre-processing + * one or more of its arguments, each with its own unary filter function, + * and then calling the target with each pre-processed argument + * replaced by the result of its corresponding filter function. + *

    + * The pre-processing is performed by one or more method handles, + * specified in the non-null elements of the {@code filters} array. + * (If there are no such elements, the original target is returned.) + * Each filter (that is, each non-null element of {@code filters}) + * is applied to the corresponding argument of the adapter. + *

    + * If a filter {@code F} applies to the {@code N}th argument of + * the method handle, then {@code F} must be a method handle which + * takes exactly one argument. The type of {@code F}'s sole argument + * replaces the corresponding argument type of the target + * in the resulting adapted method handle. + * The return type of {@code F} must be identical to the corresponding + * parameter type of the target. + *

    + * It is an error if there are non-null elements of {@code filters} + * which do not correspond to argument positions in the target. + * The actual length of the target array may be any number, it need + * not be the same as the parameter count of the target type. + * (This provides an easy way to filter just the first argument or two + * of a target method handle.) + *

    Here is pseudocode for the resulting adapter: + *

    +     * // there are N arguments in the A sequence
    +     * T target(A[N]...);
    +     * [i<N] V[i] filter[i](B[i]) = filters[i] ?: identity;
    +     * T adapter(B[N]... b) {
    +     *   A[N] a...;
    +     *   [i<N] a[i] = filter[i](b[i]);
    +     *   return target(a...);
    +     * }
    +     * 
    + * @param target the method handle to invoke after arguments are filtered + * @param filters method handles to call initially on filtered arguments + * @return method handle which incorporates the specified argument filtering logic + * @throws IllegalArgumentException if a non-null element of {@code filters} + * does not match a corresponding argument type of {@code target} + */ + public static + MethodHandle filterArguments(MethodHandle target, MethodHandle... filters) { + MethodType targetType = target.type(); + MethodHandle adapter = target; + MethodType adapterType = targetType; + int pos = -1, maxPos = targetType.parameterCount(); + for (MethodHandle filter : filters) { + pos += 1; + if (filter == null) continue; + if (pos >= maxPos) + throw newIllegalArgumentException("too many filters"); + MethodType filterType = filter.type(); + if (filterType.parameterCount() != 1 + || filterType.returnType() != targetType.parameterType(pos)) + throw newIllegalArgumentException("target and filter types do not match"); + adapterType = adapterType.changeParameterType(pos, filterType.parameterType(0)); + adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, pos, filter); + } + MethodType midType = adapter.type(); + if (midType != adapterType) + adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null); + return adapter; + } + + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Adapt a target method handle {@code target} by pre-processing + * some of its arguments, and then calling the target with + * the result of the pre-processing, plus all original arguments. + *

    + * The pre-processing is performed by a second method handle, the {@code combiner}. + * The first {@code N} arguments passed to the adapter, + * are copied to the combiner, which then produces a result. + * (Here, {@code N} is defined as the parameter count of the adapter.) + * After this, control passes to the {@code target}, with both the result + * of the combiner, and all the original incoming arguments. + *

    + * The first argument type of the target must be identical with the + * return type of the combiner. + * The resulting adapter is the same type as the target, except that the + * initial argument type of the target is dropped. + *

    + * (Note that {@link #dropArguments} can be used to remove any arguments + * that either the {@code combiner} or {@code target} does not wish to receive. + * If some of the incoming arguments are destined only for the combiner, + * consider using {@link #collectArguments} instead, since those + * arguments will not need to be live on the stack on entry to the + * target.) + *

    + * The first argument of the target must be identical with the + * return value of the combiner. + *

    Here is pseudocode for the resulting adapter: + *

    +     * // there are N arguments in the A sequence
    +     * T target(V, A[N]..., B...);
    +     * V combiner(A...);
    +     * T adapter(A... a, B... b) {
    +     *   V v = combiner(a...);
    +     *   return target(v, a..., b...);
    +     * }
    +     * 
    + * @param target the method handle to invoke after arguments are combined + * @param combiner method handle to call initially on the incoming arguments + * @return method handle which incorporates the specified argument folding logic + * @throws IllegalArgumentException if the first argument type of + * {@code target} is not the same as {@code combiner}'s return type, + * or if the next {@code foldArgs} argument types of {@code target} + * are not identical with the argument types of {@code combiner} + */ + public static + MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { + MethodType targetType = target.type(); + MethodType combinerType = combiner.type(); + int foldArgs = combinerType.parameterCount(); + boolean ok = (targetType.parameterCount() >= 1 + foldArgs); + if (!ok) + throw misMatchedTypes("target and combiner types", targetType, combinerType); + MethodType newType = targetType.dropParameterTypes(0, 1); + return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner); + } + /** * PROVISIONAL API, WORK IN PROGRESS: * Make a method handle which adapts a target method handle, @@ -985,18 +1193,18 @@ public class MethodHandles { * If the guard fails, a fallback handle is called instead. * All three method handles must have the same corresponding * argument and return types, except that the return type - * of the test must be boolean. + * of the test must be boolean, and the test is allowed + * to have fewer arguments than the other two method handles. *

    Here is pseudocode for the resulting adapter: *

    -     * signature T(A...);
          * boolean test(A...);
    -     * T target(A...);
    -     * T fallback(A...);
    -     * T adapter(A... a) {
    +     * T target(A...,B...);
    +     * T fallback(A...,B...);
    +     * T adapter(A... a,B... b) {
          *   if (test(a...))
    -     *     return target(a...);
    +     *     return target(a..., b...);
          *   else
    -     *     return fallback(a...);
    +     *     return fallback(a..., b...);
          * }
          * 
    * @param test method handle used for test, must return boolean @@ -1011,10 +1219,23 @@ public class MethodHandles { MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { - if (target.type() != fallback.type()) - throw newIllegalArgumentException("target and fallback types do not match"); - if (target.type().changeReturnType(boolean.class) != test.type()) - throw newIllegalArgumentException("target and test types do not match"); + MethodType gtype = test.type(); + MethodType ttype = target.type(); + MethodType ftype = fallback.type(); + if (ttype != ftype) + throw misMatchedTypes("target and fallback types", ttype, ftype); + MethodType gtype2 = ttype.changeReturnType(boolean.class); + if (gtype2 != gtype) { + if (gtype.returnType() != boolean.class) + throw newIllegalArgumentException("guard type is not a predicate "+gtype); + int gpc = gtype.parameterCount(), tpc = ttype.parameterCount(); + if (gpc < tpc) { + test = dropArguments(test, gpc, ttype.parameterList().subList(gpc, tpc)); + gtype = test.type(); + } + if (gtype2 != gtype) + throw misMatchedTypes("target and test types", ttype, gtype); + } /* { MethodHandle invoke = findVirtual(MethodHandle.class, "invoke", target.type()); static MethodHandle choose(boolean z, MethodHandle t, MethodHandle f) { @@ -1027,7 +1248,7 @@ public class MethodHandles { } // choose = \z.(z ? target : fallback) MethodHandle choose = findVirtual(MethodHandles.class, "choose", - MethodType.make(boolean.class, MethodHandle.class, MethodHandle.class)); + MethodType.methodType(boolean.class, MethodHandle.class, MethodHandle.class)); choose = appendArgument(choose, target); choose = appendArgument(choose, fallback); MethodHandle dispatch = compose(choose, test); @@ -1038,67 +1259,88 @@ public class MethodHandles { return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback); } - /** - * PROVISIONAL API, WORK IN PROGRESS: - * Adapt a target method handle {@code target} by first processing - * its arguments, and then calling the target. - * The initial processing is performed by a second method handle, the {@code combiner}. - * After this, control passes to the {@code target}, with the same arguments. - *

    - * The return value of the {@code combiner} is inserted into the argument list - * for the {@code target} at the indicated position {@code pos}, if it is non-negative. - * Except for this inserted argument (if any), the argument types of - * the target {@code target} and the {@code combiner} must be identical. - *

    - * (Note that {@link #dropArguments} can be used to remove any arguments - * that either the {@code combiner} or {@code target} does not wish to receive.) - *

    - * The combiner handle must have the same argument types as the - * target handle, but must return {@link MethodHandle} instead of - * the ultimate return type. The returned method handle, in turn, - * is required to have exactly the given final method type. - *

    Here is pseudocode for the resulting adapter: - *

    -     * signature V(A[pos]..., B...);
    -     * signature T(A[pos]..., V, B...);
    -     * T target(A... a, V v, B... b);
    -     * V combiner(A..., B...);
    -     * T adapter(A... a, B... b) {
    -     *   V v = combiner(a..., b...);
    -     *   return target(a..., v, b...);
    -     * }
    -     * 
    - * @param target the method handle to invoke after arguments are combined - * @param pos where the return value of {@code combiner} is to - * be inserted as an argument to {@code target} - * @param combiner method handle to call initially on the incoming arguments - * @return method handle which incorporates the specified dispatch logic - * @throws IllegalArgumentException if {@code combiner} does not itself - * return either void or the {@code pos}-th argument of {@code target}, - * or does not have the same argument types as {@code target} - * (minus the inserted argument) - */ - public static - MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) { - MethodType mhType = target.type(); - Class combineType = combiner.type().returnType(); - MethodType incomingArgs; - if (pos < 0) { - // No inserted argument; target & combiner must have same argument types. - incomingArgs = mhType; - if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) - throw newIllegalArgumentException("target and combiner types do not match"); - } else { - // Inserted argument. - if (pos >= mhType.parameterCount() - || mhType.parameterType(pos) != combineType) - throw newIllegalArgumentException("inserted combiner argument does not match target"); - incomingArgs = mhType.dropParameterType(pos); - } - if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) { - throw newIllegalArgumentException("target and combiner types do not match"); - } - return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos); + static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) { + return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2); } + /** + * PROVISIONAL API, WORK IN PROGRESS: + * Make a method handle which adapts a target method handle, + * by running it inside an exception handler. + * If the target returns normally, the adapter returns that value. + * If an exception matching the specified type is thrown, the fallback + * handle is called instead on the exception, plus the original arguments. + *

    + * The handler must have leading parameter of {@code exType} or a supertype, + * followed by arguments which correspond (how? TBD) to + * all the parameters of the target. + * The target and handler must return the same type. + *

    Here is pseudocode for the resulting adapter: + *

    +     * T target(A...);
    +     * T handler(ExType, A...);
    +     * T adapter(A... a) {
    +     *   try {
    +     *     return target(a...);
    +     *   } catch (ExType ex) {
    +     *     return handler(ex, a...);
    +     *   }
    +     * }
    +     * 
    + * @param target method handle to call + * @param exType the type of exception which the handler will catch + * @param handler method handle to call if a matching exception is thrown + * @return method handle which incorporates the specified try/catch logic + * @throws IllegalArgumentException if {@code handler} does not accept + * the given exception type, or if the method handle types do + * not match in their return types and their + * corresponding parameters + */ + public static + MethodHandle catchException(MethodHandle target, + Class exType, + MethodHandle handler) { + MethodType targetType = target.type(); + MethodType handlerType = handler.type(); + boolean ok = (targetType.parameterCount() == + handlerType.parameterCount() - 1); +// for (int i = 0; ok && i < numExArgs; i++) { +// if (targetType.parameterType(i) != handlerType.parameterType(1+i)) +// ok = false; +// } + if (!ok) + throw newIllegalArgumentException("target and handler types do not match"); + return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler); + } + + /** + * Produce a method handle which will throw exceptions of the given {@code exType}. + * The method handle will accept a single argument of {@code exType}, + * and immediately throw it as an exception. + * The method type will nominally specify a return of {@code returnType}. + * The return type may be anything convenient: It doesn't matter to the + * method handle's behavior, since it will never return normally. + */ + public static + MethodHandle throwException(Class returnType, Class exType) { + return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType)); + } + + /** Alias for {@link MethodType#methodType}. */ + @Deprecated // "use MethodType.methodType instead" + public static MethodType methodType(Class rtype) { + return MethodType.methodType(rtype); + } + + /** Alias for {@link MethodType#methodType}. */ + @Deprecated // "use MethodType.methodType instead" + public static MethodType methodType(Class rtype, Class ptype) { + return MethodType.methodType(rtype, ptype); + } + + /** Alias for {@link MethodType#methodType}. */ + @Deprecated // "use MethodType.methodType instead" + public static MethodType methodType(Class rtype, Class ptype0, Class... ptypes) { + return MethodType.methodType(rtype, ptype0, ptypes); + } } diff --git a/jdk/src/share/classes/java/dyn/MethodType.java b/jdk/src/share/classes/java/dyn/MethodType.java index 8e340de18f0..2ca02089d20 100644 --- a/jdk/src/share/classes/java/dyn/MethodType.java +++ b/jdk/src/share/classes/java/dyn/MethodType.java @@ -32,7 +32,7 @@ import java.util.List; import sun.dyn.Access; import sun.dyn.Invokers; import sun.dyn.MethodTypeImpl; -import sun.dyn.util.BytecodeSignature; +import sun.dyn.util.BytecodeDescriptor; import static sun.dyn.MemberName.newIllegalArgumentException; /** @@ -63,7 +63,7 @@ class MethodType { static { // This hack allows the implementation package special access to - // the internals of MethodType. In particular, the Form has all sorts + // the internals of MethodType. In particular, the MTImpl has all sorts // of cached information useful to the implementation code. MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() { public Class[] ptypes(MethodType mt) { return mt.ptypes; } @@ -114,51 +114,76 @@ class MethodType { * @throws IllegalArgumentException if any of the ptypes is void */ public static - MethodType make(Class rtype, Class[] ptypes) { + MethodType methodType(Class rtype, Class[] ptypes) { return makeImpl(rtype, ptypes, false); } - - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. */ - public static - MethodType make(Class rtype, List> ptypes) { - return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true); + @Deprecated public static + MethodType make(Class rtype, Class[] ptypes) { + return methodType(rtype, ptypes); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */ + public static + MethodType methodType(Class rtype, List> ptypes) { + boolean notrust = false; // random List impl. could return evil ptypes array + return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust); + } + @Deprecated public static + MethodType make(Class rtype, List> ptypes) { + return methodType(rtype, ptypes); + } + + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * The leading parameter type is prepended to the remaining array. */ public static - MethodType make(Class rtype, Class ptype0, Class... ptypes) { + MethodType methodType(Class rtype, Class ptype0, Class... ptypes) { Class[] ptypes1 = new Class[1+ptypes.length]; ptypes1[0] = ptype0; System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length); return makeImpl(rtype, ptypes1, true); } + @Deprecated public static + MethodType make(Class rtype, Class ptype0, Class... ptypes) { + return methodType(rtype, ptype0, ptypes); + } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * The resulting method has no parameter types. */ public static - MethodType make(Class rtype) { + MethodType methodType(Class rtype) { return makeImpl(rtype, NO_PTYPES, true); } + @Deprecated public static + MethodType make(Class rtype) { + return methodType(rtype); + } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * The resulting method has the single given parameter type. */ public static - MethodType make(Class rtype, Class ptype0) { + MethodType methodType(Class rtype, Class ptype0) { return makeImpl(rtype, new Class[]{ ptype0 }, true); } + @Deprecated public static + MethodType make(Class rtype, Class ptype0) { + return methodType(rtype, ptype0); + } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * The resulting method has the same parameter types as {@code ptypes}, * and the specified return type. */ public static - MethodType make(Class rtype, MethodType ptypes) { + MethodType methodType(Class rtype, MethodType ptypes) { return makeImpl(rtype, ptypes.ptypes, true); } + @Deprecated public static + MethodType make(Class rtype, MethodType ptypes) { + return methodType(rtype, ptypes); + } /** * Sole factory method to find or create an interned method type. @@ -202,15 +227,16 @@ class MethodType { private static final MethodType[] objectOnlyTypes = new MethodType[20]; /** - * Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. - * All parameters and the return type will be Object, except the final varargs parameter if any. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * All parameters and the return type will be {@code Object}, + * except the final varargs parameter if any, which will be {@code Object[]}. * @param objectArgCount number of parameters (excluding the varargs parameter if any) - * @param varargs whether there will be a varargs parameter, of type Object[] + * @param varargs whether there will be a varargs parameter, of type {@code Object[]} * @return a totally generic method type, given only its count of parameters and varargs - * @see #makeGeneric(int) + * @see #genericMethodType(int) */ public static - MethodType makeGeneric(int objectArgCount, boolean varargs) { + MethodType genericMethodType(int objectArgCount, boolean varargs) { MethodType mt; int ivarargs = (!varargs ? 0 : 1); int ootIndex = objectArgCount*2 + ivarargs; @@ -227,19 +253,27 @@ class MethodType { } return mt; } + @Deprecated public static + MethodType makeGeneric(int objectArgCount, boolean varargs) { + return genericMethodType(objectArgCount, varargs); + } /** * All parameters and the return type will be Object. * @param objectArgCount number of parameters * @return a totally generic method type, given only its count of parameters - * @see #makeGeneric(int, boolean) + * @see #genericMethodType(int, boolean) */ public static + MethodType genericMethodType(int objectArgCount) { + return genericMethodType(objectArgCount, false); + } + @Deprecated public static MethodType makeGeneric(int objectArgCount) { - return makeGeneric(objectArgCount, false); + return genericMethodType(objectArgCount); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * @param num the index (zero-based) of the parameter type to change * @param nptype a new parameter type to replace the old one with * @return the same type, except with the selected parameter changed @@ -251,11 +285,10 @@ class MethodType { return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. - * @param num the position (zero-based) of the inserted parameter type - * @param nptype a new parameter type to insert into the parameter list - * @return the same type, except with the selected parameter inserted + /** Convenience method for {@link #insertParameterTypes}. + * @deprecated Use {@link #insertParameterTypes} instead. */ + @Deprecated public MethodType insertParameterType(int num, Class nptype) { int len = ptypes.length; Class[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1); @@ -264,23 +297,73 @@ class MethodType { return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. - * @param num the index (zero-based) of the parameter type to remove - * @return the same type, except with the selected parameter removed + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * @param num the position (zero-based) of the inserted parameter type(s) + * @param ptypesToInsert zero or more a new parameter types to insert into the parameter list + * @return the same type, except with the selected parameter(s) inserted */ - public MethodType dropParameterType(int num) { + public MethodType insertParameterTypes(int num, Class... ptypesToInsert) { int len = ptypes.length; + if (num < 0 || num > len) + throw newIllegalArgumentException("num="+num); //SPECME + int ilen = ptypesToInsert.length; + if (ilen == 0) return this; + Class[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen); + System.arraycopy(nptypes, num, nptypes, num+ilen, len-num); + System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen); + return makeImpl(rtype, nptypes, true); + } + + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * @param num the position (zero-based) of the inserted parameter type(s) + * @param ptypesToInsert zero or more a new parameter types to insert into the parameter list + * @return the same type, except with the selected parameter(s) inserted + */ + public MethodType insertParameterTypes(int num, List> ptypesToInsert) { + return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES)); + } + + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * @param start the index (zero-based) of the first parameter type to remove + * @param end the index (greater than {@code start}) of the first parameter type after not to remove + * @return the same type, except with the selected parameter(s) removed + */ + public MethodType dropParameterTypes(int start, int end) { + int len = ptypes.length; + if (!(0 <= start && start <= end && end <= len)) + throw newIllegalArgumentException("start="+start+" end="+end); //SPECME + if (start == end) return this; Class[] nptypes; - if (num == 0) { - nptypes = Arrays.copyOfRange(ptypes, 1, len); + if (start == 0) { + if (end == len) { + // drop all parameters + nptypes = NO_PTYPES; + } else { + // drop initial parameter(s) + nptypes = Arrays.copyOfRange(ptypes, end, len); + } } else { - nptypes = Arrays.copyOfRange(ptypes, 0, len-1); - System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num); + if (end == len) { + // drop trailing parameter(s) + nptypes = Arrays.copyOfRange(ptypes, 0, start); + } else { + int tail = len - end; + nptypes = Arrays.copyOfRange(ptypes, 0, start + tail); + System.arraycopy(ptypes, end, nptypes, start, tail); + } } return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. + /** Convenience method for {@link #dropParameterTypes}. + * @deprecated Use {@link #dropParameterTypes} instead. + */ + @Deprecated + public MethodType dropParameterType(int num) { + return dropParameterTypes(num, num+1); + } + + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * @param nrtype a return parameter type to replace the old one with * @return the same type, except with the return type change */ @@ -291,6 +374,7 @@ class MethodType { /** Convenience method. * Report if this type contains a primitive argument or return value. + * The return type {@code void} counts as a primitive. * @return true if any of the types are primitives */ public boolean hasPrimitives() { @@ -300,39 +384,47 @@ class MethodType { /** Convenience method. * Report if this type contains a wrapper argument or return value. * Wrappers are types which box primitive values, such as {@link Integer}. + * The reference type {@code java.lang.Void} counts as a wrapper. * @return true if any of the types are wrappers */ public boolean hasWrappers() { return unwrap() != this; } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. - * Erase all reference types to Object. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * Erase all reference types to {@code Object}. + * All primitive types (including {@code void}) will remain unchanged. * @return a version of the original type with all reference types replaced */ public MethodType erase() { return form.erasedType(); } - /** Convenience method for {@link #makeGeneric(int)}. - * Convert all types, both reference and primitive, to Object. + /** Convenience method for {@link #genericMethodType(int)}. + * Convert all types, both reference and primitive, to {@code Object}. + * The expression {@code type.wrap().erase()} produces the same value + * as {@code type.generic()}. * @return a version of the original type with all types replaced */ public MethodType generic() { - return makeGeneric(parameterCount()); + return genericMethodType(parameterCount()); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * Convert all primitive types to their corresponding wrapper types. + * All reference types (including wrapper types) will remain unchanged. * A {@code void} return type is changed to the type {@code java.lang.Void}. + * The expression {@code type.wrap().erase()} produces the same value + * as {@code type.generic()}. * @return a version of the original type with all primitive types replaced */ public MethodType wrap() { return hasPrimitives() ? wrapWithPrims(this) : this; } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * Convert all wrapper types to their corresponding primitive types. + * All primitive types (including {@code void}) will remain unchanged. * A return type of {@code java.lang.Void} is changed to {@code void}. * @return a version of the original type with all wrapper types replaced */ @@ -391,6 +483,7 @@ class MethodType { /** * Convenience method to present the arguments as an array. + * Changes to the array will not result in changes to the type. * @return the parameter types (as a fresh copy if necessary) */ public Class[] parameterArray() { @@ -491,7 +584,7 @@ class MethodType { return form.parameterSlotCount(); } - /** Number of JVM stack slots which carry all parameters after + /** Number of JVM stack slots which carry all parameters including and after * the given position, which must be in the range of 0 to * {@code parameterCount} inclusive. Successive parameters are * more shallowly stacked, and parameters are indexed in the bytecodes @@ -532,7 +625,7 @@ class MethodType { return form.returnSlotCount(); } - /** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. + /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. * Find or create an instance (interned) of the given method type. * Any class or interface name embedded in the signature string * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)} @@ -544,16 +637,16 @@ class MethodType { *

    * This method is included for the benfit of applications that must * generate bytecodes that process method handles and invokedynamic. - * @param bytecodeSignature a bytecode-level signature string "(T...)T" + * @param descriptor a bytecode-level signature string "(T...)T" * @param loader the class loader in which to look up the types * @return a method type matching the bytecode-level signature * @throws IllegalArgumentException if the string is not well-formed * @throws TypeNotPresentException if a named type cannot be found */ - public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader) + public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader) throws IllegalArgumentException, TypeNotPresentException { - List> types = BytecodeSignature.parseMethod(bytecodeSignature, loader); + List> types = BytecodeDescriptor.parseMethod(descriptor, loader); Class rtype = types.remove(types.size() - 1); Class[] ptypes = types.toArray(NO_PTYPES); return makeImpl(rtype, ptypes, true); @@ -565,11 +658,21 @@ class MethodType { *

    * This method is included for the benfit of applications that must * generate bytecodes that process method handles and invokedynamic. - * {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)}, + * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader)}, * because the latter requires a suitable class loader argument. * @return the bytecode signature representation */ + public String toMethodDescriptorString() { + return BytecodeDescriptor.unparse(this); + } + + /** Temporary alias for toMethodDescriptorString; delete after M3. */ public String toBytecodeString() { - return BytecodeSignature.unparse(this); + return toMethodDescriptorString(); + } + /** Temporary alias for fromMethodDescriptorString; delete after M3. */ + public static MethodType fromBytecodeString(String descriptor, ClassLoader loader) + throws IllegalArgumentException, TypeNotPresentException { + return fromMethodDescriptorString(descriptor, loader); } } diff --git a/jdk/src/share/classes/java/dyn/package-info.java b/jdk/src/share/classes/java/dyn/package-info.java index 858d0e9bcbf..df82633c211 100644 --- a/jdk/src/share/classes/java/dyn/package-info.java +++ b/jdk/src/share/classes/java/dyn/package-info.java @@ -24,6 +24,7 @@ */ /** + * PROVISIONAL API, WORK IN PROGRESS: * This package contains dynamic language support provided directly by * the Java core class libraries and virtual machine. * @author John Rose, JSR 292 EG diff --git a/jdk/src/share/classes/java/lang/Deprecated.java b/jdk/src/share/classes/java/lang/Deprecated.java index 427b77baac8..28909e19e77 100644 --- a/jdk/src/share/classes/java/lang/Deprecated.java +++ b/jdk/src/share/classes/java/lang/Deprecated.java @@ -26,6 +26,7 @@ package java.lang; import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; /** * A program element annotated @Deprecated is one that programmers @@ -38,5 +39,6 @@ import java.lang.annotation.*; */ @Documented @Retention(RetentionPolicy.RUNTIME) +@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { } diff --git a/jdk/src/share/classes/java/lang/Error.java b/jdk/src/share/classes/java/lang/Error.java index c1ab7a89297..a5af32668e8 100644 --- a/jdk/src/share/classes/java/lang/Error.java +++ b/jdk/src/share/classes/java/lang/Error.java @@ -26,27 +26,31 @@ package java.lang; /** - * An Error is a subclass of Throwable + * An {@code Error} is a subclass of {@code Throwable} * that indicates serious problems that a reasonable application * should not try to catch. Most such errors are abnormal conditions. - * The ThreadDeath error, though a "normal" condition, - * is also a subclass of Error because most applications + * The {@code ThreadDeath} error, though a "normal" condition, + * is also a subclass of {@code Error} because most applications * should not try to catch it. *

    - * A method is not required to declare in its throws - * clause any subclasses of Error that might be thrown + * A method is not required to declare in its {@code throws} + * clause any subclasses of {@code Error} that might be thrown * during the execution of the method but not caught, since these * errors are abnormal conditions that should never occur. * + * That is, {@code Error} and its subclasses are regarded as unchecked + * exceptions for the purposes of compile-time checking of exceptions. + * * @author Frank Yellin * @see java.lang.ThreadDeath + * @jls3 11.2 Compile-Time Checking of Exceptions * @since JDK1.0 */ public class Error extends Throwable { static final long serialVersionUID = 4980196508277280342L; /** - * Constructs a new error with null as its detail message. + * Constructs a new error with {@code null} as its detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. */ @@ -69,7 +73,7 @@ public class Error extends Throwable { /** * Constructs a new error with the specified detail message and * cause.

    Note that the detail message associated with - * cause is not automatically incorporated in + * {@code cause} is not automatically incorporated in * this error's detail message. * * @param message the detail message (which is saved for later retrieval diff --git a/jdk/src/share/classes/java/lang/Exception.java b/jdk/src/share/classes/java/lang/Exception.java index 70b99ae9be6..bdb1c7d3687 100644 --- a/jdk/src/share/classes/java/lang/Exception.java +++ b/jdk/src/share/classes/java/lang/Exception.java @@ -26,19 +26,27 @@ package java.lang; /** - * The class Exception and its subclasses are a form of - * Throwable that indicates conditions that a reasonable + * The class {@code Exception} and its subclasses are a form of + * {@code Throwable} that indicates conditions that a reasonable * application might want to catch. * + *

    The class {@code Exception} and any subclasses that are not also + * subclasses of {@link RuntimeException} are checked + * exceptions. Checked exceptions need to be declared in a + * method or constructor's {@code throws} clause if they can be thrown + * by the execution of the method or constructor and propagate outside + * the method or constructor boundary. + * * @author Frank Yellin * @see java.lang.Error + * @jls3 11.2 Compile-Time Checking of Exceptions * @since JDK1.0 */ public class Exception extends Throwable { static final long serialVersionUID = -3387516993124229948L; /** - * Constructs a new exception with null as its detail message. + * Constructs a new exception with {@code null} as its detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. */ @@ -61,7 +69,7 @@ public class Exception extends Throwable { /** * Constructs a new exception with the specified detail message and * cause.

    Note that the detail message associated with - * cause is not automatically incorporated in + * {@code cause} is not automatically incorporated in * this exception's detail message. * * @param message the detail message (which is saved for later retrieval diff --git a/jdk/src/share/classes/java/lang/RuntimeException.java b/jdk/src/share/classes/java/lang/RuntimeException.java index e3378485bdf..d510e2c5898 100644 --- a/jdk/src/share/classes/java/lang/RuntimeException.java +++ b/jdk/src/share/classes/java/lang/RuntimeException.java @@ -26,22 +26,24 @@ package java.lang; /** - * RuntimeException is the superclass of those + * {@code RuntimeException} is the superclass of those * exceptions that can be thrown during the normal operation of the * Java Virtual Machine. - *

    - * A method is not required to declare in its throws - * clause any subclasses of RuntimeException that might - * be thrown during the execution of the method but not caught. * + *

    {@code RuntimeException} and its subclasses are unchecked + * exceptions. Unchecked exceptions do not need to be + * declared in a method or constructor's {@code throws} clause if they + * can be thrown by the execution of the method or constructor and + * propagate outside the method or constructor boundary. * * @author Frank Yellin + * @jls3 11.2 Compile-Time Checking of Exceptions * @since JDK1.0 */ public class RuntimeException extends Exception { static final long serialVersionUID = -7034897190745766939L; - /** Constructs a new runtime exception with null as its + /** Constructs a new runtime exception with {@code null} as its * detail message. The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause}. */ @@ -63,7 +65,7 @@ public class RuntimeException extends Exception { /** * Constructs a new runtime exception with the specified detail message and * cause.

    Note that the detail message associated with - * cause is not automatically incorporated in + * {@code cause} is not automatically incorporated in * this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval diff --git a/jdk/src/share/classes/java/lang/StrictMath.java b/jdk/src/share/classes/java/lang/StrictMath.java index dad91405741..704be3e310e 100644 --- a/jdk/src/share/classes/java/lang/StrictMath.java +++ b/jdk/src/share/classes/java/lang/StrictMath.java @@ -26,6 +26,7 @@ package java.lang; import java.util.Random; import sun.misc.FpUtils; +import sun.misc.DoubleConsts; /** * The class {@code StrictMath} contains methods for performing basic @@ -316,7 +317,9 @@ public final class StrictMath { * floating-point value that is greater than or equal to * the argument and is equal to a mathematical integer. */ - public static native double ceil(double a); + public static double ceil(double a) { + return floorOrCeil(a, -0.0, 1.0, 1.0); + } /** * Returns the largest (closest to positive infinity) @@ -333,7 +336,54 @@ public final class StrictMath { * floating-point value that less than or equal to the argument * and is equal to a mathematical integer. */ - public static native double floor(double a); + public static double floor(double a) { + return floorOrCeil(a, -1.0, 0.0, -1.0); + } + + /** + * Internal method to share logic between floor and ceil. + * + * @param a the value to be floored or ceiled + * @param negativeBoundary result for values in (-1, 0) + * @param positiveBoundary result for values in (0, 1) + * @param increment value to add when the argument is non-integral + */ + private static double floorOrCeil(double a, + double negativeBoundary, + double positiveBoundary, + double sign) { + int exponent = Math.getExponent(a); + + if (exponent < 0) { + /* + * Absolute value of argument is less than 1. + * floorOrceil(-0.0) => -0.0 + * floorOrceil(+0.0) => +0.0 + */ + return ((a == 0.0) ? a : + ( (a < 0.0) ? negativeBoundary : positiveBoundary) ); + } else if (exponent >= 52) { + /* + * Infinity, NaN, or a value so large it must be integral. + */ + return a; + } + // Else the argument is either an integral value already XOR it + // has to be rounded to one. + assert exponent >= 0 && exponent <= 51; + + long doppel = Double.doubleToRawLongBits(a); + long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; + + if ( (mask & doppel) == 0L ) + return a; // integral value + else { + double result = Double.longBitsToDouble(doppel & (~mask)); + if (sign*a > 0.0) + result = result + sign; + return result; + } + } /** * Returns the {@code double} value that is closest in value diff --git a/jdk/src/share/classes/java/lang/SuppressWarnings.java b/jdk/src/share/classes/java/lang/SuppressWarnings.java index b999bce2685..cc98d68b1c0 100644 --- a/jdk/src/share/classes/java/lang/SuppressWarnings.java +++ b/jdk/src/share/classes/java/lang/SuppressWarnings.java @@ -26,7 +26,6 @@ package java.lang; import java.lang.annotation.*; -import java.lang.annotation.ElementType; import static java.lang.annotation.ElementType.*; /** @@ -45,7 +44,7 @@ import static java.lang.annotation.ElementType.*; * @since 1.5 * @author Josh Bloch */ -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) +@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** diff --git a/jdk/src/share/classes/java/lang/Throwable.java b/jdk/src/share/classes/java/lang/Throwable.java index c4e75d250ff..ebc7fe7ceab 100644 --- a/jdk/src/share/classes/java/lang/Throwable.java +++ b/jdk/src/share/classes/java/lang/Throwable.java @@ -34,6 +34,11 @@ import java.io.*; * this class or one of its subclasses can be the argument type in a * catch clause. * + * For the purposes of compile-time checking of exceptions, {@code + * Throwable} and any subclass of {@code Throwable} that is not also a + * subclass of either {@link RuntimeException} or {@link Error} are + * regarded as checked exceptions. + * *

    Instances of two subclasses, {@link java.lang.Error} and * {@link java.lang.Exception}, are conventionally used to indicate * that exceptional situations have occurred. Typically, these instances @@ -142,6 +147,7 @@ import java.io.*; * @author unascribed * @author Josh Bloch (Added exception chaining and programmatic access to * stack trace in 1.4.) + * @jls3 11.2 Compile-Time Checking of Exceptions * @since JDK1.0 */ public class Throwable implements Serializable { diff --git a/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java b/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java index 5f68635d4fe..ca5edbeb518 100644 --- a/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java +++ b/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java @@ -32,7 +32,7 @@ import javax.management.ObjectName; * for monitoring and managing a component in the Java platform. * Each platform managed object has a unique * object name - * for the {@linkplain ManagementFactory.getPlatformMBeanServer + * for the {@linkplain ManagementFactory#getPlatformMBeanServer * platform MBeanServer} access. * All platform MXBeans will implement this interface. * diff --git a/jdk/src/share/classes/java/nio/X-Buffer.java.template b/jdk/src/share/classes/java/nio/X-Buffer.java.template index 9fc8185b646..e3431a02dfe 100644 --- a/jdk/src/share/classes/java/nio/X-Buffer.java.template +++ b/jdk/src/share/classes/java/nio/X-Buffer.java.template @@ -32,24 +32,24 @@ import java.io.IOException; #end[char] /** - * $A$ $fulltype$ buffer. + * $A$ $type$ buffer. * *

    This class defines {#if[byte]?six:four} categories of operations upon - * $fulltype$ buffers: + * $type$ buffers: * *

      * *
    • Absolute and relative {@link #get() get} and * {@link #put($type$) put} methods that read and write - * single $fulltype$s;

    • + * single $type$s;

      * *
    • Relative {@link #get($type$[]) bulk get} - * methods that transfer contiguous sequences of $fulltype$s from this buffer + * methods that transfer contiguous sequences of $type$s from this buffer * into an array; {#if[!byte]?and}

    • * *
    • Relative {@link #put($type$[]) bulk put} - * methods that transfer contiguous sequences of $fulltype$s from $a$ - * $fulltype$ array{#if[char]?, a string,} or some other $fulltype$ + * methods that transfer contiguous sequences of $type$s from $a$ + * $type$ array{#if[char]?, a string,} or some other $type$ * buffer into this buffer;{#if[!byte]? and}

    • * #if[byte] @@ -67,22 +67,22 @@ import java.io.IOException; * *
    • Methods for {@link #compact compacting}, {@link * #duplicate duplicating}, and {@link #slice - * slicing} $a$ $fulltype$ buffer.

    • + * slicing} $a$ $type$ buffer.

      * *
    * - *

    $Fulltype$ buffers can be created either by {@link #allocate + *

    $Type$ buffers can be created either by {@link #allocate * allocation}, which allocates space for the buffer's * #if[byte] * * content, or by {@link #wrap($type$[]) wrapping} an - * existing $fulltype$ array {#if[char]?or string} into a buffer. + * existing $type$ array {#if[char]?or string} into a buffer. * #else[byte] * * content, by {@link #wrap($type$[]) wrapping} an existing - * $fulltype$ array {#if[char]?or string} into a buffer, or by creating a + * $type$ array {#if[char]?or string} into a buffer, or by creating a * view of an existing byte buffer. * #end[byte] @@ -189,12 +189,12 @@ import java.io.IOException; * #if[!byte] * - *

    Like a byte buffer, $a$ $fulltype$ buffer is either Like a byte buffer, $a$ $type$ buffer is either direct or non-direct. A - * $fulltype$ buffer created via the wrap methods of this class will - * be non-direct. $A$ $fulltype$ buffer created as a view of a byte buffer will + * $type$ buffer created via the wrap methods of this class will + * be non-direct. $A$ $type$ buffer created as a view of a byte buffer will * be direct if, and only if, the byte buffer itself is direct. Whether or not - * $a$ $fulltype$ buffer is direct may be determined by invoking the {@link + * $a$ $type$ buffer is direct may be determined by invoking the {@link * #isDirect isDirect} method.

    * #end[!byte] @@ -287,7 +287,7 @@ public abstract class $Type$Buffer #if[byte] /** - * Allocates a new direct $fulltype$ buffer. + * Allocates a new direct $type$ buffer. * *

    The new buffer's position will be zero, its limit will be its * capacity, its mark will be undefined, and each of its elements will be @@ -295,9 +295,9 @@ public abstract class $Type$Buffer * {@link #hasArray backing array} is unspecified. * * @param capacity - * The new buffer's capacity, in $fulltype$s + * The new buffer's capacity, in $type$s * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer * * @throws IllegalArgumentException * If the capacity is a negative integer @@ -309,7 +309,7 @@ public abstract class $Type$Buffer #end[byte] /** - * Allocates a new $fulltype$ buffer. + * Allocates a new $type$ buffer. * *

    The new buffer's position will be zero, its limit will be its * capacity, its mark will be undefined, and each of its elements will be @@ -318,9 +318,9 @@ public abstract class $Type$Buffer * offset} will be zero. * * @param capacity - * The new buffer's capacity, in $fulltype$s + * The new buffer's capacity, in $type$s * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer * * @throws IllegalArgumentException * If the capacity is a negative integer @@ -332,9 +332,9 @@ public abstract class $Type$Buffer } /** - * Wraps $a$ $fulltype$ array into a buffer. + * Wraps $a$ $type$ array into a buffer. * - *

    The new buffer will be backed by the given $fulltype$ array; + *

    The new buffer will be backed by the given $type$ array; * that is, modifications to the buffer will cause the array to be modified * and vice versa. The new buffer's capacity will be * array.length, its position will be offset, its limit @@ -356,7 +356,7 @@ public abstract class $Type$Buffer * array.length - offset. * The new buffer's limit will be set to offset + length. * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer * * @throws IndexOutOfBoundsException * If the preconditions on the offset and length @@ -373,9 +373,9 @@ public abstract class $Type$Buffer } /** - * Wraps $a$ $fulltype$ array into a buffer. + * Wraps $a$ $type$ array into a buffer. * - *

    The new buffer will be backed by the given $fulltype$ array; + *

    The new buffer will be backed by the given $type$ array; * that is, modifications to the buffer will cause the array to be modified * and vice versa. The new buffer's capacity and limit will be * array.length, its position will be zero, and its mark will be @@ -386,7 +386,7 @@ public abstract class $Type$Buffer * @param array * The array that will back this buffer * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer */ public static $Type$Buffer wrap($type$[] array) { return wrap(array, 0, array.length); @@ -486,7 +486,7 @@ public abstract class $Type$Buffer #end[char] /** - * Creates a new $fulltype$ buffer whose content is a shared subsequence of + * Creates a new $type$ buffer whose content is a shared subsequence of * this buffer's content. * *

    The content of the new buffer will start at this buffer's current @@ -495,17 +495,17 @@ public abstract class $Type$Buffer * values will be independent. * *

    The new buffer's position will be zero, its capacity and its limit - * will be the number of $fulltype$s remaining in this buffer, and its mark + * will be the number of $type$s remaining in this buffer, and its mark * will be undefined. The new buffer will be direct if, and only if, this * buffer is direct, and it will be read-only if, and only if, this buffer * is read-only.

    * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer */ public abstract $Type$Buffer slice(); /** - * Creates a new $fulltype$ buffer that shares this buffer's content. + * Creates a new $type$ buffer that shares this buffer's content. * *

    The content of the new buffer will be that of this buffer. Changes * to this buffer's content will be visible in the new buffer, and vice @@ -517,12 +517,12 @@ public abstract class $Type$Buffer * and only if, this buffer is direct, and it will be read-only if, and * only if, this buffer is read-only.

    * - * @return The new $fulltype$ buffer + * @return The new $type$ buffer */ public abstract $Type$Buffer duplicate(); /** - * Creates a new, read-only $fulltype$ buffer that shares this buffer's + * Creates a new, read-only $type$ buffer that shares this buffer's * content. * *

    The content of the new buffer will be that of this buffer. Changes @@ -537,7 +537,7 @@ public abstract class $Type$Buffer *

    If this buffer is itself read-only then this method behaves in * exactly the same way as the {@link #duplicate duplicate} method.

    * - * @return The new, read-only $fulltype$ buffer + * @return The new, read-only $type$ buffer */ public abstract $Type$Buffer asReadOnlyBuffer(); @@ -545,10 +545,10 @@ public abstract class $Type$Buffer // -- Singleton get/put methods -- /** - * Relative get method. Reads the $fulltype$ at this buffer's + * Relative get method. Reads the $type$ at this buffer's * current position, and then increments the position.

    * - * @return The $fulltype$ at the buffer's current position + * @return The $type$ at the buffer's current position * * @throws BufferUnderflowException * If the buffer's current position is not smaller than its limit @@ -558,11 +558,11 @@ public abstract class $Type$Buffer /** * Relative put method  (optional operation). * - *

    Writes the given $fulltype$ into this buffer at the current + *

    Writes the given $type$ into this buffer at the current * position, and then increments the position.

    * * @param $x$ - * The $fulltype$ to be written + * The $type$ to be written * * @return This buffer * @@ -575,13 +575,13 @@ public abstract class $Type$Buffer public abstract $Type$Buffer put($type$ $x$); /** - * Absolute get method. Reads the $fulltype$ at the given + * Absolute get method. Reads the $type$ at the given * index.

    * * @param index - * The index from which the $fulltype$ will be read + * The index from which the $type$ will be read * - * @return The $fulltype$ at the given index + * @return The $type$ at the given index * * @throws IndexOutOfBoundsException * If index is negative @@ -592,14 +592,14 @@ public abstract class $Type$Buffer /** * Absolute put method  (optional operation). * - *

    Writes the given $fulltype$ into this buffer at the given + *

    Writes the given $type$ into this buffer at the given * index.

    * * @param index - * The index at which the $fulltype$ will be written + * The index at which the $type$ will be written * * @param $x$ - * The $fulltype$ value to be written + * The $type$ value to be written * * @return This buffer * @@ -618,14 +618,14 @@ public abstract class $Type$Buffer /** * Relative bulk get method. * - *

    This method transfers $fulltype$s from this buffer into the given - * destination array. If there are fewer $fulltype$s remaining in the + *

    This method transfers $type$s from this buffer into the given + * destination array. If there are fewer $type$s remaining in the * buffer than are required to satisfy the request, that is, if * length > remaining(), then no - * $fulltype$s are transferred and a {@link BufferUnderflowException} is + * $type$s are transferred and a {@link BufferUnderflowException} is * thrown. * - *

    Otherwise, this method copies length $fulltype$s from this + *

    Otherwise, this method copies length $type$s from this * buffer into the given array, starting at the current position of this * buffer and at the given offset in the array. The position of this * buffer is then incremented by length. @@ -638,26 +638,26 @@ public abstract class $Type$Buffer * for (int i = off; i < off + len; i++) * dst[i] = src.get(); * - * except that it first checks that there are sufficient $fulltype$s in + * except that it first checks that there are sufficient $type$s in * this buffer and it is potentially much more efficient.

    * * @param dst - * The array into which $fulltype$s are to be written + * The array into which $type$s are to be written * * @param offset - * The offset within the array of the first $fulltype$ to be + * The offset within the array of the first $type$ to be * written; must be non-negative and no larger than * dst.length * * @param length - * The maximum number of $fulltype$s to be written to the given + * The maximum number of $type$s to be written to the given * array; must be non-negative and no larger than * dst.length - offset * * @return This buffer * * @throws BufferUnderflowException - * If there are fewer than length $fulltype$s + * If there are fewer than length $type$s * remaining in this buffer * * @throws IndexOutOfBoundsException @@ -677,7 +677,7 @@ public abstract class $Type$Buffer /** * Relative bulk get method. * - *

    This method transfers $fulltype$s from this buffer into the given + *

    This method transfers $type$s from this buffer into the given * destination array. An invocation of this method of the form * src.get(a) behaves in exactly the same way as the invocation * @@ -687,7 +687,7 @@ public abstract class $Type$Buffer * @return This buffer * * @throws BufferUnderflowException - * If there are fewer than length $fulltype$s + * If there are fewer than length $type$s * remaining in this buffer */ public $Type$Buffer get($type$[] dst) { @@ -700,15 +700,15 @@ public abstract class $Type$Buffer /** * Relative bulk put method  (optional operation). * - *

    This method transfers the $fulltype$s remaining in the given source - * buffer into this buffer. If there are more $fulltype$s remaining in the + *

    This method transfers the $type$s remaining in the given source + * buffer into this buffer. If there are more $type$s remaining in the * source buffer than in this buffer, that is, if * src.remaining() > remaining(), - * then no $fulltype$s are transferred and a {@link + * then no $type$s are transferred and a {@link * BufferOverflowException} is thrown. * *

    Otherwise, this method copies - * n = src.remaining() $fulltype$s from the given + * n = src.remaining() $type$s from the given * buffer into this buffer, starting at each buffer's current position. * The positions of both buffers are then incremented by n. * @@ -723,14 +723,14 @@ public abstract class $Type$Buffer * buffer and it is potentially much more efficient.

    * * @param src - * The source buffer from which $fulltype$s are to be read; + * The source buffer from which $type$s are to be read; * must not be this buffer * * @return This buffer * * @throws BufferOverflowException * If there is insufficient space in this buffer - * for the remaining $fulltype$s in the source buffer + * for the remaining $type$s in the source buffer * * @throws IllegalArgumentException * If the source buffer is this buffer @@ -752,14 +752,14 @@ public abstract class $Type$Buffer /** * Relative bulk put method  (optional operation). * - *

    This method transfers $fulltype$s into this buffer from the given - * source array. If there are more $fulltype$s to be copied from the array + *

    This method transfers $type$s into this buffer from the given + * source array. If there are more $type$s to be copied from the array * than remain in this buffer, that is, if * length > remaining(), then no - * $fulltype$s are transferred and a {@link BufferOverflowException} is + * $type$s are transferred and a {@link BufferOverflowException} is * thrown. * - *

    Otherwise, this method copies length $fulltype$s from the + *

    Otherwise, this method copies length $type$s from the * given array into this buffer, starting at the given offset in the array * and at the current position of this buffer. The position of this buffer * is then incremented by length. @@ -776,14 +776,14 @@ public abstract class $Type$Buffer * buffer and it is potentially much more efficient.

    * * @param src - * The array from which $fulltype$s are to be read + * The array from which $type$s are to be read * * @param offset - * The offset within the array of the first $fulltype$ to be read; + * The offset within the array of the first $type$ to be read; * must be non-negative and no larger than array.length * * @param length - * The number of $fulltype$s to be read from the given array; + * The number of $type$s to be read from the given array; * must be non-negative and no larger than * array.length - offset * @@ -813,7 +813,7 @@ public abstract class $Type$Buffer * Relative bulk put method  (optional operation). * *

    This method transfers the entire content of the given source - * $fulltype$ array into this buffer. An invocation of this method of the + * $type$ array into this buffer. An invocation of this method of the * form dst.put(a) behaves in exactly the same way as the * invocation * @@ -837,15 +837,15 @@ public abstract class $Type$Buffer /** * Relative bulk put method  (optional operation). * - *

    This method transfers $fulltype$s from the given string into this - * buffer. If there are more $fulltype$s to be copied from the string than + *

    This method transfers $type$s from the given string into this + * buffer. If there are more $type$s to be copied from the string than * remain in this buffer, that is, if * end - start > remaining(), - * then no $fulltype$s are transferred and a {@link + * then no $type$s are transferred and a {@link * BufferOverflowException} is thrown. * *

    Otherwise, this method copies - * n = end - start $fulltype$s + * n = end - start $type$s * from the given string into this buffer, starting at the given * start index and at the current position of this buffer. The * position of this buffer is then incremented by n. @@ -862,15 +862,15 @@ public abstract class $Type$Buffer * buffer and it is potentially much more efficient.

    * * @param src - * The string from which $fulltype$s are to be read + * The string from which $type$s are to be read * * @param start - * The offset within the string of the first $fulltype$ to be read; + * The offset within the string of the first $type$ to be read; * must be non-negative and no larger than * string.length() * * @param end - * The offset within the string of the last $fulltype$ to be read, + * The offset within the string of the last $type$ to be read, * plus one; must be non-negative and no larger than * string.length() * @@ -921,7 +921,7 @@ public abstract class $Type$Buffer // -- Other stuff -- /** - * Tells whether or not this buffer is backed by an accessible $fulltype$ + * Tells whether or not this buffer is backed by an accessible $type$ * array. * *

    If this method returns true then the {@link #array() array} @@ -936,7 +936,7 @@ public abstract class $Type$Buffer } /** - * Returns the $fulltype$ array that backs this + * Returns the $type$ array that backs this * buffer  (optional operation). * *

    Modifications to this buffer's content will cause the returned @@ -993,17 +993,17 @@ public abstract class $Type$Buffer /** * Compacts this buffer  (optional operation). * - *

    The $fulltype$s between the buffer's current position and its limit, + *

    The $type$s between the buffer's current position and its limit, * if any, are copied to the beginning of the buffer. That is, the - * $fulltype$ at index p = position() is copied - * to index zero, the $fulltype$ at index p + 1 is copied - * to index one, and so forth until the $fulltype$ at index + * $type$ at index p = position() is copied + * to index zero, the $type$ at index p + 1 is copied + * to index one, and so forth until the $type$ at index * limit() - 1 is copied to index * n = limit() - 1 - p. * The buffer's position is then set to n+1 and its limit is set to * its capacity. The mark, if defined, is discarded. * - *

    The buffer's position is set to the number of $fulltype$s copied, + *

    The buffer's position is set to the number of $type$s copied, * rather than to zero, so that an invocation of this method can be * followed immediately by an invocation of another relative put * method.

    @@ -1032,7 +1032,7 @@ public abstract class $Type$Buffer public abstract $Type$Buffer compact(); /** - * Tells whether or not this $fulltype$ buffer is direct.

    + * Tells whether or not this $type$ buffer is direct.

    * * @return true if, and only if, this buffer is direct */ @@ -1098,6 +1098,13 @@ public abstract class $Type$Buffer * *
  • The two sequences of remaining elements, considered * independently of their starting positions, are pointwise equal. +#if[floatingPointType] + * This method considers two $type$ elements {@code a} and {@code b} + * to be equal if + * {@code (a == b) || ($Fulltype$.isNaN(a) && $Fulltype$.isNaN(b))}. + * The values {@code -0.0} and {@code +0.0} are considered to be + * equal, unlike {@link $Fulltype$#equals(Object)}. +#end[floatingPointType] *

  • * * @@ -1118,24 +1125,37 @@ public abstract class $Type$Buffer if (this.remaining() != that.remaining()) return false; int p = this.position(); - for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { - $type$ v1 = this.get(i); - $type$ v2 = that.get(j); - if (v1 != v2) { - if ((v1 != v1) && (v2 != v2)) // For float and double - continue; + for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) + if (!equals(this.get(i), that.get(j))) return false; - } - } return true; } + private static boolean equals($type$ x, $type$ y) { +#if[floatingPointType] + return (x == y) || ($Fulltype$.isNaN(x) && $Fulltype$.isNaN(y)); +#else[floatingPointType] + return x == y; +#end[floatingPointType] + } + /** * Compares this buffer to another. * *

    Two $type$ buffers are compared by comparing their sequences of * remaining elements lexicographically, without regard to the starting * position of each sequence within its corresponding buffer. +#if[floatingPointType] + * Pairs of {@code $type$} elements are compared as if by invoking + * {@link $Fulltype$#compare($type$,$type$)}, except that + * {@code -0.0} and {@code 0.0} are considered to be equal. + * {@code $Fulltype$.NaN} is considered by this method to be equal + * to itself and greater than all other {@code $type$} values + * (including {@code $Fulltype$.POSITIVE_INFINITY}). +#else[floatingPointType] + * Pairs of {@code $type$} elements are compared as if by invoking + * {@link $Fulltype$#compare($type$,$type$)}. +#end[floatingPointType] * *

    A $type$ buffer is not comparable to any other type of object. * @@ -1145,20 +1165,23 @@ public abstract class $Type$Buffer public int compareTo($Type$Buffer that) { int n = this.position() + Math.min(this.remaining(), that.remaining()); for (int i = this.position(), j = that.position(); i < n; i++, j++) { - $type$ v1 = this.get(i); - $type$ v2 = that.get(j); - if (v1 == v2) - continue; - if ((v1 != v1) && (v2 != v2)) // For float and double - continue; - if (v1 < v2) - return -1; - return +1; + int cmp = compare(this.get(i), that.get(j)); + if (cmp != 0) + return cmp; } return this.remaining() - that.remaining(); } - + private static int compare($type$ x, $type$ y) { +#if[floatingPointType] + return ((x < y) ? -1 : + (x > y) ? +1 : + (x == y) ? 0 : + $Fulltype$.isNaN(x) ? ($Fulltype$.isNaN(y) ? 0 : +1) : -1); +#else[floatingPointType] + return $Fulltype$.compare(x, y); +#end[floatingPointType] + } // -- Other char stuff -- @@ -1326,7 +1349,7 @@ public abstract class $Type$Buffer } /** - * Appends the specified $fulltype$ to this + * Appends the specified $type$ to this * buffer  (optional operation). * *

    An invocation of this method of the form dst.append($x$) @@ -1336,7 +1359,7 @@ public abstract class $Type$Buffer * dst.put($x$) * * @param $x$ - * The 16-bit $fulltype$ to append + * The 16-bit $type$ to append * * @return This buffer * @@ -1362,10 +1385,10 @@ public abstract class $Type$Buffer /** * Retrieves this buffer's byte order. * - *

    The byte order of $a$ $fulltype$ buffer created by allocation or by + *

    The byte order of $a$ $type$ buffer created by allocation or by * wrapping an existing $type$ array is the {@link * ByteOrder#nativeOrder native order} of the underlying - * hardware. The byte order of $a$ $fulltype$ buffer created as a view of a byte buffer is that of the * byte buffer at the moment that the view is created.

    * diff --git a/jdk/src/share/classes/java/rmi/activation/Activatable.java b/jdk/src/share/classes/java/rmi/activation/Activatable.java index 07879812774..de02b0d6e31 100644 --- a/jdk/src/share/classes/java/rmi/activation/Activatable.java +++ b/jdk/src/share/classes/java/rmi/activation/Activatable.java @@ -73,7 +73,7 @@ public abstract class Activatable extends RemoteServer { * can be handled properly. * *

    This method invokes the {@link - * exportObject(Remote,String,MarshalledObject,boolean,port) + * #exportObject(Remote,String,MarshalledObject,boolean,int) * exportObject} method with this object, and the specified location, * data, restart mode, and port. Subsequent calls to {@link #getID} * will return the activation identifier returned from the call to @@ -120,7 +120,7 @@ public abstract class Activatable extends RemoteServer { * can be handled properly. * *

    This method invokes the {@link - * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory) + * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory) * exportObject} method with this object, and the specified location, * data, restart mode, port, and client and server socket factories. * Subsequent calls to {@link #getID} will return the activation @@ -312,7 +312,7 @@ public abstract class Activatable extends RemoteServer { * separately, so that exceptions can be handled properly. * *

    This method invokes the {@link - * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory) + * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory) * exportObject} method with the specified object, location, data, * restart mode, and port, and null for both client and * server socket factories, and then returns the resulting activation diff --git a/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java b/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java index d32e4035749..b65feca8c80 100644 --- a/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java +++ b/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java @@ -187,7 +187,7 @@ public final class LocateRegistry { * host that accepts requests on the specified port. * *

    The Registry instance is exported as if the static - * {@link UnicastRemoteObject.exportObject(Remote,int) + * {@link UnicastRemoteObject#exportObject(Remote,int) * UnicastRemoteObject.exportObject} method is invoked, passing the * Registry instance and the specified port as * arguments, except that the Registry instance is @@ -213,7 +213,7 @@ public final class LocateRegistry { * *

    The Registry instance is exported as if * the static {@link - * UnicastRemoteObject.exportObject(Remote,int,RMIClientSocketFactory,RMIServerSocketFactory) + * UnicastRemoteObject#exportObject(Remote,int,RMIClientSocketFactory,RMIServerSocketFactory) * UnicastRemoteObject.exportObject} method is invoked, passing the * Registry instance, the specified port, the * specified RMIClientSocketFactory, and the specified diff --git a/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java b/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java index 59de6cfad02..06647bac951 100644 --- a/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java +++ b/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java @@ -138,7 +138,6 @@ public class RemoteObjectInvocationHandler * instance * @throws Throwable the exception to throw from the method invocation * on the proxy instance - * @see **/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable diff --git a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java index c1ca1d2b8de..86b0b45e276 100644 --- a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java +++ b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java @@ -216,7 +216,7 @@ public class CertPathValidatorException extends GeneralSecurityException { /** * Returns the reason that the validation failed. The reason is * associated with the index of the certificate returned by - * {@link getIndex}. + * {@link #getIndex}. * * @return the reason that the validation failed, or * BasicReason.UNSPECIFIED if a reason has not been diff --git a/jdk/src/share/classes/java/text/Bidi.java b/jdk/src/share/classes/java/text/Bidi.java index e4db4b2d086..504021ff143 100644 --- a/jdk/src/share/classes/java/text/Bidi.java +++ b/jdk/src/share/classes/java/text/Bidi.java @@ -121,9 +121,9 @@ public final class Bidi { * * @param paragraph a paragraph of text with optional character and paragraph attribute information * - * @see TextAttribute#BIDI_EMBEDDING - * @see TextAttribute#NUMERIC_SHAPING - * @see TextAttribute#RUN_DIRECTION + * @see java.awt.font.TextAttribute#BIDI_EMBEDDING + * @see java.awt.font.TextAttribute#NUMERIC_SHAPING + * @see java.awt.font.TextAttribute#RUN_DIRECTION */ public Bidi(AttributedCharacterIterator paragraph) { if (paragraph == null) { diff --git a/jdk/src/share/classes/java/util/NavigableMap.java b/jdk/src/share/classes/java/util/NavigableMap.java index 592a20dbe6d..7761b0742c5 100644 --- a/jdk/src/share/classes/java/util/NavigableMap.java +++ b/jdk/src/share/classes/java/util/NavigableMap.java @@ -298,7 +298,7 @@ public interface NavigableMap extends SortedMap { * Returns a view of the portion of this map whose keys range from * {@code fromKey} to {@code toKey}. If {@code fromKey} and * {@code toKey} are equal, the returned map is empty unless - * {@code fromExclusive} and {@code toExclusive} are both true. The + * {@code fromInclusive} and {@code toInclusive} are both true. The * returned map is backed by this map, so changes in the returned map are * reflected in this map, and vice-versa. The returned map supports all * optional map operations that this map supports. diff --git a/jdk/src/share/classes/java/util/NavigableSet.java b/jdk/src/share/classes/java/util/NavigableSet.java index b96299e1547..d4f0b2ccd7c 100644 --- a/jdk/src/share/classes/java/util/NavigableSet.java +++ b/jdk/src/share/classes/java/util/NavigableSet.java @@ -192,7 +192,7 @@ public interface NavigableSet extends SortedSet { * Returns a view of the portion of this set whose elements range from * {@code fromElement} to {@code toElement}. If {@code fromElement} and * {@code toElement} are equal, the returned set is empty unless {@code - * fromExclusive} and {@code toExclusive} are both true. The returned set + * fromInclusive} and {@code toInclusive} are both true. The returned set * is backed by this set, so changes in the returned set are reflected in * this set, and vice-versa. The returned set supports all optional set * operations that this set supports. diff --git a/jdk/src/share/classes/java/util/Objects.java b/jdk/src/share/classes/java/util/Objects.java index 3ef61bde98d..8b009243eb9 100644 --- a/jdk/src/share/classes/java/util/Objects.java +++ b/jdk/src/share/classes/java/util/Objects.java @@ -119,7 +119,7 @@ public final class Objects { * * @param values the values to be hashed * @return a hash value of the sequence of input values - * @see Arrays#hashCode + * @see Arrays#hashCode(Object[]) * @see List#hashCode */ public static int hash(Object... values) { diff --git a/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java index f994e285bcd..b27339461cb 100644 --- a/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java +++ b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java @@ -51,7 +51,7 @@ import java.lang.management.PlatformManagedObject; * The {@link PlatformManagedObject#getObjectName} method * can be used to obtain its {@code ObjectName}. * - * @See java.lang.management.PlatformManagedObject + * @see java.lang.management.PlatformManagedObject * * @author Mandy Chung * @since 1.7 diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleContext.java b/jdk/src/share/classes/javax/accessibility/AccessibleContext.java index fbe7e9b1d6f..d4a093f72ec 100644 --- a/jdk/src/share/classes/javax/accessibility/AccessibleContext.java +++ b/jdk/src/share/classes/javax/accessibility/AccessibleContext.java @@ -296,7 +296,7 @@ public abstract class AccessibleContext { * * @see #getAccessibleText * @see #addPropertyChangeListener - * @see #AccessibleText.AccessibleTextSequence + * @see AccessibleTextSequence */ public static final String ACCESSIBLE_TEXT_PROPERTY = "AccessibleText"; @@ -311,7 +311,7 @@ public abstract class AccessibleContext { * * @see #getAccessibleText * @see #addPropertyChangeListener - * @see #AccessibleText.AccessibleTextSequence + * @see AccessibleTextSequence * * @since 1.5 */ @@ -334,7 +334,7 @@ public abstract class AccessibleContext { * * @see #getAccessibleText * @see #addPropertyChangeListener - * @see #AccessibleText.AccessibleAttributeSequence + * @see AccessibleAttributeSequence * * @since 1.5 */ diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java b/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java index 4868ab85e8f..f7a04252136 100644 --- a/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java +++ b/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java @@ -45,7 +45,6 @@ import javax.swing.text.*; * @see Accessible#getAccessibleContext * @see AccessibleContext * @see AccessibleContext#getAccessibleText - * @see AccessibleText.AccessibleTextChunk * * @author Peter Korn * @author Lynn Monsanto diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java b/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java index cdf4c493a62..e50e9f54259 100644 --- a/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java +++ b/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java @@ -32,16 +32,11 @@ package javax.accessibility; * the standard mechanism for an assistive technology to determine the * key bindings which exist for this object. * Any object that has such key bindings should support this - * interface. Applications can determine if an object supports the - * AccessibleKeyBinding interface by first obtaining its AccessibleContext - * (see @link Accessible} and then calling the - * {@link AccessibleContext#getAccessibleKeyBinding} method. If the return - * value is not null, the object supports this interface. + * interface. * * @see Accessible * @see Accessible#getAccessibleContext * @see AccessibleContext - * @see AccessibleContext#getAccessibleKeyBinding * * @author Lynn Monsanto * @since 1.4 @@ -58,21 +53,7 @@ public interface AccessibleKeyBinding { /** * Returns a key binding for this object. The value returned is an * java.lang.Object which must be cast to appropriate type depending - * on the underlying implementation of the key. For example, if the - * Object returned is a javax.swing.KeyStroke, the user of this - * method should do the following: - * - * Component c = - * AccessibleContext ac = c.getAccessibleContext(); - * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding(); - * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) { - * Object o = akb.getAccessibleKeyBinding(i); - * if (o instanceof javax.swing.KeyStroke) { - * javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o; - * - * } - * } - * + * on the underlying implementation of the key. * * @param i zero-based index of the key bindings * @return a javax.lang.Object which specifies the key binding diff --git a/jdk/src/share/classes/org/ietf/jgss/GSSName.java b/jdk/src/share/classes/org/ietf/jgss/GSSName.java index f29efc74368..acc0ee55afb 100644 --- a/jdk/src/share/classes/org/ietf/jgss/GSSName.java +++ b/jdk/src/share/classes/org/ietf/jgss/GSSName.java @@ -1,5 +1,5 @@ /* - * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,11 +103,12 @@ public interface GSSName { * follows: service@hostname.

    * * It represents the following Oid value:
    - * { 1(iso), 3(org), 6(dod), 1(internet), 5(security), - * 6(nametypes), 2(gss-host-based-services) } + * { iso(1) member-body(2) United + * States(840) mit(113554) infosys(1) gssapi(2) generic(1) service_name(4) + * } */ public static final Oid NT_HOSTBASED_SERVICE - = Oid.getInstance("1.3.6.1.5.6.2"); + = Oid.getInstance("1.2.840.113554.1.2.1.4"); /** * Name type to indicate a named user on a local system.

    diff --git a/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java b/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java index a758486e0cb..092681bd92d 100644 --- a/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java +++ b/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java @@ -326,7 +326,7 @@ public final class DOMXMLSignature extends DOMStructure } // generate references and signature value - List allReferences = new ArrayList(si.getReferences()); + List allReferences = new ArrayList(); // traverse the Signature and register all objects with IDs that // may contain References @@ -356,6 +356,9 @@ public final class DOMXMLSignature extends DOMStructure } } } + // always add SignedInfo references after Manifest references so + // that Manifest reference are digested first + allReferences.addAll(si.getReferences()); // generate/digest each reference for (int i = 0, size = allReferences.size(); i < size; i++) { diff --git a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java b/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java index 334e0a563a7..3a2013551a3 100644 --- a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java +++ b/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java @@ -30,7 +30,7 @@ import sun.dyn.util.Wrapper; import java.dyn.*; import java.util.Arrays; import static sun.dyn.MethodHandleNatives.Constants.*; -import static sun.dyn.MethodHandleImpl.newIllegalArgumentException; +import static sun.dyn.MemberName.newIllegalArgumentException; /** * This method handle performs simple conversion or checking of a single argument. @@ -302,7 +302,22 @@ public class AdapterMethodHandle extends BoundMethodHandle { */ private static int type2size(int type) { assert(type >= T_BOOLEAN && type <= T_OBJECT); - return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1; + return (type == T_LONG || type == T_DOUBLE) ? 2 : 1; + } + private static int type2size(Class type) { + return type2size(basicType(type)); + } + + /** The given stackMove is the number of slots pushed. + * It might be negative. Scale it (multiply) by the + * VM's notion of how an address changes with a push, + * to get the raw SP change for stackMove. + * Then shift and mask it into the correct field. + */ + private static long insertStackMove(int stackMove) { + // following variable must be long to avoid sign extension after '<<' + long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT; + return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT; } /** Construct an adapter conversion descriptor for a single-argument conversion. */ @@ -310,16 +325,16 @@ public class AdapterMethodHandle extends BoundMethodHandle { assert(src == (src & 0xF)); assert(dest == (dest & 0xF)); assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF); - long stackMove = type2size(dest) - type2size(src); + int stackMove = type2size(dest) - type2size(src); return ((long) argnum << 32 | (long) convOp << CONV_OP_SHIFT | (int) src << CONV_SRC_TYPE_SHIFT | (int) dest << CONV_DEST_TYPE_SHIFT | - stackMove << CONV_STACK_MOVE_SHIFT + insertStackMove(stackMove) ); } private static long makeConv(int convOp, int argnum, int stackMove) { - assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS); + assert(convOp >= OP_DUP_ARGS && convOp <= OP_SPREAD_ARGS); byte src = 0, dest = 0; if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS) src = dest = T_OBJECT; @@ -327,12 +342,21 @@ public class AdapterMethodHandle extends BoundMethodHandle { (long) convOp << CONV_OP_SHIFT | (int) src << CONV_SRC_TYPE_SHIFT | (int) dest << CONV_DEST_TYPE_SHIFT | - stackMove << CONV_STACK_MOVE_SHIFT + insertStackMove(stackMove) + ); + } + private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) { + assert(convOp >= OP_SWAP_ARGS && convOp <= OP_ROT_ARGS); + return ((long) srcArg << 32 | + (long) convOp << CONV_OP_SHIFT | + (int) type << CONV_SRC_TYPE_SHIFT | + (int) type << CONV_DEST_TYPE_SHIFT | + (int) destSlot << CONV_VMINFO_SHIFT ); } private static long makeConv(int convOp) { - assert(convOp == OP_RETYPE_ONLY); - return (long) convOp << CONV_OP_SHIFT; // stackMove, src, dst, argnum all zero + assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW); + return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT); // stackMove, src, dst all zero } private static int convCode(long conv) { return (int)conv; @@ -348,16 +372,6 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** One of OP_RETYPE_ONLY, etc. */ int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; } - @Override - public String toString() { - return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]"); - } - - private static MethodHandle nonAdapter(MethodHandle mh) { - return (MethodHandle) - MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE); - } - /* Return one plus the position of the first non-trivial difference * between the given types. This is not a symmetric operation; * we are considering adapting the targetType to adapterType. @@ -399,14 +413,14 @@ public class AdapterMethodHandle extends BoundMethodHandle { //if (false) return 1; // never adaptable! return -1; // some significant difference } - private static int diffParamTypes(MethodType adapterType, int tstart, - MethodType targetType, int astart, + private static int diffParamTypes(MethodType adapterType, int astart, + MethodType targetType, int tstart, int nargs, boolean raw) { assert(nargs >= 0); int res = 0; for (int i = 0; i < nargs; i++) { - Class src = adapterType.parameterType(tstart+i); - Class dest = targetType.parameterType(astart+i); + Class src = adapterType.parameterType(astart+i); + Class dest = targetType.parameterType(tstart+i); if ((!raw ? VerifyType.canPassUnchecked(src, dest) : VerifyType.canPassRaw(src, dest) @@ -422,7 +436,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { /** Can a retyping adapter (alone) validly convert the target to newType? */ public static boolean canRetypeOnly(MethodType newType, MethodType targetType) { - return canRetypeOnly(newType, targetType, false); + return canRetype(newType, targetType, false); } /** Can a retyping adapter (alone) convert the target to newType? * It is allowed to widen subword types and void to int, to make bitwise @@ -430,14 +444,14 @@ public class AdapterMethodHandle extends BoundMethodHandle { * reference conversions on return. This last feature requires that the * caller be trusted, and perform explicit cast conversions on return values. */ - static boolean canRawRetypeOnly(MethodType newType, MethodType targetType) { - return canRetypeOnly(newType, targetType, true); + public static boolean canRetypeRaw(MethodType newType, MethodType targetType) { + return canRetype(newType, targetType, true); } - static boolean canRetypeOnly(MethodType newType, MethodType targetType, boolean raw) { - if (!convOpSupported(OP_RETYPE_ONLY)) return false; + static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) { + if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)) return false; int diff = diffTypes(newType, targetType, raw); // %%% This assert is too strong. Factor diff into VerifyType and reconcile. - assert((diff == 0) == VerifyType.isNullConversion(newType, targetType)); + assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType)); return diff == 0; } @@ -447,19 +461,21 @@ public class AdapterMethodHandle extends BoundMethodHandle { */ public static MethodHandle makeRetypeOnly(Access token, MethodType newType, MethodHandle target) { - return makeRetypeOnly(token, newType, target, false); + return makeRetype(token, newType, target, false); } - public static MethodHandle makeRawRetypeOnly(Access token, + public static MethodHandle makeRetypeRaw(Access token, MethodType newType, MethodHandle target) { - return makeRetypeOnly(token, newType, target, true); + return makeRetype(token, newType, target, true); } - static MethodHandle makeRetypeOnly(Access token, + static MethodHandle makeRetype(Access token, MethodType newType, MethodHandle target, boolean raw) { Access.check(token); - if (!canRetypeOnly(newType, target.type(), raw)) + MethodType oldType = target.type(); + if (oldType == newType) return target; + if (!canRetype(newType, oldType, raw)) return null; // TO DO: clone the target guy, whatever he is, with new type. - return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY)); + return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)); } /** Can a checkcast adapter validly convert the target to newType? @@ -492,7 +508,7 @@ public class AdapterMethodHandle extends BoundMethodHandle { Access.check(token); if (!canCheckCast(newType, target.type(), arg, castType)) return null; - long conv = makeConv(OP_CHECK_CAST, arg, 0); + long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT); return new AdapterMethodHandle(target, newType, conv, castType); } @@ -537,10 +553,9 @@ public class AdapterMethodHandle extends BoundMethodHandle { int arg, Class convType) { Access.check(token); MethodType oldType = target.type(); - Class src = newType.parameterType(arg); - Class dst = oldType.parameterType(arg); if (!canPrimCast(newType, oldType, arg, convType)) return null; + Class src = newType.parameterType(arg); long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType)); return new AdapterMethodHandle(target, newType, conv); } @@ -607,8 +622,6 @@ public class AdapterMethodHandle extends BoundMethodHandle { return null; } - // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments - /** Can an adapter simply drop arguments to convert the target to newType? */ public static boolean canDropArguments(MethodType newType, MethodType targetType, int dropArgPos, int dropArgCount) { @@ -643,26 +656,195 @@ public class AdapterMethodHandle extends BoundMethodHandle { Access.check(token); if (dropArgCount == 0) return makeRetypeOnly(IMPL_TOKEN, newType, target); - MethodType mt = target.type(); - int argCount = mt.parameterCount(); - if (!canDropArguments(newType, mt, dropArgPos, dropArgCount)) + if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount)) return null; - int dropSlotCount, dropSlotPos; - if (dropArgCount >= argCount) { - assert(dropArgPos == argCount-1); - dropSlotPos = 0; - dropSlotCount = mt.parameterSlotCount(); + // in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ] + // out arglist: [0: ...keep1 | dpos: keep2... ] + int keep2InPos = dropArgPos + dropArgCount; + int dropSlot = newType.parameterSlotDepth(keep2InPos); + int keep1InSlot = newType.parameterSlotDepth(dropArgPos); + int slotCount = keep1InSlot - dropSlot; + assert(slotCount >= dropArgCount); + assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount()); + long conv = makeConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount); + return new AdapterMethodHandle(target, newType, conv); + } + + /** Can an adapter duplicate an argument to convert the target to newType? */ + public static boolean canDupArguments(MethodType newType, MethodType targetType, + int dupArgPos, int dupArgCount) { + if (!convOpSupported(OP_DUP_ARGS)) return false; + if (diffReturnTypes(newType, targetType, false) != 0) + return false; + int nptypes = newType.parameterCount(); + if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes) + return false; + if (targetType.parameterCount() != nptypes + dupArgCount) + return false; + // parameter types must be the same up to the duplicated arguments + if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0) + return false; + // duplicated types must be, well, duplicates + if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0) + return false; + return true; + } + + /** Factory method: Duplicate the selected argument. + * Return null if this is not possible. + */ + public static MethodHandle makeDupArguments(Access token, + MethodType newType, MethodHandle target, + int dupArgPos, int dupArgCount) { + Access.check(token); + if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount)) + return null; + if (dupArgCount == 0) + return target; + // in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ] + // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ] + int keep2InPos = dupArgPos + dupArgCount; + int dupSlot = newType.parameterSlotDepth(keep2InPos); + int keep1InSlot = newType.parameterSlotDepth(dupArgPos); + int slotCount = keep1InSlot - dupSlot; + assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount()); + long conv = makeConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount); + return new AdapterMethodHandle(target, newType, conv); + } + + /** Can an adapter swap two arguments to convert the target to newType? */ + public static boolean canSwapArguments(MethodType newType, MethodType targetType, + int swapArg1, int swapArg2) { + if (!convOpSupported(OP_SWAP_ARGS)) return false; + if (diffReturnTypes(newType, targetType, false) != 0) + return false; + if (swapArg1 >= swapArg2) return false; // caller resp + int nptypes = newType.parameterCount(); + if (targetType.parameterCount() != nptypes) + return false; + if (swapArg1 < 0 || swapArg2 >= nptypes) + return false; + if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0) + return false; + if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0) + return false; + if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0) + return false; + if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0) + return false; + if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0) + return false; + return true; + } + + /** Factory method: Swap the selected arguments. + * Return null if this is not possible. + */ + public static MethodHandle makeSwapArguments(Access token, + MethodType newType, MethodHandle target, + int swapArg1, int swapArg2) { + Access.check(token); + if (swapArg1 == swapArg2) + return target; + if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } + if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) + return null; + Class swapType = newType.parameterType(swapArg1); + // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] + // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] + int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1); + long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2); + return new AdapterMethodHandle(target, newType, conv); + } + + static int positiveRotation(int argCount, int rotateBy) { + assert(argCount > 0); + if (rotateBy >= 0) { + if (rotateBy < argCount) + return rotateBy; + return rotateBy % argCount; + } else if (rotateBy >= -argCount) { + return rotateBy + argCount; } else { - // arglist: [0: keep... | dpos: drop... | dpos+dcount: keep... ] - int lastDroppedArg = dropArgPos + dropArgCount - 1; - int lastKeptArg = dropArgPos - 1; // might be -1, which is OK - dropSlotPos = mt.parameterSlotDepth(1+lastDroppedArg); - int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg); - dropSlotCount = lastKeptSlot - dropSlotPos; - assert(dropSlotCount >= dropArgCount); + return (-1-((-1-rotateBy) % argCount)) + argCount; } - long conv = makeConv(OP_DROP_ARGS, dropArgPos, +dropSlotCount); - return new AdapterMethodHandle(target, newType, dropSlotCount, conv); + } + + final static int MAX_ARG_ROTATION = 1; + + /** Can an adapter rotate arguments to convert the target to newType? */ + public static boolean canRotateArguments(MethodType newType, MethodType targetType, + int firstArg, int argCount, int rotateBy) { + if (!convOpSupported(OP_ROT_ARGS)) return false; + if (argCount <= 2) return false; // must be a swap, not a rotate + rotateBy = positiveRotation(argCount, rotateBy); + if (rotateBy == 0) return false; // no rotation + if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) + return false; // too many argument positions + // Rotate incoming args right N to the out args, N in 1..(argCouunt-1). + if (diffReturnTypes(newType, targetType, false) != 0) + return false; + int nptypes = newType.parameterCount(); + if (targetType.parameterCount() != nptypes) + return false; + if (firstArg < 0 || firstArg >= nptypes) return false; + int argLimit = firstArg + argCount; + if (argLimit > nptypes) return false; + if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0) + return false; + int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy; + // swap new chunk1 with target chunk2 + if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0) + return false; + // swap new chunk2 with target chunk1 + if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0) + return false; + return true; + } + + /** Factory method: Rotate the selected argument range. + * Return null if this is not possible. + */ + public static MethodHandle makeRotateArguments(Access token, + MethodType newType, MethodHandle target, + int firstArg, int argCount, int rotateBy) { + Access.check(token); + rotateBy = positiveRotation(argCount, rotateBy); + if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy)) + return null; + // Decide whether it should be done as a right or left rotation, + // on the JVM stack. Return the number of stack slots to rotate by, + // positive if right, negative if left. + int limit = firstArg + argCount; + int depth0 = newType.parameterSlotDepth(firstArg); + int depth1 = newType.parameterSlotDepth(limit-rotateBy); + int depth2 = newType.parameterSlotDepth(limit); + int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0); + int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0); + // From here on out, it assumes a single-argument shift. + assert(MAX_ARG_ROTATION == 1); + int srcArg, dstArg; + byte basicType; + if (chunk2Slots <= chunk1Slots) { + // Rotate right/down N (rotateBy = +N, N small, c2 small): + // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ] + // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] + srcArg = limit-1; + dstArg = firstArg; + basicType = basicType(newType.parameterType(srcArg)); + assert(chunk2Slots == type2size(basicType)); + } else { + // Rotate left/up N (rotateBy = -N, N small, c1 small): + // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ] + // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] + srcArg = firstArg; + dstArg = limit-1; + basicType = basicType(newType.parameterType(srcArg)); + assert(chunk1Slots == type2size(basicType)); + } + int dstSlot = newType.parameterSlotDepth(dstArg + 1); + long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot); + return new AdapterMethodHandle(target, newType, conv); } /** Can an adapter spread an argument to convert the target to newType? */ @@ -676,10 +858,10 @@ public class AdapterMethodHandle extends BoundMethodHandle { if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0) return false; int afterPos = spreadArgPos + spreadArgCount; - int afterCount = nptypes - afterPos; + int afterCount = nptypes - (spreadArgPos + 1); if (spreadArgPos < 0 || spreadArgPos >= nptypes || spreadArgCount < 0 || - targetType.parameterCount() != nptypes - 1 + spreadArgCount) + targetType.parameterCount() != afterPos + afterCount) return false; // parameter types after the spread point must also be the same if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0) @@ -697,32 +879,40 @@ public class AdapterMethodHandle extends BoundMethodHandle { return true; } + /** Factory method: Spread selected argument. */ public static MethodHandle makeSpreadArguments(Access token, MethodType newType, MethodHandle target, Class spreadArgType, int spreadArgPos, int spreadArgCount) { Access.check(token); - MethodType mt = target.type(); - int argCount = mt.parameterCount(); - if (!canSpreadArguments(newType, mt, spreadArgType, spreadArgPos, spreadArgCount)) + MethodType targetType = target.type(); + if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) return null; - int spreadSlotCount, spreadSlotPos; - if (spreadArgCount >= argCount) { - assert(spreadArgPos == argCount-1); - spreadSlotPos = 0; - spreadSlotCount = mt.parameterSlotCount(); - } else { - // arglist: [0: keep... | dpos: spread... | dpos+dcount: keep... ] - int lastSpreadArg = spreadArgPos + spreadArgCount - 1; - int lastKeptArg = spreadArgPos - 1; // might be -1, which is OK - spreadSlotPos = mt.parameterSlotDepth(1+lastSpreadArg); - int lastKeptSlot = mt.parameterSlotDepth(1+lastKeptArg); - spreadSlotCount = lastKeptSlot - spreadSlotPos; - assert(spreadSlotCount >= spreadArgCount); - } - long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, spreadSlotCount); - return new AdapterMethodHandle(target, newType, conv, spreadArgType); + // in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ] + // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ] + int keep2OutPos = spreadArgPos + spreadArgCount; + int spreadSlot = targetType.parameterSlotDepth(keep2OutPos); + int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos); + int slotCount = keep1OutSlot - spreadSlot; + assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+1)); + assert(slotCount >= spreadArgCount); + long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, slotCount-1); + MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType); + assert(res.type().parameterType(spreadArgPos) == spreadArgType); + return res; } // TO DO: makeCollectArguments, makeFlyby, makeRicochet + + @Override + public String toString() { + return nonAdapter((MethodHandle)vmtarget).toString(); + } + + private static MethodHandle nonAdapter(MethodHandle mh) { + while (mh instanceof AdapterMethodHandle) { + mh = (MethodHandle) mh.vmtarget; + } + return mh; + } } diff --git a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java b/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java index b0c511c2171..66bf2c97323 100644 --- a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java +++ b/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java @@ -28,6 +28,10 @@ package sun.dyn; import sun.dyn.util.VerifyType; import sun.dyn.util.Wrapper; import java.dyn.*; +import java.util.List; +import sun.dyn.MethodHandleNatives.Constants; +import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP; +import static sun.dyn.MemberName.newIllegalArgumentException; /** * The flavor of method handle which emulates an invoke instruction @@ -35,18 +39,23 @@ import java.dyn.*; * when the handle is created, not when it is invoked. * @author jrose */ -public class BoundMethodHandle extends MethodHandle { +public class BoundMethodHandle extends MethodHandle { //MethodHandle vmtarget; // next BMH or final DMH or methodOop private final Object argument; // argument to insert private final int vmargslot; // position at which it is inserted + private static final Access IMPL_TOKEN = Access.getToken(); + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN); + // Constructors in this class *must* be package scoped or private. + // Exception: JavaMethodHandle constructors are protected. + // (The link between JMH and BMH is temporary.) /** Bind a direct MH to its receiver (or first ref. argument). * The JVM will pre-dispatch the MH if it is not already static. */ BoundMethodHandle(DirectMethodHandle mh, Object argument) { - super(Access.TOKEN, mh.type().dropParameterType(0)); + super(Access.TOKEN, mh.type().dropParameterTypes(0, 1)); // check the type now, once for all: this.argument = checkReferenceArgument(argument, mh, 0); this.vmargslot = this.type().parameterSlotCount(); @@ -56,32 +65,34 @@ public class BoundMethodHandle extends MethodHandle { } else { this.vmtarget = mh; } - } - - private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2; + } /** Insert an argument into an arbitrary method handle. * If argnum is zero, inserts the first argument, etc. * The argument type must be a reference. */ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { - this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG); + this(mh.type().dropParameterTypes(argnum, argnum+1), + mh, argument, argnum); } /** Insert an argument into an arbitrary method handle. * If argnum is zero, inserts the first argument, etc. */ - BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) { - super(Access.TOKEN, mh.type().dropParameterType(argnum)); - if (whichArg == PRIM_ARG) + BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) { + super(Access.TOKEN, type); + if (mh.type().parameterType(argnum).isPrimitive()) this.argument = bindPrimitiveArgument(argument, mh, argnum); else { - if (whichArg == SELF_ARG) argument = this; this.argument = checkReferenceArgument(argument, mh, argnum); } - this.vmargslot = this.type().parameterSlotDepth(argnum); + this.vmargslot = type.parameterSlotDepth(argnum); + initTarget(mh, argnum); + } + + private void initTarget(MethodHandle mh, int argnum) { if (MethodHandleNatives.JVM_SUPPORT) { - this.vmtarget = null; // maybe updated by JVM + this.vmtarget = null; // maybe updated by JVM MethodHandleNatives.init(this, mh, argnum); } else { this.vmtarget = mh; @@ -97,29 +108,65 @@ public class BoundMethodHandle extends MethodHandle { assert(this.getClass() == AdapterMethodHandle.class); } - /** Initialize the current object as a method handle, binding it - * as the {@code argnum}th argument of the method handle {@code entryPoint}. - * The invocation type of the resulting method handle will be the - * same as {@code entryPoint}, except that the {@code argnum}th argument - * type will be dropped. - */ - public BoundMethodHandle(MethodHandle entryPoint, int argnum) { - this(entryPoint, null, argnum, SELF_ARG); - - // Note: If the conversion fails, perhaps because of a bad entryPoint, - // the MethodHandle.type field will not be filled in, and therefore - // no MH.invoke call will ever succeed. The caller may retain a pointer - // to the broken method handle, but no harm can be done with it. - } - - /** Initialize the current object as a method handle, binding it + /** Initialize the current object as a Java method handle, binding it * as the first argument of the method handle {@code entryPoint}. * The invocation type of the resulting method handle will be the * same as {@code entryPoint}, except that the first argument * type will be dropped. */ - public BoundMethodHandle(MethodHandle entryPoint) { - this(entryPoint, null, 0, SELF_ARG); + protected BoundMethodHandle(MethodHandle entryPoint) { + super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1)); + this.argument = this; // kludge; get rid of + this.vmargslot = this.type().parameterSlotDepth(0); + initTarget(entryPoint, 0); + assert(this instanceof JavaMethodHandle); + } + + /** Initialize the current object as a Java method handle. + */ + protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) { + super(Access.TOKEN, null); + MethodHandle entryPoint + = findJavaMethodHandleEntryPoint(this.getClass(), + entryPointName, type, matchArity); + MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1)); + this.argument = this; // kludge; get rid of + this.vmargslot = this.type().parameterSlotDepth(0); + initTarget(entryPoint, 0); + assert(this instanceof JavaMethodHandle); + } + + private static + MethodHandle findJavaMethodHandleEntryPoint(Class caller, + String name, + MethodType type, + boolean matchArity) { + if (matchArity) type.getClass(); // elicit NPE + List methods = IMPL_NAMES.getMethods(caller, true, name, null, caller); + MethodType foundType = null; + MemberName foundMethod = null; + for (MemberName method : methods) { + MethodType mtype = method.getMethodType(); + if (type != null && type.parameterCount() != mtype.parameterCount()) + continue; + else if (foundType == null) + foundType = mtype; + else if (foundType != mtype) + throw newIllegalArgumentException("more than one method named "+name+" in "+caller.getName()); + // discard overrides + if (foundMethod == null) + foundMethod = method; + else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) + foundMethod = method; + } + if (foundMethod == null) + throw newIllegalArgumentException("no method named "+name+" in "+caller.getName()); + MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller); + if (type != null) { + MethodType epType = type.insertParameterTypes(0, entryPoint.type().parameterType(0)); + entryPoint = MethodHandles.convertArguments(entryPoint, epType); + } + return entryPoint; } /** Make sure the given {@code argument} can be used as {@code argnum}-th @@ -175,6 +222,24 @@ public class BoundMethodHandle extends MethodHandle { @Override public String toString() { - return "Bound[" + super.toString() + "]"; + MethodHandle mh = this; + while (mh instanceof BoundMethodHandle) { + Object info = MethodHandleNatives.getTargetInfo(mh); + if (info instanceof MethodHandle) { + mh = (MethodHandle) info; + } else { + String name = null; + if (info instanceof MemberName) + name = ((MemberName)info).getName(); + if (name != null) + return name; + else + return super.toString(); // , probably + } + assert(mh != this); + if (mh instanceof JavaMethodHandle) + break; // access JMH.toString(), not BMH.toString() + } + return mh.toString(); } } diff --git a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java index c5ac600eacd..247aaf1e83f 100644 --- a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java +++ b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java @@ -26,34 +26,51 @@ package sun.dyn; import java.dyn.*; +import java.util.logging.Level; +import java.util.logging.Logger; /** - * The CallSite privately created by the JVM at every invokedynamic instruction. + * Parts of CallSite known to the JVM. + * FIXME: Merge all this into CallSite proper. * @author jrose */ -class CallSiteImpl extends CallSite { - // Fields used only by the JVM. Do not use or change. +public class CallSiteImpl { + // Field used only by the JVM. Do not use or change. private Object vmmethod; // Values supplied by the JVM: - int callerMID, callerBCI; + protected int callerMID, callerBCI; - private CallSiteImpl(Class caller, String name, MethodType type) { - super(caller, name, type); + private MethodHandle target; + protected final Object caller; // usually a class + protected final String name; + protected final MethodType type; + + /** called only directly from CallSite() */ + protected CallSiteImpl(Access token, Object caller, String name, MethodType type) { + Access.check(token); + this.caller = caller; + this.name = name; + this.type = type; } - @Override - public void setTarget(MethodHandle mh) { - checkTarget(mh); - if (MethodHandleNatives.JVM_SUPPORT) - MethodHandleNatives.linkCallSite(this, (MethodHandle) mh); - else - super.setTarget(mh); + /** native version of setTarget */ + protected void setTarget(MethodHandle mh) { + //System.out.println("setTarget "+this+" := "+mh); + // XXX I don't know how to fix this properly. +// if (false && MethodHandleNatives.JVM_SUPPORT) // FIXME: enable this +// MethodHandleNatives.linkCallSite(this, mh); +// else + this.target = mh; + } + + protected MethodHandle getTarget() { + return target; } private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE = MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite", - MethodType.make(void.class, CallSite.class, int.class, int.class)); + MethodType.methodType(void.class, CallSite.class, int.class, int.class)); // this is the up-call from the JVM: static CallSite makeSite(Class caller, String name, MethodType type, @@ -61,10 +78,25 @@ class CallSiteImpl extends CallSite { MethodHandle bsm = Linkage.getBootstrapMethod(caller); if (bsm == null) throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller); - CallSite site = bsm.invoke(caller, name, type); + CallSite site; + try { + site = bsm.invoke(caller, name, type); + } catch (Throwable ex) { + throw new InvokeDynamicBootstrapError("exception thrown while linking", ex); + } if (site == null) throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller); - PRIVATE_INITIALIZE_CALL_SITE.invoke(site, callerMID, callerBCI); + if (site.type() != type) + throw new InvokeDynamicBootstrapError("call site type not initialized correctly: "+site); + if (site.callerClass() != caller) + throw new InvokeDynamicBootstrapError("call site caller not initialized correctly: "+site); + if ((Object)site.name() != name) + throw new InvokeDynamicBootstrapError("call site name not initialized correctly: "+site); + try { + PRIVATE_INITIALIZE_CALL_SITE.invoke(site, callerMID, callerBCI); + } catch (Throwable ex) { + throw new InvokeDynamicBootstrapError("call site initialization exception", ex); + } return site; } } diff --git a/jdk/src/share/classes/sun/dyn/FilterGeneric.java b/jdk/src/share/classes/sun/dyn/FilterGeneric.java index a746ad21b95..37c4f40d231 100644 --- a/jdk/src/share/classes/sun/dyn/FilterGeneric.java +++ b/jdk/src/share/classes/sun/dyn/FilterGeneric.java @@ -31,174 +31,159 @@ import java.dyn.MethodType; import java.dyn.NoAccessException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import static sun.dyn.MemberName.newIllegalArgumentException; /** - * "Flyby adapters" which apply arbitrary conversions to arguments + * These adapters apply arbitrary conversions to arguments * on the way to a ultimate target. * For simplicity, these are all generically typed. * @author jrose */ class FilterGeneric { - // type for the outgoing call (will be generic) - private final MethodType targetType; - // position of (first) argument to participate in filtering - private final short argumentPosition; - // number of arguments to participate in filtering - private final short argumentCount; - // how the result interacts with the filtered arguments: Prepend, Append, Replace, Discard - private final char replaceMode; - // prototype adapter (clone and customize for each new target & conversion!) - private final Adapter adapter; - // entry point for adapter (Adapter mh, a...) => ... - private final MethodHandle entryPoint; - // more of them (loosely cached) - private FilterGeneric variations; + // type for the incoming call (will be generic) + private final MethodType entryType; + // prototype adapters (clone and customize for each new target & conversion!) + private final Adapter[] adapters; - /** Compute and cache information common to all unboxing adapters - * that can call out to targets of the erasure-family of the given erased type. + /** Compute and cache information common to all filtering adapters + * with the given generic type */ - // TO DO: Make this private. - FilterGeneric(MethodType targetType, short argumentPosition, short argumentCount, char replaceMode) { - if (argumentCount == 0) { - if (replaceMode == 'P' || replaceMode == 'A') replaceMode = 'R'; - if (replaceMode == 'I') argumentPosition = 0; - } - this.targetType = targetType; - this.argumentPosition = argumentPosition; - this.argumentCount = argumentCount; - this.replaceMode = replaceMode; - validate(targetType, argumentPosition, argumentCount, replaceMode); - Adapter ad = findAdapter(targetType, argumentPosition, argumentCount, replaceMode, filterType()); + FilterGeneric(MethodType entryType) { + this.entryType = entryType; + int tableSize = Kind.LIMIT.invokerIndex(1 + entryType.parameterCount()); + this.adapters = new Adapter[tableSize]; + } + + Adapter getAdapter(Kind kind, int pos) { + int index = kind.invokerIndex(pos); + Adapter ad = adapters[index]; + if (ad != null) return ad; + ad = findAdapter(entryType, kind, pos); if (ad == null) - ad = buildAdapterFromBytecodes(targetType, argumentPosition, argumentCount, replaceMode, filterType()); - this.adapter = ad; - this.entryPoint = ad.prototypeEntryPoint(); + ad = buildAdapterFromBytecodes(entryType, kind, pos); + adapters[index] = ad; + return ad; } - Adapter makeInstance(MethodHandle filter, MethodHandle target) { - return adapter.makeInstance(entryPoint, filter, target); + Adapter makeInstance(Kind kind, int pos, MethodHandle filter, MethodHandle target) { + Adapter ad = getAdapter(kind, pos); + return ad.makeInstance(ad.prototypeEntryPoint(), filter, target); } - /** Build an adapter of the given generic type, which invokes typedTarget - * on the incoming arguments, after unboxing as necessary. - * The return value is boxed if necessary. - * @param genericType the required type of the result - * @param typedTarget the target + /** Build an adapter of the given generic type, which invokes filter + * on the selected incoming argument before passing it to the target. + * @param pos the argument to filter + * @param filter the function to call on the argument + * @param target the target to call with the modified argument list * @return an adapter method handle */ - public static MethodHandle make(MethodHandle target, int pos, MethodHandle filter) { - return FilterGeneric.of(target.type(), (short)pos, (short)1, 'R').makeInstance(filter, target); + public static MethodHandle makeArgumentFilter(int pos, MethodHandle filter, MethodHandle target) { + return make(Kind.value, pos, filter, target); } - /** Return the adapter information for this type's erasure. */ - static FilterGeneric of(MethodType type, short ap, short ac, char mode) { - if (type.generic() != type) - throw new IllegalArgumentException("must be generic: "+type); - validate(type, ap, ac, mode); - MethodTypeImpl form = MethodTypeImpl.of(type); + /** Build an adapter of the given generic type, which invokes a combiner + * on a selected group of leading arguments. + * The result of the combiner is prepended before all those arguments. + * @param combiner the function to call on the selected leading arguments + * @param target the target to call with the modified argument list + * @return an adapter method handle + */ + public static MethodHandle makeArgumentFolder(MethodHandle combiner, MethodHandle target) { + int num = combiner.type().parameterCount(); + return make(Kind.fold, num, combiner, target); + } + + /** Build an adapter of the given generic type, which invokes a filter + * on the incoming arguments, reified as a group. + * The argument may be modified (by side effects in the filter). + * The arguments, possibly modified, are passed on to the target. + * @param filter the function to call on the arguments + * @param target the target to call with the possibly-modified argument list + * @return an adapter method handle + */ + public static MethodHandle makeFlyby(MethodHandle filter, MethodHandle target) { + return make(Kind.flyby, 0, filter, target); + } + + /** Build an adapter of the given generic type, which invokes a collector + * on the selected incoming argument and all following arguments. + * The result of the collector replaces all those arguments. + * @param collector the function to call on the selected trailing arguments + * @param target the target to call with the modified argument list + * @return an adapter method handle + */ + public static MethodHandle makeArgumentCollector(MethodHandle collector, MethodHandle target) { + int pos = target.type().parameterCount() - 1; + return make(Kind.collect, pos, collector, target); + } + + static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) { + FilterGeneric fgen = of(kind, pos, filter.type(), target.type()); + return fgen.makeInstance(kind, pos, filter, target); + } + + /** Return the adapter information for this target and filter type. */ + static FilterGeneric of(Kind kind, int pos, MethodType filterType, MethodType targetType) { + MethodType entryType = entryType(kind, pos, filterType, targetType); + if (entryType.generic() != entryType) + throw newIllegalArgumentException("must be generic: "+entryType); + MethodTypeImpl form = MethodTypeImpl.of(entryType); FilterGeneric filterGen = form.filterGeneric; if (filterGen == null) - form.filterGeneric = filterGen = new FilterGeneric(type, (short)0, (short)1, 'R'); - return find(filterGen, ap, ac, mode); - } - - static FilterGeneric find(FilterGeneric gen, short ap, short ac, char mode) { - for (;;) { - if (gen.argumentPosition == ap && - gen.argumentCount == ac && - gen.replaceMode == mode) { - return gen; - } - FilterGeneric gen2 = gen.variations; - if (gen2 == null) break; - gen = gen2; - } - FilterGeneric gen2 = new FilterGeneric(gen.targetType, ap, ac, mode); - gen.variations = gen2; // OK if this smashes another cached chain - return gen2; - } - - private static void validate(MethodType type, short ap, short ac, char mode) { - int endpos = ap + ac; - switch (mode) { - case 'P': case 'A': case 'R': case 'D': - if (ap >= 0 && ac >= 0 && - endpos >= 0 && endpos <= type.parameterCount()) - return; - default: - throw new InternalError("configuration "+patternName(ap, ac, mode)); - } + form.filterGeneric = filterGen = new FilterGeneric(entryType); + return filterGen; } public String toString() { - return "FilterGeneric/"+patternName()+targetType; + return "FilterGeneric/"+entryType; } - String patternName() { - return patternName(argumentPosition, argumentCount, replaceMode); - } - - static String patternName(short ap, short ac, char mode) { - return ""+mode+ap+(ac>1?"_"+ac:""); - } - - Class filterType() { - return Object.class; // result of filter operation; an uninteresting type - } - - static MethodType targetType(MethodType entryType, short ap, short ac, char mode, - Class arg) { + static MethodType targetType(MethodType entryType, Kind kind, int pos, MethodType filterType) { MethodType type = entryType; - int pos = ap; - switch (mode) { - case 'A': - pos += ac; - case 'P': - type = type.insertParameterType(pos, arg); + switch (kind) { + case value: + case flyby: + break; // no change + case fold: + type = type.insertParameterTypes(0, filterType.returnType()); break; - case 'I': - for (int i = 1; i < ac; i++) - type = type.dropParameterType(pos); - assert(type.parameterType(pos) == arg); - break; - case 'D': + case collect: + type = type.dropParameterTypes(pos, type.parameterCount()); + type = type.insertParameterTypes(pos, filterType.returnType()); break; + default: + throw new InternalError(); } return type; } - static MethodType entryType(MethodType targetType, short ap, short ac, char mode, - Class arg) { + static MethodType entryType(Kind kind, int pos, MethodType filterType, MethodType targetType) { MethodType type = targetType; - int pos = ap; - switch (mode) { - case 'A': - pos += ac; - case 'P': - type = type.dropParameterType(pos); + switch (kind) { + case value: + case flyby: + break; // no change + case fold: + type = type.dropParameterTypes(0, 1); break; - case 'I': - for (int i = 1; i < ac; i++) - type = type.insertParameterType(pos, arg); - assert(type.parameterType(pos) == arg); - break; - case 'D': + case collect: + type = type.dropParameterTypes(pos, pos+1); + type = type.insertParameterTypes(pos, filterType.parameterList()); break; + default: + throw new InternalError(); } return type; } /* Create an adapter that handles spreading calls for the given type. */ - static Adapter findAdapter(MethodType targetType, short ap, short ac, char mode, Class arg) { - MethodType entryType = entryType(targetType, ap, ac, mode, arg); - int argc = targetType.parameterCount(); - String pname = patternName(ap, ac, mode); + static Adapter findAdapter(MethodType entryType, Kind kind, int pos) { + int argc = entryType.parameterCount(); String cname0 = "F"+argc; - String cname1 = "F"+argc+mode; - String cname2 = "F"+argc+pname; - String[] cnames = { cname0, cname1, cname1+"X", cname2 }; - String iname = "invoke_"+pname; - // e.g., F5R; invoke_R3 + String cname1 = "F"+argc+kind.key; + String[] cnames = { cname0, cname1 }; + String iname = kind.invokerName(pos); + // e.g., F5; invoke_C3 for (String cname : cnames) { Class acls = Adapter.findSubClass(cname); if (acls == null) continue; @@ -220,7 +205,10 @@ class FilterGeneric { // Produce an instance configured as a prototype. return ctor.newInstance(entryPoint); } catch (IllegalArgumentException ex) { - } catch (InvocationTargetException ex) { + } catch (InvocationTargetException wex) { + Throwable ex = wex.getTargetException(); + if (ex instanceof Error) throw (Error)ex; + if (ex instanceof RuntimeException) throw (RuntimeException)ex; } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } @@ -228,7 +216,7 @@ class FilterGeneric { return null; } - static Adapter buildAdapterFromBytecodes(MethodType targetType, short ap, short ac, char mode, Class arg) { + static Adapter buildAdapterFromBytecodes(MethodType entryType, Kind kind, int pos) { throw new UnsupportedOperationException("NYI"); } @@ -242,8 +230,13 @@ class FilterGeneric { * generated once per type erasure family, and reused across adapters. */ static abstract class Adapter extends JavaMethodHandle { - protected final MethodHandle filter; - protected final MethodHandle target; + protected final MethodHandle filter; // transforms one or more arguments + protected final MethodHandle target; // ultimate target + + @Override + public String toString() { + return target.toString(); + } protected boolean isPrototype() { return target == null; } protected Adapter(MethodHandle entryPoint) { @@ -287,52 +280,4221 @@ class FilterGeneric { } } - //* generated classes follow this pattern: - static class F1RX extends Adapter { - protected F1RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype - protected F1RX(MethodHandle e, MethodHandle f, MethodHandle t) - { super(e, f, t); } - protected F1RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) - { return new F1RX(e, f, t); } - protected Object filter(Object a0) { return filter.invoke(a0); } - protected Object target(Object a0) { return target.invoke(a0); } - protected Object invoke_R0(Object a0) { return target(filter(a0)); } + static enum Kind { + value('V'), // filter and replace Nth argument value + fold('F'), // fold first N arguments, prepend result + collect('C'), // collect last N arguments, replace with result + flyby('Y'), // reify entire argument list, filter, pass to target + LIMIT('?'); + static final int COUNT = LIMIT.ordinal(); + + final char key; + Kind(char key) { this.key = key; } + String invokerName(int pos) { return "invoke_"+key+""+pos; } + int invokerIndex(int pos) { return pos * COUNT + ordinal(); } } - static class F2RX extends Adapter { - protected F2RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype - protected F2RX(MethodHandle e, MethodHandle f, MethodHandle t) + + /* generated classes follow this pattern: + static class F1X extends Adapter { + protected F1X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F1X(MethodHandle e, MethodHandle f, MethodHandle t) { super(e, f, t); } - protected F2RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) - { return new F2RX(e, f, t); } - protected Object filter(Object a0) { return filter.invoke(a0); } - protected Object target(Object a0, Object a1) { return target.invoke(a0, a1); } - protected Object invoke_R0(Object a0, Object a1) { return target(filter(a0), a1); } - protected Object invoke_R1(Object a0, Object a1) { return target(a0, filter(a1)); } + protected F1X makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F1X(e, f, t); } + protected Object invoke_V0(Object a0) { return target.invoke(filter.invoke(a0)); } + protected Object invoke_F0(Object a0) { return target.invoke(filter.invoke(), a0); } + protected Object invoke_F1(Object a0) { return target.invoke(filter.invoke(a0), a0); } + protected Object invoke_C0(Object a0) { return target.invoke(filter.invoke(a0)); } + protected Object invoke_C1(Object a0) { return target.invoke(a0, filter.invoke()); } + protected Object invoke_Y0(Object a0) { Object[] av = { a0 }; + filter.invoke(av); return target.invoke(av[0]); } } - static class F3RX extends Adapter { - protected F3RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype - protected F3RX(MethodHandle e, MethodHandle f, MethodHandle t) + static class F2X extends Adapter { + protected F2X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F2X(MethodHandle e, MethodHandle f, MethodHandle t) { super(e, f, t); } - protected F3RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) - { return new F3RX(e, f, t); } - protected Object filter(Object a0) { return filter.invoke(a0); } - protected Object target(Object a0, Object a1, Object a2) { return target.invoke(a0, a1, a2); } - protected Object invoke_R0(Object a0, Object a1, Object a2) { return target(filter(a0), a1, a2); } - protected Object invoke_R1(Object a0, Object a1, Object a2) { return target(a0, filter(a1), a2); } - protected Object invoke_R2(Object a0, Object a1, Object a2) { return target(a0, a1, filter(a2)); } - } - static class F4RX extends Adapter { - protected F4RX(MethodHandle entryPoint) { super(entryPoint); } // to build prototype - protected F4RX(MethodHandle e, MethodHandle f, MethodHandle t) - { super(e, f, t); } - protected F4RX makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) - { return new F4RX(e, f, t); } - protected Object filter(Object a0) { return filter.invoke(a0); } - protected Object target(Object a0, Object a1, Object a2, Object a3) { return target.invoke(a0, a1, a2, a3); } - protected Object invoke_R0(Object a0, Object a1, Object a2, Object a3) { return target(filter(a0), a1, a2, a3); } - protected Object invoke_R1(Object a0, Object a1, Object a2, Object a3) { return target(a0, filter(a1), a2, a3); } - protected Object invoke_R2(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, filter(a2), a3); } - protected Object invoke_R3(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, filter(a3)); } + protected F2X makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) + { return new F2X(e, f, t); } + protected Object invoke_V0(Object a0, Object a1) { return target.invoke(filter.invoke(a0), a1); } + protected Object invoke_V1(Object a0, Object a1) { return target.invoke(a0, filter.invoke(a1)); } + protected Object invoke_F0(Object a0, Object a1) { return target.invoke(filter.invoke(), a0, a1); } + protected Object invoke_F1(Object a0, Object a1) { return target.invoke(filter.invoke(a0), a0, a1); } + protected Object invoke_F2(Object a0, Object a1) { return target.invoke(filter.invoke(a0, a1), a0, a1); } + protected Object invoke_C0(Object a0, Object a1) { return target.invoke(filter.invoke(a0, a1)); } + protected Object invoke_C1(Object a0, Object a1) { return target.invoke(a0, filter.invoke(a1)); } + protected Object invoke_C2(Object a0, Object a1) { return target.invoke(a0, a1, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1) { Object[] av = { a0, a1 }; + filter.invoke(av); return target.invoke(av[0], av[1]); } } // */ + + // This one is written by hand: + static class F0 extends Adapter { + protected F0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F0(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F0 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F0(e, f, t); } + protected Object invoke_F0() throws Throwable { + return target.invoke(filter.invoke()); } + protected Object invoke_C0() throws Throwable { + return target.invoke(filter.invoke()); } + static final Object[] NO_ARGS = { }; + protected Object invoke_Y0() throws Throwable { + filter.invoke(NO_ARGS); // make the flyby + return target.invoke(); } + } + +/* + : SHELL; n=FilterGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -ea -cp . genclasses | sed 's| *[/]/ *$||') >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~ +//{{{ +import java.util.*; +class genclasses { + static String[][] TEMPLATES = { { + "@for@ N=1..20", + " //@each-cat@", + " static class @cat@ extends Adapter {", + " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype", + " protected @cat@(MethodHandle e, MethodHandle f, MethodHandle t) {", + " super(e, f, t); }", + " protected @cat@ makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) {", + " return new @cat@(e, f, t); }", + " //@each-P@", + " protected Object invoke_V@P@(@Tvav@) throws Throwable {", + " return target.invoke(@a0_@@Psp@filter.invoke(a@P@)@_aN@); }", + " //@end-P@", + " //@each-P@", + " protected Object invoke_F@P@(@Tvav@) throws Throwable {", + " return target.invoke(filter.invoke(@a0@),", + " @av@); }", + " //@end-P@", + " protected Object invoke_F@N@(@Tvav@) throws Throwable {", + " return target.invoke(filter.invoke(@av@),", + " @av@); }", + " //@each-P@", + " protected Object invoke_C@P@(@Tvav@) throws Throwable {", + " return target.invoke(@a0_@filter.invoke(a@P@@_aN@)); }", + " //@end-P@", + " protected Object invoke_C@N@(@Tvav@) throws Throwable {", + " return target.invoke(@av@, filter.invoke()); }", + " protected Object invoke_Y0(@Tvav@) throws Throwable {", + " Object[] av = { @av@ };", + " filter.invoke(av); // make the flyby", + " return target.invoke(@av[i]@); }", + " }", + } }; + static final String NEWLINE_INDENT = " //\n "; + enum VAR { + cat, N, P, Tvav, av, a0, a0_, _aN, Psp, av_i_; + public final String pattern = "@"+toString().replace('_','.')+"@"; + public String binding = toString(); + static void makeBindings(boolean topLevel, int inargs, int pos) { + assert(-1 <= pos && pos < inargs); + VAR.cat.binding = "F"+inargs; + VAR.N.binding = String.valueOf(inargs); // incoming arg count + VAR.P.binding = String.valueOf(pos); // selected arg position + String[] av = new String[inargs]; + String[] Tvav = new String[inargs]; + String[] av_i_ = new String[inargs]; + for (int i = 0; i < inargs; i++) { + av[i] = arg(i); + av_i_[i] = "av["+i+"]"; + String spc = ""; + if (i > 0 && i % 4 == 0) spc = NEWLINE_INDENT+(pos>9?" ":"")+" "; + Tvav[i] = spc+param("Object", av[i]); + } + VAR.av.binding = comma(av); + VAR.av_i_.binding = comma(av_i_); + VAR.Tvav.binding = comma(Tvav); + if (pos >= 0) { + VAR.Psp.binding = (pos > 0 && pos % 10 == 0) ? NEWLINE_INDENT : ""; + String[] a0 = new String[pos]; + String[] aN = new String[inargs - (pos+1)]; + for (int i = 0; i < pos; i++) { + String spc = ""; + if (i > 0 && i % 10 == 0) spc = NEWLINE_INDENT; + a0[i] = spc+av[i]; + } + VAR.a0.binding = comma(a0); + VAR.a0_.binding = comma(a0, ", "); + for (int i = pos+1; i < inargs; i++) { + String spc = ""; + if (i > 0 && i % 10 == 0) spc = NEWLINE_INDENT; + aN[i - (pos+1)] = spc+av[i]; + } + VAR._aN.binding = comma(", ", aN); + } + } + static String arg(int i) { return "a"+i; } + static String param(String t, String a) { return t+" "+a; } + static String comma(String[] v) { return comma(v, ""); } + static String comma(String[] v, String sep) { return comma("", v, sep); } + static String comma(String sep, String[] v) { return comma(sep, v, ""); } + static String comma(String sep1, String[] v, String sep2) { + if (v.length == 0) return ""; + String res = v[0]; + for (int i = 1; i < v.length; i++) res += ", "+v[i]; + return sep1 + res + sep2; + } + static String transform(String string) { + for (VAR var : values()) + string = string.replaceAll(var.pattern, var.binding); + return string; + } + } + static String[] stringsIn(String[] strings, int beg, int end) { + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length)); + } + static String[] stringsBefore(String[] strings, int pos) { + return stringsIn(strings, 0, pos); + } + static String[] stringsAfter(String[] strings, int pos) { + return stringsIn(strings, pos, strings.length); + } + static int indexAfter(String[] strings, int pos, String tag) { + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length); + } + static int indexBefore(String[] strings, int pos, String tag) { + for (int i = pos, end = strings.length; ; i++) { + if (i == end || strings[i].endsWith(tag)) return i; + } + } + static int MIN_ARITY, MAX_ARITY; + public static void main(String... av) { + for (String[] template : TEMPLATES) { + int forLinesLimit = indexBefore(template, 0, "@each-cat@"); + String[] forLines = stringsBefore(template, forLinesLimit); + template = stringsAfter(template, forLinesLimit); + for (String forLine : forLines) + expandTemplate(forLine, template); + } + } + static void expandTemplate(String forLine, String[] template) { + String[] params = forLine.split("[^0-9]+"); + if (params[0].length() == 0) params = stringsAfter(params, 1); + System.out.println("//params="+Arrays.asList(params)); + int pcur = 0; + MIN_ARITY = Integer.valueOf(params[pcur++]); + MAX_ARITY = Integer.valueOf(params[pcur++]); + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine); + for (int inargs = MIN_ARITY; inargs <= MAX_ARITY; inargs++) { + expandTemplate(template, true, inargs, -1); + } + } + static void expandTemplate(String[] template, boolean topLevel, int inargs, int pos) { + VAR.makeBindings(topLevel, inargs, pos); + for (int i = 0; i < template.length; i++) { + String line = template[i]; + if (line.endsWith("@each-cat@")) { + // ignore + } else if (line.endsWith("@each-P@")) { + int blockEnd = indexAfter(template, i, "@end-P@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + for (int pos1 = Math.max(0,pos); pos1 < inargs; pos1++) + expandTemplate(block, false, inargs, pos1); + VAR.makeBindings(topLevel, inargs, pos); + i = blockEnd-1; continue; + } else { + System.out.println(VAR.transform(line)); + } + } + } +} +//}}} */ +//params=[1, 20] + static class F1 extends Adapter { + protected F1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F1(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F1 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F1(e, f, t); } + protected Object invoke_V0(Object a0) throws Throwable { + return target.invoke(filter.invoke(a0)); } + protected Object invoke_F0(Object a0) throws Throwable { + return target.invoke(filter.invoke(), + a0); } + protected Object invoke_F1(Object a0) throws Throwable { + return target.invoke(filter.invoke(a0), + a0); } + protected Object invoke_C0(Object a0) throws Throwable { + return target.invoke(filter.invoke(a0)); } + protected Object invoke_C1(Object a0) throws Throwable { + return target.invoke(a0, filter.invoke()); } + protected Object invoke_Y0(Object a0) throws Throwable { + Object[] av = { a0 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0]); } + } + static class F2 extends Adapter { + protected F2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F2(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F2 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F2(e, f, t); } + protected Object invoke_V0(Object a0, Object a1) throws Throwable { + return target.invoke(filter.invoke(a0), a1); } + protected Object invoke_V1(Object a0, Object a1) throws Throwable { + return target.invoke(a0, filter.invoke(a1)); } + protected Object invoke_F0(Object a0, Object a1) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1); } + protected Object invoke_F1(Object a0, Object a1) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1); } + protected Object invoke_F2(Object a0, Object a1) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1); } + protected Object invoke_C0(Object a0, Object a1) throws Throwable { + return target.invoke(filter.invoke(a0, a1)); } + protected Object invoke_C1(Object a0, Object a1) throws Throwable { + return target.invoke(a0, filter.invoke(a1)); } + protected Object invoke_C2(Object a0, Object a1) throws Throwable { + return target.invoke(a0, a1, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1) throws Throwable { + Object[] av = { a0, a1 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1]); } + } + static class F3 extends Adapter { + protected F3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F3(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F3 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F3(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2); } + protected Object invoke_V1(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2); } + protected Object invoke_V2(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2)); } + protected Object invoke_F0(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2); } + protected Object invoke_F1(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2); } + protected Object invoke_F2(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2); } + protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2); } + protected Object invoke_C0(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2)); } + protected Object invoke_C1(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2)); } + protected Object invoke_C2(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2)); } + protected Object invoke_C3(Object a0, Object a1, Object a2) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2) throws Throwable { + Object[] av = { a0, a1, a2 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2]); } + } + static class F4 extends Adapter { + protected F4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F4(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F4 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F4(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3) throws Throwable { + Object[] av = { a0, a1, a2, a3 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3]); } + } + static class F5 extends Adapter { + protected F5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F5(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F5 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F5(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4]); } + } + static class F6 extends Adapter { + protected F6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F6(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F6 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F6(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5]); } + } + static class F7 extends Adapter { + protected F7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F7(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F7 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F7(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6]); } + } + static class F8 extends Adapter { + protected F8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F8(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F8 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F8(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7]); } + } + static class F9 extends Adapter { + protected F9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F9(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F9 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F9(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8]); } + } + static class F10 extends Adapter { + protected F10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F10(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F10 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F10(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9]); } + } + static class F11 extends Adapter { + protected F11(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F11(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F11 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F11(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10]); } + } + static class F12 extends Adapter { + protected F12(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F12(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F12 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F12(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11]); } + } + static class F13 extends Adapter { + protected F13(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F13(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F13 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F13(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12]); } + } + static class F14 extends Adapter { + protected F14(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F14(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F14 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F14(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13]); } + } + static class F15 extends Adapter { + protected F15(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F15(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F15 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F15(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14]); } + } + static class F16 extends Adapter { + protected F16(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F16(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F16 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F16(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14, a15); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14, a15); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14, a15); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14, a15); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14, a15); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14), a15); } + protected Object invoke_V15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_F16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14, a15)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14, a15)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14, a15)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14, a15)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14, a15)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15)); } + protected Object invoke_C16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15]); } + } + static class F17 extends Adapter { + protected F17(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F17(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F17 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F17(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14, a15, a16); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14, a15, a16); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14, a15, a16); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14, a15, a16); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14), a15, a16); } + protected Object invoke_V15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15), a16); } + protected Object invoke_V16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_F17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14, a15, a16)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14, a15, a16)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14, a15, a16)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14, a15, a16)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15, a16)); } + protected Object invoke_C16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16)); } + protected Object invoke_C17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16]); } + } + static class F18 extends Adapter { + protected F18(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F18(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F18 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F18(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14, a15, a16, a17); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14, a15, a16, a17); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14, a15, a16, a17); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14), a15, a16, a17); } + protected Object invoke_V15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15), a16, a17); } + protected Object invoke_V16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16), a17); } + protected Object invoke_V17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_F18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14, a15, a16, a17)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14, a15, a16, a17)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14, a15, a16, a17)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15, a16, a17)); } + protected Object invoke_C16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16, a17)); } + protected Object invoke_C17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17)); } + protected Object invoke_C18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17]); } + } + static class F19 extends Adapter { + protected F19(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F19(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F19 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F19(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14, a15, a16, a17, a18); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14, a15, a16, a17, a18); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14), a15, a16, a17, a18); } + protected Object invoke_V15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15), a16, a17, a18); } + protected Object invoke_V16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16), a17, a18); } + protected Object invoke_V17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17), a18); } + protected Object invoke_V18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, filter.invoke(a18)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_F19(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14, a15, a16, a17, a18)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14, a15, a16, a17, a18)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15, a16, a17, a18)); } + protected Object invoke_C16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16, a17, a18)); } + protected Object invoke_C17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17, a18)); } + protected Object invoke_C18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, filter.invoke(a18)); } + protected Object invoke_C19(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18]); } + } + static class F20 extends Adapter { + protected F20(MethodHandle entryPoint) { super(entryPoint); } // to build prototype + protected F20(MethodHandle e, MethodHandle f, MethodHandle t) { + super(e, f, t); } + protected F20 makeInstance(MethodHandle e, MethodHandle f, MethodHandle t) { + return new F20(e, f, t); } + protected Object invoke_V0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0), a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, filter.invoke(a1), a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2), a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3), a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4), a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5), a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6), a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7), a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8), a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9), + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + filter.invoke(a10), a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11), a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12), a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_V13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13), a14, a15, a16, a17, a18, a19); } + protected Object invoke_V14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14), a15, a16, a17, a18, a19); } + protected Object invoke_V15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15), a16, a17, a18, a19); } + protected Object invoke_V16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16), a17, a18, a19); } + protected Object invoke_V17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17), a18, a19); } + protected Object invoke_V18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, filter.invoke(a18), a19); } + protected Object invoke_V19(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, filter.invoke(a19)); } + protected Object invoke_F0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F19(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_F20(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19), + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19); } + protected Object invoke_C0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(filter.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C1(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, filter.invoke(a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C2(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, filter.invoke(a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C3(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, filter.invoke(a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C4(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, filter.invoke(a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C5(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, filter.invoke(a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C6(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, filter.invoke(a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C7(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, filter.invoke(a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C8(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, filter.invoke(a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C9(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, filter.invoke(a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C10(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, filter.invoke(a10, a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C11(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, filter.invoke(a11, a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C12(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, filter.invoke(a12, a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C13(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, filter.invoke(a13, a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C14(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, filter.invoke(a14, a15, a16, a17, a18, a19)); } + protected Object invoke_C15(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, filter.invoke(a15, a16, a17, a18, a19)); } + protected Object invoke_C16(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, filter.invoke(a16, a17, a18, a19)); } + protected Object invoke_C17(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, filter.invoke(a17, a18, a19)); } + protected Object invoke_C18(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, filter.invoke(a18, a19)); } + protected Object invoke_C19(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, filter.invoke(a19)); } + protected Object invoke_C20(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, filter.invoke()); } + protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, + Object a12, Object a13, Object a14, Object a15, + Object a16, Object a17, Object a18, Object a19) throws Throwable { + Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19 }; + filter.invoke(av); // make the flyby + return target.invoke(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18], av[19]); } + } } diff --git a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java b/jdk/src/share/classes/sun/dyn/FilterOneArgument.java index c2fd98e0c09..ac9849c69d9 100644 --- a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java +++ b/jdk/src/share/classes/sun/dyn/FilterOneArgument.java @@ -27,7 +27,6 @@ package sun.dyn; import java.dyn.JavaMethodHandle; import java.dyn.MethodHandle; -import java.dyn.MethodHandles; import java.dyn.MethodType; /** @@ -42,16 +41,21 @@ public class FilterOneArgument extends JavaMethodHandle { protected final MethodHandle filter; // Object -> Object protected final MethodHandle target; // Object -> Object - protected Object entryPoint(Object argument) { - Object filteredArgument = filter.invoke(argument); - return target.invoke(filteredArgument); + @Override + public String toString() { + return target.toString(); } - private static final MethodHandle entryPoint = - MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1)); + protected Object invoke(Object argument) throws Throwable { + Object filteredArgument = filter.invoke(argument); + return target.invoke(filteredArgument); + } + + private static final MethodHandle INVOKE = + MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.genericMethodType(1)); protected FilterOneArgument(MethodHandle filter, MethodHandle target) { - super(entryPoint); + super(INVOKE); this.filter = filter; this.target = target; } @@ -62,10 +66,6 @@ public class FilterOneArgument extends JavaMethodHandle { return new FilterOneArgument(filter, target); } - public String toString() { - return filter + "|>" + target; - } - // MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) { // MethodHandle filter = make(filter1, filter2); // return make(filter, target); diff --git a/jdk/src/share/classes/sun/dyn/FromGeneric.java b/jdk/src/share/classes/sun/dyn/FromGeneric.java index 85f35d65577..a42be3fcd51 100644 --- a/jdk/src/share/classes/sun/dyn/FromGeneric.java +++ b/jdk/src/share/classes/sun/dyn/FromGeneric.java @@ -36,8 +36,8 @@ import sun.dyn.util.ValueConversions; import sun.dyn.util.Wrapper; /** - * Adapters which mediate between incoming calls which are not generic - * and outgoing calls which are. Any call can be represented generically + * Adapters which mediate between incoming calls which are generic + * and outgoing calls which are not. Any call can be represented generically * boxing up its arguments, and (on return) unboxing the return value. *

    * A call is "generic" (in MethodHandle terms) if its MethodType features @@ -50,9 +50,6 @@ import sun.dyn.util.Wrapper; * either binds internally or else takes as a leading argument). * (To stretch the term, adapter-like method handles may have multiple * targets or be polymorphic across multiple call types.) - *

    - * This adapter can sometimes be more directly implemented - * by the JVM's built-in OP_SPREAD_ARGS adapter. * @author jrose */ class FromGeneric { @@ -99,7 +96,7 @@ class FromGeneric { } this.internalType = internalType0; this.adapter = ad; - MethodType tepType = targetType.insertParameterType(0, adapter.getClass()); + MethodType tepType = targetType.insertParameterTypes(0, adapter.getClass()); this.entryPoint = ad.prototypeEntryPoint(); this.returnConversion = computeReturnConversion(targetType, internalType0); this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0); @@ -146,7 +143,7 @@ class FromGeneric { if (fixArgs == null) throw new InternalError("bad fixArgs"); // reinterpret the calling sequence as raw: - MethodHandle retyper = AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, + MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, Invokers.invokerType(internalType), fixArgs); if (retyper == null) throw new InternalError("bad retyper"); @@ -226,7 +223,10 @@ class FromGeneric { // Produce an instance configured as a prototype. return ctor.newInstance(entryPoint); } catch (IllegalArgumentException ex) { - } catch (InvocationTargetException ex) { + } catch (InvocationTargetException wex) { + Throwable ex = wex.getTargetException(); + if (ex instanceof Error) throw (Error)ex; + if (ex instanceof RuntimeException) throw (RuntimeException)ex; } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } @@ -260,6 +260,11 @@ class FromGeneric { protected final MethodHandle convert; // raw(R) => Object protected final MethodHandle target; // (any**N) => R + @Override + public String toString() { + return target.toString(); + } + protected boolean isPrototype() { return target == null; } protected Adapter(MethodHandle entryPoint) { this(entryPoint, null, entryPoint, null); @@ -284,11 +289,11 @@ class FromGeneric { // { return new ThisType(entryPoint, convert, target); } /// Conversions on the value returned from the target. - protected Object convert_L(Object result) { return convert.invoke(result); } - protected Object convert_I(int result) { return convert.invoke(result); } - protected Object convert_J(long result) { return convert.invoke(result); } - protected Object convert_F(float result) { return convert.invoke(result); } - protected Object convert_D(double result) { return convert.invoke(result); } + protected Object convert_L(Object result) throws Throwable { return convert.invoke(result); } + protected Object convert_I(int result) throws Throwable { return convert.invoke(result); } + protected Object convert_J(long result) throws Throwable { return convert.invoke(result); } + protected Object convert_F(float result) throws Throwable { return convert.invoke(result); } + protected Object convert_D(double result) throws Throwable { return convert.invoke(result); } static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$" static { @@ -317,11 +322,11 @@ class FromGeneric { { super(e, i, c, t); } protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new xA2(e, i, c, t); } - protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.invoke(target, a0, a1)); } - protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.invoke(target, a0, a1)); } - protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.invoke(target, a0, a1)); } - protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.invoke(target, a0, a1)); } - protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.invoke(target, a0, a1)); } + protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.invoke(target, a0, a1)); } + protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.invoke(target, a0, a1)); } + protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.invoke(target, a0, a1)); } + protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.invoke(target, a0, a1)); } + protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.invoke(target, a0, a1)); } } // */ @@ -342,7 +347,7 @@ class genclasses { " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)", " { return new @cat@(e, i, c, t); }", " //@each-R@", - " protected Object invoke_@catN@(@Tvav@) { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }", + " protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@(invoker.<@R@>invoke(target@av@)); }", " //@end-R@", " }", } }; @@ -498,11 +503,11 @@ class genclasses { { super(e, i, c, t); } protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); } - protected Object invoke_L0() { return convert_L(invoker.invoke(target)); } - protected Object invoke_I0() { return convert_I(invoker.invoke(target)); } - protected Object invoke_J0() { return convert_J(invoker.invoke(target)); } - protected Object invoke_F0() { return convert_F(invoker.invoke(target)); } - protected Object invoke_D0() { return convert_D(invoker.invoke(target)); } + protected Object invoke_L0() throws Throwable { return convert_L(invoker.invoke(target)); } + protected Object invoke_I0() throws Throwable { return convert_I(invoker.invoke(target)); } + protected Object invoke_J0() throws Throwable { return convert_J(invoker.invoke(target)); } + protected Object invoke_F0() throws Throwable { return convert_F(invoker.invoke(target)); } + protected Object invoke_D0() throws Throwable { return convert_D(invoker.invoke(target)); } } static class A1 extends Adapter { protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -510,11 +515,11 @@ class genclasses { { super(e, i, c, t); } protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); } - protected Object invoke_L1(Object a0) { return convert_L(invoker.invoke(target, a0)); } - protected Object invoke_I1(Object a0) { return convert_I(invoker.invoke(target, a0)); } - protected Object invoke_J1(Object a0) { return convert_J(invoker.invoke(target, a0)); } - protected Object invoke_F1(Object a0) { return convert_F(invoker.invoke(target, a0)); } - protected Object invoke_D1(Object a0) { return convert_D(invoker.invoke(target, a0)); } + protected Object invoke_L1(Object a0) throws Throwable { return convert_L(invoker.invoke(target, a0)); } + protected Object invoke_I1(Object a0) throws Throwable { return convert_I(invoker.invoke(target, a0)); } + protected Object invoke_J1(Object a0) throws Throwable { return convert_J(invoker.invoke(target, a0)); } + protected Object invoke_F1(Object a0) throws Throwable { return convert_F(invoker.invoke(target, a0)); } + protected Object invoke_D1(Object a0) throws Throwable { return convert_D(invoker.invoke(target, a0)); } } static class A2 extends Adapter { protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -522,11 +527,11 @@ class genclasses { { super(e, i, c, t); } protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); } - protected Object invoke_L2(Object a0, Object a1) { return convert_L(invoker.invoke(target, a0, a1)); } - protected Object invoke_I2(Object a0, Object a1) { return convert_I(invoker.invoke(target, a0, a1)); } - protected Object invoke_J2(Object a0, Object a1) { return convert_J(invoker.invoke(target, a0, a1)); } - protected Object invoke_F2(Object a0, Object a1) { return convert_F(invoker.invoke(target, a0, a1)); } - protected Object invoke_D2(Object a0, Object a1) { return convert_D(invoker.invoke(target, a0, a1)); } + protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.invoke(target, a0, a1)); } + protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.invoke(target, a0, a1)); } + protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.invoke(target, a0, a1)); } + protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.invoke(target, a0, a1)); } + protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.invoke(target, a0, a1)); } } static class A3 extends Adapter { protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -534,11 +539,11 @@ class genclasses { { super(e, i, c, t); } protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); } - protected Object invoke_L3(Object a0, Object a1, Object a2) { return convert_L(invoker.invoke(target, a0, a1, a2)); } - protected Object invoke_I3(Object a0, Object a1, Object a2) { return convert_I(invoker.invoke(target, a0, a1, a2)); } - protected Object invoke_J3(Object a0, Object a1, Object a2) { return convert_J(invoker.invoke(target, a0, a1, a2)); } - protected Object invoke_F3(Object a0, Object a1, Object a2) { return convert_F(invoker.invoke(target, a0, a1, a2)); } - protected Object invoke_D3(Object a0, Object a1, Object a2) { return convert_D(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2)); } + protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2)); } } static class A4 extends Adapter { protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -546,11 +551,11 @@ class genclasses { { super(e, i, c, t); } protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); } - protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) { return convert_L(invoker.invoke(target, a0, a1, a2, a3)); } - protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) { return convert_I(invoker.invoke(target, a0, a1, a2, a3)); } - protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) { return convert_J(invoker.invoke(target, a0, a1, a2, a3)); } - protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) { return convert_F(invoker.invoke(target, a0, a1, a2, a3)); } - protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) { return convert_D(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3)); } + protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3)); } } static class A5 extends Adapter { protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -558,11 +563,11 @@ class genclasses { { super(e, i, c, t); } protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); } - protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4)); } - protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4)); } - protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4)); } - protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4)); } - protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4)); } + protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4)); } } static class A6 extends Adapter { protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -570,11 +575,11 @@ class genclasses { { super(e, i, c, t); } protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); } - protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } - protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } - protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } - protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } - protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } + protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5)); } } static class A7 extends Adapter { protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -582,11 +587,11 @@ class genclasses { { super(e, i, c, t); } protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); } - protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6)); } } static class A8 extends Adapter { protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -594,11 +599,11 @@ class genclasses { { super(e, i, c, t); } protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); } - protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7)); } } static class A9 extends Adapter { protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -606,11 +611,11 @@ class genclasses { { super(e, i, c, t); } protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); } - protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); } } static class A10 extends Adapter { protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype @@ -618,10 +623,10 @@ class genclasses { { super(e, i, c, t); } protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); } - protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D(invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } } } diff --git a/jdk/src/share/classes/sun/dyn/Invokers.java b/jdk/src/share/classes/sun/dyn/Invokers.java index eddd437a5d5..c1565852e4c 100644 --- a/jdk/src/share/classes/sun/dyn/Invokers.java +++ b/jdk/src/share/classes/sun/dyn/Invokers.java @@ -44,16 +44,20 @@ public class Invokers { // generic (untyped) invoker for the outgoing call private /*lazy*/ MethodHandle genericInvoker; + // generic (untyped) invoker for the outgoing call; accepts a single Object[] + private final /*lazy*/ MethodHandle[] varargsInvokers; + /** Compute and cache information common to all collecting adapters * that implement members of the erasure-family of the given erased type. */ public Invokers(Access token, MethodType targetType) { Access.check(token); this.targetType = targetType; + this.varargsInvokers = new MethodHandle[targetType.parameterCount()+1]; } public static MethodType invokerType(MethodType targetType) { - return targetType.insertParameterType(0, MethodHandle.class); + return targetType.insertParameterTypes(0, MethodHandle.class); } public MethodHandle exactInvoker() { @@ -76,8 +80,14 @@ public class Invokers { return invoker; } - public MethodHandle varargsInvoker() { - throw new UnsupportedOperationException("NYI"); + public MethodHandle varargsInvoker(int objectArgCount) { + MethodHandle vaInvoker = varargsInvokers[objectArgCount]; + if (vaInvoker != null) return vaInvoker; + MethodHandle gInvoker = genericInvoker(); + MethodType vaType = MethodType.genericMethodType(objectArgCount, true); + vaInvoker = MethodHandles.spreadArguments(gInvoker, invokerType(vaType)); + varargsInvokers[objectArgCount] = vaInvoker; + return vaInvoker; } public String toString() { diff --git a/jdk/src/share/classes/sun/dyn/MemberName.java b/jdk/src/share/classes/sun/dyn/MemberName.java index 26919efa8c5..01af94b5166 100644 --- a/jdk/src/share/classes/sun/dyn/MemberName.java +++ b/jdk/src/share/classes/sun/dyn/MemberName.java @@ -25,7 +25,7 @@ package sun.dyn; -import sun.dyn.util.BytecodeSignature; +import sun.dyn.util.BytecodeDescriptor; import java.dyn.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -33,6 +33,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -93,7 +94,7 @@ public final class MemberName implements Member, Cloneable { } if (type instanceof String) { String sig = (String) type; - MethodType res = MethodType.fromBytecodeString(sig, getClassLoader()); + MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); this.type = res; return res; } @@ -101,7 +102,7 @@ public final class MemberName implements Member, Cloneable { Object[] typeInfo = (Object[]) type; Class[] ptypes = (Class[]) typeInfo[1]; Class rtype = (Class) typeInfo[0]; - MethodType res = MethodType.make(rtype, ptypes); + MethodType res = MethodType.methodType(rtype, ptypes); this.type = res; return res; } @@ -111,7 +112,7 @@ public final class MemberName implements Member, Cloneable { public MethodType getInvocationType() { MethodType itype = getMethodType(); if (!isStatic()) - itype = itype.insertParameterType(0, clazz); + itype = itype.insertParameterTypes(0, clazz); return itype; } @@ -135,7 +136,7 @@ public final class MemberName implements Member, Cloneable { } if (type instanceof String) { String sig = (String) type; - MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader()); + MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); Class res = mtype.returnType(); this.type = res; return res; @@ -155,9 +156,9 @@ public final class MemberName implements Member, Cloneable { if (type instanceof String) return (String) type; if (isInvocable()) - return BytecodeSignature.unparse(getMethodType()); + return BytecodeDescriptor.unparse(getMethodType()); else - return BytecodeSignature.unparse(getFieldType()); + return BytecodeDescriptor.unparse(getFieldType()); } public int getModifiers() { @@ -353,6 +354,8 @@ public final class MemberName implements Member, Cloneable { return type.toString(); // class java.lang.String // else it is a field, method, or constructor StringBuilder buf = new StringBuilder(); + if (!isResolved()) + buf.append("*."); if (getDeclaringClass() != null) { buf.append(getName(clazz)); buf.append('.'); @@ -381,7 +384,7 @@ public final class MemberName implements Member, Cloneable { private static String getName(Object obj) { if (obj instanceof Class) return ((Class)obj).getName(); - return obj.toString(); + return String.valueOf(obj); } // Queries to the JVM: @@ -408,6 +411,9 @@ public final class MemberName implements Member, Cloneable { public static NoAccessException newNoAccessException(MemberName name, Class lookupClass) { return newNoAccessException("cannot access", name, lookupClass); } + public static NoAccessException newNoAccessException(MemberName name, MethodHandles.Lookup lookup) { + return newNoAccessException(name, lookup.lookupClass()); + } public static NoAccessException newNoAccessException(String message, MemberName name, Class lookupClass) { message += ": " + name; @@ -436,7 +442,7 @@ public final class MemberName implements Member, Cloneable { matchFlags &= ALLOWED_FLAGS; String matchSig = null; if (matchType != null) { - matchSig = BytecodeSignature.unparse(matchType); + matchSig = BytecodeDescriptor.unparse(matchType); if (matchSig.startsWith("(")) matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE); else @@ -447,17 +453,18 @@ public final class MemberName implements Member, Cloneable { MemberName[] buf = newMemberBuffer(len1); int totalCount = 0; ArrayList bufs = null; + int bufCount = 0; for (;;) { - int bufCount = MethodHandleNatives.getMembers(defc, + bufCount = MethodHandleNatives.getMembers(defc, matchName, matchSig, matchFlags, lookupClass, totalCount, buf); if (bufCount <= buf.length) { - if (bufCount >= 0) - totalCount += bufCount; + if (bufCount < 0) bufCount = 0; + totalCount += bufCount; break; } - // JVM returned tp us with an intentional overflow! + // JVM returned to us with an intentional overflow! totalCount += buf.length; int excess = bufCount - buf.length; if (bufs == null) bufs = new ArrayList(1); @@ -473,7 +480,7 @@ public final class MemberName implements Member, Cloneable { Collections.addAll(result, buf0); } } - Collections.addAll(result, buf); + result.addAll(Arrays.asList(buf).subList(0, bufCount)); // Signature matching is not the same as type matching, since // one signature might correspond to several types. // So if matchType is a Class or MethodType, refilter the results. diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java index 2dd59deeff0..f8a8bca38d7 100644 --- a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java +++ b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java @@ -25,12 +25,25 @@ package sun.dyn; +import java.dyn.JavaMethodHandle; import java.dyn.MethodHandle; import java.dyn.MethodHandles; import java.dyn.MethodHandles.Lookup; import java.dyn.MethodType; +import java.util.logging.Level; +import java.util.logging.Logger; import sun.dyn.util.VerifyType; import java.dyn.NoAccessException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import sun.dyn.empty.Empty; +import sun.dyn.util.ValueConversions; +import sun.dyn.util.Wrapper; +import sun.misc.Unsafe; import static sun.dyn.MemberName.newIllegalArgumentException; import static sun.dyn.MemberName.newNoAccessException; @@ -57,6 +70,25 @@ public abstract class MethodHandleImpl { static final int INT_FIELD = 0; static final long LONG_FIELD = 0; + /** Access methods for the internals of MethodHandle, supplied to + * MethodHandleImpl as a trusted agent. + */ + static public interface MethodHandleFriend { + void initType(MethodHandle mh, MethodType type); + } + public static void setMethodHandleFriend(Access token, MethodHandleFriend am) { + Access.check(token); + if (METHOD_HANDLE_FRIEND != null) + throw new InternalError(); // just once + METHOD_HANDLE_FRIEND = am; + } + static private MethodHandleFriend METHOD_HANDLE_FRIEND; + + // NOT public + static void initType(MethodHandle mh, MethodType type) { + METHOD_HANDLE_FRIEND.initType(mh, type); + } + // type is defined in java.dyn.MethodHandle, which is platform-independent // vmentry (a void* field) is used *only* by by the JVM. @@ -106,8 +138,8 @@ public abstract class MethodHandleImpl { } static { - // Force initialization: - Lookup.PUBLIC_LOOKUP.lookupClass(); + // Force initialization of Lookup, so it calls us back as initLookup: + MethodHandles.publicLookup(); if (IMPL_LOOKUP_INIT == null) throw new InternalError(); } @@ -151,7 +183,7 @@ public abstract class MethodHandleImpl { // adjust the advertised receiver type to be exactly the one requested // (in the case of invokespecial, this will be the calling class) Class recvType = method.getDeclaringClass(); - mtype = mtype.insertParameterType(0, recvType); + mtype = mtype.insertParameterTypes(0, recvType); if (method.isConstructor()) doDispatch = true; // FIXME: JVM has trouble building MH.invoke sites for @@ -170,21 +202,223 @@ public abstract class MethodHandleImpl { public static MethodHandle accessField(Access token, - MemberName member, boolean isSetter, - Class lookupClass) { + MemberName member, boolean isSetter, + Class lookupClass) { Access.check(token); - // FIXME: Use sun.misc.Unsafe to dig up the dirt on the field. - throw new UnsupportedOperationException("Not yet implemented"); + // Use sun. misc.Unsafe to dig up the dirt on the field. + MethodHandle mh = new FieldAccessor(token, member, isSetter); + return mh; } public static MethodHandle accessArrayElement(Access token, - Class arrayClass, boolean isSetter) { + Class arrayClass, boolean isSetter) { Access.check(token); if (!arrayClass.isArray()) throw newIllegalArgumentException("not an array: "+arrayClass); - // FIXME: Use sun.misc.Unsafe to dig up the dirt on the array. - throw new UnsupportedOperationException("Not yet implemented"); + Class elemClass = arrayClass.getComponentType(); + MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass); + if (mhs == null) { + if (!FieldAccessor.doCache(elemClass)) + return FieldAccessor.ahandle(arrayClass, isSetter); + mhs = new MethodHandle[] { + FieldAccessor.ahandle(arrayClass, false), + FieldAccessor.ahandle(arrayClass, true) + }; + if (mhs[0].type().parameterType(0) == Class.class) { + mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass); + mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass); + } + synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier + FieldAccessor.ARRAY_CACHE.put(elemClass, mhs); + } + return mhs[isSetter ? 1 : 0]; + } + + static final class FieldAccessor extends JavaMethodHandle { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + final Object base; // for static refs only + final long offset; + final String name; + + public FieldAccessor(Access token, MemberName field, boolean isSetter) { + super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic())); + this.offset = (long) field.getVMIndex(token); + this.name = field.getName(); + this.base = staticBase(field); + } + public String toString() { return name; } + + int getFieldI(C obj) { return unsafe.getInt(obj, offset); } + void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); } + long getFieldJ(C obj) { return unsafe.getLong(obj, offset); } + void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); } + float getFieldF(C obj) { return unsafe.getFloat(obj, offset); } + void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); } + double getFieldD(C obj) { return unsafe.getDouble(obj, offset); } + void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); } + boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); } + void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); } + byte getFieldB(C obj) { return unsafe.getByte(obj, offset); } + void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); } + short getFieldS(C obj) { return unsafe.getShort(obj, offset); } + void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); } + char getFieldC(C obj) { return unsafe.getChar(obj, offset); } + void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); } + @SuppressWarnings("unchecked") + V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); } + @SuppressWarnings("unchecked") + void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); } + // cast (V) is OK here, since we wrap convertArguments around the MH. + + static Object staticBase(MemberName field) { + if (!field.isStatic()) return null; + Class c = field.getDeclaringClass(); + java.lang.reflect.Field f; + try { + // FIXME: Should not have to create 'f' to get this value. + f = c.getDeclaredField(field.getName()); + return unsafe.staticFieldBase(f); + } catch (Exception ee) { + Error e = new InternalError(); + e.initCause(ee); + throw e; + } + } + + int getStaticI() { return unsafe.getInt(base, offset); } + void setStaticI(int x) { unsafe.putInt(base, offset, x); } + long getStaticJ() { return unsafe.getLong(base, offset); } + void setStaticJ(long x) { unsafe.putLong(base, offset, x); } + float getStaticF() { return unsafe.getFloat(base, offset); } + void setStaticF(float x) { unsafe.putFloat(base, offset, x); } + double getStaticD() { return unsafe.getDouble(base, offset); } + void setStaticD(double x) { unsafe.putDouble(base, offset, x); } + boolean getStaticZ() { return unsafe.getBoolean(base, offset); } + void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); } + byte getStaticB() { return unsafe.getByte(base, offset); } + void setStaticB(byte x) { unsafe.putByte(base, offset, x); } + short getStaticS() { return unsafe.getShort(base, offset); } + void setStaticS(short x) { unsafe.putShort(base, offset, x); } + char getStaticC() { return unsafe.getChar(base, offset); } + void setStaticC(char x) { unsafe.putChar(base, offset, x); } + V getStaticL() { return (V) unsafe.getObject(base, offset); } + void setStaticL(V x) { unsafe.putObject(base, offset, x); } + + static String fname(Class vclass, boolean isSetter, boolean isStatic) { + String stem; + if (!isStatic) + stem = (!isSetter ? "getField" : "setField"); + else + stem = (!isSetter ? "getStatic" : "setStatic"); + return stem + Wrapper.basicTypeChar(vclass); + } + static MethodType ftype(Class cclass, Class vclass, boolean isSetter, boolean isStatic) { + MethodType type; + if (!isStatic) { + if (!isSetter) + return MethodType.methodType(vclass, cclass); + else + return MethodType.methodType(void.class, cclass, vclass); + } else { + if (!isSetter) + return MethodType.methodType(vclass); + else + return MethodType.methodType(void.class, vclass); + } + } + static MethodHandle fhandle(Class cclass, Class vclass, boolean isSetter, boolean isStatic) { + String name = FieldAccessor.fname(vclass, isSetter, isStatic); + if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass); + Class ecclass = Object.class; //erase this type + Class evclass = vclass; + if (!evclass.isPrimitive()) evclass = Object.class; + MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic); + MethodHandle mh; + try { + mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type); + } catch (NoAccessException ee) { + Error e = new InternalError("name,type="+name+type); + e.initCause(ee); + throw e; + } + if (evclass != vclass || (!isStatic && ecclass != cclass)) { + MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic); + strongType = strongType.insertParameterTypes(0, FieldAccessor.class); + mh = MethodHandles.convertArguments(mh, strongType); + } + return mh; + } + + /// Support for array element access + static final HashMap, MethodHandle[]> ARRAY_CACHE = + new HashMap, MethodHandle[]>(); + // FIXME: Cache on the classes themselves, not here. + static boolean doCache(Class elemClass) { + if (elemClass.isPrimitive()) return true; + ClassLoader cl = elemClass.getClassLoader(); + return cl == null || cl == ClassLoader.getSystemClassLoader(); + } + static int getElementI(int[] a, int i) { return a[i]; } + static void setElementI(int[] a, int i, int x) { a[i] = x; } + static long getElementJ(long[] a, int i) { return a[i]; } + static void setElementJ(long[] a, int i, long x) { a[i] = x; } + static float getElementF(float[] a, int i) { return a[i]; } + static void setElementF(float[] a, int i, float x) { a[i] = x; } + static double getElementD(double[] a, int i) { return a[i]; } + static void setElementD(double[] a, int i, double x) { a[i] = x; } + static boolean getElementZ(boolean[] a, int i) { return a[i]; } + static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; } + static byte getElementB(byte[] a, int i) { return a[i]; } + static void setElementB(byte[] a, int i, byte x) { a[i] = x; } + static short getElementS(short[] a, int i) { return a[i]; } + static void setElementS(short[] a, int i, short x) { a[i] = x; } + static char getElementC(char[] a, int i) { return a[i]; } + static void setElementC(char[] a, int i, char x) { a[i] = x; } + static Object getElementL(Object[] a, int i) { return a[i]; } + static void setElementL(Object[] a, int i, Object x) { a[i] = x; } + static V getElementL(Class aclass, V[] a, int i) { return aclass.cast(a)[i]; } + static void setElementL(Class aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; } + + static String aname(Class aclass, boolean isSetter) { + Class vclass = aclass.getComponentType(); + if (vclass == null) throw new IllegalArgumentException(); + return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass); + } + static MethodType atype(Class aclass, boolean isSetter) { + Class vclass = aclass.getComponentType(); + if (!isSetter) + return MethodType.methodType(vclass, aclass, int.class); + else + return MethodType.methodType(void.class, aclass, int.class, vclass); + } + static MethodHandle ahandle(Class aclass, boolean isSetter) { + Class vclass = aclass.getComponentType(); + String name = FieldAccessor.aname(aclass, isSetter); + Class caclass = null; + if (!vclass.isPrimitive() && vclass != Object.class) { + caclass = aclass; + aclass = Object[].class; + vclass = Object.class; + } + MethodType type = FieldAccessor.atype(aclass, isSetter); + if (caclass != null) + type = type.insertParameterTypes(0, Class.class); + MethodHandle mh; + try { + mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type); + } catch (NoAccessException ee) { + Error e = new InternalError("name,type="+name+type); + e.initCause(ee); + throw e; + } + if (caclass != null) { + MethodType strongType = FieldAccessor.atype(caclass, isSetter); + mh = MethodHandles.insertArguments(mh, 0, caclass); + mh = MethodHandles.convertArguments(mh, strongType); + } + return mh; + } } /** Bind a predetermined first argument to the given direct method handle. @@ -203,8 +437,11 @@ public abstract class MethodHandleImpl { if (info instanceof DirectMethodHandle) { DirectMethodHandle dmh = (DirectMethodHandle) info; if (receiver == null || - dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) - target = dmh; + dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) { + MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0); + MethodType newType = target.type().dropParameterTypes(0, 1); + return convertArguments(token, bmh, newType, bmh.type(), null); + } } } if (target instanceof DirectMethodHandle) @@ -223,7 +460,7 @@ public abstract class MethodHandleImpl { MethodHandle bindArgument(Access token, MethodHandle target, int argnum, Object receiver) { Access.check(token); - throw new UnsupportedOperationException("NYI"); + return new BoundMethodHandle(target, receiver, argnum); } public static MethodHandle convertArguments(Access token, @@ -232,6 +469,189 @@ public abstract class MethodHandleImpl { MethodType oldType, int[] permutationOrNull) { Access.check(token); + if (permutationOrNull != null) { + int outargs = oldType.parameterCount(), inargs = newType.parameterCount(); + if (permutationOrNull.length != outargs) + throw newIllegalArgumentException("wrong number of arguments in permutation"); + // Make the individual outgoing argument types match up first. + Class[] callTypeArgs = new Class[outargs]; + for (int i = 0; i < outargs; i++) + callTypeArgs[i] = newType.parameterType(permutationOrNull[i]); + MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs); + target = convertArguments(token, target, callType, oldType, null); + assert(target != null); + oldType = target.type(); + List goal = new ArrayList(); // i*TOKEN + List state = new ArrayList(); // i*TOKEN + List drops = new ArrayList(); // not tokens + List dups = new ArrayList(); // not tokens + final int TOKEN = 10; // to mark items which are symbolic only + // state represents the argument values coming into target + for (int i = 0; i < outargs; i++) { + state.add(permutationOrNull[i] * TOKEN); + } + // goal represents the desired state + for (int i = 0; i < inargs; i++) { + if (state.contains(i * TOKEN)) { + goal.add(i * TOKEN); + } else { + // adapter must initially drop all unused arguments + drops.add(i); + } + } + // detect duplications + while (state.size() > goal.size()) { + for (int i2 = 0; i2 < state.size(); i2++) { + int arg1 = state.get(i2); + int i1 = state.indexOf(arg1); + if (i1 != i2) { + // found duplicate occurrence at i2 + int arg2 = (inargs++) * TOKEN; + state.set(i2, arg2); + dups.add(goal.indexOf(arg1)); + goal.add(arg2); + } + } + } + assert(state.size() == goal.size()); + int size = goal.size(); + while (!state.equals(goal)) { + // Look for a maximal sequence of adjacent misplaced arguments, + // and try to rotate them into place. + int bestRotArg = -10 * TOKEN, bestRotLen = 0; + int thisRotArg = -10 * TOKEN, thisRotLen = 0; + for (int i = 0; i < size; i++) { + int arg = state.get(i); + // Does this argument match the current run? + if (arg == thisRotArg + TOKEN) { + thisRotArg = arg; + thisRotLen += 1; + if (bestRotLen < thisRotLen) { + bestRotLen = thisRotLen; + bestRotArg = thisRotArg; + } + } else { + // The old sequence (if any) stops here. + thisRotLen = 0; + thisRotArg = -10 * TOKEN; + // But maybe a new one starts here also. + int wantArg = goal.get(i); + final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION; + if (arg != wantArg && + arg >= wantArg - TOKEN * MAX_ARG_ROTATION && + arg <= wantArg + TOKEN * MAX_ARG_ROTATION) { + thisRotArg = arg; + thisRotLen = 1; + } + } + } + if (bestRotLen >= 2) { + // Do a rotation if it can improve argument positioning + // by at least 2 arguments. This is not always optimal, + // but it seems to catch common cases. + int dstEnd = state.indexOf(bestRotArg); + int srcEnd = goal.indexOf(bestRotArg); + int rotBy = dstEnd - srcEnd; + int dstBeg = dstEnd - (bestRotLen - 1); + int srcBeg = srcEnd - (bestRotLen - 1); + assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs + // Make a span which covers both source and destination. + int rotBeg = Math.min(dstBeg, srcBeg); + int rotEnd = Math.max(dstEnd, srcEnd); + int score = 0; + for (int i = rotBeg; i <= rotEnd; i++) { + if ((int)state.get(i) != (int)goal.get(i)) + score += 1; + } + List rotSpan = state.subList(rotBeg, rotEnd+1); + Collections.rotate(rotSpan, -rotBy); // reverse direction + for (int i = rotBeg; i <= rotEnd; i++) { + if ((int)state.get(i) != (int)goal.get(i)) + score -= 1; + } + if (score >= 2) { + // Improved at least two argument positions. Do it. + List> ptypes = Arrays.asList(oldType.parameterArray()); + Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy); + MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes); + MethodHandle nextTarget + = AdapterMethodHandle.makeRotateArguments(token, rotType, target, + rotBeg, rotSpan.size(), rotBy); + if (nextTarget != null) { + //System.out.println("Rot: "+rotSpan+" by "+rotBy); + target = nextTarget; + oldType = rotType; + continue; + } + } + // Else de-rotate, and drop through to the swap-fest. + Collections.rotate(rotSpan, rotBy); + } + + // Now swap like the wind! + List> ptypes = Arrays.asList(oldType.parameterArray()); + for (int i = 0; i < size; i++) { + // What argument do I want here? + int arg = goal.get(i); + if (arg != state.get(i)) { + // Where is it now? + int j = state.indexOf(arg); + Collections.swap(ptypes, i, j); + MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes); + target = AdapterMethodHandle.makeSwapArguments(token, swapType, target, i, j); + if (target == null) throw newIllegalArgumentException("cannot swap"); + assert(target.type() == swapType); + oldType = swapType; + Collections.swap(state, i, j); + } + } + // One pass of swapping must finish the job. + assert(state.equals(goal)); + } + while (!dups.isEmpty()) { + // Grab a contiguous trailing sequence of dups. + int grab = dups.size() - 1; + int dupArgPos = dups.get(grab), dupArgCount = 1; + while (grab - 1 >= 0) { + int dup0 = dups.get(grab - 1); + if (dup0 != dupArgPos - 1) break; + dupArgPos -= 1; + dupArgCount += 1; + grab -= 1; + } + //if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size())); + dups.subList(grab, dups.size()).clear(); + // In the new target type drop that many args from the tail: + List> ptypes = oldType.parameterList(); + ptypes = ptypes.subList(0, ptypes.size() - dupArgCount); + MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes); + target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount); + if (target == null) + throw newIllegalArgumentException("cannot dup"); + oldType = target.type(); + } + while (!drops.isEmpty()) { + // Grab a contiguous initial sequence of drops. + int dropArgPos = drops.get(0), dropArgCount = 1; + while (dropArgCount < drops.size()) { + int drop1 = drops.get(dropArgCount); + if (drop1 != dropArgPos + dropArgCount) break; + dropArgCount += 1; + } + //if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount)); + drops.subList(0, dropArgCount).clear(); + List> dropTypes = newType.parameterList() + .subList(dropArgPos, dropArgPos + dropArgCount); + MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes); + target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount); + if (target == null) throw newIllegalArgumentException("cannot drop"); + oldType = target.type(); + } + } + if (newType == oldType) + return target; + if (oldType.parameterCount() != newType.parameterCount()) + throw newIllegalArgumentException("mismatched parameter count"); MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target); if (res != null) return res; @@ -241,7 +661,7 @@ public abstract class MethodHandleImpl { // Use a heavier method: Convert all the arguments to Object, // then back to the desired types. We might have to use Java-based // method handles to do this. - MethodType objType = MethodType.makeGeneric(argc); + MethodType objType = MethodType.genericMethodType(argc); MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target); if (objTarget == null) objTarget = FromGeneric.make(target); @@ -272,83 +692,386 @@ public abstract class MethodHandleImpl { Class[] ptypes = oldType.parameterArray(); for (int i = 0; i < spreadCount; i++) ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i); - MethodType midType = MethodType.make(newType.returnType(), ptypes); + MethodType midType = MethodType.methodType(newType.returnType(), ptypes); // after spreading, some arguments may need further conversion - target = convertArguments(token, target, midType, oldType, null); - if (target == null) + MethodHandle target2 = convertArguments(token, target, midType, oldType, null); + if (target2 == null) throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType); - res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount); + res = AdapterMethodHandle.makeSpreadArguments(token, newType, target2, spreadArgType, spreadArg, spreadCount); + if (res != null) + return res; + res = SpreadGeneric.make(target2, spreadCount); + if (res != null) + res = convertArguments(token, res, newType, res.type(), null); return res; } public static MethodHandle collectArguments(Access token, MethodHandle target, MethodType newType, - int collectArg) { - if (collectArg > 0) - throw new UnsupportedOperationException("NYI"); - throw new UnsupportedOperationException("NYI"); + int collectArg, + MethodHandle collector) { + MethodType oldType = target.type(); // (a...,c)=>r + if (collector == null) { + int numCollect = newType.parameterCount() - oldType.parameterCount() + 1; + collector = ValueConversions.varargsArray(numCollect); + } + // newType // (a..., b...)=>r + MethodType colType = collector.type(); // (b...)=>c + // oldType // (a..., b...)=>r + assert(newType.parameterCount() == collectArg + colType.parameterCount()); + assert(oldType.parameterCount() == collectArg + 1); + MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null); + MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null); + if (gtarget == null || gcollector == null) return null; + MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget); + MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null); + return result; } + + public static MethodHandle filterArgument(Access token, + MethodHandle target, + int pos, + MethodHandle filter) { + Access.check(token); + MethodType ttype = target.type(), gttype = ttype.generic(); + if (ttype != gttype) { + target = convertArguments(token, target, gttype, ttype, null); + ttype = gttype; + } + MethodType ftype = filter.type(), gftype = ftype.generic(); + if (ftype.parameterCount() != 1) + throw new InternalError(); + if (ftype != gftype) { + filter = convertArguments(token, filter, gftype, ftype, null); + ftype = gftype; + } + if (ftype == ttype) { + // simple unary case + return FilterOneArgument.make(filter, target); + } + return FilterGeneric.makeArgumentFilter(pos, filter, target); + } + + public static MethodHandle foldArguments(Access token, + MethodHandle target, + MethodType newType, + MethodHandle combiner) { + Access.check(token); + MethodType oldType = target.type(); + MethodType ctype = combiner.type(); + MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null); + MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null); + if (gtarget == null || gcombiner == null) return null; + MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget); + MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null); + return result; + } + public static MethodHandle dropArguments(Access token, MethodHandle target, MethodType newType, int argnum) { Access.check(token); + int drops = newType.parameterCount() - target.type().parameterCount(); + MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops); + if (res != null) + return res; throw new UnsupportedOperationException("NYI"); } + private static class GuardWithTest extends JavaMethodHandle { + private final MethodHandle test, target, fallback; + public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { + this(INVOKES[target.type().parameterCount()], test, target, fallback); + } + public GuardWithTest(MethodHandle invoker, + MethodHandle test, MethodHandle target, MethodHandle fallback) { + super(invoker); + this.test = test; + this.target = target; + this.fallback = fallback; + } + @Override + public String toString() { + return target.toString(); + } + private Object invoke_V(Object... av) throws Throwable { + if (test.invoke(av)) + return target.invoke(av); + return fallback.invoke(av); + } + private Object invoke_L0() throws Throwable { + if (test.invoke()) + return target.invoke(); + return fallback.invoke(); + } + private Object invoke_L1(Object a0) throws Throwable { + if (test.invoke(a0)) + return target.invoke(a0); + return fallback.invoke(a0); + } + private Object invoke_L2(Object a0, Object a1) throws Throwable { + if (test.invoke(a0, a1)) + return target.invoke(a0, a1); + return fallback.invoke(a0, a1); + } + private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { + if (test.invoke(a0, a1, a2)) + return target.invoke(a0, a1, a2); + return fallback.invoke(a0, a1, a2); + } + private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { + if (test.invoke(a0, a1, a2, a3)) + return target.invoke(a0, a1, a2, a3); + return fallback.invoke(a0, a1, a2, a3); + } + private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { + if (test.invoke(a0, a1, a2, a3, a4)) + return target.invoke(a0, a1, a2, a3, a4); + return fallback.invoke(a0, a1, a2, a3, a4); + } + private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { + if (test.invoke(a0, a1, a2, a3, a4, a5)) + return target.invoke(a0, a1, a2, a3, a4, a5); + return fallback.invoke(a0, a1, a2, a3, a4, a5); + } + private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { + if (test.invoke(a0, a1, a2, a3, a4, a5, a6)) + return target.invoke(a0, a1, a2, a3, a4, a5, a6); + return fallback.invoke(a0, a1, a2, a3, a4, a5, a6); + } + private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { + if (test.invoke(a0, a1, a2, a3, a4, a5, a6, a7)) + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7); + return fallback.invoke(a0, a1, a2, a3, a4, a5, a6, a7); + } + static MethodHandle[] makeInvokes() { + ArrayList invokes = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = invokes.size(); + String name = "invoke_L"+nargs; + MethodHandle invoke = null; + try { + invoke = lookup.findVirtual(GuardWithTest.class, name, MethodType.genericMethodType(nargs)); + } catch (NoAccessException ex) { + } + if (invoke == null) break; + invokes.add(invoke); + } + assert(invokes.size() == 9); // current number of methods + return invokes.toArray(new MethodHandle[0]); + }; + static final MethodHandle[] INVOKES = makeInvokes(); + // For testing use this: + //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); + static final MethodHandle VARARGS_INVOKE; + static { + try { + VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true)); + } catch (NoAccessException ex) { + throw new InternalError(""); + } + } + } + public static MethodHandle makeGuardWithTest(Access token, - final MethodHandle test, - final MethodHandle target, - final MethodHandle fallback) { + MethodHandle test, + MethodHandle target, + MethodHandle fallback) { Access.check(token); - // %%% This is just a sketch. It needs to be de-boxed. - // Adjust the handles to accept varargs lists. MethodType type = target.type(); - Class rtype = type.returnType(); - if (type.parameterCount() != 1 || type.parameterType(0).isPrimitive()) { - MethodType vatestType = MethodType.make(boolean.class, Object[].class); - MethodType vatargetType = MethodType.make(rtype, Object[].class); - MethodHandle vaguard = makeGuardWithTest(token, - MethodHandles.spreadArguments(test, vatestType), - MethodHandles.spreadArguments(target, vatargetType), - MethodHandles.spreadArguments(fallback, vatargetType)); - return MethodHandles.collectArguments(vaguard, type); + int nargs = type.parameterCount(); + if (nargs < GuardWithTest.INVOKES.length) { + MethodType gtype = type.generic(); + MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null); + MethodHandle gtarget = convertArguments(token, target, gtype, type, null); + MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null); + if (gtest == null || gtarget == null || gfallback == null) return null; + MethodHandle gguard = new GuardWithTest(gtest, gtarget, gfallback); + return convertArguments(token, gguard, type, gtype, null); + } else { + MethodType gtype = MethodType.genericMethodType(0, true); + MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0); + MethodHandle gtarget = spreadArguments(token, target, gtype, 0); + MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0); + MethodHandle gguard = new GuardWithTest(GuardWithTest.VARARGS_INVOKE, gtest, gtarget, gfallback); + if (gtest == null || gtarget == null || gfallback == null) return null; + return collectArguments(token, gguard, type, 0, null); } - if (rtype.isPrimitive()) { - MethodType boxtype = type.changeReturnType(Object.class); - MethodHandle boxguard = makeGuardWithTest(token, - test, - MethodHandles.convertArguments(target, boxtype), - MethodHandles.convertArguments(fallback, boxtype)); - return MethodHandles.convertArguments(boxguard, type); + } + + private static class GuardWithCatch extends JavaMethodHandle { + private final MethodHandle target; + private final Class exType; + private final MethodHandle catcher; + public GuardWithCatch(MethodHandle target, Class exType, MethodHandle catcher) { + this(INVOKES[target.type().parameterCount()], target, exType, catcher); } - // Got here? Reduced calling sequence to Object(Object). - class Guarder { - Object invoke(Object x) { - // If javac supports MethodHandle.invoke directly: - //z = vatest.invoke(arguments); - // If javac does not support direct MH.invoke calls: - boolean z = (Boolean) MethodHandles.invoke_1(test, x); - MethodHandle mh = (z ? target : fallback); - return MethodHandles.invoke_1(mh, x); - } - MethodHandle handle() { - MethodType invokeType = MethodType.makeGeneric(0, true); - MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType); - return MethodHandles.collectArguments(vh, target.type()); + public GuardWithCatch(MethodHandle invoker, + MethodHandle target, Class exType, MethodHandle catcher) { + super(invoker); + this.target = target; + this.exType = exType; + this.catcher = catcher; + } + @Override + public String toString() { + return target.toString(); + } + private Object invoke_V(Object... av) throws Throwable { + try { + return target.invoke(av); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, av); } } - return new Guarder().handle(); + private Object invoke_L0() throws Throwable { + try { + return target.invoke(); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t); + } + } + private Object invoke_L1(Object a0) throws Throwable { + try { + return target.invoke(a0); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0); + } + } + private Object invoke_L2(Object a0, Object a1) throws Throwable { + try { + return target.invoke(a0, a1); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1); + } + } + private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { + try { + return target.invoke(a0, a1, a2); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2); + } + } + private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { + try { + return target.invoke(a0, a1, a2, a3); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2, a3); + } + } + private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { + try { + return target.invoke(a0, a1, a2, a3, a4); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2, a3, a4); + } + } + private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { + try { + return target.invoke(a0, a1, a2, a3, a4, a5); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2, a3, a4, a5); + } + } + private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { + try { + return target.invoke(a0, a1, a2, a3, a4, a5, a6); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2, a3, a4, a5, a6); + } + } + private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { + try { + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7); + } catch (Throwable t) { + if (!exType.isInstance(t)) throw t; + return catcher.invoke(t, a0, a1, a2, a3, a4, a5, a6, a7); + } + } + static MethodHandle[] makeInvokes() { + ArrayList invokes = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = invokes.size(); + String name = "invoke_L"+nargs; + MethodHandle invoke = null; + try { + invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs)); + } catch (NoAccessException ex) { + } + if (invoke == null) break; + invokes.add(invoke); + } + assert(invokes.size() == 9); // current number of methods + return invokes.toArray(new MethodHandle[0]); + }; + static final MethodHandle[] INVOKES = makeInvokes(); + // For testing use this: + //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); + static final MethodHandle VARARGS_INVOKE; + static { + try { + VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true)); + } catch (NoAccessException ex) { + throw new InternalError(""); + } + } + } + + + public static + MethodHandle makeGuardWithCatch(Access token, + MethodHandle target, + Class exType, + MethodHandle catcher) { + Access.check(token); + MethodType type = target.type(); + MethodType ctype = catcher.type(); + int nargs = type.parameterCount(); + if (nargs < GuardWithCatch.INVOKES.length) { + MethodType gtype = type.generic(); + MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); + MethodHandle gtarget = convertArguments(token, target, gtype, type, null); + MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null); + MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher); + if (gtarget == null || gcatcher == null || gguard == null) return null; + return convertArguments(token, gguard, type, gtype, null); + } else { + MethodType gtype = MethodType.genericMethodType(0, true); + MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); + MethodHandle gtarget = spreadArguments(token, target, gtype, 0); + MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1); + MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher); + if (gtarget == null || gcatcher == null || gguard == null) return null; + return collectArguments(token, gguard, type, 0, null); + } } public static - MethodHandle combineArguments(Access token, MethodHandle target, MethodHandle checker, int pos) { + MethodHandle throwException(Access token, MethodType type) { Access.check(token); - throw new UnsupportedOperationException("Not yet implemented"); + return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION); } - protected static String basicToString(MethodHandle target) { + static final MethodHandle THROW_EXCEPTION + = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", + MethodType.methodType(Empty.class, Throwable.class)); + static Empty throwException(T t) throws T { throw t; } + + public static String getNameString(Access token, MethodHandle target) { + Access.check(token); MemberName name = null; if (target != null) name = MethodHandleNatives.getMethodName(target); @@ -357,17 +1080,30 @@ public abstract class MethodHandleImpl { return name.getName(); } - protected static String addTypeString(MethodHandle target, String name) { - if (target == null) return name; - return name+target.type(); - } - static RuntimeException newIllegalArgumentException(String string) { - return new IllegalArgumentException(string); + public static String addTypeString(MethodHandle target) { + if (target == null) return "null"; + return target.toString() + target.type(); } - @Override - public String toString() { - MethodHandle self = (MethodHandle) this; - return addTypeString(self, basicToString(self)); + public static void checkSpreadArgument(Object av, int n) { + if (av == null ? n != 0 : ((Object[])av).length != n) + throw newIllegalArgumentException("Array is not of length "+n); + } + + public static void raiseException(int code, Object actual, Object required) { + String message; + // disregard the identity of the actual object, if it is not a class: + if (!(actual instanceof Class) && !(actual instanceof MethodType)) + actual = actual.getClass(); + if (actual != null) + message = "required "+required+" but encountered "+actual; + else + message = "required "+required; + switch (code) { + case 192: // checkcast + throw new ClassCastException(message); + default: + throw new InternalError("unexpected code "+code+": "+message); + } } } diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java index fc2d82aa8ff..0ede3c2f706 100644 --- a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java +++ b/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java @@ -25,6 +25,7 @@ package sun.dyn; +import java.dyn.CallSite; import java.dyn.MethodHandle; import java.dyn.MethodType; import java.lang.reflect.AccessibleObject; @@ -60,7 +61,7 @@ class MethodHandleNatives { static native void init(MethodType self); /** Tell the JVM that we need to change the target of an invokedynamic. */ - static native void linkCallSite(CallSiteImpl site, MethodHandle target); + static native void linkCallSite(CallSite site, MethodHandle target); /** Fetch the vmtarget field. * It will be sanitized as necessary to avoid exposing non-Java references. @@ -84,8 +85,7 @@ class MethodHandleNatives { } /** Fetch the target of this method handle. - * If it directly targets a method, return a tuple of method info. - * The info is of the form new Object[]{defclass, name, sig, refclass}. + * If it directly targets a method, return a MemberName for the method. * If it is chained to another method handle, return that handle. */ static Object getTargetInfo(MethodHandle self) { @@ -123,7 +123,7 @@ class MethodHandleNatives { registerNatives(); JVM_SUPPORT_ = true; JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT); - JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT); + JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT); //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); } catch (UnsatisfiedLinkError ee) { // ignore; if we use init() methods later we'll see linkage errors @@ -149,7 +149,7 @@ class MethodHandleNatives { // MethodHandleImpl static final int // for getConstant GC_JVM_PUSH_LIMIT = 0, - GC_JVM_STACK_MOVE_LIMIT = 1; + GC_JVM_STACK_MOVE_UNIT = 1; static final int ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) @@ -178,19 +178,20 @@ class MethodHandleNatives { */ static final int OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype - OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument - OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another - OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive - OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI) - OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg) - OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg) - OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS) - OP_DROP_ARGS = 0x8, // remove one or more argument slots - OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI) - OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size) - OP_FLYBY = 0xB, // operate first on reified argument list (NYI) - OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI) - CONV_OP_LIMIT = 0xD; // limit of CONV_OP enumeration + OP_RETYPE_RAW = 0x1, // no argument changes; straight retype + OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument + OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another + OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive + OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI) + OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg) + OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg) + OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS) + OP_DROP_ARGS = 0x9, // remove one or more argument slots + OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI) + OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size) + OP_FLYBY = 0xC, // operate first on reified argument list (NYI) + OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI) + CONV_OP_LIMIT = 0xE; // limit of CONV_OP enumeration /** Shift and mask values for decoding the AMH.conversion field. * These numbers are shared with the JVM for creating AMHs. */ @@ -209,6 +210,7 @@ class MethodHandleNatives { // TODO: The following expression should be replaced by // a JVM query. ((1<[] ptypes(MethodType mt); @@ -150,7 +151,7 @@ public class MethodTypeImpl { this.argToSlotTable = argToSlotTab; this.slotToArgTable = slotToArgTab; - if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments"); + if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); // send a few bits down to the JVM: this.vmslots = parameterSlotCount(); @@ -378,10 +379,10 @@ public class MethodTypeImpl { static MethodTypeImpl findForm(MethodType mt) { MethodType erased = canonicalize(mt, ERASE, ERASE); if (erased == null) { - // It is already erased. Make a new MethodTypeForm. + // It is already erased. Make a new MethodTypeImpl. return METHOD_TYPE_FRIEND.newMethodTypeForm(mt); } else { - // Share the MethodTypeForm with the erased version. + // Share the MethodTypeImpl with the erased version. return METHOD_TYPE_FRIEND.form(erased); } } diff --git a/jdk/src/share/classes/sun/dyn/SpreadGeneric.java b/jdk/src/share/classes/sun/dyn/SpreadGeneric.java new file mode 100644 index 00000000000..264479e2336 --- /dev/null +++ b/jdk/src/share/classes/sun/dyn/SpreadGeneric.java @@ -0,0 +1,682 @@ +/* + * 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.dyn; + +import java.dyn.JavaMethodHandle; +import java.dyn.MethodHandle; +import java.dyn.MethodHandles; +import java.dyn.MethodType; +import java.dyn.NoAccessException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import sun.dyn.util.ValueConversions; +import static sun.dyn.MemberName.newIllegalArgumentException; + +/** + * Generic spread adapter. + * Expands a final argument into multiple (zero or more) arguments, keeping the others the same. + * @author jrose + */ +class SpreadGeneric { + // type for the outgoing call + private final MethodType targetType; + // number of arguments to spread + private final int spreadCount; + // prototype adapter (clone and customize for each new target!) + private final Adapter adapter; + // entry point for adapter (Adapter mh, a...) => ... + private final MethodHandle entryPoint; + + /** Compute and cache information common to all spreading adapters + * that accept calls of the given (generic) type. + */ + private SpreadGeneric(MethodType targetType, int spreadCount) { + assert(targetType == targetType.generic()); + this.targetType = targetType; + this.spreadCount = spreadCount; + // the target invoker will generally need casts on reference arguments + MethodHandle[] ep = { null }; + Adapter ad = findAdapter(this, ep); + if (ad != null) { + this.adapter = ad; + this.entryPoint = ep[0]; + return; + } + this.adapter = buildAdapterFromBytecodes(targetType, spreadCount, ep); + this.entryPoint = ep[0]; + } + + /** From targetType remove the last spreadCount arguments, and instead + * append a simple Object argument. + */ + static MethodType preSpreadType(MethodType targetType, int spreadCount) { + @SuppressWarnings("unchecked") + ArrayList> params = new ArrayList(targetType.parameterList()); + int outargs = params.size(); + params.subList(outargs - spreadCount, outargs).clear(); + params.add(Object.class); + return MethodType.methodType(targetType.returnType(), params); + } + + MethodHandle makeInstance(MethodHandle target) { + MethodType type = target.type(); + if (type != targetType) { + throw new UnsupportedOperationException("NYI type="+type); + } + return adapter.makeInstance(this, target); + } + + /** Build an adapter of the given generic type, which invokes typedTarget + * on the incoming arguments, after unboxing as necessary. + * The return value is boxed if necessary. + * @param genericType the required type of the result + * @param typedTarget the target + * @return an adapter method handle + */ + public static MethodHandle make(MethodHandle target, int spreadCount) { + MethodType type = target.type(); + MethodType gtype = type.generic(); + if (type == gtype) { + return SpreadGeneric.of(type, spreadCount).makeInstance(target); + } else { + MethodHandle gtarget = FromGeneric.make(target); + assert(gtarget.type() == gtype); + MethodHandle gspread = SpreadGeneric.of(gtype, spreadCount).makeInstance(gtarget); + return ToGeneric.make(preSpreadType(type, spreadCount), gspread); + } + } + + /** Return the adapter information for this type's erasure. */ + static SpreadGeneric of(MethodType targetType, int spreadCount) { + if (targetType != targetType.generic()) + throw new UnsupportedOperationException("NYI type="+targetType); + MethodTypeImpl form = MethodTypeImpl.of(targetType); + int outcount = form.parameterCount(); + assert(spreadCount <= outcount); + SpreadGeneric[] spreadGens = form.spreadGeneric; + if (spreadGens == null) + form.spreadGeneric = spreadGens = new SpreadGeneric[outcount+1]; + SpreadGeneric spreadGen = spreadGens[spreadCount]; + if (spreadGen == null) + spreadGens[spreadCount] = spreadGen = new SpreadGeneric(form.erasedType(), spreadCount); + return spreadGen; + } + + public String toString() { + return getClass().getSimpleName()+targetType+"["+spreadCount+"]"; + } + + // This mini-api is called from an Adapter to manage the spread. + /** A check/coercion that happens once before any selections. */ + protected Object check(Object av, int n) { + MethodHandleImpl.checkSpreadArgument(av, n); + return av; + } + + /** The selection operator for spreading; note that it takes Object not Object[]. */ + protected Object select(Object av, int n) { + return ((Object[])av)[n]; + } + /* + protected int select_I(Object av, int n) { + // maybe return ((int[])select)[n] + throw new UnsupportedOperationException("subclass resp."); + } + protected int select_J(Object av, int n) { + // maybe return ((long[])select)[n] + throw new UnsupportedOperationException("subclass resp."); + } + // */ + + /* Create an adapter that handles spreading calls for the given type. */ + static Adapter findAdapter(SpreadGeneric outer, MethodHandle[] ep) { + MethodType targetType = outer.targetType; + int spreadCount = outer.spreadCount; + int outargs = targetType.parameterCount(); + int inargs = outargs - spreadCount; + if (inargs < 0) return null; + MethodType entryType = MethodType.genericMethodType(inargs + 1); // 1 for av + String cname1 = "S" + outargs; + String[] cnames = { cname1 }; + String iname = "invoke_S"+spreadCount; + // e.g., D5I2, D5, L5I2, L5; invoke_D5 + for (String cname : cnames) { + Class acls = Adapter.findSubClass(cname); + if (acls == null) continue; + // see if it has the required invoke method + MethodHandle entryPoint = null; + try { + entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls); + } catch (NoAccessException ex) { + } + if (entryPoint == null) continue; + Constructor ctor = null; + try { + ctor = acls.getDeclaredConstructor(SpreadGeneric.class); + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { + } + if (ctor == null) continue; + try { + // Produce an instance configured as a prototype. + Adapter ad = ctor.newInstance(outer); + ep[0] = entryPoint; + return ad; + } catch (IllegalArgumentException ex) { + } catch (InvocationTargetException wex) { + Throwable ex = wex.getTargetException(); + if (ex instanceof Error) throw (Error)ex; + if (ex instanceof RuntimeException) throw (RuntimeException)ex; + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + } + return null; + } + + static Adapter buildAdapterFromBytecodes(MethodType targetType, + int spreadCount, MethodHandle[] ep) { + throw new UnsupportedOperationException("NYI"); + } + + /** + * This adapter takes some untyped arguments, and returns an untyped result. + * Internally, it applies the invoker to the target, which causes the + * objects to be unboxed; the result is a raw type in L/I/J/F/D. + * This result is passed to convert, which is responsible for + * converting the raw result into a boxed object. + * The invoker is kept separate from the target because it can be + * generated once per type erasure family, and reused across adapters. + */ + static abstract class Adapter extends JavaMethodHandle { + /* + * class X<> extends Adapter { + * (Object**N)=>R target; + * static int S = N-M; + * Object invoke(Object**M a, Object v) = target(a..., v[0]...v[S-1]); + * } + */ + protected final SpreadGeneric outer; + protected final MethodHandle target; // (any**N) => R + + @Override + public String toString() { + return target.toString(); + } + + static final MethodHandle NO_ENTRY = ValueConversions.identity(); + + protected boolean isPrototype() { return target == null; } + protected Adapter(SpreadGeneric outer) { + super(NO_ENTRY); + this.outer = outer; + this.target = null; + assert(isPrototype()); + } + + protected Adapter(SpreadGeneric outer, MethodHandle target) { + super(outer.entryPoint); + this.outer = outer; + this.target = target; + } + + /** Make a copy of self, with new fields. */ + protected abstract Adapter makeInstance(SpreadGeneric outer, MethodHandle target); + // { return new ThisType(outer, target); } + + protected Object check(Object av, int n) { + return outer.check(av, n); + } + protected Object select(Object av, int n) { + return outer.select(av, n); + } + + static private final String CLASS_PREFIX; // "sun.dyn.SpreadGeneric$" + static { + String aname = Adapter.class.getName(); + String sname = Adapter.class.getSimpleName(); + if (!aname.endsWith(sname)) throw new InternalError(); + CLASS_PREFIX = aname.substring(0, aname.length() - sname.length()); + } + /** Find a sibing class of Adapter. */ + static Class findSubClass(String name) { + String cname = Adapter.CLASS_PREFIX + name; + try { + return Class.forName(cname).asSubclass(Adapter.class); + } catch (ClassNotFoundException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + } + } + + /* generated classes follow this pattern: + static class xS2 extends Adapter { + protected xS2(SpreadGeneric outer) { super(outer); } // to build prototype + protected xS2(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected xS2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new xS2(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av,0); + return target.invoke(a0, a1)); } + protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1); + return target.invoke(a0, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1); + return target.invoke( + super.select(av,0), super.select(av,1)); } + } + // */ + +/* +: SHELL; n=SpreadGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~ +//{{{ +import java.util.*; +class genclasses { + static String[][] TEMPLATES = { { + "@for@ N=0..10", + " //@each-cat@", + " static class @cat@ extends Adapter {", + " protected @cat@(SpreadGeneric outer) { super(outer); } // to build prototype", + " protected @cat@(SpreadGeneric outer, MethodHandle t) { super(outer, t); }", + " protected @cat@ makeInstance(SpreadGeneric outer, MethodHandle t) { return new @cat@(outer, t); }", + " protected Object invoke_S0(@Tvav,@Object av) throws Throwable { av = super.check(av, 0);", + " return target.invoke(@av@); }", + " //@each-S@", + " protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);", + " return target.invoke(@av,@@sv@); }", + " //@end-S@", + " }", + } }; + static final String NEWLINE_INDENT = "\n "; + enum VAR { + cat, N, S, av, av_, Tvav_, sv; + public final String pattern = "@"+toString().replace('_','.')+"@"; + public String binding = toString(); + static void makeBindings(boolean topLevel, int outargs, int spread) { + int inargs = outargs - spread; + VAR.cat.binding = "S"+outargs; + VAR.N.binding = String.valueOf(outargs); // outgoing arg count + VAR.S.binding = String.valueOf(spread); // spread count + String[] av = new String[inargs]; + String[] Tvav = new String[inargs]; + for (int i = 0; i < inargs; i++) { + av[i] = arg(i); + Tvav[i] = param("Object", av[i]); + } + VAR.av.binding = comma(av); + VAR.av_.binding = comma(av, ", "); + VAR.Tvav_.binding = comma(Tvav, ", "); + String[] sv = new String[spread]; + for (int i = 0; i < spread; i++) { + String spc = ""; + if (i % 4 == 0) spc = NEWLINE_INDENT; + sv[i] = spc+"super.select(av,"+i+")"; + } + VAR.sv.binding = comma(sv); + } + static String arg(int i) { return "a"+i; } + static String param(String t, String a) { return t+" "+a; } + static String comma(String[] v) { return comma(v, ""); } + static String comma(String[] v, String sep) { + if (v.length == 0) return ""; + String res = v[0]; + for (int i = 1; i < v.length; i++) res += ", "+v[i]; + return res + sep; + } + static String transform(String string) { + for (VAR var : values()) + string = string.replaceAll(var.pattern, var.binding); + return string; + } + } + static String[] stringsIn(String[] strings, int beg, int end) { + return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length)); + } + static String[] stringsBefore(String[] strings, int pos) { + return stringsIn(strings, 0, pos); + } + static String[] stringsAfter(String[] strings, int pos) { + return stringsIn(strings, pos, strings.length); + } + static int indexAfter(String[] strings, int pos, String tag) { + return Math.min(indexBefore(strings, pos, tag) + 1, strings.length); + } + static int indexBefore(String[] strings, int pos, String tag) { + for (int i = pos, end = strings.length; ; i++) { + if (i == end || strings[i].endsWith(tag)) return i; + } + } + static int MIN_ARITY, MAX_ARITY; + public static void main(String... av) { + for (String[] template : TEMPLATES) { + int forLinesLimit = indexBefore(template, 0, "@each-cat@"); + String[] forLines = stringsBefore(template, forLinesLimit); + template = stringsAfter(template, forLinesLimit); + for (String forLine : forLines) + expandTemplate(forLine, template); + } + } + static void expandTemplate(String forLine, String[] template) { + String[] params = forLine.split("[^0-9]+"); + if (params[0].length() == 0) params = stringsAfter(params, 1); + System.out.println("//params="+Arrays.asList(params)); + int pcur = 0; + MIN_ARITY = Integer.valueOf(params[pcur++]); + MAX_ARITY = Integer.valueOf(params[pcur++]); + if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine); + for (int outargs = MIN_ARITY; outargs <= MAX_ARITY; outargs++) { + expandTemplate(template, true, outargs, 0); + } + } + static void expandTemplate(String[] template, boolean topLevel, int outargs, int spread) { + VAR.makeBindings(topLevel, outargs, spread); + for (int i = 0; i < template.length; i++) { + String line = template[i]; + if (line.endsWith("@each-cat@")) { + // ignore + } else if (line.endsWith("@each-S@")) { + int blockEnd = indexAfter(template, i, "@end-S@"); + String[] block = stringsIn(template, i+1, blockEnd-1); + for (int spread1 = spread+1; spread1 <= outargs; spread1++) + expandTemplate(block, false, outargs, spread1); + VAR.makeBindings(topLevel, outargs, spread); + i = blockEnd-1; continue; + } else { + System.out.println(VAR.transform(line)); + } + } + } +} +//}}} */ +//params=[0, 10] + static class S0 extends Adapter { + protected S0(SpreadGeneric outer) { super(outer); } // to build prototype + protected S0(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S0 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S0(outer, t); } + protected Object invoke_S0(Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(); } + } + static class S1 extends Adapter { + protected S1(SpreadGeneric outer) { super(outer); } // to build prototype + protected S1(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S1 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S1(outer, t); } + protected Object invoke_S0(Object a0, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0); } + protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1); + return target.invoke( + super.select(av,0)); } + } + static class S2 extends Adapter { + protected S2(SpreadGeneric outer) { super(outer); } // to build prototype + protected S2(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S2(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1); } + protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, + super.select(av,0)); } + protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2); + return target.invoke( + super.select(av,0), super.select(av,1)); } + } + static class S3 extends Adapter { + protected S3(SpreadGeneric outer) { super(outer); } // to build prototype + protected S3(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S3 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S3(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2); } + protected Object invoke_S1(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object av) throws Throwable { av = super.check(av, 3); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2)); } + } + static class S4 extends Adapter { + protected S4(SpreadGeneric outer) { super(outer); } // to build prototype + protected S4(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S4 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S4(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object av) throws Throwable { av = super.check(av, 4); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + } + static class S5 extends Adapter { + protected S5(SpreadGeneric outer) { super(outer); } // to build prototype + protected S5(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S5 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S5(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object av) throws Throwable { av = super.check(av, 5); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + } + static class S6 extends Adapter { + protected S6(SpreadGeneric outer) { super(outer); } // to build prototype + protected S6(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S6 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S6(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4, a5); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, a4, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, a3, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object a0, Object av) throws Throwable { av = super.check(av, 5); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + protected Object invoke_S6(Object av) throws Throwable { av = super.check(av, 6); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5)); } + } + static class S7 extends Adapter { + protected S7(SpreadGeneric outer) { super(outer); } // to build prototype + protected S7(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S7 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S7(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, a4, a5, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, a3, a4, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, a2, a3, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 5); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + protected Object invoke_S6(Object a0, Object av) throws Throwable { av = super.check(av, 6); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5)); } + protected Object invoke_S7(Object av) throws Throwable { av = super.check(av, 7); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6)); } + } + static class S8 extends Adapter { + protected S8(SpreadGeneric outer) { super(outer); } // to build prototype + protected S8(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S8 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S8(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, a3, a4, a5, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, a2, a3, a4, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, a1, a2, a3, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 5); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + protected Object invoke_S6(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 6); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5)); } + protected Object invoke_S7(Object a0, Object av) throws Throwable { av = super.check(av, 7); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6)); } + protected Object invoke_S8(Object av) throws Throwable { av = super.check(av, 8); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); } + } + static class S9 extends Adapter { + protected S9(SpreadGeneric outer) { super(outer); } // to build prototype + protected S9(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S9 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S9(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, a2, a3, a4, a5, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, a1, a2, a3, a4, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 5); + return target.invoke(a0, a1, a2, a3, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + protected Object invoke_S6(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 6); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5)); } + protected Object invoke_S7(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 7); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6)); } + protected Object invoke_S8(Object a0, Object av) throws Throwable { av = super.check(av, 8); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); } + protected Object invoke_S9(Object av) throws Throwable { av = super.check(av, 9); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7), + super.select(av,8)); } + } + static class S10 extends Adapter { + protected S10(SpreadGeneric outer) { super(outer); } // to build prototype + protected S10(SpreadGeneric outer, MethodHandle t) { super(outer, t); } + protected S10 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S10(outer, t); } + protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9, Object av) throws Throwable { av = super.check(av, 0); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 1); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, a8, + super.select(av,0)); } + protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 2); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, a7, + super.select(av,0), super.select(av,1)); } + protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 3); + return target.invoke(a0, a1, a2, a3, a4, a5, a6, + super.select(av,0), super.select(av,1), super.select(av,2)); } + protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 4); + return target.invoke(a0, a1, a2, a3, a4, a5, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); } + protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 5); + return target.invoke(a0, a1, a2, a3, a4, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4)); } + protected Object invoke_S6(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 6); + return target.invoke(a0, a1, a2, a3, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5)); } + protected Object invoke_S7(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 7); + return target.invoke(a0, a1, a2, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6)); } + protected Object invoke_S8(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 8); + return target.invoke(a0, a1, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); } + protected Object invoke_S9(Object a0, Object av) throws Throwable { av = super.check(av, 9); + return target.invoke(a0, + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7), + super.select(av,8)); } + protected Object invoke_S10(Object av) throws Throwable { av = super.check(av, 10); + return target.invoke( + super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3), + super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7), + super.select(av,8), super.select(av,9)); } + } +} diff --git a/jdk/src/share/classes/sun/dyn/ToGeneric.java b/jdk/src/share/classes/sun/dyn/ToGeneric.java index fd04d753e74..03c374b1c5c 100644 --- a/jdk/src/share/classes/sun/dyn/ToGeneric.java +++ b/jdk/src/share/classes/sun/dyn/ToGeneric.java @@ -34,6 +34,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import sun.dyn.util.ValueConversions; import sun.dyn.util.Wrapper; +import static sun.dyn.MemberName.newIllegalArgumentException; /** * Adapters which mediate between incoming calls which are not generic @@ -68,7 +69,7 @@ class ToGeneric { // conversion which unboxes a primitive return value private final MethodHandle returnConversion; - /** Compute and cache information common to all collecting adapters + /** Compute and cache information common to all generifying (boxing) adapters * that implement members of the erasure-family of the given erased type. */ private ToGeneric(MethodType entryType) { @@ -111,30 +112,48 @@ class ToGeneric { // primitive arguments according to their "raw" types int/long MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts(); ad = findAdapter(rawEntryTypeInit = intsAtEnd); - if (ad == null) { + MethodHandle rawEntryPoint; + if (ad != null) { + rawEntryPoint = ad.prototypeEntryPoint(); + } else { // Perhaps the adapter is available only for longs. // If so, we can use it, but there will have to be a little // more stack motion on each call. MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs(); ad = findAdapter(rawEntryTypeInit = longsAtEnd); - if (ad == null) { + if (ad != null) { + MethodType eptWithLongs = longsAtEnd.insertParameterTypes(0, ad.getClass()); + MethodType eptWithInts = intsAtEnd.insertParameterTypes(0, ad.getClass()); + rawEntryPoint = ad.prototypeEntryPoint(); + MethodType midType = eptWithLongs; // will change longs to ints + for (int i = 0, nargs = midType.parameterCount(); i < nargs; i++) { + if (midType.parameterType(i) != eptWithInts.parameterType(i)) { + assert(midType.parameterType(i) == long.class); + assert(eptWithInts.parameterType(i) == int.class); + MethodType nextType = midType.changeParameterType(i, int.class); + rawEntryPoint = MethodHandle.convertArguments(Access.TOKEN, + rawEntryPoint, nextType, midType, null); + midType = nextType; + } + } + assert(midType == eptWithInts); + } else { // If there is no statically compiled adapter, // build one by means of dynamic bytecode generation. ad = buildAdapterFromBytecodes(rawEntryTypeInit = intsAtEnd); + rawEntryPoint = ad.prototypeEntryPoint(); } } - MethodHandle rawEntryPoint = ad.prototypeEntryPoint(); - MethodType tepType = entryType.insertParameterType(0, ad.getClass()); + MethodType tepType = entryType.insertParameterTypes(0, ad.getClass()); this.entryPoint = - AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, rawEntryPoint); + AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, rawEntryPoint); if (this.entryPoint == null) throw new UnsupportedOperationException("cannot retype to "+entryType - +" from "+rawEntryPoint.type().dropParameterType(0)); + +" from "+rawEntryPoint.type().dropParameterTypes(0, 1)); this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false); this.rawEntryType = rawEntryTypeInit; this.adapter = ad; - this.invoker = makeRawArgumentFilter(invoker0, - rawEntryPoint.type().dropParameterType(0), entryType); + this.invoker = makeRawArgumentFilter(invoker0, rawEntryTypeInit, entryType); } /** A generic argument list will be created by a call of type 'raw'. @@ -157,8 +176,8 @@ class ToGeneric { if (filteredInvoker == null) throw new UnsupportedOperationException("NYI"); } MethodHandle reboxer = ValueConversions.rebox(dst, false); - FilterGeneric gen = new FilterGeneric(filteredInvoker.type(), (short)(1+i), (short)1, 'R'); - filteredInvoker = gen.makeInstance(reboxer, filteredInvoker); + filteredInvoker = FilterGeneric.makeArgumentFilter(1+i, reboxer, filteredInvoker); + if (filteredInvoker == null) throw new InternalError(); } if (filteredInvoker == null) return invoker; return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker); @@ -209,9 +228,9 @@ class ToGeneric { if (convert == null) convert = computeReturnConversion(type, rawEntryType, true); // retype erased reference arguments (the cast makes it safe to do this) - MethodType tepType = type.insertParameterType(0, adapter.getClass()); + MethodType tepType = type.insertParameterTypes(0, adapter.getClass()); MethodHandle typedEntryPoint = - AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, entryPoint); + AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, entryPoint); return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget); } @@ -225,7 +244,7 @@ class ToGeneric { public static MethodHandle make(MethodType type, MethodHandle genericTarget) { MethodType gtype = genericTarget.type(); if (type.generic() != gtype) - throw new IllegalArgumentException(); + throw newIllegalArgumentException("type must be generic"); if (type == gtype) return genericTarget; return ToGeneric.of(type).makeInstance(type, genericTarget); } @@ -283,7 +302,10 @@ class ToGeneric { try { return ctor.newInstance(entryPoint); } catch (IllegalArgumentException ex) { - } catch (InvocationTargetException ex) { + } catch (InvocationTargetException wex) { + Throwable ex = wex.getTargetException(); + if (ex instanceof Error) throw (Error)ex; + if (ex instanceof RuntimeException) throw (RuntimeException)ex; } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } @@ -317,6 +339,11 @@ class ToGeneric { protected final MethodHandle target; // Object... -> Object protected final MethodHandle convert; // Object -> R + @Override + public String toString() { + return target.toString(); + } + protected boolean isPrototype() { return target == null; } /* Prototype constructor. */ protected Adapter(MethodHandle entryPoint) { @@ -344,33 +371,33 @@ class ToGeneric { // { return new ThisType(entryPoint, convert, target); } // Code to run when the arguments (<= 4) have all been boxed. - protected Object target() { return invoker.invoke(target); } - protected Object target(Object a0) { return invoker.invoke(target, a0); } + protected Object target() throws Throwable { return invoker.invoke(target); } + protected Object target(Object a0) throws Throwable { return invoker.invoke(target, a0); } protected Object target(Object a0, Object a1) - { return invoker.invoke(target, a0, a1); } + throws Throwable { return invoker.invoke(target, a0, a1); } protected Object target(Object a0, Object a1, Object a2) - { return invoker.invoke(target, a0, a1, a2); } + throws Throwable { return invoker.invoke(target, a0, a1, a2); } protected Object target(Object a0, Object a1, Object a2, Object a3) - { return invoker.invoke(target, a0, a1, a2, a3); } + throws Throwable { return invoker.invoke(target, a0, a1, a2, a3); } /* - protected Object target_0(Object... av) { return invoker.invoke(target, av); } + protected Object target_0(Object... av) throws Throwable { return invoker.invoke(target, av); } protected Object target_1(Object a0, Object... av) - { return invoker.invoke(target, a0, (Object)av); } + throws Throwable { return invoker.invoke(target, a0, (Object)av); } protected Object target_2(Object a0, Object a1, Object... av) - { return invoker.invoke(target, a0, a1, (Object)av); } + throws Throwable { return invoker.invoke(target, a0, a1, (Object)av); } protected Object target_3(Object a0, Object a1, Object a2, Object... av) - { return invoker.invoke(target, a0, a1, a2, (Object)av); } + throws Throwable { return invoker.invoke(target, a0, a1, a2, (Object)av); } protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av) - { return invoker.invoke(target, a0, a1, a2, a3, (Object)av); } + throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, (Object)av); } // */ // (For more than 4 arguments, generate the code in the adapter itself.) // Code to run when the generic target has finished and produced a value. - protected Object return_L(Object res) { return convert.invoke(res); } - protected int return_I(Object res) { return convert.invoke(res); } - protected long return_J(Object res) { return convert.invoke(res); } - protected float return_F(Object res) { return convert.invoke(res); } - protected double return_D(Object res) { return convert.invoke(res); } + protected Object return_L(Object res) throws Throwable { return convert.invoke(res); } + protected int return_I(Object res) throws Throwable { return convert.invoke(res); } + protected long return_J(Object res) throws Throwable { return convert.invoke(res); } + protected float return_F(Object res) throws Throwable { return convert.invoke(res); } + protected double return_D(Object res) throws Throwable { return convert.invoke(res); } static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$" static { @@ -397,25 +424,25 @@ class ToGeneric { protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); } - protected Object target(Object a0) { return invoker.invoke(target, a0); } - protected Object targetA1(Object a0) { return target(a0); } - protected Object targetA1(int a0) { return target(a0); } - protected Object targetA1(long a0) { return target(a0); } - protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); } - protected int invoke_I(Object a0) { return return_I(targetA1(a0)); } - protected long invoke_J(Object a0) { return return_J(targetA1(a0)); } - protected float invoke_F(Object a0) { return return_F(targetA1(a0)); } - protected double invoke_D(Object a0) { return return_D(targetA1(a0)); } - protected Object invoke_L(int a0) { return return_L(targetA1(a0)); } - protected int invoke_I(int a0) { return return_I(targetA1(a0)); } - protected long invoke_J(int a0) { return return_J(targetA1(a0)); } - protected float invoke_F(int a0) { return return_F(targetA1(a0)); } - protected double invoke_D(int a0) { return return_D(targetA1(a0)); } - protected Object invoke_L(long a0) { return return_L(targetA1(a0)); } - protected int invoke_I(long a0) { return return_I(targetA1(a0)); } - protected long invoke_J(long a0) { return return_J(targetA1(a0)); } - protected float invoke_F(long a0) { return return_F(targetA1(a0)); } - protected double invoke_D(long a0) { return return_D(targetA1(a0)); } + protected Object target(Object a0) throws Throwable { return invoker.invoke(target, a0); } + protected Object targetA1(Object a0) throws Throwable { return target(a0); } + protected Object targetA1(int a0) throws Throwable { return target(a0); } + protected Object targetA1(long a0) throws Throwable { return target(a0); } + protected Object invoke_L(Object a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(Object a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(Object a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(Object a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(Object a0) throws Throwable { return return_D(targetA1(a0)); } + protected Object invoke_L(int a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(int a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(int a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(int a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(int a0) throws Throwable { return return_D(targetA1(a0)); } + protected Object invoke_L(long a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(long a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(long a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(long a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(long a0) throws Throwable { return return_D(targetA1(a0)); } } // */ @@ -435,13 +462,13 @@ class genclasses { " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype", " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }", " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }", - " protected Object target(@Ovav@) { return invoker.invoke(target, @av@); }", + " protected Object target(@Ovav@) throws Throwable { return invoker.invoke(target, @av@); }", " //@each-Tv@", - " protected Object target@cat@(@Tvav@) { return target(@av@); }", + " protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }", " //@end-Tv@", " //@each-Tv@", " //@each-R@", - " protected @R@ invoke_@Rc@(@Tvav@) { return return_@Rc@(target@cat@(@av@)); }", + " protected @R@ invoke_@Rc@(@Tvav@) throws Throwable { return return_@Rc@(target@cat@(@av@)); }", " //@end-R@", " //@end-Tv@", " }", @@ -595,424 +622,424 @@ class genclasses { protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); } - protected Object target() { return invoker.invoke(target); } - protected Object targetA0() { return target(); } - protected Object invoke_L() { return return_L(targetA0()); } - protected int invoke_I() { return return_I(targetA0()); } - protected long invoke_J() { return return_J(targetA0()); } - protected float invoke_F() { return return_F(targetA0()); } - protected double invoke_D() { return return_D(targetA0()); } + protected Object target() throws Throwable { return invoker.invoke(target); } + protected Object targetA0() throws Throwable { return target(); } + protected Object invoke_L() throws Throwable { return return_L(targetA0()); } + protected int invoke_I() throws Throwable { return return_I(targetA0()); } + protected long invoke_J() throws Throwable { return return_J(targetA0()); } + protected float invoke_F() throws Throwable { return return_F(targetA0()); } + protected double invoke_D() throws Throwable { return return_D(targetA0()); } } static class A1 extends Adapter { protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); } - protected Object target(Object a0) { return invoker.invoke(target, a0); } - protected Object targetA1(Object a0) { return target(a0); } - protected Object targetA1(int a0) { return target(a0); } - protected Object targetA1(long a0) { return target(a0); } - protected Object invoke_L(Object a0) { return return_L(targetA1(a0)); } - protected int invoke_I(Object a0) { return return_I(targetA1(a0)); } - protected long invoke_J(Object a0) { return return_J(targetA1(a0)); } - protected float invoke_F(Object a0) { return return_F(targetA1(a0)); } - protected double invoke_D(Object a0) { return return_D(targetA1(a0)); } - protected Object invoke_L(int a0) { return return_L(targetA1(a0)); } - protected int invoke_I(int a0) { return return_I(targetA1(a0)); } - protected long invoke_J(int a0) { return return_J(targetA1(a0)); } - protected float invoke_F(int a0) { return return_F(targetA1(a0)); } - protected double invoke_D(int a0) { return return_D(targetA1(a0)); } - protected Object invoke_L(long a0) { return return_L(targetA1(a0)); } - protected int invoke_I(long a0) { return return_I(targetA1(a0)); } - protected long invoke_J(long a0) { return return_J(targetA1(a0)); } - protected float invoke_F(long a0) { return return_F(targetA1(a0)); } - protected double invoke_D(long a0) { return return_D(targetA1(a0)); } + protected Object target(Object a0) throws Throwable { return invoker.invoke(target, a0); } + protected Object targetA1(Object a0) throws Throwable { return target(a0); } + protected Object targetA1(int a0) throws Throwable { return target(a0); } + protected Object targetA1(long a0) throws Throwable { return target(a0); } + protected Object invoke_L(Object a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(Object a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(Object a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(Object a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(Object a0) throws Throwable { return return_D(targetA1(a0)); } + protected Object invoke_L(int a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(int a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(int a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(int a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(int a0) throws Throwable { return return_D(targetA1(a0)); } + protected Object invoke_L(long a0) throws Throwable { return return_L(targetA1(a0)); } + protected int invoke_I(long a0) throws Throwable { return return_I(targetA1(a0)); } + protected long invoke_J(long a0) throws Throwable { return return_J(targetA1(a0)); } + protected float invoke_F(long a0) throws Throwable { return return_F(targetA1(a0)); } + protected double invoke_D(long a0) throws Throwable { return return_D(targetA1(a0)); } } static class A2 extends Adapter { protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); } - protected Object target(Object a0, Object a1) { return invoker.invoke(target, a0, a1); } - protected Object targetA2(Object a0, Object a1) { return target(a0, a1); } - protected Object targetA2(Object a0, int a1) { return target(a0, a1); } - protected Object targetA2(int a0, int a1) { return target(a0, a1); } - protected Object targetA2(Object a0, long a1) { return target(a0, a1); } - protected Object targetA2(long a0, long a1) { return target(a0, a1); } - protected Object invoke_L(Object a0, Object a1) { return return_L(targetA2(a0, a1)); } - protected int invoke_I(Object a0, Object a1) { return return_I(targetA2(a0, a1)); } - protected long invoke_J(Object a0, Object a1) { return return_J(targetA2(a0, a1)); } - protected float invoke_F(Object a0, Object a1) { return return_F(targetA2(a0, a1)); } - protected double invoke_D(Object a0, Object a1) { return return_D(targetA2(a0, a1)); } - protected Object invoke_L(Object a0, int a1) { return return_L(targetA2(a0, a1)); } - protected int invoke_I(Object a0, int a1) { return return_I(targetA2(a0, a1)); } - protected long invoke_J(Object a0, int a1) { return return_J(targetA2(a0, a1)); } - protected float invoke_F(Object a0, int a1) { return return_F(targetA2(a0, a1)); } - protected double invoke_D(Object a0, int a1) { return return_D(targetA2(a0, a1)); } - protected Object invoke_L(int a0, int a1) { return return_L(targetA2(a0, a1)); } - protected int invoke_I(int a0, int a1) { return return_I(targetA2(a0, a1)); } - protected long invoke_J(int a0, int a1) { return return_J(targetA2(a0, a1)); } - protected float invoke_F(int a0, int a1) { return return_F(targetA2(a0, a1)); } - protected double invoke_D(int a0, int a1) { return return_D(targetA2(a0, a1)); } - protected Object invoke_L(Object a0, long a1) { return return_L(targetA2(a0, a1)); } - protected int invoke_I(Object a0, long a1) { return return_I(targetA2(a0, a1)); } - protected long invoke_J(Object a0, long a1) { return return_J(targetA2(a0, a1)); } - protected float invoke_F(Object a0, long a1) { return return_F(targetA2(a0, a1)); } - protected double invoke_D(Object a0, long a1) { return return_D(targetA2(a0, a1)); } - protected Object invoke_L(long a0, long a1) { return return_L(targetA2(a0, a1)); } - protected int invoke_I(long a0, long a1) { return return_I(targetA2(a0, a1)); } - protected long invoke_J(long a0, long a1) { return return_J(targetA2(a0, a1)); } - protected float invoke_F(long a0, long a1) { return return_F(targetA2(a0, a1)); } - protected double invoke_D(long a0, long a1) { return return_D(targetA2(a0, a1)); } + protected Object target(Object a0, Object a1) throws Throwable { return invoker.invoke(target, a0, a1); } + protected Object targetA2(Object a0, Object a1) throws Throwable { return target(a0, a1); } + protected Object targetA2(Object a0, int a1) throws Throwable { return target(a0, a1); } + protected Object targetA2(int a0, int a1) throws Throwable { return target(a0, a1); } + protected Object targetA2(Object a0, long a1) throws Throwable { return target(a0, a1); } + protected Object targetA2(long a0, long a1) throws Throwable { return target(a0, a1); } + protected Object invoke_L(Object a0, Object a1) throws Throwable { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, Object a1) throws Throwable { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, Object a1) throws Throwable { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, Object a1) throws Throwable { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, Object a1) throws Throwable { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(Object a0, int a1) throws Throwable { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, int a1) throws Throwable { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, int a1) throws Throwable { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, int a1) throws Throwable { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, int a1) throws Throwable { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(int a0, int a1) throws Throwable { return return_L(targetA2(a0, a1)); } + protected int invoke_I(int a0, int a1) throws Throwable { return return_I(targetA2(a0, a1)); } + protected long invoke_J(int a0, int a1) throws Throwable { return return_J(targetA2(a0, a1)); } + protected float invoke_F(int a0, int a1) throws Throwable { return return_F(targetA2(a0, a1)); } + protected double invoke_D(int a0, int a1) throws Throwable { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(Object a0, long a1) throws Throwable { return return_L(targetA2(a0, a1)); } + protected int invoke_I(Object a0, long a1) throws Throwable { return return_I(targetA2(a0, a1)); } + protected long invoke_J(Object a0, long a1) throws Throwable { return return_J(targetA2(a0, a1)); } + protected float invoke_F(Object a0, long a1) throws Throwable { return return_F(targetA2(a0, a1)); } + protected double invoke_D(Object a0, long a1) throws Throwable { return return_D(targetA2(a0, a1)); } + protected Object invoke_L(long a0, long a1) throws Throwable { return return_L(targetA2(a0, a1)); } + protected int invoke_I(long a0, long a1) throws Throwable { return return_I(targetA2(a0, a1)); } + protected long invoke_J(long a0, long a1) throws Throwable { return return_J(targetA2(a0, a1)); } + protected float invoke_F(long a0, long a1) throws Throwable { return return_F(targetA2(a0, a1)); } + protected double invoke_D(long a0, long a1) throws Throwable { return return_D(targetA2(a0, a1)); } } static class A3 extends Adapter { protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2) { return invoker.invoke(target, a0, a1, a2); } - protected Object targetA3(Object a0, Object a1, Object a2) { return target(a0, a1, a2); } - protected Object targetA3(Object a0, Object a1, int a2) { return target(a0, a1, a2); } - protected Object targetA3(Object a0, int a1, int a2) { return target(a0, a1, a2); } - protected Object targetA3(int a0, int a1, int a2) { return target(a0, a1, a2); } - protected Object targetA3(Object a0, Object a1, long a2) { return target(a0, a1, a2); } - protected Object targetA3(Object a0, long a1, long a2) { return target(a0, a1, a2); } - protected Object targetA3(long a0, long a1, long a2) { return target(a0, a1, a2); } - protected Object invoke_L(Object a0, Object a1, Object a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(Object a0, Object a1, Object a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(Object a0, Object a1, Object a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(Object a0, Object a1, Object a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(Object a0, Object a1, Object a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(Object a0, Object a1, int a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(Object a0, Object a1, int a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(Object a0, Object a1, int a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(Object a0, Object a1, int a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(Object a0, Object a1, int a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(Object a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(Object a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(Object a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(Object a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(Object a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(int a0, int a1, int a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(int a0, int a1, int a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(int a0, int a1, int a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(int a0, int a1, int a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(int a0, int a1, int a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(Object a0, Object a1, long a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(Object a0, Object a1, long a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(Object a0, Object a1, long a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(Object a0, Object a1, long a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(Object a0, Object a1, long a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(Object a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(Object a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(Object a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(Object a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(Object a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); } - protected Object invoke_L(long a0, long a1, long a2) { return return_L(targetA3(a0, a1, a2)); } - protected int invoke_I(long a0, long a1, long a2) { return return_I(targetA3(a0, a1, a2)); } - protected long invoke_J(long a0, long a1, long a2) { return return_J(targetA3(a0, a1, a2)); } - protected float invoke_F(long a0, long a1, long a2) { return return_F(targetA3(a0, a1, a2)); } - protected double invoke_D(long a0, long a1, long a2) { return return_D(targetA3(a0, a1, a2)); } + protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.invoke(target, a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, Object a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, int a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(Object a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(int a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(Object a0, Object a1, long a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(Object a0, long a1, long a2) throws Throwable { return target(a0, a1, a2); } + protected Object targetA3(long a0, long a1, long a2) throws Throwable { return target(a0, a1, a2); } + protected Object invoke_L(Object a0, Object a1, Object a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, Object a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, Object a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, Object a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, Object a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, Object a1, int a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, int a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, int a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, int a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, int a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, int a1, int a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, int a1, int a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, int a1, int a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, int a1, int a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, int a1, int a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(int a0, int a1, int a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(int a0, int a1, int a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(int a0, int a1, int a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(int a0, int a1, int a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(int a0, int a1, int a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, Object a1, long a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, Object a1, long a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, Object a1, long a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, Object a1, long a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, Object a1, long a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(Object a0, long a1, long a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(Object a0, long a1, long a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(Object a0, long a1, long a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(Object a0, long a1, long a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(Object a0, long a1, long a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } + protected Object invoke_L(long a0, long a1, long a2) throws Throwable { return return_L(targetA3(a0, a1, a2)); } + protected int invoke_I(long a0, long a1, long a2) throws Throwable { return return_I(targetA3(a0, a1, a2)); } + protected long invoke_J(long a0, long a1, long a2) throws Throwable { return return_J(targetA3(a0, a1, a2)); } + protected float invoke_F(long a0, long a1, long a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); } + protected double invoke_D(long a0, long a1, long a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); } } //params=[4, 5, 2, 99, 99, 99] static class A4 extends Adapter { protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3) { return invoker.invoke(target, a0, a1, a2, a3); } - protected Object targetA4(Object a0, Object a1, Object a2, Object a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, Object a1, Object a2, int a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, Object a1, int a2, int a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(int a0, int a1, int a2, int a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, Object a1, Object a2, long a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, Object a1, long a2, long a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(Object a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); } - protected Object targetA4(long a0, long a1, long a2, long a3) { return target(a0, a1, a2, a3); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, Object a1, Object a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, Object a1, Object a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, Object a1, Object a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, Object a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, Object a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, Object a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(int a0, int a1, int a2, int a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(int a0, int a1, int a2, int a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(int a0, int a1, int a2, int a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(Object a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(Object a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } - protected Object invoke_L(long a0, long a1, long a2, long a3) { return return_L(targetA4(a0, a1, a2, a3)); } - protected int invoke_I(long a0, long a1, long a2, long a3) { return return_I(targetA4(a0, a1, a2, a3)); } - protected long invoke_J(long a0, long a1, long a2, long a3) { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, int a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, int a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(int a0, int a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, Object a2, long a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, Object a1, long a2, long a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(Object a0, long a1, long a2, long a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object targetA4(long a0, long a1, long a2, long a3) throws Throwable { return target(a0, a1, a2, a3); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(int a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(int a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(int a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(Object a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(Object a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } + protected Object invoke_L(long a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); } + protected int invoke_I(long a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); } + protected long invoke_J(long a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); } } static class A5 extends Adapter { protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) { return invoker.invoke(target, a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(int a0, int a1, int a2, int a3, int a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, Object a2, Object a3, long a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, Object a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, Object a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(Object a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } - protected Object targetA5(long a0, long a1, long a2, long a3, long a4) { return target(a0, a1, a2, a3, a4); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, Object a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, Object a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, Object a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(int a0, int a1, int a2, int a3, int a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(int a0, int a1, int a2, int a3, int a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(int a0, int a1, int a2, int a3, int a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4) { return return_L(targetA5(a0, a1, a2, a3, a4)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4) { return return_I(targetA5(a0, a1, a2, a3, a4)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4) { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, int a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, int a1, int a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(int a0, int a1, int a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, Object a3, long a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, Object a2, long a3, long a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, Object a1, long a2, long a3, long a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(Object a0, long a1, long a2, long a3, long a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object targetA5(long a0, long a1, long a2, long a3, long a4) throws Throwable { return target(a0, a1, a2, a3, a4); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, int a2, int a3, int a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, int a2, int a3, int a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, int a2, int a3, int a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, int a1, int a2, int a3, int a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, int a1, int a2, int a3, int a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, int a1, int a2, int a3, int a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(int a0, int a1, int a2, int a3, int a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(int a0, int a1, int a2, int a3, int a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(int a0, int a1, int a2, int a3, int a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4) throws Throwable { return return_L(targetA5(a0, a1, a2, a3, a4)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4) throws Throwable { return return_I(targetA5(a0, a1, a2, a3, a4)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4) throws Throwable { return return_J(targetA5(a0, a1, a2, a3, a4)); } } //params=[6, 10, 2, 99, 0, 99] static class A6 extends Adapter { protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, Object a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(Object a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object targetA6(long a0, long a1, long a2, long a3, long a4, long a5) { return target(a0, a1, a2, a3, a4, a5); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5) { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5) { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5) { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, Object a2, long a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, Object a1, long a2, long a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(Object a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object targetA6(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_L(targetA6(a0, a1, a2, a3, a4, a5)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_I(targetA6(a0, a1, a2, a3, a4, a5)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { return return_J(targetA6(a0, a1, a2, a3, a4, a5)); } } static class A7 extends Adapter { protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object targetA7(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return target(a0, a1, a2, a3, a4, a5, a6); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object targetA7(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_L(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_I(targetA7(a0, a1, a2, a3, a4, a5, a6)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { return return_J(targetA7(a0, a1, a2, a3, a4, a5, a6)); } } static class A8 extends Adapter { protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object targetA8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return target(a0, a1, a2, a3, a4, a5, a6, a7); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object targetA8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_L(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_I(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { return return_J(targetA8(a0, a1, a2, a3, a4, a5, a6, a7)); } } static class A9 extends Adapter { protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object targetA9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object targetA9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_L(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_I(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { return return_J(targetA9(a0, a1, a2, a3, a4, a5, a6, a7, a8)); } } static class A10 extends Adapter { protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); } protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); } - protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object targetA10(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } - protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.invoke(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object targetA10(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, Object a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, Object a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, Object a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(Object a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected Object invoke_L(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_L(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected int invoke_I(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_I(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } + protected long invoke_J(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { return return_J(targetA10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); } } } diff --git a/jdk/src/share/classes/sun/dyn/empty/Empty.java b/jdk/src/share/classes/sun/dyn/empty/Empty.java index 4fb72d0be67..df1ce6b7819 100644 --- a/jdk/src/share/classes/sun/dyn/empty/Empty.java +++ b/jdk/src/share/classes/sun/dyn/empty/Empty.java @@ -29,6 +29,10 @@ package sun.dyn.empty; * An empty class in an empty package. * Used as a proxy for unprivileged code, since making access checks * against it will only succeed against public methods in public types. + *

    + * This class also stands (internally to sun.dyn) for the type of a + * value that cannot be produced, because the expression of this type + * always returns abnormally. (Cf. Nothing in the closures proposal.) * @author jrose */ public class Empty { diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java b/jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java similarity index 98% rename from jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java rename to jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java index 37d8708cb29..290f2fb431b 100644 --- a/jdk/src/share/classes/sun/dyn/util/BytecodeSignature.java +++ b/jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java @@ -33,9 +33,9 @@ import java.util.List; * Utility routines for dealing with bytecode-level signatures. * @author jrose */ -public class BytecodeSignature { +public class BytecodeDescriptor { - private BytecodeSignature() { } // cannot instantiate + private BytecodeDescriptor() { } // cannot instantiate public static List> parseMethod(String bytecodeSignature, ClassLoader loader) { return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeName.java b/jdk/src/share/classes/sun/dyn/util/BytecodeName.java index 2abe780a5ef..e037e699530 100644 --- a/jdk/src/share/classes/sun/dyn/util/BytecodeName.java +++ b/jdk/src/share/classes/sun/dyn/util/BytecodeName.java @@ -298,6 +298,8 @@ public class BytecodeName { * The name {@code <init>} will be parsed into { '<', "init", '>'}} * The name {@code foo/bar$:baz} will be parsed into * {@code {"foo", '/', "bar", '$', ':', "baz"}}. + * The name {@code ::\=:foo:\=bar\!baz} will be parsed into + * {@code {':', ':', "", ':', "foo", ':', "bar:baz"}}. */ public static Object[] parseBytecodeName(String s) { int slen = s.length(); @@ -315,7 +317,7 @@ public class BytecodeName { if (lasti < i) { // normal component if (pass != 0) - res[fillp] = s.substring(lasti, i); + res[fillp] = toSourceName(s.substring(lasti, i)); fillp++; lasti = i+1; } @@ -323,13 +325,14 @@ public class BytecodeName { if (pass != 0) res[fillp] = DANGEROUS_CHARS_CA[whichDC]; fillp++; + lasti = i+1; } } if (pass != 0) break; // between passes, build the result array - res = new String[fillp]; - if (fillp <= 1) { - if (fillp != 0) res[0] = s; + res = new Object[fillp]; + if (fillp <= 1 && lasti == 0) { + if (fillp != 0) res[0] = toSourceName(s); break; } } @@ -348,9 +351,19 @@ public class BytecodeName { * @throws NullPointerException if any component is null */ public static String unparseBytecodeName(Object[] components) { - for (Object c : components) { - if (c instanceof String) - checkSafeBytecodeName((String) c); // may fail + Object[] components0 = components; + for (int i = 0; i < components.length; i++) { + Object c = components[i]; + if (c instanceof String) { + String mc = toBytecodeName((String) c); + if (i == 0 && components.length == 1) + return mc; // usual case + if ((Object)mc != c) { + if (components == components0) + components = components.clone(); + components[i] = c = mc; + } + } } return appendAll(components); } @@ -381,6 +394,14 @@ public class BytecodeName { * If the bytecode name contains dangerous characters, * assume that they are being used as punctuation, * and pass them through unchanged. + * Non-empty runs of non-dangerous characters are demangled + * if necessary, and the resulting names are quoted if + * they are not already valid Java identifiers, or if + * they contain a dangerous character (i.e., dollar sign "$"). + * Single quotes are used when quoting. + * Within quoted names, embedded single quotes and backslashes + * are further escaped by prepended backslashes. + * * @param s the original bytecode name (which may be qualified) * @return a human-readable presentation */ @@ -389,10 +410,10 @@ public class BytecodeName { for (int i = 0; i < components.length; i++) { if (!(components[i] instanceof String)) continue; - String c = (String) components[i]; - // pretty up the name by demangling it - String sn = toSourceName(c); - if ((Object)sn != c || !isJavaIdent(sn)) { + String sn = (String) components[i]; + // note that the name is already demangled! + //sn = toSourceName(sn); + if (!isJavaIdent(sn) || sn.indexOf('$') >=0 ) { components[i] = quoteDisplay(sn); } } @@ -401,10 +422,10 @@ public class BytecodeName { private static boolean isJavaIdent(String s) { int slen = s.length(); if (slen == 0) return false; - if (!Character.isUnicodeIdentifierStart(s.charAt(0))) + if (!Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i < slen; i++) { - if (!Character.isUnicodeIdentifierPart(s.charAt(0))) + if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; } return true; @@ -602,110 +623,5 @@ public class BytecodeName { return -1; } - // test driver - static void main(String[] av) { - // If verbose is enabled, quietly check everything. - // Otherwise, print the output for the user to check. - boolean verbose = false; - int maxlen = 0; - - while (av.length > 0 && av[0].startsWith("-")) { - String flag = av[0].intern(); - av = java.util.Arrays.copyOfRange(av, 1, av.length); // Java 1.6 or later - if (flag == "-" || flag == "--") break; - else if (flag == "-q") - verbose = false; - else if (flag == "-v") - verbose = true; - else if (flag.startsWith("-l")) - maxlen = Integer.valueOf(flag.substring(2)); - else - throw new Error("Illegal flag argument: "+flag); - } - - if (maxlen == 0) - maxlen = (verbose ? 2 : 4); - if (verbose) System.out.println("Note: maxlen = "+maxlen); - - switch (av.length) { - case 0: av = new String[] { - DANGEROUS_CHARS.substring(0) + - REPLACEMENT_CHARS.substring(0, 1) + - NULL_ESCAPE + "x" - }; // and fall through: - case 1: - char[] cv = av[0].toCharArray(); - av = new String[cv.length]; - int avp = 0; - for (char c : cv) { - String s = String.valueOf(c); - if (c == 'x') s = "foo"; // tradition... - av[avp++] = s; - } - } - if (verbose) - System.out.println("Note: Verbose output mode enabled. Use '-q' to suppress."); - Tester t = new Tester(); - t.maxlen = maxlen; - t.verbose = verbose; - t.tokens = av; - t.test("", 0); - } - - static class Tester { - boolean verbose; - int maxlen; - java.util.Map map = new java.util.HashMap(); - String[] tokens; - - void test(String stringSoFar, int tokensSoFar) { - test(stringSoFar); - if (tokensSoFar <= maxlen) { - for (String token : tokens) { - if (token.length() == 0) continue; // skip empty tokens - if (stringSoFar.indexOf(token) != stringSoFar.lastIndexOf(token)) - continue; // there are already two occs. of this token - if (token.charAt(0) == ESCAPE_C && token.length() == 1 && maxlen < 4) - test(stringSoFar+token, tokensSoFar); // want lots of \'s - else if (tokensSoFar < maxlen) - test(stringSoFar+token, tokensSoFar+1); - } - } - } - - void test(String s) { - // for small batches, do not test the null string - if (s.length() == 0 && maxlen >=1 && maxlen <= 2) return; - String bn = testSourceName(s); - if (bn == null) return; - if (bn == s) { - //if (verbose) System.out.println(s+" == id"); - } else { - if (verbose) System.out.println(s+" => "+bn+" "+toDisplayName(bn)); - String bnbn = testSourceName(bn); - if (bnbn == null) return; - if (verbose) System.out.println(bn+" => "+bnbn+" "+toDisplayName(bnbn)); - /* - String bn3 = testSourceName(bnbn); - if (bn3 == null) return; - if (verbose) System.out.println(bnbn+" => "+bn3); - */ - } - } - - String testSourceName(String s) { - if (map.containsKey(s)) return null; - String bn = toBytecodeName(s); - map.put(s, bn); - String sn = toSourceName(bn); - if (!sn.equals(s)) { - String bad = (s+" => "+bn+" != "+sn); - if (!verbose) throw new Error("Bad mangling: "+bad); - System.out.println("*** "+bad); - return null; - } - return bn; - } - } } diff --git a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java b/jdk/src/share/classes/sun/dyn/util/ValueConversions.java index 817c1c5cc29..9a8bd8fdadd 100644 --- a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java +++ b/jdk/src/share/classes/sun/dyn/util/ValueConversions.java @@ -27,7 +27,10 @@ package sun.dyn.util; import java.dyn.*; import java.dyn.MethodHandles.Lookup; +import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumMap; +import java.util.List; import sun.dyn.Access; import sun.dyn.AdapterMethodHandle; import sun.dyn.MethodHandleImpl; @@ -37,6 +40,7 @@ public class ValueConversions { private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN); private static EnumMap[] newWrapperCaches(int n) { + @SuppressWarnings("unchecked") EnumMap[] caches = (EnumMap[]) new EnumMap[n]; // unchecked warning expected here for (int i = 0; i < n; i++) @@ -114,7 +118,7 @@ public class ValueConversions { } private static MethodType unboxType(Wrapper wrap, boolean raw) { - return MethodType.make(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType()); + return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType()); } private static final EnumMap[] @@ -240,7 +244,7 @@ public class ValueConversions { private static MethodType boxType(Wrapper wrap, boolean raw) { // be exact, since return casts are hard to compose Class boxType = wrap.wrapperType(); - return MethodType.make(boxType, rawWrapper(wrap, raw).primitiveType()); + return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType()); } private static Wrapper rawWrapper(Wrapper wrap, boolean raw) { @@ -305,29 +309,47 @@ public class ValueConversions { /// Kludges for when raw values get accidentally boxed. + static int unboxRawInteger(Object x) { + if (x instanceof Integer) + return unboxInteger(x); + else + return (int) unboxLong(x); + } + + static Integer reboxRawInteger(Object x) { + if (x instanceof Integer) + return (Integer) x; + else + return (int) unboxLong(x); + } + static Byte reboxRawByte(Object x) { if (x instanceof Byte) return (Byte) x; - return boxByteRaw(unboxInteger(x)); + return boxByteRaw(unboxRawInteger(x)); } static Short reboxRawShort(Object x) { if (x instanceof Short) return (Short) x; - return boxShortRaw(unboxInteger(x)); + return boxShortRaw(unboxRawInteger(x)); } static Boolean reboxRawBoolean(Object x) { if (x instanceof Boolean) return (Boolean) x; - return boxBooleanRaw(unboxInteger(x)); + return boxBooleanRaw(unboxRawInteger(x)); } static Character reboxRawCharacter(Object x) { if (x instanceof Character) return (Character) x; - return boxCharacterRaw(unboxInteger(x)); + return boxCharacterRaw(unboxRawInteger(x)); } static Float reboxRawFloat(Object x) { if (x instanceof Float) return (Float) x; - return boxFloatRaw(unboxInteger(x)); + return boxFloatRaw(unboxRawInteger(x)); + } + + static Long reboxRawLong(Object x) { + return (Long) x; //never a rebox } static Double reboxRawDouble(Object x) { @@ -337,12 +359,21 @@ public class ValueConversions { private static MethodType reboxType(Wrapper wrap) { Class boxType = wrap.wrapperType(); - return MethodType.make(boxType, Object.class); + return MethodType.methodType(boxType, Object.class); } private static final EnumMap[] REBOX_CONVERSIONS = newWrapperCaches(2); + /** + * Becase we normalize primitive types to reduce the number of signatures, + * primitives are sometimes manipulated under an "erased" type, + * either int (for types other than long/double) or long (for all types). + * When the erased primitive value is then boxed into an Integer or Long, + * the final boxed primitive is sometimes required. This transformation + * is called a "rebox". It takes an Integer or Long and produces some + * other boxed value. + */ public static MethodHandle rebox(Wrapper wrap, boolean exact) { EnumMap cache = REBOX_CONVERSIONS[exact?1:0]; MethodHandle mh = cache.get(wrap); @@ -355,9 +386,6 @@ public class ValueConversions { mh = IDENTITY; break; case VOID: throw new IllegalArgumentException("cannot rebox a void"); - case INT: case LONG: - mh = cast(wrap.wrapperType(), exact); - break; } if (mh != null) { cache.put(wrap, mh); @@ -384,13 +412,21 @@ public class ValueConversions { /// Width-changing conversions between int and long. static long widenInt(int x) { - return x; + return (long) x; + } + + static Long widenBoxedInt(Integer x) { + return (long)(int)x; } static int narrowLong(long x) { return (int) x; } + static Integer narrowBoxedLong(Long x) { + return (int)(long) x; + } + /// Constant functions static void ignore(Object x) { @@ -432,7 +468,7 @@ public class ValueConversions { return mh; } // slow path - MethodType type = MethodType.make(wrap.primitiveType()); + MethodType type = MethodType.methodType(wrap.primitiveType()); switch (wrap) { case VOID: mh = EMPTY; @@ -500,11 +536,11 @@ public class ValueConversions { private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY; static { try { - MethodType idType = MethodType.makeGeneric(1); - MethodType castType = idType.insertParameterType(0, Class.class); + MethodType idType = MethodType.genericMethodType(1); + MethodType castType = idType.insertParameterTypes(0, Class.class); MethodType alwaysZeroType = idType.changeReturnType(int.class); MethodType ignoreType = idType.changeReturnType(void.class); - MethodType zeroObjectType = MethodType.makeGeneric(0); + MethodType zeroObjectType = MethodType.genericMethodType(0); IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType); //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType); @@ -512,7 +548,7 @@ public class ValueConversions { ALWAYS_ZERO = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysZero", alwaysZeroType); ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType); IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType); - EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterType(0)); + EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1)); } catch (RuntimeException ex) { throw ex; } @@ -543,10 +579,10 @@ public class ValueConversions { else if (VerifyType.isNullType(type)) mh = ALWAYS_NULL; else - mh = MethodHandles.insertArgument(CAST_REFERENCE, 0, type); + mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type); if (exact) { - MethodType xmt = MethodType.make(type, Object.class); - mh = AdapterMethodHandle.makeRawRetypeOnly(IMPL_TOKEN, xmt, mh); + MethodType xmt = MethodType.methodType(type, Object.class); + mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh); } if (cache != null) cache.put(wrap, mh); @@ -560,4 +596,127 @@ public class ValueConversions { private static MethodHandle retype(MethodType type, MethodHandle mh) { return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh); } + + private static final Object[] NO_ARGS_ARRAY = {}; + private static Object[] makeArray(Object... args) { return args; } + private static Object[] array() { return NO_ARGS_ARRAY; } + private static Object[] array(Object a0) + { return makeArray(a0); } + private static Object[] array(Object a0, Object a1) + { return makeArray(a0, a1); } + private static Object[] array(Object a0, Object a1, Object a2) + { return makeArray(a0, a1, a2); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3) + { return makeArray(a0, a1, a2, a3); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4) + { return makeArray(a0, a1, a2, a3, a4); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { return makeArray(a0, a1, a2, a3, a4, a5); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { return makeArray(a0, a1, a2, a3, a4, a5, a6); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + static MethodHandle[] makeArrays() { + ArrayList arrays = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = arrays.size(); + MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); + String name = "array"; + MethodHandle array = null; + try { + array = lookup.findStatic(ValueConversions.class, name, type); + } catch (NoAccessException ex) { + } + if (array == null) break; + arrays.add(array); + } + assert(arrays.size() == 11); // current number of methods + return arrays.toArray(new MethodHandle[0]); + } + static final MethodHandle[] ARRAYS = makeArrays(); + + /** Return a method handle that takes the indicated number of Object + * arguments and returns an Object array of them, as if for varargs. + */ + public static MethodHandle varargsArray(int nargs) { + if (nargs < ARRAYS.length) + return ARRAYS[nargs]; + // else need to spin bytecode or do something else fancy + throw new UnsupportedOperationException("NYI"); + } + + private static final List NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); + private static List makeList(Object... args) { return Arrays.asList(args); } + private static List list() { return NO_ARGS_LIST; } + private static List list(Object a0) + { return makeList(a0); } + private static List list(Object a0, Object a1) + { return makeList(a0, a1); } + private static List list(Object a0, Object a1, Object a2) + { return makeList(a0, a1, a2); } + private static List list(Object a0, Object a1, Object a2, Object a3) + { return makeList(a0, a1, a2, a3); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4) + { return makeList(a0, a1, a2, a3, a4); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { return makeList(a0, a1, a2, a3, a4, a5); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { return makeList(a0, a1, a2, a3, a4, a5, a6); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + static MethodHandle[] makeLists() { + ArrayList arrays = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = arrays.size(); + MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); + String name = "list"; + MethodHandle array = null; + try { + array = lookup.findStatic(ValueConversions.class, name, type); + } catch (NoAccessException ex) { + } + if (array == null) break; + arrays.add(array); + } + assert(arrays.size() == 11); // current number of methods + return arrays.toArray(new MethodHandle[0]); + } + static final MethodHandle[] LISTS = makeLists(); + + /** Return a method handle that takes the indicated number of Object + * arguments and returns List. + */ + public static MethodHandle varargsList(int nargs) { + if (nargs < LISTS.length) + return LISTS[nargs]; + // else need to spin bytecode or do something else fancy + throw new UnsupportedOperationException("NYI"); + } } + diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java b/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java index 8bee85017ba..aec90d54e6c 100644 --- a/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java +++ b/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java @@ -26,8 +26,12 @@ package sun.dyn.util; import java.dyn.LinkagePermission; +import java.dyn.MethodHandles.Lookup; +import java.dyn.NoAccessException; import java.lang.reflect.Modifier; -import sun.dyn.Access; +import sun.dyn.MemberName; +import sun.dyn.MethodHandleImpl; +import sun.dyn.empty.Empty; /** * This class centralizes information about the JVM's linkage access control. @@ -45,21 +49,21 @@ public class VerifyAccess { *

    * Some circumstances require an additional check on the * leading parameter (the receiver) of the method, if it is non-static. - * In the case of {@code invokespecial} ({@code doDispatch} is false), + * In the case of {@code invokespecial} ({@code isSpecialInvoke} is true), * the leading parameter must be the accessing class or a subclass. * In the case of a call to a {@code protected} method outside the same * package, the same constraint applies. * @param m the proposed callee - * @param doDispatch if false, a non-static m will be invoked as if by {@code invokespecial} + * @param isSpecialInvoke if true, a non-static method m is checked as if for {@code invokespecial} * @param lookupClass the class for which the access check is being made * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class} */ public static Class isAccessible(Class defc, int mods, - boolean doDispatch, Class lookupClass) { + Class lookupClass, boolean isSpecialInvoke) { if (!isAccessible(defc, lookupClass)) return null; Class constraint = Object.class; - if (!doDispatch && !Modifier.isStatic(mods)) { + if (isSpecialInvoke && !Modifier.isStatic(mods)) { constraint = lookupClass; } if (Modifier.isPublic(mods)) @@ -166,4 +170,38 @@ public class VerifyAccess { if (isSamePackage(requestingClass, subjectClass)) return; security.checkPermission(new LinkagePermission(permissionName, requestingClass)); } + + private static RuntimeException checkNameFailed(MemberName self, Lookup lookup, String comment) { + return new NoAccessException("cannot access from "+lookup+": "+self.toString()+": "+comment); + } + public static void checkName(MemberName self, Lookup lookup) { + Class lc = lookup.lookupClass(); + if (lc == null) return; // lookup is privileged + Class dc = self.getDeclaringClass(); + int samepkg = 0; + // First check the containing class. Must be public or local. + if (!Modifier.isPublic(dc.getModifiers())) { + if (lc != Empty.class) + samepkg = (isSamePackage(dc, lc) ? 1 : -1); + if (samepkg <= 0) + throw checkNameFailed(self, lookup, "class is not public"); + } + // At this point dc is known to be accessible. + if (self.isPublic()) { + return; + } else if (lc == Empty.class) { + throw checkNameFailed(self, lookup, "member is not public"); + } else if (self.isProtected()) { + if (dc.isAssignableFrom(lc)) return; + } else if (self.isPrivate()) { + if (isSamePackageMember(dc, lc)) return; + throw checkNameFailed(self, lookup, "member is private"); + } + // Fall-through handles the package-private and protected cases. + if (samepkg == 0) + samepkg = (isSamePackage(dc, lc) ? 1 : -1); + if (samepkg > 0) return; + throw checkNameFailed(self, lookup, + self.isProtected() ? "member is protected" : "member is private to package"); + } } diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyType.java b/jdk/src/share/classes/sun/dyn/util/VerifyType.java index 9d12c74afa9..14b0827c00e 100644 --- a/jdk/src/share/classes/sun/dyn/util/VerifyType.java +++ b/jdk/src/share/classes/sun/dyn/util/VerifyType.java @@ -26,6 +26,7 @@ package sun.dyn.util; import java.dyn.MethodType; +import sun.dyn.empty.Empty; /** * This class centralizes information about the JVM verifier @@ -73,29 +74,28 @@ public class VerifyType { } /** - * Is the given type either java.lang.Void or java.lang.Null? - * These types serve as markers for bare nulls and therefore - * may be promoted to any type. This is secure, since + * Is the given type java.lang.Null or an equivalent null-only type? */ public static boolean isNullType(Class type) { if (type == null) return false; - return type == NULL_CLASS_1 || type == NULL_CLASS_2; + return type == NULL_CLASS + // This one may also be used as a null type. + // TO DO: Decide if we really want to legitimize it here. + // Probably we do, unless java.lang.Null really makes it into Java 7 + //|| type == Void.class + // Locally known null-only class: + || type == Empty.class + ; } - private static final Class NULL_CLASS_1, NULL_CLASS_2; + private static final Class NULL_CLASS; static { - Class nullClass1 = null, nullClass2 = null; + Class nullClass = null; try { - nullClass1 = Class.forName("java.lang.Null"); + nullClass = Class.forName("java.lang.Null"); } catch (ClassNotFoundException ex) { // OK, we'll cope } - NULL_CLASS_1 = nullClass1; - - // This one may also be used as a null type. - // TO DO: Decide if we really want to legitimize it here. - // Probably we do, unless java.lang.Null really makes it into Java 7 - nullClass2 = Void.class; - NULL_CLASS_2 = nullClass2; + NULL_CLASS = nullClass; } /** @@ -191,6 +191,11 @@ public class VerifyType { // to be captured as a garbage int. // Caller promises that the actual value will be disregarded. return dst == int.class ? 1 : 0; + if (isNullType(src)) + // Special permission for raw conversions: allow a null + // to be reinterpreted as anything. For objects, it is safe, + // and for primitives you get a garbage value (probably zero). + return 1; if (!src.isPrimitive()) return 0; Wrapper sw = Wrapper.forPrimitiveType(src); diff --git a/jdk/src/share/classes/sun/dyn/util/Wrapper.java b/jdk/src/share/classes/sun/dyn/util/Wrapper.java index 556fda3bc7b..84747080de7 100644 --- a/jdk/src/share/classes/sun/dyn/util/Wrapper.java +++ b/jdk/src/share/classes/sun/dyn/util/Wrapper.java @@ -141,13 +141,19 @@ public enum Wrapper { * @throws IllegalArgumentException for unexpected types */ public static Wrapper forPrimitiveType(Class type) { + Wrapper w = findPrimitiveType(type); + if (w != null) return w; + if (type.isPrimitive()) + throw new InternalError(); // redo hash function + throw newIllegalArgumentException("not primitive: "+type); + } + + static Wrapper findPrimitiveType(Class type) { Wrapper w = FROM_PRIM[hashPrim(type)]; if (w != null && w.primitiveType == type) { return w; } - if (type.isPrimitive()) - throw new InternalError(); // redo hash function - throw newIllegalArgumentException("not primitive: "+type); + return null; } /** Return the wrapper that wraps values into the given wrapper type. @@ -160,7 +166,7 @@ public enum Wrapper { Wrapper w = findWrapperType(type); if (w != null) return w; for (Wrapper x : values()) - if (w.wrapperType == type) + if (x.wrapperType == type) throw new InternalError(); // redo hash function throw newIllegalArgumentException("not wrapper: "+type); } @@ -244,8 +250,10 @@ public enum Wrapper { public Class wrapperType() { return wrapperType; } /** What is the wrapper type for this wrapper? - * The example type must be the wrapper type, + * Otherwise, the example type must be the wrapper type, * or the corresponding primitive type. + * (For {@code OBJECT}, the example type can be any non-primitive, + * and is normalized to {@code Object.class}.) * The resulting class type has the same type parameter. */ public Class wrapperType(Class exampleType) { @@ -290,6 +298,16 @@ public enum Wrapper { return type.isPrimitive(); } + /** What is the bytecode signature character for this type? + * All non-primitives, including array types, report as 'L', the signature character for references. + */ + public static char basicTypeChar(Class type) { + if (!type.isPrimitive()) + return 'L'; + else + return forPrimitiveType(type).basicTypeChar(); + } + /** What is the bytecode signature character for this wrapper's * primitive type? */ @@ -309,7 +327,7 @@ public enum Wrapper { /** Cast a wrapped value to the given type, which may be either a primitive or wrapper type. * Performs standard primitive conversions, including truncation and float conversions. * The given type must be compatible with this wrapper. That is, it must either - * be the wrapper type (or a subtype, in the case of {@code OBJECT} or else + * be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else * it must be the wrapper's primitive type. * @throws ClassCastException if the given type is not compatible with this wrapper */ @@ -326,9 +344,17 @@ public enum Wrapper { * If the target type is a primitive, change it to a wrapper. */ static Class forceType(Class type, Class exampleType) { + boolean z = (type == exampleType || + type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) || + exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) || + type == Object.class && !exampleType.isPrimitive()); + if (!z) + System.out.println(type+" <= "+exampleType); assert(type == exampleType || - type == asWrapperType(exampleType) || - type == Object.class && exampleType.isInterface()); + type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) || + exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) || + type == Object.class && !exampleType.isPrimitive()); + @SuppressWarnings("unchecked") Class result = (Class) type; // unchecked warning is expected here return result; } diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractPath.java b/jdk/src/share/classes/sun/nio/fs/AbstractPath.java index 71204bd0a2e..e81e3eb1f98 100644 --- a/jdk/src/share/classes/sun/nio/fs/AbstractPath.java +++ b/jdk/src/share/classes/sun/nio/fs/AbstractPath.java @@ -256,8 +256,8 @@ abstract class AbstractPath extends Path { } if (option == null) throw new NullPointerException(); - throw new IllegalArgumentException("'" + option + - "' is not a valid copy option"); + throw new UnsupportedOperationException("'" + option + + "' is not a recognized copy option"); } return result; } @@ -279,9 +279,21 @@ abstract class AbstractPath extends Path { if (attrs.isSymbolicLink()) throw new IOException("Copying of symbolic links not supported"); - // delete target file - if (opts.replaceExisting) - target.deleteIfExists(); + // check if target exists + boolean exists; + if (opts.replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + // let exception translate to FileAlreadyExistsException (6895012) + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) + throw new FileAlreadyExistsException(target.toString()); // create directory or file if (attrs.isDirectory()) { @@ -318,7 +330,7 @@ abstract class AbstractPath extends Path { ReadableByteChannel rbc = newByteChannel(); try { // open target file for writing - SeekableByteChannel sbc = target.newByteChannel(CREATE, WRITE); + SeekableByteChannel sbc = target.newByteChannel(CREATE_NEW, WRITE); // simple copy loop try { diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java index 8e33f81ed84..b00c71d37cd 100644 --- a/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java +++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java @@ -88,26 +88,24 @@ abstract class AbstractWatchKey extends WatchKey { 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; + if (size > 0) { + // if the previous event is an OVERFLOW event or this is a + // repeated event then we simply increment the counter + WatchEvent prev = events.get(size-1); + if ((prev.kind() == StandardWatchEventKind.OVERFLOW) || + ((kind == prev.kind() && + Objects.equals(context, prev.context())))) + { + ((Event)prev).increment(); + return; } - // 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; - } + // if the list has reached the limit then drop pending events + // and queue an OVERFLOW event + if (size >= MAX_EVENT_LIST_SIZE) { + events.clear(); + kind = StandardWatchEventKind.OVERFLOW; + context = null; } } diff --git a/jdk/src/share/classes/sun/security/jgss/GSSManagerImpl.java b/jdk/src/share/classes/sun/security/jgss/GSSManagerImpl.java index eeb23fc940a..5a8143e30f0 100644 --- a/jdk/src/share/classes/sun/security/jgss/GSSManagerImpl.java +++ b/jdk/src/share/classes/sun/security/jgss/GSSManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,11 @@ public class GSSManagerImpl extends GSSManager { Oid[] retVal = new Oid[mechs.length]; int pos = 0; + // Compatibility with RFC 2853 old NT_HOSTBASED_SERVICE value. + if (nameType.equals(GSSNameImpl.oldHostbasedServiceName)) { + nameType = GSSName.NT_HOSTBASED_SERVICE; + } + // Iterate thru all mechs in GSS for (int i = 0; i < mechs.length; i++) { // what nametypes does this mech support? diff --git a/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java b/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java index c1834d81dbb..1e47fdfa33e 100644 --- a/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java +++ b/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,29 @@ import sun.security.util.DerOutputStream; public class GSSNameImpl implements GSSName { + /** + * The old Oid used in RFC 2853. Now supported as + * input parameters in: + * + * 1. The four overloaded GSSManager.createName(*) methods + * 2. GSSManager.getMechsForName(Oid) + * + * Note that even if a GSSName is created with this old Oid, + * its internal name type and getStringNameType() output are + * always the new value. + */ + final static Oid oldHostbasedServiceName; + + static { + Oid tmp = null; + try { + tmp = new Oid("1.3.6.1.5.6.2"); + } catch (Exception e) { + // should never happen + } + oldHostbasedServiceName = tmp; + } + private GSSManagerImpl gssManager = null; /* @@ -134,6 +157,9 @@ public class GSSNameImpl implements GSSName { Oid mech) throws GSSException { + if (oldHostbasedServiceName.equals(appNameType)) { + appNameType = GSSName.NT_HOSTBASED_SERVICE; + } if (appName == null) throw new GSSExceptionImpl(GSSException.BAD_NAME, "Cannot import null name"); diff --git a/jdk/src/share/classes/sun/security/jgss/GSSUtil.java b/jdk/src/share/classes/sun/security/jgss/GSSUtil.java index a59bf5dfab2..c2c87b5096d 100644 --- a/jdk/src/share/classes/sun/security/jgss/GSSUtil.java +++ b/jdk/src/share/classes/sun/security/jgss/GSSUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,9 +66,6 @@ public class GSSUtil { public static final Oid NT_GSS_KRB5_PRINCIPAL = GSSUtil.createOid("1.2.840.113554.1.2.2.1"); - public static final Oid NT_HOSTBASED_SERVICE2 = - GSSUtil.createOid("1.2.840.113554.1.2.1.4"); - private static final String DEFAULT_HANDLER = "auth.login.defaultCallbackHandler"; diff --git a/jdk/src/share/classes/sun/security/jgss/wrapper/GSSNameElement.java b/jdk/src/share/classes/sun/security/jgss/wrapper/GSSNameElement.java index d96a47b522d..2bab4bc8cc5 100644 --- a/jdk/src/share/classes/sun/security/jgss/wrapper/GSSNameElement.java +++ b/jdk/src/share/classes/sun/security/jgss/wrapper/GSSNameElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,8 +55,7 @@ public class GSSNameElement implements GSSNameSpi { static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement(); private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) { - if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType) || - GSSName.NT_HOSTBASED_SERVICE.equals(nameType)) { + if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) { Oid[] supportedNTs = null; try { supportedNTs = stub.inquireNamesForMech(); @@ -83,15 +82,9 @@ public class GSSNameElement implements GSSNameSpi { if (supportedNTs[i].equals(nameType)) return nameType; } // Special handling the specified name type - if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) { - SunNativeProvider.debug("Override " + nameType + - " with mechanism default(null)"); - return null; // Use mechanism specific default - } else { - SunNativeProvider.debug("Override " + nameType + - " with " + GSSUtil.NT_HOSTBASED_SERVICE2); - return GSSUtil.NT_HOSTBASED_SERVICE2; - } + SunNativeProvider.debug("Override " + nameType + + " with mechanism default(null)"); + return null; // Use mechanism specific default } } return nameType; diff --git a/jdk/src/share/classes/sun/security/krb5/Config.java b/jdk/src/share/classes/sun/security/krb5/Config.java index 283e0d28cbf..3cc209c9f21 100644 --- a/jdk/src/share/classes/sun/security/krb5/Config.java +++ b/jdk/src/share/classes/sun/security/krb5/Config.java @@ -109,6 +109,7 @@ public class Config { public static synchronized void refresh() throws KrbException { singleton = new Config(); KeyTab.refresh(); + KrbKdcReq.KdcAccessibility.reset(); } diff --git a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java index adf2cd8ace1..15d6d78c04d 100644 --- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java +++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java @@ -511,6 +511,23 @@ public class EncryptionKey return findKey(etype, null, keys); } + /** + * Determines if a kvno matches another kvno. Used in the method + * findKey(type, kvno, keys). Always returns true if either input + * is null or zero, in case any side does not have kvno info available. + * + * Note: zero is included because N/A is not a legal value for kvno + * in javax.security.auth.kerberos.KerberosKey. Therefore, the info + * that the kvno is N/A might be lost when converting between this + * class and KerberosKey. + */ + private static boolean versionMatches(Integer v1, Integer v2) { + if (v1 == null || v1 == 0 || v2 == null || v2 == 0) { + return true; + } + return v1.equals(v2); + } + /** * Find a key with given etype and kvno * @param kvno if null, return any (first?) key @@ -525,15 +542,20 @@ public class EncryptionKey } int ktype; + boolean etypeFound = false; for (int i = 0; i < keys.length; i++) { ktype = keys[i].getEType(); if (EType.isSupported(ktype)) { Integer kv = keys[i].getKeyVersionNumber(); - if (etype == ktype && (kvno == null || kvno.equals(kv))) { - return keys[i]; + if (etype == ktype) { + etypeFound = true; + if (versionMatches(kvno, kv)) { + return keys[i]; + } } } } + // Key not found. // allow DES key to be used for the DES etypes if ((etype == EncryptedData.ETYPE_DES_CBC_CRC || @@ -543,12 +565,16 @@ public class EncryptionKey if (ktype == EncryptedData.ETYPE_DES_CBC_CRC || ktype == EncryptedData.ETYPE_DES_CBC_MD5) { Integer kv = keys[i].getKeyVersionNumber(); - if (kvno == null || kvno.equals(kv)) { + etypeFound = true; + if (versionMatches(kvno, kv)) { return new EncryptionKey(etype, keys[i].getBytes()); } } } } + if (etypeFound) { + throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER); + } return null; } } diff --git a/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java b/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java index b915ff99711..389fd04be4e 100644 --- a/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java +++ b/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java @@ -31,25 +31,26 @@ package sun.security.krb5; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; +import java.util.Locale; import sun.security.krb5.internal.Krb5; import sun.security.krb5.internal.UDPClient; import sun.security.krb5.internal.TCPClient; import java.io.IOException; -import java.io.InterruptedIOException; import java.net.SocketTimeoutException; -import java.net.UnknownHostException; import java.util.StringTokenizer; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.HashSet; public abstract class KrbKdcReq { - /** - * Default port for a KDC. - */ - private static final int DEFAULT_KDC_PORT = Krb5.KDC_INET_DEFAULT_PORT; - // Currently there is no option to specify retries // in the kerberos configuration file @@ -66,7 +67,48 @@ public abstract class KrbKdcReq { private static int udpPrefLimit = -1; + private static final String BAD_POLICY_KEY = "krb5.kdc.bad.policy"; + + /** + * What to do when a KDC is unavailable, specified in the + * java.security file with key krb5.kdc.bad.policy. + * Possible values can be TRY_LAST or TRY_LESS + */ + private enum BpType { + NONE, TRY_LAST, TRY_LESS + } + private static int tryLessMaxRetries = 1; + private static int tryLessTimeout = 5000; + + private static final BpType badPolicy; + static { + String value = AccessController.doPrivileged( + new PrivilegedAction() { + public String run() { + return Security.getProperty(BAD_POLICY_KEY); + } + }); + if (value != null) { + value = value.toLowerCase(Locale.ENGLISH); + String[] ss = value.split(":"); + if ("tryless".equals(ss[0])) { + if (ss.length > 1) { + String[] params = ss[1].split(","); + tryLessMaxRetries = Integer.parseInt(params[0]); + if (params.length > 1) { + tryLessTimeout = Integer.parseInt(params[1]); + } + } + badPolicy = BpType.TRY_LESS; + } else if ("trylast".equals(ss[0])) { + badPolicy = BpType.TRY_LAST; + } else { + badPolicy = BpType.NONE; + } + } else { + badPolicy = BpType.NONE; + } /* * Get default timeout. @@ -131,22 +173,16 @@ public abstract class KrbKdcReq { } } - /* - * Get timeout. - */ - - int timeout = getKdcTimeout(realm); - String kdcList = cfg.getKDCList(realm); if (kdcList == null) { throw new KrbException("Cannot get kdc for realm " + realm); } String tempKdc = null; // may include the port number also - StringTokenizer st = new StringTokenizer(kdcList); - while (st.hasMoreTokens()) { - tempKdc = st.nextToken(); + for (String tmp: KdcAccessibility.list(kdcList)) { + tempKdc = tmp; try { send(realm,tempKdc,useTCP); + KdcAccessibility.removeBad(tempKdc); break; } catch (Exception e) { if (DEBUG) { @@ -154,6 +190,7 @@ public abstract class KrbKdcReq { tempKdc); e.printStackTrace(System.out); } + KdcAccessibility.addBad(tempKdc); savedException = e; } } @@ -174,16 +211,21 @@ public abstract class KrbKdcReq { if (obuf == null) return; - PrivilegedActionException savedException = null; - int port = Krb5.KDC_INET_DEFAULT_PORT; - /* - * Get timeout. - */ + int port = Krb5.KDC_INET_DEFAULT_PORT; + int retries = DEFAULT_KDC_RETRY_LIMIT; int timeout = getKdcTimeout(realm); - /* - * Get port number for this KDC. - */ + + if (badPolicy == BpType.TRY_LESS && + KdcAccessibility.isBad(tempKdc)) { + if (retries > tryLessMaxRetries) { + retries = tryLessMaxRetries; // less retries + } + if (timeout > tryLessTimeout) { + timeout = tryLessTimeout; // less time + } + } + String kdc = null; String portStr = null; @@ -225,12 +267,12 @@ public abstract class KrbKdcReq { + port + ", timeout=" + timeout + ", number of retries =" - + DEFAULT_KDC_RETRY_LIMIT + + retries + ", #bytes=" + obuf.length); } KdcCommunication kdcCommunication = - new KdcCommunication(kdc, port, useTCP, timeout, obuf); + new KdcCommunication(kdc, port, useTCP, timeout, retries, obuf); try { ibuf = AccessController.doPrivileged(kdcCommunication); if (DEBUG) { @@ -258,14 +300,16 @@ public abstract class KrbKdcReq { private int port; private boolean useTCP; private int timeout; + private int retries; private byte[] obuf; public KdcCommunication(String kdc, int port, boolean useTCP, - int timeout, byte[] obuf) { + int timeout, int retries, byte[] obuf) { this.kdc = kdc; this.port = port; this.useTCP = useTCP; this.timeout = timeout; + this.retries = retries; this.obuf = obuf; } @@ -294,7 +338,7 @@ public abstract class KrbKdcReq { } else { // For each KDC we try DEFAULT_KDC_RETRY_LIMIT (3) times to // get the response - for (int i=1; i <= DEFAULT_KDC_RETRY_LIMIT; i++) { + for (int i=1; i <= retries; i++) { UDPClient kdcClient = new UDPClient(kdc, port, timeout); if (DEBUG) { @@ -310,7 +354,7 @@ public abstract class KrbKdcReq { * Send the data to the kdc. */ - kdcClient.send(obuf); + kdcClient.send(obuf); /* * And get a response. @@ -323,7 +367,7 @@ public abstract class KrbKdcReq { System.out.println ("SocketTimeOutException with " + "attempt: " + i); } - if (i == DEFAULT_KDC_RETRY_LIMIT) { + if (i == retries) { ibuf = null; throw se; } @@ -385,4 +429,67 @@ public abstract class KrbKdcReq { return -1; } + + /** + * Maintains a KDC accessible list. Unavailable KDCs are put into a + * blacklist, when a KDC in the blacklist is available, it's removed + * from there. No insertion order in the blacklist. + * + * There are two methods to deal with KDCs in the blacklist. 1. Only try + * them when there's no KDC not on the blacklist. 2. Still try them, but + * with lesser number of retries and smaller timeout value. + */ + static class KdcAccessibility { + // Known bad KDCs + private static Set bads = new HashSet(); + + private static synchronized void addBad(String kdc) { + if (DEBUG) { + System.out.println(">>> KdcAccessibility: add " + kdc); + } + bads.add(kdc); + } + + private static synchronized void removeBad(String kdc) { + if (DEBUG) { + System.out.println(">>> KdcAccessibility: remove " + kdc); + } + bads.remove(kdc); + } + + private static synchronized boolean isBad(String kdc) { + return bads.contains(kdc); + } + + public static synchronized void reset() { + if (DEBUG) { + System.out.println(">>> KdcAccessibility: reset"); + } + bads.clear(); + } + + // Returns a preferred KDC list by putting the bad ones at the end + private static synchronized String[] list(String kdcList) { + StringTokenizer st = new StringTokenizer(kdcList); + List list = new ArrayList(); + if (badPolicy == BpType.TRY_LAST) { + List badkdcs = new ArrayList(); + while (st.hasMoreTokens()) { + String t = st.nextToken(); + if (bads.contains(t)) badkdcs.add(t); + else list.add(t); + } + // Bad KDCs are put at last + list.addAll(badkdcs); + } else { + // All KDCs are returned in their original order, + // This include TRY_LESS and NONE + while (st.hasMoreTokens()) { + list.add(st.nextToken()); + } + } + return list.toArray(new String[list.size()]); + } + } } + diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTabEntry.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTabEntry.java index 3eb08b5df43..49c99fcb9d3 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTabEntry.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTabEntry.java @@ -75,7 +75,7 @@ public class KeyTabEntry implements KeyTabConstants { public String getKeyString() { StringBuffer sb = new StringBuffer("0x"); for (int i = 0; i < keyblock.length; i++) { - sb.append(Integer.toHexString(keyblock[i]&0xff)); + sb.append(String.format("%02x", keyblock[i]&0xff)); } return sb.toString(); } 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 e7b148fbc7c..c80888f9c1e 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -574,10 +574,18 @@ public final class OCSPResponse { (singleExtDer.length); for (int i = 0; i < singleExtDer.length; i++) { Extension ext = new Extension(singleExtDer[i]); - singleExtensions.put(ext.getId(), ext); if (DEBUG != null) { DEBUG.println("OCSP single extension: " + ext); } + // We don't support any extensions yet. Therefore, if it + // is critical we must throw an exception because we + // don't know how to process it. + if (ext.isCritical()) { + throw new IOException( + "Unsupported OCSP critical extension: " + + ext.getExtensionId()); + } + singleExtensions.put(ext.getId(), ext); } } else { singleExtensions = Collections.emptyMap(); diff --git a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java index d0f95758c49..28af066e260 100644 --- a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. * 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,11 +50,12 @@ import sun.security.krb5.internal.EncTicketPart; import sun.security.krb5.internal.crypto.KeyUsage; import sun.security.jgss.krb5.Krb5Util; +import sun.security.krb5.KrbException; +import sun.security.krb5.internal.Krb5; import sun.security.ssl.Debug; import sun.security.ssl.HandshakeInStream; import sun.security.ssl.HandshakeOutStream; -import sun.security.ssl.KerberosClientKeyExchange; import sun.security.ssl.ProtocolVersion; /** @@ -188,7 +189,14 @@ public final class KerberosClientKeyExchangeImpl // See if we have the right key to decrypt the ticket to get // the session key. int encPartKeyType = encPart.getEType(); - KerberosKey dkey = findKey(encPartKeyType, serverKeys); + Integer encPartKeyVersion = encPart.getKeyVersionNumber(); + KerberosKey dkey = null; + try { + dkey = findKey(encPartKeyType, encPartKeyVersion, serverKeys); + } catch (KrbException ke) { // a kvno mismatch + throw new IOException( + "Cannot find key matching version number", ke); + } if (dkey == null) { // %%% Should print string repr of etype throw new IOException( @@ -355,12 +363,34 @@ public final class KerberosClientKeyExchangeImpl return localPrincipal; } - private static KerberosKey findKey(int etype, KerberosKey[] keys) { + /** + * Determines if a kvno matches another kvno. Used in the method + * findKey(etype, version, keys). Always returns true if either input + * is null or zero, in case any side does not have kvno info available. + * + * Note: zero is included because N/A is not a legal value for kvno + * in javax.security.auth.kerberos.KerberosKey. Therefore, the info + * that the kvno is N/A might be lost when converting between + * EncryptionKey and KerberosKey. + */ + private static boolean versionMatches(Integer v1, int v2) { + if (v1 == null || v1 == 0 || v2 == 0) { + return true; + } + return v1.equals(v2); + } + + private static KerberosKey findKey(int etype, Integer version, + KerberosKey[] keys) throws KrbException { int ktype; + boolean etypeFound = false; for (int i = 0; i < keys.length; i++) { ktype = keys[i].getKeyType(); if (etype == ktype) { - return keys[i]; + etypeFound = true; + if (versionMatches(version, keys[i].getVersionNumber())) { + return keys[i]; + } } } // Key not found. @@ -370,14 +400,20 @@ public final class KerberosClientKeyExchangeImpl for (int i = 0; i < keys.length; i++) { ktype = keys[i].getKeyType(); if (ktype == EncryptedData.ETYPE_DES_CBC_CRC || - ktype == EncryptedData.ETYPE_DES_CBC_MD5) { - return new KerberosKey(keys[i].getPrincipal(), - keys[i].getEncoded(), - etype, - keys[i].getVersionNumber()); + ktype == EncryptedData.ETYPE_DES_CBC_MD5) { + etypeFound = true; + if (versionMatches(version, keys[i].getVersionNumber())) { + return new KerberosKey(keys[i].getPrincipal(), + keys[i].getEncoded(), + etype, + keys[i].getVersionNumber()); + } } } } + if (etypeFound) { + throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER); + } return null; } } diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_be.java b/jdk/src/share/classes/sun/text/resources/FormatData_be.java index 27b02622b20..6912fe9e23b 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_be.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_be.java @@ -63,7 +63,7 @@ public class FormatData_be extends ListResourceBundle { "\u0436\u043d\u0456\u045e\u043d\u044f", // august "\u0432\u0435\u0440\u0430\u0441\u043d\u044f", // september "\u043a\u0430\u0441\u0442\u0440\u044b\u0447\u043d\u0456\u043a\u0430", // october - "\u043b\u0438\u0441\u0442\u0430\u043f\u0430\u0434\u0430", // november + "\u043b\u0456\u0441\u0442\u0430\u043f\u0430\u0434\u0430", // november "\u0441\u043d\u0435\u0436\u043d\u044f", // december "" // month 13 if applicable } @@ -80,7 +80,7 @@ public class FormatData_be extends ListResourceBundle { "\u0436\u043d\u0432", // abb august "\u0432\u0440\u0441", // abb september "\u043a\u0441\u0442", // abb october - "\u043b\u0441\u0442", // abb november + "\u043b\u0456\u0441", // abb november "\u0441\u043d\u0436", // abb december "" // abb month 13 if applicable } diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_de.java b/jdk/src/share/classes/sun/text/resources/FormatData_de.java index 028c17344fe..745216aedad 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_de.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_de.java @@ -130,7 +130,7 @@ public class FormatData_de extends ListResourceBundle { }, { "DateTimePatterns", new String[] { - "H.mm' Uhr 'z", // full time pattern + "HH:mm' Uhr 'z", // full time pattern "HH:mm:ss z", // long time pattern "HH:mm:ss", // medium time pattern "HH:mm", // short time pattern diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_et.java b/jdk/src/share/classes/sun/text/resources/FormatData_et.java index 9413c3da6c6..bc699f75a75 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_et.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_et.java @@ -50,35 +50,35 @@ public class FormatData_et extends ListResourceBundle { return new Object[][] { { "MonthNames", new String[] { - "Jaanuar", // january - "Veebruar", // february - "M\u00e4rts", // march - "Aprill", // april - "Mai", // may - "Juuni", // june - "Juuli", // july - "August", // august - "September", // september - "Oktoober", // october - "November", // november - "Detsember", // december + "jaanuar", // january + "veebruar", // february + "m\u00e4rts", // march + "aprill", // april + "mai", // may + "juuni", // june + "juuli", // july + "august", // august + "september", // september + "oktoober", // october + "november", // november + "detsember", // december "" // month 13 if applicable } }, { "MonthAbbreviations", new String[] { - "Jaan", // abb january - "Veebr", // abb february - "M\u00e4rts", // abb march - "Apr", // abb april - "Mai", // abb may - "Juuni", // abb june - "Juuli", // abb july - "Aug", // abb august - "Sept", // abb september - "Okt", // abb october - "Nov", // abb november - "Dets", // abb december + "jaan", // abb january + "veebr", // abb february + "m\u00e4rts", // abb march + "apr", // abb april + "mai", // abb may + "juuni", // abb june + "juuli", // abb july + "aug", // abb august + "sept", // abb september + "okt", // abb october + "nov", // abb november + "dets", // abb december "" // abb month 13 if applicable } }, diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_fi.java b/jdk/src/share/classes/sun/text/resources/FormatData_fi.java index 73956ee588c..bad7e14bbb0 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_fi.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_fi.java @@ -133,6 +133,12 @@ public class FormatData_fi extends ListResourceBundle { } }, { "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" }, + { "AmPmMarkers", + new String[] { + "ap.", // am marker + "ip." // pm marker + } + }, }; } } diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java b/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java index b6d39d332fa..0498f93a006 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java @@ -55,6 +55,19 @@ public class FormatData_hr_HR extends ListResourceBundle { "#,##0%" // percent pattern } }, + { "DateTimePatterns", + new String[] { + "HH:mm:ss z", // full time pattern + "HH:mm:ss z", // long time pattern + "HH:mm:ss", // medium time pattern + "HH:mm", // short time pattern + "yyyy. MMMM dd", // full date pattern + "yyyy. MMMM dd", // long date pattern + "dd.MM.yyyy.", // medium date pattern + "dd.MM.yy.", // short date pattern + "{1} {0}" // date-time pattern + } + } }; } } diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_hu_HU.java b/jdk/src/share/classes/sun/text/resources/FormatData_hu_HU.java index d0e5a182749..1d205068d51 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_hu_HU.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_hu_HU.java @@ -51,7 +51,7 @@ public class FormatData_hu_HU extends ListResourceBundle { { "NumberPatterns", new String[] { "#,##0.###;-#,##0.###", // decimal pattern - "\u00A4#,##0.##;-\u00A4#,##0.##", // currency pattern + "#,##0.## \u00A4;-#,##0.## \u00A4", // currency pattern "#,##0%" // percent pattern } }, diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_lt.java b/jdk/src/share/classes/sun/text/resources/FormatData_lt.java index e3631389b07..55de246ded0 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_lt.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_lt.java @@ -113,7 +113,7 @@ public class FormatData_lt extends ListResourceBundle { { "NumberElements", new String[] { ",", // decimal separator - ".", // group (thousands) separator + "\u00a0", // group (thousands) separator ";", // list separator "%", // percent sign "0", // native 0 digit @@ -133,7 +133,7 @@ public class FormatData_lt extends ListResourceBundle { "HH.mm", // short time pattern "EEEE, yyyy, MMMM d", // full date pattern "EEEE, yyyy, MMMM d", // long date pattern - "yyyy.M.d", // medium date pattern + "yyyy-MM-dd", // medium date pattern "yy.M.d", // short date pattern "{1} {0}" // date-time pattern } diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_ro.java b/jdk/src/share/classes/sun/text/resources/FormatData_ro.java index 6dde8dcaf53..cf6a182bf57 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_ro.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_ro.java @@ -90,7 +90,7 @@ public class FormatData_ro extends ListResourceBundle { "miercuri", // Wednesday "joi", // Thursday "vineri", // Friday - "s\u00eemb\u0103t\u0103" // Saturday + "s\u00e2mb\u0103t\u0103" // Saturday } }, { "DayAbbreviations", diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_uk.java b/jdk/src/share/classes/sun/text/resources/FormatData_uk.java index 90f34237c13..2db4665b796 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData_uk.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData_uk.java @@ -113,7 +113,7 @@ public class FormatData_uk extends ListResourceBundle { { "NumberElements", new String[] { ",", // decimal separator - ".", // group (thousands) separator + "\u00a0", // group (thousands) separator ";", // list separator "%", // percent sign "0", // native 0 digit diff --git a/jdk/src/share/classes/sun/util/resources/CalendarData_ro.properties b/jdk/src/share/classes/sun/util/resources/CalendarData_ro.properties index d6d95b6698e..3b6d6903439 100644 --- a/jdk/src/share/classes/sun/util/resources/CalendarData_ro.properties +++ b/jdk/src/share/classes/sun/util/resources/CalendarData_ro.properties @@ -35,9 +35,5 @@ # This notice and attribution to Taligent may not be removed. # Taligent is a registered trademark of Taligent, Inc. - -# This bundle is empty because the data of the base bundle -# is adequate for this locale. -# The bundle is necessary to prevent the resource -# bundle lookup from falling back to the default -# locale. +firstDayOfWeek=2 +minimalDaysInFirstWeek=1 diff --git a/jdk/src/share/classes/sun/util/resources/CalendarData_sl.properties b/jdk/src/share/classes/sun/util/resources/CalendarData_sl.properties index d6d95b6698e..ea7ad985223 100644 --- a/jdk/src/share/classes/sun/util/resources/CalendarData_sl.properties +++ b/jdk/src/share/classes/sun/util/resources/CalendarData_sl.properties @@ -36,8 +36,4 @@ # Taligent is a registered trademark of Taligent, Inc. -# This bundle is empty because the data of the base bundle -# is adequate for this locale. -# The bundle is necessary to prevent the resource -# bundle lookup from falling back to the default -# locale. +firstDayOfWeek=2 diff --git a/jdk/src/share/classes/sun/util/resources/CurrencyNames_en_CA.properties b/jdk/src/share/classes/sun/util/resources/CurrencyNames_en_CA.properties index 62c976ff100..e902e799d82 100644 --- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_en_CA.properties +++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_en_CA.properties @@ -36,3 +36,4 @@ # Taligent is a registered trademark of Taligent, Inc. CAD=$ +USD=US$ diff --git a/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties b/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties index 4f9c764c5d2..51ed4758556 100644 --- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties +++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties @@ -36,4 +36,4 @@ # Taligent is a registered trademark of Taligent, Inc. TRL=TL -TRY=YTL +TRY=TL diff --git a/jdk/src/share/classes/sun/util/resources/CurrencyNames_uk_UA.properties b/jdk/src/share/classes/sun/util/resources/CurrencyNames_uk_UA.properties index 20ed61b81b7..f83822dd221 100644 --- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_uk_UA.properties +++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_uk_UA.properties @@ -35,4 +35,4 @@ # This notice and attribution to Taligent may not be removed. # Taligent is a registered trademark of Taligent, Inc. -UAH=\u0433\u0440\u0432. +UAH=\u0433\u0440\u043b. diff --git a/jdk/src/share/classes/sun/util/resources/LocaleNames_es.properties b/jdk/src/share/classes/sun/util/resources/LocaleNames_es.properties index 302629c0503..d7cd4eacb66 100644 --- a/jdk/src/share/classes/sun/util/resources/LocaleNames_es.properties +++ b/jdk/src/share/classes/sun/util/resources/LocaleNames_es.properties @@ -38,7 +38,7 @@ # language names # key is ISO 639 language code -aa=afarense +aa=afar ab=abjasio ae=av\u00e9stico af=afrikaans @@ -47,16 +47,16 @@ am=am\u00e1rico an=aragon\u00e9s ar=\u00e1rabe as=asam\u00e9s -av=avaro +av=avar ay=aimara -az=azerbaiyano -ba=bashkiro +az=azer\u00ed +ba=bashkir be=bielorruso bg=b\u00falgaro -bh=bihar\u00ed +bh=bihari bi=bislama bm=bambara -bn=bengal\u00e9s +bn=bengal\u00ed bo=tibetano br=bret\u00f3n bs=bosnio @@ -66,37 +66,37 @@ ch=chamorro co=corso cr=cree cs=checo -cu=glagol\u00edtico +cu=eslavo eclesi\u00e1stico cv=chuvash cy=gal\u00e9s da=dan\u00e9s de=alem\u00e1n dv=divehi -dz=butan\u00e9s +dz=dzongkha ee=ewe el=griego en=ingl\u00e9s eo=esperanto es=espa\u00f1ol et=estonio -eu=vascuence -fa=farsi -ff=fulb\u00e9 +eu=vasco +fa=persa +ff=fula fi=fin\u00e9s -fj=fijiano -fo=faro\u00e9s +fj=fidjiano +fo=fero\u00e9s fr=franc\u00e9s -fy=frisio +fy=fris\u00f3n ga=irland\u00e9s gd=ga\u00e9lico escoc\u00e9s gl=gallego gn=guaran\u00ed -gu=gujarat\u00ed -gv=manx +gu=gujarati +gv=ga\u00e9lico man\u00e9s ha=hausa he=hebreo -hi=hind\u00fa -ho=hiri Motu +hi=hindi +ho=hiri motu hr=croata ht=haitiano hu=h\u00fangaro @@ -104,10 +104,10 @@ hy=armenio hz=herero ia=interlingua id=indonesio -ie=interlingua -ig=ibo -ii=yi de sichuan -ik=inupiak +ie=interlingue +ig=igbo +ii=sichuan yi +ik=inupiaq in=indonesio io=ido is=island\u00e9s @@ -118,20 +118,20 @@ ja=japon\u00e9s ji=y\u00eddish jv=javan\u00e9s ka=georgiano -kg=kikongo -ki=gikuyu -kj=kwanyama -kk=kazajio +kg=kongo +ki=kikuyu +kj=kuanyama +kk=kazajo kl=groenland\u00e9s -km=camboyano -kn=kanada +km=jemer +kn=canar\u00e9s ko=coreano kr=kanuri -ks=cachemir\u00ed -ku=curdo +ks=cachemiro +ku=kurdo kv=komi kw=c\u00f3rnico -ky=kirgu\u00eds +ky=kirghiz la=lat\u00edn lb=luxemburgu\u00e9s lg=ganda @@ -139,7 +139,7 @@ li=limburgu\u00e9s ln=lingala lo=laosiano lt=lituano -lu=tshiluba +lu=luba-katanga lv=let\u00f3n mg=malgache mh=marshal\u00e9s @@ -148,82 +148,82 @@ mk=macedonio ml=malayalam mn=mongol mo=moldavo -mr=m\u00e1rata +mr=marathi ms=malayo mt=malt\u00e9s my=birmano na=nauruano -nb=noruego (bokm\u00e5l) -nd=ndebele (norte) +nb=bokmal noruego +nd=ndebele septentrional ne=nepal\u00ed ng=ndonga nl=neerland\u00e9s -nn=noruego (nynorsk) +nn=nynorsk noruego no=noruego -nr=ndebele (sur) +nr=ndebele meridional nv=navajo ny=nyanja oc=occitano oj=ojibwa om=oromo or=oriya -os=osetio +os=os\u00e9tico pa=punjab\u00ed pi=pali pl=polaco ps=pashto pt=portugu\u00e9s qu=quechua -rm=retorromano -rn=rund\u00ed +rm=retorrom\u00e1nico +rn=kiroundi ro=rumano ru=ruso -rw=ruand\u00e9s +rw=kinyarwanda sa=s\u00e1nscrito sc=sardo -sd=sindino -se=sami del norte +sd=sindhi +se=sami septentrional sg=sango si=cingal\u00e9s sk=eslovaco -sl=eslovenio +sl=esloveno sm=samoano -sn=son\u00e9s +sn=shona so=somal\u00ed sq=alban\u00e9s sr=serbio -ss=suaziland\u00e9s -st=sesot\u00e9s -su=sudan\u00e9s +ss=siswati +st=sesotho +su=sundan\u00e9s sv=sueco -sw=suajili +sw=swahili ta=tamil te=telugu -tg=tajik +tg=tayiko th=tailand\u00e9s -ti=tigri\u00f1es +ti=tigri\u00f1a tk=turcomano tl=tagalo -tn=sechuan\u00e9s -to=tongu\u00e9s +tn=setchwana +to=tongano tr=turco ts=tsonga tt=t\u00e1rtaro -tw=tui -ty=taitiano -ug=uighur -uk=ucranio +tw=twi +ty=tahitiano +ug=uigur +uk=ucraniano ur=urdu -uz=uzbeco +uz=uzbeko ve=venda vi=vietnamita -vo=volapuk +vo=volap\u00fck wa=val\u00f3n wo=uolof xh=xhosa yi=y\u00eddish yo=yoruba -za=chuang +za=zhuang zh=chino zu=zul\u00fa diff --git a/jdk/src/share/classes/sun/util/resources/LocaleNames_fi.properties b/jdk/src/share/classes/sun/util/resources/LocaleNames_fi.properties index a055e55acd8..831b1a9cd7a 100644 --- a/jdk/src/share/classes/sun/util/resources/LocaleNames_fi.properties +++ b/jdk/src/share/classes/sun/util/resources/LocaleNames_fi.properties @@ -49,7 +49,7 @@ el=kreikka en=englanti es=espanja fi=suomi -fr=franska +fr=ranska he=heprea iw=heprea hi=hindi @@ -80,7 +80,7 @@ DE=Saksa DK=Tanska ES=Espanja FI=Suomi -FR=Franska +FR=Ranska GB=Iso-Britannia GR=Kreikka IE=Irlanti diff --git a/jdk/src/share/classes/sun/util/resources/LocaleNames_nl.properties b/jdk/src/share/classes/sun/util/resources/LocaleNames_nl.properties index 1f5bb150cc4..da85201e674 100644 --- a/jdk/src/share/classes/sun/util/resources/LocaleNames_nl.properties +++ b/jdk/src/share/classes/sun/util/resources/LocaleNames_nl.properties @@ -34,14 +34,436 @@ # This notice and attribution to Taligent may not be removed. # Taligent is a registered trademark of Taligent, Inc. - # language names # key is ISO 639 language code +aa=Afar +ab=Abchazisch +ae=Avestisch +af=Afrikaans +ak=Akan +am=Amhaars +an=Aragonees +ar=Arabisch +as=Assamees +av=Avarisch +ay=Aymara +az=Azerbeidzjaans +ba=Basjkiers +be=Wit-Russisch +bg=Bulgaars +bh=Bihari +bi=Bislama +bm=Bambara +bn=Bengalees +bo=Tibetaans +br=Bretons +bs=Bosnisch +ca=Catalaans +ce=Chechen +ch=Chamorro +co=Corsicaans +cr=Cree +cs=Tsjechisch +cu=Kerkslavisch +cv=Tsjoevasjisch +cy=Welsh +da=Deens +de=Duits +dv=Divehi +dz=Dzongkha +ee=Ewe +el=Grieks +en=Engels +eo=Esperanto +es=Spaans +et=Estlands +eu=Baskisch +fa=Perzisch +ff=Fulah +fi=Fins +fj=Fijisch +fo=Faer\u00f6ers +fr=Frans +fy=Fries +ga=Iers +gd=Schots Gaelic +gl=Galicisch +gn=Guarani +gu=Gujarati +gv=Manx +ha=Hausa +he=Hebreeuws +hi=Hindi +ho=Hiri Motu +hr=Kroatisch +ht=Ha\u00eftiaans +hu=Hongaars +hy=Armeens +hz=Herero +ia=Interlingua +id=Indonesisch +ie=Interlingue +ig=Igbo +ii=Sichuan Yi +ik=Inupiaq +io=Ido +is=IJslands +it=Italiaans +iu=Inuktitut +ja=Japans +jv=Javaans +ka=Georgisch +kg=Kongo +ki=Kikuyu +kj=Kuanyama +kk=Kazachs +kl=Kalaallisut +km=Khmer +kn=Kannada +ko=Koreaans +kr=Kanuri +ks=Kashmiri +ku=Koerdisch +kv=Komi +kw=Cornish +ky=Kirgizisch +la=Latijn +lb=Luxemburgs +lg=Ganda +li=Limburgs +ln=Lingala +lo=Lao +lt=Litouws +lu=Luba-Katanga +lv=Letlands +mg=Malagasisch +mh=Marshallees +mi=Maori +mk=Macedonisch +ml=Malayalam +mn=Mongools +mo=Moldavisch +mr=Marathi +ms=Maleis +mt=Maltees +my=Birmees +na=Nauru +nb=Noors - Bokm\u00e5l +nd=Noord-Ndbele +ne=Nepalees +ng=Ndonga nl=Nederlands +nn=Noors - Nynorsk +no=Noors +nr=Zuid-Ndbele +nv=Navajo +ny=Nyanja +oc=Occitaans +oj=Ojibwa +om=Oromo +or=Oriya +os=Ossetisch +pa=Punjabi +pi=Pali +pl=Pools +ps=Pasjtoe +pt=Portugees +qu=Quechua +rm=Reto-Romaans +rn=Rundi +ro=Roemeens +ru=Russisch +rw=Kinyarwanda +sa=Sanskriet +sc=Sardinisch +sd=Sindhi +se=Noord-Samisch +sg=Sango +si=Singalees +sk=Slowaaks +sl=Sloveens +sm=Samoaans +sn=Shona +so=Somalisch +sq=Albanees +sr=Servisch +ss=Swati +st=Zuid-Sotho +su=Soendanees +sv=Zweeds +sw=Swahili +ta=Tamil +te=Teloegoe +tg=Tadzjieks +th=Thais +ti=Tigrinya +tk=Turkmeens +tl=Tagalog +tn=Tswana +to=Tonga +tr=Turks +ts=Tsonga +tt=Tataars +tw=Twi +ty=Tahitisch +ug=Oeigoers +uk=Oekra\u00efens +ur=Urdu +uz=Oezbeeks +ve=Venda +vi=Vietnamees +vo=Volap\u00fck +wa=Wallonisch +wo=Wolof +xh=Xhosa +yi=Jiddisch +yo=Yoruba +za=Zhuang +zh=Chinees +zu=Zulu # country names # key is ISO 3166 country code -NL=Nederland +AD=Andorra +AE=Verenigde Arabische Emiraten +AF=Afghanistan +AG=Antigua en Barbuda +AI=Anguilla +AL=Albani\u00eb +AM=Armeni\u00eb +AN=Nederlandse Antillen +AO=Angola +AQ=Antarctica +AR=Argentini\u00eb +AS=Amerikaans Samoa +AT=Oostenrijk +AU=Australi\u00eb +AW=Aruba +AX=Alandeilanden +AZ=Azerbeidzjan +BA=Bosni\u00eb en Herzegovina +BB=Barbados +BD=Bangladesh BE=Belgi\u00eb +BF=Burkina Faso +BG=Bulgarije +BH=Bahrein +BI=Burundi +BJ=Benin +BM=Bermuda +BN=Brunei +BO=Bolivia +BR=Brazili\u00eb +BS=Bahama\u2019s +BT=Bhutan +BV=Bouveteiland +BW=Botswana +BY=Wit-Rusland +BZ=Belize +CA=Canada +CC=Cocoseilanden +CD=Congo-Kinshasa +CF=Centraal-Afrikaanse Republiek +CG=Congo +CH=Zwitserland +CI=Ivoorkust +CK=Cookeilanden +CL=Chili +CM=Kameroen +CN=China +CO=Colombia +CR=Costa Rica +CS=Servi\u00eb en Montenegro +CU=Cuba +CV=Kaapverdi\u00eb +CX=Christmaseiland +CY=Cyprus +CZ=Tsjechi\u00eb +DE=Duitsland +DJ=Djibouti +DK=Denemarken +DM=Dominica +DO=Dominicaanse Republiek +DZ=Algerije +EC=Ecuador +EE=Estland +EG=Egypte +EH=Westelijke Sahara +ER=Eritrea +ES=Spanje +ET=Ethiopi\u00eb +FI=Finland +FJ=Fiji +FK=Falklandeilanden +FM=Micronesi\u00eb +FO=Faer\u00f6er +FR=Frankrijk +GA=Gabon +GB=Verenigd Koninkrijk +GD=Grenada +GE=Georgi\u00eb +GF=Frans-Guyana +GH=Ghana +GI=Gibraltar +GL=Groenland +GM=Gambia +GN=Guinee +GP=Guadeloupe +GQ=Equatoriaal-Guinea +GR=Griekenland +GS=Zuid-Georgi\u00eb en Zuidelijke Sandwicheilanden +GT=Guatemala +GU=Guam +GW=Guinee-Bissau +GY=Guyana +HK=Hongkong SAR van China +HM=Heard- en McDonaldeilanden +HN=Honduras +HR=Kroati\u00eb +HT=Ha\u00efti +HU=Hongarije +ID=Indonesi\u00eb +IE=Ierland +IL=Isra\u00ebl +IN=India +IO=Britse Gebieden in de Indische Oceaan +IQ=Irak +IR=Iran +IS=IJsland +IT=Itali\u00eb +JM=Jamaica +JO=Jordani\u00eb +JP=Japan +KE=Kenia +KG=Kirgizi\u00eb +KH=Cambodja +KI=Kiribati +KM=Comoren +KN=Saint Kitts en Nevis +KP=Noord-Korea +KR=Zuid-Korea +KW=Koeweit +KY=Caymaneilanden +KZ=Kazachstan +LA=Laos +LB=Libanon +LC=Saint Lucia +LI=Liechtenstein +LK=Sri Lanka +LR=Liberia +LS=Lesotho +LT=Litouwen +LU=Luxemburg +LV=Letland +LY=Libi\u00eb +MA=Marokko +MC=Monaco +MD=Moldavi\u00eb +ME=Montenegro +MG=Madagaskar +MH=Marshalleilanden +MK=Macedoni\u00eb +ML=Mali +MM=Myanmar +MN=Mongoli\u00eb +MO=Macao SAR van China +MP=Noordelijke Marianeneilanden +MQ=Martinique +MR=Mauritani\u00eb +MS=Montserrat +MT=Malta +MU=Mauritius +MV=Maldiven +MW=Malawi +MX=Mexico +MY=Maleisi\u00eb +MZ=Mozambique +NA=Namibi\u00eb +NC=Nieuw-Caledoni\u00eb +NE=Niger +NF=Norfolkeiland +NG=Nigeria +NI=Nicaragua +NL=Nederland +NO=Noorwegen +NP=Nepal +NR=Nauru +NU=Niue +NZ=Nieuw-Zeeland +OM=Oman +PA=Panama +PE=Peru +PF=Frans-Polynesi\u00eb +PG=Papoea-Nieuw-Guinea +PH=Filipijnen +PK=Pakistan +PL=Polen +PM=Saint Pierre en Miquelon +PN=Pitcairn +PR=Puerto Rico +PS=Palestijns Gebied +PT=Portugal +PW=Palau +PY=Paraguay +QA=Qatar +RE=R\u00e9union +RO=Roemeni\u00eb +RS=Servi\u00eb +RU=Rusland +RW=Rwanda +SA=Saoedi-Arabi\u00eb +SB=Salomonseilanden +SC=Seychellen +SD=Soedan +SE=Zweden +SG=Singapore +SH=Sint-Helena +SI=Sloveni\u00eb +SJ=Svalbard en Jan Mayen +SK=Slowakije +SL=Sierra Leone +SM=San Marino +SN=Senegal +SO=Somali\u00eb +SR=Suriname +ST=Sao Tom\u00e9 en Principe +SV=El Salvador +SY=Syri\u00eb +SZ=Swaziland +TC=Turks- en Caicoseilanden +TD=Tsjaad +TF=Franse Gebieden in de zuidelijke Indische Oceaan +TG=Togo +TH=Thailand +TJ=Tadzjikistan +TK=Tokelau +TL=Oost-Timor +TM=Turkmenistan +TN=Tunesi\u00eb +TO=Tonga +TR=Turkije +TT=Trinidad en Tobago +TV=Tuvalu +TW=Taiwan +TZ=Tanzania +UA=Oekra\u00efne +UG=Oeganda +UM=Amerikaanse kleinere afgelegen eilanden +US=Verenigde Staten +UY=Uruguay +UZ=Oezbekistan +VA=Vaticaanstad +VC=Saint Vincent en de Grenadines +VE=Venezuela +VG=Britse Maagdeneilanden +VI=Amerikaanse Maagdeneilanden +VN=Vietnam +VU=Vanuatu +WF=Wallis en Futuna +WS=Samoa +YE=Jemen +YT=Mayotte +ZA=Zuid-Afrika +ZM=Zambia diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java index 896d72a5c53..eaef647eb8b 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java @@ -71,8 +71,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Bhutanische Sommerzeit", "BTST"}; String CAT[] = new String[] {"Zentralafrikanische Zeit", "CAT", "Zentralafrikanische Sommerzeit", "CAST"}; - String CET[] = new String[] {"Zentraleurop\u00e4ische Zeit", "CET", - "Zentraleurop\u00e4ische Sommerzeit", "CEST"}; + String CET[] = new String[] {"Mitteleurop\u00e4ische Zeit", "MEZ", + "Mitteleurop\u00e4ische Sommerzeit", "MESZ"}; String CHAST[] = new String[] {"Chatham Normalzeit", "CHAST", "Chatham Sommerzeit", "CHADT"}; String CIT[] = new String[] {"Zentralindonesische Zeit", "CIT", @@ -83,8 +83,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Zentrale Sommerzeit", "CDT"}; String CTT[] = new String[] {"Chinesische Normalzeit", "CST", "Chinesische Sommerzeit", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"Kubanische Normalzeit", "CST", + "Kubanische Sommerzeit", "CDT"}; String DARWIN[] = new String[] {"Zentrale Normalzeit (Northern Territory)", "CST", "Zentrale Sommerzeit (Northern Territory)", "CST"}; String DUBLIN[] = new String[] {"Greenwich Zeit", "GMT", @@ -93,8 +93,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Ostafrikanische Sommerzeit", "EAST"}; String EASTER[] = new String[] {"Osterinseln Zeit", "EAST", "Osterinseln Sommerzeit", "EASST"}; - String EET[] = new String[] {"Osteurop\u00e4ische Zeit", "EET", - "Osteurop\u00e4ische Sommerzeit", "EEST"}; + String EET[] = new String[] {"Osteurop\u00e4ische Zeit", "OEZ", + "Osteurop\u00e4ische Sommerzeit", "OESZ"}; String EGT[] = new String[] {"Ostgr\u00f6nl\u00e4ndische Zeit", "EGT", "Ostgr\u00f6nl\u00e4ndische Sommerzeit", "EGST"}; String EST[] = new String[] {"\u00d6stliche Normalzeit", "EST", @@ -173,12 +173,12 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { "Truk Sommerzeit", "TRUST"}; String ULAT[]= new String[] {"Ulaanbaatar Zeit", "ULAT", "Ulaanbaatar Sommerzeit", "ULAST"}; - String WART[] = new String[] {"Argentinische Zeit", "WART", - "Argentinische Sommerzeit", "WARST"}; + String WART[] = new String[] {"Westargentinische Zeit", "WART", + "Westargentinische Sommerzeit", "WARST"}; String WAT[] = new String[] {"Westafrikanische Zeit", "WAT", "Westafrikanische Sommerzeit", "WAST"}; - String WET[] = new String[] {"Westeurop\u00e4ische Zeit", "WET", - "Westeurop\u00e4ische Sommerzeit", "WEST"}; + String WET[] = new String[] {"Westeurop\u00e4ische Zeit", "WEZ", + "Westeurop\u00e4ische Sommerzeit", "WESZ"}; String WIT[] = new String[] {"Westindonesische Zeit", "WIT", "Westindonesische Sommerzeit", "WIST"}; String WST_AUS[] = new String[] {"Westliche Normalzeit (Australien)", "WST", @@ -594,8 +594,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"Zentral-Westliche Normalzeit (Australien)", "CWST", + "Zentral-Westliche Sommerzeit (Australien)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java index 20605d1187a..75f67f2a0a2 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de verano Central", "CDT"}; String CTT[] = new String[] {"Hora est\u00e1ndar de China", "CST", "Hora de verano de China", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"Hora est\u00e1ndar de Cuba", "CST", + "Hora de verano de Cuba", "CDT"}; String DARWIN[] = new String[] {"Hora est\u00e1ndar Central (territorio del Norte)", "CST", "Hora de verano Central (territorio del Norte)", "CST"}; String DUBLIN[] = new String[] {"Hora del Meridiano de Greenwich", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { "Hora de verano de Truk", "TRUST"}; String ULAT[]= new String[] {"Hora de Ulan Bator", "ULAT", "Hora de verano de Ulan Bator", "ULAST"}; - String WART[] = new String[] {"Hora de Argentina", "WART", - "Hora de verano de Argentina", "WARST"}; + String WART[] = new String[] {"Hora de Argentina Occidental", "WART", + "Hora de verano de Argentina Occidental", "WARST"}; String WAT[] = new String[] {"Hora de \u00c1frica Occidental", "WAT", "Hora de verano de \u00c1frica Occidental", "WAST"}; String WET[] = new String[] {"Hora de Europa Occidental", "WET", @@ -595,8 +595,8 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"Hora est\u00e1ndar de Australia Central y Occidental", "CWST", + "Hora de verano de Australia Central y Occidental", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java index e3f8205584a..0e68b42e93c 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure avanc\u00e9e du Centre", "CDT"} ; String CTT[] = new String[] {"Heure normale de Chine", "CST", "Heure avanc\u00e9e de Chine", "CDT"} ; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"Heure standard de Cuba", "CST", + "Heure d'\u00e9t\u00e9 de Cuba", "CDT"}; String DARWIN[] = new String[] {"Heure standard d'Australie centrale (Territoire du Nord)", "CST", "Heure d'\u00e9t\u00e9 d'Australie centrale (Territoire du Nord)", "CST"}; String DUBLIN[] = new String[] {"Heure du m\u00e9ridien de Greenwich", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { "Heure d'\u00e9t\u00e9 de Truk", "TRUST"}; String ULAT[]= new String[] {"Heure de l'Ulaanbaatar", "ULAT", "Heure d'\u00e9t\u00e9 de l'Ulaanbaatar", "ULAST"} ; - String WART[] = new String[] {"Heure D'Argentine", "WART", - "Heure d'\u00e9t\u00e9 D'Argentine", "WARST"} ; + String WART[] = new String[] {"Heure D'Argentine de l'Ouest", "WART", + "Heure d'\u00e9t\u00e9 D'Argentine de l'Ouest", "WARST"} ; String WAT[] = new String[] {"Heure d'Afrique de l'Ouest", "WAT", "Heure d'\u00e9t\u00e9 d'Afrique de l'Ouest", "WAST"} ; String WET[] = new String[] {"Heure d'Europe de l'Ouest", "WET", @@ -594,8 +594,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"Heure standard de l'Australie occidentale (centre)", "CWST", + "Heure d'\u00e9t\u00e9 de l'Australie occidentale (centre)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java index e464618f2af..a461f464c76 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora legale USA centrale", "CDT"}; String CTT[] = new String[] {"Ora solare della Cina", "CST", "Ora legale della Cina", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"Ora solare Cuba", "CST", + "Ora legale Cuba", "CDT"}; String DARWIN[] = new String[] {"Ora centrale standard (Territori del Nord)", "CST", "Ora estiva centrale (Territori del Nord)", "CST"}; String DUBLIN[] = new String[] {"Ora media di Greenwich", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { "Ora estiva di Truk", "TRUST"}; String ULAT[]= new String[] {"Ora di Ulaanbaatar", "ULAT", "Ora estiva di Ulaanbaatar", "ULAST"}; - String WART[] = new String[] {"Ora dell'Argentina", "WART", - "Ora estiva dell'Argentina", "WARST"}; + String WART[] = new String[] {"Ora dell'Argentina occidentale", "WART", + "Ora estiva dell'Argentina occidentale", "WARST"}; String WAT[] = new String[] {"Ora dell'Africa occidentale", "WAT", "Ora estiva dell'Africa occidentale", "WAST"}; String WET[] = new String[] {"Ora dell'Europa occidentale", "WET", @@ -594,8 +594,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"Ora solare Australia centrorientale", "CWST", + "Ora estiva Australia centrorientale", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java index 1292e4b8045..6587b2171da 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u4e2d\u90e8\u590f\u6642\u9593", "CDT"}; String CTT[] = new String[] {"\u4e2d\u56fd\u6a19\u6e96\u6642", "CST", "\u4e2d\u56fd\u590f\u6642\u9593", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"\u30ad\u30e5\u30fc\u30d0\u6a19\u6e96\u6642", "CST", + "\u30ad\u30e5\u30fc\u30d0\u590f\u6642\u9593", "CDT"}; String DARWIN[] = new String[] {"\u4e2d\u90e8\u6a19\u6e96\u6642 (\u30ce\u30fc\u30b6\u30f3\u30c6\u30ea\u30c8\u30ea\u30fc)", "CST", "\u4e2d\u90e8\u590f\u6642\u9593 (\u30ce\u30fc\u30b6\u30f3\u30c6\u30ea\u30c8\u30ea\u30fc)", "CST"}; String DUBLIN[] = new String[] {"\u30b0\u30ea\u30cb\u30c3\u30b8\u6a19\u6e96\u6642", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { "\u30c8\u30e9\u30c3\u30af\u590f\u6642\u9593", "TRUST"}; String ULAT[]= new String[] {"\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u6642\u9593", "ULAT", "\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u590f\u6642\u9593", "ULAST"}; - String WART[] = new String[] {"\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u6642\u9593", "WART", - "\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u590f\u6642\u9593", "WARST"}; + String WART[] = new String[] {"\u897f\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u6642\u9593", "WART", + "\u897f\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u590f\u6642\u9593", "WARST"}; String WAT[] = new String[] {"\u897f\u30a2\u30d5\u30ea\u30ab\u6642\u9593", "WAT", "\u897f\u30a2\u30d5\u30ea\u30ab\u590f\u6642\u9593", "WAST"}; String WET[] = new String[] {"\u897f\u30e8\u30fc\u30ed\u30c3\u30d1\u6642\u9593", "WET", @@ -594,8 +594,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"\u4e2d\u897f\u90e8\u6a19\u6e96\u6642 (\u30aa\u30fc\u30b9\u30c8\u30e9\u30ea\u30a2)", "CWST", + "\u4e2d\u897f\u90e8\u590f\u6642\u9593 (\u30aa\u30fc\u30b9\u30c8\u30e9\u30ea\u30a2)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java index f69e08b250e..7106b89bf26 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\uc911\ubd80 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CDT"}; String CTT[] = new String[] {"\uc911\uad6d \ud45c\uc900\uc2dc", "CST", "\uc911\uad6d \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"\ucfe0\ubc14 \ud45c\uc900\uc2dc", "CST", + "\ucfe0\ubc14 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CDT"}; String DARWIN[] = new String[] {"\uc911\ubd80 \ud45c\uc900\uc2dc(\ub178\ub358 \uc9c0\uc5ed)", "CST", "\uc911\ubd80 \uc77c\uad11\uc808\uc57d\uc2dc\uac04(\ub178\ub358 \uc9c0\uc5ed)", "CST"}; String DUBLIN[] = new String[] {"\uadf8\ub9ac\ub2c8\uce58 \ud45c\uc900\uc2dc", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { "\ud2b8\ub8e8\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "TRUST"}; String ULAT[]= new String[] {"\uc6b8\ub780\ubc14\ud0c0\ub974 \uc2dc\uac04", "ULAT", "\uc6b8\ub780\ubc14\ud0c0\ub974 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ULAST"}; - String WART[] = new String[] {"\uc544\ub974\ud5e8\ud2f0\ub098 \uc2dc\uac04", "WART", - "\uc544\ub974\ud5e8\ud2f0\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WARST"}; + String WART[] = new String[] {"\uc11c\ubd80 \uc544\ub974\ud5e8\ud2f0\ub098 \uc2dc\uac04", "WART", + "\uc11c\ubd80 \uc544\ub974\ud5e8\ud2f0\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WARST"}; String WAT[] = new String[] {"\uc11c\ubd80 \uc544\ud504\ub9ac\uce74 \uc2dc\uac04", "WAT", "\uc11c\ubd80 \uc544\ud504\ub9ac\uce74 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WAST"}; String WET[] = new String[] {"\uc11c\uc720\ub7fd \uc2dc\uac04", "WET", @@ -594,8 +594,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"\uc911\uc11c\ubd80 \ud45c\uc900\uc2dc(\uc624\uc2a4\ud2b8\ub808\uc77c\ub9ac\uc544)", "CWST", + "\uc911\uc11c\ubd80 \uc77c\uad11\uc808\uc57d\uc2dc\uac04(\uc624\uc2a4\ud2b8\ub808\uc77c\ub9ac\uc544)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java index 35ce2d11c51..1b75fd47e12 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java @@ -45,8 +45,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { protected final Object[][] getContents() { String ACT[] = new String[] {"Acre, normaltid", "ACT", "Acre, sommartid", "ACST"}; - String ADELAIDE[] = new String[] {"Central Standard Time (S\u00f6dra Australien)", "CST", - "Central Summer Time (S\u00f6dra Australien)", "CST"}; + String ADELAIDE[] = new String[] {"Central normaltid (S\u00f6dra Australien)", "CST", + "Central sommartid (S\u00f6dra Australien)", "CST"}; String AGT[] = new String[] {"Argentina, normaltid", "ART", "Argentina, sommartid", "ARST"}; String AKST[] = new String[] {"Alaska, normaltid", "AKST", @@ -61,10 +61,10 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Atlantisk sommartid", "ADT"}; String BDT[] = new String[] {"Bangladesh, normaltid", "BDT", "Bangladesh, sommartid", "BDST"}; - String BRISBANE[] = new String[] {"Eastern Standard Time (Queensland)", "EST", - "Eastern Summer Time (Queensland)", "EST"}; - String BROKEN_HILL[] = new String[] {"Central Standard Time (S\u00f6dra Australien/Nya Sydwales)", "CST", - "Central Summer Time (S\u00f6dra Australien/Nya Sydwales)", "CST"}; + String BRISBANE[] = new String[] {"\u00d6stlig normaltid (Queensland)", "EST", + "\u00d6stlig sommartid (Queensland)", "EST"}; + String BROKEN_HILL[] = new String[] {"Central normaltid (S\u00f6dra Australien/Nya Sydwales)", "CST", + "Central sommartid (S\u00f6dra Australien/Nya Sydwales)", "CST"}; String BRT[] = new String[] {"Brasilien, normaltid", "BRT", "Brasilien, sommartid", "BRST"}; String BTT[] = new String[] {"Bhutan, normaltid", "BTT", @@ -83,10 +83,10 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Central sommartid", "CDT"}; String CTT[] = new String[] {"Kina, normaltid", "CST", "Kina, sommartid", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; - String DARWIN[] = new String[] {"Central Standard Time (Nordterritoriet)", "CST", - "Central Summer Time (Nordterritoriet)", "CST"}; + String CUBA[] = new String[] {"Kuba, normaltid", "CST", + "Kuba, sommartid", "CDT"}; + String DARWIN[] = new String[] {"Central normaltid (Nordterritoriet)", "CST", + "Central sommartid (Nordterritoriet)", "CST"}; String DUBLIN[] = new String[] {"Greenwichtid", "GMT", "Irland, sommartid", "IST"}; String EAT[] = new String[] {"\u00d6stafrikansk tid", "EAT", @@ -99,8 +99,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "\u00d6stgr\u00f6nl\u00e4ndsk sommartid", "EGST"}; String EST[] = new String[] {"Eastern, normaltid", "EST", "Eastern, sommartid", "EDT"}; - String EST_NSW[] = new String[] {"Eastern Standard Time (Nya Sydwales)", "EST", - "Eastern Summer Time (Nya Sydwales)", "EST"}; + String EST_NSW[] = new String[] {"Eastern, normaltid (Nya Sydwales)", "EST", + "Eastern, sommartid (Nya Sydwales)", "EST"}; String GHMT[] = new String[] {"Ghana, normaltid", "GMT", "Ghana, sommartid", "GHST"}; String GAMBIER[] = new String[] {"Gambier, normaltid", "GAMT", @@ -163,34 +163,34 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { "Salomon\u00f6arna, sommartid", "SBST"}; String SGT[] = new String[] {"Singapore, normaltid", "SGT", "Singapore, sommartid", "SGST"}; - String SLST[] = new String[] {"Greenwich Mean Time", "GMT", + String SLST[] = new String[] {"Greenwichtid", "GMT", "Sierra Leone, sommartid", "SLST"}; - String TASMANIA[] = new String[] {"Eastern Standard Time (Tasmanien)", "EST", - "Eastern Summer Time (Tasmanien)", "EST"}; + String TASMANIA[] = new String[] {"Eastern, normaltid (Tasmanien)", "EST", + "Eastern, sommartid (Tasmanien)", "EST"}; String TMT[] = new String[] {"Turkmenistan, normaltid", "TMT", "Turkmenistan, sommartid", "TMST"}; String TRUT[] = new String[] {"Truk, normaltid", "TRUT", "Truk, sommartid", "TRUST"}; String ULAT[]= new String[] {"Ulaanbaatar, normaltid", "ULAT", "Ulaanbaatar, sommartid", "ULAST"}; - String WART[] = new String[] {"Argentina, normaltid", "WART", - "Argentina, sommartid", "WARST"}; + String WART[] = new String[] {"V\u00e4stargentina, normaltid", "WART", + "V\u00e4stargentina, sommartid", "WARST"}; String WAT[] = new String[] {"V\u00e4stafrikansk tid", "WAT", "V\u00e4stafrikansk sommartid", "WAST"}; String WET[] = new String[] {"V\u00e4steuropeisk tid", "WET", "V\u00e4steuropeisk sommartid", "WEST"}; String WIT[] = new String[] {"V\u00e4stindonesisk tid", "WIT", "V\u00e4stindonesisk sommartid", "WIST"}; - String WST_AUS[] = new String[] {"Western Standard Time (Australien)", "WST", - "Western Summer Time (Australien)", "WST"}; + String WST_AUS[] = new String[] {"V\u00e4stlig normaltid (Australien)", "WST", + "V\u00e4stlig sommartid (Australien)", "WST"}; String SAMOA[] = new String[] {"Samoa, normaltid", "SST", "Samoa, sommartid", "SDT"}; String WST_SAMOA[] = new String[] {"V\u00e4stsamoansk tid", "WST", "V\u00e4stsamoansk sommartid", "WSST"}; String ChST[] = new String[] {"Chamorro, normaltid", "ChST", "Chamorro, sommartid", "ChDT"}; - String VICTORIA[] = new String[] {"Eastern Standard Time (Victoria)", "EST", - "Eastern Summer Time (Victoria)", "EST"}; + String VICTORIA[] = new String[] {"\u00d6stlig normaltid (Victoria)", "EST", + "\u00d6stlig sommartid (Victoria)", "EST"}; String UTC[] = new String[] {"Koordinerad universell tid", "UTC", "Koordinerad universell tid", "UTC"}; String UZT[] = new String[] {"Uzbekistan, normaltid", "UZT", @@ -594,8 +594,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"Central v\u00e4stlig normaltid (Australien)", "CWST", + "Central v\u00e4stlig sommartid (Australien)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java index 70cdbd0a987..f63c322c6ff 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u4e2d\u592e\u590f\u4ee4\u65f6", "CDT"}; String CTT[] = new String[] {"\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4", "CST", "\u4e2d\u56fd\u590f\u4ee4\u65f6", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"\u53e4\u5df4\u6807\u51c6\u65f6\u95f4", "CST", + "\u53e4\u5df4\u590f\u4ee4\u65f6", "CDT"}; String DARWIN[] = new String[] {"\u4e2d\u592e\u6807\u51c6\u65f6\u95f4\uff08\u5317\u9886\u5730\uff09", "CST", "\u4e2d\u592e\u590f\u4ee4\u65f6\uff08\u5317\u9886\u5730\uff09", "CST"}; String DUBLIN[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u65f6\u95f4", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { "\u7279\u9c81\u514b\u590f\u4ee4\u65f6", "TRUST"}; String ULAT[]= new String[] {"\u5e93\u4f26\u65f6\u95f4", "ULAT", "\u5e93\u4f26\u590f\u4ee4\u65f6", "ULAST"}; - String WART[] = new String[] {"\u963f\u6839\u5ef7\u65f6\u95f4", "WART", - "\u963f\u6839\u5ef7\u590f\u4ee4\u65f6", "WARST"}; + String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u65f6\u95f4", "WART", + "\u897f\u963f\u6839\u5ef7\u590f\u4ee4\u65f6", "WARST"}; String WAT[] = new String[] {"\u897f\u975e\u65f6\u95f4", "WAT", "\u897f\u975e\u590f\u4ee4\u65f6", "WAST"}; String WET[] = new String[] {"\u897f\u6b27\u65f6\u95f4", "WET", @@ -594,8 +594,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"\u4e2d\u897f\u90e8\u6807\u51c6\u65f6\u95f4\uff08\u6fb3\u5927\u5229\u4e9a\uff09", "CWST", + "\u4e2d\u897f\u90e8\u590f\u4ee4\u65f6\uff08\u6fb3\u5927\u5229\u4e9a\uff09", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java index f5b89286ed0..91a1620c79b 100644 --- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java +++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java @@ -83,8 +83,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "\u4e2d\u592e\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "CDT"}; String CTT[] = new String[] {"\u4e2d\u570b\u6a19\u6e96\u6642\u9593", "CST", "\u4e2d\u570b\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "CDT"}; - String CUBA[] = new String[] {"Cuba Standard Time", "CST", - "Cuba Daylight Time", "CDT"}; + String CUBA[] = new String[] {"\u53e4\u5df4\u6a19\u6e96\u6642\u9593", "CST", + "\u53e4\u5df4\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "CDT"}; String DARWIN[] = new String[] {"\u4e2d\u90e8\u6a19\u6e96\u6642\u9593 (\u5317\u90e8\u5404\u5730\u5340)", "CST", "\u4e2d\u90e8\u590f\u4ee4\u6642\u9593 (\u5317\u90e8\u5404\u5730\u5340)", "CST"}; String DUBLIN[] = new String[] {"\u683c\u6797\u5a01\u6cbb\u5e73\u5747\u6642\u9593", "GMT", @@ -173,8 +173,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { "\u7279\u9b6f\u514b\u590f\u4ee4\u6642\u9593", "TRUST"}; String ULAT[]= new String[] {"\u5eab\u502b\u6642\u9593", "ULAT", "\u5eab\u502b\u590f\u4ee4\u6642\u9593", "ULAST"}; - String WART[] = new String[] {"\u963f\u6839\u5ef7\u6642\u9593", "WART", - "\u963f\u6839\u5ef7\u590f\u4ee4\u6642\u9593", "WARST"}; + String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u6642\u9593", "WART", + "\u897f\u963f\u6839\u5ef7\u590f\u4ee4\u6642\u9593", "WARST"}; String WAT[] = new String[] {"\u897f\u975e\u6642\u9593", "WAT", "\u897f\u975e\u590f\u4ee4\u6642\u9593", "WAST"}; String WET[] = new String[] {"\u897f\u6b50\u6642\u9593", "WET", @@ -551,7 +551,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Asia/Samarkand", UZT}, {"Asia/Seoul", KST}, {"Asia/Singapore", SGT}, - {"Asia/Taipei", CTT}, + {"Asia/Taipei", new String[] {"\u53f0\u7063\u6a19\u6e96\u6642\u9593", "TST", + "\u53f0\u7063\u590f\u4ee4\u6642\u9593", "TDT"}}, {"Asia/Tel_Aviv", ISRAEL}, {"Asia/Tashkent", UZT}, {"Asia/Tbilisi", new String[] {"\u55ac\u6cbb\u4e9e\u6642\u9593", "GET", @@ -594,8 +595,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { {"Australia/Canberra", EST_NSW}, {"Australia/Currie", EST_NSW}, {"Australia/Darwin", DARWIN}, - {"Australia/Eucla", new String[] {"Central Western Standard Time (Australia)", "CWST", - "Central Western Summer Time (Australia)", "CWST"}}, + {"Australia/Eucla", new String[] {"\u4e2d\u897f\u90e8\u6a19\u6e96\u6642\u9593 (\u6fb3\u5927\u5229\u4e9e)", "CWST", + "\u4e2d\u897f\u90e8\u65e5\u5149\u7bc0\u7d04\u6642\u9593 (\u6fb3\u5927\u5229\u4e9e)", "CWST"}}, {"Australia/Hobart", TASMANIA}, {"Australia/LHI", LORD_HOWE}, {"Australia/Lindeman", BRISBANE}, diff --git a/jdk/src/share/lib/security/java.security b/jdk/src/share/lib/security/java.security index b975f25e1e5..7d386b715ae 100644 --- a/jdk/src/share/lib/security/java.security +++ b/jdk/src/share/lib/security/java.security @@ -55,10 +55,10 @@ security.provider.9=sun.security.smartcardio.SunPCSC # # Select the source of seed data for SecureRandom. By default an -# attempt is made to use the entropy gathering device specified by +# attempt is made to use the entropy gathering device specified by # the securerandom.source property. If an exception occurs when -# accessing the URL then the traditional system/thread activity -# algorithm is used. +# accessing the URL then the traditional system/thread activity +# algorithm is used. # # On Solaris and Linux systems, if file:/dev/urandom is specified and it # exists, a special SecureRandom implementation is activated by default. @@ -72,7 +72,7 @@ securerandom.source=file:/dev/urandom # The entropy gathering device is described as a URL and can also # be specified with the system property "java.security.egd". For example, # -Djava.security.egd=file:/dev/urandom -# Specifying this system property will override the securerandom.source +# Specifying this system property will override the securerandom.source # setting. # @@ -149,7 +149,7 @@ package.access=sun.,com.sun.imageio. security.overridePropertiesFile=true # -# Determines the default key and trust manager factory algorithms for +# Determines the default key and trust manager factory algorithms for # the javax.net.ssl package. # ssl.KeyManagerFactory.algorithm=SunX509 @@ -168,10 +168,10 @@ ssl.TrustManagerFactory.algorithm=PKIX # is to cache for 30 seconds. # # NOTE: setting this to anything other than the default value can have -# serious security implications. Do not set it unless +# serious security implications. Do not set it unless # you are sure you are not exposed to DNS spoofing attack. # -#networkaddress.cache.ttl=-1 +#networkaddress.cache.ttl=-1 # The Java-level namelookup cache policy for failed lookups: # @@ -183,7 +183,7 @@ ssl.TrustManagerFactory.algorithm=PKIX # the WINS name service in addition to DNS, name service lookups # that fail may take a noticeably long time to return (approx. 5 seconds). # For this reason the default caching policy is to maintain these -# results for 10 seconds. +# results for 10 seconds. # # networkaddress.cache.negative.ttl=10 @@ -192,7 +192,7 @@ networkaddress.cache.negative.ttl=10 # Properties to configure OCSP for certificate revocation checking # -# Enable OCSP +# Enable OCSP # # By default, OCSP is not used for certificate revocation checking. # This property enables the use of OCSP when set to the value "true". @@ -201,7 +201,7 @@ networkaddress.cache.negative.ttl=10 # # Example, # ocsp.enable=true - + # # Location of the OCSP responder # @@ -213,15 +213,15 @@ networkaddress.cache.negative.ttl=10 # # Example, # ocsp.responderURL=http://ocsp.example.net:80 - + # # Subject name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate -# of the OCSP responder when the default does not apply. Its value is a string -# distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. In cases where +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. In cases where # the subject name alone is not sufficient to uniquely identify the certificate # then both the "ocsp.responderCertIssuerName" and # "ocsp.responderCertSerialNumber" properties must be used instead. When this @@ -237,14 +237,14 @@ networkaddress.cache.negative.ttl=10 # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in -# the set of certificates supplied during cert path validation. When this -# property is set then the "ocsp.responderCertSerialNumber" property must also -# be set. When the "ocsp.responderCertSubjectName" property is set then this +# the set of certificates supplied during cert path validation. When this +# property is set then the "ocsp.responderCertSerialNumber" property must also +# be set. When the "ocsp.responderCertSubjectName" property is set then this # property is ignored. # # Example, # ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" - + # # Serial number of the OCSP responder's certificate # @@ -259,4 +259,31 @@ networkaddress.cache.negative.ttl=10 # # Example, # ocsp.responderCertSerialNumber=2A:FF:00 - + +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +krb5.kdc.bad.policy = tryLast + diff --git a/jdk/src/share/native/java/lang/StrictMath.c b/jdk/src/share/native/java/lang/StrictMath.c index 2bf12e3b71e..01024b309d3 100644 --- a/jdk/src/share/native/java/lang/StrictMath.c +++ b/jdk/src/share/native/java/lang/StrictMath.c @@ -94,18 +94,6 @@ Java_java_lang_StrictMath_cbrt(JNIEnv *env, jclass unused, jdouble d) return (jdouble) jcbrt((double)d); } -JNIEXPORT jdouble JNICALL -Java_java_lang_StrictMath_ceil(JNIEnv *env, jclass unused, jdouble d) -{ - return (jdouble) jceil((double)d); -} - -JNIEXPORT jdouble JNICALL -Java_java_lang_StrictMath_floor(JNIEnv *env, jclass unused, jdouble d) -{ - return (jdouble) jfloor((double)d); -} - JNIEXPORT jdouble JNICALL Java_java_lang_StrictMath_atan2(JNIEnv *env, jclass unused, jdouble d1, jdouble d2) { diff --git a/jdk/src/share/native/java/util/zip/zlib-1.2.3/zutil.h b/jdk/src/share/native/java/util/zip/zlib-1.2.3/zutil.h index 55e8f36db6e..7f26e625927 100644 --- a/jdk/src/share/native/java/util/zip/zlib-1.2.3/zutil.h +++ b/jdk/src/share/native/java/util/zip/zlib-1.2.3/zutil.h @@ -220,7 +220,8 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(vsnprintf) && !defined(NO_vsnprintf) && (!defined(_MSC_VER) || (_MSC_VER < 1500)) + /* Only needed before Visual Studio 2008 */ # define vsnprintf _vsnprintf # endif # endif diff --git a/jdk/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java index d7842570a2c..2d577c2e1b1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java @@ -38,7 +38,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; import java.nio.channels.NoConnectionPendingException; -import java.nio.channels.AlreadyBoundException; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.NotYetBoundException; import java.nio.channels.NotYetConnectedException; @@ -54,7 +53,6 @@ import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.NotificationHandler; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpSocketOption; -import sun.nio.ch.NativeDispatcher; import sun.nio.ch.PollArrayWrapper; import sun.nio.ch.SelChImpl; import static com.sun.nio.sctp.SctpStandardSocketOption.*; @@ -69,9 +67,6 @@ import static sun.nio.ch.SctpResultContainer.SHUTDOWN; public class SctpChannelImpl extends SctpChannel implements SelChImpl { - /* Used to make native close and preClose calls */ - private static NativeDispatcher nd; - private final FileDescriptor fd; private final int fdVal; @@ -182,7 +177,7 @@ public class SctpChannelImpl extends SctpChannel synchronized (stateLock) { ensureOpenAndUnconnected(); if (isBound()) - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); Net.bind(fd, isa.getAddress(), isa.getPort()); @@ -234,7 +229,7 @@ public class SctpChannelImpl extends SctpChannel if (add) { for (InetSocketAddress addr : localAddresses) { if (addr.getAddress().equals(address)) { - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); } } } else { /*removing */ @@ -370,7 +365,7 @@ public class SctpChannelImpl extends SctpChannel InetAddress ia = isa.getAddress(); if (ia.isAnyLocalAddress()) ia = InetAddress.getLocalHost(); - n = Net.connect(fd, ia, isa.getPort()); + n = SctpNet.connect(fdVal, ia, isa.getPort()); if ( (n == IOStatus.INTERRUPTED) && isOpen()) continue; @@ -556,7 +551,7 @@ public class SctpChannelImpl extends SctpChannel @Override public void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { - nd.preClose(fd); + SctpNet.preClose(fdVal); if (receiverThread != 0) NativeThread.signal(receiverThread); @@ -662,7 +657,7 @@ public class SctpChannelImpl extends SctpChannel /* Postpone the kill if there is a waiting reader * or writer thread. */ if (receiverThread == 0 && senderThread == 0) { - nd.close(fd); + SctpNet.close(fdVal); state = ChannelState.KILLED; } else { state = ChannelState.KILLPENDING; @@ -874,8 +869,8 @@ public class SctpChannelImpl extends SctpChannel public HandlerResult handleNotification( AssociationChangeNotification not, T unused) { if (not.event().equals( - AssociationChangeNotification.AssocChangeEvent.COMM_UP)) { - assert association == null; + AssociationChangeNotification.AssocChangeEvent.COMM_UP) && + association == null) { SctpAssocChange sac = (SctpAssocChange) not; association = new SctpAssociationImpl (sac.assocId(), sac.maxInStreams(), sac.maxOutStreams()); @@ -987,17 +982,17 @@ public class SctpChannelImpl extends SctpChannel SocketAddress target = messageInfo.address(); boolean unordered = messageInfo.isUnordered(); int ppid = messageInfo.payloadProtocolID(); - int pos = src.position(); - int lim = src.limit(); - - assert (pos <= lim && streamNumber >= 0); - int rem = (pos <= lim ? lim - pos : 0); if (src instanceof DirectBuffer) - return sendFromNativeBuffer(fd, src, rem, pos, target, streamNumber, + return sendFromNativeBuffer(fd, src, target, streamNumber, unordered, ppid); /* Substitute a native buffer */ + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim && streamNumber >= 0); + + int rem = (pos <= lim ? lim - pos : 0); ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); try { bb.put(src); @@ -1005,7 +1000,7 @@ public class SctpChannelImpl extends SctpChannel /* Do not update src until we see how many bytes were written */ src.position(pos); - int n = sendFromNativeBuffer(fd, bb, rem, pos, target, streamNumber, + int n = sendFromNativeBuffer(fd, bb, target, streamNumber, unordered, ppid); if (n > 0) { /* now update src */ @@ -1019,13 +1014,16 @@ public class SctpChannelImpl extends SctpChannel private int sendFromNativeBuffer(int fd, ByteBuffer bb, - int rem, - int pos, SocketAddress target, int streamNumber, boolean unordered, int ppid) throws IOException { + int pos = bb.position(); + int lim = bb.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, target, -1 /*121*/, streamNumber, unordered, ppid); if (written > 0) @@ -1097,6 +1095,5 @@ public class SctpChannelImpl extends SctpChannel java.security.AccessController.doPrivileged( new sun.security.action.LoadLibraryAction("sctp")); initIDs(); - nd = new SctpSocketDispatcher(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SctpMultiChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SctpMultiChannelImpl.java index b8457fdba27..45a360ddfee 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SctpMultiChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SctpMultiChannelImpl.java @@ -38,7 +38,6 @@ import java.util.HashSet; import java.util.HashMap; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; -import java.nio.channels.AlreadyBoundException; import java.nio.channels.ClosedChannelException; import java.nio.channels.NotYetBoundException; import java.nio.channels.spi.SelectorProvider; @@ -63,9 +62,6 @@ import static sun.nio.ch.SctpResultContainer.*; public class SctpMultiChannelImpl extends SctpMultiChannel implements SelChImpl { - /* Used to make native close and preClose calls */ - private static NativeDispatcher nd; - private final FileDescriptor fd; private final int fdVal; @@ -140,7 +136,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel synchronized (stateLock) { ensureOpen(); if (isBound()) - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); @@ -155,7 +151,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel if (isa.getAddress().isAnyLocalAddress()) wildcard = true; - Net.listen(fd, backlog < 1 ? 50 : backlog); + SctpNet.listen(fdVal, backlog < 1 ? 50 : backlog); } } } @@ -196,7 +192,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel if (add) { for (InetSocketAddress addr : localAddresses) { if (addr.getAddress().equals(address)) { - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); } } } else { /*removing */ @@ -284,7 +280,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel @Override public void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { - nd.preClose(fd); + SctpNet.preClose(fdVal); if (receiverThread != 0) NativeThread.signal(receiverThread); @@ -375,7 +371,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel /* Postpone the kill if there is a thread sending or receiving. */ if (receiverThread == 0 && senderThread == 0) { - nd.close(fd); + SctpNet.close(fdVal); state = ChannelState.KILLED; } else { state = ChannelState.KILLPENDING; @@ -846,16 +842,17 @@ public class SctpMultiChannelImpl extends SctpMultiChannel int streamNumber = messageInfo.streamNumber(); boolean unordered = messageInfo.isUnordered(); int ppid = messageInfo.payloadProtocolID(); - int pos = src.position(); - int lim = src.limit(); - assert (pos <= lim && streamNumber >= 0); - int rem = (pos <= lim ? lim - pos : 0); if (src instanceof DirectBuffer) - return sendFromNativeBuffer(fd, src, rem, pos, target, assocId, + return sendFromNativeBuffer(fd, src, target, assocId, streamNumber, unordered, ppid); /* Substitute a native buffer */ + int pos = src.position(); + int lim = src.limit(); + assert (pos <= lim && streamNumber >= 0); + + int rem = (pos <= lim ? lim - pos : 0); ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); try { bb.put(src); @@ -863,7 +860,7 @@ public class SctpMultiChannelImpl extends SctpMultiChannel /* Do not update src until we see how many bytes were written */ src.position(pos); - int n = sendFromNativeBuffer(fd, bb, rem, pos, target, assocId, + int n = sendFromNativeBuffer(fd, bb, target, assocId, streamNumber, unordered, ppid); if (n > 0) { /* now update src */ @@ -877,14 +874,17 @@ public class SctpMultiChannelImpl extends SctpMultiChannel private int sendFromNativeBuffer(int fd, ByteBuffer bb, - int rem, - int pos, SocketAddress target, int assocId, int streamNumber, boolean unordered, int ppid) throws IOException { + int pos = bb.position(); + int lim = bb.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, target, assocId, streamNumber, unordered, ppid); if (written > 0) @@ -981,6 +981,5 @@ public class SctpMultiChannelImpl extends SctpMultiChannel Util.load(); /* loads nio & net native libraries */ java.security.AccessController.doPrivileged( new sun.security.action.LoadLibraryAction("sctp")); - nd = new SctpSocketDispatcher(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java b/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java index f4cd5005f15..39019e7fd0a 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.nio.channels.AlreadyBoundException; import java.util.Set; import java.util.HashSet; import java.security.AccessController; @@ -52,8 +53,29 @@ public class SctpNet { return false; } + static boolean throwAlreadyBoundException() throws IOException { + throw new AlreadyBoundException(); + } + + static void listen(int fd, int backlog) throws IOException { + listen0(fd, backlog); + } + + static int connect(int fd, InetAddress remote, int remotePort) + throws IOException { + return connect0(fd, remote, remotePort); + } + + static void close(int fd) throws IOException { + close0(fd); + } + + static void preClose(int fd) throws IOException { + preClose0(fd); + } + /** - * @param oneToone + * @param oneToOne * if {@code true} returns a one-to-one sctp socket, otherwise * returns a one-to-many sctp socket */ @@ -240,6 +262,15 @@ public class SctpNet { /* Native Methods */ static native int socket0(boolean oneToOne) throws IOException; + static native void listen0(int fd, int backlog) throws IOException; + + static native int connect0(int fd, InetAddress remote, int remotePort) + throws IOException; + + static native void close0(int fd) throws IOException; + + static native void preClose0(int fd) throws IOException; + static native void bindx(int fd, InetAddress[] addrs, int port, int length, boolean add, boolean preferIPv6) throws IOException; @@ -271,5 +302,11 @@ public class SctpNet { throws IOException; static native void shutdown0(int fd, int assocId); + + static native void init(); + + static { + init(); + } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java index 5381591b7f0..740905a0941 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.Set; import java.util.HashSet; import java.nio.channels.SelectionKey; -import java.nio.channels.AlreadyBoundException; import java.nio.channels.ClosedChannelException; import java.nio.channels.NotYetBoundException; import java.nio.channels.spi.SelectorProvider; @@ -49,9 +48,6 @@ import com.sun.nio.sctp.SctpStandardSocketOption; public class SctpServerChannelImpl extends SctpServerChannel implements SelChImpl { - /* Used to make native close and preClose calls */ - private static NativeDispatcher nd; - private final FileDescriptor fd; private final int fdVal; @@ -103,7 +99,7 @@ public class SctpServerChannelImpl extends SctpServerChannel if (!isOpen()) throw new ClosedChannelException(); if (isBound()) - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); @@ -118,7 +114,7 @@ public class SctpServerChannelImpl extends SctpServerChannel if (isa.getAddress().isAnyLocalAddress()) wildcard = true; - Net.listen(fd, backlog < 1 ? 50 : backlog); + SctpNet.listen(fdVal, backlog < 1 ? 50 : backlog); } } return this; @@ -156,7 +152,7 @@ public class SctpServerChannelImpl extends SctpServerChannel if (add) { for (InetSocketAddress addr : localAddresses) { if (addr.getAddress().equals(address)) { - throw new AlreadyBoundException(); + SctpNet.throwAlreadyBoundException(); } } } else { /*removing */ @@ -261,7 +257,7 @@ public class SctpServerChannelImpl extends SctpServerChannel @Override public void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { - nd.preClose(fd); + SctpNet.preClose(fdVal); if (thread != 0) NativeThread.signal(thread); if (!isRegistered()) @@ -282,7 +278,7 @@ public class SctpServerChannelImpl extends SctpServerChannel // Postpone the kill if there is a thread in accept if (thread == 0) { - nd.close(fd); + SctpNet.close(fdVal); state = ChannelState.KILLED; } else { state = ChannelState.KILLPENDING; @@ -423,7 +419,6 @@ public class SctpServerChannelImpl extends SctpServerChannel Util.load(); // loads nio & net native libraries java.security.AccessController.doPrivileged( new sun.security.action.LoadLibraryAction("sctp")); - nd = new SctpSocketDispatcher(); initIDs(); } } diff --git a/jdk/src/solaris/classes/sun/nio/ch/SctpSocketDispatcher.java b/jdk/src/solaris/classes/sun/nio/ch/SctpSocketDispatcher.java deleted file mode 100644 index 937a7392496..00000000000 --- a/jdk/src/solaris/classes/sun/nio/ch/SctpSocketDispatcher.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.ch; - -import java.io.IOException; -import java.io.FileDescriptor; - -/** - * Only used for {@code close} and {@code preclose}. All other methods - * throw {@code IOException}. - */ -class SctpSocketDispatcher extends NativeDispatcher { - @Override - @SuppressWarnings("unused") - int read(FileDescriptor fd, long address, int len) throws IOException { - throw new IOException("Operation Unsupported"); - } - - @Override - @SuppressWarnings("unused") - long readv(FileDescriptor fd, long address, int len) throws IOException { - throw new IOException("Operation Unsupported"); - } - - @Override - @SuppressWarnings("unused") - int write(FileDescriptor fd, long address, int len) throws IOException { - throw new IOException("Operation Unsupported"); - } - - @Override - @SuppressWarnings("unused") - long writev(FileDescriptor fd, long address, int len) throws IOException { - throw new IOException("Operation Unsupported"); - } - - @Override - void close(FileDescriptor fd) throws IOException { - FileDispatcherImpl.close0(fd); - } - - @Override - void preClose(FileDescriptor fd) throws IOException { - FileDispatcherImpl.preClose0(fd); - } -} diff --git a/jdk/src/solaris/native/sun/nio/ch/SctpNet.c b/jdk/src/solaris/native/sun/nio/ch/SctpNet.c index 85611bd0d9d..61d7764d23e 100644 --- a/jdk/src/solaris/native/sun/nio/ch/SctpNet.c +++ b/jdk/src/solaris/native/sun/nio/ch/SctpNet.c @@ -48,6 +48,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad return JNI_VERSION_1_2; } +static int preCloseFD = -1; /* File descriptor to which we dup other fd's + before closing them for real */ + /** * Loads the native sctp library that contains the socket extension * functions, as well as locating the individual functions. @@ -107,6 +110,55 @@ jboolean loadSocketExtensionFuncs return JNI_TRUE; } +jint +handleSocketError(JNIEnv *env, jint errorValue) +{ + char *xn; + switch (errorValue) { + case EINPROGRESS: /* Non-blocking connect */ + return 0; + case EPROTO: + xn= JNU_JAVANETPKG "ProtocolException"; + break; + case ECONNREFUSED: + xn = JNU_JAVANETPKG "ConnectException"; + break; + case ETIMEDOUT: + xn = JNU_JAVANETPKG "ConnectException"; + break; + case EHOSTUNREACH: + xn = JNU_JAVANETPKG "NoRouteToHostException"; + break; + case EADDRINUSE: /* Fall through */ + case EADDRNOTAVAIL: + xn = JNU_JAVANETPKG "BindException"; + break; + default: + xn = JNU_JAVANETPKG "SocketException"; + break; + } + errno = errorValue; + JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); + return IOS_THROWN; +} + +/* + * Class: sun_nio_ch_SctpNet + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_sun_nio_ch_SctpNet_init + (JNIEnv *env, jclass cl) { + int sp[2]; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); + return; + } + preCloseFD = sp[0]; + close(sp[1]); +} + /* * Class: sun_nio_ch_SctpNet * Method: socket0 @@ -184,6 +236,76 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_bindx free(sap); } +/* + * Class: sun_nio_ch_SctpNet + * Method: listen0 + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_sun_nio_ch_SctpNet_listen0 + (JNIEnv *env, jclass cl, jint fd, jint backlog) { + if (listen(fd, backlog) < 0) + handleSocketError(env, errno); +} + +/* + * Class: sun_nio_ch_SctpNet + * Method: connect0 + * Signature: (ILjava/net/InetAddress;I)I + */ +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SctpNet_connect0 + (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) { + SOCKADDR sa; + int sa_len = SOCKADDR_LEN; + int rv; + + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, + &sa_len, JNI_TRUE) != 0) { + return IOS_THROWN; + } + + rv = connect(fd, (struct sockaddr *)&sa, sa_len); + if (rv != 0) { + if (errno == EINPROGRESS) { + return IOS_UNAVAILABLE; + } else if (errno == EINTR) { + return IOS_INTERRUPTED; + } + return handleSocketError(env, errno); + } + return 1; +} + +/* + * Class: sun_nio_ch_SctpNet + * Method: close0 + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_sun_nio_ch_SctpNet_close0 + (JNIEnv *env, jclass clazz, jint fd) { + if (fd != -1) { + int rv = close(fd); + if (rv < 0) + JNU_ThrowIOExceptionWithLastError(env, "Close failed"); + } +} + +/* + * Class: sun_nio_ch_SctpNet + * Method: preClose0 + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_sun_nio_ch_SctpNet_preClose0 + (JNIEnv *env, jclass clazz, jint fd) { + if (preCloseFD >= 0) { + if (dup2(preCloseFD, fd) < 0) + JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); + } +} + void initializeISA (JNIEnv* env) { if (isaCls == 0) { @@ -394,7 +516,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setIntOption0 arglen = sizeof(arg); } - if (setsockopt(fd, klevel, kopt, parg, arglen) < 0) { + if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun_nio_ch_SctpNet.setIntOption0"); } @@ -427,7 +549,7 @@ JNIEXPORT int JNICALL Java_sun_nio_ch_SctpNet_getIntOption0 arglen = sizeof(result); } - if (getsockopt(fd, klevel, kopt, arg, &arglen) < 0) { + if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.getIntOption"); return -1; diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index 0b43ab0d516..e14ac2fc659 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -445,20 +445,17 @@ public class WindowsAsynchronousFileChannelImpl // 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); + // initiate read + n = readFile(handle, address, rem, position, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + return; + } else if (n == IOStatus.EOF) { result.setResult(n); + } else { + throw new InternalError("Unexpected result: " + n); } + } catch (Throwable x) { // failed to initiate read result.setFailure(toIOException(x)); @@ -466,12 +463,9 @@ public class WindowsAsynchronousFileChannelImpl end(); } - // read failed or EOF so completion port will not be notified - if (n < 0 && overlapped != 0L) { + // release resources + if (overlapped != 0L) ioCache.remove(overlapped); - } - - // return direct buffer to cache if substituted releaseBufferIfSubstituted(); // invoke completion handler @@ -634,20 +628,15 @@ public class WindowsAsynchronousFileChannelImpl // 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); + // initiate the write + n = writeFile(handle, address, rem, position, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + return; + } else { + throw new InternalError("Unexpected result: " + n); } + } catch (Throwable x) { // failed to initiate read: result.setFailure(toIOException(x)); diff --git a/jdk/src/windows/native/java/net/SocketInputStream.c b/jdk/src/windows/native/java/net/SocketInputStream.c index 54c9a8a88fe..bbf6a9ac6fc 100644 --- a/jdk/src/windows/native/java/net/SocketInputStream.c +++ b/jdk/src/windows/native/java/net/SocketInputStream.c @@ -121,6 +121,9 @@ Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this, newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); if (newfd == -1) { NET_ThrowSocketException(env, "Socket Closed"); + if (bufP != BUF) { + free(bufP); + } return -1; } } diff --git a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c index d8346ba3e7a..cf742116c79 100644 --- a/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c @@ -39,7 +39,6 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_readFile(JNIEnv* env, jclass 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; @@ -49,7 +48,7 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_readFile(JNIEnv* env, jclass res = ReadFile((HANDLE) jlong_to_ptr(handle), (LPVOID) jlong_to_ptr(address), (DWORD)len, - &nread, + NULL, lpOverlapped); if (res == 0) { @@ -62,7 +61,7 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_readFile(JNIEnv* env, jclass return IOS_THROWN; } - return (jint)nread; + return IOS_UNAVAILABLE; } JNIEXPORT jint JNICALL @@ -70,7 +69,6 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_writeFile(JNIEnv* env, jclass 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; @@ -80,18 +78,18 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_writeFile(JNIEnv* env, jclass res = WriteFile((HANDLE)jlong_to_ptr(handle), (LPVOID) jlong_to_ptr(address), (DWORD)len, - &nwritten, + NULL, lpOverlapped); if (res == 0) { int error = GetLastError(); - if (error == ERROR_IO_PENDING) { + if (error == ERROR_IO_PENDING) return IOS_UNAVAILABLE; - } JNU_ThrowIOExceptionWithLastError(env, "WriteFile failed"); return IOS_THROWN; } - return (jint)nwritten; + + return IOS_UNAVAILABLE; } JNIEXPORT jint JNICALL diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 25f0dc1ed6f..bffa3ad7cb0 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -291,7 +291,7 @@ TESTEXIT = \ fi ; \ testExitCode=`$(CAT) $(EXITCODE)`; \ $(ECHO) "EXIT CODE: $${testExitCode}"; \ - exit ${testExitCode} + exit $${testExitCode} BUNDLE_UP_AND_EXIT = \ ( \ @@ -300,7 +300,7 @@ BUNDLE_UP_AND_EXIT = \ $(RM) -f $(STATS_TXT) $(RUNLIST) $(PASSLIST) $(FAILLIST) $(EXITCODE); \ $(ECHO) "$${jtregExitCode}" > $(EXITCODE); \ if [ -r "$${_summary}" ] ; then \ - $(ECHO) "Summary: $${_summary}" > $(STATS_TXT); \ + $(ECHO) "Summary: $(UNIQUE_DIR)" > $(STATS_TXT); \ $(EXPAND) $${_summary} | $(EGREP) -v ' Not run\.' > $(RUNLIST); \ $(EGREP) ' Passed\.' $(RUNLIST) \ | $(EGREP) -v ' Error\.' \ @@ -370,7 +370,8 @@ ifndef USE_JTREG_SAMEVM endif # With samevm, you cannot use -javaoptions? ifeq ($(USE_JTREG_SAMEVM),true) - EXTRA_JTREG_OPTIONS += -samevm $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%) + JTREG_SAMEVM_OPTION = -samevm + EXTRA_JTREG_OPTIONS += $(JTREG_SAMEVM_OPTION) $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%) JTREG_TEST_OPTIONS = $(JAVA_VM_ARGS:%=-vmoption:%) else JTREG_TEST_OPTIONS = $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%) @@ -418,8 +419,9 @@ $(ECHO) "Running tests in othervm mode: $(call TestDirs, $?)" $(MAKE) TESTDIRS="$(call TestDirs, $?)" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests endef define SummaryInfo -$(ECHO) "Summary for: $?" +$(ECHO) "########################################################" $(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME)) +$(ECHO) "########################################################" endef # ------------------------------------------------------------------ @@ -446,10 +448,14 @@ JDK_ALL_TARGETS += jdk_beans2 jdk_beans2: java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \ java/beans/PropertyEditor $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests JDK_ALL_TARGETS += jdk_beans3 jdk_beans3: java/beans/XMLEncoder $(call RunOthervmBatch) +# All beans tests jdk_beans: jdk_beans1 jdk_beans2 jdk_beans3 @$(SummaryInfo) @@ -475,6 +481,7 @@ JDK_ALL_TARGETS += jdk_management2 jdk_management2: com/sun/jmx com/sun/management sun/management $(call RunOthervmBatch) +# All management tests jdk_management: jdk_management1 jdk_management2 @$(SummaryInfo) @@ -506,10 +513,14 @@ JDK_ALL_TARGETS += jdk_nio2 jdk_nio2: java/nio/Buffer java/nio/ByteOrder \ java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests JDK_ALL_TARGETS += jdk_nio3 jdk_nio3: com/sun/nio sun/nio $(call RunOthervmBatch) +# All nio tests jdk_nio: jdk_nio1 jdk_nio2 jdk_nio3 @$(SummaryInfo) @@ -529,10 +540,14 @@ jdk_security1: java/security JDK_ALL_TARGETS += jdk_security2 jdk_security2: javax/crypto com/sun/crypto $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests JDK_ALL_TARGETS += jdk_security3 jdk_security3: com/sun/security lib/security javax/security sun/security $(call RunOthervmBatch) +# All security tests jdk_security: jdk_security1 jdk_security2 jdk_security3 @$(SummaryInfo) @@ -547,15 +562,18 @@ JDK_ALL_TARGETS += jdk_text jdk_text: java/text sun/text $(call RunSamevmBatch) -# Stable othervm testruns (minus items from PROBLEM_LIST) -# Using samevm has serious problems with these tests +# Stable samevm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_tools1 jdk_tools1: com/sun/jdi $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests JDK_ALL_TARGETS += jdk_tools2 jdk_tools2: com/sun/tools sun/jvmstat sun/tools tools vm com/sun/servicetag com/sun/tracing $(call RunOthervmBatch) +# All tools tests jdk_tools: jdk_tools1 jdk_tools2 @$(SummaryInfo) @@ -567,7 +585,9 @@ jdk_util: java/util sun/util # ------------------------------------------------------------------ # Run all tests -jdk_all: $(filter-out jdk_awt jdk_rmi jdk_swing, $(JDK_ALL_TARGETS)) +FILTER_OUT_LIST=jdk_awt jdk_rmi jdk_swing +JDK_ALL_STABLE_TARGETS := $(filter-out $(FILTER_OUT_LIST), $(JDK_ALL_TARGETS)) +jdk_all: $(JDK_ALL_STABLE_TARGETS) @$(SummaryInfo) # These are all phony targets @@ -581,16 +601,22 @@ JTREG = $(JT_HOME)/win32/bin/jtreg JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS) # Only run automatic tests JTREG_BASIC_OPTIONS += -a +# Always turn on assertions +JTREG_ASSERT_OPTION = -ea -esa +JTREG_BASIC_OPTIONS += $(JTREG_ASSERT_OPTION) # Report details on all failed or error tests, times too JTREG_BASIC_OPTIONS += -v:fail,error,time # Retain all files for failing tests JTREG_BASIC_OPTIONS += -retain:fail,error # Ignore tests are not run and completely silent about it -JTREG_BASIC_OPTIONS += -ignore:quiet -# Multiple by 2 the timeout numbers -JTREG_BASIC_OPTIONS += -timeoutFactor:2 +JTREG_IGNORE_OPTION = -ignore:quiet +JTREG_BASIC_OPTIONS += $(JTREG_IGNORE_OPTION) +# Multiple by 4 the timeout numbers +JTREG_TIMEOUT_OPTION = -timeoutFactor:4 +JTREG_BASIC_OPTIONS += $(JTREG_TIMEOUT_OPTION) # Boost the max memory for jtreg to avoid gc thrashing -JTREG_BASIC_OPTIONS += -J-Xmx512m +JTREG_MEMORY_OPTION = -J-Xmx512m +JTREG_BASIC_OPTIONS += $(JTREG_MEMORY_OPTION) # Make sure jtreg exists $(JTREG): $(JT_HOME) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 2edcfd4d595..43d53e18b12 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -431,6 +431,11 @@ java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all # jdk_management +# Fails on Windows 2000, Test failed for iiop java.lang.NullPointerException +# at org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke(Unknown Source) +# at com.sun.corba.se.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:653) +javax/management/remote/mandatory/connection/ReconnectTest.java generic-all + # Solaris 10 sparc, NPE from org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke javax/management/remote/mandatory/threads/ExecutorTest.java generic-all @@ -494,10 +499,6 @@ javax/management/monitor/AttributeArbitraryDataTypeTest.java generic-all # Problems with rounding add failures on solaris-sparcv9 and -server java/math/BigDecimal/AddTests.java solaris-sparcv9 -# Problems on windows with samevm, missing inputstream close()? -# Also times out on solaris-sparcv9 -server -java/math/BigInteger/BigIntegerTest.java generic-all - # Should be samevm? But seems problematic with samevm on windows java/math/BigInteger/ModPow65537.java generic-all @@ -570,6 +571,7 @@ javax/print/attribute/ChromaticityValues.java generic-all javax/print/attribute/GetCopiesSupported.java generic-all javax/print/attribute/SidesPageRangesTest.java generic-all javax/print/attribute/SupportedPrintableAreas.java generic-all +javax/print/attribute/AttributeTest.java generic-all # Only print test left, excluding just because all print tests have been javax/print/attribute/MediaMappingsTest.java generic-all @@ -581,6 +583,14 @@ javax/print/attribute/MediaMappingsTest.java generic-all # Suspect many of these tests auffer from using fixed ports, no concrete # evidence. +# Dies on Solaris 10 sparc and sparcv9, Linux -ea -esa with +# Interrupted or IO exception, maybe writing to non-unique named file? +com/sun/net/httpserver/bugs/B6373555.java generic-all + +# Dies on pretty much all platforms when run with -ea -esa, Assertion error +java/net/CookieHandler/TestHttpCookie.java generic-all +java/net/URLClassLoader/closetest/CloseTest.java generic-all + # Fails on OpenSolaris, BindException unexpected java/net/BindException/Test.java generic-all @@ -717,6 +727,9 @@ sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java generic-all # Connection refused, windows samevm sun/net/www/protocol/http/DigestTest.java generic-all +# Fails on Fedora 9 32bit & 64bit & Solaris 10, wrong proxy for http://localhost/index.html +java/net/ProxySelector/B6737819.java generic-all + ############################################################################ # jdk_nio @@ -724,6 +737,33 @@ sun/net/www/protocol/http/DigestTest.java generic-all # Suspect many of these tests auffer from using fixed ports, no concrete # evidence. +# Fails with -ea -esa, Assertion error, but only on Solaris 10 machines? +com/sun/nio/sctp/SctpChannel/Send.java generic-all +com/sun/nio/sctp/SctpChannel/Shutdown.java generic-all + +# Fails on Windows 2000, Can't delete test directory .\x.SetLastModified.dir +# at SetLastModified.main(SetLastModified.java:107) +java/io/File/SetLastModified.java generic-all + +# Fails on Solaris 10 x64, address already in use +java/nio/channels/DatagramChannel/SRTest.java generic-all + +# Fails on Solaris 10 x86, times out +java/nio/channels/DatagramChannel/Sender.java generic-all + +# Fails on Fedora 9 x86, address in use +java/nio/channels/Selector/SelectWrite.java generic-all + +# Fails on Fedora 9 32bit times out +java/nio/channels/DatagramChannel/EmptyBuffer.java generic-all + +# Fails on Windows 2000, ExceptionInInitializerError +# in WindowsAsynchronousServerSocketChannelImpl.java:316 +java/nio/channels/AsynchronousChannelGroup/Unbounded.java generic-all + +# Fails on Windows 2000, times out +java/nio/channels/FileChannel/Transfer.java generic-all + # Fails on OpenSolaris, IllegalStateException: Cannot add or remove addresses # from a channel that is bound to the wildcard address com/sun/nio/sctp/SctpChannel/Bind.java generic-all @@ -893,6 +933,48 @@ java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java generic-all # jdk_security +# Fails with -ea -esa, but only on Solaris sparc? Suspect it is timing out +sun/security/tools/keytool/standard.sh generic-all + +# Fails on Solaris 10 X64, address already in use +sun/security/krb5/auto/HttpNegotiateServer.java generic-all + +# Fails on almost all platforms +# java.lang.UnsupportedClassVersionError: SerialTest : +# Unsupported major.minor version 51.0 +# at java.lang.ClassLoader.defineClass1(Native Method) +sun/security/util/Oid/S11N.sh generic-all + +# Fails on Fedora 9 32bit +# GSSException: Failure unspecified at GSS-API level (Mechanism level: +# Invalid argument (400) - Cannot find key of appropriate type to decrypt +# AP REP - DES CBC mode with MD5) +# at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:778) +sun/security/krb5/auto/NonMutualSpnego.java generic-all + +# Fails on Solaris 10 sparc, GSSException: Failure unspecified at GSS-API level +# Also fails on Windows 2000 similar way +sun/security/krb5/auto/ok-as-delegate.sh generic-all + +# Fails on Windows 2000, GSSException: Failure unspecified at GSS-API level +# (Mechanism level: Request is a replay (34)) +sun/security/krb5/auto/ok-as-delegate-xrealm.sh generic-all + +# Fails on Windows 2000, ExceptionInInitializerError +sun/security/mscapi/AccessKeyStore.sh generic-all + +# Fails on Windows 2000, UnsatisfiedLinkError: libnspr4.dll: Access is denied +sun/security/pkcs11/KeyAgreement/TestDH.java generic-all + +# Fails on Windows 2000, UnsatisfiedLinkError: libnspr4.dll: Access is denied +sun/security/pkcs11/fips/ClientJSSEServerJSSE.java generic-all + +# Fails on Solaris 10, KrbException: Additional pre-authentication required (25) +sun/security/krb5/auto/basic.sh generic-all + +# Fails on Fedora 9 64bit, PKCS11Exception: CKR_DEVICE_ERROR +sun/security/pkcs11/KeyAgreement/TestDH.java generic-all + # Run too slow on Solaris 10 sparc sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/SSLSocketTimeoutNulls.java solaris-sparc sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientTimeout.java solaris-sparc @@ -1088,6 +1170,16 @@ java/text/Bidi/Bug6665028.java linux-x64 # So most if not all tools tests are now being run with "othervm" mode. # Some of these tools tests have a tendency to use fixed ports, bad idea. +# Fails with -ea -esa on Solaris, Assertion error (Solaris specific test) +com/sun/tracing/BasicFunctionality.java generic-all + +# Fails on Fedora 9 32bit, jps output differs problem +sun/tools/jstatd/jstatdDefaults.sh generic-all + +# Fails on Linux Fedora 9 32bit, Could not read data for remote JVM 16133 +# jstat output differs from expected output +sun/tools/jstatd/jstatdExternalRegistry.sh generic-all + # Output of jps differs from expected output. # Invalid argument count on solaris-sparc and x64 sun/tools/jstatd/jstatdPort.sh generic-all @@ -1099,6 +1191,11 @@ sun/tools/jps/jps-lm.sh generic-all sun/tools/jps/jps-Vvml_2.sh generic-all sun/tools/jps/jps-m_2.sh generic-all +# Fails on Solaris 10 sparcv9, shell exits with 1 +# Turning off use of shared archive because of choice of garbage collector or large pages +# Could not synchronize with target +sun/tools/jps/jps-v_1.sh generic-all + # Fails on OpenSolaris "Could not synchronize with target" sun/tools/jps/jps-Defaults.sh generic-all sun/tools/jps/jps-V_2.sh generic-all @@ -1160,6 +1257,12 @@ tools/jar/index/MetaInf.java windows-all # jdk_util +# Fails with -ea -esa on all platforms with Assertion error +java/util/ResourceBundle/Test4300693.java generic-all + +# Failing on all -client 32bit platforms starting with b77? See 6908348. +java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java generic-all + # Assert error, failures, on Linux Fedora 9 -server # Windows samevm failure, assert error "Passed = 134, failed = 2" java/util/Arrays/ArrayObjectMethods.java generic-all diff --git a/jdk/test/com/sun/jdi/NoLaunchOptionTest.java b/jdk/test/com/sun/jdi/NoLaunchOptionTest.java index b65b375c85e..14e6acd2c5d 100644 --- a/jdk/test/com/sun/jdi/NoLaunchOptionTest.java +++ b/jdk/test/com/sun/jdi/NoLaunchOptionTest.java @@ -31,6 +31,9 @@ * @build VMConnection * @run main/othervm NoLaunchOptionTest */ + +import java.net.ServerSocket; + public class NoLaunchOptionTest extends Object { private Process subprocess; private int subprocessStatus; @@ -121,12 +124,19 @@ public class NoLaunchOptionTest extends Object { } public static void main(String[] args) throws Exception { + // find a free port + ServerSocket ss = new ServerSocket(0); + int port = ss.getLocalPort(); + ss.close(); + String address = String.valueOf(port); + String javaExe = System.getProperty("java.home") + java.io.File.separator + "bin" + java.io.File.separator + "java"; String targetClass = "NotAClass"; String cmds [] = {javaExe, - "-agentlib:jdwp=transport=dt_socket,address=8000," + + "-agentlib:jdwp=transport=dt_socket,address=" + + address + "," + "onthrow=java.lang.ClassNotFoundException,suspend=n", targetClass}; NoLaunchOptionTest myTest = new NoLaunchOptionTest(); diff --git a/jdk/test/com/sun/jdi/OptionTest.java b/jdk/test/com/sun/jdi/OptionTest.java index e3d6eb60b2d..f6124d3e02a 100644 --- a/jdk/test/com/sun/jdi/OptionTest.java +++ b/jdk/test/com/sun/jdi/OptionTest.java @@ -32,6 +32,9 @@ * @run compile -g VMConnection.java * @run main/othervm OptionTest */ + +import java.net.ServerSocket; + public class OptionTest extends Object { private Process subprocess; private int subprocessStatus; @@ -122,12 +125,18 @@ public class OptionTest extends Object { } public static void main(String[] args) throws Exception { + // find a free port + ServerSocket ss = new ServerSocket(0); + int port = ss.getLocalPort(); + ss.close(); + String address = String.valueOf(port); + String javaExe = System.getProperty("java.home") + java.io.File.separator + "bin" + java.io.File.separator + "java"; String targetClass = "HelloWorld"; String baseOptions = "transport=dt_socket" + - ",address=8000" + + ",address=" + address + ",server=y" + ",suspend=n"; diff --git a/jdk/test/com/sun/jdi/ProcessAttachTest.sh b/jdk/test/com/sun/jdi/ProcessAttachTest.sh index 38ce59fc240..e1ec05996f7 100644 --- a/jdk/test/com/sun/jdi/ProcessAttachTest.sh +++ b/jdk/test/com/sun/jdi/ProcessAttachTest.sh @@ -54,10 +54,14 @@ JAVA="${TESTJAVA}/bin/java" OS=`uname -s` case "$OS" in - Windows* | CYGWIN_NT*) + Windows*) PS=";" OS="Windows" ;; + CYGWIN*) + PS=";" + OS="CYGWIN" + ;; * ) PS=":" ;; @@ -67,16 +71,23 @@ startDebuggee() { OUTPUTFILE=${TESTCLASSES}/Debuggee.out ${JAVA} "$@" > ${OUTPUTFILE} & - pid="$!" + startpid="$!" + pid="${startpid}" + # CYGWIN startpid is not the native windows PID we want, get the WINPID + if [ "${OS}" = "CYGWIN" ]; then + sleep 2 + ps -l -p ${startpid} + pid=`ps -l -p ${startpid} | tail -1 | awk '{print $4;}'` + fi + # MKS creates an intermediate shell to launch ${JAVA} so - # ${pid} is not the actual pid. We have put in a small sleep + # ${startpid} is not the actual pid. We have put in a small sleep # to give the intermediate shell process time to launch the # "java" process. if [ "$OS" = "Windows" ]; then sleep 2 - realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` - pid=${realpid} + pid=`ps -o pid,ppid,comm|grep ${startpid}|grep "java"|cut -c1-6` fi echo "Waiting for Debuggee to initialize..." @@ -91,7 +102,7 @@ startDebuggee() echo "Waiting $attempts second(s) ..." done - echo "Debuggee is process $pid" + echo "Debuggee is process $pid (startpid=${startpid})" } stopDebuggee() @@ -100,7 +111,7 @@ stopDebuggee() if [ $? != 0 ] ; then echo "Error: ShutdownDebuggee failed" failures=`expr $failures + 1` - kill -9 $pid + kill -9 ${startpid} fi } @@ -123,7 +134,7 @@ startDebuggee \ -agentlib:jdwp=transport=dt_socket,server=y,suspend=n \ -classpath "${TESTCLASSES}" ProcessAttachDebuggee "${PORTFILE}" -$JAVA -classpath ${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVA -classpath "${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar" \ ProcessAttachDebugger $pid 2>&1 if [ $? != 0 ]; then failures=`expr $failures + 1`; fi @@ -141,7 +152,7 @@ startDebuggee \ -agentlib:jdwp=transport=dt_socket,server=y,suspend=y \ -classpath "${TESTCLASSES}" ProcessAttachDebuggee "${PORTFILE}" -$JAVA -classpath ${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVA -classpath "${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar" \ ProcessAttachDebugger $pid 2>&1 # The debuggee is suspended and doesn't run until the debugger diff --git a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh index 6331d562987..c9570cd0b35 100644 --- a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh +++ b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh @@ -51,7 +51,7 @@ case "$OS" in Linux ) PS=":" ;; - Windows* ) + Windows* | CYGWIN*) PS=";" ;; * ) @@ -71,7 +71,7 @@ SOMEOTHERDIR="${TESTCLASSES}"/someotherdir $JAVAC -d "${TESTCLASSES}" "${TESTSRC}"/JdiLoadedByCustomLoader.java mkdir "${SOMEOTHERDIR}" -$JAVAC -d "${SOMEOTHERDIR}" -classpath ${TESTSRC}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVAC -d "${SOMEOTHERDIR}" -classpath "${TESTSRC}${PS}${TESTJAVA}/lib/tools.jar" \ "${TESTSRC}"/ListConnectors.java # Run the test diff --git a/jdk/test/com/sun/nio/sctp/SctpChannel/Connect.java b/jdk/test/com/sun/nio/sctp/SctpChannel/Connect.java index 78cb52770ba..33f4441d356 100644 --- a/jdk/test/com/sun/nio/sctp/SctpChannel/Connect.java +++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Connect.java @@ -192,6 +192,18 @@ public class Connect { testCCE(new Callable() { public Void call() throws IOException { cceChannel.finishConnect(); return null; } }); + + /* TEST 8: IOException: Connection refused. Exercises handleSocketError. + * Assumption: no sctp socket listening on 3456 */ + SocketAddress addr = new InetSocketAddress("localhost", 3456); + channel = SctpChannel.open(); + try { + channel.connect(addr); + fail("should have thrown ConnectException: Connection refused"); + } catch (IOException ioe) { + pass(); + } + } catch (IOException ioe) { unexpected(ioe); } finally { diff --git a/jdk/test/com/sun/nio/sctp/SctpChannel/Send.java b/jdk/test/com/sun/nio/sctp/SctpChannel/Send.java index 3cee201d739..3a62147e9dc 100644 --- a/jdk/test/com/sun/nio/sctp/SctpChannel/Send.java +++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Send.java @@ -112,9 +112,6 @@ public class Send { /* Receive CommUp */ channel.receive(buffer, null, handler); - /* save for TEST 8 */ - Association association = channel.association(); - /* TEST 2: send small message */ int streamNumber = 0; debug("sending on stream number: " + streamNumber); @@ -250,6 +247,29 @@ public class Send { pass(); debug("OK, caught " + e); } + + /* TEST 9: Send from heap buffer to force implementation to + * substitute with a native buffer, then check that its position + * is updated correctly */ + buffer.clear(); + info = MessageInfo.createOutgoing(null, 0); + buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1")); + buffer.flip(); + final int offset = 1; + buffer.position(offset); + remaining = buffer.remaining(); + + debug("sending small message: " + buffer); + try { + sent = channel.send(buffer, info); + + check(sent == remaining, "sent should be equal to remaining"); + check(buffer.position() == (offset + sent), + "buffers position should have been incremented by sent"); + } catch (IllegalArgumentException iae) { + fail(iae + ", Error updating buffers position"); + } + } catch (IOException ioe) { unexpected(ioe); } finally { @@ -335,6 +355,30 @@ public class Send { /* TEST 7 ++ */ sc2 = ssc.accept(); + /* TEST 9 */ + ByteBuffer expected = ByteBuffer.allocate(Util.SMALL_BUFFER); + expected.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1")); + expected.flip(); + final int offset = 1; + expected.position(offset); + buffer.clear(); + do { + info = sc2.receive(buffer, null, null); + if (info == null) { + fail("Server: unexpected null from receive"); + return; + } + } while (!info.isComplete()); + + buffer.flip(); + check(info != null, "info is null"); + check(info.streamNumber() == 0, "message not sent on the correct stream"); + check(info.bytes() == expected.remaining(), + "bytes received not equal to message length"); + check(info.bytes() == buffer.remaining(), "bytes != remaining"); + check(expected.equals(buffer), + "received message not the same as sent message"); + clientFinishedLatch.await(10L, TimeUnit.SECONDS); serverFinishedLatch.countDown(); } catch (IOException ioe) { diff --git a/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java b/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java index d5715b17198..f5814a17bc5 100644 --- a/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java +++ b/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java @@ -104,7 +104,9 @@ public class SocketOptionTests { sc.setOption(SCTP_NODELAY, true); checkOption(sc, SCTP_NODELAY, true); sc.setOption(SO_SNDBUF, 16*1024); + checkOption(sc, SO_SNDBUF, 16*1024); sc.setOption(SO_RCVBUF, 16*1024); + checkOption(sc, SO_RCVBUF, 16*1024); checkOption(sc, SO_LINGER, -1); /* default should be negative */ sc.setOption(SO_LINGER, 2000); checkOption(sc, SO_LINGER, 2000); diff --git a/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Send.java b/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Send.java index b7d1379d174..1f56c5df67e 100644 --- a/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Send.java +++ b/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Send.java @@ -185,6 +185,27 @@ public class Send { /* TEST 5: getRemoteAddresses(Association) */ channel.getRemoteAddresses(assoc); + /* TEST 6: Send from heap buffer to force implementation to + * substitute with a native buffer, then check that its position + * is updated correctly */ + info = MessageInfo.createOutgoing(assoc, null, 0); + buffer.clear(); + buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1")); + buffer.flip(); + final int offset = 1; + buffer.position(offset); + remaining = buffer.remaining(); + + try { + sent = channel.send(buffer, info); + + check(sent == remaining, "sent should be equal to remaining"); + check(buffer.position() == (offset + sent), + "buffers position should have been incremented by sent"); + } catch (IllegalArgumentException iae) { + fail(iae + ", Error updating buffers position"); + } + } catch (IOException ioe) { unexpected(ioe); } finally { @@ -284,6 +305,30 @@ public class Send { bytes = serverChannel.send(buffer, info); debug("Server: sent " + bytes + "bytes"); + /* TEST 6 */ + ByteBuffer expected = ByteBuffer.allocate(Util.SMALL_BUFFER); + expected.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1")); + expected.flip(); + final int offset = 1; + expected.position(offset); + buffer.clear(); + do { + info = serverChannel.receive(buffer, null, null); + if (info == null) { + fail("Server: unexpected null from receive"); + return; + } + } while (!info.isComplete()); + + buffer.flip(); + check(info != null, "info is null"); + check(info.streamNumber() == 0, "message not sent on the correct stream"); + check(info.bytes() == expected.remaining(), + "bytes received not equal to message length"); + check(info.bytes() == buffer.remaining(), "bytes != remaining"); + check(expected.equals(buffer), + "received message not the same as sent message"); + clientFinishedLatch.await(10L, TimeUnit.SECONDS); serverFinishedLatch.countDown(); } catch (IOException ioe) { diff --git a/jdk/test/com/sun/tools/attach/ApplicationSetup.sh b/jdk/test/com/sun/tools/attach/ApplicationSetup.sh index fa8509ec394..0bd7a1b5693 100644 --- a/jdk/test/com/sun/tools/attach/ApplicationSetup.sh +++ b/jdk/test/com/sun/tools/attach/ApplicationSetup.sh @@ -49,7 +49,11 @@ startApplication() # "java" process. if [ "$OS" = "Windows" ]; then sleep 2 - realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` + if [ "${isCygwin}" = "true" ] ; then + realpid=`ps -p ${pid} | tail -1 | awk '{print $4;}'` + else + realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` + fi pid=${realpid} fi @@ -57,7 +61,7 @@ startApplication() attempts=0 while true; do sleep 1 - port=`tail -1 ${OUTPUTFILE}` + port=`tail -1 ${OUTPUTFILE} | sed -e 's@\\r@@g' ` if [ ! -z "$port" ]; then # In case of errors wait time for output to be flushed sleep 1 diff --git a/jdk/test/com/sun/tools/attach/BasicTests.sh b/jdk/test/com/sun/tools/attach/BasicTests.sh index a960b40e15d..f5c4076581e 100644 --- a/jdk/test/com/sun/tools/attach/BasicTests.sh +++ b/jdk/test/com/sun/tools/attach/BasicTests.sh @@ -48,7 +48,7 @@ failures=0 echo "Running tests ..." -$JAVA -classpath ${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVA -classpath "${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar" \ BasicTests $pid $agent $badagent $redefineagent 2>&1 if [ $? != 0 ]; then failures=`expr $failures + 1`; fi diff --git a/jdk/test/com/sun/tools/attach/CommonSetup.sh b/jdk/test/com/sun/tools/attach/CommonSetup.sh index 1520ca72b57..66d90fafddd 100644 --- a/jdk/test/com/sun/tools/attach/CommonSetup.sh +++ b/jdk/test/com/sun/tools/attach/CommonSetup.sh @@ -49,6 +49,12 @@ case "$OS" in OS="Windows" FS="\\" ;; + CYGWIN* ) + PS=";" + OS="Windows" + FS="\\" + isCygwin=true + ;; * ) echo "Unrecognized system!" exit 1; diff --git a/jdk/test/com/sun/tools/attach/PermissionTests.sh b/jdk/test/com/sun/tools/attach/PermissionTests.sh index 908e93ec077..54a7e61a7e0 100644 --- a/jdk/test/com/sun/tools/attach/PermissionTests.sh +++ b/jdk/test/com/sun/tools/attach/PermissionTests.sh @@ -48,7 +48,7 @@ startApplication echo "Deny test" # deny -$JAVA -classpath ${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVA -classpath "${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar" \ -Djava.security.manager \ -Djava.security.policy=${TESTSRC}/java.policy.deny \ PermissionTest $pid true 2>&1 @@ -56,7 +56,7 @@ if [ $? != 0 ]; then failures=`expr $failures + 1`; fi # allow echo "Allow test" -$JAVA -classpath ${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar \ +$JAVA -classpath "${TESTCLASSES}${PS}${TESTJAVA}/lib/tools.jar" \ -Djava.security.manager \ -Djava.security.policy=${TESTSRC}/java.policy.allow \ PermissionTest $pid false 2>&1 diff --git a/jdk/test/com/sun/tools/attach/ProviderTests.sh b/jdk/test/com/sun/tools/attach/ProviderTests.sh index caca75af0e7..36a90b13535 100644 --- a/jdk/test/com/sun/tools/attach/ProviderTests.sh +++ b/jdk/test/com/sun/tools/attach/ProviderTests.sh @@ -46,6 +46,6 @@ $JAR -cf ${TESTCLASSES}/SimpleProvider.jar \ echo "Running test ..." $JAVA -classpath \ - ${TESTCLASSES}${PS}${TESTCLASSES}/SimpleProvider.jar${PS}${TESTJAVA}/lib/tools.jar \ + "${TESTCLASSES}${PS}${TESTCLASSES}/SimpleProvider.jar${PS}${TESTJAVA}/lib/tools.jar" \ ProviderTest diff --git a/jdk/test/java/beans/Introspector/Test5102804.java b/jdk/test/java/beans/Introspector/Test5102804.java index 71f23f92941..cc207bdc80b 100644 --- a/jdk/test/java/beans/Introspector/Test5102804.java +++ b/jdk/test/java/beans/Introspector/Test5102804.java @@ -24,6 +24,7 @@ /* * @test * @bug 5102804 + * @ignore This test is not predictable with regards to GC * @summary Tests memory leak * @author Sergey Malenkov */ diff --git a/jdk/test/java/dyn/MethodHandlesTest.java b/jdk/test/java/dyn/MethodHandlesTest.java new file mode 100644 index 00000000000..a482d58a53c --- /dev/null +++ b/jdk/test/java/dyn/MethodHandlesTest.java @@ -0,0 +1,1839 @@ +/* + * 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 + * @summary unit tests for java.dyn.MethodHandles + * @compile -XDinvokedynamic MethodHandlesTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic jdk.java.dyn.MethodHandlesTest + */ + +package jdk.java.dyn; + +import java.dyn.*; +import java.dyn.MethodHandles.Lookup; +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.junit.*; +import static org.junit.Assert.*; + + +/** + * + * @author jrose + */ +public class MethodHandlesTest { + // How much output? + static int verbosity = 1; + + // Set this true during development if you want to fast-forward to + // a particular new, non-working test. Tests which are known to + // work (or have recently worked) test this flag and return on true. + static boolean CAN_SKIP_WORKING = false; + //static { CAN_SKIP_WORKING = true; } + + // Set true to test more calls. If false, some tests are just + // lookups, without exercising the actual method handle. + static boolean DO_MORE_CALLS = false; + + + @Test + public void testFirst() throws Throwable { + verbosity += 9; try { + // left blank for debugging + } finally { verbosity -= 9; } + } + + // current failures + @Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric") + public void testFail_1() throws Throwable { + testSpreadArguments(int.class, 0, 6); + } + @Test @Ignore("failure in JVM when expanding the stack") + public void testFail_2() throws Throwable { + // if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes: + testSpreadArguments(Object.class, 0, 2); + } + @Test @Ignore("IllArgEx failure in call to ToGeneric.make") + public void testFail_3() throws Throwable { + testSpreadArguments(int.class, 1, 2); + } + @Test @Ignore("IllArgEx failure in call to ToGeneric.make") + public void testFail_4() throws Throwable { + testCollectArguments(int.class, 1, 2); + } + @Test @Ignore("cannot collect leading primitive types") + public void testFail_5() throws Throwable { + testInvokers(MethodType.genericMethodType(2).changeParameterType(0, int.class)); + } + @Test @Ignore("should not insert arguments beyond MethodHandlePushLimit") + public void testFail_6() throws Throwable { + testInsertArguments(0, 0, MAX_ARG_INCREASE+1); + } + static final int MAX_ARG_INCREASE = 3; + + public MethodHandlesTest() { + } + + String testName; + int posTests, negTests; + @After + public void printCounts() { + if (verbosity >= 1 && (posTests | negTests) != 0) { + System.out.println(); + if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run"); + if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run"); + } + } + void countTest(boolean positive) { + if (positive) ++posTests; + else ++negTests; + } + void countTest() { countTest(true); } + void startTest(String name) { + if (testName != null) printCounts(); + if (verbosity >= 0) + System.out.println(name); + posTests = negTests = 0; + testName = name; + } + + @BeforeClass + public static void setUpClass() throws Exception { + calledLog.clear(); + calledLog.add(null); + nextArg = 1000000; + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + static List calledLog = new ArrayList(); + static Object logEntry(String name, Object... args) { + return Arrays.asList(name, Arrays.asList(args)); + } + static Object called(String name, Object... args) { + Object entry = logEntry(name, args); + calledLog.add(entry); + return entry; + } + static void assertCalled(String name, Object... args) { + Object expected = logEntry(name, args); + Object actual = calledLog.get(calledLog.size() - 1); + if (expected.equals(actual)) return; + System.out.println("assertCalled "+name+":"); + System.out.println("expected: "+expected); + System.out.println("actual: "+actual); + System.out.println("ex. types: "+getClasses(expected)); + System.out.println("act. types: "+getClasses(actual)); + assertEquals("previous method call types", expected, actual); + assertEquals("previous method call", expected, actual); + } + static void printCalled(MethodHandle target, String name, Object... args) { + if (verbosity >= 2) + System.out.println("calling "+logEntry(name, args)+" on "+target); + } + + static Object castToWrapper(Object value, Class dst) { + Object wrap = null; + if (value instanceof Number) + wrap = castToWrapperOrNull(((Number)value).longValue(), dst); + if (value instanceof Character) + wrap = castToWrapperOrNull((char)(Character)value, dst); + if (wrap != null) return wrap; + return dst.cast(value); + } + + static Object castToWrapperOrNull(long value, Class dst) { + if (dst == int.class || dst == Integer.class) + return (int)(value); + if (dst == long.class || dst == Long.class) + return (long)(value); + if (dst == char.class || dst == Character.class) + return (char)(value); + if (dst == short.class || dst == Short.class) + return (short)(value); + if (dst == float.class || dst == Float.class) + return (float)(value); + if (dst == double.class || dst == Double.class) + return (double)(value); + if (dst == byte.class || dst == Byte.class) + return (byte)(value); + if (dst == boolean.class || dst == boolean.class) + return ((value % 29) & 1) == 0; + return null; + } + + static int nextArg; + static Object randomArg(Class param) { + Object wrap = castToWrapperOrNull(nextArg, param); + if (wrap != null) { + nextArg++; + return wrap; + } +// import sun.dyn.util.Wrapper; +// Wrapper wrap = Wrapper.forBasicType(dst); +// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst)) +// wrap = Wrapper.forWrapperType(dst); +// if (wrap != Wrapper.OBJECT) +// return wrap.wrap(nextArg++); + if (param.isInterface() || param.isAssignableFrom(String.class)) + return "#"+(nextArg++); + else + try { + return param.newInstance(); + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + return null; // random class not Object, String, Integer, etc. + } + static Object[] randomArgs(Class... params) { + Object[] args = new Object[params.length]; + for (int i = 0; i < args.length; i++) + args[i] = randomArg(params[i]); + return args; + } + static Object[] randomArgs(int nargs, Class param) { + Object[] args = new Object[nargs]; + for (int i = 0; i < args.length; i++) + args[i] = randomArg(param); + return args; + } + + static T[] array(Class atype, E... a) { + return Arrays.copyOf(a, a.length, atype); + } + static T[] cat(T[] a, T... b) { + int alen = a.length, blen = b.length; + if (blen == 0) return a; + T[] c = Arrays.copyOf(a, alen + blen); + System.arraycopy(b, 0, c, alen, blen); + return c; + } + static Integer[] boxAll(int... vx) { + Integer[] res = new Integer[vx.length]; + for (int i = 0; i < res.length; i++) { + res[i] = vx[i]; + } + return res; + } + static Object getClasses(Object x) { + if (x == null) return x; + if (x instanceof String) return x; // keep the name + if (x instanceof List) { + // recursively report classes of the list elements + Object[] xa = ((List)x).toArray(); + for (int i = 0; i < xa.length; i++) + xa[i] = getClasses(xa[i]); + return Arrays.asList(xa); + } + return x.getClass().getSimpleName(); + } + + static MethodHandle changeArgTypes(MethodHandle target, Class argType) { + return changeArgTypes(target, 0, 999, argType); + } + static MethodHandle changeArgTypes(MethodHandle target, + int beg, int end, Class argType) { + MethodType targetType = target.type(); + end = Math.min(end, targetType.parameterCount()); + ArrayList> argTypes = new ArrayList>(targetType.parameterList()); + Collections.fill(argTypes.subList(beg, end), argType); + MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); + return MethodHandles.convertArguments(target, ttype2); + } + + // This lookup is good for all members in and under MethodHandlesTest. + static final Lookup PRIVATE = MethodHandles.lookup(); + // This lookup is good for package-private members but not private ones. + static final Lookup PACKAGE = PackageSibling.lookup(); + // This lookup is good only for public members. + static final Lookup PUBLIC = MethodHandles.publicLookup(); + + // Subject methods... + static class Example implements IntExample { + final String name; + public Example() { name = "Example#"+(nextArg++); } + protected Example(String name) { this.name = name; } + protected Example(int x) { this(); called("protected ", this, x); } + @Override public String toString() { return name; } + + public void v0() { called("v0", this); } + void pkg_v0() { called("pkg_v0", this); } + private void pri_v0() { called("pri_v0", this); } + public static void s0() { called("s0"); } + static void pkg_s0() { called("pkg_s0"); } + private static void pri_s0() { called("pri_s0"); } + + public Object v1(Object x) { return called("v1", this, x); } + public Object v2(Object x, Object y) { return called("v2", this, x, y); } + public Object v2(Object x, int y) { return called("v2", this, x, y); } + public Object v2(int x, Object y) { return called("v2", this, x, y); } + public Object v2(int x, int y) { return called("v2", this, x, y); } + public static Object s1(Object x) { return called("s1", x); } + public static Object s2(int x) { return called("s2", x); } + public static Object s3(long x) { return called("s3", x); } + public static Object s4(int x, int y) { return called("s4", x, y); } + public static Object s5(long x, int y) { return called("s5", x, y); } + public static Object s6(int x, long y) { return called("s6", x, y); } + public static Object s7(float x, double y) { return called("s7", x, y); } + } + public static class PubExample extends Example { + } + static class SubExample extends Example { + @Override public void v0() { called("Sub/v0", this); } + @Override void pkg_v0() { called("Sub/pkg_v0", this); } + private SubExample(int x) { called("", this, x); } + public SubExample() { super("SubExample#"+(nextArg++)); } + } + public static interface IntExample { + public void v0(); + static class Impl implements IntExample { + public void v0() { called("Int/v0", this); } + final String name; + public Impl() { name = "Example#"+(nextArg++); } + } + } + + static final Object[][][] ACCESS_CASES = { + { { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE } }, + { { false, PUBLIC }, { false, PACKAGE }, { true, PRIVATE } }, + { { false, PUBLIC }, { true, PACKAGE }, { true, PRIVATE } }, + { { true, PUBLIC }, { true, PACKAGE }, { true, PRIVATE } }, + }; + + static Object[][] accessCases(Class defc, String name) { + if (name.contains("pri_")) { + return ACCESS_CASES[1]; // PRIVATE only + } else if (name.contains("pkg_")) { + return ACCESS_CASES[2]; // not PUBLIC + } else { + assertTrue(name.indexOf('_') < 0); + boolean pubc = Modifier.isPublic(defc.getModifiers()); + if (pubc) + return ACCESS_CASES[3]; // all access levels + return ACCESS_CASES[2]; // PACKAGE but not PUBLIC + } + } + + @Test + public void testFindStatic() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("findStatic"); + testFindStatic(PubExample.class, void.class, "s0"); + testFindStatic(Example.class, void.class, "s0"); + testFindStatic(Example.class, void.class, "pkg_s0"); + testFindStatic(Example.class, void.class, "pri_s0"); + + testFindStatic(Example.class, Object.class, "s1", Object.class); + testFindStatic(Example.class, Object.class, "s2", int.class); + testFindStatic(Example.class, Object.class, "s3", long.class); + testFindStatic(Example.class, Object.class, "s4", int.class, int.class); + testFindStatic(Example.class, Object.class, "s5", long.class, int.class); + testFindStatic(Example.class, Object.class, "s6", int.class, long.class); + testFindStatic(Example.class, Object.class, "s7", float.class, double.class); + + testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); + } + + void testFindStatic(Class defc, Class ret, String name, Class... params) throws Throwable { + for (Object[] ac : accessCases(defc, name)) { + testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); + } + } + void testFindStatic(Lookup lookup, Class defc, Class ret, String name, Class... params) throws Throwable { + testFindStatic(true, lookup, defc, ret, name, params); + } + void testFindStatic(boolean positive, Lookup lookup, Class defc, Class ret, String name, Class... params) throws Throwable { + countTest(positive); + MethodType type = MethodType.methodType(ret, params); + MethodHandle target = null; + RuntimeException noAccess = null; + try { + target = lookup.findStatic(defc, name, type); + } catch (NoAccessException ex) { + noAccess = ex; + } + if (verbosity >= 2) + System.out.println("findStatic "+lookup+": "+defc+"."+name+"/"+type+" => "+target + +(noAccess == null ? "" : " !! "+noAccess)); + if (positive && noAccess != null) throw noAccess; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + assertEquals(type, target.type()); + assertTrue(target.toString().contains(name)); // rough check + if (!DO_MORE_CALLS && lookup != PRIVATE) return; + Object[] args = randomArgs(params); + printCalled(target, name, args); + target.invokeVarargs(args); + assertCalled(name, args); + System.out.print(':'); + } + + @Test + public void testFindVirtual() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("findVirtual"); + testFindVirtual(Example.class, void.class, "v0"); + testFindVirtual(Example.class, void.class, "pkg_v0"); + testFindVirtual(Example.class, void.class, "pri_v0"); + testFindVirtual(Example.class, Object.class, "v1", Object.class); + testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class); + testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class); + testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class); + testFindVirtual(Example.class, Object.class, "v2", int.class, int.class); + testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); + // test dispatch + testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0"); + testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0"); + testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0"); + testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0"); + testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0"); + testFindVirtual(Example.class, IntExample.class, void.class, "v0"); + testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); + } + + void testFindVirtual(Class defc, Class ret, String name, Class... params) throws Throwable { + Class rcvc = defc; + testFindVirtual(rcvc, defc, ret, name, params); + } + void testFindVirtual(Class rcvc, Class defc, Class ret, String name, Class... params) throws Throwable { + for (Object[] ac : accessCases(defc, name)) { + testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params); + } + } + void testFindVirtual(Lookup lookup, Class rcvc, Class defc, Class ret, String name, Class... params) throws Throwable { + testFindVirtual(true, lookup, rcvc, defc, ret, name, params); + } + void testFindVirtual(boolean positive, Lookup lookup, Class rcvc, Class defc, Class ret, String name, Class... params) throws Throwable { + countTest(positive); + String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo + MethodType type = MethodType.methodType(ret, params); + MethodHandle target = null; + RuntimeException noAccess = null; + try { + target = lookup.findVirtual(defc, methodName, type); + } catch (NoAccessException ex) { + noAccess = ex; + } + if (verbosity >= 2) + System.out.println("findVirtual "+lookup+": "+defc+"."+name+"/"+type+" => "+target + +(noAccess == null ? "" : " !! "+noAccess)); + if (positive && noAccess != null) throw noAccess; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + Class[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params); + MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); + MethodType ttype = target.type(); + ttype = ttype.changeParameterType(0, defc); // FIXME: test this + assertEquals(typeWithSelf, ttype); + assertTrue(target.toString().contains(methodName)); // rough check + if (!DO_MORE_CALLS && lookup != PRIVATE) return; + Object[] argsWithSelf = randomArgs(paramsWithSelf); + if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc); + printCalled(target, name, argsWithSelf); + target.invokeVarargs(argsWithSelf); + assertCalled(name, argsWithSelf); + System.out.print(':'); + } + + @Test + public void testFindSpecial() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("findSpecial"); + testFindSpecial(Example.class, void.class, "v0"); + testFindSpecial(Example.class, void.class, "pkg_v0"); + testFindSpecial(false, PRIVATE, Example.class, void.class, "", int.class); + testFindSpecial(false, PRIVATE, Example.class, void.class, "bogus"); + } + + void testFindSpecial(Class defc, Class ret, String name, Class... params) throws Throwable { + testFindSpecial(true, PRIVATE, defc, ret, name, params); + testFindSpecial(false, PACKAGE, defc, ret, name, params); + testFindSpecial(false, PUBLIC, defc, ret, name, params); + } + void testFindSpecial(boolean positive, Lookup lookup, Class defc, Class ret, String name, Class... params) throws Throwable { + countTest(positive); + MethodType type = MethodType.methodType(ret, params); + MethodHandle target = null; + RuntimeException noAccess = null; + try { + target = lookup.findSpecial(defc, name, type, defc); + } catch (NoAccessException ex) { + noAccess = ex; + } + if (verbosity >= 2) + System.out.println("findSpecial "+defc+"."+name+"/"+type+" => "+target + +(noAccess == null ? "" : " !! "+noAccess)); + if (positive && noAccess != null) throw noAccess; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + Class[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params); + MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); + MethodType ttype = target.type(); + ttype = ttype.changeParameterType(0, defc); // FIXME: test this + assertEquals(typeWithSelf, ttype); + assertTrue(target.toString().contains(name)); // rough check + if (!DO_MORE_CALLS && lookup != PRIVATE) return; + Object[] args = randomArgs(paramsWithSelf); + printCalled(target, name, args); + target.invokeVarargs(args); + assertCalled(name, args); + System.out.print(':'); + } + + @Test + public void testBind() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("bind"); + testBind(Example.class, void.class, "v0"); + testBind(Example.class, void.class, "pkg_v0"); + testBind(Example.class, void.class, "pri_v0"); + testBind(Example.class, Object.class, "v1", Object.class); + testBind(Example.class, Object.class, "v2", Object.class, Object.class); + testBind(Example.class, Object.class, "v2", Object.class, int.class); + testBind(Example.class, Object.class, "v2", int.class, Object.class); + testBind(Example.class, Object.class, "v2", int.class, int.class); + testBind(false, PRIVATE, Example.class, void.class, "bogus"); + testBind(SubExample.class, void.class, "Sub/v0"); + testBind(SubExample.class, void.class, "Sub/pkg_v0"); + testBind(IntExample.Impl.class, void.class, "Int/v0"); + } + + void testBind(Class defc, Class ret, String name, Class... params) throws Throwable { + for (Object[] ac : accessCases(defc, name)) { + testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); + } + } + + void testBind(boolean positive, Lookup lookup, Class defc, Class ret, String name, Class... params) throws Throwable { + countTest(positive); + String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo + MethodType type = MethodType.methodType(ret, params); + Object receiver = randomArg(defc); + MethodHandle target = null; + RuntimeException noAccess = null; + try { + target = lookup.bind(receiver, methodName, type); + } catch (NoAccessException ex) { + noAccess = ex; + } + if (verbosity >= 2) + System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target + +(noAccess == null ? "" : " !! "+noAccess)); + if (positive && noAccess != null) throw noAccess; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + assertEquals(type, target.type()); + Object[] args = randomArgs(params); + printCalled(target, name, args); + target.invokeVarargs(args); + Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); + assertCalled(name, argsWithReceiver); + System.out.print(':'); + } + + @Test + public void testUnreflect() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("unreflect"); + testUnreflect(Example.class, true, void.class, "s0"); + testUnreflect(Example.class, true, void.class, "pkg_s0"); + testUnreflect(Example.class, true, void.class, "pri_s0"); + + testUnreflect(Example.class, true, Object.class, "s1", Object.class); + testUnreflect(Example.class, true, Object.class, "s2", int.class); + //testUnreflect(Example.class, true, Object.class, "s3", long.class); + //testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class); + //testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class); + //testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class); + + testUnreflect(Example.class, false, void.class, "v0"); + testUnreflect(Example.class, false, void.class, "pkg_v0"); + testUnreflect(Example.class, false, void.class, "pri_v0"); + testUnreflect(Example.class, false, Object.class, "v1", Object.class); + testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class); + testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class); + testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class); + testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class); + } + + void testUnreflect(Class defc, boolean isStatic, Class ret, String name, Class... params) throws Throwable { + for (Object[] ac : accessCases(defc, name)) { + testUnreflect((Boolean)ac[0], (Lookup)ac[1], defc, isStatic, ret, name, params); + } + } + void testUnreflect(boolean positive, Lookup lookup, Class defc, boolean isStatic, Class ret, String name, Class... params) throws Throwable { + countTest(positive); + MethodType type = MethodType.methodType(ret, params); + Method rmethod = null; + MethodHandle target = null; + RuntimeException noAccess = null; + try { + rmethod = defc.getDeclaredMethod(name, params); + } catch (NoSuchMethodException ex) { + throw new NoAccessException(ex); + } + assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers())); + try { + target = lookup.unreflect(rmethod); + } catch (NoAccessException ex) { + noAccess = ex; + } + if (verbosity >= 2) + System.out.println("unreflect "+defc+"."+name+"/"+type+" => "+target + +(noAccess == null ? "" : " !! "+noAccess)); + if (positive && noAccess != null) throw noAccess; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + Class[] paramsMaybeWithSelf = params; + if (!isStatic) { + paramsMaybeWithSelf = cat(array(Class[].class, (Class)defc), params); + } + MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf); + MethodType ttype = target.type(); + if (!isStatic) + ttype = ttype.changeParameterType(0, defc); // FIXME: test this + assertEquals(typeMaybeWithSelf, ttype); + Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf); + printCalled(target, name, argsMaybeWithSelf); + target.invokeVarargs(argsMaybeWithSelf); + assertCalled(name, argsMaybeWithSelf); + System.out.print(':'); + } + + @Test @Ignore("unimplemented") + public void testUnreflectSpecial() throws Throwable { + Lookup lookup = PRIVATE; // FIXME: test more lookups than this one + startTest("unreflectSpecial"); + Method m = null; + MethodHandle expResult = null; + MethodHandle result = lookup.unreflectSpecial(m, Example.class); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + public static class HasFields { + boolean fZ = false; + byte fB = (byte)'B'; + short fS = (short)'S'; + char fC = 'C'; + int fI = 'I'; + long fJ = 'J'; + float fF = 'F'; + double fD = 'D'; + static boolean sZ = true; + static byte sB = 1+(byte)'B'; + static short sS = 1+(short)'S'; + static char sC = 1+'C'; + static int sI = 1+'I'; + static long sJ = 1+'J'; + static float sF = 1+'F'; + static double sD = 1+'D'; + + Object fL = 'L'; + String fR = "R"; + static Object sL = 'M'; + static String sR = "S"; + + static final Object[][] CASES; + static { + ArrayList cases = new ArrayList(); + Object types[][] = { + {'L',Object.class}, {'R',String.class}, + {'I',int.class}, {'J',long.class}, + {'F',float.class}, {'D',double.class}, + {'Z',boolean.class}, {'B',byte.class}, + {'S',short.class}, {'C',char.class}, + }; + HasFields fields = new HasFields(); + for (Object[] t : types) { + for (int kind = 0; kind <= 1; kind++) { + boolean isStatic = (kind != 0); + char btc = (Character)t[0]; + String name = (isStatic ? "s" : "f") + btc; + Class type = (Class) t[1]; + Object value; + Field field; + try { + field = HasFields.class.getDeclaredField(name); + } catch (Exception ex) { + throw new InternalError("no field HasFields."+name); + } + try { + value = field.get(fields); + } catch (Exception ex) { + throw new InternalError("cannot fetch field HasFields."+name); + } + if (type == float.class) { + float v = 'F'; + if (isStatic) v++; + assert(value.equals(v)); + } + assert(name.equals(field.getName())); + assert(type.equals(field.getType())); + assert(isStatic == (Modifier.isStatic(field.getModifiers()))); + cases.add(new Object[]{ field, value }); + } + } + CASES = cases.toArray(new Object[0][]); + } + } + + @Test + public void testUnreflectGetter() throws Throwable { + Lookup lookup = PRIVATE; // FIXME: test more lookups than this one + startTest("unreflectGetter"); + for (Object[] c : HasFields.CASES) { + Field f = (Field)c[0]; + Object value = c[1]; + Class type = f.getType(); + if (type.isPrimitive() && type != int.class) + continue; //FIXME + testUnreflectGetter(lookup, f, type, value); + } + } + public void testUnreflectGetter(MethodHandles.Lookup lookup, + Field f, Class type, Object value) throws Throwable { + countTest(true); + boolean isStatic = Modifier.isStatic(f.getModifiers()); + MethodType expType = MethodType.methodType(type, HasFields.class); + if (isStatic) expType = expType.dropParameterTypes(0, 1); + MethodHandle mh = lookup.unreflectGetter(f); + assertSame(mh.type(), expType); + assertEquals(mh.toString(), f.getName()); + HasFields fields = new HasFields(); + Object sawValue; + Class rtype = type; + if (type != int.class) rtype = Object.class; + mh = MethodHandles.convertArguments(mh, mh.type().generic().changeReturnType(rtype)); + Object expValue = value; + for (int i = 0; i <= 1; i++) { + if (isStatic) { + if (type == int.class) + sawValue = mh.invoke(); // do these exactly + else + sawValue = mh.invoke(); + } else { + if (type == int.class) + sawValue = mh.invoke((Object) fields); + else + sawValue = mh.invoke((Object) fields); + } + assertEquals(sawValue, expValue); + Object random = randomArg(type); + f.set(fields, random); + expValue = random; + } + f.set(fields, value); // put it back + } + + + @Test + public void testUnreflectSetter() throws Throwable { + Lookup lookup = PRIVATE; // FIXME: test more lookups than this one + startTest("unreflectSetter"); + for (Object[] c : HasFields.CASES) { + Field f = (Field)c[0]; + Object value = c[1]; + Class type = f.getType(); + if (type.isPrimitive() && type != int.class) + continue; //FIXME + testUnreflectSetter(lookup, f, type, value); + } + } + public void testUnreflectSetter(MethodHandles.Lookup lookup, + Field f, Class type, Object value) throws Throwable { + countTest(true); + boolean isStatic = Modifier.isStatic(f.getModifiers()); + MethodType expType = MethodType.methodType(void.class, HasFields.class, type); + if (isStatic) expType = expType.dropParameterTypes(0, 1); + MethodHandle mh = lookup.unreflectSetter(f); + assertSame(mh.type(), expType); + assertEquals(mh.toString(), f.getName()); + HasFields fields = new HasFields(); + Object sawValue; + Class vtype = type; + if (type != int.class) vtype = Object.class; + int last = mh.type().parameterCount() - 1; + mh = MethodHandles.convertArguments(mh, mh.type().generic().changeReturnType(void.class).changeParameterType(last, vtype)); + assertEquals(f.get(fields), value); // clean to start with + for (int i = 0; i <= 1; i++) { + Object putValue = randomArg(type); + if (isStatic) { + if (type == int.class) + mh.invoke((int)(Integer)putValue); // do these exactly + else + mh.invoke(putValue); + } else { + if (type == int.class) + mh.invoke((Object) fields, (int)(Integer)putValue); + else + mh.invoke((Object) fields, putValue); + } + assertEquals(f.get(fields), putValue); + } + f.set(fields, value); // put it back + } + + @Test + public void testArrayElementGetter() throws Throwable { + startTest("arrayElementGetter"); + testArrayElementGetterSetter(new Object[10], false); + testArrayElementGetterSetter(new String[10], false); + testArrayElementGetterSetter(new int[10], false); + // FIXME: Do the other primitive types. + //testArrayElementGetterSetter(new float[10], false); + } + + @Test + public void testArrayElementSetter() throws Throwable { + startTest("arrayElementSetter"); + testArrayElementGetterSetter(new Object[10], true); + testArrayElementGetterSetter(new String[10], true); + testArrayElementGetterSetter(new int[10], true); + // FIXME: Do the other primitive types. + //testArrayElementGetterSetter(new float[10], true); + } + + public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable { + countTest(true); + Class arrayType = array.getClass(); + Class elemType = arrayType.getComponentType(); + MethodType expType = !testSetter + ? MethodType.methodType(elemType, arrayType, int.class) + : MethodType.methodType(void.class, arrayType, int.class, elemType); + MethodHandle mh = !testSetter + ? MethodHandles.arrayElementGetter(arrayType) + : MethodHandles.arrayElementSetter(arrayType); + assertSame(mh.type(), expType); + //assertEquals(mh.toString(), f.getName()); + Object sawValue, expValue; + List model = array2list(array); + int length = Array.getLength(array); + for (int i = 0; i < length; i++) { + // update array element + Object random = randomArg(elemType); + model.set(i, random); + if (testSetter) { + if (elemType == int.class) + mh.invoke((int[]) array, i, (int)(Integer)random); + else + mh.invokeGeneric(array, i, random); + assertEquals(model, array2list(array)); + } else { + Array.set(array, i, random); + + } + // observe array element + sawValue = Array.get(array, i); + if (!testSetter) { + expValue = sawValue; + if (elemType == int.class) + sawValue = mh.invoke((int[]) array, i); + else + sawValue = mh.invokeGeneric(array, i); + assertEquals(sawValue, expValue); + assertEquals(model, array2list(array)); + } + } + } + + List array2list(Object array) { + int length = Array.getLength(array); + ArrayList model = new ArrayList(length); + for (int i = 0; i < length; i++) + model.add(Array.get(array, i)); + return model; + } + + static class Callee { + static Object id() { return called("id"); } + static Object id(Object x) { return called("id", x); } + static Object id(Object x, Object y) { return called("id", x, y); } + static Object id(Object x, Object y, Object z) { return called("id", x, y, z); } + static Object id(Object... vx) { return called("id", vx); } + static MethodHandle ofType(int n) { + return ofType(Object.class, n); + } + static MethodHandle ofType(Class rtype, int n) { + if (n == -1) + return ofType(MethodType.methodType(rtype, Object[].class)); + return ofType(MethodType.genericMethodType(n).changeReturnType(rtype)); + } + static MethodHandle ofType(Class rtype, Class... ptypes) { + return ofType(MethodType.methodType(rtype, ptypes)); + } + static MethodHandle ofType(MethodType type) { + Class rtype = type.returnType(); + String pfx = ""; + if (rtype != Object.class) + pfx = rtype.getSimpleName().substring(0, 1).toLowerCase(); + String name = pfx+"id"; + return PRIVATE.findStatic(Callee.class, name, type); + } + } + + @Test + public void testConvertArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("convertArguments"); + testConvert(Callee.ofType(1), null, "id", int.class); + testConvert(Callee.ofType(1), null, "id", String.class); + testConvert(Callee.ofType(1), null, "id", Integer.class); + testConvert(Callee.ofType(1), null, "id", short.class); + } + + void testConvert(MethodHandle id, Class rtype, String name, Class... params) throws Throwable { + testConvert(true, id, rtype, name, params); + } + + void testConvert(boolean positive, MethodHandle id, Class rtype, String name, Class... params) throws Throwable { + countTest(positive); + MethodType idType = id.type(); + if (rtype == null) rtype = idType.returnType(); + for (int i = 0; i < params.length; i++) { + if (params[i] == null) params[i] = idType.parameterType(i); + } + // simulate the pairwise conversion + MethodType newType = MethodType.methodType(rtype, params); + Object[] args = randomArgs(newType.parameterArray()); + Object[] convArgs = args.clone(); + for (int i = 0; i < args.length; i++) { + Class src = newType.parameterType(i); + Class dst = idType.parameterType(i); + if (src != dst) + convArgs[i] = castToWrapper(convArgs[i], dst); + } + Object convResult = id.invokeVarargs(convArgs); + { + Class dst = newType.returnType(); + Class src = idType.returnType(); + if (src != dst) + convResult = castToWrapper(convResult, dst); + } + MethodHandle target = null; + RuntimeException error = null; + try { + target = MethodHandles.convertArguments(id, newType); + } catch (RuntimeException ex) { + error = ex; + } + if (verbosity >= 2) + System.out.println("convert "+id+ " to "+newType+" => "+target + +(error == null ? "" : " !! "+error)); + if (positive && error != null) throw error; + assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); + if (!positive) return; // negative test failed as expected + assertEquals(newType, target.type()); + printCalled(target, id.toString(), args); + Object result = target.invokeVarargs(args); + assertCalled(name, convArgs); + assertEquals(convResult, result); + System.out.print(':'); + } + + @Test + public void testPermuteArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("permuteArguments"); + testPermuteArguments(4, Integer.class, 2, String.class, 0); + //testPermuteArguments(6, Integer.class, 0, null, 30); + //testPermuteArguments(4, Integer.class, 1, int.class, 6); + } + public void testPermuteArguments(int max, Class type1, int t2c, Class type2, int dilution) throws Throwable { + if (verbosity >= 1) + System.out.println("permuteArguments "+max+"*"+type1.getName() + +(t2c==0?"":"/"+t2c+"*"+type2.getName()) + +(dilution > 0 ? " with dilution "+dilution : "")); + int t2pos = t2c == 0 ? 0 : 1; + for (int inargs = t2pos+1; inargs <= max; inargs++) { + Class[] types = new Class[inargs]; + Arrays.fill(types, type1); + if (t2c != 0) { + // Fill in a middle range with type2: + Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2); + } + Object[] args = randomArgs(types); + int numcases = 1; + for (int outargs = 0; outargs <= max; outargs++) { + if (outargs - inargs >= MAX_ARG_INCREASE) continue; + int[] reorder = new int[outargs]; + int casStep = dilution + 1; + // Avoid some common factors: + while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) || + (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0)) + casStep++; + for (int cas = 0; cas < numcases; cas += casStep) { + for (int i = 0, c = cas; i < outargs; i++) { + reorder[i] = c % inargs; + c /= inargs; + } + testPermuteArguments(args, types, reorder); + } + numcases *= inargs; + if (dilution > 10 && outargs >= 4) { + // Do some special patterns, which we probably missed. + // Replication of a single argument or argument pair. + for (int i = 0; i < inargs; i++) { + Arrays.fill(reorder, i); + testPermuteArguments(args, types, reorder); + for (int d = 1; d <= 2; d++) { + if (i + d >= inargs) continue; + for (int j = 1; j < outargs; j += 2) + reorder[j] += 1; + testPermuteArguments(args, types, reorder); + testPermuteArguments(args, types, reverse(reorder)); + } + } + // Repetition of a sequence of 3 or more arguments. + for (int i = 1; i < inargs; i++) { + for (int len = 3; len <= inargs; len++) { + for (int j = 0; j < outargs; j++) + reorder[j] = (i + (j % len)) % inargs; + testPermuteArguments(args, types, reorder); + testPermuteArguments(args, types, reverse(reorder)); + } + } + } + } + } + } + + static int[] reverse(int[] reorder) { + reorder = reorder.clone(); + for (int i = 0, imax = reorder.length / 2; i < imax; i++) { + int j = reorder.length - 1 - i; + int tem = reorder[i]; + reorder[i] = reorder[j]; + reorder[j] = tem; + } + return reorder; + } + + void testPermuteArguments(Object[] args, Class[] types, int[] reorder) throws Throwable { + countTest(); + if (args == null && types == null) { + int max = 0; + for (int j : reorder) { + if (max < j) max = j; + } + args = randomArgs(max+1, Integer.class); + } + if (args == null) { + args = randomArgs(types); + } + if (types == null) { + types = new Class[args.length]; + for (int i = 0; i < args.length; i++) + types[i] = args[i].getClass(); + } + int inargs = args.length, outargs = reorder.length; + assert(inargs == types.length); + if (verbosity >= 2) + System.out.println("permuteArguments "+Arrays.toString(reorder)); + Object[] permArgs = new Object[outargs]; + Class[] permTypes = new Class[outargs]; + for (int i = 0; i < outargs; i++) { + permArgs[i] = args[reorder[i]]; + permTypes[i] = types[reorder[i]]; + } + if (verbosity >= 3) { + System.out.println("in args: "+Arrays.asList(args)); + System.out.println("out args: "+Arrays.asList(permArgs)); + System.out.println("in types: "+Arrays.asList(types)); + System.out.println("out types: "+Arrays.asList(permTypes)); + } + MethodType inType = MethodType.methodType(Object.class, types); + MethodType outType = MethodType.methodType(Object.class, permTypes); + MethodHandle target = MethodHandles.convertArguments(ValueConversions.varargsList(outargs), outType); + MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder); + Object result = newTarget.invokeVarargs(args); + Object expected = Arrays.asList(permArgs); + assertEquals(expected, result); + } + + + @Test + public void testSpreadArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("spreadArguments"); + for (Class argType : new Class[]{Object.class, Integer.class, int.class}) { + if (verbosity >= 2) + System.out.println("spreadArguments "+argType); + for (int nargs = 0; nargs < 10; nargs++) { + if (argType == int.class && nargs >= 6) continue; // FIXME Fail_1 + for (int pos = 0; pos < nargs; pos++) { + if (argType == int.class && pos > 0) continue; // FIXME Fail_3 + testSpreadArguments(argType, pos, nargs); + } + } + } + } + public void testSpreadArguments(Class argType, int pos, int nargs) throws Throwable { + countTest(); + MethodHandle target = ValueConversions.varargsArray(nargs); + MethodHandle target2 = changeArgTypes(target, argType); + if (verbosity >= 2) + System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]"); + Object[] args = randomArgs(target2.type().parameterArray()); + // make sure the target does what we think it does: + if (pos == 0 && nargs < 5) { + Object[] check = (Object[]) target.invokeVarargs(args); + assertArrayEquals(args, check); + switch (nargs) { + case 0: + check = target.invoke(); + assertArrayEquals(args, check); + break; + case 1: + check = target.invoke(args[0]); + assertArrayEquals(args, check); + break; + case 2: + check = target.invoke(args[0], args[1]); + assertArrayEquals(args, check); + break; + } + } + List> newParams = new ArrayList>(target2.type().parameterList()); + { // modify newParams in place + List> spreadParams = newParams.subList(pos, nargs); + spreadParams.clear(); spreadParams.add(Object[].class); + } + MethodType newType = MethodType.methodType(Object.class, newParams); + MethodHandle result = MethodHandles.spreadArguments(target2, newType); + Object[] returnValue; + if (pos == 0) { + returnValue = (Object[]) result.invoke(args); + } else { + Object[] args1 = Arrays.copyOfRange(args, 0, pos+1); + args1[pos] = Arrays.copyOfRange(args, pos, args.length); + returnValue = (Object[]) result.invokeVarargs(args1); + } + assertArrayEquals(args, returnValue); + } + + @Test + public void testCollectArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("collectArguments"); + for (Class argType : new Class[]{Object.class, Integer.class, int.class}) { + if (verbosity >= 2) + System.out.println("collectArguments "+argType); + for (int nargs = 0; nargs < 10; nargs++) { + for (int pos = 0; pos < nargs; pos++) { + if (argType == int.class) continue; // FIXME Fail_4 + testCollectArguments(argType, pos, nargs); + } + } + } + } + public void testCollectArguments(Class argType, int pos, int nargs) throws Throwable { + countTest(); + // fake up a MH with the same type as the desired adapter: + MethodHandle fake = ValueConversions.varargsArray(nargs); + fake = changeArgTypes(fake, argType); + MethodType newType = fake.type(); + Object[] args = randomArgs(newType.parameterArray()); + // here is what should happen: + Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1); + collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length); + // here is the MH which will witness the collected argument tail: + MethodHandle target = ValueConversions.varargsArray(pos+1); + target = changeArgTypes(target, 0, pos, argType); + target = changeArgTypes(target, pos, pos+1, Object[].class); + if (verbosity >= 2) + System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]"); + MethodHandle result = MethodHandles.collectArguments(target, newType); + Object[] returnValue = (Object[]) result.invokeVarargs(args); +// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]); +// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]); +// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]); + assertArrayEquals(collectedArgs, returnValue); + } + + @Test + public void testInsertArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("insertArguments"); + for (int nargs = 0; nargs <= 4; nargs++) { + for (int ins = 0; ins <= 4; ins++) { + if (ins > MAX_ARG_INCREASE) continue; // FIXME Fail_6 + for (int pos = 0; pos <= nargs; pos++) { + testInsertArguments(nargs, pos, ins); + } + } + } + } + + void testInsertArguments(int nargs, int pos, int ins) throws Throwable { + countTest(); + MethodHandle target = ValueConversions.varargsArray(nargs + ins); + Object[] args = randomArgs(target.type().parameterArray()); + List resList = Arrays.asList(args); + List argsToPass = new ArrayList(resList); + List argsToInsert = argsToPass.subList(pos, pos + ins); + if (verbosity >= 2) + System.out.println("insert: "+argsToInsert+" into "+target); + MethodHandle target2 = MethodHandles.insertArguments(target, pos, + (Object[]) argsToInsert.toArray()); + argsToInsert.clear(); // remove from argsToInsert + Object res2 = target2.invokeVarargs(argsToPass); + Object res2List = Arrays.asList((Object[])res2); + if (verbosity >= 2) + System.out.println("result: "+res2List); + //if (!resList.equals(res2List)) + // System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List); + assertEquals(resList, res2List); + } + + @Test + public void testFilterArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("filterArguments"); + for (int nargs = 1; nargs <= 6; nargs++) { + for (int pos = 0; pos < nargs; pos++) { + testFilterArguments(nargs, pos); + } + } + } + + void testFilterArguments(int nargs, int pos) throws Throwable { + countTest(); + MethodHandle target = ValueConversions.varargsList(nargs); + MethodHandle filter = ValueConversions.varargsList(1); + filter = MethodHandles.convertArguments(filter, filter.type().generic()); + Object[] argsToPass = randomArgs(nargs, Object.class); + if (verbosity >= 2) + System.out.println("filter "+target+" at "+pos+" with "+filter); + MethodHandle[] filters = new MethodHandle[pos*2+1]; + filters[pos] = filter; + MethodHandle target2 = MethodHandles.filterArguments(target, filters); + // Simulate expected effect of filter on arglist: + Object[] filteredArgs = argsToPass.clone(); + filteredArgs[pos] = filter.invoke(filteredArgs[pos]); + List expected = Arrays.asList(filteredArgs); + Object result = target2.invokeVarargs(argsToPass); + if (verbosity >= 2) + System.out.println("result: "+result); + if (!expected.equals(result)) + System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+argsToPass+" => "+result); + assertEquals(expected, result); + } + + @Test + public void testFoldArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("foldArguments"); + for (int nargs = 0; nargs <= 4; nargs++) { + for (int fold = 0; fold <= nargs; fold++) { + for (int pos = 0; pos <= nargs; pos++) { + testFoldArguments(nargs, pos, fold); + } + } + } + } + + void testFoldArguments(int nargs, int pos, int fold) throws Throwable { + if (pos != 0) return; // can fold only at pos=0 for now + countTest(); + MethodHandle target = ValueConversions.varargsList(1 + nargs); + MethodHandle combine = ValueConversions.varargsList(fold); + List argsToPass = Arrays.asList(randomArgs(nargs, Object.class)); + if (verbosity >= 2) + System.out.println("fold "+target+" with "+combine); + MethodHandle target2 = MethodHandles.foldArguments(target, combine); + // Simulate expected effect of combiner on arglist: + List expected = new ArrayList(argsToPass); + List argsToFold = expected.subList(pos, pos + fold); + if (verbosity >= 2) + System.out.println("fold: "+argsToFold+" into "+target2); + Object foldedArgs = combine.invokeVarargs(argsToFold); + argsToFold.add(0, foldedArgs); + Object result = target2.invokeVarargs(argsToPass); + if (verbosity >= 2) + System.out.println("result: "+result); + if (!expected.equals(result)) + System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result); + assertEquals(expected, result); + } + + @Test + public void testDropArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("dropArguments"); + for (int nargs = 0; nargs <= 4; nargs++) { + for (int drop = 1; drop <= 4; drop++) { + for (int pos = 0; pos <= nargs; pos++) { + testDropArguments(nargs, pos, drop); + } + } + } + } + + void testDropArguments(int nargs, int pos, int drop) throws Throwable { + countTest(); + MethodHandle target = ValueConversions.varargsArray(nargs); + Object[] args = randomArgs(target.type().parameterArray()); + MethodHandle target2 = MethodHandles.dropArguments(target, pos, + Collections.nCopies(drop, Object.class).toArray(new Class[0])); + List resList = Arrays.asList(args); + List argsToDrop = new ArrayList(resList); + for (int i = drop; i > 0; i--) { + argsToDrop.add(pos, "blort#"+i); + } + Object res2 = target2.invokeVarargs(argsToDrop); + Object res2List = Arrays.asList((Object[])res2); + //if (!resList.equals(res2List)) + // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); + assertEquals(resList, res2List); + } + + @Test + public void testInvokers() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker"); + // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker + Set done = new HashSet(); + for (int i = 0; i <= 6; i++) { + MethodType gtype = MethodType.genericMethodType(i); + for (Class argType : new Class[]{Object.class, Integer.class, int.class}) { + for (int j = -1; j < i; j++) { + MethodType type = gtype; + if (j < 0) + type = type.changeReturnType(argType); + else if (argType == void.class) + continue; + else + type = type.changeParameterType(j, argType); + if (argType.isPrimitive() && j != i-1) continue; // FIXME Fail_5 + if (done.add(type)) + testInvokers(type); + MethodType vtype = type.changeReturnType(void.class); + if (done.add(vtype)) + testInvokers(vtype); + } + } + } + } + + public void testInvokers(MethodType type) throws Throwable { + if (verbosity >= 2) + System.out.println("test invokers for "+type); + int nargs = type.parameterCount(); + boolean testRetCode = type.returnType() != void.class; + MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee", + MethodType.genericMethodType(0, true)); + target = MethodHandles.collectArguments(target, type); + Object[] args = randomArgs(type.parameterArray()); + List targetPlusArgs = new ArrayList(Arrays.asList(args)); + targetPlusArgs.add(0, target); + int code = (Integer) invokee(args); + Object log = logEntry("invokee", args); + assertEquals(log.hashCode(), code); + assertCalled("invokee", args); + MethodHandle inv; + Object result; + // exact invoker + countTest(); + calledLog.clear(); + inv = MethodHandles.exactInvoker(type); + result = inv.invokeVarargs(targetPlusArgs); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + // generic invoker + countTest(); + inv = MethodHandles.genericInvoker(type); + if (nargs <= 3) { + calledLog.clear(); + switch (nargs) { + case 0: + result = inv.invoke(target); + break; + case 1: + result = inv.invoke(target, args[0]); + break; + case 2: + result = inv.invoke(target, args[0], args[1]); + break; + case 3: + result = inv.invoke(target, args[0], args[1], args[2]); + break; + } + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + calledLog.clear(); + result = inv.invokeVarargs(targetPlusArgs); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + // varargs invoker #0 + calledLog.clear(); + inv = MethodHandles.varargsInvoker(type, 0); + result = inv.invoke(target, args); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + if (nargs >= 1) { + // varargs invoker #1 + calledLog.clear(); + inv = MethodHandles.varargsInvoker(type, 1); + result = inv.invoke(target, args[0], Arrays.copyOfRange(args, 1, nargs)); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + if (nargs >= 2) { + // varargs invoker #2 + calledLog.clear(); + inv = MethodHandles.varargsInvoker(type, 2); + result = inv.invoke(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs)); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + if (nargs >= 3) { + // varargs invoker #3 + calledLog.clear(); + inv = MethodHandles.varargsInvoker(type, 3); + result = inv.invoke(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs)); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + for (int k = 0; k <= nargs; k++) { + // varargs invoker #0..N + countTest(); + calledLog.clear(); + inv = MethodHandles.varargsInvoker(type, k); + List targetPlusVarArgs = new ArrayList(targetPlusArgs); + List tailList = targetPlusVarArgs.subList(1+k, 1+nargs); + Object[] tail = tailList.toArray(); + tailList.clear(); tailList.add(tail); + result = inv.invokeVarargs(targetPlusVarArgs); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + // dynamic invoker + countTest(); + CallSite site = new CallSite(MethodHandlesTest.class, "foo", type); + inv = MethodHandles.dynamicInvoker(site); + site.setTarget(target); + calledLog.clear(); + result = inv.invokeVarargs(args); + if (testRetCode) assertEquals(code, result); + assertCalled("invokee", args); + } + + static Object invokee(Object... args) { + return called("invokee", args).hashCode(); + } + + private static final String MISSING_ARG = "missingArg"; + static Object targetIfEquals() { + return called("targetIfEquals"); + } + static Object fallbackIfNotEquals() { + return called("fallbackIfNotEquals"); + } + static Object targetIfEquals(Object x) { + assertEquals(x, MISSING_ARG); + return called("targetIfEquals", x); + } + static Object fallbackIfNotEquals(Object x) { + assertFalse(x.toString(), x.equals(MISSING_ARG)); + return called("fallbackIfNotEquals", x); + } + static Object targetIfEquals(Object x, Object y) { + assertEquals(x, y); + return called("targetIfEquals", x, y); + } + static Object fallbackIfNotEquals(Object x, Object y) { + assertFalse(x.toString(), x.equals(y)); + return called("fallbackIfNotEquals", x, y); + } + static Object targetIfEquals(Object x, Object y, Object z) { + assertEquals(x, y); + return called("targetIfEquals", x, y, z); + } + static Object fallbackIfNotEquals(Object x, Object y, Object z) { + assertFalse(x.toString(), x.equals(y)); + return called("fallbackIfNotEquals", x, y, z); + } + + @Test + public void testGuardWithTest() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("guardWithTest"); + for (int nargs = 0; nargs <= 3; nargs++) { + if (nargs != 2) continue; // FIXME: test more later + testGuardWithTest(nargs, Object.class); + testGuardWithTest(nargs, String.class); + } + } + void testGuardWithTest(int nargs, Class argClass) throws Throwable { + countTest(); + MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); + MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs)); + MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs)); + while (test.type().parameterCount() < nargs) + test = MethodHandles.dropArguments(test, test.type().parameterCount()-1, Object.class); + while (test.type().parameterCount() > nargs) + test = MethodHandles.insertArguments(test, 0, MISSING_ARG); + if (argClass != Object.class) { + test = changeArgTypes(test, argClass); + target = changeArgTypes(target, argClass); + fallback = changeArgTypes(fallback, argClass); + } + MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback); + assertEquals(target.type(), mh.type()); + Object[][] argLists = { + { }, + { "foo" }, { MISSING_ARG }, + { "foo", "foo" }, { "foo", "bar" }, + { "foo", "foo", "baz" }, { "foo", "bar", "baz" } + }; + for (Object[] argList : argLists) { + if (argList.length != nargs) continue; + boolean equals; + switch (nargs) { + case 0: equals = true; break; + case 1: equals = MISSING_ARG.equals(argList[0]); break; + default: equals = argList[0].equals(argList[1]); break; + } + String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); + if (verbosity >= 2) + System.out.println(logEntry(willCall, argList)); + Object result = mh.invokeVarargs(argList); + assertCalled(willCall, argList); + } + } + + @Test + public void testCatchException() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("catchException"); + for (int nargs = 2; nargs <= 6; nargs++) { + for (int ti = 0; ti <= 1; ti++) { + boolean throwIt = (ti != 0); + testCatchException(int.class, new ClassCastException("testing"), throwIt, nargs); + testCatchException(void.class, new java.io.IOException("testing"), throwIt, nargs); + testCatchException(String.class, new LinkageError("testing"), throwIt, nargs); + } + } + } + + private static + Object throwOrReturn(Object normal, T exception) throws T { + if (exception != null) throw exception; + return normal; + } + + void testCatchException(Class returnType, Throwable thrown, boolean throwIt, int nargs) throws Throwable { + countTest(); + if (verbosity >= 2) + System.out.println("catchException rt="+returnType+" throw="+throwIt+" nargs="+nargs); + Class exType = thrown.getClass(); + MethodHandle throwOrReturn + = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn", + MethodType.methodType(Object.class, Object.class, Throwable.class)); + MethodHandle thrower = throwOrReturn; + while (thrower.type().parameterCount() < nargs) + thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class); + MethodHandle target = MethodHandles.catchException(thrower, + thrown.getClass(), ValueConversions.varargsList(1+nargs)); + assertEquals(thrower.type(), target.type()); + //System.out.println("catching with "+target+" : "+throwOrReturn); + Object[] args = randomArgs(nargs, Object.class); + args[1] = (throwIt ? thrown : null); + Object returned = target.invokeVarargs(args); + //System.out.println("return from "+target+" : "+returned); + if (!throwIt) { + assertSame(args[0], returned); + } else { + List catchArgs = new ArrayList(Arrays.asList(args)); + catchArgs.add(0, thrown); + assertEquals(catchArgs, returned); + } + } + + @Test + public void testThrowException() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("throwException"); + testThrowException(int.class, new ClassCastException("testing")); + testThrowException(void.class, new java.io.IOException("testing")); + testThrowException(String.class, new LinkageError("testing")); + } + + void testThrowException(Class returnType, Throwable thrown) throws Throwable { + countTest(); + Class exType = thrown.getClass(); + MethodHandle target = MethodHandles.throwException(returnType, exType); + //System.out.println("throwing with "+target+" : "+thrown); + MethodType expectedType = MethodType.methodType(returnType, exType); + assertEquals(expectedType, target.type()); + Throwable caught = null; + try { + Object res = target.invokeGeneric(thrown); + fail("got "+res+" instead of throwing "+thrown); + } catch (Throwable ex) { + if (ex != thrown) { + if (ex instanceof Error) throw (Error)ex; + if (ex instanceof RuntimeException) throw (RuntimeException)ex; + } + caught = ex; + } + assertSame(thrown, caught); + } + + @Test + public void testCastFailure() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("testCastFailure"); + testCastFailure("cast/argument", 11000); + testCastFailure("unbox/argument", 11000); + testCastFailure("cast/return", 11000); + testCastFailure("unbox/return", 11000); + } + + static class Surprise extends JavaMethodHandle { + Surprise() { super("value"); } + Object value(Object x) { + trace("value", x); + if (boo != null) return boo; + return x; + } + Object boo; + void boo(Object x) { boo = x; } + + static void trace(String x, Object y) { + if (verbosity > 8) System.out.println(x+"="+y); + } + static Object refIdentity(Object x) { trace("ref.x", x); return x; } + static Integer boxIdentity(Integer x) { trace("box.x", x); return x; } + static int intIdentity(int x) { trace("int.x", x); return x; } + static MethodHandle REF_IDENTITY = PRIVATE.findStatic( + Surprise.class, "refIdentity", + MethodType.methodType(Object.class, Object.class)); + static MethodHandle BOX_IDENTITY = PRIVATE.findStatic( + Surprise.class, "boxIdentity", + MethodType.methodType(Integer.class, Integer.class)); + static MethodHandle INT_IDENTITY = PRIVATE.findStatic( + Surprise.class, "intIdentity", + MethodType.methodType(int.class, int.class)); + } + + void testCastFailure(String mode, int okCount) throws Throwable { + countTest(false); + if (verbosity > 1) System.out.println("mode="+mode); + Surprise boo = new Surprise(); + MethodHandle identity = Surprise.REF_IDENTITY, surprise = boo; + if (mode.endsWith("/return")) { + if (mode.equals("unbox/return")) { + // fail on return to ((Integer)surprise).intValue + surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(int.class, Object.class)); + identity = MethodHandles.convertArguments(identity, MethodType.methodType(int.class, Object.class)); + } else if (mode.equals("cast/return")) { + // fail on return to (Integer)surprise + surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(Integer.class, Object.class)); + identity = MethodHandles.convertArguments(identity, MethodType.methodType(Integer.class, Object.class)); + } + } else if (mode.endsWith("/argument")) { + MethodHandle callee = null; + if (mode.equals("unbox/argument")) { + // fail on handing surprise to int argument + callee = Surprise.INT_IDENTITY; + } else if (mode.equals("cast/argument")) { + // fail on handing surprise to Integer argument + callee = Surprise.BOX_IDENTITY; + } + if (callee != null) { + callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1)); + surprise = MethodHandles.filterArguments(callee, surprise); + identity = MethodHandles.filterArguments(callee, identity); + } + } + assertNotSame(mode, surprise, boo); + identity = MethodHandles.convertArguments(identity, MethodType.genericMethodType(1)); + surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1)); + Object x = 42; + for (int i = 0; i < okCount; i++) { + Object y = identity.invoke(x); + assertEquals(x, y); + Object z = surprise.invoke(x); + assertEquals(x, z); + } + boo.boo("Boo!"); + Object y = identity.invoke(x); + assertEquals(x, y); + try { + Object z = surprise.invoke(x); + System.out.println("Failed to throw; got z="+z); + assertTrue(false); + } catch (Exception ex) { + if (verbosity > 1) + System.out.println("caught "+ex); + if (verbosity > 2) + ex.printStackTrace(); + assertTrue(ex instanceof ClassCastException + // FIXME: accept only one of the two for any given unit test + || ex instanceof WrongMethodTypeException + ); + } + } + +} +// Local abbreviated copy of sun.dyn.util.ValueConversions +class ValueConversions { + private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); + private static final Object[] NO_ARGS_ARRAY = {}; + private static Object[] makeArray(Object... args) { return args; } + private static Object[] array() { return NO_ARGS_ARRAY; } + private static Object[] array(Object a0) + { return makeArray(a0); } + private static Object[] array(Object a0, Object a1) + { return makeArray(a0, a1); } + private static Object[] array(Object a0, Object a1, Object a2) + { return makeArray(a0, a1, a2); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3) + { return makeArray(a0, a1, a2, a3); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4) + { return makeArray(a0, a1, a2, a3, a4); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { return makeArray(a0, a1, a2, a3, a4, a5); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { return makeArray(a0, a1, a2, a3, a4, a5, a6); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + private static Object[] array(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + static MethodHandle[] makeArrays() { + ArrayList arrays = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = arrays.size(); + MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); + String name = "array"; + MethodHandle array = null; + try { + array = lookup.findStatic(ValueConversions.class, name, type); + } catch (NoAccessException ex) { + } + if (array == null) break; + arrays.add(array); + } + assert(arrays.size() == 11); // current number of methods + return arrays.toArray(new MethodHandle[0]); + } + static final MethodHandle[] ARRAYS = makeArrays(); + + /** Return a method handle that takes the indicated number of Object + * arguments and returns an Object array of them, as if for varargs. + */ + public static MethodHandle varargsArray(int nargs) { + if (nargs < ARRAYS.length) + return ARRAYS[nargs]; + // else need to spin bytecode or do something else fancy + throw new UnsupportedOperationException("NYI"); + } + + private static final List NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); + private static List makeList(Object... args) { return Arrays.asList(args); } + private static List list() { return NO_ARGS_LIST; } + private static List list(Object a0) + { return makeList(a0); } + private static List list(Object a0, Object a1) + { return makeList(a0, a1); } + private static List list(Object a0, Object a1, Object a2) + { return makeList(a0, a1, a2); } + private static List list(Object a0, Object a1, Object a2, Object a3) + { return makeList(a0, a1, a2, a3); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4) + { return makeList(a0, a1, a2, a3, a4); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5) + { return makeList(a0, a1, a2, a3, a4, a5); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6) + { return makeList(a0, a1, a2, a3, a4, a5, a6); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } + private static List list(Object a0, Object a1, Object a2, Object a3, + Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } + static MethodHandle[] makeLists() { + ArrayList arrays = new ArrayList(); + MethodHandles.Lookup lookup = IMPL_LOOKUP; + for (;;) { + int nargs = arrays.size(); + MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); + String name = "list"; + MethodHandle array = null; + try { + array = lookup.findStatic(ValueConversions.class, name, type); + } catch (NoAccessException ex) { + } + if (array == null) break; + arrays.add(array); + } + assert(arrays.size() == 11); // current number of methods + return arrays.toArray(new MethodHandle[0]); + } + static final MethodHandle[] LISTS = makeLists(); + + /** Return a method handle that takes the indicated number of Object + * arguments and returns List. + */ + public static MethodHandle varargsList(int nargs) { + if (nargs < LISTS.length) + return LISTS[nargs]; + // else need to spin bytecode or do something else fancy + throw new UnsupportedOperationException("NYI"); + } +} +// This guy tests access from outside the same package member, but inside +// the package itself. +class PackageSibling { + static Lookup lookup() { + return MethodHandles.lookup(); + } +} diff --git a/jdk/test/java/io/File/Basic.java b/jdk/test/java/io/File/Basic.java index a57c6ccddef..cbb8259e5fe 100644 --- a/jdk/test/java/io/File/Basic.java +++ b/jdk/test/java/io/File/Basic.java @@ -75,7 +75,7 @@ public class Basic { if (!f.canRead()) fail(f, "is not readable"); if (f.canWrite() != writeable) fail(f, writeable ? "is not writeable" : "is writeable"); - int rwLen = (File.separatorChar == '/' ? 6 : 7); + int rwLen = 6; if (f.length() != length) fail(f, "has wrong length"); } @@ -89,7 +89,7 @@ public class Basic { if (nonExistantFile.exists()) fail(nonExistantFile, "exists"); show(rwFile); - testFile(rwFile, true, File.separatorChar == '/' ? 6 : 7); + testFile(rwFile, true, 6); rwFile.delete(); if (rwFile.exists()) fail(rwFile, "could not delete"); diff --git a/jdk/test/java/io/File/basic.sh b/jdk/test/java/io/File/basic.sh index fa11c66536b..cc87ac32e84 100644 --- a/jdk/test/java/io/File/basic.sh +++ b/jdk/test/java/io/File/basic.sh @@ -32,10 +32,10 @@ fi rm -rf x.Basic.* rm -f x.Basic.non -echo xyzzy > x.Basic.rw +printf "%s" "xyzzyN" > x.Basic.rw touch x.Basic.ro; chmod ugo-w x.Basic.ro mkdir x.Basic.dir -if $TESTJAVA/bin/java $* -classpath $TESTCLASSES Basic; then +if $TESTJAVA/bin/java $* -classpath "$TESTCLASSES" Basic; then [ -f x.Basic.rw ] && (echo "x.Basic.rw not deleted"; exit 1) ([ -d x.Basic.dir ] || [ \! -d x.Basic.dir2 ]) \ && (echo "x.Basic.dir not renamed"; exit 1) diff --git a/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh b/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh index 2f194c06123..df76b738308 100644 --- a/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh +++ b/jdk/test/java/io/Serializable/evolution/RenamePackage/run.sh @@ -43,7 +43,7 @@ OS=`uname -s` case "$OS" in SunOS | Linux ) PS=":" ;; -Windows* ) +Windows* | CYGWIN* ) PS=";" ;; * ) echo "Unrecognized system!" @@ -85,14 +85,14 @@ CLASSPATH=${TESTCLASSES}/share; export CLASSPATH; ${JAVAC} -d ${TESTCLASSES}/nclasses ${TESTSRC}/install/SerialDriver.java # Run Case 1. Map test.SerialDriver within stream to install.SerialDriver. -CLASSPATH=${TESTCLASSES}/oclasses${PS}${TESTCLASSES}/share; export CLASSPATH; +CLASSPATH="${TESTCLASSES}/oclasses${PS}${TESTCLASSES}/share"; export CLASSPATH; ${JAVA} test.SerialDriver -s -CLASSPATH=${TESTCLASSES}/nclasses${PS}${TESTCLASSES}/share; export CLASSPATH; +CLASSPATH="${TESTCLASSES}/nclasses${PS}${TESTCLASSES}/share"; export CLASSPATH; ${JAVA} install.SerialDriver -d rm stream.ser # Run Case 2. Map install.SerialDriver within stream to test.SerialDriver. -CLASSPATH=${TESTCLASSES}/nclasses${PS}${TESTCLASSES}/share; export CLASSPATH; +CLASSPATH="${TESTCLASSES}/nclasses${PS}${TESTCLASSES}/share"; export CLASSPATH; ${JAVA} install.SerialDriver -s -CLASSPATH=${TESTCLASSES}/oclasses${PS}${TESTCLASSES}/share; export CLASSPATH; +CLASSPATH="${TESTCLASSES}/oclasses${PS}${TESTCLASSES}/share"; export CLASSPATH; ${JAVA} test.SerialDriver -d diff --git a/jdk/test/java/io/Serializable/serialver/classpath/run.sh b/jdk/test/java/io/Serializable/serialver/classpath/run.sh index aa3251e4798..6fb127f89fa 100644 --- a/jdk/test/java/io/Serializable/serialver/classpath/run.sh +++ b/jdk/test/java/io/Serializable/serialver/classpath/run.sh @@ -49,7 +49,7 @@ OS=`uname -s` case "$OS" in SunOS | Linux ) PS=":" ;; - Windows* ) + Windows* | CYGWIN* ) PS=";" ;; * ) echo "Unrecognized system!" diff --git a/jdk/test/java/io/Serializable/serialver/nested/run.sh b/jdk/test/java/io/Serializable/serialver/nested/run.sh index 57b0ca0a759..9b53f756f1e 100644 --- a/jdk/test/java/io/Serializable/serialver/nested/run.sh +++ b/jdk/test/java/io/Serializable/serialver/nested/run.sh @@ -49,7 +49,7 @@ OS=`uname -s` case "$OS" in SunOS | Linux ) PS=":" ;; - Windows* ) + Windows* | CYGWIN* ) PS=";" ;; * ) echo "Unrecognized system!" diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh index 1f6a08ff342..e4aac0ddd60 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh @@ -55,7 +55,7 @@ case "$OS" in Linux ) FS="/" ;; - Windows* ) + Windows* | CYGWIN* ) FS="\\" ;; esac diff --git a/jdk/test/java/lang/Math/CeilAndFloorTests.java b/jdk/test/java/lang/Math/CeilAndFloorTests.java new file mode 100644 index 00000000000..12d899d8180 --- /dev/null +++ b/jdk/test/java/lang/Math/CeilAndFloorTests.java @@ -0,0 +1,201 @@ +/* + * 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 6908131 + * @summary Check for correct implementation of Math.ceil and Math.floor + */ + +import sun.misc.FpUtils; +import sun.misc.DoubleConsts; + +public class CeilAndFloorTests { + private static int testCeilCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.ceil", input, Math.ceil(input), expected); + failures += Tests.test("StrictMath.ceil", input, StrictMath.ceil(input), expected); + return failures; + } + + private static int testFloorCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.floor", input, Math.floor(input), expected); + failures += Tests.test("StrictMath.floor", input, StrictMath.floor(input), expected); + return failures; + } + + private static int nearIntegerTests() { + int failures = 0; + + double [] fixedPoints = { + -0.0, + 0.0, + -1.0, + 1.0, + -0x1.0p52, + 0x1.0p52, + -Double.MAX_VALUE, + Double.MAX_VALUE, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.NaN, + }; + + for(double fixedPoint : fixedPoints) { + failures += testCeilCase(fixedPoint, fixedPoint); + failures += testFloorCase(fixedPoint, fixedPoint); + } + + for(int i = Double.MIN_EXPONENT; i <= Double.MAX_EXPONENT; i++) { + double powerOfTwo = Math.scalb(1.0, i); + double neighborDown = FpUtils.nextDown(powerOfTwo); + double neighborUp = Math.nextUp(powerOfTwo); + + if (i < 0) { + failures += testCeilCase( powerOfTwo, 1.0); + failures += testCeilCase(-powerOfTwo, -0.0); + + failures += testFloorCase( powerOfTwo, 0.0); + failures += testFloorCase(-powerOfTwo, -1.0); + + failures += testCeilCase( neighborDown, 1.0); + failures += testCeilCase(-neighborDown, -0.0); + + failures += testFloorCase( neighborUp, 0.0); + failures += testFloorCase(-neighborUp, -1.0); + } else { + failures += testCeilCase(powerOfTwo, powerOfTwo); + failures += testFloorCase(powerOfTwo, powerOfTwo); + + if (neighborDown==Math.rint(neighborDown)) { + failures += testCeilCase( neighborDown, neighborDown); + failures += testCeilCase(-neighborDown, -neighborDown); + + failures += testFloorCase( neighborDown, neighborDown); + failures += testFloorCase(-neighborDown,-neighborDown); + } else { + failures += testCeilCase( neighborDown, powerOfTwo); + failures += testFloorCase(-neighborDown, -powerOfTwo); + } + + if (neighborUp==Math.rint(neighborUp)) { + failures += testCeilCase(neighborUp, neighborUp); + failures += testCeilCase(-neighborUp, -neighborUp); + + failures += testFloorCase(neighborUp, neighborUp); + failures += testFloorCase(-neighborUp, -neighborUp); + } else { + failures += testFloorCase(neighborUp, powerOfTwo); + failures += testCeilCase(-neighborUp, -powerOfTwo); + } + } + } + + for(int i = -(0x10000); i <= 0x10000; i++) { + double d = (double) i; + double neighborDown = FpUtils.nextDown(d); + double neighborUp = Math.nextUp(d); + + failures += testCeilCase( d, d); + failures += testCeilCase(-d, -d); + + failures += testFloorCase( d, d); + failures += testFloorCase(-d, -d); + + if (Math.abs(d) > 1.0) { + failures += testCeilCase( neighborDown, d); + failures += testCeilCase(-neighborDown, -d+1); + + failures += testFloorCase( neighborUp, d); + failures += testFloorCase(-neighborUp, -d-1); + } + } + + return failures; + } + + public static int roundingTests() { + int failures = 0; + double [][] testCases = { + { Double.MIN_VALUE, 1.0}, + {-Double.MIN_VALUE, -0.0}, + { FpUtils.nextDown(DoubleConsts.MIN_NORMAL), 1.0}, + {-FpUtils.nextDown(DoubleConsts.MIN_NORMAL), -0.0}, + { DoubleConsts.MIN_NORMAL, 1.0}, + {-DoubleConsts.MIN_NORMAL, -0.0}, + + { 0.1, 1.0}, + {-0.1, -0.0}, + + { 0.5, 1.0}, + {-0.5, -0.0}, + + { 1.5, 2.0}, + {-1.5, -1.0}, + + { 2.5, 3.0}, + {-2.5, -2.0}, + + { FpUtils.nextDown(1.0), 1.0}, + { FpUtils.nextDown(-1.0), -1.0}, + + { Math.nextUp(1.0), 2.0}, + { Math.nextUp(-1.0), -0.0}, + + { 0x1.0p51, 0x1.0p51}, + {-0x1.0p51, -0x1.0p51}, + + { FpUtils.nextDown(0x1.0p51), 0x1.0p51}, + {-Math.nextUp(0x1.0p51), -0x1.0p51}, + + { Math.nextUp(0x1.0p51), 0x1.0p51+1}, + {-FpUtils.nextDown(0x1.0p51), -0x1.0p51+1}, + + { FpUtils.nextDown(0x1.0p52), 0x1.0p52}, + {-Math.nextUp(0x1.0p52), -0x1.0p52-1.0}, + + { Math.nextUp(0x1.0p52), 0x1.0p52+1.0}, + {-FpUtils.nextDown(0x1.0p52), -0x1.0p52+1.0}, + }; + + for(double[] testCase : testCases) { + failures += testCeilCase(testCase[0], testCase[1]); + failures += testFloorCase(-testCase[0], -testCase[1]); + } + return failures; + } + + public static void main(String... args) { + int failures = 0; + + failures += nearIntegerTests(); + failures += roundingTests(); + + if (failures > 0) { + System.err.println("Testing {Math, StrictMath}.ceil incurred " + + failures + " failures."); + throw new RuntimeException(); + } + } +} diff --git a/jdk/test/java/lang/StringCoding/CheckEncodings.sh b/jdk/test/java/lang/StringCoding/CheckEncodings.sh index 6fa20c4d5a6..9bfe2f7aad6 100644 --- a/jdk/test/java/lang/StringCoding/CheckEncodings.sh +++ b/jdk/test/java/lang/StringCoding/CheckEncodings.sh @@ -31,7 +31,7 @@ OS=`uname -s` case "$OS" in SunOS | Linux ) ;; - Windows* ) + Windows* | CYGWIN* ) echo "Passed"; exit 0 ;; * ) echo "Unrecognized system!" ; exit 1 ;; esac diff --git a/jdk/test/java/lang/System/finalization/FinExit.sh b/jdk/test/java/lang/System/finalization/FinExit.sh index d2e48da8fe3..c08fb6fdd5d 100644 --- a/jdk/test/java/lang/System/finalization/FinExit.sh +++ b/jdk/test/java/lang/System/finalization/FinExit.sh @@ -24,7 +24,9 @@ # # -x=`$TESTJAVA/bin/java -cp $TESTCLASSES FinExit` + +# We only want the first character, Windows might add CRLF +x=`$TESTJAVA/bin/java -cp "$TESTCLASSES" FinExit | cut -c1` echo $x if [ "x$x" != "x1" ]; then echo On-exit finalizer invoked twice diff --git a/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh b/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh index d8a47462f9b..28ac016d423 100644 --- a/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh +++ b/jdk/test/java/lang/annotation/loaderLeak/LoaderLeak.sh @@ -49,6 +49,11 @@ case "$OS" in PS=":" FS="/" ;; + CYGWIN* ) + NULL=/dev/null + PS=";" + FS="/" + ;; Windows* ) NULL=NUL PS=";" diff --git a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh index 0fdce4ba0a4..c2b1a763bb8 100644 --- a/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh +++ b/jdk/test/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh @@ -43,11 +43,17 @@ case "$OS" in PS=":" FS="/" ;; - Windows* | CYGWIN*) + Windows*) PS=";" OS="Windows" FS="\\" ;; + CYGWIN*) + PS=";" + OS="Windows" + FS="\\" + isCygwin=true + ;; * ) echo "Unrecognized system!" exit 1; diff --git a/jdk/test/java/math/BigInteger/BigIntegerTest.java b/jdk/test/java/math/BigInteger/BigIntegerTest.java index 75ce0033779..c5196eb7252 100644 --- a/jdk/test/java/math/BigInteger/BigIntegerTest.java +++ b/jdk/test/java/math/BigInteger/BigIntegerTest.java @@ -642,37 +642,71 @@ public class BigIntegerTest { for(int i = 0; i < bitPatterns.length; i++) { BigInteger b1 = new BigInteger(bitPatterns[i], 16); + BigInteger b2 = null; File f = new File("serialtest"); FileOutputStream fos = new FileOutputStream(f); - ObjectOutputStream oos = new ObjectOutputStream(fos); - oos.writeObject(b1); - oos.flush(); - oos.close(); - FileInputStream fis = new FileInputStream(f); - ObjectInputStream ois = new ObjectInputStream(fis); - BigInteger b2 = (BigInteger)ois.readObject(); + try { + ObjectOutputStream oos = new ObjectOutputStream(fos); + try { + oos.writeObject(b1); + oos.flush(); + } finally { + oos.close(); + } - if (!b1.equals(b2) || - !b1.equals(b1.or(b2))) { - failCount++; - System.err.println("Serialized failed for hex " + - b1.toString(16)); + FileInputStream fis = new FileInputStream(f); + try { + ObjectInputStream ois = new ObjectInputStream(fis); + try { + b2 = (BigInteger)ois.readObject(); + } finally { + ois.close(); + } + } finally { + fis.close(); + } + + if (!b1.equals(b2) || + !b1.equals(b1.or(b2))) { + failCount++; + System.err.println("Serialized failed for hex " + + b1.toString(16)); + } + } finally { + fos.close(); } f.delete(); } for(int i=0; i<10; i++) { BigInteger b1 = fetchNumber(rnd.nextInt(100)); + BigInteger b2 = null; File f = new File("serialtest"); FileOutputStream fos = new FileOutputStream(f); - ObjectOutputStream oos = new ObjectOutputStream(fos); - oos.writeObject(b1); - oos.flush(); - oos.close(); - FileInputStream fis = new FileInputStream(f); - ObjectInputStream ois = new ObjectInputStream(fis); - BigInteger b2 = (BigInteger)ois.readObject(); + try { + ObjectOutputStream oos = new ObjectOutputStream(fos); + try { + oos.writeObject(b1); + oos.flush(); + } finally { + oos.close(); + } + + FileInputStream fis = new FileInputStream(f); + try { + ObjectInputStream ois = new ObjectInputStream(fis); + try { + b2 = (BigInteger)ois.readObject(); + } finally { + ois.close(); + } + } finally { + fis.close(); + } + } finally { + fos.close(); + } if (!b1.equals(b2) || !b1.equals(b1.or(b2))) diff --git a/jdk/test/java/nio/Buffer/Basic-X.java.template b/jdk/test/java/nio/Buffer/Basic-X.java.template index 6612771def4..93cbe8eb5ee 100644 --- a/jdk/test/java/nio/Buffer/Basic-X.java.template +++ b/jdk/test/java/nio/Buffer/Basic-X.java.template @@ -38,6 +38,26 @@ public class Basic$Type$ extends Basic { + private static final $type$[] VALUES = { + $Fulltype$.MIN_VALUE, + ($type$) -1, + ($type$) 0, + ($type$) 1, + $Fulltype$.MAX_VALUE, +#if[float] + $Fulltype$.NEGATIVE_INFINITY, + $Fulltype$.POSITIVE_INFINITY, + $Fulltype$.NaN, + ($type$) -0.0, +#end[float] +#if[double] + $Fulltype$.NEGATIVE_INFINITY, + $Fulltype$.POSITIVE_INFINITY, + $Fulltype$.NaN, + ($type$) -0.0, +#end[double] + }; + private static void relGet($Type$Buffer b) { int n = b.capacity(); $type$ v; @@ -309,6 +329,12 @@ public class Basic$Type$ #end[byte] + private static void fail(String problem, + $Type$Buffer xb, $Type$Buffer yb, + $type$ x, $type$ y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } + private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; try { @@ -522,6 +548,42 @@ public class Basic$Type$ if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for ($type$ x : VALUES) { + $Type$Buffer xb = $Type$Buffer.wrap(new $type$[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for ($type$ y : VALUES) { + $Type$Buffer yb = $Type$Buffer.wrap(new $type$[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != $Fulltype$.compare(x, y)) { +#if[float] + if (x == 0.0 && y == 0.0) continue; +#end[float] +#if[double] + if (x == 0.0 && y == 0.0) continue; +#end[double] + fail("Incorrect results for $Type$Buffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for $Type$Buffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicByte.java b/jdk/test/java/nio/Buffer/BasicByte.java index 7e259a1416d..78b209936d7 100644 --- a/jdk/test/java/nio/Buffer/BasicByte.java +++ b/jdk/test/java/nio/Buffer/BasicByte.java @@ -38,6 +38,26 @@ public class BasicByte extends Basic { + private static final byte[] VALUES = { + Byte.MIN_VALUE, + (byte) -1, + (byte) 0, + (byte) 1, + Byte.MAX_VALUE, + + + + + + + + + + + + + }; + private static void relGet(ByteBuffer b) { int n = b.capacity(); byte v; @@ -309,6 +329,12 @@ public class BasicByte + private static void fail(String problem, + ByteBuffer xb, ByteBuffer yb, + byte x, byte y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } + private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; try { @@ -522,6 +548,42 @@ public class BasicByte if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (byte x : VALUES) { + ByteBuffer xb = ByteBuffer.wrap(new byte[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (byte y : VALUES) { + ByteBuffer yb = ByteBuffer.wrap(new byte[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Byte.compare(x, y)) { + + + + + + + fail("Incorrect results for ByteBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for ByteBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicChar.java b/jdk/test/java/nio/Buffer/BasicChar.java index a0df9fcf3a9..9f3c5e4219c 100644 --- a/jdk/test/java/nio/Buffer/BasicChar.java +++ b/jdk/test/java/nio/Buffer/BasicChar.java @@ -38,6 +38,26 @@ public class BasicChar extends Basic { + private static final char[] VALUES = { + Character.MIN_VALUE, + (char) -1, + (char) 0, + (char) 1, + Character.MAX_VALUE, + + + + + + + + + + + + + }; + private static void relGet(CharBuffer b) { int n = b.capacity(); char v; @@ -308,6 +328,12 @@ public class BasicChar + + private static void fail(String problem, + CharBuffer xb, CharBuffer yb, + char x, char y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicChar if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (char x : VALUES) { + CharBuffer xb = CharBuffer.wrap(new char[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (char y : VALUES) { + CharBuffer yb = CharBuffer.wrap(new char[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Character.compare(x, y)) { + + + + + + + fail("Incorrect results for CharBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for CharBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicDouble.java b/jdk/test/java/nio/Buffer/BasicDouble.java index a627d0e9194..97f5fa200de 100644 --- a/jdk/test/java/nio/Buffer/BasicDouble.java +++ b/jdk/test/java/nio/Buffer/BasicDouble.java @@ -38,6 +38,26 @@ public class BasicDouble extends Basic { + private static final double[] VALUES = { + Double.MIN_VALUE, + (double) -1, + (double) 0, + (double) 1, + Double.MAX_VALUE, + + + + + + + + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.NaN, + (double) -0.0, + + }; + private static void relGet(DoubleBuffer b) { int n = b.capacity(); double v; @@ -308,6 +328,12 @@ public class BasicDouble + + private static void fail(String problem, + DoubleBuffer xb, DoubleBuffer yb, + double x, double y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicDouble if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (double x : VALUES) { + DoubleBuffer xb = DoubleBuffer.wrap(new double[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (double y : VALUES) { + DoubleBuffer yb = DoubleBuffer.wrap(new double[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Double.compare(x, y)) { + + + + + if (x == 0.0 && y == 0.0) continue; + + fail("Incorrect results for DoubleBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for DoubleBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicFloat.java b/jdk/test/java/nio/Buffer/BasicFloat.java index 730dcbeac95..46bdfe163cb 100644 --- a/jdk/test/java/nio/Buffer/BasicFloat.java +++ b/jdk/test/java/nio/Buffer/BasicFloat.java @@ -38,6 +38,26 @@ public class BasicFloat extends Basic { + private static final float[] VALUES = { + Float.MIN_VALUE, + (float) -1, + (float) 0, + (float) 1, + Float.MAX_VALUE, + + Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, + Float.NaN, + (float) -0.0, + + + + + + + + }; + private static void relGet(FloatBuffer b) { int n = b.capacity(); float v; @@ -308,6 +328,12 @@ public class BasicFloat + + private static void fail(String problem, + FloatBuffer xb, FloatBuffer yb, + float x, float y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicFloat if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (float x : VALUES) { + FloatBuffer xb = FloatBuffer.wrap(new float[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (float y : VALUES) { + FloatBuffer yb = FloatBuffer.wrap(new float[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Float.compare(x, y)) { + + if (x == 0.0 && y == 0.0) continue; + + + + + fail("Incorrect results for FloatBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for FloatBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicInt.java b/jdk/test/java/nio/Buffer/BasicInt.java index b20e4bb1056..478debd76e1 100644 --- a/jdk/test/java/nio/Buffer/BasicInt.java +++ b/jdk/test/java/nio/Buffer/BasicInt.java @@ -38,6 +38,26 @@ public class BasicInt extends Basic { + private static final int[] VALUES = { + Integer.MIN_VALUE, + (int) -1, + (int) 0, + (int) 1, + Integer.MAX_VALUE, + + + + + + + + + + + + + }; + private static void relGet(IntBuffer b) { int n = b.capacity(); int v; @@ -308,6 +328,12 @@ public class BasicInt + + private static void fail(String problem, + IntBuffer xb, IntBuffer yb, + int x, int y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicInt if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (int x : VALUES) { + IntBuffer xb = IntBuffer.wrap(new int[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (int y : VALUES) { + IntBuffer yb = IntBuffer.wrap(new int[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Integer.compare(x, y)) { + + + + + + + fail("Incorrect results for IntBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for IntBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicLong.java b/jdk/test/java/nio/Buffer/BasicLong.java index 0d4c568e1e3..0abc7cdf2f4 100644 --- a/jdk/test/java/nio/Buffer/BasicLong.java +++ b/jdk/test/java/nio/Buffer/BasicLong.java @@ -38,6 +38,26 @@ public class BasicLong extends Basic { + private static final long[] VALUES = { + Long.MIN_VALUE, + (long) -1, + (long) 0, + (long) 1, + Long.MAX_VALUE, + + + + + + + + + + + + + }; + private static void relGet(LongBuffer b) { int n = b.capacity(); long v; @@ -308,6 +328,12 @@ public class BasicLong + + private static void fail(String problem, + LongBuffer xb, LongBuffer yb, + long x, long y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicLong if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (long x : VALUES) { + LongBuffer xb = LongBuffer.wrap(new long[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (long y : VALUES) { + LongBuffer yb = LongBuffer.wrap(new long[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Long.compare(x, y)) { + + + + + + + fail("Incorrect results for LongBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for LongBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/BasicShort.java b/jdk/test/java/nio/Buffer/BasicShort.java index 58e5a3e6d68..861d356b6df 100644 --- a/jdk/test/java/nio/Buffer/BasicShort.java +++ b/jdk/test/java/nio/Buffer/BasicShort.java @@ -38,6 +38,26 @@ public class BasicShort extends Basic { + private static final short[] VALUES = { + Short.MIN_VALUE, + (short) -1, + (short) 0, + (short) 1, + Short.MAX_VALUE, + + + + + + + + + + + + + }; + private static void relGet(ShortBuffer b) { int n = b.capacity(); short v; @@ -308,6 +328,12 @@ public class BasicShort + + private static void fail(String problem, + ShortBuffer xb, ShortBuffer yb, + short x, short y) { + fail(problem + String.format(": x=%s y=%s", x, y), xb, yb); + } private static void tryCatch(Buffer b, Class ex, Runnable thunk) { boolean caught = false; @@ -522,6 +548,42 @@ public class BasicShort if (b.compareTo(b2) <= 0) fail("Comparison to lesser buffer <= 0", b, b2); + // Check equals and compareTo with interesting values + for (short x : VALUES) { + ShortBuffer xb = ShortBuffer.wrap(new short[] { x }); + if (xb.compareTo(xb) != 0) { + fail("compareTo not reflexive", xb, xb, x, x); + } + if (! xb.equals(xb)) { + fail("equals not reflexive", xb, xb, x, x); + } + for (short y : VALUES) { + ShortBuffer yb = ShortBuffer.wrap(new short[] { y }); + if (xb.compareTo(yb) != - yb.compareTo(xb)) { + fail("compareTo not anti-symmetric", + xb, yb, x, y); + } + if ((xb.compareTo(yb) == 0) != xb.equals(yb)) { + fail("compareTo inconsistent with equals", + xb, yb, x, y); + } + if (xb.compareTo(yb) != Short.compare(x, y)) { + + + + + + + fail("Incorrect results for ShortBuffer.compareTo", + xb, yb, x, y); + } + if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) { + fail("Incorrect results for ShortBuffer.equals", + xb, yb, x, y); + } + } + } + // Sub, dup relPut(b); diff --git a/jdk/test/java/nio/Buffer/genBasic.sh b/jdk/test/java/nio/Buffer/genBasic.sh index da5fca5df33..009cf2dbb1b 100644 --- a/jdk/test/java/nio/Buffer/genBasic.sh +++ b/jdk/test/java/nio/Buffer/genBasic.sh @@ -36,5 +36,3 @@ gen int Int Integer gen long Long Long gen float Float Float gen double Double Double - -rm -rf build diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java new file mode 100644 index 00000000000..dd2c27ddbd4 --- /dev/null +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/LotsOfWrites.java @@ -0,0 +1,162 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6913877 + * @summary Stress AsynchronousFileChannel.write + */ + +import java.io.*; +import java.nio.ByteBuffer; +import static java.nio.file.StandardOpenOption.*; +import java.nio.channels.*; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +public class LotsOfWrites { + static final Random rand = new Random(); + + /** + * Asynchronously writes a known pattern to a file up to a given size, + * counting down a latch to release waiters when done. + */ + static class Writer implements CompletionHandler { + private final File file; + private final long size; + private final CountDownLatch latch; + private final AsynchronousFileChannel channel; + + private volatile long position; + private volatile byte nextByte; + + private long updatePosition(long nwrote) { + position += nwrote; + return position; + } + + private ByteBuffer genNextBuffer() { + int n = Math.min(8192 + rand.nextInt(8192), (int)(size - position)); + ByteBuffer buf = ByteBuffer.allocate(n); + for (int i=0; i= size) { + done(); + return; + } + buf = genNextBuffer(); + } + channel.write(buf, pos, buf, this); + } + + @Override + public void failed(Throwable exc, ByteBuffer buf) { + exc.printStackTrace(); + done(); + } + } + + public static void main(String[] args) throws Exception { + // random number of writers + int count = 20 + rand.nextInt(16); + Writer[] writers = new Writer[count]; + CountDownLatch latch = new CountDownLatch(count); + + // initiate writing to each file + for (int i=0; i 0) { + for (int j=0; j env = Collections.emptyMap(); + URI uri = URI.create("pass:///"); + return provider.newFileSystem(uri, env); + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public void close() throws IOException { + delegate.close(); + } + + @Override + public boolean isOpen() { + return delegate.isOpen(); + } + + @Override + public boolean isReadOnly() { + return delegate.isReadOnly(); + } + + @Override + public String getSeparator() { + return delegate.getSeparator(); + } + + @Override + public Iterable getRootDirectories() { + final Iterable roots = delegate.getRootDirectories(); + return new Iterable() { + @Override + public Iterator iterator() { + final Iterator itr = roots.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return new PassThroughPath(delegate, itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + }; + } + + @Override + public Iterable getFileStores() { + // assume that unwrapped objects aren't exposed + return delegate.getFileStores(); + } + + @Override + public Set supportedFileAttributeViews() { + // assume that unwrapped objects aren't exposed + return delegate.supportedFileAttributeViews(); + } + + @Override + public Path getPath(String path) { + return new PassThroughPath(this, delegate.getPath(path)); + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndPattern) { + final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + return matcher.matches(PassThroughPath.unwrap(path)); + } + }; + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + // assume that unwrapped objects aren't exposed + return delegate.getUserPrincipalLookupService(); + } + + @Override + public WatchService newWatchService() throws IOException { + // to keep it simple + throw new UnsupportedOperationException(); + } + + static class PassThroughProvider extends FileSystemProvider { + private static final String SCHEME = "pass"; + private static volatile PassThroughFileSystem delegate; + + public PassThroughProvider() { } + + @Override + public String getScheme() { + return SCHEME; + } + + private void checkScheme(URI uri) { + if (!uri.getScheme().equalsIgnoreCase(SCHEME)) + throw new IllegalArgumentException(); + } + + private void checkUri(URI uri) { + checkScheme(uri); + if (!uri.getSchemeSpecificPart().equals("///")) + throw new IllegalArgumentException(); + } + + @Override + public FileSystem newFileSystem(URI uri, Map env) + throws IOException + { + checkUri(uri); + synchronized (PassThroughProvider.class) { + if (delegate != null) + throw new FileSystemAlreadyExistsException(); + PassThroughFileSystem result = + new PassThroughFileSystem(this, FileSystems.getDefault()); + delegate = result; + return result; + } + } + + @Override + public FileSystem getFileSystem(URI uri) { + checkUri(uri); + FileSystem result = delegate; + if (result == null) + throw new FileSystemNotFoundException(); + return result; + } + + @Override + public Path getPath(URI uri) { + checkScheme(uri); + if (delegate == null) + throw new FileSystemNotFoundException(); + uri = URI.create(delegate.provider().getScheme() + ":" + + uri.getSchemeSpecificPart()); + return new PassThroughPath(delegate, delegate.provider().getPath(uri)); + } + } + + static class PassThroughPath extends Path { + private final FileSystem fs; + private final Path delegate; + + PassThroughPath(FileSystem fs, Path delegate) { + this.fs = fs; + this.delegate = delegate; + } + + private Path wrap(Path path) { + return (path != null) ? new PassThroughPath(fs, path) : null; + } + + static Path unwrap(Path wrapper) { + if (!(wrapper instanceof PassThroughPath)) + throw new ProviderMismatchException(); + return ((PassThroughPath)wrapper).delegate; + } + + @Override + public FileSystem getFileSystem() { + return fs; + } + + @Override + public boolean isAbsolute() { + return delegate.isAbsolute(); + } + + @Override + public Path getRoot() { + return wrap(delegate.getRoot()); + } + + + @Override + public Path getName() { + return wrap(delegate.getName()); + } + + @Override + public Path getParent() { + return wrap(delegate.getParent()); + } + + @Override + public int getNameCount() { + return delegate.getNameCount(); + } + + @Override + public Path getName(int index) { + return wrap(delegate.getName(index)); + } + + @Override + public Path subpath(int beginIndex, int endIndex) { + return wrap(delegate.subpath(beginIndex, endIndex)); + } + + @Override + public boolean startsWith(Path other) { + return delegate.startsWith(unwrap(other)); + } + + @Override + public boolean endsWith(Path other) { + return delegate.endsWith(unwrap(other)); + } + + @Override + public Path normalize() { + return wrap(delegate.normalize()); + } + + @Override + public Path resolve(Path other) { + return wrap(delegate.resolve(unwrap(other))); + } + + @Override + public Path resolve(String other) { + return wrap(delegate.resolve(other)); + } + + @Override + public Path relativize(Path other) { + return wrap(delegate.relativize(unwrap(other))); + } + + @Override + public void setAttribute(String attribute, Object value, LinkOption... options) + throws IOException + { + delegate.setAttribute(attribute, value, options); + } + + @Override + public Object getAttribute(String attribute, LinkOption... options) + throws IOException + { + // assume that unwrapped objects aren't exposed + return delegate.getAttribute(attribute, options); + } + + @Override + public Map readAttributes(String attributes, LinkOption... options) + throws IOException + { + // assume that unwrapped objects aren't exposed + return delegate.readAttributes(attributes, options); + } + + @Override + public V getFileAttributeView(Class type, + LinkOption... options) + { + return delegate.getFileAttributeView(type, options); + } + + @Override + public void delete() throws IOException { + delegate.delete(); + } + + @Override + public void deleteIfExists() throws IOException { + delegate.deleteIfExists(); + } + + @Override + public Path createSymbolicLink(Path target, FileAttribute... attrs) + throws IOException + { + delegate.createSymbolicLink(unwrap(target), attrs); + return this; + } + + @Override + public Path createLink(Path existing) throws IOException { + delegate.createLink(unwrap(existing)); + return this; + } + + @Override + public Path readSymbolicLink() throws IOException { + return wrap(delegate.readSymbolicLink()); + } + + @Override + public URI toUri() { + String ssp = delegate.toUri().getSchemeSpecificPart(); + return URI.create(fs.provider().getScheme() + ":" + ssp); + } + + @Override + public Path toAbsolutePath() { + return wrap(delegate.toAbsolutePath()); + } + + @Override + public Path toRealPath(boolean resolveLinks) throws IOException { + return wrap(delegate.toRealPath(resolveLinks)); + } + + @Override + public Path copyTo(Path target, CopyOption... options) throws IOException { + return wrap(delegate.copyTo(unwrap(target), options)); + } + + @Override + public Path moveTo(Path target, CopyOption... options) throws IOException { + return wrap(delegate.copyTo(unwrap(target), options)); + } + + private DirectoryStream wrap(final DirectoryStream stream) { + return new DirectoryStream() { + @Override + public Iterator iterator() { + final Iterator itr = stream.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return wrap(itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + @Override + public void close() throws IOException { + stream.close(); + } + }; + } + + @Override + public DirectoryStream newDirectoryStream() throws IOException { + return wrap(delegate.newDirectoryStream()); + } + + @Override + public DirectoryStream newDirectoryStream(String glob) + throws IOException + { + return wrap(delegate.newDirectoryStream(glob)); + } + + @Override + public DirectoryStream newDirectoryStream(DirectoryStream.Filter filter) + throws IOException + { + return wrap(delegate.newDirectoryStream(filter)); + } + + @Override + public Path createFile(FileAttribute... attrs) throws IOException { + delegate.createFile(attrs); + return this; + } + + @Override + public Path createDirectory(FileAttribute... attrs) + throws IOException + { + delegate.createDirectory(attrs); + return this; + } + + @Override + public SeekableByteChannel newByteChannel(Set options, + FileAttribute... attrs) + throws IOException + { + return delegate.newByteChannel(options, attrs); + } + + @Override + public SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException + { + return delegate.newByteChannel(options); + } + + @Override + public InputStream newInputStream(OpenOption... options) throws IOException { + return delegate.newInputStream(); + } + + @Override + public OutputStream newOutputStream(OpenOption... options) + throws IOException + { + return delegate.newOutputStream(options); + } + + @Override + public boolean isHidden() throws IOException { + return delegate.isHidden(); + } + + @Override + public void checkAccess(AccessMode... modes) throws IOException { + delegate.checkAccess(modes); + } + + @Override + public boolean exists() { + return delegate.exists(); + } + + @Override + public boolean notExists() { + return delegate.notExists(); + } + + @Override + public FileStore getFileStore() throws IOException { + return delegate.getFileStore(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) + { + throw new UnsupportedOperationException(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind... events) + { + throw new UnsupportedOperationException(); + } + + + @Override + public Iterator iterator() { + final Iterator itr = delegate.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return wrap(itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + + @Override + public int compareTo(Path other) { + return delegate.compareTo(unwrap(other)); + } + + @Override + public boolean isSameFile(Path other) throws IOException { + return delegate.isSameFile(unwrap(other)); + } + + + @Override + public boolean equals(Object other) { + if (!(other instanceof PassThroughPath)) + return false; + return delegate.equals(unwrap((PassThroughPath)other)); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } +} diff --git a/jdk/test/java/nio/file/Path/delete_on_close.sh b/jdk/test/java/nio/file/Path/delete_on_close.sh index 198e99d7201..c7f3299e144 100644 --- a/jdk/test/java/nio/file/Path/delete_on_close.sh +++ b/jdk/test/java/nio/file/Path/delete_on_close.sh @@ -40,7 +40,7 @@ fi OS=`uname -s` case "$OS" in - Windows_* ) + Windows_* | CYGWIN* ) CLASSPATH="${TESTCLASSES};${TESTSRC}" ;; * ) diff --git a/jdk/test/java/nio/file/TestUtil.java b/jdk/test/java/nio/file/TestUtil.java index 2436a45992c..972dc250d87 100644 --- a/jdk/test/java/nio/file/TestUtil.java +++ b/jdk/test/java/nio/file/TestUtil.java @@ -30,17 +30,20 @@ public class TestUtil { private TestUtil() { } - public static Path createTemporaryDirectory() throws IOException { - Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + static Path createTemporaryDirectory(String where) throws IOException { + Path top = FileSystems.getDefault().getPath(where); Random r = new Random(); - Path dir; do { - dir = tmpdir.resolve("name" + r.nextInt()); + dir = top.resolve("name" + r.nextInt()); } while (dir.exists()); return dir.createDirectory(); } + static Path createTemporaryDirectory() throws IOException { + return createTemporaryDirectory(System.getProperty("java.io.tmpdir")); + } + static void removeAll(Path dir) { Files.walkFileTree(dir, new FileVisitor() { @Override diff --git a/jdk/test/java/nio/file/WatchService/OverflowEventIsLoner.java b/jdk/test/java/nio/file/WatchService/OverflowEventIsLoner.java new file mode 100644 index 00000000000..0b48a942d84 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/OverflowEventIsLoner.java @@ -0,0 +1,122 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6907760 + * @summary Check that the OVERFLOW event is not retrieved with other events + * @library .. + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class OverflowEventIsLoner { + + static void drainEvents(WatchService watcher, + WatchEvent.Kind expectedKind, + int count) + throws IOException, InterruptedException + { + // wait for key to be signalled - the timeout is long to allow for + // polling implementations + WatchKey key = watcher.poll(15, TimeUnit.SECONDS); + if (key != null && count == 0) + throw new RuntimeException("Key was signalled (unexpected)"); + if (key == null && count > 0) + throw new RuntimeException("Key not signalled (unexpected)"); + + int nread = 0; + boolean gotOverflow = false; + do { + List> events = key.pollEvents(); + for (WatchEvent event: events) { + WatchEvent.Kind kind = event.kind(); + if (kind == expectedKind) { + // expected event kind + if (++nread > count) + throw new RuntimeException("More events than expected!!"); + } else if (kind == OVERFLOW) { + // overflow event should not be retrieved with other events + if (events.size() > 1) + throw new RuntimeException("Overflow retrieved with other events"); + gotOverflow = true; + } else { + throw new RuntimeException("Unexpected event '" + kind + "'"); + } + } + if (!key.reset()) + throw new RuntimeException("Key is no longer valid"); + key = watcher.poll(2, TimeUnit.SECONDS); + } while (key != null); + + // check that all expected events were received or there was an overflow + if (nread < count && !gotOverflow) + throw new RuntimeException("Insufficient events"); + } + + + static void test(Path dir) throws IOException, InterruptedException { + WatchService watcher = dir.getFileSystem().newWatchService(); + try { + WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE); + + // create a lot of files + int n = 1024; + Path[] files = new Path[n]; + for (int i=0; i(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque(CAPACITY), pairs, iters); + oneRun(new SynchronousQueue(), pairs, iters / 8); + + /* TODO: unbounded queue implementations are prone to OOME + oneRun(new PriorityBlockingQueue(iters / 2 * pairs), pairs, iters / 4); oneRun(new LinkedTransferQueue(), pairs, iters); oneRun(new LTQasSQ(), pairs, iters); oneRun(new HalfSyncLTQ(), pairs, iters); - oneRun(new SynchronousQueue(), pairs, iters / 8); - - /* PriorityBlockingQueue is unbounded - oneRun(new PriorityBlockingQueue(iters / 2 * pairs), pairs, iters / 4); */ } diff --git a/jdk/test/java/util/jar/JarFile/TurkCert.java b/jdk/test/java/util/jar/JarFile/TurkCert.java index 8be8fd837ab..da044a9ace6 100644 --- a/jdk/test/java/util/jar/JarFile/TurkCert.java +++ b/jdk/test/java/util/jar/JarFile/TurkCert.java @@ -26,6 +26,7 @@ * @bug 4624534 * @summary Make sure jar certificates work for Turkish locale * @author kladko + * @run main/othervm TurkCert */ import java.util.*; diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh index af3e428cb30..f60cfd5d52a 100644 --- a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh @@ -92,7 +92,7 @@ case "$OS" in TMP="/tmp" ;; - Windows_95 | Windows_98 | Windows_NT | Windows_ME ) + Windows_95 | Windows_98 | Windows_NT | Windows_ME | CYGWIN* ) VAR="A different value for Win32" DEFAULT_JDK=/usr/local/java/jdk1.2/win32 FILESEP="\\" diff --git a/jdk/test/javax/print/DialogMargins.java b/jdk/test/javax/print/DialogMargins.java new file mode 100644 index 00000000000..5168bb140d1 --- /dev/null +++ b/jdk/test/javax/print/DialogMargins.java @@ -0,0 +1,244 @@ +/* + * Copyright 2001-2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 4485755 6361370 6448717 5080051 + * @summary dialog doesn't have way to specify margins + * for 6361370, verify exception for offline printer in Windows + * for 6448717, faster display of print dialog + * for 6500903, verify status of printer if accepting jobs or not + * @author prr + * @run main/manual DialogMargins + */ + +import java.awt.*; +import java.awt.event.*; +import java.awt.print.*; +import javax.print.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; + +public class DialogMargins extends Frame { + + public DialogMargins() { + super("Dialog Margins Test"); + + Button printButton = new Button ("Print ..."); + add("Center", printButton); + printButton.addActionListener(new ActionListener() { + public void actionPerformed (ActionEvent e) { + new MarginsPrinter(); + } + }); + + addWindowListener (new WindowAdapter() { + public void windowClosing (WindowEvent e) { + dispose(); + } + + }); + + pack(); + setVisible (true); + } + +class MarginsPrinter implements Printable { + + PrinterJob myPrinterJob; + PageFormat myPageFormat; + + public MarginsPrinter() { + PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); + //aset.add(MediaSizeName.ISO_A4); + //aset.add(new MediaPrintableArea(0f,0f,210f,297f,MediaPrintableArea.MM)); + myPrinterJob = PrinterJob.getPrinterJob(); + myPageFormat = myPrinterJob.pageDialog(aset); + myPrinterJob.setPrintable(this, myPageFormat); + //myPrinterJob.setPrintable(this); + if (myPrinterJob.printDialog(aset)) { + try { + //PrintRequestAttributeSet newaset = + //new HashPrintRequestAttributeSet(); + myPrinterJob.print(aset); + + } catch (PrinterException pe ) { + System.out.println("DialogMargins Exception caught:" + pe); + } + } + } + + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { + + if (pageIndex > 0) { + return Printable.NO_SUCH_PAGE; + } + + Graphics2D g2d = (Graphics2D)graphics; + g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + g2d.drawString("ORIGIN("+pageFormat.getImageableX()+","+ + pageFormat.getImageableY()+")", 20, 20); + g2d.drawString("X THIS WAY", 200, 50); + g2d.drawString("Y THIS WAY", 60 , 200); + g2d.drawString("Graphics is " + g2d.getClass().getName(), 100, 100); + g2d.drawRect(0,0,(int)pageFormat.getImageableWidth(), + (int)pageFormat.getImageableHeight()); + g2d.setColor(Color.black); + g2d.drawRect(1,1,(int)pageFormat.getImageableWidth()-2, + (int)pageFormat.getImageableHeight()-2); + + return Printable.PAGE_EXISTS; + } + +} + public static void main( String[] args) { + + String[] instructions = + { + "You must have a printer available to perform this test", + "Specify various pageformats and compare the printed results with the", + "request." + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + new DialogMargins(); + } +} + + +class Sysout { + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog { + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + show(); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + + }// TestDialog class diff --git a/jdk/test/javax/print/StreamPrintingOrientation.java b/jdk/test/javax/print/StreamPrintingOrientation.java new file mode 100644 index 00000000000..d0a4ec534a3 --- /dev/null +++ b/jdk/test/javax/print/StreamPrintingOrientation.java @@ -0,0 +1,120 @@ +/* + * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 4904236 + * @summary You would see a cross-platform print dialog being popped up. Check whether orientation is shown as LANDSCAPE. Click 'OK'. 'streamexample.ps' will be created in the same dir where this application was executed. Pass if the orientation in the ps file is landscape. + * @run main/manual StreamPrintingOrientation + */ + +import java.awt.*; +import java.awt.print.*; +import javax.print.*; +import javax.print.attribute.standard.*; +import javax.print.attribute.*; +import java.io.FileOutputStream; +import java.io.File; +import java.util.Locale; + +class StreamPrintingOrientation implements Printable { + /** + * Constructor + */ + public StreamPrintingOrientation() { + super(); + } + /** + * Starts the application. + */ + public static void main(java.lang.String[] args) { + StreamPrintingOrientation pd = new StreamPrintingOrientation(); + PrinterJob pj = PrinterJob.getPrinterJob(); + HashPrintRequestAttributeSet prSet = new HashPrintRequestAttributeSet(); + PrintService service = null; + + FileOutputStream fos = null; + File f = null, f1 = null; + String mType = "application/postscript"; + + try { + f = new File("streamexample.ps"); + fos = new FileOutputStream(f); + StreamPrintServiceFactory[] factories = PrinterJob.lookupStreamPrintServices(mType); + if (factories.length > 0) + service = factories[0].getPrintService(fos); + + if (service != null) { + System.out.println("Stream Print Service "+service); + pj.setPrintService(service); + } else { + throw new RuntimeException("No stream Print Service available."); + } + } catch (Exception e) { + e.printStackTrace(); + } + + pj.setPrintable(pd); + prSet.add(OrientationRequested.LANDSCAPE); + prSet.add(new Copies(3)); + prSet.add(new JobName("orientation test", null)); + System.out.println("open PrintDialog.."); + if (pj.printDialog(prSet)) { + try { + System.out.println("\nValues in attr set passed to print method"); + Attribute attr[] = prSet.toArray(); + for (int x = 0; x < attr.length; x ++) { + System.out.println("Name "+attr[x].getName()+" "+attr[x]); + } + System.out.println("About to print the data ..."); + if (service != null) { + System.out.println("TEST: calling Print"); + pj.print(prSet); + System.out.println("TEST: Printed"); + } + } + catch (PrinterException pe) { + pe.printStackTrace(); + } + } + + } + + //printable interface + public int print(Graphics g, PageFormat pf, int pi) throws PrinterException { + + if (pi > 0) { + return Printable.NO_SUCH_PAGE; + } + // Simply draw two rectangles + Graphics2D g2 = (Graphics2D)g; + g2.setColor(Color.black); + g2.translate(pf.getImageableX(), pf.getImageableY()); + System.out.println("StreamPrinting Test Width "+pf.getWidth()+" Height "+pf.getHeight()); + g2.drawRect(1,1,200,300); + g2.drawRect(1,1,25,25); + return Printable.PAGE_EXISTS; + } +} diff --git a/jdk/test/javax/print/attribute/AttributeTest.java b/jdk/test/javax/print/attribute/AttributeTest.java new file mode 100644 index 00000000000..c9ea142686f --- /dev/null +++ b/jdk/test/javax/print/attribute/AttributeTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2006-2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6387255 + * @summary Tests conflict of Media values returned by isAttrValueSupported and getSupportedAttrValues. No runtime exception should be thrown. + * @run main AttributeTest + */ +import javax.print.*; +import javax.print.attribute.standard.*; +import javax.print.attribute.*; + +public class AttributeTest { + + public AttributeTest() { + + PrintService service[] = PrintServiceLookup.lookupPrintServices(null, null); + + if (service.length == 0) { + throw new RuntimeException("No printer found. TEST ABORTED"); + } + + for (int x = 0; x < service.length; x ++) { + DocFlavor flavors[] = service[x].getSupportedDocFlavors(); + + for (int y = 0; y < flavors.length; y ++) { + Object attrVal = service[x].getSupportedAttributeValues(Media.class, flavors[y], null); + if (attrVal == null) { + continue; + } + Media attr[] = (Media[]) attrVal; + for (int z = 0; z < attr.length; z ++) { + if (!service[x].isAttributeValueSupported(attr[z], flavors[y], null)) { + throw new RuntimeException("ERROR: There is a conflict between getSupportedAttrValues " + + " and isAttributeValueSupported, for the attribute: " + attr[z] + + ", where the flavor is: " + flavors[y] + " and the print service is: " + + service[x] + "\n"); + } + } + } + } + + System.out.println("Test Passed"); + } + + public static void main (String args[]) { + AttributeTest test = new AttributeTest(); + } +} diff --git a/jdk/test/javax/print/attribute/ServiceDialogTest.java b/jdk/test/javax/print/attribute/ServiceDialogTest.java new file mode 100644 index 00000000000..a1d6006b8e3 --- /dev/null +++ b/jdk/test/javax/print/attribute/ServiceDialogTest.java @@ -0,0 +1,307 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 4910388 4871089 4998624 + * @summary Confirm that + * 1. After choosing Reverse Landscape in the system default print + * Print Service (2nd in the list), it + * will reset to portrait in "Test Printer" + * 2. Print To File button is not cleared when switching between the + * 2nd service (system default printer) and Test Printer. + * 3. Make sure "Postscript" printer is the default and make sure the + * "print to file" button is disabled. File Dialog should not be + * shown after pressing print button. + * + * @run main/manual ServiceDialogTest + */ +import java.awt.*; +import javax.print.*; +import javax.print.attribute.standard.*; +import javax.print.attribute.*; +import javax.print.event.*; +import java.io.*; +import java.util.Locale; + +public class ServiceDialogTest { + /** + * Constructor + */ + public ServiceDialogTest() { + super(); + } + /** + * Starts the application. + */ + public static void main(java.lang.String[] args) { + ServiceDialogTest pd = new ServiceDialogTest(); + PrintService services[] = new PrintService[3]; + services[1] = PrintServiceLookup.lookupDefaultPrintService(); + + FileOutputStream fos = null; + File f = null; + String mType = "application/postscript"; + DocFlavor flavor = DocFlavor.INPUT_STREAM.JPEG; + try { + f = new File("streamexample.ps"); + fos = new FileOutputStream(f); + StreamPrintServiceFactory[] factories = StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor, mType); + if (factories.length > 0) { + services[0] = factories[0].getPrintService(fos); + } else { + throw new RuntimeException("No StreamPrintService available which would support "+flavor"); + } + + services[2] = new TestPrintService("Test Printer"); + + //System.out.println("is "+flavor+" supported? "+services[0].isDocFlavorSupported(flavor)); + //System.out.println("is Orientation supported? "+services[0].isAttributeCategorySupported(OrientationRequested.class)); + //System.out.println("is REVERSE PORTRAIT supported ? "+services[0].isAttributeValueSupported(OrientationRequested.REVERSE_PORTRAIT, flavor, null)); + + HashPrintRequestAttributeSet prSet = new HashPrintRequestAttributeSet(); + prSet.add(new Destination(new File("./dest.prn").toURI())); + PrintService selService = ServiceUI.printDialog(null, 200, 200, services, services[0], flavor, prSet); + Attribute attr[] = prSet.toArray(); + for (int x = 0; x < attr.length; x ++) { + System.out.println(attr[x]); + } + + //DocPrintJob pj = service.createPrintJob(); + //PrintDocument prDoc = new PrintDocument(); + //pj.print(prDoc, null); + + } catch (Exception e) { + e.printStackTrace(); + } + } +} + + +class TestPrintService implements PrintService +{ + + private static DocFlavor textByteFlavor = null; + private static final DocFlavor supportedDocFlavors[] = (new DocFlavor[] { + javax.print.DocFlavor.INPUT_STREAM.JPEG + }); + + private static final Class serviceAttrCats[] = (new Class[] { + javax.print.attribute.standard.PrinterName.class + }); + + private static final Class otherAttrCats[] = (new Class [] { + javax.print.attribute.standard.Copies.class, + javax.print.attribute.standard.OrientationRequested.class, + javax.print.attribute.standard.Destination.class, + }); + + private String printer = null; + + public TestPrintService() { + } + + public TestPrintService(String printerName) { + if (printerName == null) { + throw new IllegalArgumentException("null printer name"); + } else { + printer = printerName; + } + } + + public String getName() + { + return printer; + } + + + public DocPrintJob createPrintJob() + { + return null; + } + + public PrintServiceAttributeSet getUpdatedAttributes() + { + return null; + } + + + public void addPrintServiceAttributeListener(PrintServiceAttributeListener printserviceattributelistener) + { + } + + public void removePrintServiceAttributeListener(PrintServiceAttributeListener printserviceattributelistener) + { + } + + public PrintServiceAttribute getAttribute(Class category) + { + return null; + } + + public PrintServiceAttributeSet getAttributes() + { + HashPrintServiceAttributeSet aSet = new HashPrintServiceAttributeSet(); + return aSet; + } + + public DocFlavor[] getSupportedDocFlavors() + { + int i = supportedDocFlavors.length; + DocFlavor adocflavor[] = new DocFlavor[i]; + System.arraycopy(supportedDocFlavors, 0, adocflavor, 0, i); + return adocflavor; + } + + public boolean isDocFlavorSupported(DocFlavor docflavor) + { + for (int i = 0; i < supportedDocFlavors.length; i++) { + if (docflavor.equals(supportedDocFlavors[i])) { + return true; + } + } + return false; + } + + public Class[] getSupportedAttributeCategories() + { + int i = otherAttrCats.length; + Class aclass[] = new Class[i]; + System.arraycopy(otherAttrCats, 0, aclass, 0, otherAttrCats.length); + return aclass; + } + + public boolean isAttributeCategorySupported(Class category) + { + if (category == null) { + throw new NullPointerException("null category"); + } + + for (int i = 0; i < otherAttrCats.length; i++) { + if (category == otherAttrCats[i]) { + return true; + } + } + return false; + } + + public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, AttributeSet attributes) { + + if (attrval == OrientationRequested.PORTRAIT) + return true; + else if (attrval == OrientationRequested.LANDSCAPE) + return true; + else + return false; + } + + public Object getDefaultAttributeValue(Class category) + { + if (category == null) { + throw new NullPointerException("null category"); + } + if (category == javax.print.attribute.standard.Copies.class) + return new Copies(1); + + if (category == javax.print.attribute.standard.OrientationRequested.class) + return OrientationRequested.PORTRAIT; + + return null; + } + + public Object getSupportedAttributeValues(Class category, DocFlavor docflavor, AttributeSet attributeset) + { + if (category == null) { + throw new NullPointerException("null category"); + } + + if (docflavor != null) { + if (!isDocFlavorSupported(docflavor)) { + throw new IllegalArgumentException(docflavor + " is an unsupported flavor"); + } + } + if (!isAttributeCategorySupported(category)) { + return null; + } + if (category == javax.print.attribute.standard.Copies.class ) { + return new CopiesSupported(1, 5); + } + if (category == javax.print.attribute.standard.OrientationRequested.class ) { + OrientationRequested req[] = { OrientationRequested.PORTRAIT, OrientationRequested.LANDSCAPE }; + return req; + } + + return null; + } + + public AttributeSet getUnsupportedAttributes(DocFlavor docflavor, AttributeSet attributeset) { + + if (docflavor != null && !isDocFlavorSupported(docflavor)) { + throw new IllegalArgumentException("flavor " + docflavor + "is not supported"); + } + if (attributeset == null) { + return null; + } + + HashAttributeSet hashattributeset = new HashAttributeSet(); + Attribute attributearray[] = attributeset.toArray(); + for (int i = 0; i < attributearray.length; i++) { + try { + Attribute attribute = attributearray[i]; + if (!isAttributeCategorySupported(attribute.getCategory())) { + hashattributeset.add(attribute); + } else { + if (!isAttributeValueSupported(attribute, docflavor, attributeset)) { + hashattributeset.add(attribute); + } + } + } + catch (ClassCastException classcastexception) { + + } + } + + if (hashattributeset.isEmpty()) { + return null; + } + return hashattributeset; + } + + public ServiceUIFactory getServiceUIFactory() { + return null; + } + + public String toString() { + return "Printer : " + getName(); + } + + public boolean equals(Object obj) { + return obj == this || (obj instanceof TestPrintService) && ((TestPrintService)obj).getName().equals(getName()); + } + + public int hashCode() { + return getClass().hashCode() + getName().hashCode(); + } + +} diff --git a/jdk/test/javax/print/attribute/SidesPageRangesTest.java b/jdk/test/javax/print/attribute/SidesPageRangesTest.java index cf487616137..73c23a7ed42 100644 --- a/jdk/test/javax/print/attribute/SidesPageRangesTest.java +++ b/jdk/test/javax/print/attribute/SidesPageRangesTest.java @@ -64,7 +64,7 @@ public class SidesPageRangesTest { System.out.println("\nPageRanges Attribute category is supported"); } else { System.out.println("\nPageRanges Attribute category is not supported. terminating..."); - System.exit(1); + return; } flavors = defService.getSupportedDocFlavors(); diff --git a/jdk/test/javax/script/CommonSetup.sh b/jdk/test/javax/script/CommonSetup.sh index e76da82125b..4a66829131f 100644 --- a/jdk/test/javax/script/CommonSetup.sh +++ b/jdk/test/javax/script/CommonSetup.sh @@ -49,6 +49,12 @@ case "$OS" in OS="Windows" FS="\\" ;; + CYGWIN* ) + PS=";" + OS="Windows" + FS="\\" + isCygwin=true + ;; * ) echo "Unrecognized system!" exit 1; diff --git a/jdk/test/javax/script/ProviderTest.sh b/jdk/test/javax/script/ProviderTest.sh index 211d9edc1d9..a32383e4078 100644 --- a/jdk/test/javax/script/ProviderTest.sh +++ b/jdk/test/javax/script/ProviderTest.sh @@ -46,5 +46,5 @@ $JAR -cf ${TESTCLASSES}/dummy.jar \ echo "Running test ..." $JAVA -classpath \ - ${TESTCLASSES}${PS}${TESTCLASSES}/dummy.jar \ + "${TESTCLASSES}${PS}${TESTCLASSES}/dummy.jar" \ ProviderTest diff --git a/jdk/test/javax/xml/crypto/dsig/GenerationTests.java b/jdk/test/javax/xml/crypto/dsig/GenerationTests.java index 13881966d32..1ed649cd83a 100644 --- a/jdk/test/javax/xml/crypto/dsig/GenerationTests.java +++ b/jdk/test/javax/xml/crypto/dsig/GenerationTests.java @@ -23,7 +23,7 @@ /** * @test - * @bug 4635230 6283345 6303830 6824440 + * @bug 4635230 6283345 6303830 6824440 6867348 * @summary Basic unit tests for generating XML Signatures with JSR 105 * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java GenerationTests.java @@ -126,13 +126,14 @@ public class GenerationTests { test_create_signature_x509_is(); test_create_signature_x509_ski(); test_create_signature_x509_sn(); -// test_create_signature(); + test_create_signature(); test_create_exc_signature(); test_create_sign_spec(); test_create_signature_enveloping_sha256_dsa(); test_create_signature_enveloping_sha384_rsa_sha256(); test_create_signature_enveloping_sha512_rsa_sha384(); test_create_signature_enveloping_sha512_rsa_sha512(); + test_create_signature_reference_dependency(); } private static void setup() throws Exception { @@ -410,6 +411,55 @@ public class GenerationTests { System.out.println(); } + static void test_create_signature_reference_dependency() throws Exception { + System.out.println("* Generating signature-reference-dependency.xml"); + // create references + List refs = Collections.singletonList + (fac.newReference("#object-1", sha1)); + + // create SignedInfo + SignedInfo si = fac.newSignedInfo(withoutComments, rsaSha1, refs); + + // create objects + List objs = new ArrayList(); + + // Object 1 + List manRefs = Collections.singletonList + (fac.newReference("#object-2", sha1)); + objs.add(fac.newXMLObject(Collections.singletonList + (fac.newManifest(manRefs, "manifest-1")), "object-1", null, null)); + + // Object 2 + Document doc = db.newDocument(); + Element nc = doc.createElementNS(null, "NonCommentandus"); + nc.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", ""); + nc.appendChild(doc.createComment(" Commentandum ")); + objs.add(fac.newXMLObject(Collections.singletonList + (new DOMStructure(nc)), "object-2", null, null)); + + // create XMLSignature + XMLSignature sig = fac.newXMLSignature(si, rsa, objs, "signature", null); + DOMSignContext dsc = new DOMSignContext(getPrivateKey("RSA"), doc); + + sig.sign(dsc); + +// dumpDocument(doc, new PrintWriter(System.out)); + + DOMValidateContext dvc = new DOMValidateContext + (kvks, doc.getDocumentElement()); + XMLSignature sig2 = fac.unmarshalXMLSignature(dvc); + + if (sig.equals(sig2) == false) { + throw new Exception + ("Unmarshalled signature is not equal to generated signature"); + } + if (sig2.validate(dvc) == false) { + throw new Exception("Validation of generated signature failed"); + } + + System.out.println(); + } + static void test_create_signature() throws Exception { System.out.println("* Generating signature.xml"); @@ -645,6 +695,7 @@ public class GenerationTests { envDoc.getElementsByTagName("YoursSincerely").item(0); DOMSignContext dsc = new DOMSignContext(signingKey, ys); + dsc.setURIDereferencer(httpUd); sig.sign(dsc); @@ -660,6 +711,7 @@ public class GenerationTests { DOMValidateContext dvc = new DOMValidateContext (new X509KeySelector(ks), sigElement); + dvc.setURIDereferencer(httpUd); File f = new File( System.getProperty("dir.test.vector.baltimore") + System.getProperty("file.separator") + diff --git a/jdk/test/sun/jvmstat/testlibrary/utils.sh b/jdk/test/sun/jvmstat/testlibrary/utils.sh index d3b04956373..8bd4215d088 100644 --- a/jdk/test/sun/jvmstat/testlibrary/utils.sh +++ b/jdk/test/sun/jvmstat/testlibrary/utils.sh @@ -40,7 +40,7 @@ setup() { OS=`uname -s` case ${OS} in - Windows_*) + Windows_* | CYGWIN*) PS=";" FS="\\" ;; @@ -54,7 +54,7 @@ setup() { verify_os() { OS=`uname -s` case ${OS} in - Windows_95 | Windows_98 | Windows_ME) + Windows_95 | Windows_98 | Windows_ME | CYGWIN* ) echo "Test bypassed: jvmstat feature not supported on ${OS}" exit 0 ;; diff --git a/jdk/test/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh b/jdk/test/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh index b06a4073b61..283c6cde2ab 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/GeneratePropertyPassword.sh @@ -45,7 +45,7 @@ cat < ${TMP_FILE} s^@TEST-SRC@/^${TESTCLASSES}${DFILESEP}^g EOF ;; -Windows_95 | Windows_98 | Windows_NT | Windows_ME) +Windows_95 | Windows_98 | Windows_NT | Windows_ME | CYGWIN*) PATHSEP=";" FILESEP="\\" DFILESEP=$FILESEP$FILESEP diff --git a/jdk/test/sun/misc/URLClassPath/ClassnameCharTest.sh b/jdk/test/sun/misc/URLClassPath/ClassnameCharTest.sh index 9cc5c58b555..3e1db07e017 100644 --- a/jdk/test/sun/misc/URLClassPath/ClassnameCharTest.sh +++ b/jdk/test/sun/misc/URLClassPath/ClassnameCharTest.sh @@ -44,7 +44,7 @@ case "$OS" in PS=":" FS="/" ;; - Windows* ) + Windows* | CYGWIN* ) PS=";" FS="\\" ;; @@ -59,6 +59,6 @@ cd ${TESTCLASSES} ${TESTJAVA}${FS}bin${FS}jar xvf testclasses.jar "fo o.class" ${TESTJAVA}${FS}bin${FS}javac -d ${TESTCLASSES} ${TESTSRC}${FS}ClassnameCharTest.java -${TESTJAVA}${FS}bin${FS}java -classpath ${TESTCLASSES}${PS}${TESTCLASSES}${FS}sun${FS}misc${FS}URLClassPath ClassnameCharTest +${TESTJAVA}${FS}bin${FS}java -classpath "${TESTCLASSES}${PS}${TESTCLASSES}${FS}sun${FS}misc${FS}URLClassPath" ClassnameCharTest rm -rf "fo o.class" testclasses.jar diff --git a/jdk/test/sun/security/krb5/auto/BadKdc.java b/jdk/test/sun/security/krb5/auto/BadKdc.java new file mode 100644 index 00000000000..e4c5267271e --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/BadKdc.java @@ -0,0 +1,113 @@ +/* + * 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.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.security.krb5.Config; + +public class BadKdc { + + // Matches the krb5 debug output: + // >>> KDCCommunication: kdc=kdc.rabbit.hole UDP:14319, timeout=2000,... + // ^ kdc# ^ timeout + static final Pattern re = Pattern.compile( + ">>> KDCCommunication: kdc=kdc.rabbit.hole UDP:(\\d)...., " + + "timeout=(\\d)000,"); + public static void go(int[]... expected) + throws Exception { + System.setProperty("sun.security.krb5.debug", "true"); + + // Make sure KDCs' ports starts with 1 and 2 and 3, + // useful for checking debug output. + int p1 = 10000 + new java.util.Random().nextInt(10000); + int p2 = 20000 + new java.util.Random().nextInt(10000); + int p3 = 30000 + new java.util.Random().nextInt(10000); + + FileWriter fw = new FileWriter("alternative-krb5.conf"); + + fw.write("[libdefaults]\n" + + "default_realm = " + OneKDC.REALM + "\n" + + "kdc_timeout = 2000\n"); + fw.write("[realms]\n" + OneKDC.REALM + " = {\n" + + "kdc = " + OneKDC.KDCHOST + ":" + p1 + "\n" + + "kdc = " + OneKDC.KDCHOST + ":" + p2 + "\n" + + "kdc = " + OneKDC.KDCHOST + ":" + p3 + "\n" + + "}\n"); + + fw.close(); + System.setProperty("java.security.krb5.conf", "alternative-krb5.conf"); + Config.refresh(); + + // Turn on k3 only + KDC k3 = on(p3); + + test(expected[0]); + test(expected[1]); + Config.refresh(); + test(expected[2]); + + k3.terminate(); // shutdown k3 + on(p2); // k2 is on + test(expected[3]); + on(p1); // k1 and k2 is on + test(expected[4]); + } + + private static KDC on(int p) throws Exception { + KDC k = new KDC(OneKDC.REALM, OneKDC.KDCHOST, p, true); + k.addPrincipal(OneKDC.USER, OneKDC.PASS); + k.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); + return k; + } + + /** + * One round of test for max_retries and timeout. + * @param timeout the expected timeout + * @param expected the expected kdc# timeout kdc# timeout... + */ + private static void test(int... expected) throws Exception { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + System.setOut(oldout); + + String[] lines = new String(bo.toByteArray()).split("\n"); + System.out.println("----------------- TEST -----------------"); + int count = 0; + for (String line: lines) { + Matcher m = re.matcher(line); + if (m.find()) { + System.out.println(line); + if (Integer.parseInt(m.group(1)) != expected[count++] || + Integer.parseInt(m.group(2)) != expected[count++]) { + throw new Exception("Fail here"); + } + } + } + if (count != expected.length) { + throw new Exception("Less rounds"); + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/BadKdc1.java b/jdk/test/sun/security/krb5/auto/BadKdc1.java new file mode 100644 index 00000000000..584edc3889a --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/BadKdc1.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 6843127 + * @run main/timeout=300 BadKdc1 + * @summary krb5 should not try to access unavailable kdc too often + */ + +import java.io.*; +import java.security.Security; + +public class BadKdc1 { + + public static void main(String[] args) + throws Exception { + Security.setProperty("krb5.kdc.bad.policy", "tryLess"); + BadKdc.go( + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,2,2,2,3,2}, // 1, 2 + // The above line means try kdc1 for 2 seconds, then kdc1 + // for 2 seconds,..., finally kdc3 for 2 seconds. + new int[]{1,2,2,2,3,2,1,2,2,2,3,2}, // 1, 2 + // refresh + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,2,2,2,3,2}, // 1, 2 + // k3 off, k2 on + new int[]{1,2,2,2,1,2,2,2}, // 1 + // k1 on + new int[]{1,2,1,2} // empty + ); + } +} + diff --git a/jdk/test/sun/security/krb5/auto/BadKdc2.java b/jdk/test/sun/security/krb5/auto/BadKdc2.java new file mode 100644 index 00000000000..f9c017e8dad --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/BadKdc2.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 6843127 + * @run main/timeout=300 BadKdc2 + * @summary krb5 should not try to access unavailable kdc too often + */ + +import java.io.*; +import java.security.Security; + +public class BadKdc2 { + + public static void main(String[] args) + throws Exception { + Security.setProperty("krb5.kdc.bad.policy", "tryLess:2,1000"); + BadKdc.go( + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,1,1,1,2,1,2,1,3,2}, // 1, 2 + new int[]{1,1,1,1,2,1,2,1,3,2,1,1,1,1,2,1,2,1,3,2}, // 1, 2 + // refresh + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,1,1,1,2,1,2,1,3,2}, // 1, 2 + // k3 off, k2 on + new int[]{1,1,1,1,2,1,1,1,1,1,2,2}, // 1 + // k1 on + new int[]{1,1,1,2} // empty + ); + } +} diff --git a/jdk/test/sun/security/krb5/auto/BadKdc3.java b/jdk/test/sun/security/krb5/auto/BadKdc3.java new file mode 100644 index 00000000000..547e91578aa --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/BadKdc3.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 6843127 + * @run main/timeout=300 BadKdc3 + * @summary krb5 should not try to access unavailable kdc too often + */ + +import java.io.*; +import java.security.Security; + +public class BadKdc3 { + + public static void main(String[] args) + throws Exception { + Security.setProperty("krb5.kdc.bad.policy", "tryLast"); + BadKdc.go( + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,3,2}, // 1, 2 + new int[]{3,2,3,2}, // 1, 2 + // refresh + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,3,2}, // 1, 2 + // k3 off, k2 on + new int[]{3,2,3,2,3,2,1,2,1,2,1,2,2,2,2,2}, // 1, 3 + // k1 on + new int[]{2,2,2,2} // 1, 3 + ); + } +} diff --git a/jdk/test/sun/security/krb5/auto/BadKdc4.java b/jdk/test/sun/security/krb5/auto/BadKdc4.java new file mode 100644 index 00000000000..6774b76c3ae --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/BadKdc4.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 6843127 + * @run main/timeout=300 BadKdc4 + * @summary krb5 should not try to access unavailable kdc too often + */ + +import java.io.*; +import java.security.Security; + +public class BadKdc4 { + + public static void main(String[] args) + throws Exception { + Security.setProperty("krb5.kdc.bad.policy", ""); + BadKdc.go( + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,2,1,2,1,2,2,2,2,2,2,2,3,2}, + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,2,1,2,1,2,2,2,2,2,2,2,3,2}, + // refresh + new int[]{1,2,1,2,1,2,2,2,2,2,2,2,3,2,1,2,1,2,1,2,2,2,2,2,2,2,3,2}, + // k3 off, k2 on + new int[]{1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2}, + // k1 on + new int[]{1,2,1,2} + ); + } +} diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java index 169094c779b..b03058798bd 100644 --- a/jdk/test/sun/security/krb5/auto/KDC.java +++ b/jdk/test/sun/security/krb5/auto/KDC.java @@ -141,6 +141,10 @@ public class KDC { // Options private Map options = new HashMap(); + private Thread thread1, thread2, thread3; + DatagramSocket u1 = null; + ServerSocket t1 = null; + /** * Option names, to be expanded forever. */ @@ -480,8 +484,9 @@ public class KDC { Method stringToKey = EncryptionKey.class.getDeclaredMethod("stringToKey", char[].class, String.class, byte[].class, Integer.TYPE); stringToKey.setAccessible(true); Integer kvno = null; - // For service whose password ending with a number, use it as kvno - if (p.toString().indexOf('/') >= 0) { + // For service whose password ending with a number, use it as kvno. + // Kvno must be postive. + if (p.toString().indexOf('/') > 0) { char[] pass = getPassword(p, server); if (Character.isDigit(pass[pass.length-1])) { kvno = pass[pass.length-1] - '0'; @@ -940,8 +945,6 @@ public class KDC { * @throws java.io.IOException for any communication error */ protected void startServer(int port, boolean asDaemon) throws IOException { - DatagramSocket u1 = null; - ServerSocket t1 = null; if (port > 0) { u1 = new DatagramSocket(port, InetAddress.getByName("127.0.0.1")); t1 = new ServerSocket(port); @@ -966,7 +969,7 @@ public class KDC { this.port = port; // The UDP consumer - Thread thread = new Thread() { + thread1 = new Thread() { public void run() { while (true) { try { @@ -982,11 +985,11 @@ public class KDC { } } }; - thread.setDaemon(asDaemon); - thread.start(); + thread1.setDaemon(asDaemon); + thread1.start(); // The TCP consumer - thread = new Thread() { + thread2 = new Thread() { public void run() { while (true) { try { @@ -1004,11 +1007,11 @@ public class KDC { } } }; - thread.setDaemon(asDaemon); - thread.start(); + thread2.setDaemon(asDaemon); + thread2.start(); // The dispatcher - thread = new Thread() { + thread3 = new Thread() { public void run() { while (true) { try { @@ -1018,10 +1021,21 @@ public class KDC { } } }; - thread.setDaemon(true); - thread.start(); + thread3.setDaemon(true); + thread3.start(); } + public void terminate() { + try { + thread1.stop(); + thread2.stop(); + thread3.stop(); + u1.close(); + t1.close(); + } catch (Exception e) { + // OK + } + } /** * Helper class to encapsulate a job in a KDC. */ diff --git a/jdk/test/sun/security/krb5/auto/MoreKvno.java b/jdk/test/sun/security/krb5/auto/MoreKvno.java index 66740a8b799..5a2c9e56a58 100644 --- a/jdk/test/sun/security/krb5/auto/MoreKvno.java +++ b/jdk/test/sun/security/krb5/auto/MoreKvno.java @@ -24,15 +24,20 @@ /* * @test * @bug 6893158 + * @bug 6907425 * @summary AP_REQ check should use key version number */ +import org.ietf.jgss.GSSException; import sun.security.jgss.GSSUtil; +import sun.security.krb5.KrbException; import sun.security.krb5.PrincipalName; import sun.security.krb5.internal.ktab.KeyTab; +import sun.security.krb5.internal.Krb5; public class MoreKvno { + static PrincipalName p; public static void main(String[] args) throws Exception { @@ -41,21 +46,40 @@ public class MoreKvno { // Rewrite keytab, 3 set of keys with different kvno KeyTab ktab = KeyTab.create(OneKDC.KTAB); - PrincipalName p = new PrincipalName(OneKDC.SERVER+"@"+OneKDC.REALM, PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(p, "pass0".toCharArray(), 0); - ktab.addEntry(p, "pass2".toCharArray(), 2); + p = new PrincipalName( + OneKDC.SERVER+"@"+OneKDC.REALM, PrincipalName.KRB_NT_SRV_HST); ktab.addEntry(p, "pass1".toCharArray(), 1); + ktab.addEntry(p, "pass3".toCharArray(), 3); + ktab.addEntry(p, "pass2".toCharArray(), 2); ktab.save(); - kdc.addPrincipal(OneKDC.SERVER, "pass1".toCharArray()); - go(OneKDC.SERVER, "com.sun.security.jgss.krb5.accept"); - kdc.addPrincipal(OneKDC.SERVER, "pass2".toCharArray()); + char[] pass = "pass2".toCharArray(); + kdc.addPrincipal(OneKDC.SERVER, pass); + go(OneKDC.SERVER, "com.sun.security.jgss.krb5.accept", pass); + + pass = "pass3".toCharArray(); + kdc.addPrincipal(OneKDC.SERVER, pass); // "server" initiate also, check pass2 is used at authentication - go(OneKDC.SERVER, "server"); + go(OneKDC.SERVER, "server", pass); + + try { + pass = "pass4".toCharArray(); + kdc.addPrincipal(OneKDC.SERVER, pass); + go(OneKDC.SERVER, "com.sun.security.jgss.krb5.accept", pass); + throw new Exception("This test should fail"); + } catch (GSSException gsse) { + KrbException ke = (KrbException)gsse.getCause(); + if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) { + throw new Exception("Not expected failure code: " + + ke.returnCode()); + } + } } - static void go(String server, String entry) throws Exception { + static void go(String server, String entry, char[] pass) throws Exception { Context c, s; + + // Part 1: Test keytab c = Context.fromUserPass("dummy", "bogus".toCharArray(), false); s = Context.fromJAAS(entry); @@ -66,5 +90,17 @@ public class MoreKvno { s.dispose(); c.dispose(); + + // Part 2: Test username/password pair + c = Context.fromUserPass("dummy", "bogus".toCharArray(), false); + s = Context.fromUserPass(p.getNameString(), pass, true); + + c.startAsClient(server, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + + Context.handshake(c, s); + + s.dispose(); + c.dispose(); } } diff --git a/jdk/test/sun/security/krb5/auto/OneKDC.java b/jdk/test/sun/security/krb5/auto/OneKDC.java index 213869e8d24..d52ada56313 100644 --- a/jdk/test/sun/security/krb5/auto/OneKDC.java +++ b/jdk/test/sun/security/krb5/auto/OneKDC.java @@ -24,8 +24,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.security.Security; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; diff --git a/jdk/test/sun/security/krb5/auto/SSL.java b/jdk/test/sun/security/krb5/auto/SSL.java index d8e361a00e0..72e37361d6f 100644 --- a/jdk/test/sun/security/krb5/auto/SSL.java +++ b/jdk/test/sun/security/krb5/auto/SSL.java @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved. * 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 6894643 + * @bug 6894643 6913636 * @summary Test JSSE Kerberos ciphersuite */ import java.io.*; @@ -32,12 +32,13 @@ import javax.net.ssl.*; import java.security.Principal; import java.util.Date; import sun.security.jgss.GSSUtil; +import sun.security.krb5.PrincipalName; +import sun.security.krb5.internal.ktab.KeyTab; public class SSL { private static final String KRB5_CIPHER = "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"; private static final int LOOP_LIMIT = 1; - private static final char[] PASS = "secret".toCharArray(); private static int loopCount = 0; private static volatile String server; private static volatile int port; @@ -54,12 +55,39 @@ public class SSL { kdc.addPrincipal(OneKDC.USER, OneKDC.PASS); kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); - kdc.addPrincipal("host/" + server, PASS); KDC.saveConfig(OneKDC.KRB5_CONF, kdc); System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); + // Add 3 versions of keys into keytab + KeyTab ktab = KeyTab.create(OneKDC.KTAB); + PrincipalName service = new PrincipalName( + "host/" + server, PrincipalName.KRB_NT_SRV_HST); + ktab.addEntry(service, "pass1".toCharArray(), 1); + ktab.addEntry(service, "pass2".toCharArray(), 2); + ktab.addEntry(service, "pass3".toCharArray(), 3); + ktab.save(); + + // and use the middle one as the real key + kdc.addPrincipal("host/" + server, "pass2".toCharArray()); + + // JAAS config entry name ssl + System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF); + File f = new File(OneKDC.JAAS_CONF); + FileOutputStream fos = new FileOutputStream(f); + fos.write(( + "ssl {\n" + + " com.sun.security.auth.module.Krb5LoginModule required\n" + + " principal=\"host/" + server + "\"\n" + + " useKeyTab=true\n" + + " keyTab=" + OneKDC.KTAB + "\n" + + " isInitiator=false\n" + + " storeKey=true;\n};\n" + ).getBytes()); + fos.close(); + f.deleteOnExit(); + final Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - final Context s = Context.fromUserPass("host/" + server, PASS, true); + final Context s = Context.fromJAAS("ssl"); c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); diff --git a/jdk/test/sun/security/krb5/auto/Test5653.java b/jdk/test/sun/security/krb5/auto/Test5653.java new file mode 100644 index 00000000000..cc61e8c7d72 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/Test5653.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6895424 + * @summary RFC 5653 + */ + +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSManager; +import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; +import sun.security.jgss.GSSUtil; + +public class Test5653 { + + public static void main(String[] args) + throws Exception { + + Oid oldOid = new Oid("1.3.6.1.5.6.2"); + new OneKDC(null).writeJAASConf(); + + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + GSSManager m = GSSManager.getInstance(); + boolean found = false; + + // Test 1: the getMechsForName() method accepts it. + for (Oid tmp: m.getMechsForName(oldOid)) { + if (tmp.equals(GSSUtil.GSS_KRB5_MECH_OID)) { + found = true; + break; + } + } + if (!found) { + throw new Exception("Cannot found krb5 mech for old name type"); + } + + // Test 2: the createName() method accepts it. + GSSName name = m.createName("server@host.rabbit.hole", oldOid); + + // Test 3: its getStringNameType() output is correct + if (!name.getStringNameType().equals(GSSName.NT_HOSTBASED_SERVICE)) { + throw new Exception("GSSName not correct name type"); + } + + // Test 4: everything still works. + GSSContext c1 = m.createContext( + name, + GSSUtil.GSS_KRB5_MECH_OID, + null, + GSSContext.DEFAULT_LIFETIME); + byte[] token = c1.initSecContext(new byte[0], 0, 0); + + Context s; + s = Context.fromJAAS("server"); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.x().acceptSecContext(token, 0, token.length); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.inline.hpp b/jdk/test/sun/security/krb5/ktab/KeyString.java similarity index 63% rename from hotspot/src/share/vm/gc_implementation/g1/ptrQueue.inline.hpp rename to jdk/test/sun/security/krb5/ktab/KeyString.java index c3ff2260ffd..8a9c8898b4f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.inline.hpp +++ b/jdk/test/sun/security/krb5/ktab/KeyString.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,23 +19,21 @@ * Please contact Sun 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 6917791 + * @summary KeyTabEntry, when the byte value smaller then 16, the string drop '0' */ -void PtrQueue::handle_zero_index() { - assert(0 == _index, "Precondition."); - // This thread records the full buffer and allocates a new one (while - // holding the lock if there is one). - void** buf = _buf; - _buf = qset()->allocate_buffer(); - _sz = qset()->buffer_size(); - _index = _sz; - assert(0 <= _index && _index <= _sz, "Invariant."); - if (buf != NULL) { - if (_lock) { - locking_enqueue_completed_buffer(buf); - } else { - qset()->enqueue_complete_buffer(buf); +import sun.security.krb5.internal.ktab.KeyTabEntry; + +public class KeyString { + public static void main(String[] args) throws Exception { + KeyTabEntry e = new KeyTabEntry(null, null, null, 1, 1, new byte[8]); + // "0x" plus eight "00" + if (e.getKeyString().length() != 18) { + throw new Exception("key bytes length not correct"); + } } - } } diff --git a/jdk/test/sun/security/util/Oid/S11N.sh b/jdk/test/sun/security/util/Oid/S11N.sh index 081cd52298f..82046f360c0 100644 --- a/jdk/test/sun/security/util/Oid/S11N.sh +++ b/jdk/test/sun/security/util/Oid/S11N.sh @@ -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 @@ -21,8 +21,8 @@ # have any questions. # # @test -# @bug 4811968 -# @summary Serialization compatibility with old versions +# @bug 4811968 6908628 +# @summary Serialization compatibility with old versions (and fix) # @author Weijun Wang # # set a few environment variables so that the shell-script can run stand-alone @@ -99,7 +99,8 @@ esac # the test code -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}SerialTest.java || exit 10 +${TESTJAVA}${FS}bin${FS}javac -target 1.4 -source 1.4 \ + -d . ${TESTSRC}${FS}SerialTest.java || exit 10 OLDJAVA=" /java/re/j2se/1.6.0/latest/binaries/${PF} @@ -161,4 +162,10 @@ rm -f tmp.oid.serial rm -f tmp.oid.serial.old rm -f SerialTest.class +for oldj in ${OLDJAVA}; do + if [ ! -d ${oldj} ]; then + echo WARNING: ${oldj} is missing. Test incomplete! > /dev/stderr + fi +done + exit 0 diff --git a/jdk/test/sun/text/resources/LocaleData b/jdk/test/sun/text/resources/LocaleData index 7b0ada3c594..e662c356117 100644 --- a/jdk/test/sun/text/resources/LocaleData +++ b/jdk/test/sun/text/resources/LocaleData @@ -673,8 +673,8 @@ FormatData/es_VE/NumberElements/0=, FormatData/es_VE/NumberElements/1=. FormatData/es_VE/NumberElements/2=; -# bug #4099810, 4290801 -CurrencyNames/uk_UA/UAH=\u0433\u0440\u0432. +# bug #4099810, 4290801, 6868106 +CurrencyNames/uk_UA/UAH=\u0433\u0440\u043b. FormatData/uk_UA/NumberPatterns/0=#,##0.###;-#,##0.### # FormatData/uk_UA/NumberPatterns/1=#,##0.## '\u0433\u0440\u0432.';-#,##0.## '\u0433\u0440\u0432.' # Changed; see bug 4122840 FormatData/uk_UA/NumberPatterns/2=#,##0% @@ -5526,3 +5526,575 @@ LocaleNames//IM=Isle Of Man # BL, MF (6627549) LocaleNames//BL=Saint Barth\u00e9lemy LocaleNames//MF=Saint Martin + +# bug 6609737 +FormatData/de/DateTimePatterns/0=HH:mm' Uhr 'z +TimeZoneNames/de/CET/1=Mitteleurop\u00e4ische Zeit +TimeZoneNames/de/CET/2=MEZ +TimeZoneNames/de/CET/3=Mitteleurop\u00e4ische Sommerzeit +TimeZoneNames/de/CET/4=MESZ +TimeZoneNames/de/EET/2=OEZ +TimeZoneNames/de/EET/4=OESZ +TimeZoneNames/de/WET/2=WEZ +TimeZoneNames/de/WET/4=WESZ + +# bug 6610748 +FormatData/fi/AmPmMarkers/0=ap. +FormatData/fi/AmPmMarkers/1=ip. + +# bug 6507067 +TimeZoneNames/zh_TW/Asia\/Taipei/1=\u53f0\u7063\u6a19\u6e96\u6642\u9593 +TimeZoneNames/zh_TW/Asia\/Taipei/2=TST + +# bug 6645271 +FormatData/hr_HR/DateTimePatterns/6=dd.MM.yyyy. +FormatData/hr_HR/DateTimePatterns/7=dd.MM.yy. + +# bug 6873931 +CurrencyNames/tr_TR/TRY=TL + +#bug 6450945 +CalendarData/ro/firstDayOfWeek=2 +CalendarData/ro/minimalDaysInFirstWeek=1 +FormatData/ro/DayNames/6=s\u00e2mb\u0103t\u0103 + +#bug 6645268 +LocaleNames/fi/fr=ranska +LocaleNames/fi/FR=Ranska +LocaleNames/fi_FI/fr=ranska +LocaleNames/fi_FI/FR=Ranska + +# bug 6646611, 6914413 +FormatData/be_BY/MonthNames/10=\u043b\u0456\u0441\u0442\u0430\u043f\u0430\u0434\u0430 +FormatData/be_BY/MonthAbbreviations/10=\u043b\u0456\u0441 + +# bug 6645405 +FormatData/hu_HU/NumberPatterns/1=#,##0.## \u00A4;-#,##0.## \u00A4 + +# bug 6650730 +FormatData/lt/NumberElements/1=\u00a0 +FormatData/lt/DateTimePatterns/6=yyyy-MM-dd + +#bug 6910489 +CalendarData/sl/firstDayOfWeek=2 + +# bug 6573250 +CurrencyNames/en_CA/USD=US$ + +# bug 6870908 +FormatData/et/MonthNames/0=jaanuar +FormatData/et/MonthNames/1=veebruar +FormatData/et/MonthNames/2=m\u00e4rts +FormatData/et/MonthNames/3=aprill +FormatData/et/MonthNames/4=mai +FormatData/et/MonthNames/5=juuni +FormatData/et/MonthNames/6=juuli +FormatData/et/MonthNames/7=august +FormatData/et/MonthNames/8=september +FormatData/et/MonthNames/9=oktoober +FormatData/et/MonthNames/10=november +FormatData/et/MonthNames/11=detsember +FormatData/et/MonthAbbreviations/0=jaan +FormatData/et/MonthAbbreviations/1=veebr +FormatData/et/MonthAbbreviations/2=m\u00e4rts +FormatData/et/MonthAbbreviations/3=apr +FormatData/et/MonthAbbreviations/4=mai +FormatData/et/MonthAbbreviations/5=juuni +FormatData/et/MonthAbbreviations/6=juuli +FormatData/et/MonthAbbreviations/7=aug +FormatData/et/MonthAbbreviations/8=sept +FormatData/et/MonthAbbreviations/9=okt +FormatData/et/MonthAbbreviations/10=nov +FormatData/et/MonthAbbreviations/11=dets + +# bug 6585666 +LocaleNames/es/aa=afar +LocaleNames/es/av=avar +LocaleNames/es/az=azer\u00ed +LocaleNames/es/ba=bashkir +LocaleNames/es/bh=bihari +LocaleNames/es/bn=bengal\u00ed +LocaleNames/es/cu=eslavo eclesi\u00e1stico +LocaleNames/es/dz=dzongkha +LocaleNames/es/eu=vasco +LocaleNames/es/fa=persa +LocaleNames/es/ff=fula +LocaleNames/es/fj=fidjiano +LocaleNames/es/fo=fero\u00e9s +LocaleNames/es/fy=fris\u00f3n +LocaleNames/es/gu=gujarati +LocaleNames/es/gv=ga\u00e9lico man\u00e9s +LocaleNames/es/hi=hindi +LocaleNames/es/ho=hiri motu +LocaleNames/es/ie=interlingue +LocaleNames/es/ig=igbo +LocaleNames/es/ii=sichuan yi +LocaleNames/es/ik=inupiaq +LocaleNames/es/kg=kongo +LocaleNames/es/ki=kikuyu +LocaleNames/es/kj=kuanyama +LocaleNames/es/kk=kazajo +LocaleNames/es/km=jemer +LocaleNames/es/kn=canar\u00e9s +LocaleNames/es/ks=cachemiro +LocaleNames/es/ku=kurdo +LocaleNames/es/ky=kirghiz +LocaleNames/es/lu=luba-katanga +LocaleNames/es/mr=marathi +LocaleNames/es/nb=bokmal noruego +LocaleNames/es/nd=ndebele septentrional +LocaleNames/es/nn=nynorsk noruego +LocaleNames/es/nr=ndebele meridional +LocaleNames/es/os=os\u00e9tico +LocaleNames/es/rm=retorrom\u00e1nico +LocaleNames/es/rn=kiroundi +LocaleNames/es/rw=kinyarwanda +LocaleNames/es/sd=sindhi +LocaleNames/es/se=sami septentrional +LocaleNames/es/sl=esloveno +LocaleNames/es/sn=shona +LocaleNames/es/ss=siswati +LocaleNames/es/st=sesotho +LocaleNames/es/su=sundan\u00e9s +LocaleNames/es/sw=swahili +LocaleNames/es/tg=tayiko +LocaleNames/es/ti=tigri\u00f1a +LocaleNames/es/tn=setchwana +LocaleNames/es/to=tongano +LocaleNames/es/tw=twi +LocaleNames/es/ty=tahitiano +LocaleNames/es/ug=uigur +LocaleNames/es/uk=ucraniano +LocaleNames/es/uz=uzbeko +LocaleNames/es/vo=volap\u00fck +LocaleNames/es/za=zhuang + +# bug 6716626 - language +LocaleNames/nl/aa=Afar +LocaleNames/nl/ab=Abchazisch +LocaleNames/nl/ae=Avestisch +LocaleNames/nl/af=Afrikaans +LocaleNames/nl/ak=Akan +LocaleNames/nl/am=Amhaars +LocaleNames/nl/an=Aragonees +LocaleNames/nl/ar=Arabisch +LocaleNames/nl/as=Assamees +LocaleNames/nl/av=Avarisch +LocaleNames/nl/ay=Aymara +LocaleNames/nl/az=Azerbeidzjaans +LocaleNames/nl/ba=Basjkiers +LocaleNames/nl/be=Wit-Russisch +LocaleNames/nl/bg=Bulgaars +LocaleNames/nl/bh=Bihari +LocaleNames/nl/bi=Bislama +LocaleNames/nl/bm=Bambara +LocaleNames/nl/bn=Bengalees +LocaleNames/nl/bo=Tibetaans +LocaleNames/nl/br=Bretons +LocaleNames/nl/bs=Bosnisch +LocaleNames/nl/ca=Catalaans +LocaleNames/nl/ce=Chechen +LocaleNames/nl/ch=Chamorro +LocaleNames/nl/co=Corsicaans +LocaleNames/nl/cr=Cree +LocaleNames/nl/cs=Tsjechisch +LocaleNames/nl/cu=Kerkslavisch +LocaleNames/nl/cv=Tsjoevasjisch +LocaleNames/nl/cy=Welsh +LocaleNames/nl/da=Deens +LocaleNames/nl/de=Duits +LocaleNames/nl/dv=Divehi +LocaleNames/nl/dz=Dzongkha +LocaleNames/nl/ee=Ewe +LocaleNames/nl/el=Grieks +LocaleNames/nl/en=Engels +LocaleNames/nl/eo=Esperanto +LocaleNames/nl/es=Spaans +LocaleNames/nl/et=Estlands +LocaleNames/nl/eu=Baskisch +LocaleNames/nl/fa=Perzisch +LocaleNames/nl/ff=Fulah +LocaleNames/nl/fi=Fins +LocaleNames/nl/fj=Fijisch +LocaleNames/nl/fo=Faer\u00f6ers +LocaleNames/nl/fr=Frans +LocaleNames/nl/fy=Fries +LocaleNames/nl/ga=Iers +LocaleNames/nl/gd=Schots Gaelic +LocaleNames/nl/gl=Galicisch +LocaleNames/nl/gn=Guarani +LocaleNames/nl/gu=Gujarati +LocaleNames/nl/gv=Manx +LocaleNames/nl/ha=Hausa +LocaleNames/nl/he=Hebreeuws +LocaleNames/nl/hi=Hindi +LocaleNames/nl/ho=Hiri Motu +LocaleNames/nl/hr=Kroatisch +LocaleNames/nl/ht=Ha\u00eftiaans +LocaleNames/nl/hu=Hongaars +LocaleNames/nl/hy=Armeens +LocaleNames/nl/hz=Herero +LocaleNames/nl/ia=Interlingua +LocaleNames/nl/id=Indonesisch +LocaleNames/nl/ie=Interlingue +LocaleNames/nl/ig=Igbo +LocaleNames/nl/ii=Sichuan Yi +LocaleNames/nl/ik=Inupiaq +LocaleNames/nl/io=Ido +LocaleNames/nl/is=IJslands +LocaleNames/nl/it=Italiaans +LocaleNames/nl/iu=Inuktitut +LocaleNames/nl/ja=Japans +LocaleNames/nl/jv=Javaans +LocaleNames/nl/ka=Georgisch +LocaleNames/nl/kg=Kongo +LocaleNames/nl/ki=Kikuyu +LocaleNames/nl/kj=Kuanyama +LocaleNames/nl/kk=Kazachs +LocaleNames/nl/kl=Kalaallisut +LocaleNames/nl/km=Khmer +LocaleNames/nl/kn=Kannada +LocaleNames/nl/ko=Koreaans +LocaleNames/nl/kr=Kanuri +LocaleNames/nl/ks=Kashmiri +LocaleNames/nl/ku=Koerdisch +LocaleNames/nl/kv=Komi +LocaleNames/nl/kw=Cornish +LocaleNames/nl/ky=Kirgizisch +LocaleNames/nl/la=Latijn +LocaleNames/nl/lb=Luxemburgs +LocaleNames/nl/lg=Ganda +LocaleNames/nl/li=Limburgs +LocaleNames/nl/ln=Lingala +LocaleNames/nl/lo=Lao +LocaleNames/nl/lt=Litouws +LocaleNames/nl/lu=Luba-Katanga +LocaleNames/nl/lv=Letlands +LocaleNames/nl/mg=Malagasisch +LocaleNames/nl/mh=Marshallees +LocaleNames/nl/mi=Maori +LocaleNames/nl/mk=Macedonisch +LocaleNames/nl/ml=Malayalam +LocaleNames/nl/mn=Mongools +LocaleNames/nl/mo=Moldavisch +LocaleNames/nl/mr=Marathi +LocaleNames/nl/ms=Maleis +LocaleNames/nl/mt=Maltees +LocaleNames/nl/my=Birmees +LocaleNames/nl/na=Nauru +LocaleNames/nl/nb=Noors - Bokm\u00e5l +LocaleNames/nl/nd=Noord-Ndbele +LocaleNames/nl/ne=Nepalees +LocaleNames/nl/ng=Ndonga +LocaleNames/nl/nl=Nederlands +LocaleNames/nl/nn=Noors - Nynorsk +LocaleNames/nl/no=Noors +LocaleNames/nl/nr=Zuid-Ndbele +LocaleNames/nl/nv=Navajo +LocaleNames/nl/ny=Nyanja +LocaleNames/nl/oc=Occitaans +LocaleNames/nl/oj=Ojibwa +LocaleNames/nl/om=Oromo +LocaleNames/nl/or=Oriya +LocaleNames/nl/os=Ossetisch +LocaleNames/nl/pa=Punjabi +LocaleNames/nl/pi=Pali +LocaleNames/nl/pl=Pools +LocaleNames/nl/ps=Pasjtoe +LocaleNames/nl/pt=Portugees +LocaleNames/nl/qu=Quechua +LocaleNames/nl/rm=Reto-Romaans +LocaleNames/nl/rn=Rundi +LocaleNames/nl/ro=Roemeens +LocaleNames/nl/ru=Russisch +LocaleNames/nl/rw=Kinyarwanda +LocaleNames/nl/sa=Sanskriet +LocaleNames/nl/sc=Sardinisch +LocaleNames/nl/sd=Sindhi +LocaleNames/nl/se=Noord-Samisch +LocaleNames/nl/sg=Sango +LocaleNames/nl/si=Singalees +LocaleNames/nl/sk=Slowaaks +LocaleNames/nl/sl=Sloveens +LocaleNames/nl/sm=Samoaans +LocaleNames/nl/sn=Shona +LocaleNames/nl/so=Somalisch +LocaleNames/nl/sq=Albanees +LocaleNames/nl/sr=Servisch +LocaleNames/nl/ss=Swati +LocaleNames/nl/st=Zuid-Sotho +LocaleNames/nl/su=Soendanees +LocaleNames/nl/sv=Zweeds +LocaleNames/nl/sw=Swahili +LocaleNames/nl/ta=Tamil +LocaleNames/nl/te=Teloegoe +LocaleNames/nl/tg=Tadzjieks +LocaleNames/nl/th=Thais +LocaleNames/nl/ti=Tigrinya +LocaleNames/nl/tk=Turkmeens +LocaleNames/nl/tl=Tagalog +LocaleNames/nl/tn=Tswana +LocaleNames/nl/to=Tonga +LocaleNames/nl/tr=Turks +LocaleNames/nl/ts=Tsonga +LocaleNames/nl/tt=Tataars +LocaleNames/nl/tw=Twi +LocaleNames/nl/ty=Tahitisch +LocaleNames/nl/ug=Oeigoers +LocaleNames/nl/uk=Oekra\u00efens +LocaleNames/nl/ur=Urdu +LocaleNames/nl/uz=Oezbeeks +LocaleNames/nl/ve=Venda +LocaleNames/nl/vi=Vietnamees +LocaleNames/nl/vo=Volap\u00fck +LocaleNames/nl/wa=Wallonisch +LocaleNames/nl/wo=Wolof +LocaleNames/nl/xh=Xhosa +LocaleNames/nl/yi=Jiddisch +LocaleNames/nl/yo=Yoruba +LocaleNames/nl/za=Zhuang +LocaleNames/nl/zh=Chinees +LocaleNames/nl/zu=Zulu + +# bug 6716626 - country +LocaleNames/nl/AD=Andorra +LocaleNames/nl/AE=Verenigde Arabische Emiraten +LocaleNames/nl/AF=Afghanistan +LocaleNames/nl/AG=Antigua en Barbuda +LocaleNames/nl/AI=Anguilla +LocaleNames/nl/AL=Albani\u00eb +LocaleNames/nl/AM=Armeni\u00eb +LocaleNames/nl/AN=Nederlandse Antillen +LocaleNames/nl/AO=Angola +LocaleNames/nl/AQ=Antarctica +LocaleNames/nl/AR=Argentini\u00eb +LocaleNames/nl/AS=Amerikaans Samoa +LocaleNames/nl/AT=Oostenrijk +LocaleNames/nl/AU=Australi\u00eb +LocaleNames/nl/AW=Aruba +LocaleNames/nl/AX=Alandeilanden +LocaleNames/nl/AZ=Azerbeidzjan +LocaleNames/nl/BA=Bosni\u00eb en Herzegovina +LocaleNames/nl/BB=Barbados +LocaleNames/nl/BD=Bangladesh +LocaleNames/nl/BE=Belgi\u00eb +LocaleNames/nl/BF=Burkina Faso +LocaleNames/nl/BG=Bulgarije +LocaleNames/nl/BH=Bahrein +LocaleNames/nl/BI=Burundi +LocaleNames/nl/BJ=Benin +LocaleNames/nl/BM=Bermuda +LocaleNames/nl/BN=Brunei +LocaleNames/nl/BO=Bolivia +LocaleNames/nl/BR=Brazili\u00eb +LocaleNames/nl/BS=Bahama\u2019s +LocaleNames/nl/BT=Bhutan +LocaleNames/nl/BV=Bouveteiland +LocaleNames/nl/BW=Botswana +LocaleNames/nl/BY=Wit-Rusland +LocaleNames/nl/BZ=Belize +LocaleNames/nl/CA=Canada +LocaleNames/nl/CC=Cocoseilanden +LocaleNames/nl/CD=Congo-Kinshasa +LocaleNames/nl/CF=Centraal-Afrikaanse Republiek +LocaleNames/nl/CG=Congo +LocaleNames/nl/CH=Zwitserland +LocaleNames/nl/CI=Ivoorkust +LocaleNames/nl/CK=Cookeilanden +LocaleNames/nl/CL=Chili +LocaleNames/nl/CM=Kameroen +LocaleNames/nl/CN=China +LocaleNames/nl/CO=Colombia +LocaleNames/nl/CR=Costa Rica +LocaleNames/nl/CS=Servi\u00eb en Montenegro +LocaleNames/nl/CU=Cuba +LocaleNames/nl/CV=Kaapverdi\u00eb +LocaleNames/nl/CX=Christmaseiland +LocaleNames/nl/CY=Cyprus +LocaleNames/nl/CZ=Tsjechi\u00eb +LocaleNames/nl/DE=Duitsland +LocaleNames/nl/DJ=Djibouti +LocaleNames/nl/DK=Denemarken +LocaleNames/nl/DM=Dominica +LocaleNames/nl/DO=Dominicaanse Republiek +LocaleNames/nl/DZ=Algerije +LocaleNames/nl/EC=Ecuador +LocaleNames/nl/EE=Estland +LocaleNames/nl/EG=Egypte +LocaleNames/nl/EH=Westelijke Sahara +LocaleNames/nl/ER=Eritrea +LocaleNames/nl/ES=Spanje +LocaleNames/nl/ET=Ethiopi\u00eb +LocaleNames/nl/FI=Finland +LocaleNames/nl/FJ=Fiji +LocaleNames/nl/FK=Falklandeilanden +LocaleNames/nl/FM=Micronesi\u00eb +LocaleNames/nl/FO=Faer\u00f6er +LocaleNames/nl/FR=Frankrijk +LocaleNames/nl/GA=Gabon +LocaleNames/nl/GB=Verenigd Koninkrijk +LocaleNames/nl/GD=Grenada +LocaleNames/nl/GE=Georgi\u00eb +LocaleNames/nl/GF=Frans-Guyana +LocaleNames/nl/GH=Ghana +LocaleNames/nl/GI=Gibraltar +LocaleNames/nl/GL=Groenland +LocaleNames/nl/GM=Gambia +LocaleNames/nl/GN=Guinee +LocaleNames/nl/GP=Guadeloupe +LocaleNames/nl/GQ=Equatoriaal-Guinea +LocaleNames/nl/GR=Griekenland +LocaleNames/nl/GS=Zuid-Georgi\u00eb en Zuidelijke Sandwicheilanden +LocaleNames/nl/GT=Guatemala +LocaleNames/nl/GU=Guam +LocaleNames/nl/GW=Guinee-Bissau +LocaleNames/nl/GY=Guyana +LocaleNames/nl/HK=Hongkong SAR van China +LocaleNames/nl/HM=Heard- en McDonaldeilanden +LocaleNames/nl/HN=Honduras +LocaleNames/nl/HR=Kroati\u00eb +LocaleNames/nl/HT=Ha\u00efti +LocaleNames/nl/HU=Hongarije +LocaleNames/nl/ID=Indonesi\u00eb +LocaleNames/nl/IE=Ierland +LocaleNames/nl/IL=Isra\u00ebl +LocaleNames/nl/IN=India +LocaleNames/nl/IO=Britse Gebieden in de Indische Oceaan +LocaleNames/nl/IQ=Irak +LocaleNames/nl/IR=Iran +LocaleNames/nl/IS=IJsland +LocaleNames/nl/IT=Itali\u00eb +LocaleNames/nl/JM=Jamaica +LocaleNames/nl/JO=Jordani\u00eb +LocaleNames/nl/JP=Japan +LocaleNames/nl/KE=Kenia +LocaleNames/nl/KG=Kirgizi\u00eb +LocaleNames/nl/KH=Cambodja +LocaleNames/nl/KI=Kiribati +LocaleNames/nl/KM=Comoren +LocaleNames/nl/KN=Saint Kitts en Nevis +LocaleNames/nl/KP=Noord-Korea +LocaleNames/nl/KR=Zuid-Korea +LocaleNames/nl/KW=Koeweit +LocaleNames/nl/KY=Caymaneilanden +LocaleNames/nl/KZ=Kazachstan +LocaleNames/nl/LA=Laos +LocaleNames/nl/LB=Libanon +LocaleNames/nl/LC=Saint Lucia +LocaleNames/nl/LI=Liechtenstein +LocaleNames/nl/LK=Sri Lanka +LocaleNames/nl/LR=Liberia +LocaleNames/nl/LS=Lesotho +LocaleNames/nl/LT=Litouwen +LocaleNames/nl/LU=Luxemburg +LocaleNames/nl/LV=Letland +LocaleNames/nl/LY=Libi\u00eb +LocaleNames/nl/MA=Marokko +LocaleNames/nl/MC=Monaco +LocaleNames/nl/MD=Moldavi\u00eb +LocaleNames/nl/ME=Montenegro +LocaleNames/nl/MG=Madagaskar +LocaleNames/nl/MH=Marshalleilanden +LocaleNames/nl/MK=Macedoni\u00eb +LocaleNames/nl/ML=Mali +LocaleNames/nl/MM=Myanmar +LocaleNames/nl/MN=Mongoli\u00eb +LocaleNames/nl/MO=Macao SAR van China +LocaleNames/nl/MP=Noordelijke Marianeneilanden +LocaleNames/nl/MQ=Martinique +LocaleNames/nl/MR=Mauritani\u00eb +LocaleNames/nl/MS=Montserrat +LocaleNames/nl/MT=Malta +LocaleNames/nl/MU=Mauritius +LocaleNames/nl/MV=Maldiven +LocaleNames/nl/MW=Malawi +LocaleNames/nl/MX=Mexico +LocaleNames/nl/MY=Maleisi\u00eb +LocaleNames/nl/MZ=Mozambique +LocaleNames/nl/NA=Namibi\u00eb +LocaleNames/nl/NC=Nieuw-Caledoni\u00eb +LocaleNames/nl/NE=Niger +LocaleNames/nl/NF=Norfolkeiland +LocaleNames/nl/NG=Nigeria +LocaleNames/nl/NI=Nicaragua +LocaleNames/nl/NL=Nederland +LocaleNames/nl/NO=Noorwegen +LocaleNames/nl/NP=Nepal +LocaleNames/nl/NR=Nauru +LocaleNames/nl/NU=Niue +LocaleNames/nl/NZ=Nieuw-Zeeland +LocaleNames/nl/OM=Oman +LocaleNames/nl/PA=Panama +LocaleNames/nl/PE=Peru +LocaleNames/nl/PF=Frans-Polynesi\u00eb +LocaleNames/nl/PG=Papoea-Nieuw-Guinea +LocaleNames/nl/PH=Filipijnen +LocaleNames/nl/PK=Pakistan +LocaleNames/nl/PL=Polen +LocaleNames/nl/PM=Saint Pierre en Miquelon +LocaleNames/nl/PN=Pitcairn +LocaleNames/nl/PR=Puerto Rico +LocaleNames/nl/PS=Palestijns Gebied +LocaleNames/nl/PT=Portugal +LocaleNames/nl/PW=Palau +LocaleNames/nl/PY=Paraguay +LocaleNames/nl/QA=Qatar +LocaleNames/nl/RE=R\u00e9union +LocaleNames/nl/RO=Roemeni\u00eb +LocaleNames/nl/RS=Servi\u00eb +LocaleNames/nl/RU=Rusland +LocaleNames/nl/RW=Rwanda +LocaleNames/nl/SA=Saoedi-Arabi\u00eb +LocaleNames/nl/SB=Salomonseilanden +LocaleNames/nl/SC=Seychellen +LocaleNames/nl/SD=Soedan +LocaleNames/nl/SE=Zweden +LocaleNames/nl/SG=Singapore +LocaleNames/nl/SH=Sint-Helena +LocaleNames/nl/SI=Sloveni\u00eb +LocaleNames/nl/SJ=Svalbard en Jan Mayen +LocaleNames/nl/SK=Slowakije +LocaleNames/nl/SL=Sierra Leone +LocaleNames/nl/SM=San Marino +LocaleNames/nl/SN=Senegal +LocaleNames/nl/SO=Somali\u00eb +LocaleNames/nl/SR=Suriname +LocaleNames/nl/ST=Sao Tom\u00e9 en Principe +LocaleNames/nl/SV=El Salvador +LocaleNames/nl/SY=Syri\u00eb +LocaleNames/nl/SZ=Swaziland +LocaleNames/nl/TC=Turks- en Caicoseilanden +LocaleNames/nl/TD=Tsjaad +LocaleNames/nl/TF=Franse Gebieden in de zuidelijke Indische Oceaan +LocaleNames/nl/TG=Togo +LocaleNames/nl/TH=Thailand +LocaleNames/nl/TJ=Tadzjikistan +LocaleNames/nl/TK=Tokelau +LocaleNames/nl/TL=Oost-Timor +LocaleNames/nl/TM=Turkmenistan +LocaleNames/nl/TN=Tunesi\u00eb +LocaleNames/nl/TO=Tonga +LocaleNames/nl/TR=Turkije +LocaleNames/nl/TT=Trinidad en Tobago +LocaleNames/nl/TV=Tuvalu +LocaleNames/nl/TW=Taiwan +LocaleNames/nl/TZ=Tanzania +LocaleNames/nl/UA=Oekra\u00efne +LocaleNames/nl/UG=Oeganda +LocaleNames/nl/UM=Amerikaanse kleinere afgelegen eilanden +LocaleNames/nl/US=Verenigde Staten +LocaleNames/nl/UY=Uruguay +LocaleNames/nl/UZ=Oezbekistan +LocaleNames/nl/VA=Vaticaanstad +LocaleNames/nl/VC=Saint Vincent en de Grenadines +LocaleNames/nl/VE=Venezuela +LocaleNames/nl/VG=Britse Maagdeneilanden +LocaleNames/nl/VI=Amerikaanse Maagdeneilanden +LocaleNames/nl/VN=Vietnam +LocaleNames/nl/VU=Vanuatu +LocaleNames/nl/WF=Wallis en Futuna +LocaleNames/nl/WS=Samoa +LocaleNames/nl/YE=Jemen +LocaleNames/nl/YT=Mayotte +LocaleNames/nl/ZA=Zuid-Afrika +LocaleNames/nl/ZM=Zambia diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java index ff36327ea77..308c3d6b64f 100644 --- a/jdk/test/sun/text/resources/LocaleDataTest.java +++ b/jdk/test/sun/text/resources/LocaleDataTest.java @@ -31,7 +31,8 @@ * 5102005 5074431 6182685 6208712 6277020 6245766 6351682 6386647 6379382 * 6414459 6455680 6498742 6558863 6488119 6547501 6497154 6558856 6481177 * 6379214 6485516 6486607 4225362 4494727 6533691 6531591 6531593 6570259 - * 6509039 + * 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611 + * 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 * @summary Verify locale data * */ @@ -255,6 +256,15 @@ public class LocaleDataTest index = key.length(); resTag = key.substring(oldIndex, index); + // TimeZone name may have "/" in it, for example "Asia/Taipei", so use "Asia\/Taipei in LocaleData. + if(resTag.endsWith("\\")) { + resTag = resTag.substring(0, resTag.length() - 1); + oldIndex = index; + index = key.indexOf("/", oldIndex + 1); + if (index == -1) index = key.length(); + resTag += key.substring(oldIndex, index); + } + if (index < key.length() - 1) qualifier = key.substring(index + 1); else diff --git a/jdk/test/sun/tools/common/ApplicationSetup.sh b/jdk/test/sun/tools/common/ApplicationSetup.sh index b5c0ad2314d..9c8e9d2bbc6 100644 --- a/jdk/test/sun/tools/common/ApplicationSetup.sh +++ b/jdk/test/sun/tools/common/ApplicationSetup.sh @@ -45,7 +45,11 @@ startApplication() # "java" process. if [ "$OS" = "Windows" ]; then sleep 2 - realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` + if [ "${isCygwin}" = "true" ] ; then + realpid=`ps -p ${pid} | tail -1 | awk '{print $4;}'` + else + realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` + fi pid=${realpid} fi diff --git a/jdk/test/sun/tools/common/CommonSetup.sh b/jdk/test/sun/tools/common/CommonSetup.sh index 861289c08d9..3876affc5ac 100644 --- a/jdk/test/sun/tools/common/CommonSetup.sh +++ b/jdk/test/sun/tools/common/CommonSetup.sh @@ -67,6 +67,11 @@ case "$OS" in PS=";" OS="Windows" ;; + CYGWIN* ) + PS=";" + OS="Windows" + isCygwin=true + ;; * ) PS=":" ;; diff --git a/jdk/test/sun/tools/jhat/HatRun.java b/jdk/test/sun/tools/jhat/HatRun.java index cb1e41b248e..6d736f83193 100644 --- a/jdk/test/sun/tools/jhat/HatRun.java +++ b/jdk/test/sun/tools/jhat/HatRun.java @@ -166,8 +166,10 @@ public class HatRun { jre_home ); String cdir = System.getProperty("test.classes", "."); String os_arch = System.getProperty("os.arch"); - boolean d64 = os_arch.equals("sparcv9") || - os_arch.equals("amd64"); + String os_name = System.getProperty("os.name"); + boolean d64 = os_name.equals("SunOS") && ( + os_arch.equals("sparcv9") || + os_arch.equals("amd64")); String isa_dir = d64?(File.separator+os_arch):""; String java = jre_home + File.separator + "bin" + isa_dir diff --git a/jdk/test/sun/tools/jps/jps-help.sh b/jdk/test/sun/tools/jps/jps-help.sh index 28a47864280..0303954343a 100644 --- a/jdk/test/sun/tools/jps/jps-help.sh +++ b/jdk/test/sun/tools/jps/jps-help.sh @@ -35,7 +35,7 @@ JPS="${TESTJAVA}/bin/jps" rm -f jps.out 2>/dev/null ${JPS} -? > jps.out 2>&1 -diff jps.out ${TESTSRC}/usage.out +diff -w jps.out ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jps -? differ from expected output. Failed." @@ -46,7 +46,7 @@ fi rm -f jps.out 2>/dev/null ${JPS} -help > jps.out 2>&1 -diff jps.out ${TESTSRC}/usage.out +diff -w jps.out ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jps -help differ from expected output. Failed." diff --git a/jdk/test/sun/tools/jstat/jstatHelp.sh b/jdk/test/sun/tools/jstat/jstatHelp.sh index 545970e3110..3ec7906c0e3 100644 --- a/jdk/test/sun/tools/jstat/jstatHelp.sh +++ b/jdk/test/sun/tools/jstat/jstatHelp.sh @@ -35,7 +35,7 @@ JSTAT="${TESTJAVA}/bin/jstat" rm -f jstat.out 2>/dev/null ${JSTAT} -? > jstat.out 2>&1 -diff jstat.out ${TESTSRC}/usage.out +diff -w jstat.out ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jstat -? differ from expected output. Failed." @@ -45,7 +45,7 @@ fi rm -f jstat.out 2>/dev/null ${JSTAT} -help > jstat.out 2>&1 -diff jstat.out ${TESTSRC}/usage.out +diff -w jstat.out ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jstat -help differ from expected output. Failed." diff --git a/jdk/test/sun/tools/jstat/jstatOptions1.sh b/jdk/test/sun/tools/jstat/jstatOptions1.sh index e38c413790f..ad3df13ca30 100644 --- a/jdk/test/sun/tools/jstat/jstatOptions1.sh +++ b/jdk/test/sun/tools/jstat/jstatOptions1.sh @@ -35,4 +35,4 @@ JSTAT="${TESTJAVA}/bin/jstat" rm -f jstat.out 2>/dev/null ${JSTAT} -options > jstat.out 2>&1 -diff jstat.out ${TESTSRC}/options1.out +diff -w jstat.out ${TESTSRC}/options1.out diff --git a/jdk/test/sun/tools/jstatd/jstatdUsage1.sh b/jdk/test/sun/tools/jstatd/jstatdUsage1.sh index 22d309b62c8..074ec5ce2ba 100644 --- a/jdk/test/sun/tools/jstatd/jstatdUsage1.sh +++ b/jdk/test/sun/tools/jstatd/jstatdUsage1.sh @@ -37,7 +37,7 @@ JSTATD_2_OUT="jstatd_$$_2.out" ${JSTATD} -? > ${JSTATD_1_OUT} 2>&1 -diff ${JSTATD_1_OUT} ${TESTSRC}/usage.out +diff -w ${JSTATD_1_OUT} ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jstatd -? differs from expected output. Failed." @@ -46,7 +46,7 @@ fi ${JSTATD} -help > ${JSTATD_2_OUT} 2>&1 -diff ${JSTATD_2_OUT} ${TESTSRC}/usage.out +diff -w ${JSTATD_2_OUT} ${TESTSRC}/usage.out if [ $? != 0 ] then echo "Output of jstatd -help differs from expected output. Failed." diff --git a/jdk/test/sun/tools/native2ascii/Native2AsciiTests.sh b/jdk/test/sun/tools/native2ascii/Native2AsciiTests.sh index 1fa7f6c0004..26281ba7241 100644 --- a/jdk/test/sun/tools/native2ascii/Native2AsciiTests.sh +++ b/jdk/test/sun/tools/native2ascii/Native2AsciiTests.sh @@ -32,7 +32,7 @@ if [ "${TESTSRC}" = "" ]; then TESTSRC=.; fi if [ "${TESTJAVA}" = "" ]; then TESTJAVA=$1; shift; fi case `uname -s` in - Windows*) OS=Windows;; + Windows* | CYGWIN*) OS=Windows;; SunOS|Linux) OS=Unix;; esac @@ -45,12 +45,14 @@ check() { # Strip carriage returns from output when comparing with n2a test output # on win32 systems - if [ OS = Windows ]; then - tr -d '\015' <$out >$out.1 + if [ ${OS} = Windows ]; then + sed -e 's@\\r@@g' $out >$out.1 + sed -e 's@\\r@@g' $expected >$out.expected else cp $out $out.1 + cp $expected $out.expected fi - if (set -x; diff -c $expected $out.1); then + if (set -x; diff -c $out.expected $out.1); then echo "$bug passed" else echo "$bug failed" diff --git a/jdk/test/sun/util/resources/Locale/Bug4429024.java b/jdk/test/sun/util/resources/Locale/Bug4429024.java index 6a3ffc2891f..e592025d0b3 100644 --- a/jdk/test/sun/util/resources/Locale/Bug4429024.java +++ b/jdk/test/sun/util/resources/Locale/Bug4429024.java @@ -46,7 +46,7 @@ public class Bug4429024 { { "en", "englanti" }, { "es", "espanja" }, { "fi", "suomi" }, - { "fr", "franska" }, + { "fr", "ranska" }, { "he", "heprea" }, { "hi", "hindi" }, { "it", "italia" }, @@ -75,7 +75,7 @@ public class Bug4429024 { { "DK", "Tanska" }, { "ES", "Espanja" }, { "FI", "Suomi" }, - { "FR", "Franska" }, + { "FR", "Ranska" }, { "GB", "Iso-Britannia" }, { "GR", "Kreikka" }, { "IE", "Irlanti" }, diff --git a/jdk/test/tools/launcher/ChangeDataModel.sh b/jdk/test/tools/launcher/ChangeDataModel.sh index eddc38d7cfc..1fc689f403b 100644 --- a/jdk/test/tools/launcher/ChangeDataModel.sh +++ b/jdk/test/tools/launcher/ChangeDataModel.sh @@ -29,6 +29,9 @@ OS=`uname -s`; +# To remove CR from output, needed for java apps in CYGWIN, harmless otherwise +SED_CR="sed -e s@\\r@@g" + case "$OS" in Windows* | CYGWIN* ) PATHSEP=";" @@ -79,10 +82,10 @@ $JAVAC GetDataModel.java # Verify data model flag for default data model is accepted -DM=`$JAVA GetDataModel` +DM=`$JAVA GetDataModel | ${SED_CR}` case "$DM" in 32 ) - DM2=`${JAVA} -d32 GetDataModel` + DM2=`${JAVA} -d32 GetDataModel | ${SED_CR}` if [ "${DM2}" != "32" ] then echo "Data model flag -d32 not accepted or had improper effect." @@ -91,7 +94,7 @@ case "$DM" in ;; 64 ) - DM2=`${JAVA} -d64 GetDataModel` + DM2=`${JAVA} -d64 GetDataModel | ${SED_CR}` if [ "${DM2}" != "64" ] then echo "Data model flag -d64 not accepted or had improper effect." @@ -227,10 +230,10 @@ then else # Negative tests for non-dual mode platforms to ensure the other data model is # rejected - DM=`$JAVA GetDataModel` + DM=`$JAVA GetDataModel | ${SED_CR}` case "$DM" in 32 ) - DM2=`${JAVA} -d64 GetDataModel` + DM2=`${JAVA} -d64 GetDataModel | ${SED_CR}` if [ "x${DM2}" != "x" ] then echo "Data model flag -d64 was accepted." @@ -239,7 +242,7 @@ else ;; 64 ) - DM2=`${JAVA} -d32 GetDataModel` + DM2=`${JAVA} -d32 GetDataModel | ${SED_CR}` if [ "x${DM2}" != "x" ] then echo "Data model flag -d32 was accepted." diff --git a/jdk/test/tools/launcher/ClassPathWildCard.sh b/jdk/test/tools/launcher/ClassPathWildCard.sh index 46a4866e486..4b3b0dfb5e1 100644 --- a/jdk/test/tools/launcher/ClassPathWildCard.sh +++ b/jdk/test/tools/launcher/ClassPathWildCard.sh @@ -145,7 +145,7 @@ CreateClassFiles D OS=`uname -s` case $OS in - Windows*|Cygwin*) + Windows*|CYGWIN*) PATHSEP=";" ExecJava "" "${PATHSEP}NOOPDIR" ExecJava "w" "${PATHSEP}NOOPDIR" diff --git a/jdk/test/tools/launcher/DefaultLocaleTest.sh b/jdk/test/tools/launcher/DefaultLocaleTest.sh index 97eddd5bf63..31af0aa3199 100644 --- a/jdk/test/tools/launcher/DefaultLocaleTest.sh +++ b/jdk/test/tools/launcher/DefaultLocaleTest.sh @@ -48,7 +48,7 @@ fi OS=`uname` case "$OS" in - Windows* | CYGWIN* ) + Windows* ) JAVAC="${TESTJAVA}/bin/javac -d . " JAVA="${TESTJAVA}/bin/java -classpath . " JAVAW="${TESTJAVA}/bin/javaw -classpath . " @@ -64,6 +64,22 @@ case "$OS" in echo "Test passes" exit 0 ;; + CYGWIN* ) + JAVAC="${TESTJAVA}/bin/javac -d . " + JAVA="${TESTJAVA}/bin/java -classpath . " + JAVAW="${TESTJAVA}/bin/javaw -classpath . " + + ${JAVAC} ${TESTSRC}/DefaultLocaleTest.java + ${JAVA} DefaultLocaleTest | sed -e s@\\r@@g > x.out + ${JAVAW} DefaultLocaleTest `cat x.out` + if [ $? -ne 0 ] + then + echo "Test fails" + exit 1 + fi + echo "Test passes" + exit 0 + ;; * ) echo "Non-windows environment; test vacuously succeeds." exit 0; diff --git a/jdk/test/tools/launcher/UnicodeTest.sh b/jdk/test/tools/launcher/UnicodeTest.sh index 7b4789772f0..8f77f4b739d 100644 --- a/jdk/test/tools/launcher/UnicodeTest.sh +++ b/jdk/test/tools/launcher/UnicodeTest.sh @@ -54,7 +54,7 @@ mkdir UnicodeTest-src UnicodeTest-classes echo "creating test source files" "$JAVAC" -d . "${TESTSRC}"/UnicodeTest.java -CLASS_NAME=`"$JAVA" UnicodeTest` +CLASS_NAME=`"$JAVA" UnicodeTest | sed -e 's@\\r@@g' ` if [ "$CLASS_NAME" = "" ] then diff --git a/langtools/.hgignore b/langtools/.hgignore index ca1b0b21ee2..0092bd4ff5a 100644 --- a/langtools/.hgignore +++ b/langtools/.hgignore @@ -1,3 +1,3 @@ ^build/ ^dist/ -^nbproject/private/ +/nbproject/private/ diff --git a/langtools/.hgtags b/langtools/.hgtags index ed1d1b15d59..662a0caab64 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -51,3 +51,7 @@ ce9bcdcb7859bb7ef10afd078ad59ba7847f208d jdk7-b69 1a66b08deed0459054b5b1bea3dfbead30d258fa jdk7-b74 2485f5641ed0829205aaaeb31ad711c2c2ef0de3 jdk7-b75 8fb9b4be3cb1574302acde90549a4d333ef51e93 jdk7-b76 +0398ae15b90ac76d87ee21844453e95ff8613e43 jdk7-b77 +acc1e40a5874ebf32bebcb6ada565b3b40b7461c jdk7-b78 +ac5b4c5644ce54585e5287563dde2b006fa664f4 jdk7-b79 +f0074aa48d4e2a4c03c92b9c4f880679fea0306c jdk7-b80 diff --git a/langtools/make/Makefile b/langtools/make/Makefile index e2c8202f6b5..ec31db106b5 100644 --- a/langtools/make/Makefile +++ b/langtools/make/Makefile @@ -133,6 +133,23 @@ ifdef ALT_BOOTDIR ANT_JAVA_HOME = JAVA_HOME=$(ALT_BOOTDIR) endif +# To facilitate bootstrapping, much of langtools can be compiled with (just) +# a boot JDK. However, some source files need to be compiled against +# new JDK API. In a bootstrap build, an import JDK may not be available, +# so build.xml can also build against the source files in a jdk repo, +# in which case it will automatically generate stub files for the new JDK API. +ifdef JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(JDK_TOPDIR) +else + ifdef ALT_JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_TOPDIR) + else + ifdef ALT_JDK_IMPORT_PATH + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_IMPORT_PATH) + endif + endif +endif + ifdef ALT_OUTPUTDIR OUTPUTDIR = $(ALT_OUTPUTDIR) ANT_OPTIONS += -Dbuild.dir=$(ALT_OUTPUTDIR)/build diff --git a/langtools/make/build.properties b/langtools/make/build.properties index ffe6fc0ce85..75dc6c97b32 100644 --- a/langtools/make/build.properties +++ b/langtools/make/build.properties @@ -148,6 +148,28 @@ apt.tests = \ # +# The following files require the import JDK to be available +require.import.jdk.files = \ + com/sun/tools/javac/nio/*.java + +# The following files in the import jdk source directory are required +# in order to compile the files defined in ${require.import.jdk.files} +# +# For NIO, the list of stub files is defined by the contents of the primary +# API packages, together with such types that may be required in order to +# compile the stubs. Some of these dependencies would go away if the stub +# generator were to be improved -- e.g. by removing unnecessary imports. +# +import.jdk.stub.files = \ + java/io/File.java \ + java/nio/file/**.java \ + java/nio/file/attribute/**.java \ + java/nio/file/spi/**.java \ + java/nio/channels/AsynchronousChannel.java \ + java/nio/channels/AsynchronousFileChannel.java \ + java/nio/channels/CompletionHandler.java \ + java/nio/channels/SeekableByteChannel.java + # The following value is used by the main jtreg target. # An empty value means all tests # Override as desired to run a specific set of tests diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 6b04ca30fc1..d614578847f 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -56,6 +56,7 @@ + @@ -93,6 +94,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -108,11 +151,17 @@ - + - + - + + + @@ -188,23 +237,27 @@ - - + + + + - - + + - - + + + - + @@ -217,19 +270,20 @@ - + + + - + - - + + @@ -249,21 +303,19 @@ - + + - + - + - + @@ -281,19 +333,19 @@ - + + + - - + + + - + @@ -310,21 +362,23 @@ - - + + + + - + - - + + @@ -342,19 +396,19 @@ - + + + - - + + + - + @@ -372,6 +426,17 @@ + + + + + + + @@ -396,40 +461,12 @@ - + - - - - - - - - - - - - - - @@ -442,35 +479,15 @@ - + - - - - - - - - - - - + - - - + + + + + + + + + + - - - - - + + - + - - - + + @@ -562,30 +574,32 @@ + java="${boot.java}"/> + + + + + + + full.version="${bootstrap.full.version}" + excludes="${require.import.jdk.files} **/package-info.java"/> @@ -603,6 +617,20 @@ classpath="${build.toolclasses.dir}/"/> + + + + + + @@ -764,7 +792,7 @@ + description="display settings of configuration values"> ant.home = ${ant.home} boot.java.home = ${boot.java.home} target.java.home = ${target.java.home} diff --git a/langtools/make/tools/CompileProperties/CompileProperties.java b/langtools/make/tools/CompileProperties/CompileProperties.java index f498815ddf2..7e2d5dca58f 100644 --- a/langtools/make/tools/CompileProperties/CompileProperties.java +++ b/langtools/make/tools/CompileProperties/CompileProperties.java @@ -101,7 +101,7 @@ public class CompileProperties { boolean ok = true; /* Original usage */ if (args.length == 2 && args[0].charAt(0) != '-' ) { - ok = createFile(args[0], args[1], "ListResourceBundle"); + ok = createFile(args[0], args[1], "java.util.ListResourceBundle"); } else if (args.length == 3) { ok = createFile(args[0], args[1], args[2]); } else if (args.length == 0) { @@ -285,9 +285,9 @@ public class CompileProperties { log.info(" java CompileProperties {-compile path_to_properties_file path_to_java_output_file super_class} -or- -optionsfile filename"); log.info(""); log.info("Example:"); - log.info(" java CompileProperties -compile test.properties test.java ListResourceBundle"); + log.info(" java CompileProperties -compile test.properties test.java java.util.ListResourceBundle"); log.info(" java CompileProperties -optionsfile option_file"); - log.info("option_file contains: -compile test.properties test.java ListResourceBundle"); + log.info("option_file contains: -compile test.properties test.java java.util.ListResourceBundle"); } private static String escape(String theString) { @@ -379,7 +379,6 @@ public class CompileProperties { private static final String FORMAT = "{0}" + - "import java.util.ListResourceBundle;\n\n" + "public final class {1} extends {2} '{'\n" + " protected final Object[][] getContents() '{'\n" + " return new Object[][] '{'\n" + diff --git a/langtools/make/tools/CompileProperties/CompilePropertiesTask.java b/langtools/make/tools/CompileProperties/CompilePropertiesTask.java index e7a0be1751d..bed9e27b3bf 100644 --- a/langtools/make/tools/CompileProperties/CompilePropertiesTask.java +++ b/langtools/make/tools/CompileProperties/CompilePropertiesTask.java @@ -45,6 +45,7 @@ public class CompilePropertiesTask extends MatchingTask { this.superclass = superclass; } + @Override public void execute() { CompileProperties.Log log = new CompileProperties.Log() { public void error(String msg, Exception e) { @@ -84,7 +85,7 @@ public class CompilePropertiesTask extends MatchingTask { log("Generating " + count + " resource files to " + destDir, Project.MSG_INFO); CompileProperties cp = new CompileProperties(); cp.setLog(log); - boolean ok = cp.run((String[])mainOpts.toArray(new String[mainOpts.size()])); + boolean ok = cp.run(mainOpts.toArray(new String[mainOpts.size()])); if (!ok) throw new BuildException("CompileProperties failed."); } diff --git a/langtools/make/tools/GenStubs/GenStubs.java b/langtools/make/tools/GenStubs/GenStubs.java new file mode 100644 index 00000000000..a2fd4b3605b --- /dev/null +++ b/langtools/make/tools/GenStubs/GenStubs.java @@ -0,0 +1,448 @@ +/* + * 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.util.*; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; + + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.TypeTags; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.Pretty; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.tree.TreeTranslator; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; +import javax.tools.JavaFileManager; + +/** + * Generate stub source files by removing implementation details from input files. + * + * This is a special purpose stub generator, specific to the needs of generating + * stub files for JDK 7 API that are needed to compile langtools files that depend + * on that API. The stub generator works by removing as much of the API source code + * as possible without affecting the public signature, in order to reduce the + * transitive closure of the API being referenced. The resulting stubs can be + * put on the langtools sourcepath with -implicit:none to compile the langtools + * files that depend on the JDK 7 API. + * + * Usage: + * genstubs -s -sourcepath + * + * The specified class names are looked up on the sourcepath, and corresponding + * stubs are written to the source output directory. + * + * Classes are parsed into javac ASTs, then processed with a javac TreeTranslator + * to remove implementation details, and written out in the source output directory. + * Documentation comments and annotations are removed. Method bodies are removed + * and methods are marked native. Private and package-private field definitions + * have their initializers replace with 0, 0.0, false, null as appropriate. + * + * An Ant task, Main$Ant is also provided. Files are specified with an implicit + * fileset, using srcdir as a base directory. The set of files to be included + * is specified with an includes attribute or nested set. However, + * unlike a normal fileset, an empty includes attribute means "no files" instead + * of "all files". The Ant task also accepts "fork=true" and classpath attribute + * or nested element to run GenStubs in a separate VM with the specified + * path. This is likely necessary if a JDK 7 parser is required to read the + * JDK 7 input files. + */ + +public class GenStubs { + static class Fault extends Exception { + private static final long serialVersionUID = 0; + Fault(String message) { + super(message); + } + Fault(String message, Throwable cause) { + super(message); + initCause(cause); + } + } + + public static void main(String[] args) { + boolean ok = new GenStubs().run(args); + if (!ok) + System.exit(1); + } + + boolean run(String... args) { + File outdir = null; + String sourcepath = null; + List classes = new ArrayList(); + for (ListIterator iter = Arrays.asList(args).listIterator(); iter.hasNext(); ) { + String arg = iter.next(); + if (arg.equals("-s") && iter.hasNext()) + outdir = new File(iter.next()); + else if (arg.equals("-sourcepath") && iter.hasNext()) + sourcepath = iter.next(); + else if (arg.startsWith("-")) + throw new IllegalArgumentException(arg); + else { + classes.add(arg); + while (iter.hasNext()) + classes.add(iter.next()); + } + } + + return run(sourcepath, outdir, classes); + } + + boolean run(String sourcepath, File outdir, List classes) { + //System.err.println("run: sourcepath:" + sourcepath + " outdir:" + outdir + " classes:" + classes); + if (sourcepath == null) + throw new IllegalArgumentException("sourcepath not set"); + if (outdir == null) + throw new IllegalArgumentException("source output dir not set"); + + JavacTool tool = JavacTool.create(); + StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); + + try { + fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outdir)); + fm.setLocation(StandardLocation.SOURCE_PATH, splitPath(sourcepath)); + List files = new ArrayList(); + for (String c: classes) { + JavaFileObject fo = fm.getJavaFileForInput( + StandardLocation.SOURCE_PATH, c, JavaFileObject.Kind.SOURCE); + if (fo == null) + error("class not found: " + c); + else + files.add(fo); + } + + JavacTask t = tool.getTask(null, fm, null, null, null, files); + Iterable trees = t.parse(); + for (CompilationUnitTree tree: trees) { + makeStub(fm, tree); + } + } catch (IOException e) { + error("IO error " + e, e); + } + + return (errors == 0); + } + + void makeStub(StandardJavaFileManager fm, CompilationUnitTree tree) throws IOException { + CompilationUnitTree tree2 = new StubMaker().translate(tree); + CompilationUnitTree tree3 = new ImportCleaner(fm).removeRedundantImports(tree2); + + String className = fm.inferBinaryName(StandardLocation.SOURCE_PATH, tree.getSourceFile()); + JavaFileObject fo = fm.getJavaFileForOutput(StandardLocation.SOURCE_OUTPUT, + className, JavaFileObject.Kind.SOURCE, null); + // System.err.println("Writing " + className + " to " + fo.getName()); + Writer out = fo.openWriter(); + try { + new Pretty(out, true).printExpr((JCTree) tree3); + } finally { + out.close(); + } + } + + List splitPath(String path) { + List list = new ArrayList(); + for (String p: path.split(File.pathSeparator)) { + if (p.length() > 0) + list.add(new File(p)); + } + return list; + } + + void error(String message) { + System.err.println(message); + errors++; + } + + void error(String message, Throwable cause) { + error(message); + } + + int errors; + + class StubMaker extends TreeTranslator { + CompilationUnitTree translate(CompilationUnitTree tree) { + return super.translate((JCCompilationUnit) tree); + } + + /** + * compilation units: remove javadoc comments + * -- required, in order to remove @deprecated tags, since we + * (separately) remove all annotations, including @Deprecated + */ + public void visitTopLevel(JCCompilationUnit tree) { + super.visitTopLevel(tree); + tree.docComments = Collections.emptyMap(); + } + + /** + * methods: remove method bodies, make methods native + */ + @Override + public void visitMethodDef(JCMethodDecl tree) { + tree.mods = translate(tree.mods); + tree.restype = translate(tree.restype); + tree.typarams = translateTypeParams(tree.typarams); + tree.params = translateVarDefs(tree.params); + tree.thrown = translate(tree.thrown); + if (tree.restype != null && tree.body != null) { + tree.mods.flags |= Flags.NATIVE; + tree.body = null; + } + result = tree; + } + + /** + * modifiers: remove annotations + */ + @Override + public void visitModifiers(JCModifiers tree) { + tree.annotations = com.sun.tools.javac.util.List.nil(); + result = tree; + } + + /** + * field definitions: replace initializers with 0, 0.0, false etc + * when possible -- i.e. leave public, protected initializers alone + */ + @Override + public void visitVarDef(JCVariableDecl tree) { + tree.mods = translate(tree.mods); + tree.vartype = translate(tree.vartype); + if (tree.init != null) { + if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0) + tree.init = translate(tree.init); + else { + String t = tree.vartype.toString(); + if (t.equals("boolean")) + tree.init = new JCLiteral(TypeTags.BOOLEAN, 0) { }; + else if (t.equals("byte")) + tree.init = new JCLiteral(TypeTags.BYTE, 0) { }; + else if (t.equals("char")) + tree.init = new JCLiteral(TypeTags.CHAR, 0) { }; + else if (t.equals("double")) + tree.init = new JCLiteral(TypeTags.DOUBLE, 0.d) { }; + else if (t.equals("float")) + tree.init = new JCLiteral(TypeTags.FLOAT, 0.f) { }; + else if (t.equals("int")) + tree.init = new JCLiteral(TypeTags.INT, 0) { }; + else if (t.equals("long")) + tree.init = new JCLiteral(TypeTags.LONG, 0) { }; + else if (t.equals("short")) + tree.init = new JCLiteral(TypeTags.SHORT, 0) { }; + else + tree.init = new JCLiteral(TypeTags.BOT, null) { }; + } + } + result = tree; + } + } + + class ImportCleaner extends TreeScanner { + private Set names = new HashSet(); + private TreeMaker m; + + ImportCleaner(JavaFileManager fm) { + // ImportCleaner itself doesn't require a filemanager, but instantiating + // a TreeMaker does, indirectly (via ClassReader, sigh) + Context c = new Context(); + c.put(JavaFileManager.class, fm); + m = TreeMaker.instance(c); + } + + CompilationUnitTree removeRedundantImports(CompilationUnitTree t) { + JCCompilationUnit tree = (JCCompilationUnit) t; + tree.accept(this); + ListBuffer defs = new ListBuffer(); + for (JCTree def: tree.defs) { + if (def.getTag() == JCTree.IMPORT) { + JCImport imp = (JCImport) def; + if (imp.qualid.getTag() == JCTree.SELECT) { + JCFieldAccess qualid = (JCFieldAccess) imp.qualid; + if (!qualid.name.toString().equals("*") + && !names.contains(qualid.name)) { + continue; + } + } + } + defs.add(def); + } + return m.TopLevel(tree.packageAnnotations, tree.pid, defs.toList()); + } + + @Override + public void visitImport(JCImport tree) { } // ignore names found in imports + + @Override + public void visitIdent(JCIdent tree) { + names.add(tree.name); + } + + @Override + public void visitSelect(JCFieldAccess tree) { + super.visitSelect(tree); + names.add(tree.name); + } + } + + //---------- Ant Invocation ------------------------------------------------ + + public static class Ant extends MatchingTask { + private File srcDir; + private File destDir; + private boolean fork; + private Path classpath; + private String includes; + + public void setSrcDir(File dir) { + this.srcDir = dir; + } + + public void setDestDir(File dir) { + this.destDir = dir; + } + + public void setFork(boolean v) { + this.fork = v; + } + + public void setClasspath(Path cp) { + if (classpath == null) + classpath = cp; + else + classpath.append(cp); + } + + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(getProject()); + } + return classpath.createPath(); + } + + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + public void setIncludes(String includes) { + super.setIncludes(includes); + this.includes = includes; + } + + @Override + public void execute() { + if (includes != null && includes.trim().isEmpty()) + return; + + DirectoryScanner s = getDirectoryScanner(srcDir); + String[] files = s.getIncludedFiles(); +// System.err.println("Ant.execute: srcDir " + srcDir); +// System.err.println("Ant.execute: destDir " + destDir); +// System.err.println("Ant.execute: files " + Arrays.asList(files)); + + files = filter(srcDir, destDir, files); + if (files.length == 0) + return; + System.out.println("Generating " + files.length + " stub files to " + destDir); + + List classNames = new ArrayList(); + for (String file: files) { + classNames.add(file.replaceAll(".java$", "").replace('/', '.')); + } + + if (!fork) { + GenStubs m = new GenStubs(); + boolean ok = m.run(srcDir.getPath(), destDir, classNames); + if (!ok) + throw new BuildException("genstubs failed"); + } else { + List cmd = new ArrayList(); + String java_home = System.getProperty("java.home"); + cmd.add(new File(new File(java_home, "bin"), "java").getPath()); + if (classpath != null) + cmd.add("-Xbootclasspath/p:" + classpath); + cmd.add(GenStubs.class.getName()); + cmd.add("-sourcepath"); + cmd.add(srcDir.getPath()); + cmd.add("-s"); + cmd.add(destDir.getPath()); + cmd.addAll(classNames); + //System.err.println("GenStubs exec " + cmd); + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.redirectErrorStream(true); + try { + Process p = pb.start(); + BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + try { + String line; + while ((line = in.readLine()) != null) + System.out.println(line); + } finally { + in.close(); + } + int rc = p.waitFor(); + if (rc != 0) + throw new BuildException("genstubs failed"); + } catch (IOException e) { + throw new BuildException("genstubs failed", e); + } catch (InterruptedException e) { + throw new BuildException("genstubs failed", e); + } + } + } + + String[] filter(File srcDir, File destDir, String[] files) { + List results = new ArrayList(); + for (String f: files) { + long srcTime = new File(srcDir, f).lastModified(); + long destTime = new File(destDir, f).lastModified(); + if (srcTime > destTime) + results.add(f); + } + return results.toArray(new String[results.size()]); + } + } +} diff --git a/langtools/src/share/bin/launcher.sh-template b/langtools/src/share/bin/launcher.sh-template index c62af2e9b94..16ade3e071d 100644 --- a/langtools/src/share/bin/launcher.sh-template +++ b/langtools/src/share/bin/launcher.sh-template @@ -38,7 +38,7 @@ mylib="`dirname $mydir`"/lib # dependent jar files for additional dependencies. if [ "$LANGTOOLS_USE_BOOTCLASSPATH" != "no" ]; then - cp=`unzip -c $mylib/#PROGRAM#.jar META-INF/MANIFEST.MF | + cp=`unzip -c "$mylib/#PROGRAM#.jar" META-INF/MANIFEST.MF | grep "Class-Path:" | sed -e 's|Class-Path: *||' -e 's|\([a-z]*\.jar\) *|'"$mylib"'/\1:|g'` bcp="$mylib/#PROGRAM#.jar":$cp diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java new file mode 100644 index 00000000000..c42ae8ec07e --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java @@ -0,0 +1,718 @@ +/* + * 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 java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import com.sun.tools.classfile.Dependency.Finder; +import com.sun.tools.classfile.Dependency.Filter; +import com.sun.tools.classfile.Dependency.Location; +import com.sun.tools.classfile.Type.ArrayType; +import com.sun.tools.classfile.Type.ClassSigType; +import com.sun.tools.classfile.Type.ClassType; +import com.sun.tools.classfile.Type.MethodType; +import com.sun.tools.classfile.Type.SimpleType; +import com.sun.tools.classfile.Type.TypeParamType; +import com.sun.tools.classfile.Type.WildcardType; + +import static com.sun.tools.classfile.ConstantPool.*; + +/** + * A framework for determining {@link Dependency dependencies} between class files. + * + * A {@link Dependency.Finder finder} is used to identify the dependencies of + * individual classes. Some finders may return subtypes of {@code Dependency} to + * further characterize the type of dependency, such as a dependency on a + * method within a class. + * + * A {@link Dependency.Filter filter} may be used to restrict the set of + * dependencies found by a finder. + * + * Dependencies that are found may be passed to a {@link Dependencies.Recorder + * recorder} so that the dependencies can be stored in a custom data structure. + */ +public class Dependencies { + /** + * Thrown when a class file cannot be found. + */ + public static class ClassFileNotFoundException extends Exception { + private static final long serialVersionUID = 3632265927794475048L; + + public ClassFileNotFoundException(String className) { + super(className); + this.className = className; + } + + public ClassFileNotFoundException(String className, Throwable cause) { + this(className); + initCause(cause); + } + + public final String className; + } + + /** + * Thrown when an exception is found processing a class file. + */ + public static class ClassFileError extends Error { + private static final long serialVersionUID = 4111110813961313203L; + + public ClassFileError(Throwable cause) { + initCause(cause); + } + } + + /** + * Service provider interface to locate and read class files. + */ + public interface ClassFileReader { + /** + * Get the ClassFile object for a specified class. + * @param className the name of the class to be returned. + * @return the ClassFile for the given class + * @throws Dependencies#ClassFileNotFoundException if the classfile cannot be + * found + */ + public ClassFile getClassFile(String className) + throws ClassFileNotFoundException; + } + + /** + * Service provide interface to handle results. + */ + public interface Recorder { + /** + * Record a dependency that has been found. + * @param d + */ + public void addDependency(Dependency d); + } + + /** + * Get the default finder used to locate the dependencies for a class. + * @return the default finder + */ + public static Finder getDefaultFinder() { + return new APIDependencyFinder(AccessFlags.ACC_PRIVATE); + } + + /** + * Get a finder used to locate the API dependencies for a class. + * These include the superclass, superinterfaces, and classes referenced in + * the declarations of fields and methods. The fields and methods that + * are checked can be limited according to a specified access. + * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC}, + * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE}, + * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for + * package private access. Members with greater than or equal accessibility + * to that specified will be searched for dependencies. + * @param access the access of members to be checked + * @return an API finder + */ + public static Finder getAPIFinder(int access) { + return new APIDependencyFinder(access); + } + + /** + * Get the finder used to locate the dependencies for a class. + * @return the finder + */ + public Finder getFinder() { + if (finder == null) + finder = getDefaultFinder(); + return finder; + } + + /** + * Set the finder used to locate the dependencies for a class. + * @param f the finder + */ + public void setFinder(Finder f) { + f.getClass(); // null check + finder = f; + } + + /** + * Get the default filter used to determine included when searching + * the transitive closure of all the dependencies. + * Unless overridden, the default filter accepts all dependencies. + * @return the default filter. + */ + public static Filter getDefaultFilter() { + return DefaultFilter.instance(); + } + + /** + * Get a filter which uses a regular expression on the target's class name + * to determine if a dependency is of interest. + * @param pattern the pattern used to match the target's class name + * @return a filter for matching the target class name with a regular expression + */ + public static Filter getRegexFilter(Pattern pattern) { + return new TargetRegexFilter(pattern); + } + + /** + * Get a filter which checks the package of a target's class name + * to determine if a dependency is of interest. The filter checks if the + * package of the target's class matches any of a set of given package + * names. The match may optionally match subpackages of the given names as well. + * @param packageNames the package names used to match the target's class name + * @param matchSubpackages whether or not to match subpackages as well + * @return a filter for checking the target package name against a list of package names + */ + public static Filter getPackageFilter(Set packageNames, boolean matchSubpackages) { + return new TargetPackageFilter(packageNames, matchSubpackages); + } + + /** + * Get the filter used to determine the dependencies included when searching + * the transitive closure of all the dependencies. + * Unless overridden, the default filter accepts all dependencies. + * @return the filter + */ + public Filter getFilter() { + if (filter == null) + filter = getDefaultFilter(); + return filter; + } + + /** + * Set the filter used to determine the dependencies included when searching + * the transitive closure of all the dependencies. + * @param f the filter + */ + public void setFilter(Filter f) { + f.getClass(); // null check + filter = f; + } + + /** + * Find the dependencies of a class, using the current + * {@link Dependencies#getFinder finder} and + * {@link Dependencies#getFilter filter}. + * The search may optionally include the transitive closure of all the + * filtered dependencies, by also searching in the classes named in those + * dependencies. + * @param classFinder a finder to locate class files + * @param rootClassNames the names of the root classes from which to begin + * searching + * @param transitiveClosure whether or not to also search those classes + * named in any filtered dependencies that are found. + * @return the set of dependencies that were found + * @throws ClassFileNotFoundException if a required class file cannot be found + * @throws ClassFileError if an error occurs while processing a class file, + * such as an error in the internal class file structure. + */ + public Set findAllDependencies( + ClassFileReader classFinder, Set rootClassNames, + boolean transitiveClosure) + throws ClassFileNotFoundException { + final Set results = new HashSet(); + Recorder r = new Recorder() { + public void addDependency(Dependency d) { + results.add(d); + } + }; + findAllDependencies(classFinder, rootClassNames, transitiveClosure, r); + return results; + } + + + + /** + * Find the dependencies of a class, using the current + * {@link Dependencies#getFinder finder} and + * {@link Dependencies#getFilter filter}. + * The search may optionally include the transitive closure of all the + * filtered dependencies, by also searching in the classes named in those + * dependencies. + * @param classFinder a finder to locate class files + * @param rootClassNames the names of the root classes from which to begin + * searching + * @param transitiveClosure whether or not to also search those classes + * named in any filtered dependencies that are found. + * @param recorder a recorder for handling the results + * @throws ClassFileNotFoundException if a required class file cannot be found + * @throws ClassFileError if an error occurs while processing a class file, + * such as an error in the internal class file structure. + */ + public void findAllDependencies( + ClassFileReader classFinder, Set rootClassNames, + boolean transitiveClosure, Recorder recorder) + throws ClassFileNotFoundException { + Set doneClasses = new HashSet(); + + getFinder(); // ensure initialized + getFilter(); // ensure initialized + + // Work queue of names of classfiles to be searched. + // Entries will be unique, and for classes that do not yet have + // dependencies in the results map. + Deque deque = new LinkedList(rootClassNames); + + String className; + while ((className = deque.poll()) != null) { + assert (!doneClasses.contains(className)); + doneClasses.add(className); + + ClassFile cf = classFinder.getClassFile(className); + + // The following code just applies the filter to the dependencies + // followed for the transitive closure. + for (Dependency d: finder.findDependencies(cf)) { + recorder.addDependency(d); + if (transitiveClosure && filter.accepts(d)) { + String cn = d.getTarget().getClassName(); + if (!doneClasses.contains(cn)) + deque.add(cn); + } + } + } + } + + private Filter filter; + private Finder finder; + + /** + * A location identifying a class. + */ + static class SimpleLocation implements Location { + public SimpleLocation(String className) { + this.className = className; + } + + /** + * Get the name of the class being depended on. This name will be used to + * locate the class file for transitive dependency analysis. + * @return the name of the class being depended on + */ + public String getClassName() { + return className; + } + + @Override + public boolean equals(Object other) { + if (this == other) + return true; + if (!(other instanceof SimpleLocation)) + return false; + return (className.equals(((SimpleLocation) other).className)); + } + + @Override + public int hashCode() { + return className.hashCode(); + } + + @Override + public String toString() { + return className; + } + + private String className; + } + + /** + * A dependency of one class on another. + */ + static class SimpleDependency implements Dependency { + public SimpleDependency(Location origin, Location target) { + this.origin = origin; + this.target = target; + } + + public Location getOrigin() { + return origin; + } + + public Location getTarget() { + return target; + } + + @Override + public boolean equals(Object other) { + if (this == other) + return true; + if (!(other instanceof SimpleDependency)) + return false; + SimpleDependency o = (SimpleDependency) other; + return (origin.equals(o.origin) && target.equals(o.target)); + } + + @Override + public int hashCode() { + return origin.hashCode() * 31 + target.hashCode(); + } + + @Override + public String toString() { + return origin + ":" + target; + } + + private Location origin; + private Location target; + } + + + /** + * This class accepts all dependencies. + */ + static class DefaultFilter implements Filter { + private static DefaultFilter instance; + + static DefaultFilter instance() { + if (instance == null) + instance = new DefaultFilter(); + return instance; + } + + public boolean accepts(Dependency dependency) { + return true; + } + } + + /** + * This class accepts those dependencies whose target's class name matches a + * regular expression. + */ + static class TargetRegexFilter implements Filter { + TargetRegexFilter(Pattern pattern) { + this.pattern = pattern; + } + + public boolean accepts(Dependency dependency) { + return pattern.matcher(dependency.getTarget().getClassName()).matches(); + } + + private final Pattern pattern; + } + + /** + * This class accepts those dependencies whose class name is in a given + * package. + */ + static class TargetPackageFilter implements Filter { + TargetPackageFilter(Set packageNames, boolean matchSubpackages) { + for (String pn: packageNames) { + if (pn.length() == 0) // implies null check as well + throw new IllegalArgumentException(); + } + this.packageNames = packageNames; + this.matchSubpackages = matchSubpackages; + } + + public boolean accepts(Dependency dependency) { + String cn = dependency.getTarget().getClassName(); + int lastSep = cn.lastIndexOf("/"); + String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep)); + if (packageNames.contains(pn)) + return true; + + if (matchSubpackages) { + for (String n: packageNames) { + if (pn.startsWith(n + ".")) + return true; + } + } + + return false; + } + + private final Set packageNames; + private final boolean matchSubpackages; + } + + + + /** + * This class identifies class names directly or indirectly in the constant pool. + */ + static class ClassDependencyFinder extends BasicDependencyFinder { + public Iterable findDependencies(ClassFile classfile) { + Visitor v = new Visitor(classfile); + for (CPInfo cpInfo: classfile.constant_pool.entries()) { + v.scan(cpInfo); + } + return v.deps; + } + } + + /** + * This class identifies class names in the signatures of classes, fields, + * and methods in a class. + */ + static class APIDependencyFinder extends BasicDependencyFinder { + APIDependencyFinder(int access) { + switch (access) { + case AccessFlags.ACC_PUBLIC: + case AccessFlags.ACC_PROTECTED: + case AccessFlags.ACC_PRIVATE: + case 0: + showAccess = access; + break; + default: + throw new IllegalArgumentException("invalid access 0x" + + Integer.toHexString(access)); + } + } + + public Iterable findDependencies(ClassFile classfile) { + try { + Visitor v = new Visitor(classfile); + v.addClass(classfile.super_class); + v.addClasses(classfile.interfaces); + // inner classes? + for (Field f : classfile.fields) { + if (checkAccess(f.access_flags)) + v.scan(f.descriptor, f.attributes); + } + for (Method m : classfile.methods) { + if (checkAccess(m.access_flags)) { + v.scan(m.descriptor, m.attributes); + Exceptions_attribute e = + (Exceptions_attribute) m.attributes.get(Attribute.Exceptions); + if (e != null) + v.addClasses(e.exception_index_table); + } + } + return v.deps; + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + boolean checkAccess(AccessFlags flags) { + // code copied from javap.Options.checkAccess + boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC); + boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED); + boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE); + boolean isPackage = !(isPublic || isProtected || isPrivate); + + if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage)) + return false; + else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage)) + return false; + else if ((showAccess == 0) && (isPrivate)) + return false; + else + return true; + } + + private int showAccess; + } + + static abstract class BasicDependencyFinder implements Finder { + private Map locations = new HashMap(); + + Location getLocation(String className) { + Location l = locations.get(className); + if (l == null) + locations.put(className, l = new SimpleLocation(className)); + return l; + } + + class Visitor implements ConstantPool.Visitor, Type.Visitor { + private ConstantPool constant_pool; + private Location origin; + Set deps; + + Visitor(ClassFile classFile) { + try { + constant_pool = classFile.constant_pool; + origin = getLocation(classFile.getName()); + deps = new HashSet(); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + void scan(Descriptor d, Attributes attrs) { + try { + scan(new Signature(d.index).getType(constant_pool)); + Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); + if (sa != null) + scan(new Signature(sa.signature_index).getType(constant_pool)); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + void scan(CPInfo cpInfo) { + cpInfo.accept(this, null); + } + + void scan(Type t) { + t.accept(this, null); + } + + void addClass(int index) throws ConstantPoolException { + if (index != 0) { + String name = constant_pool.getClassInfo(index).getBaseName(); + if (name != null) + addDependency(name); + } + } + + void addClasses(int[] indices) throws ConstantPoolException { + for (int i: indices) + addClass(i); + } + + private void addDependency(String name) { + deps.add(new SimpleDependency(origin, getLocation(name))); + } + + // ConstantPool.Visitor methods + + public Void visitClass(CONSTANT_Class_info info, Void p) { + try { + if (info.getName().startsWith("[")) + new Signature(info.name_index).getType(constant_pool).accept(this, null); + else + addDependency(info.getBaseName()); + return null; + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public Void visitDouble(CONSTANT_Double_info info, Void p) { + return null; + } + + public Void visitFieldref(CONSTANT_Fieldref_info info, Void p) { + return visitRef(info, p); + } + + public Void visitFloat(CONSTANT_Float_info info, Void p) { + return null; + } + + public Void visitInteger(CONSTANT_Integer_info info, Void p) { + return null; + } + + public Void visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return visitRef(info, p); + } + + public Void visitLong(CONSTANT_Long_info info, Void p) { + return null; + } + + public Void visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + try { + new Signature(info.type_index).getType(constant_pool).accept(this, null); + return null; + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public Void visitMethodref(CONSTANT_Methodref_info info, Void p) { + return visitRef(info, p); + } + + public Void visitString(CONSTANT_String_info info, Void p) { + return null; + } + + public Void visitUtf8(CONSTANT_Utf8_info info, Void p) { + return null; + } + + private Void visitRef(CPRefInfo info, Void p) { + try { + visitClass(info.getClassInfo(), p); + return null; + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + // Type.Visitor methods + + private void findDependencies(Type t) { + if (t != null) + t.accept(this, null); + } + + private void findDependencies(List ts) { + if (ts != null) { + for (Type t: ts) + t.accept(this, null); + } + } + + public Void visitSimpleType(SimpleType type, Void p) { + return null; + } + + public Void visitArrayType(ArrayType type, Void p) { + findDependencies(type.elemType); + return null; + } + + public Void visitMethodType(MethodType type, Void p) { + findDependencies(type.paramTypes); + findDependencies(type.returnType); + findDependencies(type.throwsTypes); + return null; + } + + public Void visitClassSigType(ClassSigType type, Void p) { + findDependencies(type.superclassType); + findDependencies(type.superinterfaceTypes); + return null; + } + + public Void visitClassType(ClassType type, Void p) { + findDependencies(type.outerType); + addDependency(type.name); + findDependencies(type.typeArgs); + return null; + } + + public Void visitTypeParamType(TypeParamType type, Void p) { + findDependencies(type.classBound); + findDependencies(type.interfaceBounds); + return null; + } + + public Void visitWildcardType(WildcardType type, Void p) { + findDependencies(type.boundType); + return null; + } + } + } +} diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java new file mode 100644 index 00000000000..bf09a7ca247 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java @@ -0,0 +1,90 @@ +/* + * 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; + + +/** + * A directed relationship between two {@link Dependency.Location Location}s. + * Subtypes of {@code Dependency} may provide additional detail about the dependency. + * + * @see Dependency.Finder + * @see Dependency.Filter + * @see Dependencies + */ +public interface Dependency { + /** + * A filter used to select dependencies of interest, and to discard others. + */ + public interface Filter { + /** + * Return true if the dependency is of interest. + * @param dependency the dependency to be considered + * @return true if and only if the dependency is of interest. + */ + boolean accepts(Dependency dependency); + } + + /** + * An interface for finding the immediate dependencies of a given class file. + */ + public interface Finder { + /** + * Find the immediate dependencies of a given class file. + * @param classfile the class file to be examined + * @return the dependencies located in the given class file. + */ + public Iterable findDependencies(ClassFile classfile); + } + + + /** + * A location somewhere within a class. Subtypes of {@code Location} + * may be used to provide additional detail about the location. + */ + public interface Location { + /** + * Get the name of the class containing the location. + * This name will be used to locate the class file for transitive + * dependency analysis. + * @return the name of the class containing the location. + */ + String getClassName(); + } + + + /** + * Get the location that has the dependency. + * @return the location that has the dependency. + */ + Location getOrigin(); + + /** + * Get the location that is being depended upon. + * @return the location that is being depended upon. + */ + Location getTarget(); +} + diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java index c0a30ba2755..6f0ab4c155a 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java @@ -106,9 +106,9 @@ public class Instruction { /** 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); + R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p); /** See {@link Kind#DYNAMIC}. */ - R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets); + R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p); /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ R visitValue(Instruction instr, int value, P p); /** Instruction is unrecognized. */ @@ -282,7 +282,7 @@ public class Instruction { for (int i = 0; i < values.length; i++) values[i] = getInt(pad + 12 + 4 * i); return visitor.visitTableSwitch( - this, default_, low, high, values); + this, default_, low, high, values, p); } case LOOKUPSWITCH: { int pad = align(pc + 1) - pc; @@ -295,7 +295,7 @@ public class Instruction { offsets[i] = getInt(pad + 12 + i * 8); } return visitor.visitLookupSwitch( - this, default_, npairs, matches, offsets); + this, default_, npairs, matches, offsets, p); } default: throw new IllegalStateException(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java index 6af5c889392..4809565d855 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java @@ -110,9 +110,6 @@ public enum Source { } /** Allow encoding errors, giving only warnings. */ - public boolean allowStringsInSwitch() { - return compareTo(JDK1_7) >= 0; - } public boolean allowEncodingErrors() { return compareTo(JDK1_6) < 0; } @@ -168,6 +165,9 @@ public enum Source { public boolean allowUnderscoresInLiterals() { return compareTo(JDK1_7) >= 0; } + public boolean allowStringsInSwitch() { + return compareTo(JDK1_7) >= 0; + } public static SourceVersion toSourceVersion(Source source) { switch(source) { case JDK1_2: 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 fa03454970d..f2983724122 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 @@ -3117,7 +3117,6 @@ public class Lower extends TreeTranslator { tree.cases = translateCases(tree.cases); if (enumSwitch) { result = visitEnumSwitch(tree); - patchTargets(result, tree, result); } else if (stringSwitch) { result = visitStringSwitch(tree); } else { @@ -3146,7 +3145,9 @@ public class Lower extends TreeTranslator { cases.append(c); } } - return make.Switch(selector, cases.toList()); + JCSwitch enumSwitch = make.Switch(selector, cases.toList()); + patchTargets(enumSwitch, tree, enumSwitch); + return enumSwitch; } public JCTree visitStringSwitch(JCSwitch tree) { @@ -3187,7 +3188,14 @@ public class Lower extends TreeTranslator { * of String is the same in the compilation environment as * in the environment the code will run in. The string * hashing algorithm in the SE JDK has been unchanged - * since at least JDK 1.2. + * since at least JDK 1.2. Since the algorithm has been + * specified since that release as well, it is very + * unlikely to be changed in the future. + * + * Different hashing algorithms, such as the length of the + * strings or a perfect hashing algorithm over the + * particular set of case labels, could potentially be + * used instead of String.hashCode. */ ListBuffer stmtList = new ListBuffer(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java index 6435e05a04c..9666f1cee7e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java @@ -39,6 +39,8 @@ import javax.tools.JavaFileObject; import static javax.tools.JavaFileObject.Kind.*; +import com.sun.tools.javac.util.BaseFileManager; + /** *

    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. @@ -74,14 +76,7 @@ public abstract class BaseFileObject implements JavaFileObject { protected abstract String inferBinaryName(Iterable path); protected static JavaFileObject.Kind getKind(String filename) { - if (filename.endsWith(CLASS.extension)) - return CLASS; - else if (filename.endsWith(SOURCE.extension)) - return SOURCE; - else if (filename.endsWith(HTML.extension)) - return HTML; - else - return OTHER; + return BaseFileManager.getKind(filename); } protected static String removeExtension(String fileName) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java index 23f169b5392..661f89eb717 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java @@ -26,29 +26,16 @@ package com.sun.tools.javac.file; import java.io.ByteArrayOutputStream; -import java.io.Closeable; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStreamWriter; -import java.lang.ref.SoftReference; -import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.URLClassLoader; -import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.nio.channels.FileChannel; import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -66,18 +53,13 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; -import com.sun.tools.javac.code.Source; import com.sun.tools.javac.file.RelativePath.RelativeFile; import com.sun.tools.javac.file.RelativePath.RelativeDirectory; -import com.sun.tools.javac.main.JavacOption; import com.sun.tools.javac.main.OptionName; -import com.sun.tools.javac.main.RecognizedOptions; +import com.sun.tools.javac.util.BaseFileManager; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Options; import static javax.tools.StandardLocation.*; import static com.sun.tools.javac.main.OptionName.*; @@ -91,7 +73,7 @@ import static com.sun.tools.javac.main.OptionName.*; * This code and its internal interfaces are subject to change or * deletion without notice. */ -public class JavacFileManager implements StandardJavaFileManager { +public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager { boolean useZipFileIndex; @@ -102,17 +84,10 @@ public class JavacFileManager implements StandardJavaFileManager { return buffer.toString().toCharArray(); } - /** - * The log to be used for error reporting. - */ - protected Log log; - /** Encapsulates knowledge of paths */ private Paths paths; - private Options options; - private FSInfo fsInfo; private final File uninited = new File("U N I N I T E D"); @@ -134,12 +109,6 @@ public class JavacFileManager implements StandardJavaFileManager { protected boolean mmappedIO; protected boolean ignoreSymbolFile; - protected String classLoaderClass; - - /** - * User provided charset (through javax.tools). - */ - protected Charset charset; /** * Register a Context.Factory to create a JavacFileManager. @@ -157,18 +126,18 @@ public class JavacFileManager implements StandardJavaFileManager { * it as the JavaFileManager for that context. */ public JavacFileManager(Context context, boolean register, Charset charset) { + super(charset); if (register) context.put(JavaFileManager.class, this); - byteBufferCache = new ByteBufferCache(); - this.charset = charset; setContext(context); } /** * Set the context for JavacFileManager. */ + @Override public void setContext(Context context) { - log = Log.instance(context); + super.setContext(context); if (paths == null) { paths = Paths.instance(context); } else { @@ -177,14 +146,12 @@ public class JavacFileManager implements StandardJavaFileManager { paths.setContext(context); } - options = Options.instance(context); fsInfo = FSInfo.instance(context); useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null; mmappedIO = options.get("mmappedIO") != null; ignoreSymbolFile = options.get("ignore.symbol.file") != null; - classLoaderClass = options.get("procloader"); } public JavaFileObject getFileForInput(String name) { @@ -214,17 +181,6 @@ public class JavacFileManager implements StandardJavaFileManager { return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names))); } - protected JavaFileObject.Kind getKind(String extension) { - if (extension.equals(JavaFileObject.Kind.CLASS.extension)) - return JavaFileObject.Kind.CLASS; - else if (extension.equals(JavaFileObject.Kind.SOURCE.extension)) - return JavaFileObject.Kind.SOURCE; - else if (extension.equals(JavaFileObject.Kind.HTML.extension)) - return JavaFileObject.Kind.HTML; - else - return JavaFileObject.Kind.OTHER; - } - private static boolean isValidName(String name) { // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ), // but the set of keywords depends on the source level, and we don't want @@ -359,9 +315,7 @@ public class JavacFileManager implements StandardJavaFileManager { } private boolean isValidFile(String s, Set fileKinds) { - int lastDot = s.lastIndexOf("."); - String extn = (lastDot == -1 ? s : s.substring(lastDot)); - JavaFileObject.Kind kind = getKind(extn); + JavaFileObject.Kind kind = getKind(s); return fileKinds.contains(kind); } @@ -564,18 +518,6 @@ public class JavacFileManager implements StandardJavaFileManager { } } - CharBuffer getCachedContent(JavaFileObject file) { - SoftReference r = contentCache.get(file); - return (r == null ? null : r.get()); - } - - void cache(JavaFileObject file, CharBuffer cb) { - contentCache.put(file, new SoftReference(cb)); - } - - private final Map> contentCache - = new HashMap>(); - private String defaultEncodingName; private String getDefaultEncodingName() { if (defaultEncodingName == null) { @@ -585,161 +527,6 @@ public class JavacFileManager implements StandardJavaFileManager { return defaultEncodingName; } - protected String getEncodingName() { - String encName = options.get(OptionName.ENCODING); - if (encName == null) - return getDefaultEncodingName(); - else - return encName; - } - - protected Source getSource() { - String sourceName = options.get(OptionName.SOURCE); - Source source = null; - if (sourceName != null) - source = Source.lookup(sourceName); - return (source != null ? source : Source.DEFAULT); - } - - /** - * Make a byte buffer from an input stream. - */ - ByteBuffer makeByteBuffer(InputStream in) - throws IOException { - int limit = in.available(); - if (mmappedIO && in instanceof FileInputStream) { - // Experimental memory mapped I/O - FileInputStream fin = (FileInputStream)in; - return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit); - } - if (limit < 1024) limit = 1024; - ByteBuffer result = byteBufferCache.get(limit); - int position = 0; - while (in.available() != 0) { - if (position >= limit) - // expand buffer - result = ByteBuffer. - allocate(limit <<= 1). - put((ByteBuffer)result.flip()); - int count = in.read(result.array(), - position, - limit - position); - if (count < 0) break; - result.position(position += count); - } - return (ByteBuffer)result.flip(); - } - - void recycleByteBuffer(ByteBuffer bb) { - byteBufferCache.put(bb); - } - - /** - * A single-element cache of direct byte buffers. - */ - private static class ByteBufferCache { - private ByteBuffer cached; - ByteBuffer get(int capacity) { - if (capacity < 20480) capacity = 20480; - ByteBuffer result = - (cached != null && cached.capacity() >= capacity) - ? (ByteBuffer)cached.clear() - : ByteBuffer.allocate(capacity + capacity>>1); - cached = null; - return result; - } - void put(ByteBuffer x) { - cached = x; - } - } - - private final ByteBufferCache byteBufferCache; - - CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) { - Charset cs = (this.charset == null) - ? Charset.forName(encodingName) - : this.charset; - CharsetDecoder decoder = cs.newDecoder(); - - CodingErrorAction action; - if (ignoreEncodingErrors) - action = CodingErrorAction.REPLACE; - else - action = CodingErrorAction.REPORT; - - return decoder - .onMalformedInput(action) - .onUnmappableCharacter(action); - } - - /** - * Decode a ByteBuffer into a CharBuffer. - */ - CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) { - String encodingName = getEncodingName(); - CharsetDecoder decoder; - try { - decoder = getDecoder(encodingName, ignoreEncodingErrors); - } catch (IllegalCharsetNameException e) { - log.error("unsupported.encoding", encodingName); - return (CharBuffer)CharBuffer.allocate(1).flip(); - } catch (UnsupportedCharsetException e) { - log.error("unsupported.encoding", encodingName); - return (CharBuffer)CharBuffer.allocate(1).flip(); - } - - // slightly overestimate the buffer size to avoid reallocation. - float factor = - decoder.averageCharsPerByte() * 0.8f + - decoder.maxCharsPerByte() * 0.2f; - CharBuffer dest = CharBuffer. - allocate(10 + (int)(inbuf.remaining()*factor)); - - while (true) { - CoderResult result = decoder.decode(inbuf, dest, true); - dest.flip(); - - if (result.isUnderflow()) { // done reading - // make sure there is at least one extra character - if (dest.limit() == dest.capacity()) { - dest = CharBuffer.allocate(dest.capacity()+1).put(dest); - dest.flip(); - } - return dest; - } else if (result.isOverflow()) { // buffer too small; expand - int newCapacity = - 10 + dest.capacity() + - (int)(inbuf.remaining()*decoder.maxCharsPerByte()); - dest = CharBuffer.allocate(newCapacity).put(dest); - } else if (result.isMalformed() || result.isUnmappable()) { - // bad character in input - - // report coding error (warn only pre 1.5) - if (!getSource().allowEncodingErrors()) { - log.error(new SimpleDiagnosticPosition(dest.limit()), - "illegal.char.for.encoding", - charset == null ? encodingName : charset.name()); - } else { - log.warning(new SimpleDiagnosticPosition(dest.limit()), - "illegal.char.for.encoding", - charset == null ? encodingName : charset.name()); - } - - // skip past the coding error - inbuf.position(inbuf.position() + result.length()); - - // undo the flip() to prepare the output buffer - // for more translation - dest.position(dest.limit()); - dest.limit(dest.capacity()); - dest.put((char)0xfffd); // backward compatible - } else { - throw new AssertionError(result); - } - } - // unreached - } - public ClassLoader getClassLoader(Location location) { nullCheck(location); Iterable path = getLocation(location); @@ -754,39 +541,7 @@ public class JavacFileManager implements StandardJavaFileManager { } } - URL[] urls = lb.toArray(new URL[lb.size()]); - ClassLoader thisClassLoader = getClass().getClassLoader(); - - // Bug: 6558476 - // Ideally, ClassLoader should be Closeable, but before JDK7 it is not. - // On older versions, try the following, to get a closeable classloader. - - // 1: Allow client to specify the class to use via hidden option - if (classLoaderClass != null) { - try { - Class loader = - Class.forName(classLoaderClass).asSubclass(ClassLoader.class); - Class[] constrArgTypes = { URL[].class, ClassLoader.class }; - Constructor constr = loader.getConstructor(constrArgTypes); - return constr.newInstance(new Object[] { urls, thisClassLoader }); - } catch (Throwable t) { - // ignore errors loading user-provided class loader, fall through - } - } - - // 2: If URLClassLoader implements Closeable, use that. - if (Closeable.class.isAssignableFrom(URLClassLoader.class)) - return new URLClassLoader(urls, thisClassLoader); - - // 3: Try using private reflection-based CloseableURLClassLoader - try { - return new CloseableURLClassLoader(urls, thisClassLoader); - } catch (Throwable t) { - // ignore errors loading workaround class loader, fall through - } - - // 4: If all else fails, use plain old standard URLClassLoader - return new URLClassLoader(urls, thisClassLoader); + return getClassLoader(lb.toArray(new URL[lb.size()])); } public Iterable list(Location location, @@ -836,38 +591,6 @@ public class JavacFileManager implements StandardJavaFileManager { return a.equals(b); } - public boolean handleOption(String current, Iterator remaining) { - for (JavacOption o: javacFileManagerOptions) { - if (o.matches(current)) { - if (o.hasArg()) { - if (remaining.hasNext()) { - if (!o.process(options, current, remaining.next())) - return true; - } - } else { - if (!o.process(options, current)) - return true; - } - // operand missing, or process returned false - throw new IllegalArgumentException(current); - } - } - - return false; - } - // where - private static JavacOption[] javacFileManagerOptions = - RecognizedOptions.getJavacFileManagerOptions( - new RecognizedOptions.GrumpyHelper()); - - public int isSupportedOption(String option) { - for (JavacOption o : javacFileManagerOptions) { - if (o.matches(option)) - return o.hasArg() ? 1 : 0; - } - return -1; - } - public boolean hasLocation(Location location) { return getLocation(location) != null; } @@ -1115,15 +838,4 @@ public class JavacFileManager implements StandardJavaFileManager { } throw new IllegalArgumentException("Invalid relative path: " + file); } - - private static T nullCheck(T o) { - o.getClass(); // null check - return o; - } - - private static Iterable nullCheck(Iterable it) { - for (T t : it) - t.getClass(); // null check - return it; - } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java index 6457b8107a5..c4dc9bb2301 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java @@ -66,7 +66,7 @@ public class Paths { * @param context the context * @return the Paths instance for this context */ - static Paths instance(Context context) { + public static Paths instance(Context context) { Paths instance = context.get(pathsKey); if (instance == null) instance = new Paths(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java index 6ea261c0fe0..7aa983c6691 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java @@ -1002,7 +1002,7 @@ public class ZipFileIndex { // Do nothing } finally { try { - if (raf == null) { + if (raf != null) { raf.close(); } } catch (Throwable t) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java index 2b8a915cf01..952ba5baf52 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java @@ -130,7 +130,7 @@ public interface JavacOption { private static Map createChoices(String... choices) { Map map = new LinkedHashMap(); for (String c: choices) - map.put(c, true); + map.put(c, false); return map; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java new file mode 100644 index 00000000000..6202b37d3b9 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java @@ -0,0 +1,543 @@ +/* + * 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.nio; + + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.Attributes; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import javax.lang.model.SourceVersion; +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardLocation; + +import static java.nio.file.FileVisitOption.*; +import static javax.tools.StandardLocation.*; + +import com.sun.tools.javac.file.Paths; +import com.sun.tools.javac.util.BaseFileManager; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; + +import static com.sun.tools.javac.main.OptionName.*; + + +// NOTE the imports carefully for this compilation unit. +// +// Path: java.nio.file.Path -- the new NIO type for which this file manager exists +// +// Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options +// The other Paths (java.nio.file.Paths) is not used + +// NOTE this and related classes depend on new API in JDK 7. +// This requires special handling while bootstrapping the JDK build, +// when these classes might not yet have been compiled. To workaround +// this, the build arranges to make stubs of these classes available +// when compiling this and related classes. The set of stub files +// is specified in make/build.properties. + +/** + * Implementation of PathFileManager: a JavaFileManager based on the use + * of java.nio.file.Path. + * + *

    Just as a Path is somewhat analagous to a File, so too is this + * JavacPathFileManager analogous to JavacFileManager, as it relates to the + * support of FileObjects based on File objects (i.e. just RegularFileObject, + * not ZipFileObject and its variants.) + * + *

    The default values for the standard locations supported by this file + * manager are the same as the default values provided by JavacFileManager -- + * i.e. as determined by the javac.file.Paths class. To override these values, + * call {@link #setLocation}. + * + *

    To reduce confusion with Path objects, the locations such as "class path", + * "source path", etc, are generically referred to here as "search paths". + * + *

    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. + */ +public class JavacPathFileManager extends BaseFileManager implements PathFileManager { + protected FileSystem defaultFileSystem; + + /** + * Create a JavacPathFileManager using a given context, optionally registering + * it as the JavaFileManager for that context. + */ + public JavacPathFileManager(Context context, boolean register, Charset charset) { + super(charset); + if (register) + context.put(JavaFileManager.class, this); + pathsForLocation = new HashMap(); + fileSystems = new HashMap(); + setContext(context); + } + + /** + * Set the context for JavacPathFileManager. + */ + @Override + protected void setContext(Context context) { + super.setContext(context); + searchPaths = Paths.instance(context); + } + + @Override + public FileSystem getDefaultFileSystem() { + if (defaultFileSystem == null) + defaultFileSystem = FileSystems.getDefault(); + return defaultFileSystem; + } + + @Override + public void setDefaultFileSystem(FileSystem fs) { + defaultFileSystem = fs; + } + + @Override + public void flush() throws IOException { + contentCache.clear(); + } + + @Override + public void close() throws IOException { + for (FileSystem fs: fileSystems.values()) + fs.close(); + } + + @Override + public ClassLoader getClassLoader(Location location) { + nullCheck(location); + Iterable path = getLocation(location); + if (path == null) + return null; + ListBuffer lb = new ListBuffer(); + for (Path p: path) { + try { + lb.append(p.toUri().toURL()); + } catch (MalformedURLException e) { + throw new AssertionError(e); + } + } + + return getClassLoader(lb.toArray(new URL[lb.size()])); + } + + // + + public boolean hasLocation(Location location) { + return (getLocation(location) != null); + } + + public Iterable getLocation(Location location) { + nullCheck(location); + lazyInitSearchPaths(); + PathsForLocation path = pathsForLocation.get(location); + if (path == null && !pathsForLocation.containsKey(location)) { + setDefaultForLocation(location); + path = pathsForLocation.get(location); + } + return path; + } + + private Path getOutputLocation(Location location) { + Iterable paths = getLocation(location); + return (paths == null ? null : paths.iterator().next()); + } + + public void setLocation(Location location, Iterable searchPath) + throws IOException + { + nullCheck(location); + lazyInitSearchPaths(); + if (searchPath == null) { + setDefaultForLocation(location); + } else { + if (location.isOutputLocation()) + checkOutputPath(searchPath); + PathsForLocation pl = new PathsForLocation(); + for (Path p: searchPath) + pl.add(p); // TODO -Xlint:path warn if path not found + pathsForLocation.put(location, pl); + } + } + + private void checkOutputPath(Iterable searchPath) throws IOException { + Iterator pathIter = searchPath.iterator(); + if (!pathIter.hasNext()) + throw new IllegalArgumentException("empty path for directory"); + Path path = pathIter.next(); + if (pathIter.hasNext()) + throw new IllegalArgumentException("path too long for directory"); + if (!path.exists()) + throw new FileNotFoundException(path + ": does not exist"); + else if (!isDirectory(path)) + throw new IOException(path + ": not a directory"); + } + + private void setDefaultForLocation(Location locn) { + Collection files = null; + if (locn instanceof StandardLocation) { + switch ((StandardLocation) locn) { + case CLASS_PATH: + files = searchPaths.userClassPath(); + break; + case PLATFORM_CLASS_PATH: + files = searchPaths.bootClassPath(); + break; + case SOURCE_PATH: + files = searchPaths.sourcePath(); + break; + case CLASS_OUTPUT: { + String arg = options.get(D); + files = (arg == null ? null : Collections.singleton(new File(arg))); + break; + } + case SOURCE_OUTPUT: { + String arg = options.get(S); + files = (arg == null ? null : Collections.singleton(new File(arg))); + break; + } + } + } + + PathsForLocation pl = new PathsForLocation(); + if (files != null) { + for (File f: files) + pl.add(f.toPath()); + } + pathsForLocation.put(locn, pl); + } + + private void lazyInitSearchPaths() { + if (!inited) { + setDefaultForLocation(PLATFORM_CLASS_PATH); + setDefaultForLocation(CLASS_PATH); + setDefaultForLocation(SOURCE_PATH); + inited = true; + } + } + // where + private boolean inited = false; + + private Map pathsForLocation; + private Paths searchPaths; + + private static class PathsForLocation extends LinkedHashSet { + private static final long serialVersionUID = 6788510222394486733L; + } + + // + + // + + @Override + public Path getPath(FileObject fo) { + nullCheck(fo); + if (!(fo instanceof PathFileObject)) + throw new IllegalArgumentException(); + return ((PathFileObject) fo).getPath(); + } + + @Override + public boolean isSameFile(FileObject a, FileObject b) { + nullCheck(a); + nullCheck(b); + if (!(a instanceof PathFileObject)) + throw new IllegalArgumentException("Not supported: " + a); + if (!(b instanceof PathFileObject)) + throw new IllegalArgumentException("Not supported: " + b); + return ((PathFileObject) a).isSameFile((PathFileObject) b); + } + + @Override + public Iterable list(Location location, + String packageName, Set kinds, boolean recurse) + throws IOException { + // validatePackageName(packageName); + nullCheck(packageName); + nullCheck(kinds); + + Iterable paths = getLocation(location); + if (paths == null) + return List.nil(); + ListBuffer results = new ListBuffer(); + + for (Path path : paths) + list(path, packageName, kinds, recurse, results); + + return results.toList(); + } + + private void list(Path path, String packageName, final Set kinds, + boolean recurse, final ListBuffer results) + throws IOException { + if (!path.exists()) + return; + + final Path pathDir; + if (isDirectory(path)) + pathDir = path; + else { + FileSystem fs = getFileSystem(path); + if (fs == null) + return; + pathDir = fs.getRootDirectories().iterator().next(); + } + String sep = path.getFileSystem().getSeparator(); + Path packageDir = packageName.isEmpty() ? pathDir + : pathDir.resolve(packageName.replace(".", sep)); + if (!packageDir.exists()) + return; + +/* Alternate impl of list, superceded by use of Files.walkFileTree */ +// Deque queue = new LinkedList(); +// queue.add(packageDir); +// +// Path dir; +// while ((dir = queue.poll()) != null) { +// DirectoryStream ds = dir.newDirectoryStream(); +// try { +// for (Path p: ds) { +// String name = p.getName().toString(); +// if (isDirectory(p)) { +// if (recurse && SourceVersion.isIdentifier(name)) { +// queue.add(p); +// } +// } else { +// if (kinds.contains(getKind(name))) { +// JavaFileObject fe = +// PathFileObject.createDirectoryPathFileObject(this, p, pathDir); +// results.append(fe); +// } +// } +// } +// } finally { +// ds.close(); +// } +// } + int maxDepth = (recurse ? Integer.MAX_VALUE : 1); + Set opts = EnumSet.of(DETECT_CYCLES, FOLLOW_LINKS); + Files.walkFileTree(packageDir, opts, maxDepth, + new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir) { + if (SourceVersion.isIdentifier(dir.getName().toString())) // JSR 292? + return FileVisitResult.CONTINUE; + else + return FileVisitResult.SKIP_SUBTREE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (attrs.isRegularFile() && kinds.contains(getKind(file.getName().toString()))) { + JavaFileObject fe = + PathFileObject.createDirectoryPathFileObject( + JavacPathFileManager.this, file, pathDir); + results.append(fe); + } + return FileVisitResult.CONTINUE; + } + }); + } + + @Override + public Iterable getJavaFileObjectsFromPaths( + Iterable paths) { + ArrayList result; + if (paths instanceof Collection) + result = new ArrayList(((Collection)paths).size()); + else + result = new ArrayList(); + for (Path p: paths) + result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p))); + return result; + } + + @Override + public Iterable getJavaFileObjects(Path... paths) { + return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths))); + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, + String className, Kind kind) throws IOException { + return getFileForInput(location, getRelativePath(className, kind)); + } + + @Override + public FileObject getFileForInput(Location location, + String packageName, String relativeName) throws IOException { + return getFileForInput(location, getRelativePath(packageName, relativeName)); + } + + private JavaFileObject getFileForInput(Location location, String relativePath) + throws IOException { + for (Path p: getLocation(location)) { + if (isDirectory(p)) { + Path f = resolve(p, relativePath); + if (f.exists()) + return PathFileObject.createDirectoryPathFileObject(this, f, p); + } else { + FileSystem fs = getFileSystem(p); + if (fs != null) { + Path file = getPath(fs, relativePath); + if (file.exists()) + return PathFileObject.createJarPathFileObject(this, file); + } + } + } + return null; + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, + String className, Kind kind, FileObject sibling) throws IOException { + return getFileForOutput(location, getRelativePath(className, kind), sibling); + } + + @Override + public FileObject getFileForOutput(Location location, String packageName, + String relativeName, FileObject sibling) + throws IOException { + return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling); + } + + private JavaFileObject getFileForOutput(Location location, + String relativePath, FileObject sibling) { + Path dir = getOutputLocation(location); + if (dir == null) { + if (location == CLASS_OUTPUT) { + Path siblingDir = null; + if (sibling != null && sibling instanceof PathFileObject) { + siblingDir = ((PathFileObject) sibling).getPath().getParent(); + } + return PathFileObject.createSiblingPathFileObject(this, + siblingDir.resolve(getBaseName(relativePath)), + relativePath); + } else if (location == SOURCE_OUTPUT) { + dir = getOutputLocation(CLASS_OUTPUT); + } + } + + Path file; + if (dir != null) { + file = resolve(dir, relativePath); + return PathFileObject.createDirectoryPathFileObject(this, file, dir); + } else { + file = getPath(getDefaultFileSystem(), relativePath); + return PathFileObject.createSimplePathFileObject(this, file); + } + + } + + @Override + public String inferBinaryName(Location location, JavaFileObject fo) { + nullCheck(fo); + // Need to match the path semantics of list(location, ...) + Iterable paths = getLocation(location); + if (paths == null) { + return null; + } + + if (!(fo instanceof PathFileObject)) + throw new IllegalArgumentException(fo.getClass().getName()); + + return ((PathFileObject) fo).inferBinaryName(paths); + } + + private FileSystem getFileSystem(Path p) throws IOException { + FileSystem fs = fileSystems.get(p); + if (fs == null) { + fs = FileSystems.newFileSystem(p, Collections.emptyMap(), null); + fileSystems.put(p, fs); + } + return fs; + } + + private Map fileSystems; + + // + + // + + private static String getRelativePath(String className, Kind kind) { + return className.replace(".", "/") + kind.extension; + } + + private static String getRelativePath(String packageName, String relativeName) { + return packageName.replace(".", "/") + relativeName; + } + + private static String getBaseName(String relativePath) { + int lastSep = relativePath.lastIndexOf("/"); + return relativePath.substring(lastSep + 1); // safe if "/" not found + } + + private static boolean isDirectory(Path path) throws IOException { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path); + return attrs.isDirectory(); + } + + private static Path getPath(FileSystem fs, String relativePath) { + return fs.getPath(relativePath.replace("/", fs.getSeparator())); + } + + private static Path resolve(Path base, String relativePath) { + FileSystem fs = base.getFileSystem(); + Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator())); + return base.resolve(rp); + } + + // + +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java new file mode 100644 index 00000000000..0b55e6859ba --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java @@ -0,0 +1,125 @@ +/* + * 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.nio; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; + +/** + * File manager based on {@linkplain File java.nio.file.Path}. + * + * Eventually, this should be moved to javax.tools. + * Also, JavaCompiler might reasonably provide a method getPathFileManager, + * similar to {@link javax.tools.JavaCompiler#getStandardFileManager + * getStandardFileManager}. However, would need to be handled carefully + * as another forward reference from langtools to jdk. + * + *

    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. + */ +public interface PathFileManager extends JavaFileManager { + /** + * Get the default file system used to create paths. If no value has been + * set, the default file system is {@link FileSystems#getDefault}. + */ + FileSystem getDefaultFileSystem(); + + /** + * Set the default file system used to create paths. + * @param fs the default file system used to create any new paths. + */ + void setDefaultFileSystem(FileSystem fs); + + /** + * Get file objects representing the given files. + * + * @param paths a list of paths + * @return a list of file objects + * @throws IllegalArgumentException if the list of paths includes + * a directory + */ + Iterable getJavaFileObjectsFromPaths( + Iterable paths); + + /** + * Get file objects representing the given paths. + * Convenience method equivalent to: + * + *

    +     *     getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
    +     * 
    + * + * @param paths an array of paths + * @return a list of file objects + * @throws IllegalArgumentException if the array of files includes + * a directory + * @throws NullPointerException if the given array contains null + * elements + */ + Iterable getJavaFileObjects(Path... paths); + + /** + * Return the Path for a file object that has been obtained from this + * file manager. + * + * @param fo A file object that has been obtained from this file manager. + * @return The underlying Path object. + * @throws IllegalArgumentException is the file object was not obtained from + * from this file manager. + */ + Path getPath(FileObject fo); + + /** + * Get the search path associated with the given location. + * + * @param location a location + * @return a list of paths or {@code null} if this location has no + * associated search path + * @see #setLocation + */ + Iterable getLocation(Location location); + + /** + * Associate the given search path with the given location. Any + * previous value will be discarded. + * + * @param location a location + * @param searchPath a list of files, if {@code null} use the default + * search path for this location + * @see #getLocation + * @throws IllegalArgumentException if location is an output + * location and searchpath does not contain exactly one element + * @throws IOException if location is an output location and searchpath + * does not represent an existing directory + */ + void setLocation(Location location, Iterable searchPath) throws IOException; +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java new file mode 100644 index 00000000000..dc22ff3d978 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java @@ -0,0 +1,319 @@ +/* + * 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.nio; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetDecoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.Attributes; +import java.nio.file.attribute.BasicFileAttributes; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.util.BaseFileManager; + + +/** + * Implementation of JavaFileObject using java.nio.file API. + * + *

    PathFileObjects are, for the most part, straightforward wrappers around + * Path objects. The primary complexity is the support for "inferBinaryName". + * This is left as an abstract method, implemented by each of a number of + * different factory methods, which compute the binary name based on + * information available at the time the file object is created. + * + *

    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. + */ +abstract class PathFileObject implements JavaFileObject { + private JavacPathFileManager fileManager; + private Path path; + + /** + * Create a PathFileObject within a directory, such that the binary name + * can be inferred from the relationship to the parent directory. + */ + static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager, + final Path path, final Path dir) { + return new PathFileObject(fileManager, path) { + @Override + String inferBinaryName(Iterable paths) { + return toBinaryName(dir.relativize(path)); + } + }; + } + + /** + * Create a PathFileObject in a file system such as a jar file, such that + * the binary name can be inferred from its position within the filesystem. + */ + static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager, + final Path path) { + return new PathFileObject(fileManager, path) { + @Override + String inferBinaryName(Iterable paths) { + return toBinaryName(path); + } + }; + } + + /** + * Create a PathFileObject whose binary name can be inferred from the + * relative path to a sibling. + */ + static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager, + final Path path, final String relativePath) { + return new PathFileObject(fileManager, path) { + @Override + String inferBinaryName(Iterable paths) { + return toBinaryName(relativePath, "/"); + } + }; + } + + /** + * Create a PathFileObject whose binary name might be inferred from its + * position on a search path. + */ + static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager, + final Path path) { + return new PathFileObject(fileManager, path) { + @Override + String inferBinaryName(Iterable paths) { + Path absPath = path.toAbsolutePath(); + for (Path p: paths) { + Path ap = p.toAbsolutePath(); + if (absPath.startsWith(ap)) { + try { + Path rp = ap.relativize(absPath); + if (rp != null) // maybe null if absPath same as ap + return toBinaryName(rp); + } catch (IllegalArgumentException e) { + // ignore this p if cannot relativize path to p + } + } + } + return null; + } + }; + } + + protected PathFileObject(JavacPathFileManager fileManager, Path path) { + fileManager.getClass(); // null check + path.getClass(); // null check + this.fileManager = fileManager; + this.path = path; + } + + abstract String inferBinaryName(Iterable paths); + + /** + * Return the Path for this object. + * @return the Path for this object. + */ + Path getPath() { + return path; + } + + @Override + public Kind getKind() { + return BaseFileManager.getKind(path.getName().toString()); + } + + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + simpleName.getClass(); + // null check + if (kind == Kind.OTHER && getKind() != kind) { + return false; + } + String sn = simpleName + kind.extension; + String pn = path.getName().toString(); + if (pn.equals(sn)) { + return true; + } + if (pn.equalsIgnoreCase(sn)) { + try { + // allow for Windows + return path.toRealPath(false).getName().toString().equals(sn); + } catch (IOException e) { + } + } + return false; + } + + @Override + public NestingKind getNestingKind() { + return null; + } + + @Override + public Modifier getAccessLevel() { + return null; + } + + @Override + public URI toUri() { + return path.toUri(); + } + + @Override + public String getName() { + return path.toString(); + } + + @Override + public InputStream openInputStream() throws IOException { + return path.newInputStream(); + } + + @Override + public OutputStream openOutputStream() throws IOException { + ensureParentDirectoriesExist(); + return path.newOutputStream(); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors); + return new InputStreamReader(openInputStream(), decoder); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + CharBuffer cb = fileManager.getCachedContent(this); + if (cb == null) { + InputStream in = openInputStream(); + try { + ByteBuffer bb = fileManager.makeByteBuffer(in); + JavaFileObject prev = fileManager.log.useSource(this); + try { + cb = fileManager.decode(bb, ignoreEncodingErrors); + } finally { + fileManager.log.useSource(prev); + } + fileManager.recycleByteBuffer(bb); + if (!ignoreEncodingErrors) { + fileManager.cache(this, cb); + } + } finally { + in.close(); + } + } + return cb; + } + + @Override + public Writer openWriter() throws IOException { + ensureParentDirectoriesExist(); + return new OutputStreamWriter(path.newOutputStream(), fileManager.getEncodingName()); + } + + @Override + public long getLastModified() { + try { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path); + return attrs.lastModifiedTime().toMillis(); + } catch (IOException e) { + return -1; + } + } + + @Override + public boolean delete() { + try { + path.delete(); + return true; + } catch (IOException e) { + return false; + } + } + + public boolean isSameFile(PathFileObject other) { + try { + return path.isSameFile(other.path); + } catch (IOException e) { + return false; + } + } + + @Override + public boolean equals(Object other) { + return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path)); + } + + @Override + public int hashCode() { + return path.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + path + "]"; + } + + private void ensureParentDirectoriesExist() throws IOException { + Path parent = path.getParent(); + if (parent != null) + Files.createDirectories(parent); + } + + private long size() { + try { + BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path); + return attrs.size(); + } catch (IOException e) { + return -1; + } + } + + protected static String toBinaryName(Path relativePath) { + return toBinaryName(relativePath.toString(), + relativePath.getFileSystem().getSeparator()); + } + + protected static String toBinaryName(String relativePath, String sep) { + return removeExtension(relativePath).replace(sep, "."); + } + + protected static String removeExtension(String fileName) { + int lastDot = fileName.lastIndexOf("."); + return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); + } +} 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 c84f2097c45..bf3aeb6ef6d 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 @@ -2613,12 +2613,12 @@ public class JavacParser implements Parser { body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); } if (args.isEmpty() && body == null) - createPos = Position.NOPOS; - JCIdent ident = F.at(Position.NOPOS).Ident(enumName); + createPos = identPos; + JCIdent ident = F.at(identPos).Ident(enumName); JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body); - if (createPos != Position.NOPOS) + if (createPos != identPos) storeEnd(create, S.prevEndPos()); - ident = F.at(Position.NOPOS).Ident(enumName); + ident = F.at(identPos).Ident(enumName); JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create)); attach(result, dc); return result; diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java index bec19a72ec1..c9922e46486 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java @@ -51,12 +51,10 @@ public class Keywords { return instance; } - private final Log log; private final Names names; protected Keywords(Context context) { context.put(keywordsKey, this); - log = Log.instance(context); names = Names.instance(context); for (Token t : Token.values()) { 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 ba27f304dfd..ff9f85b494a 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 @@ -704,7 +704,7 @@ compiler.warn.override.bridge=\ {0}; overridden method is a bridge method compiler.warn.pkg-info.already.seen=\ - [package-info] a package-info.java file has already been seen for package {0} + a package-info.java file has already been seen for package {0} compiler.warn.path.element.not.found=\ [path] bad path element "{0}": no such file or directory compiler.warn.possible.fall-through.into.case=\ diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java index a1381517a06..ef4d4dc02dc 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -54,7 +54,7 @@ public class Pretty extends JCTree.Visitor { /** Set when we are producing source output. If we're not * producing source output, we can sometimes give more detail in * the output even though that detail would not be valid java - * soruce. + * source. */ private final boolean sourceOutput; @@ -468,6 +468,10 @@ public class Pretty extends JCTree.Visitor { print(" throws "); printExprs(tree.thrown); } + if (tree.defaultValue != null) { + print(" default "); + printExpr(tree.defaultValue); + } if (tree.body != null) { print(" "); printStat(tree.body); @@ -489,6 +493,20 @@ public class Pretty extends JCTree.Visitor { print("/*public static final*/ "); print(tree.name); if (tree.init != null) { + if (sourceOutput && tree.init.getTag() == JCTree.NEWCLASS) { + print(" /*enum*/ "); + JCNewClass init = (JCNewClass) tree.init; + if (init.args != null && init.args.nonEmpty()) { + print("("); + print(init.args); + print(")"); + } + if (init.def != null && init.def.defs != null) { + print(" "); + printBlock(init.def.defs); + } + return; + } print(" /* = "); printExpr(tree.init); print(" */"); @@ -1134,20 +1152,7 @@ public class Pretty extends JCTree.Visitor { // Prints the inner element type of a nested array private void printBaseElementType(JCTree tree) throws IOException { - switch (tree.getTag()) { - case JCTree.TYPEARRAY: - printBaseElementType(((JCArrayTypeTree)tree).elemtype); - return; - case JCTree.WILDCARD: - printBaseElementType(((JCWildcard)tree).inner); - return; - case JCTree.ANNOTATED_TYPE: - printBaseElementType(((JCAnnotatedType)tree).underlyingType); - return; - default: - printExpr(tree); - return; - } + printExpr(TreeInfo.innermostType(tree)); } // prints the brackets of a nested array in reverse order diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java index fead12535a3..de1afecbbf4 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -891,4 +891,17 @@ public class TreeInfo { throw new AssertionError("Unexpected type tree: " + tree); } } + + public static JCTree innermostType(JCTree type) { + switch (type.getTag()) { + case JCTree.TYPEARRAY: + return innermostType(((JCArrayTypeTree)type).elemtype); + case JCTree.WILDCARD: + return innermostType(((JCWildcard)type).inner); + case JCTree.ANNOTATED_TYPE: + return innermostType(((JCAnnotatedType)type).underlyingType); + default: + return type; + } + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java new file mode 100644 index 00000000000..bc91c470f7a --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java @@ -0,0 +1,355 @@ +/* + * 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.util; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.main.JavacOption; +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.main.RecognizedOptions; +import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.lang.ref.SoftReference; +import java.lang.reflect.Constructor; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; + +/** + * Utility methods for building a filemanager. + * There are no references here to file-system specific objects such as + * java.io.File or java.nio.file.Path. + */ +public class BaseFileManager { + protected BaseFileManager(Charset charset) { + this.charset = charset; + byteBufferCache = new ByteBufferCache(); + } + + /** + * Set the context for JavacPathFileManager. + */ + protected void setContext(Context context) { + log = Log.instance(context); + options = Options.instance(context); + classLoaderClass = options.get("procloader"); + } + + /** + * The log to be used for error reporting. + */ + public Log log; + + /** + * User provided charset (through javax.tools). + */ + protected Charset charset; + + protected Options options; + + protected String classLoaderClass; + + protected Source getSource() { + String sourceName = options.get(OptionName.SOURCE); + Source source = null; + if (sourceName != null) + source = Source.lookup(sourceName); + return (source != null ? source : Source.DEFAULT); + } + + protected ClassLoader getClassLoader(URL[] urls) { + ClassLoader thisClassLoader = getClass().getClassLoader(); + + // Bug: 6558476 + // Ideally, ClassLoader should be Closeable, but before JDK7 it is not. + // On older versions, try the following, to get a closeable classloader. + + // 1: Allow client to specify the class to use via hidden option + if (classLoaderClass != null) { + try { + Class loader = + Class.forName(classLoaderClass).asSubclass(ClassLoader.class); + Class[] constrArgTypes = { URL[].class, ClassLoader.class }; + Constructor constr = loader.getConstructor(constrArgTypes); + return constr.newInstance(new Object[] { urls, thisClassLoader }); + } catch (Throwable t) { + // ignore errors loading user-provided class loader, fall through + } + } + + // 2: If URLClassLoader implements Closeable, use that. + if (Closeable.class.isAssignableFrom(URLClassLoader.class)) + return new URLClassLoader(urls, thisClassLoader); + + // 3: Try using private reflection-based CloseableURLClassLoader + try { + return new CloseableURLClassLoader(urls, thisClassLoader); + } catch (Throwable t) { + // ignore errors loading workaround class loader, fall through + } + + // 4: If all else fails, use plain old standard URLClassLoader + return new URLClassLoader(urls, thisClassLoader); + } + + // + public boolean handleOption(String current, Iterator remaining) { + for (JavacOption o: javacFileManagerOptions) { + if (o.matches(current)) { + if (o.hasArg()) { + if (remaining.hasNext()) { + if (!o.process(options, current, remaining.next())) + return true; + } + } else { + if (!o.process(options, current)) + return true; + } + // operand missing, or process returned false + throw new IllegalArgumentException(current); + } + } + + return false; + } + // where + private static JavacOption[] javacFileManagerOptions = + RecognizedOptions.getJavacFileManagerOptions( + new RecognizedOptions.GrumpyHelper()); + + public int isSupportedOption(String option) { + for (JavacOption o : javacFileManagerOptions) { + if (o.matches(option)) + return o.hasArg() ? 1 : 0; + } + return -1; + } + // + + // + private String defaultEncodingName; + private String getDefaultEncodingName() { + if (defaultEncodingName == null) { + defaultEncodingName = + new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding(); + } + return defaultEncodingName; + } + + public String getEncodingName() { + String encName = options.get(OptionName.ENCODING); + if (encName == null) + return getDefaultEncodingName(); + else + return encName; + } + + public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) { + String encodingName = getEncodingName(); + CharsetDecoder decoder; + try { + decoder = getDecoder(encodingName, ignoreEncodingErrors); + } catch (IllegalCharsetNameException e) { + log.error("unsupported.encoding", encodingName); + return (CharBuffer)CharBuffer.allocate(1).flip(); + } catch (UnsupportedCharsetException e) { + log.error("unsupported.encoding", encodingName); + return (CharBuffer)CharBuffer.allocate(1).flip(); + } + + // slightly overestimate the buffer size to avoid reallocation. + float factor = + decoder.averageCharsPerByte() * 0.8f + + decoder.maxCharsPerByte() * 0.2f; + CharBuffer dest = CharBuffer. + allocate(10 + (int)(inbuf.remaining()*factor)); + + while (true) { + CoderResult result = decoder.decode(inbuf, dest, true); + dest.flip(); + + if (result.isUnderflow()) { // done reading + // make sure there is at least one extra character + if (dest.limit() == dest.capacity()) { + dest = CharBuffer.allocate(dest.capacity()+1).put(dest); + dest.flip(); + } + return dest; + } else if (result.isOverflow()) { // buffer too small; expand + int newCapacity = + 10 + dest.capacity() + + (int)(inbuf.remaining()*decoder.maxCharsPerByte()); + dest = CharBuffer.allocate(newCapacity).put(dest); + } else if (result.isMalformed() || result.isUnmappable()) { + // bad character in input + + // report coding error (warn only pre 1.5) + if (!getSource().allowEncodingErrors()) { + log.error(new SimpleDiagnosticPosition(dest.limit()), + "illegal.char.for.encoding", + charset == null ? encodingName : charset.name()); + } else { + log.warning(new SimpleDiagnosticPosition(dest.limit()), + "illegal.char.for.encoding", + charset == null ? encodingName : charset.name()); + } + + // skip past the coding error + inbuf.position(inbuf.position() + result.length()); + + // undo the flip() to prepare the output buffer + // for more translation + dest.position(dest.limit()); + dest.limit(dest.capacity()); + dest.put((char)0xfffd); // backward compatible + } else { + throw new AssertionError(result); + } + } + // unreached + } + + public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) { + Charset cs = (this.charset == null) + ? Charset.forName(encodingName) + : this.charset; + CharsetDecoder decoder = cs.newDecoder(); + + CodingErrorAction action; + if (ignoreEncodingErrors) + action = CodingErrorAction.REPLACE; + else + action = CodingErrorAction.REPORT; + + return decoder + .onMalformedInput(action) + .onUnmappableCharacter(action); + } + // + + // + /** + * Make a byte buffer from an input stream. + */ + public ByteBuffer makeByteBuffer(InputStream in) + throws IOException { + int limit = in.available(); + if (limit < 1024) limit = 1024; + ByteBuffer result = byteBufferCache.get(limit); + int position = 0; + while (in.available() != 0) { + if (position >= limit) + // expand buffer + result = ByteBuffer. + allocate(limit <<= 1). + put((ByteBuffer)result.flip()); + int count = in.read(result.array(), + position, + limit - position); + if (count < 0) break; + result.position(position += count); + } + return (ByteBuffer)result.flip(); + } + + public void recycleByteBuffer(ByteBuffer bb) { + byteBufferCache.put(bb); + } + + /** + * A single-element cache of direct byte buffers. + */ + private static class ByteBufferCache { + private ByteBuffer cached; + ByteBuffer get(int capacity) { + if (capacity < 20480) capacity = 20480; + ByteBuffer result = + (cached != null && cached.capacity() >= capacity) + ? (ByteBuffer)cached.clear() + : ByteBuffer.allocate(capacity + capacity>>1); + cached = null; + return result; + } + void put(ByteBuffer x) { + cached = x; + } + } + + private final ByteBufferCache byteBufferCache; + // + + // + public CharBuffer getCachedContent(JavaFileObject file) { + SoftReference r = contentCache.get(file); + return (r == null ? null : r.get()); + } + + public void cache(JavaFileObject file, CharBuffer cb) { + contentCache.put(file, new SoftReference(cb)); + } + + protected final Map> contentCache + = new HashMap>(); + // + + public static Kind getKind(String name) { + if (name.endsWith(Kind.CLASS.extension)) + return Kind.CLASS; + else if (name.endsWith(Kind.SOURCE.extension)) + return Kind.SOURCE; + else if (name.endsWith(Kind.HTML.extension)) + return Kind.HTML; + else + return Kind.OTHER; + } + + protected static T nullCheck(T o) { + o.getClass(); // null check + return o; + } + + protected static Collection nullCheck(Collection it) { + for (T t : it) + t.getClass(); // null check + return it; + } +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java similarity index 96% rename from langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java rename to langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java index bcba74bef9f..48c1e6f0dfd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java @@ -23,7 +23,7 @@ * have any questions. */ -package com.sun.tools.javac.file; +package com.sun.tools.javac.util; import java.io.Closeable; import java.io.IOException; @@ -45,9 +45,9 @@ import java.util.jar.JarFile; * This code and its internal interfaces are subject to change or * deletion without notice. */ -class CloseableURLClassLoader +public class CloseableURLClassLoader extends URLClassLoader implements Closeable { - CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error { + public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error { super(urls, parent); try { getLoaders(); //proactive check that URLClassLoader is as expected @@ -63,6 +63,7 @@ class CloseableURLClassLoader * @throws java.io.IOException if the jar files cannot be found for any * reson, or if closing the jar file itself causes an IOException. */ + @Override public void close() throws IOException { try { for (Object l: getLoaders()) { 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 dd4f4dd9e03..05158b61cae 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 @@ -49,7 +49,7 @@ public interface LayoutCharacters { /** Tabulator character. */ - final static byte TAB = 0x8; + final static byte TAB = 0x9; /** Line feed 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 7184bd9ed5c..ee7d7fa8caa 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 @@ -145,7 +145,10 @@ public class Log extends AbstractLog { private int getIntOption(Options options, String optionName, int defaultValue) { String s = options.get(optionName); try { - if (s != null) return Integer.parseInt(s); + if (s != null) { + int n = Integer.parseInt(s); + return (n <= 0 ? Integer.MAX_VALUE : n); + } } catch (NumberFormatException e) { // silently ignore ill-formed numbers } 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 06a508bba91..b02836d3cbc 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java @@ -118,28 +118,33 @@ class CodeWriter extends BasicWriter { public void writeInstr(Instruction instr) { print(String.format("%4d: %-13s ", instr.getPC(), instr.getMnemonic())); - instr.accept(instructionPrinter, null); + // compute the number of indentations for the body of multi-line instructions + // This is 6 (the width of "%4d: "), divided by the width of each indentation level, + // and rounded up to the next integer. + int indentWidth = options.indentWidth; + int indent = (6 + indentWidth - 1) / indentWidth; + instr.accept(instructionPrinter, indent); println(); } // where - Instruction.KindVisitor instructionPrinter = - new Instruction.KindVisitor() { + Instruction.KindVisitor instructionPrinter = + new Instruction.KindVisitor() { - public Void visitNoOperands(Instruction instr, Void p) { + public Void visitNoOperands(Instruction instr, Integer indent) { return null; } - public Void visitArrayType(Instruction instr, TypeKind kind, Void p) { + public Void visitArrayType(Instruction instr, TypeKind kind, Integer indent) { print(" " + kind.name); return null; } - public Void visitBranch(Instruction instr, int offset, Void p) { + public Void visitBranch(Instruction instr, int offset, Integer indent) { print((instr.getPC() + offset)); return null; } - public Void visitConstantPoolRef(Instruction instr, int index, Void p) { + public Void visitConstantPoolRef(Instruction instr, int index, Integer indent) { print("#" + index); tab(); print("// "); @@ -147,7 +152,7 @@ class CodeWriter extends BasicWriter { return null; } - public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Void p) { + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Integer indent) { print("#" + index + ", " + value); tab(); print("// "); @@ -155,46 +160,48 @@ class CodeWriter extends BasicWriter { return null; } - public Void visitLocal(Instruction instr, int index, Void p) { + public Void visitLocal(Instruction instr, int index, Integer indent) { print(index); return null; } - public Void visitLocalAndValue(Instruction instr, int index, int value, Void p) { + public Void visitLocalAndValue(Instruction instr, int index, int value, Integer indent) { print(index + ", " + value); return null; } - public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets) { + public Void visitLookupSwitch(Instruction instr, + int default_, int npairs, int[] matches, int[] offsets, Integer indent) { int pc = instr.getPC(); print("{ // " + npairs); - indent(+1); + indent(indent); for (int i = 0; i < npairs; i++) { - print("\n" + matches[i] + ": " + (pc + offsets[i])); + print(String.format("%n%12d: %d", matches[i], (pc + offsets[i]))); } - print("\ndefault: " + (pc + default_) + " }"); - indent(-1); + print("\n default: " + (pc + default_) + "\n}"); + indent(-indent); return null; } - public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets) { + public Void visitTableSwitch(Instruction instr, + int default_, int low, int high, int[] offsets, Integer indent) { int pc = instr.getPC(); - print("{ //" + low + " to " + high); - indent(+1); + print("{ // " + low + " to " + high); + indent(indent); for (int i = 0; i < offsets.length; i++) { - print("\n" + (low + i) + ": " + (pc + offsets[i])); + print(String.format("%n%12d: %d", (low + i), (pc + offsets[i]))); } - print("\ndefault: " + (pc + default_) + " }"); - indent(-1); + print("\n default: " + (pc + default_) + "\n}"); + indent(-indent); return null; } - public Void visitValue(Instruction instr, int value, Void p) { + public Void visitValue(Instruction instr, int value, Integer indent) { print(value); return null; } - public Void visitUnknown(Instruction instr, Void p) { + public Void visitUnknown(Instruction instr, Integer indent) { return null; } }; diff --git a/langtools/src/share/classes/javax/lang/model/element/package-info.java b/langtools/src/share/classes/javax/lang/model/element/package-info.java index 26ea184c432..7729f505578 100644 --- a/langtools/src/share/classes/javax/lang/model/element/package-info.java +++ b/langtools/src/share/classes/javax/lang/model/element/package-info.java @@ -26,6 +26,16 @@ /** * Interfaces used to model elements of the Java programming language. * + * The term "element" in this package is used to refer to program + * elements, the declared entities that make up a program. Elements + * include classes, interfaces, methods, constructors, and fields. + * The interfaces in this package do not model the structure of a + * program inside a method body; for example there is no + * representation of a {@code for} loop or {@code try}-{@code finally} + * block. However, the interfaces can model some structures only + * appearing inside method bodies, such as local variables and + * anonymous classes. + * *

    When used in the context of annotation processing, an accurate * model of the element being represented must be returned. As this * is a language model, the source code provides the fiducial diff --git a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java index 116cf8c55f4..028c8d8f509 100644 --- a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java +++ b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java @@ -28,7 +28,6 @@ package javax.tools; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.concurrent.*; /** * File manager based on {@linkplain File java.io.File}. A common way diff --git a/langtools/test/tools/javac/6902720/E1.java b/langtools/test/tools/javac/6902720/E1.java new file mode 100644 index 00000000000..15ab8b4c96f --- /dev/null +++ b/langtools/test/tools/javac/6902720/E1.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +enum E1 { + A, + B { }, + C { void m() { } }; +} diff --git a/langtools/test/tools/javac/6902720/E2.java b/langtools/test/tools/javac/6902720/E2.java new file mode 100644 index 00000000000..6f76f1468c3 --- /dev/null +++ b/langtools/test/tools/javac/6902720/E2.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. + */ + +enum E2 { + A(1), + B(2) { }, + C(3) { void m() { } }; + E2(int i) { } +} diff --git a/langtools/test/tools/javac/6902720/Test.java b/langtools/test/tools/javac/6902720/Test.java new file mode 100644 index 00000000000..76d8501550c --- /dev/null +++ b/langtools/test/tools/javac/6902720/Test.java @@ -0,0 +1,91 @@ +/* + * 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.net.*; +import javax.tools.*; +import java.util.*; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.Pretty; + +/** + * @test + * @bug 6902720 + * @summary javac pretty printer does not handle enums correctly + */ + +public class Test { + + public static void main(String[] args) throws Exception { + Test t = new Test(); + t.run("E1.java", "E2.java"); + } + + void run(String... args) throws Exception { + File testSrcDir = new File(System.getProperty("test.src")); + for (String arg: args) { + test(new File(testSrcDir, arg)); + } + } + + void test(File test) throws Exception { + JavacTool tool1 = JavacTool.create(); + StandardJavaFileManager fm = tool1.getStandardFileManager(null, null, null); + Iterable files = fm.getJavaFileObjects(test); + + // parse test file into a tree, and write it out to a stringbuffer using Pretty + JavacTask t1 = tool1.getTask(null, fm, null, null, null, files); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Iterable trees = t1.parse(); + for (CompilationUnitTree tree: trees) { + new Pretty(pw, true).printExpr((JCTree) tree); + } + pw.close(); + + final String out = sw.toString(); + System.err.println("generated code:\n" + out + "\n"); + + // verify the generated code is valid Java by compiling it + JavacTool tool2 = JavacTool.create(); + JavaFileObject fo = new SimpleJavaFileObject(URI.create("output"), JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return out; + } + }; + JavacTask t2 = tool2.getTask(null, fm, null, null, null, Collections.singleton(fo)); + boolean ok = t2.call(); + if (!ok) + throw new Exception("compilation of generated code failed"); + + File expectedClass = new File(test.getName().replace(".java", ".class")); + if (!expectedClass.exists()) + throw new Exception(expectedClass + " not found"); + } +} + diff --git a/langtools/test/tools/javac/T6326754.java b/langtools/test/tools/javac/T6326754.java new file mode 100644 index 00000000000..b04f311abde --- /dev/null +++ b/langtools/test/tools/javac/T6326754.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6326754 + * @summary Compiler will fail to handle -Xmaxerrs with -ve numbers + * + * @compile/fail/ref=T6326754.out -XDrawDiagnostics -Xmaxerrs -1 T6326754.java + * @compile/fail/ref=T6326754.out -XDrawDiagnostics -Xmaxerrs 0 T6326754.java + * @compile/fail/ref=T6326754.out -XDrawDiagnostics -Xmaxerrs 10 T6326754.java + * @compile/fail/ref=T6326754.out -XDrawDiagnostics T6326754.java + */ +class TestConstructor{ + T t; + K k; + public TestConstructor(T t,K k){ + this.t =t; + } + public TestConstructor(K k){ + this.k = k; + this.t = null; + } + public TestConstructor(T t){ + this.t=t; + this.k=null; + } + public void setT(T t){ + this.t=t; + this.k=null; + } + public void setT(K k){ + this.k = k; + this.t = null; + } + public void setT(T t,K k){ + this.t = t; + this.k = k; + } +} +class TestC{ + T t; + public void setT(T t){ + this.t = t; + } +} +public class T6326754{ + public static void main(String... arg){ + TestC tC =new TestC(); + tC.setT(); + TestConstructor tc = new TestConstructor("saaa"); + tc.setT("sasa"); + TestC tC1 = new TestC(); + tC1.setT(545); + } +} diff --git a/langtools/test/tools/javac/T6326754.out b/langtools/test/tools/javac/T6326754.out new file mode 100644 index 00000000000..efbd8393b8b --- /dev/null +++ b/langtools/test/tools/javac/T6326754.out @@ -0,0 +1,7 @@ +T6326754.java:44:12: compiler.err.name.clash.same.erasure: TestConstructor(T), TestConstructor(K) +T6326754.java:52:17: compiler.err.name.clash.same.erasure: setT(K), setT(T) +T6326754.java:64:18: compiler.err.prob.found.req: (compiler.misc.incompatible.types), T, T +T6326754.java:70:11: compiler.err.cant.apply.symbol: kindname.method, setT, java.lang.Object, compiler.misc.no.args, kindname.class, TestC, null +- compiler.note.unchecked.filename: T6326754.java +- compiler.note.unchecked.recompile +4 errors diff --git a/langtools/test/tools/javac/T6472751.java b/langtools/test/tools/javac/T6472751.java new file mode 100644 index 00000000000..2f3e63f3ef5 --- /dev/null +++ b/langtools/test/tools/javac/T6472751.java @@ -0,0 +1,81 @@ +/* + * Copyright 2006-2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6472751 + * @summary SourcePositions.getStartPos returns incorrect value for enum constants + * @author Peter Ahe + */ + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.JavacTask; +import com.sun.source.util.SourcePositions; +import com.sun.source.util.TreeScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.util.List; +import java.io.IOException; +import java.net.URI; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class T6472751 { + static class MyFileObject extends SimpleJavaFileObject { + public MyFileObject() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + } + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return "public enum Test { ABC, DEF; }"; + } + } + static Trees trees; + static SourcePositions positions; + public static void main(String[] args) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + JavacTask task = (JavacTask) compiler.getTask(null, null, null, null, null, List.of(new MyFileObject())); + trees = Trees.instance(task); + positions = trees.getSourcePositions(); + Iterable asts = task.parse(); + for (CompilationUnitTree ast : asts) { + new MyVisitor().scan(ast, null); + } + } + + static class MyVisitor extends TreeScanner { + @Override + public Void scan(Tree node, Void ignored) { + if (node == null) + return null; + Kind k = node.getKind(); + long pos = positions.getStartPosition(null,node); + System.out.format("%s: %s%n", k, pos); + if (k != Kind.MODIFIERS && pos < 0) + throw new Error("unexpected position found"); + return super.scan(node, ignored); + } + } +} diff --git a/langtools/test/tools/javac/T6567414.java b/langtools/test/tools/javac/T6567414.java new file mode 100644 index 00000000000..1a2fa48c840 --- /dev/null +++ b/langtools/test/tools/javac/T6567414.java @@ -0,0 +1,11 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6567414 + * @summary javac compiler reports no source file or line on enum constant declaration error + * @compile/fail/ref=T6567414.out -XDrawDiagnostics T6567414.java + */ +enum Test { + FOO; + Test() throws Exception {} +} + diff --git a/langtools/test/tools/javac/T6567414.out b/langtools/test/tools/javac/T6567414.out new file mode 100644 index 00000000000..0f332d24cb9 --- /dev/null +++ b/langtools/test/tools/javac/T6567414.out @@ -0,0 +1,2 @@ +T6567414.java:8:3: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception +1 error diff --git a/langtools/test/tools/javac/T6665791.java b/langtools/test/tools/javac/T6665791.java new file mode 100644 index 00000000000..8a258f8e66a --- /dev/null +++ b/langtools/test/tools/javac/T6665791.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6665791 + * @summary com.sun.source.tree.MethodTree.toString() does not output default values + */ + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import com.sun.source.tree.ClassTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreeScanner; +import java.io.FileWriter; + +public class T6665791 { + static String test = "public @interface Annotation { boolean booleanProperty() default false; }"; + static File test_java = new File("Test.java"); + + public static void main(String[] args) throws Exception { + write(test_java, test); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager manager = + compiler.getStandardFileManager(null, null, null); + Iterable units = manager.getJavaFileObjects(test_java); + final StringWriter sw = new StringWriter(); + JavacTask task = (JavacTask) compiler.getTask(sw, manager, null, null, + null, units); + + new TreeScanner() { + @Override + public Boolean visitClass(ClassTree arg0, Void arg1) { + sw.write(arg0.toString()); + return super.visitClass(arg0, arg1); + } + }.scan(task.parse(), null); + + System.out.println("output:"); + System.out.println(sw.toString()); + String found = sw.toString().replaceAll("\\s+", " ").trim(); + String expect = test.replaceAll("\\s+", " ").trim(); + if (!expect.equals(found)) { + System.out.println("expect: " + expect); + System.out.println("found: " + found); + throw new Exception("unexpected output"); + } + } + + static void write(File file, String body) throws IOException { + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + } +} diff --git a/langtools/test/tools/javac/T6855236.java b/langtools/test/tools/javac/T6855236.java new file mode 100644 index 00000000000..fba6a37ad59 --- /dev/null +++ b/langtools/test/tools/javac/T6855236.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6855236 + * @summary Compiler Tree API TreePath class generates NullPointerException from Iterator + * @compile T6855236.java + * @compile -processor T6855236 -proc:only T6855236.java + */ + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; + +import com.sun.source.tree.*; +import com.sun.source.util.*; + +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedAnnotationTypes("*") +public class T6855236 extends AbstractProcessor { + + private Trees trees; + + @Override + public void init(ProcessingEnvironment pe) { + super.init(pe); + trees = Trees.instance(pe); + } + + @Override + public boolean process(Set arg0, RoundEnvironment roundEnvironment) { + // Scanner class to scan through various component elements + CodeVisitor visitor = new CodeVisitor(); + + for (Element e : roundEnvironment.getRootElements()) { + TreePath tp = trees.getPath(e); + visitor.scan(tp, trees); + } + + return true; + } + + class CodeVisitor extends TreePathScanner { + + @Override + public Object visitMethodInvocation(MethodInvocationTree node, Trees p) { + System.out.print("current path: "); + for (Tree t : getCurrentPath()) { + System.out.print('/'); + System.out.print(t); + } + System.out.println(); + System.out.println("parent path: " + getCurrentPath().getParentPath()); + System.out.println("method select: " + node.getMethodSelect().toString()); + for (ExpressionTree arg : node.getArguments()) { + System.out.println("argument: " + arg.toString()); + } + return super.visitMethodInvocation(node, p); + } + + @Override + public Object visitExpressionStatement(ExpressionStatementTree node, Trees p) { + ExpressionTree t = node.getExpression(); + System.out.println("expression statement: " + t.toString()); + return super.visitExpressionStatement(node, p); + } + + } + +} + + diff --git a/langtools/test/tools/javac/nio/compileTest/CompileTest.java b/langtools/test/tools/javac/nio/compileTest/CompileTest.java new file mode 100644 index 00000000000..9ec65c8014d --- /dev/null +++ b/langtools/test/tools/javac/nio/compileTest/CompileTest.java @@ -0,0 +1,170 @@ +/* + * 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 6906175 6915476 6915497 + * @summary Path-based JavaFileManager + * @compile -g HelloPathWorld.java + * @run main CompileTest + */ + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.jar.*; +import javax.tools.*; + +import com.sun.tools.javac.nio.*; +import com.sun.tools.javac.util.Context; +import java.nio.file.spi.FileSystemProvider; + + +public class CompileTest { + public static void main(String[] args) throws Exception { + new CompileTest().run(); + } + + public void run() throws Exception { + File rtDir = new File("rt.dir"); + File javaHome = new File(System.getProperty("java.home")); + if (javaHome.getName().equals("jre")) + javaHome = javaHome.getParentFile(); + File rtJar = new File(new File(new File(javaHome, "jre"), "lib"), "rt.jar"); + expand(rtJar, rtDir); + + String[] rtDir_opts = { + "-bootclasspath", rtDir.toString(), + "-classpath", "", + "-sourcepath", "", + "-extdirs", "" + }; + test(rtDir_opts, "HelloPathWorld"); + + if (isJarFileSystemAvailable()) { + String[] rtJar_opts = { + "-bootclasspath", rtJar.toString(), + "-classpath", "", + "-sourcepath", "", + "-extdirs", "" + }; + test(rtJar_opts, "HelloPathWorld"); + + String[] default_opts = { }; + test(default_opts, "HelloPathWorld"); + + // finally, a non-trivial program + test(default_opts, "CompileTest"); + } else + System.err.println("jar file system not available: test skipped"); + } + + void test(String[] opts, String className) throws Exception { + count++; + System.err.println("Test " + count + " " + Arrays.asList(opts) + " " + className); + Path testSrcDir = Paths.get(System.getProperty("test.src")); + Path testClassesDir = Paths.get(System.getProperty("test.classes")); + Path classes = Paths.get("classes." + count); + classes.createDirectory(); + + Context ctx = new Context(); + PathFileManager fm = new JavacPathFileManager(ctx, true, null); + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + List options = new ArrayList(); + options.addAll(Arrays.asList(opts)); + options.addAll(Arrays.asList( + "-verbose", "-XDverboseCompilePolicy", + "-d", classes.toString(), + "-g" + )); + Iterable compilationUnits = + fm.getJavaFileObjects(testSrcDir.resolve(className + ".java")); + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + JavaCompiler.CompilationTask t = + compiler.getTask(out, fm, null, options, null, compilationUnits); + boolean ok = t.call(); + System.err.println(sw.toString()); + if (!ok) { + throw new Exception("compilation failed"); + } + + File expect = new File("classes." + count + "/" + className + ".class"); + if (!expect.exists()) + throw new Exception("expected file not found: " + expect); + // Note that we explicitly specify -g for compiling both the actual class and the expected class. + // This isolates the expected class from javac options that might be given to jtreg. + long expectedSize = new File(testClassesDir.toString(), className + ".class").length(); + long actualSize = expect.length(); + if (expectedSize != actualSize) + throw new Exception("wrong size found: " + actualSize + "; expected: " + expectedSize); + } + + boolean isJarFileSystemAvailable() { + boolean result = false; + for (FileSystemProvider fsp: FileSystemProvider.installedProviders()) { + String scheme = fsp.getScheme(); + System.err.println("Provider: " + scheme + " " + fsp); + if (scheme.equalsIgnoreCase("jar") || scheme.equalsIgnoreCase("zip")) + result = true; + } + return result; + } + + void expand(File jar, File dir) throws IOException { + JarFile jarFile = new JarFile(jar); + try { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry je = entries.nextElement(); + if (!je.isDirectory()) { + copy(jarFile.getInputStream(je), new File(dir, je.getName())); + } + } + } finally { + jarFile.close(); + } + } + + void copy(InputStream in, File dest) throws IOException { + dest.getParentFile().mkdirs(); + OutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); + try { + byte[] data = new byte[8192]; + int n; + while ((n = in.read(data, 0, data.length)) > 0) + out.write(data, 0, n); + } finally { + out.close(); + in.close(); + } + } + + void error(String message) { + System.err.println("Error: " + message); + errors++; + } + + int errors; + int count; +} diff --git a/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java new file mode 100644 index 00000000000..a65e21a9afa --- /dev/null +++ b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +class HelloPathWorld { + public static void main(String... args) { + System.out.println("Hello World!"); + } +} diff --git a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java index 889a227d992..ca7804f89e0 100644 --- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java +++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 + * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854 * @summary Tests that getElementsAnnotatedWith works properly. * @author Joseph D. Darcy * @compile TestElementsAnnotatedWith.java @@ -33,8 +33,8 @@ * @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.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 + * @compile Foo.java + * @compile/process -processor TestElementsAnnotatedWith -proc:only Foo */ import java.lang.annotation.Annotation; @@ -89,7 +89,7 @@ public class TestElementsAnnotatedWith extends AbstractProcessor { // Verify that the annotation information is as // expected. - Set expectedNames = new HashSet(Arrays.asList(annotatedElementInfo.names())); + Set expectedNames = new HashSet<>(Arrays.asList(annotatedElementInfo.names())); resultsMeta = roundEnvironment. @@ -126,9 +126,6 @@ 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. @@ -163,48 +160,14 @@ public class TestElementsAnnotatedWith extends AbstractProcessor { } catch(IllegalArgumentException iae) {} try { - Set elements = roundEnvironment.getElementsAnnotatedWith(processingEnv. - getElementUtils(). - getTypeElement("java.lang.Object") ); + Set elements = + roundEnvironment.getElementsAnnotatedWith(processingEnv. + getElementUtils(). + getTypeElement("java.lang.Object") ); throw new RuntimeException("Illegal argument exception not thrown"); } 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"))); - try { - int datum = io.read(); - while(datum != -1) { - os.write(datum); - datum = io.read(); - } - } finally { - io.close(); - } - os.close(); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - - - } - @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); diff --git a/langtools/test/tools/javap/classfile/deps/GetDeps.java b/langtools/test/tools/javap/classfile/deps/GetDeps.java new file mode 100644 index 00000000000..5621a778f8d --- /dev/null +++ b/langtools/test/tools/javap/classfile/deps/GetDeps.java @@ -0,0 +1,211 @@ +/* + * 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.util.*; +import java.util.regex.Pattern; +import javax.tools.*; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Dependencies.*; +import com.sun.tools.classfile.Dependency.Location; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; + +/** + * Demo utility for using the classfile dependency analysis API framework. + * + * Usage: + * getdeps [options] classes + * where options include: + * -classpath path where to find classes to analyze + * -p package-name restrict analysis to classes in this package + * (may be given multiple times) + * -r regex restrict analysis to packages matching pattern + * (-p and -r are exclusive) + * -rev invert the dependencies in the output + * -t transitive closure of dependencies + */ +public class GetDeps { + public static void main(String... args) throws Exception { + new GetDeps().run(args); + } + + void run(String... args) throws IOException, ClassFileNotFoundException { + PrintWriter pw = new PrintWriter(System.out); + try { + run(pw, args); + } finally { + pw.flush(); + } + } + + void run(PrintWriter out, String... args) throws IOException, ClassFileNotFoundException { + decodeArgs(args); + + final StandardJavaFileManager fm = new JavacFileManager(new Context(), false, null); + if (classpath != null) + fm.setLocation(StandardLocation.CLASS_PATH, classpath); + + ClassFileReader reader = new ClassFileReader(fm); + + Dependencies d = new Dependencies(); + + if (regex != null) + d.setFilter(Dependencies.getRegexFilter(Pattern.compile(regex))); + + if (packageNames.size() > 0) + d.setFilter(Dependencies.getPackageFilter(packageNames, false)); + + SortedRecorder r = new SortedRecorder(reverse); + + d.findAllDependencies(reader, rootClassNames, transitiveClosure, r); + + SortedMap> deps = r.getMap(); + for (Map.Entry> e: deps.entrySet()) { + out.println(e.getKey()); + for (Dependency dep: e.getValue()) { + out.println(" " + dep.getTarget()); + } + } + } + + void decodeArgs(String... args) { + rootClassNames = new TreeSet(); + packageNames = new TreeSet(); + + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-classpath") && (i + 1 < args.length)) + classpath = getPathFiles(args[++i]); + else if (arg.equals("-p") && (i + 1 < args.length)) + packageNames.add(args[++i]); + else if (arg.equals("-r") && (i + 1 < args.length)) + regex = args[++i]; + else if (arg.equals("-rev")) + reverse = true; + else if (arg.equals("-t")) + transitiveClosure = true; + else if (arg.startsWith("-")) + throw new Error(arg); + else { + for ( ; i < args.length; i++) + rootClassNames.add(args[i]); + } + } + } + + List getPathFiles(String path) { + List files = new ArrayList(); + for (String p: path.split(File.pathSeparator)) { + if (p.length() > 0) + files.add(new File(p)); + } + return files; + } + + boolean transitiveClosure; + List classpath; + Set rootClassNames; + Set packageNames; + String regex; + boolean reverse; + + + static class ClassFileReader implements Dependencies.ClassFileReader { + private JavaFileManager fm; + + ClassFileReader(JavaFileManager fm) { + this.fm = fm; + } + + @Override + public ClassFile getClassFile(String className) throws ClassFileNotFoundException { + try { + JavaFileObject fo = fm.getJavaFileForInput( + StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); + if (fo == null) + fo = fm.getJavaFileForInput( + StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); + if (fo == null) + throw new ClassFileNotFoundException(className); + InputStream in = fo.openInputStream(); + try { + return ClassFile.read(in); + } finally { + in.close(); + } + } catch (ConstantPoolException e) { + throw new ClassFileNotFoundException(className, e); + } catch (IOException e) { + throw new ClassFileNotFoundException(className, e); + } + } + }; + + static class SortedRecorder implements Recorder { + public SortedRecorder(boolean reverse) { + this.reverse = reverse; + } + + public void addDependency(Dependency d) { + Location o = (reverse ? d.getTarget() : d.getOrigin()); + SortedSet odeps = map.get(o); + if (odeps == null) { + Comparator c = (reverse ? originComparator : targetComparator); + map.put(o, odeps = new TreeSet(c)); + } + odeps.add(d); + } + + public SortedMap> getMap() { + return map; + } + + private Comparator originComparator = new Comparator() { + public int compare(Dependency o1, Dependency o2) { + return o1.getOrigin().toString().compareTo(o2.getOrigin().toString()); + } + }; + + private Comparator targetComparator = new Comparator() { + public int compare(Dependency o1, Dependency o2) { + return o1.getTarget().toString().compareTo(o2.getTarget().toString()); + } + }; + + private Comparator locationComparator = new Comparator() { + public int compare(Location o1, Location o2) { + return o1.toString().compareTo(o2.toString()); + } + }; + + private final SortedMap> map = + new TreeMap>(locationComparator); + + boolean reverse; + } + +} diff --git a/langtools/test/tools/javap/classfile/deps/T6907575.java b/langtools/test/tools/javap/classfile/deps/T6907575.java new file mode 100644 index 00000000000..23983ec7928 --- /dev/null +++ b/langtools/test/tools/javap/classfile/deps/T6907575.java @@ -0,0 +1,71 @@ +/* + * 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 6907575 + * @build GetDeps p.C1 + * @run main T6907575 + */ + +import java.io.*; + +public class T6907575 { + public static void main(String... args) throws Exception { + new T6907575().run(); + } + + void run() throws Exception { + String testSrc = System.getProperty("test.src"); + String testClasses = System.getProperty("test.classes"); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + GetDeps gd = new GetDeps(); + gd.run(pw, "-classpath", testClasses, "-t", "-p", "p", "p/C1"); + pw.close(); + System.out.println(sw); + + String ref = readFile(new File(testSrc, "T6907575.out")); + diff(sw.toString().replaceAll("[\r\n]+", "\n"), ref); + } + + void diff(String actual, String ref) throws Exception { + System.out.println("EXPECT:>>>" + ref + "<<<"); + System.out.println("ACTUAL:>>>" + actual + "<<<"); + if (!actual.equals(ref)) + throw new Exception("output not as expected"); + } + + String readFile(File f) throws IOException { + Reader r = new FileReader(f); + char[] buf = new char[(int) f.length()]; + int offset = 0; + int n; + while (offset < buf.length && (n = r.read(buf, offset, buf.length - offset)) != -1) + offset += n; + return new String(buf, 0, offset); + } +} diff --git a/langtools/test/tools/javap/classfile/deps/T6907575.out b/langtools/test/tools/javap/classfile/deps/T6907575.out new file mode 100644 index 00000000000..f1315914eb1 --- /dev/null +++ b/langtools/test/tools/javap/classfile/deps/T6907575.out @@ -0,0 +1,8 @@ +p/C1 + java/lang/Object + p/C2 +p/C2 + java/lang/Object + p/C3 +p/C3 + java/lang/Object diff --git a/langtools/test/tools/javap/classfile/deps/p/C1.java b/langtools/test/tools/javap/classfile/deps/p/C1.java new file mode 100644 index 00000000000..71f253e128b --- /dev/null +++ b/langtools/test/tools/javap/classfile/deps/p/C1.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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 p; + +public class C1 { + C2 c2; +} + +class C2 { + C3 c3; +} + +class C3 { +} diff --git a/make/Defs-internal.gmk b/make/Defs-internal.gmk index e3c6a2db7b2..db3072744ba 100644 --- a/make/Defs-internal.gmk +++ b/make/Defs-internal.gmk @@ -227,6 +227,37 @@ ifndef SKIP_FASTDEBUG_BUILD SKIP_FASTDEBUG_BUILD=false endif +# Select javadoc setting GENERATE_DOCS +ifndef NO_DOCS + # Default value (we want javadoc run) + GENERATE_DOCS=true + # No DOCS build when JDK_UPDATE_VERSION set on non-OPENJDK builds + ifndef OPENJDK + ifdef JDK_UPDATE_VERSION + GENERATE_DOCS=false + endif + endif + # If langtools, corba, jaxp, and jaxws are not being built, + # a full jdk javadoc is not possible + ifneq ($(BUILD_LANGTOOLS), true) + GENERATE_DOCS=false + endif + ifneq ($(BUILD_CORBA), true) + GENERATE_DOCS=false + endif + ifneq ($(BUILD_JAXP), true) + GENERATE_DOCS=false + endif + ifneq ($(BUILD_JAXWS), true) + GENERATE_DOCS=false + endif + ifeq ($(GENERATE_DOCS),false) + NO_DOCS=true + endif +else + GENERATE_DOCS=false +endif + # Output directory for hotspot build HOTSPOT_DIR = $(ABS_OUTPUTDIR)/hotspot diff --git a/make/jdk-rules.gmk b/make/jdk-rules.gmk index b9416bd0070..d7a20c03fe2 100644 --- a/make/jdk-rules.gmk +++ b/make/jdk-rules.gmk @@ -30,43 +30,20 @@ JDK_JAVA_EXE = $(OUTPUTDIR)/bin/java$(EXE_SUFFIX) # NO_IMAGES may be set in conjunction with DEV_ONLY -ifdef NO_IMAGES - IMAGES_TARGET = -else - IMAGES_TARGET = images +IMAGES_TARGET = images +ifdef DEV_ONLY + ifdef NO_IMAGES + IMAGES_TARGET = + endif endif -# No DOCS build when JDK_UPDATE_VERSION set -ifdef JDK_UPDATE_VERSION - DOCS_TARGET = -else - DOCS_TARGET = docs -endif - -# NO_DOCS may be set in conjunction with DEV_ONLY -ifdef NO_DOCS +# GENERATE_DOCS determines if we ask for the docs target +DOCS_TARGET = docs +ifeq ($(GENERATE_DOCS),false) DOCS_TARGET = endif - -# If langtools not being built, full jdk javadoc is not possible -ifneq ($(BUILD_LANGTOOLS), true) - DOCS_TARGET = -endif -ifneq ($(BUILD_CORBA), true) - DOCS_TARGET = -endif -ifneq ($(BUILD_JAXP), true) - DOCS_TARGET = -endif -ifneq ($(BUILD_JAXWS), true) - DOCS_TARGET = -endif - -ifndef DEV_ONLY - JDK_BUILD_TARGETS = sanity all $(DOCS_TARGET) images -else - JDK_BUILD_TARGETS = sanity all $(IMAGES_TARGET) -endif + +JDK_BUILD_TARGETS = sanity all $(DOCS_TARGET) $(IMAGES_TARGET) JDK_CLOBBER_TARGETS = clobber diff --git a/make/sanity-rules.gmk b/make/sanity-rules.gmk index 5d2a7adb84d..289300f9c06 100644 --- a/make/sanity-rules.gmk +++ b/make/sanity-rules.gmk @@ -204,13 +204,9 @@ ifeq ($(SPONSORS_SRC_AVAILABLE), true) "" >> $(WARNING_FILE) endif endif -ifndef OPENJDK - ifdef NO_DOCS - @$(ECHO) "WARNING: Your build environment has the variable NO_DOCS\n" \ - " defined. This will result in a development-only\n" \ - " build of the JDK, lacking the documentation.\n" \ +ifeq ($(GENERATE_DOCS),false) + @$(ECHO) "WARNING: This build does not include running javadoc.\n" \ "" >> $(WARNING_FILE) - endif endif ifdef NO_IMAGES @$(ECHO) "WARNING: Your build environment has the variable NO_IMAGES\n" \ @@ -355,4 +351,4 @@ endif .PHONY: sanity settings pre-sanity insane \ post-sanity post-sanity-hotspot post-sanity-jdk \ post-sanity-install post-sanity-deploy \ - alt_bootdir bootdir + alt_bootdir bootdir environment