diff --git a/.hgtags b/.hgtags index 453018dc5fe1c22116edef017f7bf217006b7b7b..39177739d9e7bbd9f270e87427051c6e9cf3d912 100644 --- a/.hgtags +++ b/.hgtags @@ -105,3 +105,5 @@ ac311eb325bfc763698219252bf3cee9e091f3af jdk7-b122 f08682e23279d6cccbdcafda1eb0647ba4900874 jdk7-b128 14cd5d54a8d0b9c368d60ea83a066735b9931015 jdk7-b129 bdc069d3f9101f89ec3f81c2950ee2d68fa846d3 jdk7-b130 +8ac52c85f9e91336dc00b52ef90b42eecf3230b3 jdk7-b131 +6bbc7a4734952ae7604578f270e1566639fa8752 jdk7-b132 diff --git a/LICENSE b/LICENSE index eeab58c21c9a42ab1dfe8a17a9aed6607100bec2..b40a0f457d75c638172ceb89da9b91d17c7b7fe3 100644 --- a/LICENSE +++ b/LICENSE @@ -325,11 +325,11 @@ License instead of this License. "CLASSPATH" EXCEPTION TO THE GPL -Certain source files distributed by Sun Microsystems, Inc. are subject to -the following clarification and special exception to the GPL, but only where -Sun has expressly included in the particular source file's header the words -"Sun designates this particular file as subject to the "Classpath" exception -as provided by Sun in the LICENSE file that accompanied this code." +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of diff --git a/make/common/Defs-windows.gmk b/make/common/Defs-windows.gmk index 7899b0e668de22375fe587effaaca0faa2114a39..87bc793596dcd6b3877cbcdc4ab9d117be3eae4e 100644 --- a/make/common/Defs-windows.gmk +++ b/make/common/Defs-windows.gmk @@ -359,7 +359,13 @@ ifeq ($(CC_VERSION),msvc) # VS2008 has bufferoverflow baked in: LFLAGS_VS2008 = - LFLAGS_VS2010 = + + # VS2010, always need safe exception handlers, not needed on 64bit + ifeq ($(ARCH_DATA_MODEL), 32) + LFLAGS_VS2010 = -SAFESEH + else + LFLAGS_VS2010 = + endif # LFLAGS are the flags given to $(LINK) and used to build the actual DLL file BASELFLAGS = -nologo /opt:REF /incremental:no diff --git a/make/common/Release.gmk b/make/common/Release.gmk index 9af023f2c54139e2dab2f09709d082bc491cd35f..224dcd1650b38aa8119688f32e26e29965b4841b 100644 --- a/make/common/Release.gmk +++ b/make/common/Release.gmk @@ -124,9 +124,11 @@ JRE_MAN_PAGES = \ tnameserv.1 \ unpack200.1 +ifndef OPENJDK ifeq ($(ARCH_DATA_MODEL),32) JRE_MAN_PAGES += javaws.1 endif +endif JDK_MAN_PAGES = \ $(JRE_MAN_PAGES) \ diff --git a/make/common/shared/Defs-windows.gmk b/make/common/shared/Defs-windows.gmk index 461913ac9dc5097648dd72764cf8eae6ac041615..d928448b48f01bcfbcf2b726be140b5cf5c4ca6e 100644 --- a/make/common/shared/Defs-windows.gmk +++ b/make/common/shared/Defs-windows.gmk @@ -772,9 +772,20 @@ else BANNED_DLLS=msvcp100[.]dll|msvcr100d[.]dll|msvcrtd[.]dll endif -# Macro to check it's input file for banned dependencies and verify the -# binary was built properly. Relies on process exit code. -define binary_file_verification # binary_file +# Check for /safeseh (only used on 32bit) +define binary_file_safeseh_verification # binary_file +( \ + $(ECHO) "Checking for /SAFESEH usage in: $1" && \ + if [ "`$(DUMPBIN) /loadconfig $1 | $(EGREP) -i 'Safe Exception Handler Table'`" = "" ] ; then \ + $(ECHO) "ERROR: Did not find 'Safe Exception Handler Table' in loadconfig: $1" ; \ + $(DUMPBIN) /loadconfig $1 ; \ + exit 6 ; \ + fi ; \ +) +endef + +# Check for /NXCOMPAT usage +define binary_file_nxcompat_verification # binary_file ( \ $(ECHO) "Checking for /NXCOMPAT usage in: $1" && \ if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'NX compatible'`" = "" ] ; then \ @@ -782,12 +793,24 @@ define binary_file_verification # binary_file $(DUMPBIN) /headers $1 ; \ exit 7 ; \ fi ; \ +) +endef + +# Check for /DYNAMICBASE usage +define binary_file_dynamicbase_verification # binary_file +( \ $(ECHO) "Checking for /DYNAMICBASE usage in: $1" && \ if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'Dynamic base'`" = "" ] ; then \ $(ECHO) "ERROR: Did not find 'Dynamic base' in headers: $1" ; \ $(DUMPBIN) /headers $1 ; \ exit 8 ; \ fi ; \ +) +endef + +# Check for banned dll usage +define binary_file_dll_verification # binary_file +( \ $(ECHO) "Checking for banned dependencies in: $1" && \ if [ "`$(DUMPBIN) /dependents $1 | $(EGREP) -i '$(BANNED_DLLS)'`" != "" ] ; then \ $(ECHO) "ERROR: Found use of $(BANNED_DLLS)"; \ @@ -797,6 +820,27 @@ define binary_file_verification # binary_file ) endef +# Macro to check it's input file for properly built executables. +# Relies on process exit code. Different for 32bit vs 64bit. +ifeq ($(ARCH_DATA_MODEL),32) +define binary_file_verification # binary_file +( \ + $(call binary_file_safeseh_verification,$1); \ + $(call binary_file_nxcompat_verification,$1); \ + $(call binary_file_dynamicbase_verification,$1); \ + $(call binary_file_dll_verification,$1); \ +) +endef +else +define binary_file_verification # binary_file +( \ + $(call binary_file_nxcompat_verification,$1); \ + $(call binary_file_dynamicbase_verification,$1); \ + $(call binary_file_dll_verification,$1); \ +) +endef +endif + else # Macro to check it's input file for banned dependencies and verify the diff --git a/make/java/security/Makefile b/make/java/security/Makefile index 95c56767fae007441a511c7b72725cf4dfc0eff5..1d28b60f2ff0dadac2ec6d35f3e2e1ba1070d73b 100644 --- a/make/java/security/Makefile +++ b/make/java/security/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2010 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2011 Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,8 @@ CACERTS_BUILD = $(LIBDIR)/security/cacerts ifndef OPENJDK BLACKLIST_SRC = $(CLOSED_SHARE_SRC)/lib/security/blacklist BLACKLIST_BUILD = $(LIBDIR)/security/blacklist + TRUSTEDLIBS_SRC = $(CLOSED_SHARE_SRC)/lib/security/trusted.libraries + TRUSTEDLIBS_BUILD = $(LIBDIR)/security/trusted.libraries endif FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class) @@ -77,7 +79,7 @@ include $(BUILDDIR)/common/Rules.gmk ifdef OPENJDK build: properties policy cacerts else -build: properties policy cacerts blacklist +build: properties policy cacerts blacklist trustedlibs endif install: all @@ -90,6 +92,8 @@ cacerts: classes $(CACERTS_BUILD) blacklist: classes $(BLACKLIST_BUILD) +trustedlibs: classes $(TRUSTEDLIBS_BUILD) + $(PROPS_BUILD): $(PROPS_SRC) $(install-file) @@ -102,9 +106,12 @@ $(CACERTS_BUILD): $(CACERTS_SRC) $(BLACKLIST_BUILD): $(BLACKLIST_SRC) $(install-file) +$(TRUSTEDLIBS_BUILD): $(TRUSTEDLIBS_SRC) + $(install-file) + clean clobber:: .delete.classlist $(RM) -r $(CLASSBINDIR)/java/security - $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD) + $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD) $(TRUSTEDLIBS_BUILD) # Additional Rule for building sun.security.util $(CLASSBINDIR)/%.class: $(SHARE_SRC)/sun/%.java diff --git a/make/sun/javazic/tzdata/VERSION b/make/sun/javazic/tzdata/VERSION index 5d158c9e6db90ba0601e1d5eb0a91af6938573e8..b82ee890a30866aa38dd80e72491336ba437a28c 100644 --- a/make/sun/javazic/tzdata/VERSION +++ b/make/sun/javazic/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2010o +tzdata2011b diff --git a/make/sun/javazic/tzdata/australasia b/make/sun/javazic/tzdata/australasia index 35ab9cfc9b8e48c037bd2e08eaca09f08606d126..430a6f146f5db8454c46ed950a1d85defb58112b 100644 --- a/make/sun/javazic/tzdata/australasia +++ b/make/sun/javazic/tzdata/australasia @@ -106,14 +106,13 @@ Rule AS 1986 only - Oct 19 2:00s 1:00 - Rule AS 1987 2007 - Oct lastSun 2:00s 1:00 - Rule AS 1972 only - Feb 27 2:00s 0 - Rule AS 1973 1985 - Mar Sun>=1 2:00s 0 - -Rule AS 1986 1989 - Mar Sun>=15 2:00s 0 - -Rule AS 1990 only - Mar Sun>=18 2:00s 0 - -Rule AS 1991 only - Mar Sun>=1 2:00s 0 - -Rule AS 1992 only - Mar Sun>=18 2:00s 0 - -Rule AS 1993 only - Mar Sun>=1 2:00s 0 - -Rule AS 1994 only - Mar Sun>=18 2:00s 0 - +Rule AS 1986 1990 - Mar Sun>=15 2:00s 0 - +Rule AS 1991 only - Mar 3 2:00s 0 - +Rule AS 1992 only - Mar 22 2:00s 0 - +Rule AS 1993 only - Mar 7 2:00s 0 - +Rule AS 1994 only - Mar 20 2:00s 0 - Rule AS 1995 2005 - Mar lastSun 2:00s 0 - -Rule AS 2006 only - Apr Sun>=1 2:00s 0 - +Rule AS 2006 only - Apr 2 2:00s 0 - Rule AS 2007 only - Mar lastSun 2:00s 0 - Rule AS 2008 max - Apr Sun>=1 2:00s 0 - Rule AS 2008 max - Oct Sun>=1 2:00s 1:00 - diff --git a/make/sun/javazic/tzdata/northamerica b/make/sun/javazic/tzdata/northamerica index d07c69c9b45979a79d1a88567d1ae7c3eec963ca..281ab4f6748312dfed8840ef86d06d6e2ddf8d28 100644 --- a/make/sun/javazic/tzdata/northamerica +++ b/make/sun/javazic/tzdata/northamerica @@ -368,6 +368,27 @@ Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21 -7:00 US M%sT 2003 Oct 26 02:00 -6:00 US C%sT +# From Josh Findley (2011-01-21): +# ...it appears that Mercer County, North Dakota, changed from the +# mountain time zone to the central time zone at the last transition from +# daylight-saving to standard time (on Nov. 7, 2010): +# +# http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm +# +# +# http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html +# + +# From Andy Lipscomb (2011-01-24): +# ...according to the Census Bureau, the largest city is Beulah (although +# it's commonly referred to as Beulah-Hazen, with Hazen being the next +# largest city in Mercer County). Google Maps places Beulah's city hall +# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07". + +Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53 + -7:00 US M%sT 2010 Nov 7 2:00 + -6:00 US C%sT + # US mountain time, represented by Denver # # Colorado, far western Kansas, Montana, western @@ -493,20 +514,50 @@ Zone America/Adak 12:13:21 - LMT 1867 Oct 18 # three votes for and one against." # Hawaii -# -# From Arthur David Olson: -# And then there's Hawaii. -# DST was observed for one day in 1933; -# standard time was changed by half an hour in 1947; -# it's always standard as of 1986. -# -# From Paul Eggert: -# Shanks says the 1933 experiment lasted for three weeks. Go with Shanks. -# -Zone Pacific/Honolulu -10:31:26 - LMT 1900 Jan 1 12:00 - -10:30 - HST 1933 Apr 30 2:00 - -10:30 1:00 HDT 1933 May 21 2:00 - -10:30 US H%sT 1947 Jun 8 2:00 + +# From Arthur David Olson (2010-12-09): +# "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225 +# of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09, +# the article is available at +# +# http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf +# +# and indicates that standard time was adopted effective noon, January +# 13, 1896 (page 218), that in "1933, the Legislature decreed daylight +# saving for the period between the last Sunday of each April and the +# last Sunday of each September, but less than a month later repealed the +# act," (page 220), that year-round daylight saving time was in effect +# from 1942-02-09 to 1945-09-30 (page 221, with no time of day given for +# when clocks changed) and that clocks were changed by 30 minutes +# effective the second Sunday of June, 1947 (page 219, with no time of +# day given for when clocks changed). A footnote for the 1933 changes +# cites Session Laws of Hawaii 1933, "Act. 90 (approved 26 Apr. 1933) +# and Act 163 (approved 21 May 1933)." + +# From Arthur David Olson (2011-01-19): +# The following is from "Laws of the Territory of Hawaii Passed by the +# Seventeenth Legislature: Regular Session 1933," available (as of +# 2011-01-19) at American University's Pence Law Library. Page 85: "Act +# 90...At 2 o'clock ante meridian of the last Sunday in April of each +# year, the standard time of this Territory shall be advanced one +# hour...This Act shall take effect upon its approval. Approved this 26th +# day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of +# Hawaii." Page 172: "Act 163...Act 90 of the Session Laws of 1933 is +# hereby repealed...This Act shall take effect upon its approval, upon +# which date the standard time of this Territory shall be restored to +# that existing immediately prior to the taking effect of said Act 90. +# Approved this 21st day of May, A. D. 1933. LAWRENCE M. JUDD, Governor +# of the Territory of Hawaii." +# +# Note that 1933-05-21 was a Sunday. +# We're left to guess the time of day when Act 163 was approved; guess noon. + +Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 #Schmitt&Cox + -10:30 - HST 1933 Apr 30 2:00 #Laws 1933 + -10:30 1:00 HDT 1933 May 21 12:00 #Laws 1933+12 + -10:30 - HST 1942 Feb 09 2:00 #Schmitt&Cox+2 + -10:30 1:00 HDT 1945 Sep 30 2:00 #Schmitt&Fox+2 + -10:30 US H%sT 1947 Jun 8 2:00 #Schmitt&Fox+2 -10:00 - HST # Now we turn to US areas that have diverged from the consensus since 1970. diff --git a/make/sun/javazic/tzdata/zone.tab b/make/sun/javazic/tzdata/zone.tab index c1b3e0707eb62fdb1df064852f859586fa754160..cddfedae509a15e0f650c03e29f68168a2924873 100644 --- a/make/sun/javazic/tzdata/zone.tab +++ b/make/sun/javazic/tzdata/zone.tab @@ -233,8 +233,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java & Sumatra ID -0002+10920 Asia/Pontianak west & central Borneo -ID -0507+11924 Asia/Makassar east & south Borneo, Celebes, Bali, Nusa Tengarra, west Timor -ID -0232+14042 Asia/Jayapura Irian Jaya & the Moluccas +ID -0507+11924 Asia/Makassar east & south Borneo, Sulawesi (Celebes), Bali, Nusa Tengarra, west Timor +ID -0232+14042 Asia/Jayapura west New Guinea (Irian Jaya) & Malukus (Moluccas) IE +5320-00615 Europe/Dublin IL +3146+03514 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -426,6 +426,7 @@ US +411745-0863730 America/Indiana/Knox Central Time - Indiana - Starke County US +450628-0873651 America/Menominee Central Time - Michigan - Dickinson, Gogebic, Iron & Menominee Counties US +470659-1011757 America/North_Dakota/Center Central Time - North Dakota - Oliver County US +465042-1012439 America/North_Dakota/New_Salem Central Time - North Dakota - Morton County (except Mandan area) +US +471551-1014640 America/North_Dakota/Beulah Central Time - North Dakota - Mercer County US +394421-1045903 America/Denver Mountain Time US +433649-1161209 America/Boise Mountain Time - south Idaho & east Oregon US +364708-1084111 America/Shiprock Mountain Time - Navajo diff --git a/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.FormatConversionProvider b/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.FormatConversionProvider index 2ea4f8b80407786c26f161f02507c05a6d4c9f3c..a92a6020d50bf21c1d5731b4dbccea03182c41bd 100644 --- a/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.FormatConversionProvider +++ b/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.FormatConversionProvider @@ -1,5 +1,5 @@ # Providers for FormatConversion +com.sun.media.sound.AudioFloatFormatConverter com.sun.media.sound.UlawCodec com.sun.media.sound.AlawCodec com.sun.media.sound.PCMtoPCMCodec -com.sun.media.sound.AudioFloatFormatConverter diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java index 2290aa84e2b4cf23f94067d97ea570f4684d4511..42af08a729b02c56181154c2a1968146aae48733 100644 --- a/src/share/classes/java/dyn/CallSite.java +++ b/src/share/classes/java/dyn/CallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ static { } private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) { // ignore caller and name, but match the type: - return new ConstantCallSite(MethodHandles.collectArguments(printArgs, type)); + return new ConstantCallSite(printArgs.asType(type)); } * @author John Rose, JSR 292 EG @@ -86,6 +86,7 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam abstract public class CallSite { private static final Access IMPL_TOKEN = Access.getToken(); + static { MethodHandleImpl.initStatics(); } // Fields used only by the JVM. Do not use or change. private MemberName vmmethod; // supplied by the JVM (ref. to calling method) @@ -125,8 +126,8 @@ public class CallSite { } /** - * Report the type of this call site's target. - * Although targets may change, the call site's type can never change. + * Returns the type of this call site's target. + * Although targets may change, any call site's type is permanent, and can never change to an unequal type. * The {@code setTarget} method enforces this invariant by refusing any new target that does * not have the previous target's type. * @return the type of the current target, which is also the type of any future target @@ -154,73 +155,40 @@ public class CallSite { } /** - * Report the current linkage state of the call site, a value which may change over time. - *
- * If a {@code CallSite} object is returned - * from the bootstrap method of the {@code invokedynamic} instruction, - * the {@code CallSite} is permanently bound to that instruction. - * When the {@code invokedynamic} instruction is executed, the target method - * of its associated call site object is invoked directly. - * It is as if the instruction calls {@code getTarget} and then - * calls {@link MethodHandle#invokeExact invokeExact} on the result. - *
- * Unless specified differently by a subclass, - * 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 - * non-volatile, non-final field. - *
- * In particular, the current thread may choose to reuse the result - * of a previous read of the target from memory, and may fail to see - * a recent update to the target by another thread. - *
- * In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves - * like a read from a {@code final} field of the {@code CallSite}. - *
- * In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves - * like a read from a {@code volatile} field of the {@code CallSite}. - *
- * This method may not be overridden by application code. + * Returns the target method of the call site, according to the + * behavior defined by this call site's specific class. + * The immediate subclasses of {@code CallSite} document the + * class-specific behaviors of this method. + * * @return the current linkage state of the call site, its target method handle * @see ConstantCallSite * @see VolatileCallSite * @see #setTarget + * @see ConstantCallSite#getTarget + * @see MutableCallSite#getTarget + * @see VolatileCallSite#getTarget */ - public final MethodHandle getTarget() { - return getTarget0(); - } - - /** - * Privileged implementations can override this to force final or volatile semantics on getTarget. - */ - /*package-private*/ - MethodHandle getTarget0() { - return target; - } + public abstract MethodHandle getTarget(); /** - * Set the target method of this call site. + * Updates the target method of this call site, according to the + * behavior defined by this call site's specific class. + * The immediate subclasses of {@code CallSite} document the + * class-specific behaviors of this method. *
- * Unless a subclass of CallSite documents otherwise, - * the interactions of {@code setTarget} with memory are the same - * as of a write to an ordinary variable, such as an array element or a - * non-volatile, non-final field. - *
- * In particular, unrelated threads may fail to see the updated target - * until they perform a read from memory. - * Stronger guarantees can be created by putting appropriate operations - * into the bootstrap method and/or the target methods used - * at any given call site. + * The type of the new target must be {@linkplain MethodType#equals equal to} + * the type of the old target. + * * @param newTarget the new target * @throws NullPointerException if the proposed new target is null * @throws WrongMethodTypeException if the proposed new target * has a method type that differs from the previous target - * @throws UnsupportedOperationException if the call site is - * in fact a {@link ConstantCallSite} + * @see CallSite#getTarget + * @see ConstantCallSite#setTarget + * @see MutableCallSite#setTarget + * @see VolatileCallSite#setTarget */ - public void setTarget(MethodHandle newTarget) { - checkTargetChange(this.target, newTarget); - setTargetNormal(newTarget); - } + public abstract void setTarget(MethodHandle newTarget); void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { MethodType oldType = oldTarget.type(); @@ -236,31 +204,31 @@ public class CallSite { /** * Produce a method handle equivalent to an invokedynamic instruction * which has been linked to this call site. - *
If this call site is a {@linkplain ConstantCallSite constant call site}, - * this method simply returns the call site's target, since that will never change. - *
Otherwise, this method is equivalent to the following code: - *
+ *+ * This method is equivalent to the following code: + *
+ * * @return a method handle which always invokes this call site's current target */ - public final MethodHandle dynamicInvoker() { - if (this instanceof ConstantCallSite) { - return getTarget0(); // will not change dynamically - } + public abstract MethodHandle dynamicInvoker(); + + /*non-public*/ MethodHandle makeDynamicInvoker() { MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); return MethodHandles.foldArguments(invoker, getTarget); } + private static final MethodHandle GET_TARGET; static { try { GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP. findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); - } catch (NoAccessException ignore) { + } catch (ReflectiveOperationException ignore) { throw new InternalError(); } } diff --git a/src/share/classes/java/dyn/ClassValue.java b/src/share/classes/java/dyn/ClassValue.java index 7b00a727d07091a45de63bbf434d8eaff32b5b32..597dd951eb691471f770b2c6ea30b2cbfc4925f0 100644 --- a/src/share/classes/java/dyn/ClassValue.java +++ b/src/share/classes/java/dyn/ClassValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,14 @@ import java.util.concurrent.atomic.AtomicReference; import java.lang.reflect.UndeclaredThrowableException; /** - * Lazily associate a computed value with (potentially) every class. + * Lazily associate a computed value with (potentially) every type. + * For example, if a dynamic language needs to construct a message dispatch + * table for each class encountered at a message send call site, + * it can use a {@code ClassValue} to cache information needed to + * perform the message send quickly, for each class encountered. * @author John Rose, JSR 292 EG */ -public class ClassValue* MethodHandle getTarget, invoker, result; - * getTarget = MethodHandles.lookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); + * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); * invoker = MethodHandles.exactInvoker(this.type()); * result = MethodHandles.foldArguments(invoker, getTarget) *{ +public abstract class ClassValue { /** * Compute the given class's derived value for this {@code ClassValue}. * @@ -45,61 +49,41 @@ public class ClassValue
{ * but it may be invoked again if there has been a call to * {@link #remove remove}. * - * If there is no override from a subclass, this method returns - * the result of applying the {@code ClassValue}'s {@code computeValue} - * method handle, which was supplied at construction time. + * If this method throws an exception, the corresponding call to {@code get} + * will terminate abnormally with that exception, and no class value will be recorded. * + * @param type the type whose class value must be computed * @return the newly computed value associated with this {@code ClassValue}, for the given class or interface - * @throws UndeclaredThrowableException if the {@code computeValue} method handle invocation throws something other than a {@code RuntimeException} or {@code Error} - * @throws UnsupportedOperationException if the {@code computeValue} method handle is null (subclasses must override) + * @see #get + * @see #remove */ - protected T computeValue(Class> type) { - if (computeValue == null) - return null; - try { - return (T) (Object) computeValue.invokeGeneric(type); - } catch (Throwable ex) { - if (ex instanceof Error) throw (Error) ex; - if (ex instanceof RuntimeException) throw (RuntimeException) ex; - throw new UndeclaredThrowableException(ex); - } - } - - private final MethodHandle computeValue; - - /** - * Creates a new class value. - * Subclasses which use this constructor must override - * the {@link #computeValue computeValue} method, - * since the default {@code computeValue} method requires a method handle, - * which this constructor does not provide. - */ - protected ClassValue() { - this.computeValue = null; - } - - /** - * Creates a new class value, whose {@link #computeValue computeValue} method - * will return the result of {@code computeValue.invokeGeneric(type)}. - * @throws NullPointerException if the method handle parameter is null - */ - public ClassValue(MethodHandle computeValue) { - computeValue.getClass(); // trigger NPE if null - this.computeValue = computeValue; - } + protected abstract T computeValue(Class> type); /** * Returns the value for the given class. * If no value has yet been computed, it is obtained by - * by an invocation of the {@link #computeValue computeValue} method. + * an invocation of the {@link #computeValue computeValue} method. *
* The actual installation of the value on the class * is performed atomically. - * At that point, if racing threads have + * At that point, if several racing threads have * computed values, one is chosen, and returned to * all the racing threads. + *
+ * The {@code type} parameter is typically a class, but it may be any type, + * such as an interface, a primitive type (like {@code int.class}), or {@code void.class}. + *
+ * In the absence of {@code remove} calls, a class value has a simple + * state diagram: uninitialized and initialized. + * When {@code remove} calls are made, + * the rules for value observation are more complex. + * See the documentation for {@link #remove remove} for more information. * + * @param type the type whose class value must be computed or retrieved * @return the current value associated with this {@code ClassValue}, for the given class or interface + * @throws NullPointerException if the argument is null + * @see #remove + * @see #computeValue */ public T get(Class> type) { ClassValueMap map = getMap(type); @@ -119,12 +103,51 @@ public class ClassValue
{ * This may result in an additional invocation of the * {@code computeValue computeValue} method for the given class. * - * If racing threads perform a combination of {@code get} and {@code remove} calls, - * the calls are serialized. - * A value produced by a call to {@code computeValue} will be discarded, if - * the corresponding {@code get} call was followed by a {@code remove} call - * before the {@code computeValue} could complete. - * In such a case, the {@code get} call will re-invoke {@code computeValue}. + * In order to explain the interaction between {@code get} and {@code remove} calls, + * we must model the state transitions of a class value to take into account + * the alternation between uninitialized and initialized states. + * To do this, number these states sequentially from zero, and note that + * uninitialized (or removed) states are numbered with even numbers, + * while initialized (or re-initialized) states have odd numbers. + *
+ * When a thread {@code T} removes a class value in state {@code 2N}, + * nothing happens, since the class value is already uninitialized. + * Otherwise, the state is advanced atomically to {@code 2N+1}. + *
+ * When a thread {@code T} queries a class value in state {@code 2N}, + * the thread first attempts to initialize the class value to state {@code 2N+1} + * by invoking {@code computeValue} and installing the resulting value. + *
+ * When {@code T} attempts to install the newly computed value, + * if the state is still at {@code 2N}, the class value will be initialized + * with the computed value, advancing it to state {@code 2N+1}. + *
+ * Otherwise, whether the new state is even or odd, + * {@code T} will discard the newly computed value + * and retry the {@code get} operation. + *
+ * Discarding and retrying is an important proviso, + * since otherwise {@code T} could potentially install + * a disastrously stale value. For example: + *
+ *
+ * We can assume in the above scenario that {@code CV.computeValue} uses locks to properly + * observe the time-dependent states as it computes {@code V1}, etc. + * This does not remove the threat of a stale value, since there is a window of time + * between the return of {@code computeValue} in {@code T} and the installation + * of the the new value. No user synchronization is possible during this time. + * + * @param type the type whose class value must be removed + * @throws NullPointerException if the argument is null */ public void remove(Class> type) { ClassValueMap map = getMap(type); @@ -137,9 +160,9 @@ public class ClassValue- {@code T} calls {@code CV.get(C)} and sees state {@code 2N} + *
- {@code T} quickly computes a time-dependent value {@code V0} and gets ready to install it + *
- {@code T} is hit by an unlucky paging or scheduling event, and goes to sleep for a long time + *
- ...meanwhile, {@code T2} also calls {@code CV.get(C)} and sees state {@code 2N} + *
- {@code T2} quickly computes a similar time-dependent value {@code V1} and installs it on {@code CV.get(C)} + *
- {@code T2} (or a third thread) then calls {@code CV.remove(C)}, undoing {@code T2}'s work + *
- the previous actions of {@code T2} are repeated several times + *
- also, the relevant computed values change over time: {@code V1}, {@code V2}, ... + *
- ...meanwhile, {@code T} wakes up and attempts to install {@code V0}; this must fail + *
{ /// Implementation... - /** The hash code for this type is based on the identity of the object, - * and is well-dispersed for power-of-two tables. - */ + // The hash code for this type is based on the identity of the object, + // and is well-dispersed for power-of-two tables. + /** @deprecated This override, which is implementation-specific, will be removed for PFD. */ public final int hashCode() { return hashCode; } private final int hashCode = HASH_CODES.getAndAdd(0x61c88647); private static final AtomicInteger HASH_CODES = new AtomicInteger(); diff --git a/src/share/classes/java/dyn/ConstantCallSite.java b/src/share/classes/java/dyn/ConstantCallSite.java index 585fdc712cef9352ecacff7657f9d89cc68a0d8c..50240a0f50f45e1459fa05e633e83f65560b3375 100644 --- a/src/share/classes/java/dyn/ConstantCallSite.java +++ b/src/share/classes/java/dyn/ConstantCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,16 +32,46 @@ package java.dyn; * @author John Rose, JSR 292 EG */ public class ConstantCallSite extends CallSite { - /** Create a call site with a permanent target. + /** + * Creates a call site with a permanent target. + * @param target the target to be permanently associated with this call site * @throws NullPointerException if the proposed target is null */ public ConstantCallSite(MethodHandle target) { super(target); } + + /** + * Returns the target method of the call site, which behaves + * like a {@code final} field of the {@code ConstantCallSite}. + * That is, the the target is always the original value passed + * to the constructor call which created this instance. + * + * @return the immutable linkage state of this call site, a constant method handle + * @throws UnsupportedOperationException because this kind of call site cannot change its target + */ + @Override public final MethodHandle getTarget() { + return target; + } + /** - * Throw an {@link UnsupportedOperationException}, because this kind of call site cannot change its target. + * Always throws an {@link UnsupportedOperationException}. + * This kind of call site cannot change its target. + * @param ignore a new target proposed for the call site, which is ignored + * @throws UnsupportedOperationException because this kind of call site cannot change its target */ @Override public final void setTarget(MethodHandle ignore) { throw new UnsupportedOperationException("ConstantCallSite"); } + + /** + * Returns this call site's permanent target. + * Since that target will never change, this is a correct implementation + * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}. + * @return the immutable linkage state of this call site, a constant method handle + */ + @Override + public final MethodHandle dynamicInvoker() { + return getTarget(); + } } diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java index 1fe1af02b45901516845354e05dc9811174f12be..76e795e2f0e8ebaf160f0e6d46b309c4764b76ba 100644 --- a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java +++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java @@ -31,8 +31,8 @@ package java.dyn; * {@linkplain BootstrapMethod bootstrap method}, * or the bootstrap method has * failed to provide a - * {@linkplain CallSite} call site with a non-null {@linkplain MethodHandle target} - * of the correct {@linkplain MethodType method type}. + * {@linkplain CallSite call site} with a {@linkplain CallSite#getTarget target} + * of the correct {@linkplain MethodHandle#type method type}. * * @author John Rose, JSR 292 EG * @since 1.7 diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java index aad9409abdf1b5b29d915ce770641ac210242dbb..4ddda0a19902740d362d1a44be290700dfa703d1 100644 --- a/src/share/classes/java/dyn/Linkage.java +++ b/src/share/classes/java/dyn/Linkage.java @@ -88,7 +88,7 @@ public class Linkage { MethodHandle bootstrapMethod; try { bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE); - } catch (NoAccessException ex) { + } catch (ReflectiveOperationException ex) { throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex); } MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod); @@ -101,8 +101,9 @@ public class Linkage { /** * METHOD WILL BE REMOVED FOR PFD: * Invalidate all invokedynamiccall sites everywhere. - * @deprecated Use {@linkplain CallSite#setTarget call site target setting} - * and {@link VolatileCallSite#invalidateAll call site invalidation} instead. + * @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting}, + * {@link MutableCallSite#syncAll call site update pushing}, + * and {@link SwitchPoint#guardWithTest target switching} instead. */ public static Object invalidateAll() { @@ -113,8 +114,9 @@ public class Linkage { * METHOD WILL BE REMOVED FOR PFD: * Invalidate all {@code invokedynamic} call sites in the bytecodes * of any methods of the given class. - * @deprecated Use {@linkplain CallSite#setTarget call site target setting} - * and {@link VolatileCallSite#invalidateAll call site invalidation} instead. + * @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting}, + * {@link MutableCallSite#syncAll call site update pushing}, + * and {@link SwitchPoint#guardWithTest target switching} instead. */ public static Object invalidateCallerClass(Class> callerClass) { diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java index 25d0f807488c5688c3c7cd46c0748fdc3e075d02..b78b40248053f521214048a6b52230b42698a454 100644 --- a/src/share/classes/java/dyn/MethodHandle.java +++ b/src/share/classes/java/dyn/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import static java.dyn.MethodHandles.invokers; // package-private API import static sun.dyn.MemberName.newIllegalArgumentException; // utility /** - * A method handle is a typed, directly executable reference to a method, + * A method handle is a typed, directly executable reference to an underlying method, * constructor, field, or similar low-level operation, with optional * transformations of arguments or return values. * These transformations are quite general, and include such patterns as @@ -48,99 +48,182 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility * will be removed before the Proposed Final Draft. * Also, the final version will not include any public or * protected constructors. - *- * Method handles are strongly typed according to signature. - * They are not distinguished by method name or enclosing class. - * A method handle must be invoked under a signature which matches - * the method handle's own {@linkplain MethodType method type}. + * + *
Method handle contents
+ * Method handles are dynamically and strongly typed according to type descriptor. + * They are not distinguished by the name or defining class of their underlying methods. + * A method handle must be invoked using type descriptor which matches + * the method handle's own {@linkplain #type method type}. ** Every method handle reports its type via the {@link #type type} accessor. - * The structure of this type is a series of classes, one of which is + * This type descriptor is a {@link java.dyn.MethodType MethodType} object, + * whose structure is a series of classes, one of which is * the return type of the method (or {@code void.class} if none). *
- * Every method handle appears as an object containing a method named - * {@link #invokeExact invokeExact}, whose signature exactly matches - * the method handle's type. - * A Java method call expression, which compiles to an - * {@code 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. - * (The type is specified in the {@code invokevirtual} instruction, - * via a {@code CONSTANT_NameAndType} constant pool entry.) - * The call looks within the receiver object for a method - * named {@code invokeExact} of the intended method type. - * The call fails with a {@link WrongMethodTypeException} - * if the method does not exist, even if there is an {@code invokeExact} - * 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}. - *
- * Each individual method handle also contains a method named - * {@link #invokeGeneric invokeGeneric}, whose type is the same - * as {@code invokeExact}, and is therefore also reported by - * the {@link #type type} accessor. + * A method handle's type controls the types of invocations it accepts, + * and the kinds of transformations that apply to it. + *
+ * A method handle contains a pair of special invoker methods + * called {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. + * Both invoker methods provide direct access to the method handle's + * underlying method, constructor, field, or other operation, + * as modified by transformations of arguments and return values. + * Both invokers accept calls which exactly match the method handle's own type. + * The {@code invokeGeneric} invoker also accepts a range of other call types. + *
+ * Method handles are immutable and have no visible state. + * Of course, they can be bound to underlying methods or data which exhibit state. + * With respect to the Java Memory Model, any method handle will behave + * as if all of its (internal) fields are final variables. This means that any method + * handle made visible to the application will always be fully formed. + * This is true even if the method handle is published through a shared + * variable in a data race. + *
+ * Method handles cannot be subclassed by the user. + * Implementations may (or may not) create internal subclasses of {@code MethodHandle} + * which may be visible via the {@link java.lang.Object#getClass Object.getClass} + * operation. The programmer should not draw conclusions about a method handle + * from its specific class, as the method handle class hierarchy (if any) + * may change from time to time or across implementations from different vendors. + * + *
Method handle compilation
+ * A Java method call expression naming {@code invokeExact} or {@code invokeGeneric} + * can invoke a method handle from Java source code. + * From the viewpoint of source code, these methods can take any arguments + * and their result can be cast to any return type. + * Formally this is accomplished by giving the invoker methods + * {@code Object} return types and variable-arity {@code Object} arguments, + * but they have an additional quality called signature polymorphism + * which connects this freedom of invocation directly to the JVM execution stack. + *+ * As is usual with virtual methods, source-level calls to {@code invokeExact} + * and {@code invokeGeneric} compile to an {@code invokevirtual} instruction. + * More unusually, the compiler must record the actual argument types, + * and may not perform method invocation conversions on the arguments. + * Instead, it must push them on the stack according to their own unconverted types. + * The method handle object itself is pushed on the stack before the arguments. + * The compiler then calls the method handle with a type descriptor which + * describes the argument and return types. + *
+ * To issue a complete type descriptor, the compiler must also determine + * the return type. This is based on a cast on the method invocation expression, + * if there is one, or else {@code Object} if the invocation is an expression + * or else {@code void} if the invocation is a statement. + * The cast may be to a primitive type (but not {@code void}). + *
+ * As a corner case, an uncasted {@code null} argument is given + * a type descriptor of {@code java.lang.Void}. + * The ambiguity with the type {@code Void} is harmless, since there are no references of type + * {@code Void} except the null reference. + * + *
Method handle invocation
+ * The first time a {@code invokevirtual} instruction is executed + * it is linked, by symbolically resolving the names in the instruction + * and verifying that the method call is statically legal. + * This is true of calls to {@code invokeExact} and {@code invokeGeneric}. + * In this case, the type descriptor emitted by the compiler is checked for + * correct syntax and names it contains are resolved. + * Thus, an {@code invokevirtual} instruction which invokes + * a method handle will always link, as long + * as the type descriptor is syntactically well-formed + * and the types exist. + *+ * When the {@code invokevirtual} is executed after linking, + * the receiving method handle's type is first checked by the JVM + * to ensure that it matches the descriptor. + * If the type match fails, it means that the method which the + * caller is invoking is not present on the individual + * method handle being invoked. + *
+ * In the case of {@code invokeExact}, the type descriptor of the invocation + * (after resolving symbolic type names) must exactly match the method type + * of the receiving method handle. + * In the case of {@code invokeGeneric}, the resolved type descriptor + * must be a valid argument to the receiver's {@link #asType asType} method. + * Thus, {@code invokeGeneric} is more permissive than {@code invokeExact}. + *
+ * After type matching, a call to {@code invokeExact} directly + * and immediately invoke the method handle's underlying method + * (or other behavior, as the case may be). + *
* A call to {@code invokeGeneric} works the same as a call to - * {@code invokeExact}, if the signature specified by the caller + * {@code invokeExact}, if the type descriptor specified by the caller * exactly matches the method handle's own type. * If there is a type mismatch, {@code invokeGeneric} attempts - * to adjust the type of the target method handle - * (as if by a call to {@link #asType asType}) - * to obtain an exactly invokable target. + * to adjust the type of the receiving method handle, + * as if by a call to {@link #asType asType}, + * to obtain an exactly invokable method handle {@code M2}. * This allows a more powerful negotiation of method type * between caller and callee. *
- * 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 - * that has access to that method; the resulting handle can be used - * in any place by any caller who receives a reference to it. Thus, access - * checking is performed when the method handle is created, not - * (as in reflection) every time it is called. Handles to non-public - * methods, or in non-public classes, should generally be kept secret. - * They should not be passed to untrusted code unless their use from - * the untrusted code would be harmless. + * (Note: The adjusted method handle {@code M2} is not directly observable, + * and implementations are therefore not required to materialize it.) + * + *
Invocation checking
+ * In typical programs, method handle type matching will usually succeed. + * But if a match fails, the JVM will throw a {@link WrongMethodTypeException}, + * either directly (in the case of {@code invokeExact}) or indirectly as if + * by a failed call to {@code asType} (in the case of {@code invokeGeneric}). *- * Bytecode in the JVM can directly call a method handle's - * {@code invokeExact} method from an {@code invokevirtual} instruction. - * The receiver class type must be {@code MethodHandle} and the method name - * must be {@code invokeExact}. The signature of the invocation - * (after resolving symbolic type names) must exactly match the method type - * of the target method. - * Similarly, bytecode can directly call a method handle's {@code invokeGeneric} - * method. The signature of the invocation (after resolving symbolic type names) - * must either exactly match the method type or be a valid argument to - * the target's {@link #asType asType} method. - *
- * Every {@code invokeExact} and {@code invokeGeneric} method always - * throws {@link java.lang.Throwable Throwable}, - * 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 java.lang.Throwable Throwable}, or else must catch all - * throwables locally, rethrowing only those which are legal in the context, - * and wrapping ones which are illegal. + * Thus, a method type mismatch which might show up as a linkage error + * in a statically typed program can show up as + * a dynamic {@code WrongMethodTypeException} + * in a program which uses method handles. *
- * Bytecode in the JVM can directly obtain a method handle - * for any accessible method from a {@code ldc} instruction - * which refers to a {@code CONSTANT_MethodHandle} constant pool entry. - * (Each such entry refers directly to a {@code CONSTANT_Methodref}, - * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref} - * constant pool entry. - * For more details, see the package summary.) + * Because method types contain "live" {@code Class} objects, + * method type matching takes into account both types names and class loaders. + * Thus, even if a method handle {@code M} is created in one + * class loader {@code L1} and used in another {@code L2}, + * method handle calls are type-safe, because the caller's type + * descriptor, as resolved in {@code L2}, + * is matched against the original callee method's type descriptor, + * as resolved in {@code L1}. + * The resolution in {@code L1} happens when {@code M} is created + * and its type is assigned, while the resolution in {@code L2} happens + * when the {@code invokevirtual} instruction is linked. *
- * Java code can also use a reflective API called + * Apart from the checking of type descriptors, + * a method handle's capability to call its underlying method is unrestricted. + * If a method handle is formed on a non-public method by a class + * that has access to that method, the resulting handle can be used + * in any place by any caller who receives a reference to it. + *
+ * Unlike with the Core Reflection API, where access is checked every time + * a reflective method is invoked, + * method handle access checking is performed + * when the method handle is created. + * In the case of {@code ldc} (see below), access checking is performed as part of linking + * the constant pool entry underlying the constant method handle. + *
+ * Thus, handles to non-public methods, or to methods in non-public classes, + * should generally be kept secret. + * They should not be passed to untrusted code unless their use from + * the untrusted code would be harmless. + * + *
Method handle creation
+ * Java code can create a method handle that directly accesses + * any method, constructor, or field that is accessible to that code. + * This is done via a reflective, capability-based API called * {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup} - * for creating and calling method handles. * For example, a static method handle can be obtained * from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}. - * There are also bridge methods from Core Reflection API objects, - * such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.ureflect}. + * There are also conversion methods from Core Reflection API objects, + * such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}. + *+ * Like classes and strings, method handles that correspond to accessible + * fields, methods, and constructors can also be represented directly + * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes. + * A new type of constant pool entry, {@code CONSTANT_MethodHandle}, + * refers directly to an associated {@code CONSTANT_Methodref}, + * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref} + * constant pool entry. + * (For more details on method handle constants, + * see the package summary.) + *
+ * Method handles produced by lookups or constant loads from methods or + * constructors with the variable arity modifier bit ({@code 0x0080}) + * have a corresponding variable arity, as if they were defined with + * the help of {@link #asVarargsCollector asVarargsCollector}. *
* A method reference may refer either to a static or non-static method. * In the non-static case, the method handle type includes an explicit @@ -153,61 +236,191 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility * When a method handle to a virtual method is invoked, the method is * always looked up in the receiver (that is, the first argument). *
- * A non-virtual method handles to a specific virtual method implementation + * A non-virtual method handle to a specific virtual method implementation * can also be created. These do not perform virtual lookup based on * receiver type. Such a method handle simulates the effect of * an {@code invokespecial} instruction to the same method. - *
+ * + *
Usage examples
* Here are some examples of usage: *- * 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 cast immediately applied to the call. - * This cast may be to a primitive. - * If it is missing, the type defaults to {@code Object} if the call - * occurs in a context which uses the return value. - * If the call occurs as a statement, a cast is impossible, - * and there is no return type; the call is {@code void}. - *Object x, y; String s; int i; MethodType mt; MethodHandle mh; MethodHandles.Lookup lookup = MethodHandles.lookup(); -// mt is {(char,char) => String} +// mt is (char,char)String mt = MethodType.methodType(String.class, char.class, char.class); mh = lookup.findVirtual(String.class, "replace", mt); -// (Ljava/lang/String;CC)Ljava/lang/String; s = (String) mh.invokeExact("daddy",'d','n'); +// invokeExact(Ljava/lang/String;CC)Ljava/lang/String; assert(s.equals("nanny")); // weakly typed invocation (using MHs.invoke) s = (String) mh.invokeWithArguments("sappy", 'p', 'v'); assert(s.equals("savvy")); -// mt is {Object[] => List} +// mt is (Object[])List mt = MethodType.methodType(java.util.List.class, Object[].class); mh = lookup.findStatic(java.util.Arrays.class, "asList", mt); -// mt is {(Object,Object,Object) => Object} +assert(mh.isVarargsCollector()); +x = mh.invokeGeneric("one", "two"); +// invokeGeneric(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; +assert(x.equals(java.util.Arrays.asList("one","two"))); +// mt is (Object,Object,Object)Object mt = MethodType.genericMethodType(3); -mh = MethodHandles.collectArguments(mh, mt); -// mt is {(Object,Object,Object) => Object} -// (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +mh = mh.asType(mt); x = mh.invokeExact((Object)1, (Object)2, (Object)3); +// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; assert(x.equals(java.util.Arrays.asList(1,2,3))); // mt is { => int} mt = MethodType.methodType(int.class); mh = lookup.findVirtual(java.util.List.class, "size", mt); -// (Ljava/util/List;)I i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3)); +// invokeExact(Ljava/util/List;)I assert(i == 3); mt = MethodType.methodType(void.class, String.class); mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt); mh.invokeExact(System.out, "Hello, world."); -// (Ljava/io/PrintStream;Ljava/lang/String;)V +// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V *- * 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 + * Each of the above calls to {@code invokeExact} or {@code invokeGeneric} + * generates a single invokevirtual instruction with + * the type descriptor indicated in the following comment. + * + *
Exceptions
+ * The methods {@code invokeExact} and {@code invokeGeneric} are declared + * to throw {@link java.lang.Throwable Throwable}, + * 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 java.lang.Throwable Throwable}, or else must catch all + * throwables locally, rethrowing only those which are legal in the context, + * and wrapping ones which are illegal. + * + *Signature polymorphism
+ * The unusual compilation and linkage behavior of + * {@code invokeExact} and {@code invokeGeneric} + * is referenced by the term signature polymorphism. + * A signature polymorphic method is one which can operate with + * any of a wide range of call signatures and return types. + * In order to make this work, both the Java compiler and the JVM must + * give special treatment to signature polymorphic methods. + *+ * In source code, a call to a signature polymorphic method will + * compile, regardless of the requested type descriptor. + * As usual, the Java compiler emits an {@code invokevirtual} + * instruction with the given type descriptor against the named method. + * The unusual part is that the type descriptor is derived from + * the actual argument and return types, not from the method declaration. + *
+ * When the JVM processes bytecode containing signature polymorphic calls, + * it will successfully link any such call, regardless of its type descriptor. + * (In order to retain type safety, the JVM will guard such calls with suitable + * dynamic type checks, as described elsewhere.) + *
+ * Bytecode generators, including the compiler back end, are required to emit + * untransformed type descriptors for these methods. + * Tools which determine symbolic linkage are required to accept such + * untransformed descriptors, without reporting linkage errors. + *
+ * For the sake of tools (but not as a programming API), the signature polymorphic + * methods are marked with a private yet standard annotation, + * {@code @java.dyn.MethodHandle.PolymorphicSignature}. + * The annotation's retention is {@code RUNTIME}, so that all tools can see it. + * + *
Formal rules for processing signature polymorphic methods
+ *+ * The following methods (and no others) are signature polymorphic: + *
+ *
+ *- {@link java.dyn.MethodHandle#invokeExact MethodHandle.invokeExact} + *
- {@link java.dyn.MethodHandle#invokeGeneric MethodHandle.invokeGeneric} + *
+ * A signature polymorphic method will be declared with the following properties: + *
+ *
+ * Because of these requirements, a signature polymorphic method is able to accept + * any number and type of actual arguments, and can, with a cast, produce a value of any type. + * However, the JVM will treat these declaration features as a documentation convention, + * rather than a description of the actual structure of the methods as executed. + *- It must be native. + *
- It must take a single varargs parameter of the form {@code Object...}. + *
- It must produce a return value of type {@code Object}. + *
- It must be contained within the {@code java.dyn} package. + *
+ * When a call to a signature polymorphic method is compiled, the associated linkage information for + * its arguments is not array of {@code Object} (as for other similar varargs methods) + * but rather the erasure of the static types of all the arguments. + *
+ * In an argument position of a method invocation on a signature polymorphic method, + * a null literal has type {@code java.lang.Void}, unless cast to a reference type. + * (Note: This typing rule allows the null type to have its own encoding in linkage information + * distinct from other types. + *
+ * The linkage information for the return type is derived from a context-dependent target typing convention. + * The return type for a signature polymorphic method invocation is determined as follows: + *
+ *
+ * (Programmers are encouraged to use explicit casts unless it is clear that a signature polymorphic + * call will be used as a plain {@code Object} expression.) + *- If the method invocation expression is an expression statement, the method is {@code void}. + *
- Otherwise, if the method invocation expression is the immediate operand of a cast, + * the return type is the erasure of the cast type. + *
- Otherwise, the return type is the method's nominal return type, {@code Object}. + *
+ * The linkage information for argument and return types is stored in the descriptor for the + * compiled (bytecode) call site. As for any invocation instruction, the arguments and return value + * will be passed directly on the JVM stack, in accordance with the descriptor, + * and without implicit boxing or unboxing. + * + *
Interoperation between method handles and the Core Reflection API
+ * Using factory methods in the {@link java.dyn.MethodHandles.Lookup Lookup} API, + * any class member represented by a Core Reflection API object + * can be converted to a behaviorally equivalent method handle. + * For example, a reflective {@link java.lang.reflect.Method Method} can + * be converted to a method handle using + * {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}. + * The resulting method handles generally provide more direct and efficient + * access to the underlying class members. + *+ * As a special case, + * when the Core Reflection API is used to view the signature polymorphic + * methods {@code invokeExact} or {@code invokeGeneric} in this class, + * they appear as single, non-polymorphic native methods. + * Calls to these native methods do not result in method handle invocations. + * Since {@code invokevirtual} instructions can natively + * invoke method handles under any type descriptor, this reflective view conflicts + * with the normal presentation via bytecodes. + * Thus, these two native methods, as viewed by + * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod}, + * are placeholders only. + * If invoked via {@link java.lang.reflect.Method#invoke Method.invoke}, + * they will throw {@code UnsupportedOperationException}. + *
+ * In order to obtain an invoker method for a particular type descriptor, + * use {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker}, + * or {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker}. + * The {@link java.dyn.MethodHandles.Lookup#findVirtual Lookup.findVirtual} + * API is also able to return a method handle + * to call {@code invokeExact} or {@code invokeGeneric}, + * for any specified type descriptor . + * + *
Interoperation between method handles and Java generics
+ * A method handle can be obtained on a method, constructor, or field + * which is declared with Java generic types. + * As with the Core Reflection API, the type of the method handle + * will constructed from the erasure of the source-level type. + * When a method handle is invoked, the types of its arguments + * or the return value cast type may be generic types or type instances. + * If this occurs, the compiler will replace those + * types by their erasures when when it constructs the type descriptor + * for the {@code invokevirtual} instruction. + *+ * Method handles do not represent + * their function-like types in terms of Java parameterized (generic) types, + * because there are three mismatches between function-like types and parameterized * Java types. - *
+ *
- * Signature polymorphic methods in this class appear to be documented - * as having type parameters for return types and a parameter, but that is - * merely a documentation convention. These type parameters do - * not play a role in type-checking method handle invocations. - **
- Method types range over all possible arities, * from no arguments to up to 255 of arguments (a limit imposed by the JVM). * Generics are not variadic, and so cannot represent this.
@@ -217,29 +430,7 @@ mh.invokeExact(System.out, "Hello, world."); * 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. - *- * Like classes and strings, method handles that correspond to accessible - * fields, methods, and constructors can be represented directly - * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes. - * Loading such a constant causes the component classes of its type to be loaded as necessary. - *
- * Method handles cannot be subclassed by the user. - * Implementations may (or may not) create internal subclasses of {@code MethodHandle} - * which may be visible via the {@code java.lang.Object#getClass Object.getClass} - * operation. The programmer should not draw conclusions about a method handle - * from its specific class, as the method handle class hierarchy (if any) - * may change from time to time or across implementations from different vendors. - *
- * With respect to the Java Memory Model, any method handle will behave - * as if all of its fields are final variables. This means that any method - * handle made visible to the application will always be fully formed. - * This is true even if the method handle is published through a shared - * variables in a data race. + * * * @see MethodType * @see MethodHandles @@ -251,15 +442,16 @@ public abstract class MethodHandle extends MethodHandleImpl { private static Access IMPL_TOKEN = Access.getToken(); + static { MethodHandleImpl.initStatics(); } // interface MethodHandle
// { MethodType type(); public R invokeExact(A...) throws X; } /** * Internal marker interface which distinguishes (to the Java compiler) - * those methods which are signature polymorphic. + * those methods which are signature polymorphic. */ - @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.TYPE}) + @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface PolymorphicSignature { } @@ -270,7 +462,7 @@ public abstract class MethodHandle * Every invocation of this method handle via {@code invokeExact} must exactly match this type. * @return the method handle type */ - public final MethodType type() { + public MethodType type() { return type; } @@ -307,40 +499,27 @@ public abstract class MethodHandle } /** - * Returns a string representation of the method handle, - * starting with the string {@code "MethodHandle"} and - * ending with the string representation of the method handle's type. - * In other words, this method returns a string equal to the value of: - * - *- * "MethodHandle" + type().toString() - *- * Note: Future releases of this API may add further information - * to the string representation. - * Therefore, the present syntax should not be parsed by applications. - * - * @return a string representation of the method handle - */ - @Override - public String toString() { - return MethodHandleImpl.getNameString(IMPL_TOKEN, this); - } - - /** - * Invoke the method handle, allowing any caller signature, but requiring an exact signature match. - * The signature at the call site of {@code invokeExact} must + * Invoke the method handle, allowing any caller type descriptor, but requiring an exact type match. + * The type descriptor at the call site of {@code invokeExact} must * exactly match this method handle's {@link #type type}. * No conversions are allowed on arguments or return values. - * @throws WrongMethodTypeException if the target's type is not identical with the caller's type signature + *
+ * When this method is observed via the Core Reflection API, + * it will appear as a single native method, taking an object array and returning an object. + * If this native method is invoked directly via + * {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI, + * or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}, + * it will throw an {@code UnsupportedOperationException}. + * @throws WrongMethodTypeException if the target's type is not identical with the caller's type descriptor * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable; /** - * Invoke the method handle, allowing any caller signature, - * and optionally performing conversions for arguments and return types. + * Invoke the method handle, allowing any caller type descriptor, + * and optionally performing conversions on arguments and return values. *
- * If the call site signature exactly matches this method handle's {@link #type type}, + * If the call site type descriptor exactly matches this method handle's {@link #type type}, * the call proceeds as if by {@link #invokeExact invokeExact}. *
* Otherwise, the call proceeds as if this method handle were first @@ -353,14 +532,20 @@ public abstract class MethodHandle * adaptations directly on the caller's arguments, * and call the target method handle according to its own exact type. *
- * If the method handle is equipped with a - * {@linkplain #withTypeHandler type handler}, the handler must produce - * an entry point of the call site's exact type. - * Otherwise, the signature at the call site of {@code invokeGeneric} must - * be a valid argument to the standard {@code asType} method. + * The type descriptor at the call site of {@code invokeGeneric} must + * be a valid argument to the receivers {@code asType} method. * In particular, the caller must specify the same argument arity - * as the callee's type. - * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type signature + * as the callee's type, + * if the callee is not a {@linkplain #asVarargsCollector variable arity collector}. + *
+ * When this method is observed via the Core Reflection API, + * it will appear as a single native method, taking an object array and returning an object. + * If this native method is invoked directly via + * {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI, + * or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}, + * it will throw an {@code UnsupportedOperationException}. + * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type descriptor + * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable; @@ -400,16 +585,22 @@ public abstract class MethodHandle *
* This call is equivalent to the following code: *
+ *- * MethodHandle invoker = MethodHandles.varargsInvoker(this.type(), 0); + * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0); * Object result = invoker.invokeExact(this, arguments); *+ * Unlike the signature polymorphic methods {@code invokeExact} and {@code invokeGeneric}, + * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI. + * It can therefore be used as a bridge between native or reflective code and method handles. + * * @param arguments the arguments to pass to the target * @return the result returned by the target - * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the arguments + * @throws ClassCastException if an argument cannot be converted by reference casting + * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments * @throws Throwable anything thrown by the target method invocation - * @see MethodHandles#varargsInvoker + * @see MethodHandles#spreadInvoker */ - public final Object invokeWithArguments(Object... arguments) throws Throwable { + public Object invokeWithArguments(Object... arguments) throws Throwable { int argc = arguments == null ? 0 : arguments.length; MethodType type = type(); if (type.parameterCount() != argc) { @@ -417,7 +608,7 @@ public abstract class MethodHandle return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments); } if (argc <= 10) { - MethodHandle invoker = MethodHandles.invokers(type).genericInvoker(); + MethodHandle invoker = invokers(type).genericInvoker(); switch (argc) { case 0: return invoker.invokeExact(this); case 1: return invoker.invokeExact(this, @@ -456,19 +647,11 @@ public abstract class MethodHandle } // more than ten arguments get boxed in a varargs list: - MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0); + MethodHandle invoker = invokers(type).spreadInvoker(0); return invoker.invokeExact(this, arguments); } /** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */ - public final Object invokeWithArguments(java.util.List> arguments) throws Throwable { - return invokeWithArguments(arguments.toArray()); - } - @Deprecated - public final Object invokeVarargs(Object... arguments) throws Throwable { - return invokeWithArguments(arguments); - } - @Deprecated - public final Object invokeVarargs(java.util.List> arguments) throws Throwable { + public Object invokeWithArguments(java.util.List> arguments) throws Throwable { return invokeWithArguments(arguments.toArray()); } @@ -488,13 +671,7 @@ public abstract class MethodHandle * to match up the caller's and callee's types. *
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments}, - * except for method handles produced by {@link #withTypeHandler withTypeHandler}, - * in which case the specified type handler is used for calls to {@code asType}. - *
- * Note that the default behavior of {@code asType} only performs - * pairwise argument conversion and return value conversion. - * Because of this, unless the method handle has a type handler, - * the original type and new type must have the same number of arguments. + * except for variable arity method handles produced by {@link #asVarargsCollector asVarargsCollector}. * * @param newType the expected type of the new method handle * @return a method handle which delegates to {@code this} after performing @@ -508,14 +685,16 @@ public abstract class MethodHandle } /** - * Produce a method handle which adapts, as its target, + * Make an adapter which accepts a trailing array argument + * and spreads its elements as positional arguments. + * The new method handle 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 the final * {@code arrayLength} parameters of the target's type are replaced * by a single array parameter of type {@code arrayType}. *
* If the array element type differs from any of the corresponding - * argument types on original target, + * argument types on the original target, * the original target is adapted to take the array elements directly, * as if by a call to {@link #asType asType}. *
@@ -539,8 +718,9 @@ public abstract class MethodHandle * @throws IllegalArgumentException if target does not have at least * {@code arrayLength} parameter types * @throws WrongMethodTypeException if the implied {@code asType} call fails + * @see #asCollector */ - public final MethodHandle asSpreader(Class> arrayType, int arrayLength) { + public MethodHandle asSpreader(Class> arrayType, int arrayLength) { Class> arrayElement = arrayType.getComponentType(); if (arrayElement == null) throw newIllegalArgumentException("not an array type"); MethodType oldType = type(); @@ -553,13 +733,15 @@ public abstract class MethodHandle } /** - * Produce a method handle which adapts, as its target, + * Make an adapter which accepts a given number of trailing + * positional arguments and collects them into an array argument. + * The new method handle 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 * parameter (usually of type {@code arrayType}) is replaced by * {@code arrayLength} parameters whose type is element type of {@code arrayType}. *
- * If the array type differs from the final argument type on original target, + * If the array type differs from the final argument type on the original target, * the original target is adapted to take the array type directly, * as if by a call to {@link #asType asType}. *
@@ -570,21 +752,31 @@ public abstract class MethodHandle * What the target eventually returns is returned unchanged by the adapter. *
* (The array may also be a shared constant when {@code arrayLength} is zero.) - * @param arrayType usually {@code Object[]}, the type of the array argument which will collect the arguments + *
+ * (Note: The {@code arrayType} is often identical to the last + * parameter type of the original target. + * It is an explicit argument for symmetry with {@code asSpreader}, and also + * to allow the target to use a simple {@code Object} as its last parameter type.) + *
+ * In order to create a collecting adapter which is not restricted to a particular + * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead. + * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments * @param arrayLength the number of arguments to collect into a new array argument * @return a new method handle which collects some trailing argument * into an array, before calling the original method handle * @throws IllegalArgumentException if {@code arrayType} is not an array type - or {@code arrayType} is not assignable to this method handle's trailing parameter type - * @throws IllegalArgumentException if {@code arrayLength} is not - * a legal array size + * or {@code arrayType} is not assignable to this method handle's trailing parameter type, + * or {@code arrayLength} is not a legal array size * @throws WrongMethodTypeException if the implied {@code asType} call fails + * @see #asSpreader + * @see #asVarargsCollector */ - public final MethodHandle asCollector(Class> arrayType, int arrayLength) { + public MethodHandle asCollector(Class> arrayType, int arrayLength) { Class> arrayElement = arrayType.getComponentType(); if (arrayElement == null) throw newIllegalArgumentException("not an array type"); MethodType oldType = type(); int nargs = oldType.parameterCount(); + if (nargs == 0) throw newIllegalArgumentException("no trailing argument"); MethodType newType = oldType.dropParameterTypes(nargs-1, nargs); newType = newType.insertParameterTypes(nargs-1, java.util.Collections.
>nCopies(arrayLength, arrayElement)); @@ -592,8 +784,185 @@ public abstract class MethodHandle } /** - * Produce a method handle which binds the given argument - * to the current method handle as target. + * Make a variable arity adapter which is able to accept + * any number of trailing positional arguments and collect them + * into an array argument. + * + * The type and behavior of the adapter will be the same as + * the type and behavior of the target, except that certain + * {@code invokeGeneric} and {@code asType} requests can lead to + * trailing positional arguments being collected into target's + * trailing parameter. + * Also, the last parameter type of the adapter will be + * {@code arrayType}, even if the target has a different + * last parameter type. + *
+ * When called with {@link #invokeExact invokeExact}, the adapter invokes + * the target with no argument changes. + * (Note: This behavior is different from a + * {@linkplain #asCollector fixed arity collector}, + * since it accepts a whole array of indeterminate length, + * rather than a fixed number of arguments.) + *
+ * When called with {@link #invokeGeneric invokeGeneric}, if the caller + * type is the same as the adapter, the adapter invokes the target as with + * {@code invokeExact}. + * (This is the normal behavior for {@code invokeGeneric} when types match.) + *
+ * Otherwise, if the caller and adapter arity are the same, and the + * trailing parameter type of the caller is a reference type identical to + * or assignable to the trailing parameter type of the adapter, + * the arguments and return values are converted pairwise, + * as if by {@link MethodHandles#convertArguments convertArguments}. + * (This is also normal behavior for {@code invokeGeneric} in such a case.) + *
+ * Otherwise, the arities differ, or the adapter's trailing parameter + * type is not assignable from the corresponding caller type. + * In this case, the adapter replaces all trailing arguments from + * the original trailing argument position onward, by + * a new array of type {@code arrayType}, whose elements + * comprise (in order) the replaced arguments. + *
+ * The caller type must provides as least enough arguments, + * and of the correct type, to satisfy the target's requirement for + * positional arguments before the trailing array argument. + * Thus, the caller must supply, at a minimum, {@code N-1} arguments, + * where {@code N} is the arity of the target. + * Also, there must exist conversions from the incoming arguments + * to the target's arguments. + * As with other uses of {@code invokeGeneric}, if these basic + * requirements are not fulfilled, a {@code WrongMethodTypeException} + * may be thrown. + *
+ * In all cases, what the target eventually returns is returned unchanged by the adapter. + *
+ * In the final case, it is exactly as if the target method handle were + * temporarily adapted with a {@linkplain #asCollector fixed arity collector} + * to the arity required by the caller type. + * (As with {@code asCollector}, if the array length is zero, + * a shared constant may be used instead of a new array. + * If the implied call to {@code asCollector} would throw + * an {@code IllegalArgumentException} or {@code WrongMethodTypeException}, + * the call to the variable arity adapter must throw + * {@code WrongMethodTypeException}.) + *
+ * The behavior of {@link #asType asType} is also specialized for + * variable arity adapters, to maintain the invariant that + * {@code invokeGeneric} is always equivalent to an {@code asType} + * call to adjust the target type, followed by {@code invokeExact}. + * Therefore, a variable arity adapter responds + * to an {@code asType} request by building a fixed arity collector, + * if and only if the adapter and requested type differ either + * in arity or trailing argument type. + * The resulting fixed arity collector has its type further adjusted + * (if necessary) to the requested type by pairwise conversion, + * as if by another application of {@code asType}. + *
+ * When a method handle is obtained by executing an {@code ldc} instruction + * of a {@code CONSTANT_MethodHandle} constant, and the target method is marked + * as a variable arity method (with the modifier bit {@code 0x0080}), + * the method handle will accept multiple arities, as if the method handle + * constant were created by means of a call to {@code asVarargsCollector}. + *
+ * In order to create a collecting adapter which collects a predetermined + * number of arguments, and whose type reflects this predetermined number, + * use {@link #asCollector asCollector} instead. + *
+ * No method handle transformations produce new method handles with + * variable arity, unless they are documented as doing so. + * Therefore, besides {@code asVarargsCollector}, + * all methods in {@code MethodHandle} and {@code MethodHandles} + * will return a method handle with fixed arity, + * except in the cases where they are specified to return their original + * operand (e.g., {@code asType} of the method handle's own type). + *
+ * Calling {@code asVarargsCollector} on a method handle which is already + * of variable arity will produce a method handle with the same type and behavior. + * It may (or may not) return the original variable arity method handle. + *
+ * Here is an example, of a list-making variable arity method handle: + *
+ *+MethodHandle asList = publicLookup() + .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)) + .asVarargsCollector(Object[].class); +assertEquals("[]", asList.invokeGeneric().toString()); +assertEquals("[1]", asList.invokeGeneric(1).toString()); +assertEquals("[two, too]", asList.invokeGeneric("two", "too").toString()); +Object[] argv = { "three", "thee", "tee" }; +assertEquals("[three, thee, tee]", asList.invokeGeneric(argv).toString()); +List ls = (List) asList.invokeGeneric((Object)argv); +assertEquals(1, ls.size()); +assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); + *+ * Discussion: + * These rules are designed as a dynamically-typed variation + * of the Java rules for variable arity methods. + * In both cases, callers to a variable arity method or method handle + * can either pass zero or more positional arguments, or else pass + * pre-collected arrays of any length. Users should be aware of the + * special role of the final argument, and of the effect of a + * type match on that final argument, which determines whether + * or not a single trailing argument is interpreted as a whole + * array or a single element of an array to be collected. + * Note that the dynamic type of the trailing argument has no + * effect on this decision, only a comparison between the static + * type descriptor of the call site and the type of the method handle.) + *
+ * As a result of the previously stated rules, the variable arity behavior + * of a method handle may be suppressed, by binding it to the exact invoker + * of its own type, as follows: + *
+ * This transformation has no behavioral effect if the method handle is + * not of variable arity. + * + * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments + * @return a new method handle which can collect any number of trailing arguments + * into an array, before calling the original method handle + * @throws IllegalArgumentException if {@code arrayType} is not an array type + * or {@code arrayType} is not assignable to this method handle's trailing parameter type + * @see #asCollector + * @see #isVarargsCollector + */ + public MethodHandle asVarargsCollector(Class> arrayType) { + Class> arrayElement = arrayType.getComponentType(); + if (arrayElement == null) throw newIllegalArgumentException("not an array type"); + return MethodHandles.asVarargsCollector(this, arrayType); + } + + /** + * Determine if this method handle + * supports {@linkplain #asVarargsCollector variable arity} calls. + * Such method handles arise from the following sources: + *+MethodHandle vamh = publicLookup() + .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)) + .asVarargsCollector(Object[].class); +MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh); +assert(vamh.type().equals(mh.type())); +assertEquals("[1, 2, 3]", vamh.invokeGeneric(1,2,3).toString()); +boolean failed = false; +try { mh.invokeGeneric(1,2,3); } +catch (WrongMethodTypeException ex) { failed = true; } +assert(failed); + *+ *
+ * @return true if this method handle accepts more than one arity of {@code invokeGeneric} calls + * @see #asVarargsCollector + */ + public boolean isVarargsCollector() { + return false; + } + + /** + * Bind a value {@code x} to the first argument of a method handle, without invoking it. + * The new method handle adapts, as its target, + * to the current method handle. * 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. @@ -614,79 +983,27 @@ public abstract class MethodHandle * to the leading parameter type of the target * @see MethodHandles#insertArguments */ - public final MethodHandle bindTo(Object x) { + public MethodHandle bindTo(Object x) { return MethodHandles.insertArguments(this, 0, x); } /** - * PROVISIONAL API, WORK IN PROGRESS: - * Create a new method handle with the same type as this one, - * but whose {@code asType} method invokes the given - * {@code typeHandler} on this method handle, - * instead of the standard {@code MethodHandles.convertArguments}. - *- a call to {@linkplain #asVarargsCollector asVarargsCollector} + *
- a call to a {@linkplain java.dyn.MethodHandles.Lookup lookup method} + * which resolves to a variable arity Java method or constructor + *
- an {@code ldc} instruction of a {@code CONSTANT_MethodHandle} + * which resolves to a variable arity Java method or constructor + *
- * The new method handle will have the same behavior as the - * old one when invoked by {@code invokeExact}. - * For {@code invokeGeneric} calls which exactly match - * the method type, the two method handles will also - * have the same behavior. - * For other {@code invokeGeneric} calls, the {@code typeHandler} - * will control the behavior of the new method handle. - *
- * Thus, a method handle with an {@code asType} handler can - * be configured to accept more than one arity of {@code invokeGeneric} - * call, and potentially every possible arity. - * It can also be configured to supply default values for - * optional arguments, when the caller does not specify them. - *
- * The given method handle must take two arguments and return - * one result. The result it returns must be a method handle - * of exactly the requested type. If the result returned by - * the target is null, a {@link NullPointerException} is thrown, - * else if the type of the target does not exactly match - * the requested type, a {@link WrongMethodTypeException} is thrown. - *
- * A method handle's type handler is not guaranteed to be called every - * time its {@code asType} or {@code invokeGeneric} method is called. - * If the implementation is faced is able to prove that an equivalent - * type handler call has already occurred (on the same two arguments), - * it may substitute the result of that previous invocation, without - * making a new invocation. Thus, type handlers should not (in general) - * perform significant side effects. - *
- * Therefore, the type handler is invoked as if by this code: + * Returns a string representation of the method handle, + * starting with the string {@code "MethodHandle"} and + * ending with the string representation of the method handle's type. + * In other words, this method returns a string equal to the value of: *
*- * MethodHandle target = this; // original method handle - * MethodHandle adapter = ...; // adapted method handle - * MethodType requestedType = ...; // argument to asType() - * if (type().equals(requestedType)) - * return adapter; - * MethodHandle result = (MethodHandle) - * typeHandler.invokeGeneric(target, requestedType); - * if (!result.type().equals(requestedType)) - * throw new WrongMethodTypeException(); - * return result; + * "MethodHandle" + type().toString() *- * For example, here is a list-making variable-arity method handle: - *
-MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList()); -MethodHandle asList = lookup() - .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); -static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) { - return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType); -} -MethodHandle collectingTypeHandler = lookup() - .findStatic(lookup().lookupClass(), "collectingTypeHandler", - methodType(MethodHandle.class, MethodHandle.class, MethodType.class)); -MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler); - -assertEquals("[]", makeAnyList.invokeGeneric().toString()); -assertEquals("[1]", makeAnyList.invokeGeneric(1).toString()); -assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString()); - *+ * Note: Future releases of this API may add further information + * to the string representation. + * Therefore, the present syntax should not be parsed by applications. + * + * @return a string representation of the method handle */ - public MethodHandle withTypeHandler(MethodHandle typeHandler) { - return MethodHandles.withTypeHandler(this, typeHandler); + @Override + public String toString() { + return MethodHandleImpl.getNameString(IMPL_TOKEN, this); } } diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java index d2de0c24a488f495abe99be6a83d62f4d674fd9c..3bc9bd4a327e9462de0fe5a5c06319d4d23dd2ed 100644 --- a/src/share/classes/java/dyn/MethodHandles.java +++ b/src/share/classes/java/dyn/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.lang.reflect.*; import sun.dyn.Access; import sun.dyn.MemberName; import sun.dyn.MethodHandleImpl; +import sun.dyn.WrapperInstance; import sun.dyn.util.ValueConversions; import sun.dyn.util.VerifyAccess; import sun.dyn.util.Wrapper; @@ -45,10 +46,10 @@ import static sun.dyn.MemberName.newNoAccessException; * This class consists exclusively of static methods that operate on or return * method handles. They fall into several categories: *- *
*- Factory methods which create method handles for methods and fields. - *
- Invoker methods which can invoke method handles on dynamically typed arguments and/or varargs arrays. - *
- Combinator methods, which combine or transforming pre-existing method handles into new ones. - *
- Factory methods which create method handles that emulate other common JVM operations or control flow patterns. + *
- Lookup methods which help create method handles for methods and fields. + *
- Combinator methods, which combine or transform pre-existing method handles into new ones. + *
- Other factory methods to create method handles that emulate other common JVM operations or control flow patterns. + *
- Wrapper methods which can convert between method handles and other function-like "SAM types". *
* @author John Rose, JSR 292 EG @@ -97,47 +98,155 @@ public class MethodHandles { * when the creation requires access checking. * Method handles do not perform * access checks when they are called, but rather when they are created. - * (This is a major difference - * from reflective {@link Method}, which performs access checking - * against every caller, on every call.) * Therefore, method handle access * restrictions must be enforced when a method handle is created. * The caller class against which those restrictions are enforced * is known as the {@linkplain #lookupClass lookup class}. - * A lookup object embodies an - * authenticated lookup class, and can be used to create any number + *
+ * A lookup class which needs to create method handles will call + * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself. + * When the {@code Lookup} factory object is created, the identity of the lookup class is + * determined, and securely stored in the {@code Lookup} object. + * The lookup class (or its delegates) may then use factory methods + * on the {@code Lookup} object to create method handles for access-checked members. + * This includes all methods, constructors, and fields which are allowed to the lookup class, + * even private ones. + *
+ * The factory methods on a {@code Lookup} object correspond to all major + * use cases for methods, constructors, and fields. + * Here is a summary of the correspondence between these factory methods and + * the behavior the resulting method handles: + *
+ *+ * Here, the type {@code C} is the class or interface being searched for a member, + * documented as a parameter named {@code refc} in the lookup methods. + * The method or constructor type {@code MT} is composed from the return type {@code T} + * and the sequence of argument types {@code A*}. + * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}. + * The formal parameter {@code this} stands for the self-reference of type {@code C}; + * if it is present, it is always the leading argument to the method handle invocation. + * The name {@code arg} stands for all the other method handle arguments. + * In the code examples for the Core Reflection API, the name {@code thisOrNull} + * stands for a null reference if the accessed method or field is static, + * and {@code this} otherwise. + * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand + * for reflective objects corresponding to the given members. + *+ *
+ *+ * lookup expression member behavior + * + *{@linkplain java.dyn.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)} + *FT f; (T) this.f; + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)} + *static
FT f;(T) C.f; + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)} + *FT f; this.f = x; + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)} + *static
FT f;C.f = arg; + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)} + *T m(A*); (T) this.m(arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)} + *static
T m(A*);(T) C.m(arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)} + *T m(A*); (T) super.m(arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)} + *C(A*); (T) new C(arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)} + *(static)?
FT f;(FT) aField.get(thisOrNull); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)} + *(static)?
FT f;aField.set(thisOrNull, arg); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)} + *(static)?
T m(A*);(T) aMethod.invoke(thisOrNull, arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)} + *C(A*); (C) aConstructor.newInstance(arg*); + *+ * + *{@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)} + *(static)?
T m(A*);(T) aMethod.invoke(thisOrNull, arg*); + *+ * The equivalence between looked-up method handles and underlying + * class members can break down in a few ways: + *
+ *
+ * + *- If {@code C} is not symbolically accessible from the lookup class's loader, + * the lookup can still succeed, even when there is no equivalent + * Java expression or bytecoded constant. + *
- Likewise, if {@code T} or {@code MT} + * is not symbolically accessible from the lookup class's loader, + * the lookup can still succeed. + * For example, lookups for {@code MethodHandle.invokeExact} and + * {@code MethodHandle.invokeGeneric} will always succeed, regardless of requested type. + *
- If there is a security manager installed, it can forbid the lookup + * on various grounds (see below). + * By contrast, the {@code ldc} instruction is not subject to + * security manager checks. + *
Access checking
+ * Access checks are applied in the factory methods of {@code Lookup}, + * when a method handle is created. + * This is a key difference from the Core Reflection API, since + * {@link java.lang.reflect.Method#invoke Method.invoke} + * performs access checking against every caller, on every call. + *+ * All access checks start from a {@code Lookup} object, which + * compares its recorded lookup class against all requests to + * create method handles. + * A single {@code Lookup} object can be used to create any number * of access-checked method handles, all checked against a single * lookup class. *
- * A class which needs to create method handles will call - * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself. - * It may then use this factory to create method handles on - * all of its methods, including private ones. - * It may also delegate the lookup (e.g., to a metaobject protocol) - * by passing the lookup object to other code. - * If this other code creates method handles, they will be access - * checked against the original lookup class, and not with any higher - * privileges. + * A {@code Lookup} object can be shared with other trusted code, + * such as a metaobject protocol. + * A shared {@code Lookup} object delegates the capability + * to create method handles on private members of the lookup class. + * Even if privileged code uses the {@code Lookup} object, + * the access checking is confined to the privileges of the + * original lookup class. *
- * Access checks only apply to named and reflected methods. - * Other method handle creation methods, such as - * {@link #convertArguments MethodHandles.convertArguments}, - * do not require any access checks, and can be done independently - * of any lookup class. - *
How access errors are handled
* A lookup can fail, because * the containing class is not accessible to the lookup class, or * because the desired class member is missing, or because the * desired class member is not accessible to the lookup class. - * It can also fail if a security manager is installed and refuses - * access. In any of these cases, an exception will be - * thrown from the attempted lookup. + * In any of these cases, a {@code ReflectiveOperationException} will be + * thrown from the attempted lookup. The exact class will be one of + * the following: + *+ *
*- NoSuchMethodException — if a method is requested but does not exist + *
- NoSuchFieldException — if a field is requested but does not exist + *
- IllegalAccessException — if the member exists but an access check fails + *
* In general, the conditions under which a method handle may be - * created for a method {@code M} are exactly as restrictive as the conditions - * under which the lookup class could have compiled a call to {@code M}. + * looked up for a method {@code M} are exactly equivalent to the conditions + * under which the lookup class could have compiled and resolved a call to {@code M}. + * And the effect of invoking the method handle resulting from the lookup + * is exactly equivalent to executing the compiled and resolved call to {@code M}. + * The same point is true of fields and constructors. *
- * In some cases, this access is obtained by the Java compiler by creating + * In some cases, access between nested classes is obtained by the Java compiler by creating * an wrapper method to access a private method of another class * in the same top-level declaration. * For example, a nested class {@code C.D} @@ -149,6 +258,61 @@ public class MethodHandles { * A workaround for this limitation is the {@link Lookup#in Lookup.in} method, * which can transform a lookup on {@code C.E} into one on any of those other * classes, without special elevation of privilege. + *
+ * Although bytecode instructions can only refer to classes in + * a related class loader, this API can search for methods in any + * class, as long as a reference to its {@code Class} object is + * available. Such cross-loader references are also possible with the + * Core Reflection API, and are impossible to bytecode instructions + * such as {@code invokestatic} or {@code getfield}. + * There is a {@linkplain java.lang.SecurityManager security manager API} + * to allow applications to check such cross-loader references. + * These checks apply to both the {@code MethodHandles.Lookup} API + * and the Core Reflection API + * (as found on {@link java.lang.Class Class}). + *
+ * Access checks only apply to named and reflected methods, + * constructors, and fields. + * Other method handle creation methods, such as + * {@link #convertArguments MethodHandles.convertArguments}, + * do not require any access checks, and are done + * with static methods of {@link MethodHandles}, + * independently of any {@code Lookup} object. + * + *
Security manager interactions
+ * + * If a security manager is present, member lookups are subject to + * additional checks. + * From one to four calls are made to the security manager. + * Any of these calls can refuse access by throwing a + * {@link java.lang.SecurityException SecurityException}. + * Define {@code smgr} as the security manager, + * {@code refc} as the containing class in which the member + * is being sought, and {@code defc} as the class in which the + * member is actually defined. + * The calls are made according to the following rules: + *+ *
+ * In all cases, the requesting class presented to the security + * manager will be the lookup class from the current {@code Lookup} object. */ public static final class Lookup { @@ -194,12 +358,12 @@ public class MethodHandles { return (mods != 0) ? mods : PACKAGE; } - /** Which class is performing the lookup? It is this class against + /** Tells which class is performing the lookup. It is this class against * which checks are performed for visibility and access permissions. *- In all cases, {@link SecurityManager#checkMemberAccess + * smgr.checkMemberAccess(refc, Member.PUBLIC)} is called. + *
- If the class loader of the lookup class is not + * the same as or an ancestor of the class loader of {@code refc}, + * then {@link SecurityManager#checkPackageAccess + * smgr.checkPackageAccess(refcPkg)} is called, + * where {@code refcPkg} is the package of {@code refc}. + *
- If the retrieved member is not public, + * {@link SecurityManager#checkMemberAccess + * smgr.checkMemberAccess(defc, Member.DECLARED)} is called. + * (Note that {@code defc} might be the same as {@code refc}.) + *
- If the retrieved member is not public, + * and if {@code defc} and {@code refc} are in different class loaders, + * and if the class loader of the lookup class is not + * the same as or an ancestor of the class loader of {@code defc}, + * then {@link SecurityManager#checkPackageAccess + * smgr.checkPackageAccess(defcPkg)} is called, + * where {@code defcPkg} is the package of {@code defc}. + *
* The class implies a maximum level of access permission, * but the permissions may be additionally limited by the bitmask - * {@link #lookupModes}, which controls whether non-public members + * {@link #lookupModes lookupModes}, which controls whether non-public members * can be accessed. */ public Class> lookupClass() { @@ -211,7 +375,7 @@ public class MethodHandles { return (allowedModes == TRUSTED) ? null : lookupClass; } - /** Which types of members can this lookup object produce? + /** Tells which access-protection classes of members this lookup object can produce. * The result is a bit-mask of the bits * {@linkplain #PUBLIC PUBLIC (0x01)}, * {@linkplain #PRIVATE PRIVATE (0x02)}, @@ -257,7 +421,7 @@ public class MethodHandles { } /** - * Create a lookup on the specified new lookup class. + * Creates a lookup on the specified new lookup class. * The resulting object will report the specified * class as its own {@link #lookupClass lookupClass}. *
@@ -275,6 +439,10 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) * + * + * @param requestedLookupClass the desired lookup class for the new lookup object + * @return a lookup object which reports the desired lookup class + * @throws NullPointerException if the argument is null */ public Lookup in(Class> requestedLookupClass) { requestedLookupClass.getClass(); // null check @@ -322,11 +490,12 @@ public class MethodHandles { } /** - * Display the name of the class from which lookups are to be made. + * Displays the name of the class from which lookups are to be made. * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.) * If there are restrictions on the access permitted to this lookup, * this is indicated by adding a suffix to the class name, consisting - * of a slash and a keyword. The keyword is chosen as follows: + * of a slash and a keyword. The keyword represents the strongest + * allowed access, and is chosen as follows: *
*
*- If no access is allowed, the suffix is "/noaccess". *
- If only public access is allowed, the suffix is "/public". @@ -337,26 +506,37 @@ public class MethodHandles { * access (public, package, private, and protected) is allowed. * In this case, no suffix is added. * This is true only of an object obtained originally from - * {@link java.dyn.MethodHandles#lookup() MethodHandles.lookup}. - * Objects created by {@link java.dyn.MethodHandles.Lookup#in() Lookup#in} + * {@link java.dyn.MethodHandles#lookup MethodHandles.lookup}. + * Objects created by {@link java.dyn.MethodHandles.Lookup#in Lookup.in} * always have restricted access, and will display a suffix. + *
+ * (It may seem strange that protected access should be + * stronger than private access. Viewed independently from + * package access, protected access is the first to be lost, + * because it requires a direct subclass relationship between + * caller and callee.) + * @see #in */ @Override public String toString() { String cname = lookupClass.getName(); switch (allowedModes) { - case TRUSTED: - return "/trusted"; // internal only + case 0: // no privileges + return cname + "/noaccess"; case PUBLIC: return cname + "/public"; case PUBLIC|PACKAGE: return cname + "/package"; - case 0: // no privileges - return cname + "/noaccess"; + case ALL_MODES & ~PROTECTED: + return cname + "/private"; case ALL_MODES: return cname; - default: - return cname + "/private"; + case TRUSTED: + return "/trusted"; // internal only; not exported + default: // Should not happen, but it's a bitfield... + cname = cname + "/" + Integer.toHexString(allowedModes); + assert(false) : cname; + return cname; } } @@ -371,29 +551,37 @@ public class MethodHandles { } /** - * Produce a method handle for a static method. + * Produces 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 {@link #findVirtual} or {@link #findSpecial}.) + * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial 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. + *
+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set. * @param refc the class from which the method is accessed * @param name the name of the method * @param type the type of the method * @return the desired method handle - * @exception NoAccessException if the method does not exist or access checking fails + * @throws NoSuchMethodException if the method does not exist + * @throws IllegalAccessException if access checking fails, or if the method is not {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ public - MethodHandle findStatic(Class> refc, String name, MethodType type) throws NoAccessException { + MethodHandle findStatic(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, true); checkMethod(refc, method, true); return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull()); } /** - * Produce a method handle for a virtual method. + * Produces a method handle for a virtual method. * The type of the method handle will be that of the method, * with the receiver type (usually {@code refc}) prepended. * The method and all its argument types must be accessible to the lookup class. @@ -403,13 +591,31 @@ public class MethodHandles { * implementation to enter. * (The dispatching action is identical with that performed by an * {@code invokevirtual} or {@code invokeinterface} instruction.) + *
+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set. + *
+ * Because of the general equivalence between {@code invokevirtual} + * instructions and method handles produced by {@code findVirtual}, + * if the class is {@code MethodHandle} and the name string is + * {@code invokeExact} or {@code invokeGeneric}, the resulting + * method handle is equivalent to one produced by + * {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker} or + * {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker} + * with the same {@code type} argument. + * * @param refc the class or interface 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 * @return the desired method handle - * @exception NoAccessException if the method does not exist or access checking fails + * @throws NoSuchMethodException if the method does not exist + * @throws IllegalAccessException if access checking fails, or if the method is {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findVirtual(Class> refc, String name, MethodType type) throws NoAccessException { + public MethodHandle findVirtual(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(refc, name, type, false); checkMethod(refc, method, false); MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); @@ -417,7 +623,7 @@ public class MethodHandles { } /** - * Produce a method handle which creates an object and initializes it, using + * Produces a method handle which creates an object and initializes it, using * the constructor of the specified type. * The parameter types of the method handle will be those of the constructor, * while the return type will be a reference to the constructor's class. @@ -426,23 +632,47 @@ public class MethodHandles { * immediately, before the method handle is returned. *
* Note: The requested type must have a return type of {@code void}. - * This is consistent with the JVM's treatment of constructor signatures. + * This is consistent with the JVM's treatment of constructor type descriptors. + *
+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the constructor's variable arity modifier bit ({@code 0x0080}) is set. * @param refc the class or interface from which the method is accessed * @param type the type of the method, with the receiver argument omitted, and a void return type * @return the desired method handle - * @exception NoAccessException if the method does not exist or access checking fails + * @throws NoSuchMethodException if the constructor does not exist + * @throws IllegalAccessException if access checking fails + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findConstructor(Class> refc, MethodType type) throws NoAccessException { + public MethodHandle findConstructor(Class> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { String name = "
"; MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); assert(ctor.isConstructor()); checkAccess(refc, ctor); MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); - return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH); + MethodHandle allocMH = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH); + return fixVarargs(allocMH, rawMH); + } + + /** Return a version of MH which matches matchMH w.r.t. isVarargsCollector. */ + private static MethodHandle fixVarargs(MethodHandle mh, MethodHandle matchMH) { + boolean va1 = mh.isVarargsCollector(); + boolean va2 = matchMH.isVarargsCollector(); + if (va1 == va2) { + return mh; + } else if (va2) { + MethodType type = mh.type(); + int arity = type.parameterCount(); + return mh.asVarargsCollector(type.parameterType(arity-1)); + } else { + throw new InternalError("already varargs, but template is not: "+mh); + } } /** - * Produce an early-bound method handle for a virtual method, + * Produces an early-bound method handle for a virtual method, * as if called from an {@code invokespecial} * instruction from {@code caller}. * The type of the method handle will be that of the method, @@ -458,15 +688,23 @@ public class MethodHandles { * If the explicitly specified caller class is not identical with the * lookup class, or if this lookup object does not have private access * privileges, the access fails. + * + * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set. * @param refc the class or interface from which the method is accessed * @param name the name of the method (which must not be "<init>") * @param type the type of the method, with the receiver argument omitted * @param specialCaller the proposed calling class to perform the {@code invokespecial} * @return the desired method handle - * @exception NoAccessException if the method does not exist or access checking fails + * @throws NoSuchMethodException if the method does not exist + * @throws IllegalAccessException if access checking fails + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ public MethodHandle findSpecial(Class> refc, String name, MethodType type, - Class> specialCaller) throws NoAccessException { + Class> specialCaller) throws NoSuchMethodException, IllegalAccessException { checkSpecialCaller(specialCaller); MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller); checkMethod(refc, method, false); @@ -475,69 +713,89 @@ public class MethodHandles { } /** - * Produce a method handle giving read access to a non-static field. + * Produces a method handle giving read access to a non-static field. * The type of the method handle will have a return type of the field's * value type. * The method handle's single argument will be the instance containing * the field. * Access checking is performed immediately on behalf of the lookup class. + * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type * @return a method handle which can load values from the field - * @exception NoAccessException if access checking fails + * @throws NoSuchFieldException if the field does not exist + * @throws IllegalAccessException if access checking fails, or if the field is {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findGetter(Class> refc, String name, Class> type) throws NoAccessException { + public MethodHandle findGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException { return makeAccessor(refc, name, type, false, false); } /** - * Produce a method handle giving write access to a non-static field. + * Produces a method handle giving write access to a non-static field. * The type of the method handle will have a void return type. * The method handle will take two arguments, the instance containing * the field, and the value to be stored. * The second argument will be of the field's value type. * Access checking is performed immediately on behalf of the lookup class. + * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type * @return a method handle which can store values into the field - * @exception NoAccessException if access checking fails + * @throws NoSuchFieldException if the field does not exist + * @throws IllegalAccessException if access checking fails, or if the field is {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findSetter(Class> refc, String name, Class> type) throws NoAccessException { + public MethodHandle findSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException { return makeAccessor(refc, name, type, false, true); } /** - * Produce a method handle giving read access to a static field. + * Produces a method handle giving read access to a static field. * The type of the method handle will have a return type of the field's * value type. * The method handle will take no arguments. * Access checking is performed immediately on behalf of the lookup class. + * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type * @return a method handle which can load values from the field - * @exception NoAccessException if access checking fails + * @throws NoSuchFieldException if the field does not exist + * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findStaticGetter(Class> refc, String name, Class> type) throws NoAccessException { + public MethodHandle findStaticGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException { return makeAccessor(refc, name, type, true, false); } /** - * Produce a method handle giving write access to a static field. + * Produces a method handle giving write access to a static field. * The type of the method handle will have a void return type. * The method handle will take a single * argument, of the field's value type, the value to be stored. * Access checking is performed immediately on behalf of the lookup class. + * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type * @return a method handle which can store values into the field - * @exception NoAccessException if access checking fails + * @throws NoSuchFieldException if the field does not exist + * @throws IllegalAccessException if access checking fails, or if the field is not {@code static} + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle findStaticSetter(Class> refc, String name, Class> type) throws NoAccessException { + public MethodHandle findStaticSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException { return makeAccessor(refc, name, type, true, true); } /** - * Produce an early-bound method handle for a non-static method. + * Produces an early-bound method handle for a non-static method. * 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. @@ -547,28 +805,47 @@ public class MethodHandles { * so that every call to the method handle will invoke the * requested method on the given receiver. *
- * This is equivalent to the following expression: - *
- * {@link #insertArguments insertArguments}({@link #findVirtual findVirtual}(defc, name, type), receiver) - *+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set + * and the trailing array argument is not the only argument. + * (If the trailing array argument is the only argument, + * the given receiver value will be bound to it.) + *+ * This is equivalent to the following code: + *
* 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. + * (Note that {@code bindTo} does not preserve variable arity.) * @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 * @return the desired method handle - * @exception NoAccessException if the method does not exist or access checking fails + * @throws NoSuchMethodException if the method does not exist + * @throws IllegalAccessException if access checking fails + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws NullPointerException if any argument is null */ - public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException { + public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class extends Object> refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(refc, name, type, false); checkMethod(refc, method, false); MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull()); MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver); if (bmh == null) - throw newNoAccessException(method, lookupClass()); - return bmh; + throw newNoAccessException(method, this); + if (dmh.type().parameterCount() == 0) + return dmh; // bound the trailing parameter; no varargs possible + return fixVarargs(bmh, dmh); } /** @@ -581,11 +858,16 @@ public class MethodHandles { * If the method's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. * If m is not public, do not share the resulting handle with untrusted parties. + *+MethodHandle mh0 = {@link #findVirtual findVirtual}(defc, name, type); +MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver); +MethodType mt1 = mh1.type(); +if (mh0.isVarargsCollector() && mt1.parameterCount() > 0) { + mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1)); +return mh1; + *+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set. * @param m the reflected method * @return a method handle which can invoke the reflected method - * @exception NoAccessException if access checking fails + * @throws IllegalAccessException if access checking fails + * @throws NullPointerException if the argument is null */ - public MethodHandle unreflect(Method m) throws NoAccessException { + public MethodHandle unreflect(Method m) throws IllegalAccessException { MemberName method = new MemberName(m); assert(method.isMethod()); if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); @@ -595,7 +877,7 @@ public class MethodHandles { } /** - * Produce a method handle for a reflected method. + * Produces a method handle for a reflected method. * It will bypass checks for overriding methods on the receiver, * as if by a {@code invokespecial} instruction from within the {@code specialCaller}. * The type of the method handle will be that of the method, @@ -603,12 +885,17 @@ public class MethodHandles { * If the method'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. + *
+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the method's variable arity modifier bit ({@code 0x0080}) is set. * @param m the reflected method * @param specialCaller the class nominally calling the method * @return a method handle which can invoke the reflected method - * @exception NoAccessException if access checking fails + * @throws IllegalAccessException if access checking fails + * @throws NullPointerException if any argument is null */ - public MethodHandle unreflectSpecial(Method m, Class> specialCaller) throws NoAccessException { + public MethodHandle unreflectSpecial(Method m, Class> specialCaller) throws IllegalAccessException { checkSpecialCaller(specialCaller); MemberName method = new MemberName(m); assert(method.isMethod()); @@ -619,7 +906,7 @@ public class MethodHandles { } /** - * Produce a method handle for a reflected constructor. + * Produces a method handle for a reflected 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, @@ -628,20 +915,26 @@ public class MethodHandles { *
* If the constructor's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. + *
+ * The returned method handle will have + * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if + * the constructor's variable arity modifier bit ({@code 0x0080}) is set. * @param c the reflected constructor * @return a method handle which can invoke the reflected constructor - * @exception NoAccessException if access checking fails + * @throws IllegalAccessException if access checking fails + * @throws NullPointerException if the argument is null */ - public MethodHandle unreflectConstructor(Constructor c) throws NoAccessException { + public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { MemberName ctor = new MemberName(c); assert(ctor.isConstructor()); if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor); MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull()); - return MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor); + MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor); + return fixVarargs(allocator, rawCtor); } /** - * Produce a method handle giving read access to a reflected field. + * Produces 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. * If the field is static, the method handle will take no arguments. @@ -651,14 +944,15 @@ public class MethodHandles { * access checking is performed immediately on behalf of the lookup class. * @param f the reflected field * @return a method handle which can load values from the reflected field - * @exception NoAccessException if access checking fails + * @throws IllegalAccessException if access checking fails + * @throws NullPointerException if the argument is null */ - public MethodHandle unreflectGetter(Field f) throws NoAccessException { + public MethodHandle unreflectGetter(Field f) throws IllegalAccessException { return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false); } /** - * Produce a method handle giving write access to a reflected field. + * Produces a method handle giving write access to a reflected field. * The type of the method handle will have a void return type. * If the field is static, the method handle will take a single * argument, of the field's value type, the value to be stored. @@ -668,40 +962,47 @@ public class MethodHandles { * access checking is performed immediately on behalf of the lookup class. * @param f the reflected field * @return a method handle which can store values into the reflected field - * @exception NoAccessException if access checking fails + * @throws IllegalAccessException if access checking fails + * @throws NullPointerException if the argument is null */ - public MethodHandle unreflectSetter(Field f) throws NoAccessException { + public MethodHandle unreflectSetter(Field f) throws IllegalAccessException { return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true); } /// Helper methods, all package-private. - MemberName resolveOrFail(Class> refc, String name, Class> type, boolean isStatic) throws NoAccessException { + MemberName resolveOrFail(Class> refc, String name, Class> type, boolean isStatic) throws NoSuchFieldException, IllegalAccessException { checkSymbolicClass(refc); // do this before attempting to resolve + name.getClass(); type.getClass(); // NPE int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); + return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), + NoSuchFieldException.class); } - MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic) throws NoAccessException { + MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic) throws NoSuchMethodException, IllegalAccessException { checkSymbolicClass(refc); // do this before attempting to resolve + name.getClass(); type.getClass(); // NPE int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull()); + return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(), + NoSuchMethodException.class); } MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic, - boolean searchSupers, Class> specialCaller) throws NoAccessException { + boolean searchSupers, Class> specialCaller) throws NoSuchMethodException, IllegalAccessException { checkSymbolicClass(refc); // do this before attempting to resolve + name.getClass(); type.getClass(); // NPE int mods = (isStatic ? Modifier.STATIC : 0); - return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller); + return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller, + NoSuchMethodException.class); } - void checkSymbolicClass(Class> refc) throws NoAccessException { + void checkSymbolicClass(Class> refc) throws IllegalAccessException { Class> caller = lookupClassOrNull(); if (caller != null && !VerifyAccess.isClassAccessible(refc, caller)) - throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller); + throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), this); } - void checkMethod(Class> refc, MemberName m, boolean wantStatic) throws NoAccessException { + void checkMethod(Class> refc, MemberName m, boolean wantStatic) throws IllegalAccessException { String message; if (m.isConstructor()) message = "expected a method, not a constructor"; @@ -711,10 +1012,10 @@ public class MethodHandles { message = wantStatic ? "expected a static method" : "expected a non-static method"; else { checkAccess(refc, m); return; } - throw newNoAccessException(message, m, lookupClass()); + throw newNoAccessException(message, m, this); } - void checkAccess(Class> refc, MemberName m) throws NoAccessException { + void checkAccess(Class> refc, MemberName m) throws IllegalAccessException { int allowedModes = this.allowedModes; if (allowedModes == TRUSTED) return; int mods = m.getModifiers(); @@ -729,22 +1030,25 @@ public class MethodHandles { && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass())) // Protected members can also be checked as if they were package-private. return; - throw newNoAccessException(accessFailedMessage(refc, m), m, lookupClass()); + throw newNoAccessException(accessFailedMessage(refc, m), m, this); } String accessFailedMessage(Class> refc, MemberName m) { Class> defc = m.getDeclaringClass(); int mods = m.getModifiers(); - if (!VerifyAccess.isClassAccessible(defc, lookupClass())) + // check the class first: + boolean classOK = (Modifier.isPublic(defc.getModifiers()) && + (defc == refc || + Modifier.isPublic(refc.getModifiers()))); + if (!classOK && (allowedModes & PACKAGE) != 0) { + classOK = (VerifyAccess.isClassAccessible(defc, lookupClass()) && + (defc == refc || + VerifyAccess.isClassAccessible(refc, lookupClass()))); + } + if (!classOK) return "class is not public"; - if (refc != defc && !VerifyAccess.isClassAccessible(refc, lookupClass())) - return "symbolic reference "+refc.getName()+" is not public"; if (Modifier.isPublic(mods)) return "access to public member failed"; // (how?) - else if (allowedModes == PUBLIC) - return "member is not public"; - else if (allowedModes == 0) - return "attempted member access through a non-public class"; if (Modifier.isPrivate(mods)) return "member is private"; if (Modifier.isProtected(mods)) @@ -754,17 +1058,17 @@ public class MethodHandles { private static final boolean ALLOW_NESTMATE_ACCESS = false; - void checkSpecialCaller(Class> specialCaller) throws NoAccessException { + void checkSpecialCaller(Class> specialCaller) throws IllegalAccessException { if (allowedModes == TRUSTED) return; if ((allowedModes & PRIVATE) == 0 || (specialCaller != lookupClass() && !(ALLOW_NESTMATE_ACCESS && VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) throw newNoAccessException("no private access for invokespecial", - new MemberName(specialCaller), lookupClass()); + new MemberName(specialCaller), this); } - MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws NoAccessException { + MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException { // The accessing class only has the right to use a protected member // on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc. if (!method.isProtected() || method.isStatic() @@ -776,7 +1080,7 @@ public class MethodHandles { else return restrictReceiver(method, mh, lookupClass()); } - MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class> caller) throws NoAccessException { + MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class> caller) throws IllegalAccessException { assert(!method.isStatic()); Class> defc = method.getDeclaringClass(); // receiver type of mh is too wide if (defc.isInterface() || !defc.isAssignableFrom(caller)) { @@ -785,22 +1089,23 @@ public class MethodHandles { MethodType rawType = mh.type(); if (rawType.parameterType(0) == caller) return mh; MethodType narrowType = rawType.changeParameterType(0, caller); - return MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); + MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null); + return fixVarargs(narrowMH, mh); } MethodHandle makeAccessor(Class> refc, String name, Class> type, - boolean isStatic, boolean isSetter) throws NoAccessException { + boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(refc, name, type, isStatic); if (isStatic != field.isStatic()) throw newNoAccessException(isStatic ? "expected a static field" : "expected a non-static field", - field, lookupClass()); + field, this); return makeAccessor(refc, field, false, isSetter); } MethodHandle makeAccessor(Class> refc, MemberName field, - boolean trusted, boolean isSetter) throws NoAccessException { + boolean trusted, boolean isSetter) throws IllegalAccessException { assert(field.isField()); if (trusted) return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull()); @@ -811,12 +1116,13 @@ public class MethodHandles { } /** - * Produce a method handle giving read access to elements of an array. + * Produces a method handle giving read access to elements of an array. * The type of the method handle will have a return type of the array's * element type. Its first argument will be the array type, * and the second will be {@code int}. * @param arrayClass an array type * @return a method handle which can load values from the given array type + * @throws NullPointerException if the argument is null * @throws IllegalArgumentException if arrayClass is not an array type */ public static @@ -825,11 +1131,12 @@ public class MethodHandles { } /** - * Produce a method handle giving write access to elements of an array. + * Produces a method handle giving write access to elements of an array. * The type of the method handle will have a void return type. * Its last argument will be the array's element type. * The first and second arguments will be the array type and int. * @return a method handle which can store values into the array type + * @throws NullPointerException if the argument is null * @throws IllegalArgumentException if arrayClass is not an array type */ public static @@ -840,47 +1147,7 @@ public class MethodHandles { /// method handle invocation (reflective style) /** - * Produce a method handle which will invoke any method handle of the - * given type on a standard set of {@code Object} type arguments. - * The resulting invoker will be a method handle with the following - * arguments: - *
- *
- *- a single {@code MethodHandle} target - *
- zero or more {@code Object} values (one for each argument in {@code type}) - *
- * The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with - * the indicated {@code type}. - * That is, if the target is exactly of the given {@code type}, it will behave - * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType} - * is used to convert the target to the required {@code type}. - *
- * The type of the returned invoker will not be the given {@code type}, but rather - * will have all parameter and return types replaced by {@code Object}. - *
- * Before invoking its target, the invoker will apply reference casts as - * necessary and unbox and widen 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 method is equivalent to the following code (though it may be more efficient): - *
- * @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) { - return invokers(type).genericInvoker(); - } - - /** - * Produce a method handle which will invoke any method handle of the + * Produces a method handle which will invoke any method handle of the * given {@code 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 @@ -891,10 +1158,10 @@ public class MethodHandles { *- * MethodHandle invoker = lookup().findVirtual(MethodHandle.class, "invokeGeneric", type); - * MethodType genericType = type.generic(); - * genericType = genericType.insertParameterType(0, MethodHandle.class); - * return invoker.asType(genericType); - *- an {@code Object[]} array containing more arguments *
- * The invoker will behave like a call to {@link MethodHandle.invokeGeneric} with + * The invoker will behave like a call to {@link MethodHandle#invokeGeneric invokeGeneric} with * the indicated {@code type}. * That is, if the target is exactly of the given {@code type}, it will behave - * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle.asType} + * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType} * is used to convert the target to the required {@code type}. *
* The type of the returned invoker will not be the given {@code type}, but rather @@ -909,34 +1176,56 @@ public class MethodHandles { *
* This method is equivalent to the following code (though it may be more efficient): *
+ *- * MethodHandle invoker = lookup().findVirtual(MethodHandle.class, "invokeGeneric", type); - * MethodType vaType = MethodType.genericMethodType(objectArgCount, true); - * vaType = vaType.insertParameterType(0, MethodHandle.class); - * int spreadArgCount = type.parameterCount - objectArgCount; - * invoker = invoker.asSpreader(Object.class, spreadArgCount); - * return invoker.asType(vaType); +MethodHandle invoker = MethodHandles.genericInvoker(type); +int spreadArgCount = type.parameterCount - objectArgCount; +invoker = invoker.asSpreader(Object[].class, spreadArgCount); +return invoker; *+ * This method throws no reflective or security exceptions. * @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) { + MethodHandle spreadInvoker(MethodType type, int objectArgCount) { if (objectArgCount < 0 || objectArgCount > type.parameterCount()) throw new IllegalArgumentException("bad argument count "+objectArgCount); - return invokers(type).varargsInvoker(objectArgCount); + return invokers(type).spreadInvoker(objectArgCount); } /** - * 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 + * Produces a special invoker method handle which can be used to + * invoke any method handle of the given type, as if by {@code invokeExact}. + * 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 method is equivalent to the following code (though it may be more efficient): *
+ * + *- * lookup().findVirtual(MethodHandle.class, "invokeExact", type); +publicLookup().findVirtual(MethodHandle.class, "invokeExact", type) *+ * Discussion: + * Invoker method handles can be useful when working with variable method handles + * of unknown types. + * For example, to emulate an {@code invokeExact} call to a variable method + * handle {@code M}, extract its type {@code T}, + * look up the invoker method {@code X} for {@code T}, + * and call the invoker method, as {@code X.invokeGeneric(T, A...)}. + * (It would not work to call {@code X.invokeExact}, since the type {@code T} + * is unknown.) + * If spreading, collecting, or other argument transformations are required, + * they can be applied once to the invoker {@code X} and reused on many {@code M} + * method handle values, as long as they are compatible with the type of {@code X}. + *
+ * (Note: The invoker method is not available via the Core Reflection API. + * An attempt to call {@linkplain java.lang.reflect.Method#invoke Method.invoke} + * on the declared {@code invokeExact} or {@code invokeGeneric} method will raise an + * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.) + *
+ * This method throws no reflective or security exceptions. * @param type the desired target type * @return a method handle suitable for invoking any method handle of the given type */ @@ -945,12 +1234,38 @@ public class MethodHandles { return invokers(type).exactInvoker(); } + /** + * Produces a special invoker method handle which can be used to + * invoke any method handle of the given type, as if by {@code invokeGeneric}. + * 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}. + *
+ * Before invoking its target, the invoker will apply reference casts as + * necessary and unbox and widen primitive arguments, as if by {@link #convertArguments 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 method is equivalent to the following code (though it may be more efficient): + *
+ *+publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type) + *+ * This method throws no reflective or security exceptions. + * @param type the desired target type + * @return a method handle suitable for invoking any method handle convertible to the given type + */ + static public + MethodHandle genericInvoker(MethodType type) { + return invokers(type).genericInvoker(); + } + static Invokers invokers(MethodType type) { return MethodTypeImpl.invokers(IMPL_TOKEN, type); } /** - * WORK IN PROGRESS: * Perform value checking, exactly as if for an adapted method handle. * It is assumed that the given value is either null, of type T0, * or (if T0 is primitive) of the wrapper type corresponding to T0. @@ -1021,7 +1336,7 @@ public class MethodHandles { /// method handle modification (creation from other method handles) /** - * Produce a method handle which adapts the type of the + * Produces a method handle which adapts the type of the * 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 report a type @@ -1060,6 +1375,7 @@ public class MethodHandles { * @return a method handle which delegates to {@code target} after performing * any necessary argument conversions, and arranges for any * necessary return value conversions + * @throws NullPointerException if either argument is null * @throws WrongMethodTypeException if the conversion cannot be made * @see MethodHandle#asType * @see MethodHandles#explicitCastArguments @@ -1081,7 +1397,7 @@ public class MethodHandles { } /** - * Produce a method handle which adapts the type of the + * Produces a method handle which adapts the type of the * 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 report a type @@ -1113,6 +1429,7 @@ public class MethodHandles { * @return a method handle which delegates to {@code target} after performing * any necessary argument conversions, and arranges for any * necessary return value conversions + * @throws NullPointerException if either argument is null * @throws WrongMethodTypeException if the conversion cannot be made * @see MethodHandle#asType * @see MethodHandles#convertArguments @@ -1160,7 +1477,7 @@ public class MethodHandles { */ /** - * Produce a method handle which adapts the calling sequence of the + * Produces a method handle which adapts the calling sequence of the * given method handle to a new type, by reordering the arguments. * The resulting method handle is guaranteed to report a type * which is equal to the desired new type. @@ -1208,6 +1525,7 @@ assert((int)twice.invokeExact(21) == 42); * @param reorder a string which controls the reordering * @return a method handle which delegates to {@code target} after it * drops unused arguments and moves and/or duplicates the other arguments + * @throws NullPointerException if any argument is null */ public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { @@ -1233,11 +1551,10 @@ assert((int)twice.invokeExact(21) == 42); } /** - * METHOD WILL BE REMOVED FOR PFD: * Equivalent to the following code: *
* int spreadPos = newType.parameterCount() - 1; - * Class> spreadType = newType.parameterType(spreadPos); + * Class<?> spreadType = newType.parameterType(spreadPos); * int spreadCount = target.type().parameterCount() - spreadPos; * MethodHandle adapter = target.asSpreader(spreadType, spreadCount); * adapter = adapter.asType(newType); @@ -1247,9 +1564,8 @@ assert((int)twice.invokeExact(21) == 42); * @param newType the expected type of the new method handle * @return a method handle which spreads its final argument, * before calling the original method handle - * @deprecated Use {@link MethodHandle#asSpreader} */ - public static + /*non-public*/ static MethodHandle spreadArguments(MethodHandle target, MethodType newType) { MethodType oldType = target.type(); int inargs = newType.parameterCount(); @@ -1267,11 +1583,10 @@ assert((int)twice.invokeExact(21) == 42); } /** - * METHOD WILL BE REMOVED FOR PFD: * Equivalent to the following code: *+ * * @param target the method handle to invoke after arguments are filtered * @param pos the position of the first argument to filter * @param filters method handles to call initially on filtered arguments * @return method handle which incorporates the specified argument filtering logic - * @throws IllegalArgumentException if an element of {@code filters} is null or - * does not match a corresponding argument type of {@code target} as described above + * @throws NullPointerException if the {@code target} argument is null + * or if the {@code filters} array is null + * @throws IllegalArgumentException if a non-null element of {@code filters} + * does not match a corresponding argument type of {@code target} as described above, + * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()} */ public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) { @@ -1557,17 +1844,18 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY MethodHandle adapter = target; MethodType adapterType = targetType; int maxPos = targetType.parameterCount(); - int curPos = pos; + if (pos + filters.length > maxPos) + throw newIllegalArgumentException("too many filters"); + int curPos = pos-1; // pre-incremented for (MethodHandle filter : filters) { - if (curPos >= maxPos) - throw newIllegalArgumentException("too many filters"); + curPos += 1; + if (filter == null) continue; // ignore null elements of filters MethodType filterType = filter.type(); if (filterType.parameterCount() != 1 || filterType.returnType() != targetType.parameterType(curPos)) throw newIllegalArgumentException("target and filter types do not match"); adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0)); adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, curPos, filter); - curPos += 1; } MethodType midType = adapter.type(); if (midType != adapterType) @@ -1602,7 +1890,8 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * @param target the method handle to invoke before filtering the return value * @param filter method handle to call on the return value * @return method handle which incorporates the specified return value filtering logic - * @throws IllegalArgumentException if {@code filter} is null or + * @throws NullPointerException if either argument is null + * @throws IllegalArgumentException if {@code filter} * does not match the return type of {@code target} as described above */ public static @@ -1612,9 +1901,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 if (filterType.parameterCount() != 1 || filterType.parameterType(0) != targetType.returnType()) throw newIllegalArgumentException("target and filter types do not match"); + // result = fold( lambda(retval, arg...) { filter(retval) }, + // lambda( arg...) { target(arg...) } ) // FIXME: Too many nodes here. - MethodHandle returner = dropArguments(filter, 0, targetType.parameterList()); - return foldArguments(returner, exactInvoker(target.type()).bindTo(target)); + MethodHandle returner = dropArguments(filter, 1, targetType.parameterList()); + return foldArguments(returner, target); } /** @@ -1637,7 +1928,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * (Note that {@link #dropArguments(MethodHandle,int,List) 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 MethodHandle#asCollector} instead, since those + * consider using {@link MethodHandle#asCollector asCollector} instead, since those * arguments will not need to be live on the stack on entry to the * target.) ** int collectPos = target.type().parameterCount() - 1; - * Class> collectType = target.type().parameterType(collectPos); + * Class<?> collectType = target.type().parameterType(collectPos); * if (!collectType.isArray()) collectType = Object[].class; * int collectCount = newType.parameterCount() - collectPos; * MethodHandle adapter = target.asCollector(collectType, collectCount); @@ -1282,9 +1597,8 @@ assert((int)twice.invokeExact(21) == 42); * @param newType the expected type of the new method handle * @return a method handle which collects some trailing argument * into an array, before calling the original method handle - * @deprecated Use {@link MethodHandle#asCollector} instead. */ - public static + /*non-public*/ static MethodHandle collectArguments(MethodHandle target, MethodType newType) { MethodType oldType = target.type(); int inargs = newType.parameterCount(); @@ -1301,7 +1615,7 @@ assert((int)twice.invokeExact(21) == 42); } /** - * Produce a method handle of the requested return type which returns the given + * Produces a method handle of the requested return type which returns the given * constant value every time it is invoked. ** Before the method handle is returned, the passed-in value is converted to the requested type. @@ -1312,12 +1626,15 @@ assert((int)twice.invokeExact(21) == 42); * @param type the return type of the desired method handle * @param value the value to return * @return a method handle of the given return type and no arguments, which always returns the given value - * @throws WrongMethodTypeException if the value cannot be converted to the required return type + * @throws NullPointerException if the {@code type} argument is null + * @throws ClassCastException if the value cannot be converted to the required return type + * @throws IllegalArgumentException if the given type is {@code void.class} */ public static MethodHandle constant(Class> type, Object value) { if (type.isPrimitive()) { - if (type == void.class) return identity(type); + if (type == void.class) + throw newIllegalArgumentException("void type"); Wrapper w = Wrapper.forPrimitiveType(type); return identity(type).bindTo(w.convert(value, type)); } else { @@ -1326,64 +1643,22 @@ assert((int)twice.invokeExact(21) == 42); } /** - * Produce a method handle of the requested type which returns the given - * constant value every time it is invoked. - *
- * Before the method handle is returned, the passed-in value is converted to the requested return type, - * as if by {@link #explicitCastArguments #explicitCastArguments}. - * That is, if the return type is primitive, the value is unboxed, - * and the primitive value is widened and/or narrowed. - * Otherwise, reference conversions are attempted. - * @param type the type of the desired method handle - * @param value the value to return - * @return a method handle of the given return type and no arguments, which always returns the given value - * @throws WrongMethodTypeException if the value cannot be converted to the required return type + * Produces a method handle which returns its sole argument when invoked. + *
The identity function for {@code void} takes no arguments and returns no values. + * @param type the type of the sole parameter and return value of the desired method handle + * @return a unary method handle which accepts and returns the given type + * @throws NullPointerException if the argument is null + * @throws IllegalArgumentException if the given type is {@code void.class} */ public static - MethodHandle constant(MethodType type, Object value) { - MethodHandle target = constant(type.returnType(), value); - int len = type.parameterCount(); - if (len == 0) - return target.asType(type); - target = target.asType(type.dropParameterTypes(0, len)); - return dropArguments(target, 0, type.parameterList().subList(0, len)); - } - - /** - * Produce a method handle which returns its sole argument when invoked. - *
The identity function for {@code void} takes no arguments and returns no values. - * @param type the type of the sole parameter and return value of the desired method handle - * @return a unary method handle which accepts and returns the given type - */ - public static MethodHandle identity(Class> type) { + if (type == void.class) + throw newIllegalArgumentException("void type"); return ValueConversions.identity(type); } - /** - * Produce a method handle of the requested type which returns its argument when invoked. - * If the return type differs from the first argument type, the argument will be - * converted as if by {@link #explicitCastArguments explicitCastArguments}. - * If there are additional arguments beyond the first, they are discarded. - *
The identity function for {@code void} discards all its arguments. - * @param type the type of the desired method handle - * @return a method handle of the given type, which always returns its first argument - * @throws WrongMethodTypeException if the first argument cannot be converted to the required return type - */ - public static - MethodHandle identity(MethodType type) { - MethodHandle target = identity(type.returnType()); - int len = type.parameterCount(); - if (len == 1) - return explicitCastArguments(target, type); - if (len == 0) - throw new IllegalArgumentException("not enough arguments"); - target = explicitCastArguments(target, type.dropParameterTypes(1, len)); - return dropArguments(target, 1, type.parameterList().subList(1, len)); - } - /** - * Produce a method handle which calls the original method handle {@code target}, + * Produces 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 @@ -1404,6 +1679,7 @@ assert((int)twice.invokeExact(21) == 42); * @param values the series of arguments to insert * @return a method handle which inserts an additional argument, * before calling the original method handle + * @throws NullPointerException if the {@code target} argument or the {@code values} array is null * @see MethodHandle#bindTo */ public static @@ -1438,7 +1714,7 @@ assert((int)twice.invokeExact(21) == 42); } /** - * Produce a method handle which calls the original method handle, + * Produces a method handle which calls the original method handle, * after dropping the given argument(s) at the given position. * The type of the new method handle will insert the given argument * type(s), at that position, into the original handle's type. @@ -1470,6 +1746,9 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); * @param pos position of first argument to drop (zero for the leftmost) * @return a method handle which drops arguments of the given types, * before calling the original method handle + * @throws NullPointerException if the {@code target} argument is null, + * or if the {@code valueTypes} list or any of its elements is null + * @throws IllegalArgumentException if any of the {@code valueTypes} is {@code void.class} */ public static MethodHandle dropArguments(MethodHandle target, int pos, List
> valueTypes) { @@ -1487,7 +1766,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); } /** - * Produce a method handle which calls the original method handle, + * Produces a method handle which calls the original method handle, * after dropping the given argument(s) at the given position. * The type of the new method handle will insert the given argument * type(s), at that position, into the original handle's type. @@ -1500,6 +1779,9 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); * @param pos position of first argument to drop (zero for the leftmost) * @return a method handle which drops arguments of the given types, * before calling the original method handle + * @throws NullPointerException if the {@code target} argument is null, + * or if the {@code valueTypes} array or any of its elements is null + * @throws IllegalArgumentException if any of the {@code valueTypes} is {@code void.class} */ public static MethodHandle dropArguments(MethodHandle target, int pos, Class>... valueTypes) { @@ -1514,7 +1796,8 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); * * The pre-processing is performed by one or more method handles, * specified in the elements of the {@code filters} array. - * (If there are no elements in the array, the original target is returned.) + * Null arguments in the array are ignored, and the corresponding arguments left unchanged. + * (If there are no non-null elements in the array, the original target is returned.) * Each filter is applied to the corresponding argument of the adapter. *
* If a filter {@code F} applies to the {@code N}th argument of @@ -1544,12 +1827,16 @@ assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY MethodHandle f2 = filterArguments(cat, 0, upcase, upcase); assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY *
@@ -1656,6 +1947,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * @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 NullPointerException if either argument is null * @throws IllegalArgumentException if the first argument type of * {@code target} is not the same as {@code combiner}'s return type, * or if the following argument types of {@code target} @@ -1704,6 +1996,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * @param target method handle to call if test passes * @param fallback method handle to call if test fails * @return method handle which incorporates the specified if/then/else logic + * @throws NullPointerException if any argument is null * @throws IllegalArgumentException if {@code test} does not return boolean, * or if all three method types do not match (with the return * type of {@code test} changed to match that of {@code target}). @@ -1772,6 +2065,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * @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 NullPointerException if any argument is null * @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 @@ -1802,12 +2096,14 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 } /** - * Produce a method handle which will throw exceptions of the given {@code exType}. + * Produces 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. + * @return method handle which can throw the given exceptions + * @throws NullPointerException if either argument is null */ public static MethodHandle throwException(Class> returnType, Class extends Throwable> exType) { @@ -1815,18 +2111,43 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 } /** - * PROVISIONAL API, WORK IN PROGRESS: - * Produce a wrapper instance of the given "SAM" interface which redirects + * Produces an instance of the given "SAM" interface which redirects * its calls to the given method handle. + *
* A SAM interface is an interface which declares a single abstract method. - * The type must be public. (No additional access checks are performed.) + * When determining the unique abstract method of a SAM interface, + * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode}) + * are disregarded. For example, {@link java.util.Comparator} is a SAM interface, + * even though it re-declares the {@code Object.equals} method. + * Also, if the SAM interface has a supertype, + * the SAM interface may override an inherited method. + * Any such overrides are respected, and the method handle will be accessible + * by either the inherited method or the SAM method. + * In particular, a {@linkplain java.lang.reflect.Method#isBridge bridge method} + * may be created if the methods have different return types. + *
+ * The type must be public. No additional access checks are performed. *
* The resulting instance of the required SAM type will respond to * invocation of the SAM type's single abstract method by calling * the given {@code target} on the incoming arguments, * and returning or throwing whatever the {@code target} * returns or throws. The invocation will be as if by - * {@code target.invokeExact}. + * {@code target.invokeGeneric}. + * The target's type will be checked before the SAM + * instance is created, as if by a call to {@code asType}, + * which may result in a {@code WrongMethodTypeException}. + *
+ * The wrapper instance will implement the requested SAM interface + * and its super-types, but no other SAM types. + * This means that the SAM instance will not unexpectedly + * pass an {@code instanceof} test for any unrequested type. + *
+ * Implementation Note: + * Therefore, each SAM instance must implement a unique SAM type. + * Implementations may not bundle together + * multiple SAM types onto single implementation classes + * in the style of {@link java.awt.AWTEventMulticaster}. *
* The method handle may throw an undeclared exception, * which means any checked exception (or other checked throwable) @@ -1835,54 +2156,46 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException} * and thrown in that wrapped form. *
- * The wrapper instance is guaranteed to be of a non-public - * implementation class C in a package containing no classes - * or methods except system-defined classes and methods. - * The implementation class C will have no public supertypes - * or public methods beyond the following: - *
- *
- *- the SAM type itself and any methods in the SAM type - *
- the supertypes of the SAM type (if any) and their methods - *
- {@link Object} and its methods - *
- {@link java.dyn.AsInstanceObject AsInstanceObject} and its methods
- *- * (Note: When determining the unique abstract method of a SAM interface, - * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode}) - * are disregarded. For example, {@link java.util.Comparator} is a SAM interface, - * even though it re-declares the {@code Object.equals} method.) - *
- * No stable mapping is promised between the SAM type and - * the implementation class C. Over time, several implementation - * classes might be used for the same SAM type. - *
- * This method is not guaranteed to return a distinct - * wrapper object for each separate call. If the implementation is able - * to prove that a wrapper of the required SAM type - * has already been created for a given - * method handle, or for another method handle with the - * same behavior, the implementation may return that wrapper in place of - * a new wrapper. + * Like {@link java.lang.Integer#valueOf Integer.valueOf}, + * {@code asInstance} is a factory method whose results are defined + * by their behavior. + * It is not guaranteed to return a new instance for every call. *
- * This method is designed to apply to common use cases - * where a single method handle must interoperate with - * a type (class or interface) that implements a function-like - * API. Additional variations, such as SAM classes with - * private constructors, or interfaces with multiple but related - * entry points, must be covered by hand-written or automatically - * generated adapter classes. In those cases, consider implementing - * {@link java.dyn.MethodHandles.AsInstanceObject AsInstanceObject} - * in the adapters, so that generic code can extract the underlying - * method handle without knowing where the SAM adapter came from. + * Future versions of this API may accept additional types, + * such as abstract classes with single abstract methods. + * Future versions of this API may also equip wrapper instances + * with one or more additional public "marker" interfaces. + * * @param target the method handle to invoke from the wrapper * @param samType the desired type of the wrapper, a SAM type * @return a correctly-typed wrapper for the given {@code target} - * @throws IllegalArgumentException if the {@code target} throws - * an undeclared exception + * @throws NullPointerException if either argument is null + * @throws IllegalArgumentException if the {@code samType} is not a + * valid argument to this method + * @throws WrongMethodTypeException if the {@code target} cannot + * be converted to the type required by the SAM type */ - // ISSUE: Should we delegate equals/hashCode to the targets? - // Not useful unless there is a stable equals/hashCode behavior - // for MethodHandle, but there isn't. + // Other notes to implementors: + //
+ // No stable mapping is promised between the SAM type and + // the implementation class C. Over time, several implementation + // classes might be used for the same SAM type. + //
+ // If the implementation is able + // to prove that a wrapper of the required SAM type + // has already been created for a given + // method handle, or for another method handle with the + // same behavior, the implementation may return that wrapper in place of + // a new wrapper. + //
+ // This method is designed to apply to common use cases + // where a single method handle must interoperate with + // an interface that implements a function-like + // API. Additional variations, such as SAM classes with + // private constructors, or interfaces with multiple but related + // entry points, must be covered by hand-written or automatically + // generated adapter classes. + // public static
T asInstance(final MethodHandle target, final Class samType) { // POC implementation only; violates the above contract several ways @@ -1890,22 +2203,23 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 if (sam == null) throw new IllegalArgumentException("not a SAM type: "+samType.getName()); MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes()); - if (!samMT.equals(target.type())) - throw new IllegalArgumentException("wrong method type: "+target+" should match "+sam); + MethodHandle checkTarget = target.asType(samMT); // make throw WMT + checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); + final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, samMT.parameterCount()); return samType.cast(Proxy.newProxyInstance( samType.getClassLoader(), - new Class[]{ samType, AsInstanceObject.class }, + new Class[]{ samType, WrapperInstance.class }, new InvocationHandler() { private Object getArg(String name) { - if ((Object)name == "getAsInstanceTarget") return target; - if ((Object)name == "getAsInstanceType") return samType; + if ((Object)name == "getWrapperInstanceTarget") return target; + if ((Object)name == "getWrapperInstanceType") return samType; throw new AssertionError(); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getDeclaringClass() == AsInstanceObject.class) + if (method.getDeclaringClass() == WrapperInstance.class) return getArg(method.getName()); if (method.equals(sam)) - return target.invokeVarargs(args); + return vaTarget.invokeExact(args); if (isObjectMethod(method)) return callObjectMethod(this, method, args); throw new InternalError(); @@ -1914,21 +2228,49 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 } /** - * PROVISIONAL API, WORK IN PROGRESS: - * Interface implemented by every object which is produced by {@link #asInstance asInstance}. - * The methods of this interface allow a caller to recover the parameters - * to {@code asInstance}. - * This allows applications to repeatedly convert between method handles - * and SAM objects, without the risk of creating unbounded delegation chains. + * Determine if the given object was produced by a call to {@link #asInstance asInstance}. + * @param x any reference + * @return true if the reference is not null and points to an object produced by {@code asInstance} */ - public interface AsInstanceObject { - /** Produce or recover a target method handle which is behaviorally - * equivalent to the SAM method of this object. - */ - public MethodHandle getAsInstanceTarget(); - /** Recover the SAM type for which this object was created. - */ - public Class> getAsInstanceType(); + public static + boolean isWrapperInstance(Object x) { + return x instanceof WrapperInstance; + } + + private static WrapperInstance asWrapperInstance(Object x) { + try { + if (x != null) + return (WrapperInstance) x; + } catch (ClassCastException ex) { + } + throw new IllegalArgumentException("not a wrapper instance"); + } + + /** + * Produces or recovers a target method handle which is behaviorally + * equivalent to the SAM method of this wrapper instance. + * The object {@code x} must have been produced by a call to {@link #asInstance asInstance}. + * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. + * @param x any reference + * @return a method handle implementing the SAM method + * @throws IllegalArgumentException if the reference x is not to a wrapper instance + */ + public static + MethodHandle wrapperInstanceTarget(Object x) { + return asWrapperInstance(x).getWrapperInstanceTarget(); + } + + /** + * Recover the SAM type for which this wrapper instance was created. + * The object {@code x} must have been produced by a call to {@link #asInstance asInstance}. + * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. + * @param x any reference + * @return the SAM type for which the wrapper was created + * @throws IllegalArgumentException if the reference x is not to a wrapper instance + */ + public static + Class> wrapperInstanceType(Object x) { + return asWrapperInstance(x).getWrapperInstanceType(); } private static @@ -1991,7 +2333,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 } /*non-public*/ - static MethodHandle withTypeHandler(MethodHandle target, MethodHandle typeHandler) { - return MethodHandleImpl.withTypeHandler(IMPL_TOKEN, target, typeHandler); + static MethodHandle asVarargsCollector(MethodHandle target, Class> arrayType) { + return MethodHandleImpl.asVarargsCollector(IMPL_TOKEN, target, arrayType); } } diff --git a/src/share/classes/java/dyn/MethodType.java b/src/share/classes/java/dyn/MethodType.java index 32f3a196b537dec067511a2491e1ea50641b6c8d..a7baf7c634e7892233bb45e2d8ec9a7205872f90 100644 --- a/src/share/classes/java/dyn/MethodType.java +++ b/src/share/classes/java/dyn/MethodType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.List; import sun.dyn.Access; import sun.dyn.Invokers; +import sun.dyn.MethodHandleImpl; import sun.dyn.MethodTypeImpl; import sun.dyn.util.BytecodeDescriptor; import static sun.dyn.MemberName.newIllegalArgumentException; @@ -41,8 +42,8 @@ import static sun.dyn.MemberName.newIllegalArgumentException; * and expected by a method handle caller. Method types must be properly * matched between a method handle and all its callers, * and the JVM's operations enforce this matching at, specifically - * during calls to {@link MethodHandle#invokeExact} - * and {@link MethodHandle#invokeGeneric}, and during execution + * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact} + * and {@link MethodHandle#invokeGeneric MethodHandle.invokeGeneric}, and during execution * of {@code invokedynamic} instructions. * * The structure is a return type accompanied by any number of parameter types. @@ -70,8 +71,9 @@ import static sun.dyn.MemberName.newIllegalArgumentException; * with the instructions in a class file's constant pool. *
* Like classes and strings, method types can also be represented directly - * in a class file's constant pool as constants. The may be loaded by an {@code ldc} - * instruction which refers to a suitable {@code CONSTANT_MethodType} constant pool entry. + * in a class file's constant pool as constants. + * A method type may be loaded by an {@code ldc} instruction which refers + * to a suitable {@code CONSTANT_MethodType} constant pool entry. * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string. * For more details, see the package summary. *
@@ -82,9 +84,14 @@ import static sun.dyn.MemberName.newIllegalArgumentException; * @author John Rose, JSR 292 EG */ public final -class MethodType { +class MethodType implements java.io.Serializable { + private static final long serialVersionUID = 292L; // {rtype, {ptype...}} + + // The rtype and ptypes fields define the structural identity of the method type: private final Class> rtype; private final Class>[] ptypes; + + // The remaining fields are caches of various sorts: private MethodTypeForm form; // erased form, plus cached data about primitives private MethodType wrapAlt; // alternative wrapped/unwrapped version private Invokers invokers; // cache of handy higher-order adapters @@ -117,6 +124,9 @@ class MethodType { }); } + /** + * Check the given parameters for validity and store them into the final fields. + */ private MethodType(Class> rtype, Class>[] ptypes) { checkRtype(rtype); checkPtypes(ptypes); @@ -124,15 +134,32 @@ class MethodType { this.ptypes = ptypes; } - private void checkRtype(Class> rtype) { + private static void checkRtype(Class> rtype) { rtype.equals(rtype); // null check } - private void checkPtypes(Class>[] ptypes) { + private static int checkPtype(Class> ptype) { + ptype.getClass(); //NPE + if (ptype == void.class) + throw newIllegalArgumentException("parameter type cannot be void"); + if (ptype == double.class || ptype == long.class) return 1; + return 0; + } + /** Return number of extra slots (count of long/double args). */ + private static int checkPtypes(Class>[] ptypes) { + int slots = 0; for (Class> ptype : ptypes) { - ptype.equals(ptype); // null check - if (ptype == void.class) - throw newIllegalArgumentException("parameter type cannot be void"); + slots += checkPtype(ptype); } + checkSlotCount(ptypes.length + slots); + return slots; + } + private static void checkSlotCount(int count) { + if ((count & 0xFF) != count) + throw newIllegalArgumentException("bad parameter count "+count); + } + private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) { + if (num instanceof Integer) num = "bad index: "+num; + return new IndexOutOfBoundsException(num.toString()); } static final HashMap
internTable @@ -140,27 +167,39 @@ class MethodType { static final Class>[] NO_PTYPES = {}; - /** Find or create an instance of the given method type. + /** + * Find or create an instance of the given method type. * @param rtype the return type * @param ptypes the parameter types - * @return a method type with the given parts - * @throws NullPointerException if rtype or any ptype is null - * @throws IllegalArgumentException if any of the ptypes is void + * @return a method type with the given components + * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null + * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class} */ public static MethodType methodType(Class> rtype, Class>[] ptypes) { return makeImpl(rtype, ptypes, false); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */ + /** + * Finds or creates a method type with the given components. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * @return a method type with the given components + * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null + * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class} + */ public static - MethodType methodType(Class> rtype, List extends Class>> ptypes) { + 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); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * The leading parameter type is prepended to the remaining array. + /** + * Finds or creates a method type with the given components. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * The leading parameter type is prepended to the remaining array. + * @return a method type with the given components + * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null + * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class} */ public static MethodType methodType(Class> rtype, Class> ptype0, Class>... ptypes) { @@ -170,25 +209,37 @@ class MethodType { return makeImpl(rtype, ptypes1, true); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * The resulting method has no parameter types. + /** + * Finds or creates a method type with the given components. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * The resulting method has no parameter types. + * @return a method type with the given return value + * @throws NullPointerException if {@code rtype} is null */ public static MethodType methodType(Class> rtype) { return makeImpl(rtype, NO_PTYPES, true); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * The resulting method has the single given parameter type. + /** + * Finds or creates a method type with the given components. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * The resulting method has the single given parameter type. + * @return a method type with the given return value and parameter type + * @throws NullPointerException if {@code rtype} or {@code ptype0} is null + * @throws IllegalArgumentException if {@code ptype0} is {@code void.class} */ public static MethodType methodType(Class> rtype, Class> ptype0) { return makeImpl(rtype, new Class>[]{ ptype0 }, true); } - /** 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. + /** + * Finds or creates a method type with the given components. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * The resulting method has the same parameter types as {@code ptypes}, + * and the specified return type. + * @throws NullPointerException if {@code rtype} or {@code ptypes} is null */ public static MethodType methodType(Class> rtype, MethodType ptypes) { @@ -237,17 +288,20 @@ class MethodType { private static final MethodType[] objectOnlyTypes = new MethodType[20]; /** - * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * 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 {@code Object[]} * @return a totally generic method type, given only its count of parameters and varargs + * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 * @see #genericMethodType(int) */ public static MethodType genericMethodType(int objectArgCount, boolean varargs) { MethodType mt; + checkSlotCount(objectArgCount); int ivarargs = (!varargs ? 0 : 1); int ootIndex = objectArgCount*2 + ivarargs; if (ootIndex < objectOnlyTypes.length) { @@ -265,9 +319,12 @@ class MethodType { } /** + * Finds or creates a method type whose components are all {@code Object}. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * 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 + * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 * @see #genericMethodType(int, boolean) */ public static @@ -275,27 +332,41 @@ class MethodType { return genericMethodType(objectArgCount, false); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + /** + * Finds or creates a method type with a single different parameter type. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * @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 + * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()} + * @throws IllegalArgumentException if {@code nptype} is {@code void.class} + * @throws NullPointerException if {@code nptype} is null */ public MethodType changeParameterType(int num, Class> nptype) { if (parameterType(num) == nptype) return this; + checkPtype(nptype); Class>[] nptypes = ptypes.clone(); nptypes[num] = nptype; return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + /** + * Finds or creates a method type with additional parameter types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * @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 + * @param ptypesToInsert zero or more new parameter types to insert into the parameter list * @return the same type, except with the selected parameter(s) inserted + * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()} + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class} + * or if the resulting method type would have more than 255 parameter slots + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null */ public MethodType insertParameterTypes(int num, Class>... ptypesToInsert) { int len = ptypes.length; if (num < 0 || num > len) - throw newIllegalArgumentException("num="+num); //SPECME + throw newIndexOutOfBoundsException(num); + int ins = checkPtypes(ptypesToInsert); + checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins); int ilen = ptypesToInsert.length; if (ilen == 0) return this; Class>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen); @@ -304,40 +375,61 @@ class MethodType { return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list + /** + * Finds or creates a method type with additional parameter types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list * @return the same type, except with the selected parameter(s) appended + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class} + * or if the resulting method type would have more than 255 parameter slots + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null */ public MethodType appendParameterTypes(Class>... ptypesToInsert) { return insertParameterTypes(parameterCount(), ptypesToInsert); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list - * @return the same type, except with the selected parameter(s) appended - */ - public MethodType appendParameterTypes(List > ptypesToInsert) { - return insertParameterTypes(parameterCount(), ptypesToInsert); - } - - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + /** + * Finds or creates a method type with additional parameter types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * @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 + * @param ptypesToInsert zero or more new parameter types to insert into the parameter list * @return the same type, except with the selected parameter(s) inserted + * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()} + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class} + * or if the resulting method type would have more than 255 parameter slots + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null */ 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[])}. + /** + * Finds or creates a method type with additional parameter types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. + * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list + * @return the same type, except with the selected parameter(s) appended + * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class} + * or if the resulting method type would have more than 255 parameter slots + * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null + */ + public MethodType appendParameterTypes(List > ptypesToInsert) { + return insertParameterTypes(parameterCount(), ptypesToInsert); + } + + /** + * Finds or creates a method type with some parameter types omitted. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * @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 + * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()} + * or if {@code end} is negative or greater than {@code parameterCount()} + * or if {@code start} is greater than {@code end} */ 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 + throw newIndexOutOfBoundsException("start="+start+" end="+end); if (start == end) return this; Class>[] nptypes; if (start == 0) { @@ -361,17 +453,20 @@ class MethodType { return makeImpl(rtype, nptypes, true); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + /** + * Finds or creates a method type with a different return type. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * @param nrtype a return parameter type to replace the old one with * @return the same type, except with the return type change + * @throws NullPointerException if {@code nrtype} is null */ public MethodType changeReturnType(Class> nrtype) { if (returnType() == nrtype) return this; return makeImpl(nrtype, ptypes, true); } - /** Convenience method. - * Report if this type contains a primitive argument or return value. + /** + * Reports 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 */ @@ -379,8 +474,8 @@ class MethodType { return form.hasPrimitives(); } - /** Convenience method. - * Report if this type contains a wrapper argument or return value. + /** + * Reports 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 @@ -389,8 +484,9 @@ class MethodType { return unwrap() != this; } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * Erase all reference types to {@code Object}. + /** + * Erases all reference types to {@code Object}. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * All primitive types (including {@code void}) will remain unchanged. * @return a version of the original type with all reference types replaced */ @@ -398,8 +494,9 @@ class MethodType { return form.erasedType(); } - /** Convenience method for {@link #genericMethodType(int)}. - * Convert all types, both reference and primitive, to {@code Object}. + /** + * Converts all types, both reference and primitive, to {@code Object}. + * Convenience method for {@link #genericMethodType(int) genericMethodType}. * 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 @@ -408,8 +505,9 @@ class MethodType { return genericMethodType(parameterCount()); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * Convert all primitive types to their corresponding wrapper types. + /** + * Converts all primitive types to their corresponding wrapper types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * 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 @@ -420,8 +518,9 @@ class MethodType { return hasPrimitives() ? wrapWithPrims(this) : this; } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. + /** * Convert all wrapper types to their corresponding primitive types. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * 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 @@ -456,23 +555,33 @@ class MethodType { return uwt; } - /** @param num the index (zero-based) of the desired parameter type - * @return the selected parameter type + /** + * Returns the parameter type at the specified index, within this method type. + * @param num the index (zero-based) of the desired parameter type + * @return the selected parameter type + * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()} */ public Class> parameterType(int num) { return ptypes[num]; } - /** @return the number of parameter types */ + /** + * Returns the number of parameter types in this method type. + * @return the number of parameter types + */ public int parameterCount() { return ptypes.length; } - /** @return the return type */ + /** + * Returns the return type of this method type. + * @return the return type + */ public Class> returnType() { return rtype; } /** - * Convenience method to present the arguments as a list. + * Presents the parameter types as a list (a convenience method). + * The list will be immutable. * @return the parameter types (as an immutable list) */ public List > parameterList() { @@ -480,7 +589,7 @@ class MethodType { } /** - * Convenience method to present the arguments as an array. + * Presents the parameter types as an array (a convenience method). * Changes to the array will not result in changes to the type. * @return the parameter types (as a fresh copy if necessary) */ @@ -524,14 +633,14 @@ class MethodType { } /** + * Returns a string representation of the method type, + * of the form {@code "(PT0,PT1...)RT"}. * The string representation of a method type is a * parenthesis enclosed, comma separated list of type names, * followed immediately by the return type. * * Each type is represented by its * {@link java.lang.Class#getSimpleName simple name}. - * If a type name name is array, it the base type followed - * by [], rather than the Class.getName of the array type. */ @Override public String toString() { @@ -548,21 +657,22 @@ class MethodType { /// Queries which have to do with the bytecode architecture - /** The number of JVM stack slots required to invoke a method + /** Reports the number of JVM stack slots required to invoke a method * of this type. Note that (for historic reasons) the JVM requires * a second stack slot to pass long and double arguments. - * So this method returns {@link #parameterCount()} plus the + * So this method returns {@link #parameterCount() parameterCount} plus the * number of long and double parameters (if any). *
* This method is included for the benfit of applications that must * generate bytecodes that process method handles and invokedynamic. * @return the number of JVM stack slots for this type's parameters + * @deprecated Will be removed for PFD. */ public int parameterSlotCount() { return form.parameterSlotCount(); } - /** Number of JVM stack slots which carry all parameters including and after + /** Reports the 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 @@ -583,6 +693,8 @@ class MethodType { * @param num an index (zero-based, inclusive) within the parameter types * @return the index of the (shallowest) JVM stack slot transmitting the * given parameter + * @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()} + * @deprecated Will be removed for PFD. */ public int parameterSlotDepth(int num) { if (num < 0 || num > ptypes.length) @@ -590,7 +702,7 @@ class MethodType { return form.parameterToArgSlot(num-1); } - /** The number of JVM stack slots required to receive a return value + /** Reports the number of JVM stack slots required to receive a return value * from a method of this type. * If the {@link #returnType() return type} is void, it will be zero, * else if the return type is long or double, it will be two, else one. @@ -598,13 +710,15 @@ class MethodType { * This method is included for the benfit of applications that must * generate bytecodes that process method handles and invokedynamic. * @return the number of JVM stack slots (0, 1, or 2) for this type's return value + * @deprecated Will be removed for PFD. */ public int returnSlotCount() { return form.returnSlotCount(); } - /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. - * Find or create an instance of the given method type. + /** + * Find or create an instance of a method type, given the spelling of its bytecode descriptor. + * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * Any class or interface name embedded in the descriptor string * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)} * on the given loader (or if it is null, on the system class loader). @@ -614,10 +728,10 @@ class MethodType { * not all reachable from a common class loader. *
* This method is included for the benfit of applications that must - * generate bytecodes that process method handles and invokedynamic. - * @param descriptor a bytecode-level signature string "(T...)T" + * generate bytecodes that process method handles and {@code invokedynamic}. + * @param descriptor a bytecode-level type descriptor string "(T...)T" * @param loader the class loader in which to look up the types - * @return a method type matching the bytecode-level signature + * @return a method type matching the bytecode-level type descriptor * @throws IllegalArgumentException if the string is not well-formed * @throws TypeNotPresentException if a named type cannot be found */ @@ -631,19 +745,121 @@ class MethodType { } /** - * Create a bytecode descriptor representation of the method type. + * Produces a bytecode descriptor representation of the method type. *
- * Note that this is not a strict inverse of {@link #fromMethodDescriptorString}. + * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}. * Two distinct classes which share a common name but have different class loaders * will appear identical when viewed within descriptor strings. *
* This method is included for the benfit of applications that must - * generate bytecodes that process method handles and invokedynamic. - * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader)}, + * generate bytecodes that process method handles and {@code invokedynamic}. + * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString}, * because the latter requires a suitable class loader argument. - * @return the bytecode signature representation + * @return the bytecode type descriptor representation */ public String toMethodDescriptorString() { return BytecodeDescriptor.unparse(this); } + + /// Serialization. + + /** + * There are no serializable fields for {@code MethodType}. + */ + private static final java.io.ObjectStreamField[] serialPersistentFields = { }; + + /** + * Save the {@code MethodType} instance to a stream. + * + * @serialData + * For portability, the serialized format does not refer to named fields. + * Instead, the return type and parameter type arrays are written directly + * from the {@code writeObject} method, using two calls to {@code s.writeObject} + * as follows: + *
+ *+s.writeObject(this.returnType()); +s.writeObject(this.parameterArray()); + *+ * The deserialized field values are checked as if they were + * provided to the factory method {@link #methodType(Class,Class[]) methodType}. + * For example, null values, or {@code void} parameter types, + * will lead to exceptions during deserialization. + * @param the stream to write the object to + */ + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); // requires serialPersistentFields to be an empty array + s.writeObject(returnType()); + s.writeObject(parameterArray()); + } + + /** + * Reconstitute the {@code MethodType} instance from a stream (that is, + * deserialize it). + * This instance is a scratch object with bogus final fields. + * It provides the parameters to the factory method called by + * {@link #readResolve readResolve}. + * After that call it is discarded. + * @param the stream to read the object from + * @see #MethodType() + * @see #readResolve + * @see #writeObject + */ + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); // requires serialPersistentFields to be an empty array + + Class> returnType = (Class>) s.readObject(); + Class>[] parameterArray = (Class>[]) s.readObject(); + + // Probably this object will never escape, but let's check + // the field values now, just to be sure. + checkRtype(returnType); + checkPtypes(parameterArray); + + parameterArray = parameterArray.clone(); // make sure it is unshared + MethodType_init(returnType, parameterArray); + } + + /** + * For serialization only. + * Sets the final fields to null, pending {@code Unsafe.putObject}. + */ + private MethodType() { + this.rtype = null; + this.ptypes = null; + } + private void MethodType_init(Class> rtype, Class>[] ptypes) { + // In order to communicate these values to readResolve, we must + // store them into the implementation-specific final fields. + checkRtype(rtype); + checkPtypes(ptypes); + unsafe.putObject(this, rtypeOffset, rtype); + unsafe.putObject(this, ptypesOffset, ptypes); + } + + // Support for resetting final fields while deserializing + private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + private static final long rtypeOffset, ptypesOffset; + static { + try { + rtypeOffset = unsafe.objectFieldOffset + (MethodType.class.getDeclaredField("rtype")); + ptypesOffset = unsafe.objectFieldOffset + (MethodType.class.getDeclaredField("ptypes")); + } catch (Exception ex) { + throw new Error(ex); + } + } + + /** + * Resolves and initializes a {@code MethodType} object + * after serialization. + * @return the fully initialized {@code MethodType} object + */ + private Object readResolve() { + // Do not use a trusted path for deserialization: + //return makeImpl(rtype, ptypes, true); + // Verify all operands, and make sure ptypes is unshared: + return methodType(rtype, ptypes); + } } diff --git a/src/share/classes/java/dyn/MutableCallSite.java b/src/share/classes/java/dyn/MutableCallSite.java index b33c41c1a5ad6bd059e2ccdb2ff8a4b7b303da55..95df7a6a6d1b5428dcba527a5426e008bf09ee9c 100644 --- a/src/share/classes/java/dyn/MutableCallSite.java +++ b/src/share/classes/java/dyn/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ assertEquals("Wilma, dear?", (String) worker2.invokeExact()); * (This is a normal consequence of the Java Memory Model as applied * to object fields.) *
- * The {@link #sync sync} operation provides a way to force threads + * The {@link #syncAll syncAll} operation provides a way to force threads * to accept a new target value, even if there is no other synchronization. *
* For target values which will be frequently updated, consider using @@ -82,13 +82,17 @@ assertEquals("Wilma, dear?", (String) worker2.invokeExact()); */ public class MutableCallSite extends CallSite { /** - * Make a blank call site object with the given method type. - * An initial target method is supplied which will throw - * an {@link IllegalStateException} if called. + * Creates a blank call site object with the given method type. + * The initial target is set to a method handle of the given type + * which will throw an {@link IllegalStateException} if called. + *
+ * The type of the call site is permanently set to the given type. *
* Before this {@code CallSite} object is returned from a bootstrap method, + * or invoked in some other manner, * it is usually provided with a more useful target method, * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}. + * @param type the method type that this call site will have * @throws NullPointerException if the proposed type is null */ public MutableCallSite(MethodType type) { @@ -96,8 +100,9 @@ public class MutableCallSite extends CallSite { } /** - * Make a blank call site object, possibly equipped with an initial target method handle. - * @param target the method handle which will be the initial target of the call site + * Creates a call site object with an initial target method handle. + * The type of the call site is permanently set to the initial target's type. + * @param target the method handle that will be the initial target of the call site * @throws NullPointerException if the proposed target is null */ public MutableCallSite(MethodHandle target) { @@ -105,7 +110,59 @@ public class MutableCallSite extends CallSite { } /** - * Perform a synchronization operation on each call site in the given array, + * Returns the target method of the call site, which behaves + * like a normal field of the {@code MutableCallSite}. + *
+ * 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 + * non-volatile, non-final field. + *
+ * In particular, the current thread may choose to reuse the result + * of a previous read of the target from memory, and may fail to see + * a recent update to the target by another thread. + * + * @return the linkage state of this call site, a method handle which can change over time + * @see #setTarget + */ + @Override public final MethodHandle getTarget() { + return target; + } + + /** + * Updates the target method of this call site, as a normal variable. + * The type of the new target must agree with the type of the old target. + *
+ * The interactions with memory are the same + * as of a write to an ordinary variable, such as an array element or a + * non-volatile, non-final field. + *
+ * In particular, unrelated threads may fail to see the updated target + * until they perform a read from memory. + * Stronger guarantees can be created by putting appropriate operations + * into the bootstrap method and/or the target methods used + * at any given call site. + * + * @param newTarget the new target + * @throws NullPointerException if the proposed new target is null + * @throws WrongMethodTypeException if the proposed new target + * has a method type that differs from the previous target + * @see #getTarget + */ + @Override public void setTarget(MethodHandle newTarget) { + checkTargetChange(this.target, newTarget); + setTargetNormal(newTarget); + } + + /** + * {@inheritDoc} + */ + @Override + public final MethodHandle dynamicInvoker() { + return makeDynamicInvoker(); + } + + /** + * Performs a synchronization operation on each call site in the given array, * forcing all other threads to throw away any cached values previously * loaded from the target of any of the call sites. *
@@ -115,19 +172,29 @@ public class MutableCallSite extends CallSite { *
* The overall effect is to force all future readers of each call site's target * to accept the most recently stored value. - * ("Most recently" is reckoned relative to the {@code sync} itself.) - * Conversely, the {@code sync} call may block until all readers have + * ("Most recently" is reckoned relative to the {@code syncAll} itself.) + * Conversely, the {@code syncAll} call may block until all readers have * (somehow) decached all previous versions of each call site's target. *
- * To avoid race conditions, calls to {@code setTarget} and {@code sync} + * To avoid race conditions, calls to {@code setTarget} and {@code syncAll} * should generally be performed under some sort of mutual exclusion. * Note that reader threads may observe an updated target as early * as the {@code setTarget} call that install the value - * (and before the {@code sync} that confirms the value). + * (and before the {@code syncAll} that confirms the value). * On the other hand, reader threads may observe previous versions of - * the target until the {@code sync} call returns + * the target until the {@code syncAll} call returns * (and after the {@code setTarget} that attempts to convey the updated version). *
+ * This operation is likely to be expensive and should be used sparingly. + * If possible, it should be buffered for batch processing on sets of call sites. + *
+ * If {@code sites} contains a null element, + * a {@code NullPointerException} will be raised. + * In this case, some non-null elements in the array may be + * processed before the method returns abnormally. + * Which elements these are (if any) is implementation-dependent. + * + *
Java Memory Model details
* In terms of the Java Memory Model, this operation performs a synchronization * action which is comparable in effect to the writing of a volatile variable * by the current thread, and an eventual volatile read by every other thread @@ -171,18 +238,17 @@ public class MutableCallSite extends CallSite { * thereby ensuring communication of the new target value. ** As long as the constraints of the Java Memory Model are obeyed, - * implementations may delay the completion of a {@code sync} + * implementations may delay the completion of a {@code syncAll} * operation while other threads ({@code T} above) continue to * use previous values of {@code S}'s target. * However, implementations are (as always) encouraged to avoid * livelock, and to eventually require all threads to take account * of the updated target. - *
- * This operation is likely to be expensive and should be used sparingly. - * If possible, it should be buffered for batch processing on sets of call sites. + * *
- * (This is a static method on a set of call sites, not a - * virtual method on a single call site, for performance reasons. + * Discussion: + * For performance reasons, {@code syncAll} is not a virtual method + * on a single call site, but rather applies to a set of call sites. * Some implementations may incur a large fixed overhead cost * for processing one or more synchronization operations, * but a small incremental cost for each additional call site. @@ -191,15 +257,25 @@ public class MutableCallSite extends CallSite { * in order to make them notice the updated target value. * However, it may be observed that a single call to synchronize * several sites has the same formal effect as many calls, - * each on just one of the sites.) - *
+ * each on just one of the sites. + * + *
+ * Implementation Note: * Simple implementations of {@code MutableCallSite} may use * a volatile variable for the target of a mutable call site. - * In such an implementation, the {@code sync} method can be a no-op, + * In such an implementation, the {@code syncAll} method can be a no-op, * and yet it will conform to the JMM behavior documented above. + * + * @param sites an array of call sites to be synchronized + * @throws NullPointerException if the {@code sites} array reference is null + * or the array contains a null */ - public static void sync(MutableCallSite[] sites) { + public static void syncAll(MutableCallSite[] sites) { + if (sites.length == 0) return; STORE_BARRIER.lazySet(0); + for (int i = 0; i < sites.length; i++) { + sites[i].getClass(); // trigger NPE on first null + } // FIXME: NYI } private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); diff --git a/src/share/classes/java/dyn/NoAccessException.java b/src/share/classes/java/dyn/NoAccessException.java deleted file mode 100644 index 89c1a52af2a6ae061f8ab7acb1fb96d1490bc6a5..0000000000000000000000000000000000000000 --- a/src/share/classes/java/dyn/NoAccessException.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.dyn; - -/** - * Thrown to indicate that a caller has attempted to create a method handle - * which accesses a field, method, or class to which the caller does not have access. - * This unchecked exception is analogous to {@link IllegalAccessException}, - * which is a checked exception thrown when reflective invocation fails - * because of an access check. With method handles, this same access - * checking is performed by the {@link MethodHandles.Lookup lookup object} - * on behalf of the method handle creator, - * at the time of creation. - * @author John Rose, JSR 292 EG - * @since 1.7 - */ -public class NoAccessException extends ReflectiveOperationException { - private static final long serialVersionUID = 292L; - - /** - * Constructs a {@code NoAccessException} with no detail message. - */ - public NoAccessException() { - super(); - } - - /** - * Constructs a {@code NoAccessException} with the specified - * detail message. - * - * @param s the detail message - */ - public NoAccessException(String s) { - super(s); - } - - /** - * Constructs a {@code NoAccessException} with the specified cause. - * - * @param cause the underlying cause of the exception - */ - public NoAccessException(Throwable cause) { - super(cause); - } - - /** - * Constructs a {@code NoAccessException} with the specified - * detail message and cause. - * - * @param s the detail message - * @param cause the underlying cause of the exception - */ - public NoAccessException(String s, Throwable cause) { - super(s, cause); - } -} diff --git a/src/share/classes/java/dyn/SwitchPoint.java b/src/share/classes/java/dyn/SwitchPoint.java new file mode 100644 index 0000000000000000000000000000000000000000..642e194b863614ef7041dd2a9e3a95775c1fb137 --- /dev/null +++ b/src/share/classes/java/dyn/SwitchPoint.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.dyn; + +/** + *
+ * A {@code SwitchPoint} is an object which can publish state transitions to other threads. + * A switch point is initially in the valid state, but may at any time be + * changed to the invalid state. Invalidation cannot be reversed. + * A switch point can combine a guarded pair of method handles into a + * guarded delegator. + * The guarded delegator is a method handle which delegates to one of the old method handles. + * The state of the switch point determines which of the two gets the delegation. + *
+ * A single switch point may be used to control any number of method handles. + * (Indirectly, therefore, it can control any number of call sites.) + * This is done by using the single switch point as a factory for combining + * any number of guarded method handle pairs into guarded delegators. + *
+ * When a guarded delegator is created from a guarded pair, the pair + * is wrapped in a new method handle {@code M}, + * which is permanently associated with the switch point that created it. + * Each pair consists of a target {@code T} and a fallback {@code F}. + * While the switch point is valid, invocations to {@code M} are delegated to {@code T}. + * After it is invalidated, invocations are delegated to {@code F}. + *
+ * Invalidation is global and immediate, as if the switch point contained a + * volatile boolean variable consulted on every call to {@code M}. + * The invalidation is also permanent, which means the switch point + * can change state only once. + * The switch point will always delegate to {@code F} after being invalidated. + * At that point {@code guardWithTest} may ignore {@code T} and return {@code F}. + *
+ * Here is an example of a switch point in action: + *
+ *+MethodType MT_str2 = MethodType.methodType(String.class, String.class); +MethodHandle MH_strcat = MethodHandles.lookup() + .findVirtual(String.class, "concat", MT_str2); +SwitchPoint spt = new SwitchPoint(); +// the following steps may be repeated to re-use the same switch point: +MethodHandle worker1 = strcat; +MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0); +MethodHandle worker = spt.guardWithTest(worker1, worker2); +assertEquals("method", (String) worker.invokeExact("met", "hod")); +SwitchPoint.invalidateAll(new SwitchPoint[]{ spt }); +assertEquals("hodmet", (String) worker.invokeExact("met", "hod")); + *+ * Discussion: + * Switch points are useful without subclassing. They may also be subclassed. + * This may be useful in order to associate application-specific invalidation logic + * with the switch point. + *
+ * Implementation Note: + * A switch point behaves as if implemented on top of {@link MutableCallSite}, + * approximately as follows: + *
+ * @author Remi Forax, JSR 292 EG + */ +public class SwitchPoint { + private static final MethodHandle + K_true = MethodHandles.constant(boolean.class, true), + K_false = MethodHandles.constant(boolean.class, false); + + private final MutableCallSite mcs; + private final MethodHandle mcsInvoker; + + /** + * Creates a new switch point. + */ + public SwitchPoint() { + this.mcs = new MutableCallSite(K_true); + this.mcsInvoker = mcs.dynamicInvoker(); + } + + /** + * Returns a method handle which always delegates either to the target or the fallback. + * The method handle will delegate to the target exactly as long as the switch point is valid. + * After that, it will permanently delegate to the fallback. + *+public class SwitchPoint { + private static final MethodHandle + K_true = MethodHandles.constant(boolean.class, true), + K_false = MethodHandles.constant(boolean.class, false); + private final MutableCallSite mcs; + private final MethodHandle mcsInvoker; + public SwitchPoint() { + this.mcs = new MutableCallSite(K_true); + this.mcsInvoker = mcs.dynamicInvoker(); + } + public MethodHandle guardWithTest( + MethodHandle target, MethodHandle fallback) { + // Note: mcsInvoker is of type ()boolean. + // Target and fallback may take any arguments, but must have the same type. + return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback); + } + public static void invalidateAll(SwitchPoint[] spts) { + List<MutableCallSite> mcss = new ArrayList<>(); + for (SwitchPoint spt : spts) mcss.add(spt.mcs); + for (MutableCallSite mcs : mcss) mcs.setTarget(K_false); + MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0])); + } +} + *+ * The target and fallback must be of exactly the same method type, + * and the resulting combined method handle will also be of this type. + * + * @param target the method handle selected by the switch point as long as it is valid + * @param fallback the method handle selected by the switch point after it is invalidated + * @return a combined method handle which always calls either the target or fallback + * @throws NullPointerException if either argument is null + * @see MethodHandles#guardWithTest + */ + public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) { + if (mcs.getTarget() == K_false) + return fallback; // already invalid + return MethodHandles.guardWithTest(mcsInvoker, target, fallback); + } + + /** + * Sets all of the given switch points into the invalid state. + * After this call executes, no thread will observe any of the + * switch points to be in a valid state. + *
+ * This operation is likely to be expensive and should be used sparingly. + * If possible, it should be buffered for batch processing on sets of switch points. + *
+ * If {@code switchPoints} contains a null element, + * a {@code NullPointerException} will be raised. + * In this case, some non-null elements in the array may be + * processed before the method returns abnormally. + * Which elements these are (if any) is implementation-dependent. + * + *
+ * Discussion: + * For performance reasons, {@code invalidateAll} is not a virtual method + * on a single switch point, but rather applies to a set of switch points. + * Some implementations may incur a large fixed overhead cost + * for processing one or more invalidation operations, + * but a small incremental cost for each additional invalidation. + * In any case, this operation is likely to be costly, since + * other threads may have to be somehow interrupted + * in order to make them notice the updated switch point state. + * However, it may be observed that a single call to invalidate + * several switch points has the same formal effect as many calls, + * each on just one of the switch points. + * + *
+ * Implementation Note: + * Simple implementations of {@code SwitchPoint} may use + * a private {@link MutableCallSite} to publish the state of a switch point. + * In such an implementation, the {@code invalidateAll} method can + * simply change the call site's target, and issue one call to + * {@linkplain MutableCallSite#syncAll synchronize} all the + * private call sites. + * + * @param switchPoints an array of call sites to be synchronized + * @throws NullPointerException if the {@code switchPoints} array reference is null + * or the array contains a null + */ + public static void invalidateAll(SwitchPoint[] switchPoints) { + if (switchPoints.length == 0) return; + MutableCallSite[] sites = new MutableCallSite[switchPoints.length]; + for (int i = 0; i < switchPoints.length; i++) { + SwitchPoint spt = switchPoints[i]; + if (spt == null) break; // MSC.syncAll will trigger a NPE + sites[i] = spt.mcs; + spt.mcs.setTarget(K_false); + } + MutableCallSite.syncAll(sites); + } +} diff --git a/src/share/classes/java/dyn/Switcher.java b/src/share/classes/java/dyn/Switcher.java deleted file mode 100644 index b0838764b4417a68bda5dbde1d2418feceb600ce..0000000000000000000000000000000000000000 --- a/src/share/classes/java/dyn/Switcher.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.dyn; - -/** - *
- * A {@code Switcher} is an object which can publish state transitions to other threads. - * A switcher is initially in the valid state, but may at any time be - * changed to the invalid state. Invalidation cannot be reversed. - *
- * A single switcher may be used to create any number of guarded method handle pairs. - * Each guarded pair is wrapped in a new method handle {@code M}, - * which is permanently associated with the switcher that created it. - * Each pair consists of a target {@code T} and a fallback {@code F}. - * While the switcher is valid, invocations to {@code M} are delegated to {@code T}. - * After it is invalidated, invocations are delegated to {@code F}. - *
- * Invalidation is global and immediate, as if the switcher contained a - * volatile boolean variable consulted on every call to {@code M}. - * The invalidation is also permanent, which means the switcher - * can change state only once. - *
- * Here is an example of a switcher in action: - *
- *-MethodType MT_str2 = MethodType.methodType(String.class, String.class); -MethodHandle MH_strcat = MethodHandles.lookup() - .findVirtual(String.class, "concat", MT_str2); -Switcher switcher = new Switcher(); -// the following steps may be repeated to re-use the same switcher: -MethodHandle worker1 = strcat; -MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0); -MethodHandle worker = switcher.guardWithTest(worker1, worker2); -assertEquals("method", (String) worker.invokeExact("met", "hod")); -switcher.invalidate(); -assertEquals("hodmet", (String) worker.invokeExact("met", "hod")); - *- * Implementation Note: - * A switcher behaves as if implemented on top of {@link MutableCallSite}, - * approximately as follows: - *
- * @author Remi Forax, JSR 292 EG - */ -public class Switcher { - private static final MethodHandle - K_true = MethodHandles.constant(boolean.class, true), - K_false = MethodHandles.constant(boolean.class, false); - - private final MutableCallSite mcs; - private final MethodHandle mcsInvoker; - - /** Create a switcher. */ - public Switcher() { - this.mcs = new MutableCallSite(K_true); - this.mcsInvoker = mcs.dynamicInvoker(); - } - - /** - * Return a method handle which always delegates either to the target or the fallback. - * The method handle will delegate to the target exactly as long as the switcher is valid. - * After that, it will permanently delegate to the fallback. - *-public class Switcher { - private static final MethodHandle - K_true = MethodHandles.constant(boolean.class, true), - K_false = MethodHandles.constant(boolean.class, false); - private final MutableCallSite mcs; - private final MethodHandle mcsInvoker; - public Switcher() { - this.mcs = new MutableCallSite(K_true); - this.mcsInvoker = mcs.dynamicInvoker(); - } - public MethodHandle guardWithTest( - MethodHandle target, MethodHandle fallback) { - // Note: mcsInvoker is of type boolean(). - // Target and fallback may take any arguments, but must have the same type. - return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback); - } - public static void invalidateAll(Switcher[] switchers) { - Listmcss = new ArrayList<>(); - for (Switcher s : switchers) mcss.add(s.mcs); - for (MutableCallSite mcs : mcss) mcs.setTarget(K_false); - MutableCallSite.sync(mcss.toArray(new MutableCallSite[0])); - } -} - * - * The target and fallback must be of exactly the same method type, - * and the resulting combined method handle will also be of this type. - * @see MethodHandles#guardWithTest - */ - public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) { - if (mcs.getTarget() == K_false) - return fallback; // already invalid - return MethodHandles.guardWithTest(mcsInvoker, target, fallback); - } - - /** Set all of the given switchers into the invalid state. */ - public static void invalidateAll(Switcher[] switchers) { - MutableCallSite[] sites = new MutableCallSite[switchers.length]; - int fillp = 0; - for (Switcher switcher : switchers) { - sites[fillp++] = switcher.mcs; - switcher.mcs.setTarget(K_false); - } - MutableCallSite.sync(sites); - } -} diff --git a/src/share/classes/java/dyn/VolatileCallSite.java b/src/share/classes/java/dyn/VolatileCallSite.java index 8c603b9191593991b7b0c9fd911d8f8a8d43056e..616813ce2f5a55f40b629262758b1212aaecb3ae 100644 --- a/src/share/classes/java/dyn/VolatileCallSite.java +++ b/src/share/classes/java/dyn/VolatileCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import java.util.List; * There may be a performance penalty for such tight coupling between threads. *
* Unlike {@code MutableCallSite}, there is no - * {@linkplain MutableCallSite#sync sync operation} on volatile + * {@linkplain MutableCallSite#syncAll syncAll operation} on volatile * call sites, since every write to a volatile variable is implicitly * synchronized with reader threads. *
@@ -44,36 +44,68 @@ import java.util.List; * @author John Rose, JSR 292 EG */ public class VolatileCallSite extends CallSite { - /** Create a call site with a volatile target. - * The initial target is set to a method handle - * of the given type which will throw {@code IllegalStateException}. + /** + * Creates a call site with a volatile binding to its target. + * The initial target is set to a method handle + * of the given type which will throw an {@code IllegalStateException} if called. + * @param type the method type that this call site will have * @throws NullPointerException if the proposed type is null */ public VolatileCallSite(MethodType type) { super(type); } - /** Create a call site with a volatile target. - * The target is set to the given value. + /** + * Creates a call site with a volatile binding to its target. + * The target is set to the given value. + * @param target the method handle that will be the initial target of the call site * @throws NullPointerException if the proposed target is null */ public VolatileCallSite(MethodHandle target) { super(target); } - /** Internal override to nominally final getTarget. */ - @Override - MethodHandle getTarget0() { + /** + * Returns the target method of the call site, which behaves + * like a {@code volatile} field of the {@code VolatileCallSite}. + *
+ * The interactions of {@code getTarget} with memory are the same + * as of a read from a {@code volatile} field. + *
+ * In particular, the current thread is required to issue a fresh + * read of the target from memory, and must not fail to see + * a recent update to the target by another thread. + * + * @return the linkage state of this call site, a method handle which can change over time + * @see #setTarget + */ + @Override public final MethodHandle getTarget() { return getTargetVolatile(); } /** - * Set the target method of this call site, as a volatile variable. - * Has the same effect as {@link CallSite#setTarget CallSite.setTarget}, with the additional - * effects associated with volatiles, in the Java Memory Model. + * Updates the target method of this call site, as a volatile variable. + * The type of the new target must agree with the type of the old target. + *
+ * The interactions with memory are the same as of a write to a volatile field. + * In particular, any threads is guaranteed to see the updated target + * the next time it calls {@code getTarget}. + * @param newTarget the new target + * @throws NullPointerException if the proposed new target is null + * @throws WrongMethodTypeException if the proposed new target + * has a method type that differs from the previous target + * @see #getTarget */ @Override public void setTarget(MethodHandle newTarget) { checkTargetChange(getTargetVolatile(), newTarget); setTargetVolatile(newTarget); } + + /** + * {@inheritDoc} + */ + @Override + public final MethodHandle dynamicInvoker() { + return makeDynamicInvoker(); + } } diff --git a/src/share/classes/java/dyn/WrongMethodTypeException.java b/src/share/classes/java/dyn/WrongMethodTypeException.java index 4c4c99817ffec82b37b265639887a57023d9672b..2455432e858be4721fe36e8938b441cc2d0af770 100644 --- a/src/share/classes/java/dyn/WrongMethodTypeException.java +++ b/src/share/classes/java/dyn/WrongMethodTypeException.java @@ -29,7 +29,7 @@ package java.dyn; * Thrown to indicate that code has attempted to call a method handle * via the wrong method type. As with the bytecode representation of * normal Java method calls, method handle calls are strongly typed - * to a specific signature associated with a call site. + * to a specific type descriptor associated with a call site. *
* This exception may also be thrown when two method handles are * composed, and the system detects that their types cannot be diff --git a/src/share/classes/java/dyn/package-info.java b/src/share/classes/java/dyn/package-info.java index d2fa14ffc9ffe13d0da94c625968d3e579dfa1f0..d01c644f312959b7351f3b1ab09ae0c9235a9dd2 100644 --- a/src/share/classes/java/dyn/package-info.java +++ b/src/share/classes/java/dyn/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,21 +24,20 @@ */ /** - * This package contains dynamic language support provided directly by + * The {@code java.lang.invoke} package contains dynamic language support provided directly by * the Java core class libraries and virtual machine. + * + *
+ * Historic Note: In some early versions of Java SE 7, + * the name of this package is {@code java.dyn}. *
* Certain types in this package have special relations to dynamic * language support in the virtual machine: *
- *
- In source code, a call to - * {@link java.dyn.MethodHandle#invokeExact MethodHandle.invokeExact} or - * {@link java.dyn.MethodHandle#invokeGeneric MethodHandle.invokeGeneric} - * will compile and link, regardless of the requested type signature. - * As usual, the Java compiler emits an {@code invokevirtual} - * instruction with the given signature against the named method. - * The JVM links any such call (regardless of signature) to a dynamically - * typed method handle invocation. In the case of {@code invokeGeneric}, - * argument and return value conversions are applied. + *
- The class {@link java.dyn.MethodHandle MethodHandle} contains + * signature polymorphic methods + * which can be linked regardless of their type descriptor. + * Normally, method linkage requires exact matching of type descriptors. *
* *- The JVM bytecode format supports immediate constants of @@ -58,12 +57,11 @@ * The final two bytes are reserved for future use and required to be zero. * The constant pool reference of an {@code invokedynamic} instruction is to a entry * with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format. - * (The tag value 17 is also temporarily allowed. See below.) * The entry specifies the following information: *
*
*- a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)
*- the dynamic invocation name (a UTF8 string)
- *- the argument and return types of the call (encoded as a signature in a UTF8 string)
+ *- the argument and return types of the call (encoded as a type descriptor in a UTF8 string)
*- optionally, a sequence of additional static arguments to the bootstrap method ({@code ldc}-type constants)
*@@ -78,9 +76,9 @@ * as described below. * *
- * (Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType} + * Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType} * instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the - * bootstrap method was specified dynamically, in a per-class basis, during class initialization.) + * bootstrap method was specified dynamically, in a per-class basis, during class initialization. * *
constant pool entries for {@code invokedynamic} instructions
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18), @@ -90,33 +88,21 @@ * bootstrap method table, which is stored in the {@code BootstrapMethods} * attribute as described below. * The second pair of bytes must be an index to a {@code CONSTANT_NameAndType}. - * This table is not part of the constant pool. Instead, it is stored - * in a class attribute named {@code BootstrapMethods}, described below. ** The first index specifies a bootstrap method used by the associated dynamic call sites. * The second index specifies the method name, argument types, and return type of the dynamic call site. * The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref}, * except that the bootstrap method specifier reference replaces * the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry. - *
- * Some older JVMs may allow an older constant pool entry tag of decimal 17. - * The format and behavior of a constant pool entry with this tag is identical to - * an entry with a tag of decimal 18, except that the first index refers directly - * to a {@code CONSTANT_MethodHandle} to use as the bootstrap method. - * This format does not require the bootstrap method table. - * - *
- * (Note: The Proposed Final Draft of this specification is likely to support - * only the tag 18, not the tag 17.) * *
constant pool entries for {@linkplain java.dyn.MethodType method types}
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16), * it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8} - * entry which represents a method type signature. + * entry which represents a method type descriptor. ** The JVM will ensure that on first * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType} - * will be created which represents the signature. + * will be created which represents the type descriptor. * Any classes mentioned in the {@code MethodType} will be loaded if necessary, * but not initialized. * Access checking and error reporting is performed exactly as it is for @@ -141,38 +127,75 @@ * type is created. Any classes mentioned in this reification will be loaded if necessary, * but not initialized, and access checking and error reporting performed as usual. *
+ * Unlike the reflective {@code Lookup} API, there are no security manager calls made + * when these constants are resolved. + *
* The method handle itself will have a type and behavior determined by the subtag as follows: *
*+ * Here, the type {@code C} is taken from the {@code CONSTANT_Class} reference associated + * with the {@code CONSTANT_NameAndType} descriptor. + * The field name {@code f} or method name {@code m} is taken from the {@code CONSTANT_NameAndType} + * as is the result type {@code T} and (in the case of a method or constructor) the argument type sequence + * {@code A*}. + *- *
*- * N subtag name member MH type MH behavior - * 1 REF_getField C.f:T (C)T getfield C.f:T - * 2 REF_getStatic C.f:T ( )T getstatic C.f:T - * 3 REF_putField C.f:T (C,T)void putfield C.f:T - * 4 REF_putStatic C.f:T (T)void putstatic C.f:T - * 5 REF_invokeVirtual C.m(A*)T (C,A*)T invokevirtual C.m(A*)T - * 6 REF_invokeStatic C.m(A*)T (C,A*)T invokestatic C.m(A*)T - * 7 REF_invokeSpecial C.m(A*)T (C,A*)T invokespecial C.m(A*)T - * 8 REF_newInvokeSpecial C.<init>(A*)void (A*)C new C; dup; invokespecial C.<init>(A*)void + * 9 REF_invokeInterface C.m(A*)T (C,A*)T invokeinterface C.m(A*)T + * N subtag name member MH type bytecode behavior lookup expression + * 1 REF_getField C.f:T (C)T getfield C.f:T + *{@linkplain java.dyn.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)} + * 2 REF_getStatic C.f:T ( )T getstatic C.f:T + *{@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)} + * 3 REF_putField C.f:T (C,T)void putfield C.f:T + *{@linkplain java.dyn.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)} + * 4 REF_putStatic C.f:T (T)void putstatic C.f:T + *{@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)} + * 5 REF_invokeVirtual C.m(A*)T (C,A*)T invokevirtual C.m(A*)T + *{@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)} + * 6 REF_invokeStatic C.m(A*)T (C,A*)T invokestatic C.m(A*)T + *{@linkplain java.dyn.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)} + * 7 REF_invokeSpecial C.m(A*)T (C,A*)T invokespecial C.m(A*)T + *{@linkplain java.dyn.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)} + * 8 REF_newInvokeSpecial C.<init>(A*)void (A*)C new C; dup; invokespecial C.<init>(A*)void + *{@linkplain java.dyn.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)} * 9 REF_invokeInterface C.m(A*)T (C,A*)T invokeinterface C.m(A*)T + *{@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)} + * Each method handle constant has an equivalent instruction sequence called its bytecode behavior. + * In general, creating a method handle constant can be done in exactly the same circumstances that + * the JVM would successfully resolve the symbolic references in the bytecode behavior. + * Also, the type of a method handle constant is such that a valid {@code invokeExact} call + * on the method handle has exactly the same JVM stack effects as the bytecode behavior. + * Finally, calling a method handle constant on a valid set of arguments has exactly the same effect + * and returns the same result (if any) as the corresponding bytecode behavior. + *
+ * Each method handle constant also has an equivalent reflective lookup expression, + * which is a query to a method in {@link java.dyn.MethodHandles.Lookup}. + * In the example lookup method expression given in the table above, the name {@code MT} + * stands for a {@code MethodType} built from {@code T} and the sequence of argument types {@code A*}. + * (Note that the type {@code C} is not prepended to the query type {@code MT} even if the member is non-static.) + * In the case of {@code findSpecial}, the name {@code this.class} refers to the class containing + * the bytecodes. *
* The special name {@code
} is not allowed. * The special name {@code } is not allowed except for subtag 8 as shown. * * The JVM verifier and linker apply the same access checks and restrictions for these references as for the hypothetical - * bytecode instructions specified in the last column of the table. In particular, method handles to + * bytecode instructions specified in the last column of the table. + * A method handle constant will successfully resolve to a method handle if the symbolic references + * of the corresponding bytecode instruction(s) would also resolve successfully. + * Otherwise, an attempt to resolve the constant will throw equivalent linkage errors. + * In particular, method handles to * private and protected members can be created in exactly those classes for which the corresponding * normal accesses are legal. *
* A constant may refer to a method or constructor with the {@code varargs} - * bit (hexadecimal {@code 80}) set in its modifier bitmask. - * The method handle constant produced for such a method behaves the same + * bit (hexadecimal {@code 0x0080}) set in its modifier bitmask. + * The method handle constant produced for such a method behaves as if + * it were created by {@link java.dyn.MethodHandle#asVarargsCollector asVarargsCollector}. + * In other words, the constant method handle will exhibit variable arity, + * when invoked via {@code invokeGeneric}. + * On the other hand, its behavior with respect to {@code invokeExact} will be the same * as if the {@code varargs} bit were not set. - * The argument-collecting behavior of {@code varargs} can be emulated by - * adapting the method handle constant with - * {@link java.dyn.MethodHandle#asCollector asCollector}. - * There is no provision for doing this automatically. *
* Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types * resolve class names, they do not force class initialization. @@ -186,14 +209,14 @@ * by the execution of {@code invokedynamic} and {@code ldc} instructions. * (Roughly speaking, this means that every use of a constant pool entry * must lead to the same outcome. - * If the resoultion succeeds, the same object reference is produced + * If the resolution succeeds, the same object reference is produced * by every subsequent execution of the same instruction. * If the resolution of the constant causes an error to occur, * the same error will be re-thrown on every subsequent attempt * to use this particular constant.) *
* Constants created by the resolution of these constant pool types are not necessarily - * interned. Except for {@link CONSTANT_Class} and {@link CONSTANT_String} entries, + * interned. Except for {@code CONSTANT_Class} and {@code CONSTANT_String} entries, * two distinct constant pool entries might not resolve to the same reference * even if they contain the same symbolic reference. * @@ -207,31 +230,31 @@ *
* Each {@code invokedynamic} instruction statically specifies its own * bootstrap method as a constant pool reference. - * The constant pool reference also specifies the call site's name and type signature, + * The constant pool reference also specifies the call site's name and type descriptor, * just like {@code invokevirtual} and the other invoke instructions. *
* Linking starts with resolving the constant pool entry for the * bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for - * the type signature of the dynamic call site. + * the type descriptor of the dynamic call site. * This resolution process may trigger class loading. * It may therefore throw an error if a class fails to load. * This error becomes the abnormal termination of the dynamic * call site execution. * Linkage does not trigger class initialization. *
- * Next, the bootstrap method call is started, with four or five values being stacked: + * Next, the bootstrap method call is started, with at least four values being stacked: *
*
* The method handle is then applied to the other values as if by * {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}. * The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass). * The type of the call site's target must be exactly equal to the type - * derived from the dynamic call site signature and passed to + * derived from the dynamic call site's type descriptor and passed to * the bootstrap method. * The call site then becomes permanently linked to the dynamic call site. *- a {@code MethodHandle}, the resolved bootstrap method itself
*- a {@code MethodHandles.Lookup}, a lookup object on the caller class in which dynamic call site occurs
*- a {@code String}, the method name mentioned in the call site
- *- a {@code MethodType}, the resolved type signature of the call
- *- optionally, a single object representing one or more additional static arguments
+ *- a {@code MethodType}, the resolved type descriptor of the call
+ *- optionally, one or more additional static arguments
*@@ -299,11 +322,11 @@ * chosen target object. * *
- * (Historic Note: Unlike some previous versions of this specification, + * Historic Note: Unlike some previous versions of this specification, * these rules do not enable the JVM to duplicate dynamic call sites, * or to issue “causeless” bootstrap method calls. * Every dynamic call site transitions at most once from unlinked to linked, - * just before its first invocation.) + * just before its first invocation. * *
the {@code BootstrapMethods} attribute
* Each {@code CONSTANT_InvokeDynamic} entry contains an index which references @@ -349,7 +372,6 @@ * Static arguments are specified constant pool indexes stored in the {@code BootstrapMethods} attribute. * Before the bootstrap method is invoked, each index is used to compute an {@code Object} * reference to the indexed value in the constant pool. - * If the value is a primitive type, it is converted to a reference by boxing conversion. * The valid constant pool entries are listed in this table: **