# HG changeset patch
# User asaha
# Date 1302283643 25200
# Node ID afcc1530e68b474de2bf7ae23802b81643697ecf
# Parent fe27fe44ac51a7ef1e4f60b7b6de74ea6c0ba98b# Parent 9aaa2233b0deb137acc75dbf09755d98740e12cc
Merge
diff -r fe27fe44ac51 -r afcc1530e68b .hgtags
--- a/.hgtags Thu Mar 03 14:16:57 2011 -0800
+++ b/.hgtags Fri Apr 08 10:27:23 2011 -0700
@@ -109,3 +109,5 @@
6bbc7a4734952ae7604578f270e1566639fa8752 jdk7-b132
5e5f68a01d12a4432172f384d5201f3a05254493 jdk7-b133
554adcfb615e63e62af530b1c10fcf7813a75b26 jdk7-b134
+d8ced728159fbb2caa8b6adb477fd8efdbbdf179 jdk7-b135
+aa13e7702cd9d8aca9aa38f1227f966990866944 jdk7-b136
diff -r fe27fe44ac51 -r afcc1530e68b make/common/Defs-windows.gmk
--- a/make/common/Defs-windows.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/Defs-windows.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -68,40 +68,10 @@
# The following DLL's are considered MS runtime libraries and should
# not to be REBASEd, see deploy/make/common/Release.gmk.
# msvcr*.dll: Microsoft runtimes
-ifeq ($(ARCH_DATA_MODEL), 32)
- ifeq ($(COMPILER_VERSION), VS2003)
- MSVCRNN_DLL = msvcr71.dll
- MSVCPNN_DLL = msvcp71.dll
- MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL)
- endif
- ifeq ($(COMPILER_VERSION), VS2005)
- MSVCRNN_DLL = msvcr80.dll
- MSVCPNN_DLL = msvcp80.dll
- MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL)
- endif
- ifeq ($(COMPILER_VERSION), VS2008)
- MSVCRNN_DLL = msvcr90.dll
- MSVCPNN_DLL = msvcp90.dll
- MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL)
- endif
- ifeq ($(COMPILER_VERSION), VS2010)
- MSVCRNN_DLL = msvcr100.dll
- MSVCPNN_DLL = msvcp100.dll
- MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL)
- endif
-endif
-
-ifeq ($(ARCH_DATA_MODEL), 64)
- ifeq ($(COMPILER_VERSION), VS2008)
- MSVCRNN_DLL = msvcr90.dll
- MSVCPNN_DLL = msvcp90.dll
- MS_RUNTIME_LIBRARIES = msvcrt.dll $(MSVCRNN_DLL)
- endif
- ifeq ($(COMPILER_VERSION), VS2010)
- MSVCRNN_DLL = msvcr100.dll
- MSVCPNN_DLL = msvcp100.dll
- MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL)
- endif
+ifeq ($(COMPILER_VERSION), VS2010)
+ MSVCRNN_DLL = msvcr100.dll
+ MSVCPNN_DLL = msvcp100.dll
+ MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL)
endif
EXTRA_LFLAGS += /LIBPATH:$(DXSDK_LIB_PATH)
@@ -124,109 +94,31 @@
endif
ifeq ($(CC_VERSION),msvc)
- # Visual Studio .NET 2003 or VS2003 compiler option definitions:
+ # Visual Studio compiler option definitions:
# -O1 Favors reduced size over speed (-Og -Os -Oy -Ob2 -Gs -GF -Gy)
# -O2 Favors speed over reduced size (-Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy)
- # -Ox Full optimization (use -O2) (-Og -Oi -Ot -Oy -Ob2)
- # (Removed in Visual Studio 2005 or VS2005)
# -Ob2 More aggressive inlining
# -Og Global optimizations
# -Oi Replace some functions with intrinsic or special forms
- # -Op Improve floating point calculations (disables some optimizations)
- # (Replaced with -fp:precise in VS2005, /Op is default now)
+ # -fp:precise (should be the default)
+ # Improve floating point calculations (disables some optimizations)
# -Os Favor small code
# -Ot Favor faster code
# -Oy Frame pointer omission
- # -GB Optimize for pentium (old VC6 option?)
- # -G6 VS2003 version of -GB?
+ # -G6 Used to be -GB?
# -GF Pool strings in read-only memory
# -Gf Pool strings in read-write memory (the default)
# -Gs Controls stack probess
- # -GS Adds buffer overflow checks on stacks
- # (Default in VS2005)
- # -GX Enables exception handling
- # (Replaced with /EHsc in VS2005)
+ # -GS Adds buffer overflow checks on stacks (the default)
+ # -EHsc Enables exception handling
# -Gy Function level linking only
#
- # NOTE: With VC6, -Ox included -Gs.
- # NOTE: With VC6, -Ox, -O1, and -O2 used -Ob1, not -Ob2.
- # NOTE: With VC6, -O1 and -O2 used -Gf, not -GF.
- #
CC_OPT/NONE = -Od
CC_OPT/LOWER = -O2
CC_OPT/HIGHER = -O3
CC_OPT/HIGHEST = -O3
- ifeq ($(COMPILER_VERSION), VC6)
- # VC6 (6.2) msvc compiler (the way Tiger and early Mustang were built)
- # Automatic precompiled header option to use (if COMPILE_APPROACH=batch)
- AUTOMATIC_PCH_OPTION =
- GX_OPTION = -GX
- GZ_OPTION = -GZ
- ifeq ($(ARCH_DATA_MODEL), 32)
- CC_OPT/HIGHEST = -Ox -Gy -Os -GB
- CC_OPT/HIGHER = -Ox -Gy -Os -GB
- CC_OPT/LOWER = -Ox -Gy -Os -GB
- else
- CC_OPT/HIGHEST = -Ox -Gy -Op
- CC_OPT/HIGHER = -Ox -Gy -Op
- CC_OPT/LOWER = -Ox -Gy -Op
- endif
- endif
-
- ifeq ($(COMPILER_VERSION), VS2003)
- # Automatic precompiled header option to use (if COMPILE_APPROACH=batch)
- AUTOMATIC_PCH_OPTION = -YX
- # Also known as VC7 compiler
- GX_OPTION = -GX
- GZ_OPTION = -GZ
- ifeq ($(ARCH_DATA_MODEL), 32)
- # Lowered opt level to try and reduce footprint, dll size especially.
- # Was: CC_OPT/HIGHEST = -O2 -G6
- # Was: CC_OPT/HIGHER = -O2
- CC_OPT/HIGHEST = -O2
- CC_OPT/HIGHER = -O1
- CC_OPT/LOWER = -O1
- else
- CC_OPT/HIGHEST = -O2 -Op
- CC_OPT/HIGHER = -O2 -Op
- CC_OPT/LOWER = -O1 -Op
- endif
- endif
-
- ifeq ($(COMPILER_VERSION), VS2005)
- # Automatic precompiled header option to use (if COMPILE_APPROACH=batch)
- AUTOMATIC_PCH_OPTION =
- # VS2005 compiler, only with Platform SDK right now?
- GX_OPTION = -EHsc
- GZ_OPTION = -RTC1
- ifeq ($(ARCH_DATA_MODEL), 32)
- CC_OPT/HIGHEST = -O2
- CC_OPT/HIGHER = -O1
- CC_OPT/LOWER = -O1
- else
- CC_OPT/HIGHEST = -O2
- CC_OPT/HIGHER = -O1
- CC_OPT/LOWER = -O1
- endif
- endif
- ifeq ($(COMPILER_VERSION), VS2008)
- # Automatic precompiled header option to use (if COMPILE_APPROACH=batch)
- AUTOMATIC_PCH_OPTION =
- GX_OPTION = -EHsc
- GZ_OPTION = -RTC1
- ifeq ($(ARCH_DATA_MODEL), 32)
- CC_OPT/HIGHEST = -O2
- CC_OPT/HIGHER = -O1
- CC_OPT/LOWER = -O1
- else
- CC_OPT/HIGHEST = -O2
- CC_OPT/HIGHER = -O1
- CC_OPT/LOWER = -O1
- endif
- endif
-
ifeq ($(COMPILER_VERSION), VS2010)
# Automatic precompiled header option to use (if COMPILE_APPROACH=batch)
AUTOMATIC_PCH_OPTION =
@@ -256,7 +148,7 @@
# Select the runtime support library carefully, need to be consistent
#
-# VS2003 compiler option definitions:
+# Visual Studio Runtime compiler option definitions:
# -MD Use dynamic multi-threaded runtime library
# -MDd Use debug version (don't use, doesn't mix with -MD DLL's)
# -MT Use static multi-threaded runtime library (-ML is going away)
@@ -265,12 +157,9 @@
#
# NOTE: We also will use /D _STATIC_CPPLIB so we don't need msvcpnn.dll
#
-# If MS_RUNTIME_STATIC is requested, use -MT only with VS2003.
-ifeq ($(MS_RUNTIME_STATIC),true)
- ifeq ($(COMPILER_VERSION), VS2003)
- MS_RUNTIME_OPTION=-MT
- endif
-else
+# If MS_RUNTIME_STATIC is requested we may have a problem, it is no longer
+# supported by VS2010
+ifneq ($(MS_RUNTIME_STATIC),true)
MS_RUNTIME_OPTION=-MD
endif
# The _DEBUG macro option (changes things like malloc to use debug version)
@@ -302,7 +191,7 @@
MS_RUNTIME_OPTION += $(STATIC_CPPLIB_OPTION)
ifeq ($(CC_VERSION),msvc)
- # VS2003 compiler option definitions:
+ # Visual Studio compiler option definitions:
# -Zi Cause *.pdb file to be created, full debug information
# -Z7 Full debug inside the .obj, no .pdb
# -Zd Basic debug, no local variables? In the .obj
@@ -317,31 +206,10 @@
CFLAGS_OPT = $(CC_OPT)
CFLAGS_DBG = -Od $(MS_RUNTIME_DEBUG_OPTION)
- # REMIND: I don't see where CFLAGS_VS2005 is used. I suspect its
- # pulled in as a combined "CFLAGS_$(COMPILER_VERSION)" string
- # but the lack of this isn't causing any apparent build problems
- # with VS 2010 but it could be causing compiler warnings.
- # For now, I will add it for all cases :
CFLAGS_VS2010 += -Zc:wchar_t-
- #
- # Starting from VS2005 the wchar_t is handled as a built-in C/C++ data type
- # by default. However, we expect the wchar_t to be a typedef to the
- # unsigned short data type. The -Zc:wchar_t- option restores the old
- # behavior (as seen in VS2003) to avoid massive code modifications.
- # When/if our code will be "C/C++ Standard"-compliant (at least in the area
- # of handling the wchar_t type), the option won't be necessary.
- ifeq ($(ARCH_DATA_MODEL), 32)
- CFLAGS_VS2005 += -Zc:wchar_t-
- else
- # The 64bit Platform SDK we use (April 2005) doesn't like this option
- ifneq ($(CC_VER), 14.00.40310.41)
- CFLAGS_VS2005 += -Zc:wchar_t-
- endif
- endif
# All builds get the same runtime setting
CFLAGS_COMMON += $(MS_RUNTIME_OPTION) $(CFLAGS_$(COMPILER_VERSION))
-
LDEBUG = /debug
@@ -350,21 +218,9 @@
LDEBUG += /pdb:NONE
endif
- # The new Platform SDK and VS2005 has /GS as a default and requires
- # bufferoverflowU.lib on the link command line, otherwise
- # we get missing __security_check_cookie externals at link time.
- BUFFEROVERFLOWLIB = bufferoverflowU.lib
- # Always add bufferoverflowU.lib to VS2005 link commands (pack uses LDDFLAGS)
- LFLAGS_VS2005 = $(BUFFEROVERFLOWLIB)
-
- # VS2008 has bufferoverflow baked in:
- LFLAGS_VS2008 =
-
# VS2010, always need safe exception handlers, not needed on 64bit
ifeq ($(ARCH_DATA_MODEL), 32)
- LFLAGS_VS2010 = -SAFESEH
- else
- LFLAGS_VS2010 =
+ LFLAGS_VS2010 += -SAFESEH
endif
# LFLAGS are the flags given to $(LINK) and used to build the actual DLL file
diff -r fe27fe44ac51 -r afcc1530e68b make/common/Defs.gmk
--- a/make/common/Defs.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/Defs.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -524,6 +524,10 @@
COPYRIGHT_YEAR := $(shell $(DATE) '+%Y')
endif
+ifndef OPENJDK
+include $(JDK_TOPDIR)/make/closed/common/Defs.gmk
+endif
+
# Install of imported file (JDK_IMPORT_PATH, or some other external location)
define install-importonly-file
@$(ECHO) "ASSEMBLY_IMPORT: $@"
diff -r fe27fe44ac51 -r afcc1530e68b make/common/Release.gmk
--- a/make/common/Release.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/Release.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -54,9 +54,6 @@
com.sun.java.swing.plaf.motif \
com.sun.java.swing.plaf.gtk
-# This is a stopgap until 6839872 is fixed.
-EXCLUDE_PROPWARN_PKGS += sun.dyn
-
#
# Include the exported private packages in ct.sym.
# This is an interim solution until the ct.sym is replaced
@@ -86,14 +83,7 @@
IMAGE_DOCLIST_JDK = LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README
IMAGE_DOCLIST_JRE = LICENSE ASSEMBLY_EXCEPTION THIRD_PARTY_README
else
- # Where to find these files
- ifeq ($(J4B), true)
- SHARE_JDK_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jdkfb
- SHARE_JRE_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jrefb
- else
- SHARE_JDK_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jdk
- SHARE_JRE_DOC_SRC = $(CLOSED_SHARE_SRC)/doc/jre
- endif
+ # make/closed/common/Defs.gmk for closed location of SHARE_JDK_DOC_SRC
IMAGE_DOCLIST_JDK = COPYRIGHT README.html THIRDPARTYLICENSEREADME.txt
IMAGE_DOCLIST_JRE = COPYRIGHT Welcome.html THIRDPARTYLICENSEREADME.txt
@@ -932,11 +922,6 @@
ifeq ($(COMPILER_VERSION), VS2010)
$(CP) $(BINDIR)/msvc*100.$(LIBRARY_SUFFIX) $(JDK_IMAGE_DIR)/bin
endif
- ifeq ($(ARCH_DATA_MODEL), 32)
- ifeq ($(COMPILER_VERSION), VS2003)
- $(CP) $(BINDIR)/msvc*71.$(LIBRARY_SUFFIX) $(JDK_IMAGE_DIR)/bin
- endif
- endif
else # PLATFORM
@#
@# bin/
diff -r fe27fe44ac51 -r afcc1530e68b make/common/shared/Compiler-msvc.gmk
--- a/make/common/shared/Compiler-msvc.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/shared/Compiler-msvc.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -47,82 +47,8 @@
# Compiler version and type (Always get word after "Version")
CC_VER := $(shell $(CC) 2>&1 | $(HEAD) -n 1 | $(SED) 's/.*\(Version.*\)/\1/' | $(NAWK) '{print $$2}')
- # The MSDEVTOOLS_PATH is for older compilers, place for rc, mt, etc.
- _OTHER_TOOLS_PATH = $(MSDEVTOOLS_PATH)
-
- # SDK-64 and MSVC6 put REBASE.EXE in a different places - go figure...
- ifeq ($(ARCH_DATA_MODEL), 32)
- LINK_VER := $(shell $(LINK) | $(HEAD) -n 1 | $(NAWK) '{print $$6}')
- CC_MAJORVER :=$(call MajorVersion,$(CC_VER))
- ifeq ($(CC_MAJORVER), 13)
- # This should be: CC_VER=13.10.3077 LINK_VER=7.10.3077
- COMPILER_NAME=Visual Studio .NET 2003 Professional C++
- COMPILER_VERSION=VS2003
- RC = $(_OTHER_TOOLS_PATH)rc
- REBASE = $(COMPILER_PATH)../../Common7/Tools/Bin/rebase
- MTL = $(COMPILER_PATH)../../Common7/Tools/Bin/midl
- endif
- ifeq ($(CC_MAJORVER), 14)
- COMPILER_NAME=Visual Studio 8
- COMPILER_VERSION=VS2005
- RC = $(_OTHER_TOOLS_PATH)rc
- REBASE = $(COMPILER_PATH)../../Common8/Tools/Bin/rebase
- MTL = $(COMPILER_PATH)../../Common8/Tools/Bin/midl
- MT = $(_OTHER_TOOLS_PATH)/mt
- endif
- ifeq ($(CC_MAJORVER), 15)
- COMPILER_NAME=Visual Studio 9
- COMPILER_VERSION=VS2008
- RC = $(_OTHER_TOOLS_PATH)rc
- #rebase and midl moved out of Visual Studio into the SDK:
- REBASE = $(_OTHER_TOOLS_PATH)/rebase
- MTL = $(_OTHER_TOOLS_PATH)/midl.exe
- MT = $(_OTHER_TOOLS_PATH)mt
- endif
- else
- # else ARCH_DATA_MODEL is 64
- LINK_VER := $(shell $(LINK) | $(HEAD) -n 1 | $(NAWK) '{print $$6}')
- CC_MAJORVER :=$(call MajorVersion,$(CC_VER))
- CC_MINORVER :=$(call MinorVersion,$(CC_VER))
- CC_MICROVER :=$(call MicroVersion,$(CC_VER))
- ifeq ($(CC_MAJORVER), 13)
- ifeq ($(ARCH), ia64)
- # This should be: CC_VER=13.00.9337.7 LINK_VER=7.00.9337.7
- COMPILER_NAME=Microsoft Platform SDK - November 2001 Edition
- COMPILER_VERSION=VS2003
- RC = $(_OTHER_TOOLS_PATH)rc
- endif
- endif
- ifeq ($(CC_MAJORVER), 14)
- ifeq ($(ARCH), amd64)
- #rebase and midl moved out of Visual Studio into the SDK:
- RC = $(_OTHER_TOOLS_PATH)/rc
- REBASE = $(_OTHER_TOOLS_PATH)/rebase
- MTL = $(_OTHER_TOOLS_PATH)/midl.exe
- ifeq ($(CC_MICROVER), 30701)
- # This should be: CC_VER=14.00.30701 LINK_VER=8.00.30701
- # WARNING: it says 14, but it is such an early build it doesn't
- # have all the VS2005 compiler option changes, so treat
- # this like a VS2003 compiler.
- COMPILER_NAME=Microsoft Platform SDK - February 2003 Edition
- COMPILER_VERSION=VS2003
- else
- # This should be: CC_VER=14.00.40310.41 LINK_VER=8.00.40310.39
- COMPILER_NAME=Microsoft Platform SDK - April 2005 Edition (3790.1830)
- COMPILER_VERSION=VS2005
- endif
- else
- REBASE = $(COMPILER_PATH)../rebase
- endif
- endif
- ifeq ($(CC_MAJORVER), 15)
- COMPILER_NAME=Microsoft Windows SDK with Visual Studio 9 (6001.18000.367)
- COMPILER_VERSION=VS2008
- RC = $(MSSDK61)/Bin/X64/rc.exe
- MT = $(MSSDK61)/Bin/X64/mt.exe
- MTL = $(MSSDK61)/Bin/X64/midl.exe
- endif
- endif
+ LINK_VER := $(shell $(LINK) | $(HEAD) -n 1 | $(NAWK) '{print $$6}')
+ CC_MAJORVER :=$(call MajorVersion,$(CC_VER))
# The VS2010 compiler is the same one used on both 32bit and 64bit
ifeq ($(CC_MAJORVER), 16)
diff -r fe27fe44ac51 -r afcc1530e68b make/common/shared/Defs-versions.gmk
--- a/make/common/shared/Defs-versions.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/shared/Defs-versions.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -190,25 +190,10 @@
REQUIRED_FREE_SPACE = 500000
REQUIRED_DXSDK_VER = 0x0900
ifeq ($(CC_VERSION),msvc)
- ifeq ($(ARCH_DATA_MODEL), 32)
- REQUIRED_COMPILER_NAME = Visual Studio 10
- REQUIRED_COMPILER_VERSION = VS2010
- REQUIRED_CC_VER = 16.00.30319.01
- REQUIRED_LINK_VER = 10.00.30319.01
- else
- ifeq ($(ARCH), ia64)
- REQUIRED_COMPILER_NAME = Microsoft Platform SDK - November 2001 Edition
- REQUIRED_COMPILER_VERSION = VS2003
- REQUIRED_CC_VER = 13.00.9337.7
- REQUIRED_LINK_VER = 7.00.9337.7
- endif
- ifeq ($(ARCH), amd64)
- REQUIRED_COMPILER_NAME = Visual Studio 10
- REQUIRED_COMPILER_VERSION = VS2010
- REQUIRED_CC_VER = 16.00.30319.01
- REQUIRED_LINK_VER = 10.00.30319.01
- endif
- endif
+ REQUIRED_COMPILER_NAME = Visual Studio 10
+ REQUIRED_COMPILER_VERSION = VS2010
+ REQUIRED_CC_VER = 16.00.30319.01
+ REQUIRED_LINK_VER = 10.00.30319.01
endif
ifeq ($(CC_VERSION),gcc)
REQUIRED_CC_VER = 3.4.3
diff -r fe27fe44ac51 -r afcc1530e68b make/common/shared/Defs-windows.gmk
--- a/make/common/shared/Defs-windows.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/shared/Defs-windows.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -333,136 +333,26 @@
export WINDOWSSDKDIR
endif
-# Setup for VS2010 is simple, others logic is historic
-ifeq ($(VS2010_EXISTS),true)
-
- # VS2010 Compiler root directory
- _msvc_dir :=$(VS100COMNTOOLS)/../../Vc
- # SDK root directory
- _ms_sdk :=$(WINDOWSSDKDIR)
- # Compiler bin directory and redist directory
- ifeq ($(ARCH_DATA_MODEL), 32)
- _compiler_bin :=$(_msvc_dir)/Bin
- _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x86/Microsoft.VC100.CRT)
- endif
- ifeq ($(ARCH_DATA_MODEL), 64)
- _compiler_bin :=$(_msvc_dir)/bin/amd64
- _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x64/Microsoft.VC100.CRT)
- endif
- ifeq ($(_redist_sdk),)
- _redist_sdk :=$(_system_root)/system32
- endif
-
-else # Not VS2010
-
- # Compilers, SDK, and Visual Studio (MSDEV) [32bit is different from 64bit]
- ifeq ($(ARCH_DATA_MODEL), 32)
+ifneq ($(VS2010_EXISTS),true)
+ x:=$(error ERROR: No VS2010 found on system.)
+endif
- # Try looking in MSVCDIR or MSVCDir area first
- # (set by vcvars32.bat for VC .NET, not defined in the VC 2008/2010)
- ifdef MSVCDIR
- xMSVCDIR :="$(subst \,/,$(MSVCDIR))"
- _msvc_dir :=$(call FullPath,$(xMSVCDIR))
- else
- ifdef MSVCDir
- xMSVCDIR :="$(subst \,/,$(MSVCDir))"
- _msvc_dir :=$(call FullPath,$(xMSVCDIR))
- endif
- endif
- # If we still don't have it, look for VSnnCOMNTOOLS (newest first),
- # set by installer?
- ifeq ($(_msvc_dir),)
- ifdef VS90COMNTOOLS # /Common/Tools directory, use ../../Vc
- xVS90COMNTOOLS :="$(subst \,/,$(VS90COMNTOOLS))"
- _vs90tools :=$(call FullPath,$(xVS90COMNTOOLS))
- endif
- ifneq ($(_vs90tools),)
- _msvc_dir :=$(_vs90tools)/../../Vc
- else
- ifdef VS80COMNTOOLS # /Common/Tools directory, use ../../Vc
- xVS80COMNTOOLS :="$(subst \,/,$(VS80COMNTOOLS))"
- _vs80tools :=$(call FullPath,$(xVS80COMNTOOLS))
- endif
- ifneq ($(_vs80tools),)
- _msvc_dir :=$(_vs80tools)/../../Vc
- else
- ifdef VS71COMNTOOLS # /Common/Tools directory, use ../../Vc7
- xVS71COMNTOOLS :="$(subst \,/,$(VS71COMNTOOLS))"
- _vs71tools :=$(call FullPath,$(xVS71COMNTOOLS))
- endif
- ifneq ($(_vs71tools),)
- _msvc_dir :=$(_vs71tools)/../../Vc7
- endif
- endif
- endif
- endif
-
- ifneq ($(_msvc_dir),)
- _compiler_bin :=$(_msvc_dir)/Bin
- # Assume PlatformSDK is in VS71 (will be empty if VS90)
- _ms_sdk :=$(call FullPath,$(_msvc_dir)/PlatformSDK)
- _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x86/Microsoft.VC90.CRT)
- ifeq ($(_redist_sdk),)
- _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x86/Microsoft.VC80.CRT)
- ifeq ($(_redist_sdk),)
- _redist_sdk :=$(call FullPath,$(_msvc_dir)/../SDK/v1.1/Bin)
- endif
- endif
- endif
- endif
-
- # The Microsoft Platform SDK installed by itself
- ifneq ($(_program_files),)
- _PSDK :="$(_program_files)/Microsoft SDKs/Windows/v6.1/"
- _psdk :=$(call FullPath,$(xMSSDK61))
- ifeq ($(_psdk),)
- xPSDK :="$(_program_files)/Microsoft Platform SDK"
- _psdk :=$(call FullPath,$(xPSDK))
- ifeq ($(_psdk),)
- xPSDK :="$(_program_files)/Microsoft SDK"
- _psdk :=$(call FullPath,$(xMSSDK))
- endif
- endif
- endif
-
- # If no SDK found yet, look in other places
- ifeq ($(_ms_sdk),)
- ifdef MSSDK
- xMSSDK :="$(subst \,/,$(MSSDK))"
- _ms_sdk :=$(call FullPath,$(xMSSDK))
- else
- ifdef MSSdk
- xMSSDK :="$(subst \,/,$(MSSdk))"
- _ms_sdk :=$(call FullPath,$(xMSSDK))
- else
- _ms_sdk :=$(_psdk)
- endif
- endif
- endif
-
- # Compilers for 64bit may be from the free SDK, or Visual Studio Professional.
- ifeq ($(ARCH_DATA_MODEL), 64)
- xVS2008 :="$(_program_files32)/Microsoft Visual Studio 9.0/"
- VS2008 :=$(call FullPath,$(xVS2008))
- ifneq ($(VS2008),)
- _compiler_bin :=$(VS2008)/VC/Bin/$(ARCH)
- xMSSDK61 :="$(_program_files)/Microsoft SDKs/Windows/v6.1/"
- MSSDK61 :=$(call FullPath,$(xMSSDK61))
- _redist_sdk :=$(VS2008)/VC/redist/x64/Microsoft.VC90.CRT
- else
- ifneq ($(_ms_sdk),)
- ifeq ($(ARCH), ia64)
- _compiler_bin :=$(_ms_sdk)/Bin/Win64
- endif
- ifeq ($(ARCH), amd64)
- _compiler_bin :=$(_ms_sdk)/Bin/Win64/x86/$(ARCH)
- _redist_sdk :=$(_ms_sdk)/redist/win64/AMD64
- endif
- endif
- endif
- endif
-
-endif # VS2010_EXISTS
+# VS2010 Compiler root directory
+_msvc_dir :=$(VS100COMNTOOLS)/../../Vc
+# SDK root directory
+_ms_sdk :=$(WINDOWSSDKDIR)
+# Compiler bin directory and redist directory
+ifeq ($(ARCH_DATA_MODEL), 32)
+ _compiler_bin :=$(_msvc_dir)/Bin
+ _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x86/Microsoft.VC100.CRT)
+endif
+ifeq ($(ARCH_DATA_MODEL), 64)
+ _compiler_bin :=$(_msvc_dir)/bin/amd64
+ _redist_sdk :=$(call FullPath,$(_msvc_dir)/redist/x64/Microsoft.VC100.CRT)
+endif
+ifeq ($(_redist_sdk),)
+ _redist_sdk :=$(_system_root)/system32
+endif
# Location on system where jdk installs might be
ifneq ($(_program_files),)
@@ -566,20 +456,8 @@
_BOOTDIR3 =$(SLASH_JAVA)/re/jdk/$(PREVIOUS_JDK_VERSION)/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
endif
-# 32bit always needs the MSVCRNN runtime, 64bit does when using VS2008
-ifeq ($(ARCH_DATA_MODEL), 32)
- _NEEDS_MSVCRNN = true
-else
- ifeq ($(VS2010_EXISTS),true)
- _NEEDS_MSVCRNN = true
- else
- ifneq ($(VS2008),)
- _NEEDS_MSVCRNN = true
- else
- _NEEDS_MSVCRNN = false
- endif
- endif
-endif
+# Everybody needs the MSVCRNN runtime starting with VS2010
+_NEEDS_MSVCRNN = true
ifeq ($(_NEEDS_MSVCRNN), true)
# MSVCRNN_DLL_PATH: location of msvcrnn.dll that will be re-distributed
@@ -758,8 +636,6 @@
# Special define for checking the binaries
-ifeq ($(VS2010_EXISTS),true)
-
# All windows dll and exe files should have been built with /NXCOMPAT
# and be setup for dynamic base addresses.
# In addition, we should not be dependent on certain dll files that
@@ -841,12 +717,3 @@
endef
endif
-else
-
-# 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
-endef
-
-endif
-
diff -r fe27fe44ac51 -r afcc1530e68b make/common/shared/Sanity.gmk
--- a/make/common/shared/Sanity.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/common/shared/Sanity.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -996,25 +996,15 @@
######################################################
sane-msdevtools_path:
ifeq ($(PLATFORM), windows)
- ifneq ($(COMPILER_VERSION), VS2010)
- @if [ "$(MSDEVTOOLS_PATH)" != "" -a ! -r "$(MSDEVTOOLS_PATH)" ]; then \
- $(ECHO) "ERROR: You do not have a valid MSDEVTOOLS_PATH setting. \n" \
- " Please check your access to \n" \
- " $(MSDEVTOOLS_PATH) \n" \
- " and/or check your value of ALT_MSDEVTOOLS_PATH. \n" \
- "" >> $(ERROR_FILE) ; \
- fi
- else
- ifeq ($(wildcard $(RC)),)
+ ifeq ($(wildcard $(RC)),)
@$(ECHO) "ERROR: Cannot find the RC utility from path: $(RC)\n" \
" This is normally obtained from the WINDOWSSDKDIR." \
"" >> $(ERROR_FILE)
- endif
- ifeq ($(wildcard $(DUMPBIN)),)
+ endif
+ ifeq ($(wildcard $(DUMPBIN)),)
@$(ECHO) "ERROR: Cannot find the DUMPBIN utility from path: $(DUMPBIN)\n" \
" This is normally obtained from the COMPILER_PATH." \
"" >> $(ERROR_FILE)
- endif
endif
endif
@@ -1432,7 +1422,6 @@
######################################################
sane-install-mssdk_path:
ifeq ($(PLATFORM), windows)
- ifeq ($(COMPILER_VERSION), VS2010)
@if [ -z "$(WINDOWSSDKDIR)" ]; then \
$(ECHO) "WARNING: Your WINDOWSSDKDIR setting is empty.\n" \
" It is recommended to set ALT_WINDOWSSDKDIR.\n" \
@@ -1445,7 +1434,6 @@
" and/or check your value of ALT_WINDOWSSDKDIR. \n" \
"" >> $(ERROR_FILE) ; \
fi
- endif
@if [ -z "$(INSTALL_MSSDK)" ]; then \
$(ECHO) "WARNING: Your INSTALL_MSSDK setting is empty.\n" \
" It is recommended to set ALT_INSTALL_MSSDK.\n" \
diff -r fe27fe44ac51 -r afcc1530e68b make/docs/CORE_PKGS.gmk
--- a/make/docs/CORE_PKGS.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/docs/CORE_PKGS.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2001, 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
@@ -55,7 +55,7 @@
# This is a list of regular expressions. So foo.* matches "foo" and "foo.bar".
#
ACTIVE_JSR_PKGS= \
- java.dyn \
+ java.lang.invoke \
java.sql \
javax.activation \
javax.annotation.* \
@@ -97,11 +97,11 @@
java.awt.print \
java.beans \
java.beans.beancontext \
- java.dyn \
java.io \
java.lang \
java.lang.annotation \
java.lang.instrument \
+ java.lang.invoke \
java.lang.management \
java.lang.ref \
java.lang.reflect \
diff -r fe27fe44ac51 -r afcc1530e68b make/java/Makefile
--- a/make/java/Makefile Thu Mar 03 14:16:57 2011 -0800
+++ b/make/java/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1995, 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
@@ -44,7 +44,7 @@
SUBDIRS_desktop = awt applet beans
SUBDIRS_management = management
SUBDIRS_misc = npt java_crw_demo java_hprof_demo \
- logging instrument dyn sql rmi
+ logging instrument invoke sql rmi
ifeq ($(PLATFORM), solaris)
diff -r fe27fe44ac51 -r afcc1530e68b make/java/dyn/Makefile
--- a/make/java/dyn/Makefile Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +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.
-#
-
-BUILDDIR = ../..
-
-PACKAGE = java.dyn
-PRODUCT = java
-include $(BUILDDIR)/common/Defs.gmk
-
-AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
-
-# The sources built here use new language syntax to generate
-# method handle calls. Let's be sure we are using that format.
-LANGUAGE_VERSION = -source 7
-CLASS_VERSION = -target 7
-
-# Tell the compiler not to accept transitional forms.
-OTHER_JAVACFLAGS = -XDallowTransitionalJSR292=no
-
-include $(BUILDDIR)/common/Classes.gmk
diff -r fe27fe44ac51 -r afcc1530e68b make/java/invoke/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/java/invoke/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,42 @@
+#
+# 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
+# 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.
+#
+
+BUILDDIR = ../..
+
+PACKAGE = java.lang.invoke
+PRODUCT = java
+include $(BUILDDIR)/common/Defs.gmk
+
+AUTO_FILES_JAVA_DIRS = java/lang/invoke sun/invoke
+FILES_java = \
+ java/lang/ClassValue.java \
+ java/lang/BootstrapMethodError.java
+
+# The sources built here use new language syntax to generate
+# method handle calls. Let's be sure we are using that format.
+LANGUAGE_VERSION = -source 7
+CLASS_VERSION = -target 7
+
+include $(BUILDDIR)/common/Classes.gmk
diff -r fe27fe44ac51 -r afcc1530e68b make/java/text/base/FILES_java.gmk
--- a/make/java/text/base/FILES_java.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/java/text/base/FILES_java.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -136,6 +136,7 @@
sun/text/resources/CollationData_sl.java \
sun/text/resources/CollationData_sq.java \
sun/text/resources/CollationData_sr.java \
+ sun/text/resources/CollationData_sr_Latn.java \
sun/text/resources/CollationData_sv.java \
sun/text/resources/CollationData_tr.java \
sun/text/resources/CollationData_uk.java \
@@ -251,6 +252,10 @@
sun/text/resources/FormatData_sr_CS.java \
sun/text/resources/FormatData_sr_ME.java \
sun/text/resources/FormatData_sr_RS.java \
+ sun/text/resources/FormatData_sr_Latn.java \
+ sun/text/resources/FormatData_sr_Latn_BA.java \
+ sun/text/resources/FormatData_sr_Latn_ME.java \
+ sun/text/resources/FormatData_sr_Latn_RS.java \
sun/text/resources/FormatData_sv.java \
sun/text/resources/FormatData_sv_SE.java \
sun/text/resources/FormatData_tr.java \
diff -r fe27fe44ac51 -r afcc1530e68b make/java/util/FILES_properties.gmk
--- a/make/java/util/FILES_properties.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/java/util/FILES_properties.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -65,6 +65,7 @@
sun/util/resources/LocaleNames_sl.properties \
sun/util/resources/LocaleNames_sq.properties \
sun/util/resources/LocaleNames_sr.properties \
+ sun/util/resources/LocaleNames_sr_Latn.properties \
sun/util/resources/LocaleNames_sv.properties \
sun/util/resources/LocaleNames_tr.properties \
sun/util/resources/LocaleNames_uk.properties \
@@ -111,6 +112,9 @@
sun/util/resources/CalendarData_sl.properties \
sun/util/resources/CalendarData_sq.properties \
sun/util/resources/CalendarData_sr.properties \
+ sun/util/resources/CalendarData_sr_Latn_BA.properties \
+ sun/util/resources/CalendarData_sr_Latn_ME.properties \
+ sun/util/resources/CalendarData_sr_Latn_RS.properties \
sun/util/resources/CalendarData_sv.properties \
sun/util/resources/CalendarData_tr.properties \
sun/util/resources/CalendarData_uk.properties \
@@ -186,6 +190,7 @@
sun/util/resources/CurrencyNames_nl_NL.properties \
sun/util/resources/CurrencyNames_no_NO.properties \
sun/util/resources/CurrencyNames_pl_PL.properties \
+ sun/util/resources/CurrencyNames_pt.properties \
sun/util/resources/CurrencyNames_pt_BR.properties \
sun/util/resources/CurrencyNames_pt_PT.properties \
sun/util/resources/CurrencyNames_ro_RO.properties \
@@ -196,6 +201,10 @@
sun/util/resources/CurrencyNames_sr_BA.properties \
sun/util/resources/CurrencyNames_sr_CS.properties \
sun/util/resources/CurrencyNames_sr_ME.properties \
+ sun/util/resources/CurrencyNames_sr_RS.properties \
+ sun/util/resources/CurrencyNames_sr_Latn_BA.properties \
+ sun/util/resources/CurrencyNames_sr_Latn_ME.properties \
+ sun/util/resources/CurrencyNames_sr_Latn_RS.properties \
sun/util/resources/CurrencyNames_sv.properties \
sun/util/resources/CurrencyNames_sv_SE.properties \
sun/util/resources/CurrencyNames_tr_TR.properties \
diff -r fe27fe44ac51 -r afcc1530e68b make/mkdemo/jfc/Laffy/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mkdemo/jfc/Laffy/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 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.
+#
+
+#
+# Makefile to build the Laffy demo.
+#
+
+BUILDDIR = ../../..
+PRODUCT = demo/jfc
+DEMONAME = Laffy
+include $(BUILDDIR)/common/Defs.gmk
+
+DEMO_ROOT = $(CLOSED_SRC)/share/demo/jfc/$(DEMONAME)
+DEMO_DESTDIR = $(DEMODIR)/jfc/$(DEMONAME)
+DEMO_TOPFILES = ./readme.html ./laffy.png
+DEMO_SKIP_SRCZIP = true
+
+#
+# Demo jar building rules.
+#
+include $(BUILDDIR)/common/Demo.gmk
diff -r fe27fe44ac51 -r afcc1530e68b make/mkdemo/jfc/Makefile
--- a/make/mkdemo/jfc/Makefile Thu Mar 03 14:16:57 2011 -0800
+++ b/make/mkdemo/jfc/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -43,7 +43,7 @@
# Some demos aren't currently included in OpenJDK
ifndef OPENJDK
- SUBDIRS += Java2D SwingSet2 SwingSet3 Stylepad
+ SUBDIRS += Java2D Laffy SwingSet2 SwingSet3 Stylepad
endif
include $(BUILDDIR)/common/Subdirs.gmk
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/cmm/kcms/Makefile
--- a/make/sun/cmm/kcms/Makefile Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/cmm/kcms/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -71,7 +71,8 @@
# Extra rules
#
ifeq ($(PLATFORM), linux)
-LDLIBS += -lpthread
+ LDLIBS += -lpthread
+ OTHER_CFLAGS += -Wno-missing-field-initializers
endif
clean clobber::
@@ -103,6 +104,5 @@
endif # PLATFORM
-#CFLAGS += -DJAVACMM -DFUT_CALC_EX -DNO_FUT_GCONST
-CFLAGS += -DFUT_CALC_EX -DNO_FUT_GCONST
+CFLAGS += -DJAVACMM -DFUT_CALC_EX -DNO_FUT_GCONST
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/cmm/lcms/Makefile
--- a/make/sun/cmm/lcms/Makefile Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/cmm/lcms/Makefile Fri Apr 08 10:27:23 2011 -0700
@@ -81,10 +81,6 @@
ifeq ($(PLATFORM), windows)
OTHER_CFLAGS += -DCMS_IS_WINDOWS_
-ifeq ($(COMPILER_VERSION), VS2003)
-OTHER_CFLAGS += -Dsqrtf=sqrt
-endif
-
OTHER_LDLIBS = $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
OTHER_INCLUDES += -I$(SHARE_SRC)/native/sun/java2d \
-I$(SHARE_SRC)/native/sun/awt/debug
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/VERSION
--- a/make/sun/javazic/tzdata/VERSION Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/VERSION Fri Apr 08 10:27:23 2011 -0700
@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-tzdata2011b
+tzdata2011d
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/australasia
--- a/make/sun/javazic/tzdata/australasia Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/australasia Fri Apr 08 10:27:23 2011 -0700
@@ -531,11 +531,31 @@
# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
# backwards from 1:00am to 12:00am"
+# From Raymond Hughes (2011-03-07)
+# I believe this will be posted shortly on the website
+#
+# www.mcil.gov.ws
+#
+#
+# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
+#
+# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
+# businesses and the general public are hereby advised that daylight
+# saving time is on the first Saturday of April 2011 (02/04/11).
+#
+# The public is therefore advised that when the standard time strikes
+# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
+# then all instruments used to measure standard time are to be
+# adjusted/changed to three oclock (3:00am or 0300Hrs).
+#
+# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
+# INDUSTRY AND LABOUR 28th February 2011
+
Zone Pacific/Apia 12:33:04 - LMT 1879 Jul 5
-11:26:56 - LMT 1911
-11:30 - SAMT 1950 # Samoa Time
-11:00 - WST 2010 Sep 26
- -11:00 1:00 WSDT 2011 Apr 3 1:00
+ -11:00 1:00 WSDT 2011 Apr 2 4:00
-11:00 - WST
# Solomon Is
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/etcetera
--- a/make/sun/javazic/tzdata/etcetera Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/etcetera Fri Apr 08 10:27:23 2011 -0700
@@ -58,8 +58,7 @@
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UTC (i.e. east of Greenwich).
#
-# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation
-# (which is not yet supported by the tz code) allows for
+# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for
# TZ='+4'; if you want time zone abbreviations conforming to
# ISO 8601 you can use TZ='<-0400>+4'. Thus the commonly-expected
# offset is kept within the angle bracket (and is used for display)
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/europe
--- a/make/sun/javazic/tzdata/europe Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/europe Fri Apr 08 10:27:23 2011 -0700
@@ -2505,25 +2505,18 @@
# (on a non-government server though) describing dates between 2002 and 2006:
# http://www.alomaliye.com/bkk_2002_3769.htm
-# From Sue Williams (2008-08-11):
-# I spotted this news article about a potential change in Turkey.
-#
-#
-# http://www.hurriyet.com.tr/english/domestic/9626174.asp?scr=1
+# From Gökdeniz Karadağ (2011-03-10):
+#
+# According to the articles linked below, Turkey will change into summer
+# time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
+# This change is due to a nationwide exam on 27th.
+#
+#
+# http://www.worldbulletin.net/?aType=haber&ArticleID=70872
#
-
-# From Sue Williams (2008-08-20):
-# This article says that around the end of March 2011, Turkey wants to
-# adjust the clocks forward by 1/2 hour and stay that way permanently.
-# The article indicates that this is a change in timezone offset in addition
-# to stopping observance of DST.
-# This proposal has not yet been approved.
-#
-# Read more here...
-#
-# Turkey to abandon daylight saving time in 2011
-#
-# http://www.turkishdailynews.com.tr/article.php?enewsid=112989
+# Turkish:
+#
+# http://www.hurriyet.com.tr/ekonomi/17230464.asp?gid=373
#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
@@ -2591,6 +2584,8 @@
2:00 Turkey EE%sT 1978 Oct 15
3:00 Turkey TR%sT 1985 Apr 20 # Turkey Time
2:00 Turkey EE%sT 2007
+ 2:00 EU EE%sT 2011 Mar 27 1:00u
+ 2:00 - EET 2011 Mar 28 1:00u
2:00 EU EE%sT
Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents.
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/leapseconds
--- a/make/sun/javazic/tzdata/leapseconds Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/leapseconds Fri Apr 08 10:27:23 2011 -0700
@@ -78,13 +78,13 @@
# SERVICE DE LA ROTATION TERRESTRE
# OBSERVATOIRE DE PARIS
# 61, Av. de l'Observatoire 75014 PARIS (France)
-# Tel. : 33 (0) 1 40 51 22 26
+# Tel. : 33 (0) 1 40 51 22 29
# FAX : 33 (0) 1 40 51 22 91
# Internet : services.iers@obspm.fr
#
-# Paris, 14 July 2010
+# Paris, 2 February 2011
#
-# Bulletin C 40
+# Bulletin C 41
#
# To authorities responsible
# for the measurement and
@@ -92,9 +92,9 @@
#
# INFORMATION ON UTC - TAI
#
-# NO positive leap second will be introduced at the end of December 2010.
+# NO positive leap second will be introduced at the end of June 2011.
# The difference between Coordinated Universal Time UTC and the
-# International Atomic Time TAI is :
+# International Atomic Time TAI is :
#
# from 2009 January 1, 0h UTC, until further notice : UTC-TAI = -34 s
#
@@ -104,6 +104,6 @@
# will be no time step at the next possible date.
#
# Daniel GAMBIS
-# Director
-# Earth Orientation Center of IERS
+# Head
+# Earth Orientation Center of the IERS
# Observatoire de Paris, France
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/northamerica
--- a/make/sun/javazic/tzdata/northamerica Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/northamerica Fri Apr 08 10:27:23 2011 -0700
@@ -448,15 +448,74 @@
# were nearby inhabitants in some cases and for our purposes perhaps
# it's best to simply use the official transition.
#
+
+# From Steve Ferguson (2011-01-31):
+# The author lives in Alaska and many of the references listed are only
+# available to Alaskan residents.
+#
+#
+# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
+#
+
+# From Arthur David Olson (2011-02-01):
+# Here's database-relevant material from the 2001 "Alaska History" article:
+#
+# On September 20 [1979]...DOT...officials decreed that on April 27,
+# 1980, Juneau and other nearby communities would move to Yukon Time.
+# Sitka, Petersburg, Wrangell, and Ketchikan, however, would remain on
+# Pacific Time.
+#
+# ...on September 22, 1980, DOT Secretary Neil E. Goldschmidt rescinded the
+# Department's September 1979 decision. Juneau and other communities in
+# northern Southeast reverted to Pacific Time on October 26.
+#
+# On October 28 [1983]...the Metlakatla Indian Community Council voted
+# unanimously to keep the reservation on Pacific Time.
+#
+# According to DOT official Joanne Petrie, Indian reservations are not
+# bound to follow time zones imposed by neighboring jurisdictions.
+#
+# (The last is consistent with how the database now handles the Navajo
+# Nation.)
+
+# From Arthur David Olson (2011-02-09):
+# I just spoke by phone with a staff member at the Metlakatla Indian
+# Community office (using contact information available at
+#
+# http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
+# ).
+# It's shortly after 1:00 here on the east coast of the United States;
+# the staffer said it was shortly after 10:00 there. When I asked whether
+# that meant they were on Pacific time, they said no--they were on their
+# own time. I asked about daylight saving; they said it wasn't used. I
+# did not inquire about practices in the past.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Juneau 15:02:19 - LMT 1867 Oct 18
-8:57:41 - LMT 1900 Aug 20 12:00
-8:00 - PST 1942
-8:00 US P%sT 1946
-8:00 - PST 1969
+ -8:00 US P%sT 1980 Apr 27 2:00
+ -9:00 US Y%sT 1980 Oct 26 2:00
-8:00 US P%sT 1983 Oct 30 2:00
-9:00 US Y%sT 1983 Nov 30
-9:00 US AK%sT
+Zone America/Sitka -14:58:47 - LMT 1867 Oct 18
+ -9:01:13 - LMT 1900 Aug 20 12:00
+ -8:00 - PST 1942
+ -8:00 US P%sT 1946
+ -8:00 - PST 1969
+ -8:00 US P%sT 1983 Oct 30 2:00
+ -9:00 US Y%sT 1983 Nov 30
+ -9:00 US AK%sT
+Zone America/Metlakatla 15:13:42 - LMT 1867 Oct 18
+ -8:46:18 - LMT 1900 Aug 20 12:00
+ -8:00 - PST 1942
+ -8:00 US P%sT 1946
+ -8:00 - PST 1969
+ -8:00 US P%sT 1983 Oct 30 2:00
+ -8:00 US MeST
Zone America/Yakutat 14:41:05 - LMT 1867 Oct 18
-9:18:55 - LMT 1900 Aug 20 12:00
-9:00 - YST 1942
@@ -2569,6 +2628,21 @@
# the time was announced as "diez cinco"--the same time as here, indicating
# that has indeed switched to DST. Assume second Sunday from 2009 forward.
+# From Steffen Thorsen (2011-03-08):
+# Granma announced that Cuba is going to start DST on 2011-03-20 00:00:00
+# this year. Nothing about the end date known so far (if that has
+# changed at all).
+#
+# Source:
+#
+# http://granma.co.cu/2011/03/08/nacional/artic01.html
+#
+#
+# Our info:
+#
+# http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
+#
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Cuba 1928 only - Jun 10 0:00 1:00 D
Rule Cuba 1928 only - Oct 10 0:00 0 S
@@ -2602,7 +2676,9 @@
Rule Cuba 2006 max - Oct lastSun 0:00s 0 S
Rule Cuba 2007 only - Mar Sun>=8 0:00s 1:00 D
Rule Cuba 2008 only - Mar Sun>=15 0:00s 1:00 D
-Rule Cuba 2009 max - Mar Sun>=8 0:00s 1:00 D
+Rule Cuba 2009 2010 - Mar Sun>=8 0:00s 1:00 D
+Rule Cuba 2011 only - Mar Sun>=15 0:00s 1:00 D
+Rule Cuba 2012 max - Mar Sun>=8 0:00s 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Havana -5:29:28 - LMT 1890
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/southamerica
--- a/make/sun/javazic/tzdata/southamerica Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/southamerica Fri Apr 08 10:27:23 2011 -0700
@@ -1176,6 +1176,23 @@
# From Arthur Daivd Olson (2010-03-06):
# Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
+# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
+# It appears that the Chilean government has decided to postpone the
+# change from summer time to winter time again, by three weeks to April
+# 2nd:
+#
+# http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
+#
+#
+# This is not yet reflected in the offical "cambio de hora" site, but
+# probably will be soon:
+#
+# http://www.horaoficial.cl/cambio.htm
+#
+
+# From Arthur David Olson (2011-03-02):
+# The emol.com article mentions a water shortage as the cause of the
+# postponement, which may mean that it's not a permanent change.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Chile 1927 1932 - Sep 1 0:00 1:00 S
Rule Chile 1928 1932 - Apr 1 0:00 0 -
@@ -1211,8 +1228,8 @@
# which is used below in specifying the transition.
Rule Chile 2008 only - Mar 30 3:00u 0 -
Rule Chile 2009 only - Mar Sun>=9 3:00u 0 -
-Rule Chile 2010 only - Apr 4 3:00u 0 -
-Rule Chile 2011 max - Mar Sun>=9 3:00u 0 -
+Rule Chile 2010 2011 - Apr Sun>=1 3:00u 0 -
+Rule Chile 2012 max - Mar Sun>=9 3:00u 0 -
# IATA SSIM anomalies: (1992-02) says 1992-03-14;
# (1996-09) says 1998-03-08. Ignore these.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/javazic/tzdata/zone.tab
--- a/make/sun/javazic/tzdata/zone.tab Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/javazic/tzdata/zone.tab Fri Apr 08 10:27:23 2011 -0700
@@ -434,9 +434,11 @@
US +340308-1181434 America/Los_Angeles Pacific Time
US +611305-1495401 America/Anchorage Alaska Time
US +581807-1342511 America/Juneau Alaska Time - Alaska panhandle
+US +571035-1351807 America/Sitka Alaska Time - southeast Alaska panhandle
US +593249-1394338 America/Yakutat Alaska Time - Alaska panhandle neck
US +643004-1652423 America/Nome Alaska Time - west Alaska
US +515248-1763929 America/Adak Aleutian Islands
+US +550737-1313435 America/Metlakatla Metlakatla Time - Annette Island
US +211825-1575130 Pacific/Honolulu Hawaii
UY -3453-05611 America/Montevideo
UZ +3940+06648 Asia/Samarkand west Uzbekistan
diff -r fe27fe44ac51 -r afcc1530e68b make/sun/net/FILES_java.gmk
--- a/make/sun/net/FILES_java.gmk Thu Mar 03 14:16:57 2011 -0800
+++ b/make/sun/net/FILES_java.gmk Fri Apr 08 10:27:23 2011 -0700
@@ -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
@@ -34,6 +34,7 @@
sun/net/ProgressListener.java \
sun/net/ProgressMeteringPolicy.java \
sun/net/SocksProxy.java \
+ sun/net/ResourceManager.java \
sun/net/TelnetInputStream.java \
sun/net/TelnetOutputStream.java \
sun/net/TelnetProtocolException.java \
@@ -100,6 +101,7 @@
sun/net/www/protocol/http/NegotiateAuthentication.java \
sun/net/www/protocol/http/Negotiator.java \
sun/net/www/protocol/http/ntlm/NTLMAuthentication.java \
+ sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback.java \
sun/net/www/protocol/http/spnego/NegotiatorImpl.java \
sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java \
sun/net/www/protocol/http/logging/HttpLogFormatter.java \
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/com/sun/org/apache/xml/internal/security/transforms/Transform.java
--- a/src/share/classes/com/sun/org/apache/xml/internal/security/transforms/Transform.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/com/sun/org/apache/xml/internal/security/transforms/Transform.java Fri Apr 08 10:27:23 2011 -0700
@@ -210,6 +210,8 @@
public static void init() {
if (!alreadyInitialized) {
transformClassHash = new HashMap(10);
+ // make sure builtin algorithms are all registered first
+ com.sun.org.apache.xml.internal.security.Init.init();
alreadyInitialized = true;
}
}
@@ -236,12 +238,7 @@
"algorithm.alreadyRegistered", exArgs);
}
- ClassLoader cl = (ClassLoader) AccessController.doPrivileged(
- new PrivilegedAction() {
- public Object run() {
- return Thread.currentThread().getContextClassLoader();
- }
- });
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
transformClassHash.put
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/AWTEvent.java
--- a/src/share/classes/java/awt/AWTEvent.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/AWTEvent.java Fri Apr 08 10:27:23 2011 -0700
@@ -33,6 +33,11 @@
import sun.awt.AWTAccessor;
import sun.util.logging.PlatformLogger;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+
/**
* The root event class for all AWT events.
* This class and its subclasses supercede the original
@@ -97,6 +102,22 @@
*/
protected boolean consumed = false;
+ /*
+ * The event's AccessControlContext.
+ */
+ private transient volatile AccessControlContext acc =
+ AccessController.getContext();
+
+ /*
+ * Returns the acc this event was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException("AWTEvent is missing AccessControlContext");
+ }
+ return acc;
+ }
+
transient boolean focusManagerIsDispatching = false;
transient boolean isPosted;
@@ -247,6 +268,10 @@
public boolean isSystemGenerated(AWTEvent ev) {
return ev.isSystemGenerated;
}
+
+ public AccessControlContext getAccessControlContext(AWTEvent ev) {
+ return ev.getAccessControlContext();
+ }
});
}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/Component.java
--- a/src/share/classes/java/awt/Component.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/Component.java Fri Apr 08 10:27:23 2011 -0700
@@ -59,6 +59,7 @@
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.security.AccessControlContext;
import javax.accessibility.*;
import java.applet.Applet;
@@ -471,6 +472,12 @@
static final Object LOCK = new AWTTreeLock();
static class AWTTreeLock {}
+ /*
+ * The component's AccessControlContext.
+ */
+ private transient volatile AccessControlContext acc =
+ AccessController.getContext();
+
/**
* Minimum size.
* (This field perhaps should have been transient).
@@ -671,6 +678,16 @@
return objectLock;
}
+ /*
+ * Returns the acc this component was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException("Component is missing AccessControlContext");
+ }
+ return acc;
+ }
+
boolean isPacked = false;
/**
@@ -950,6 +967,10 @@
public void processEvent(Component comp, AWTEvent e) {
comp.processEvent(e);
}
+
+ public AccessControlContext getAccessControlContext(Component comp) {
+ return comp.getAccessControlContext();
+ }
});
}
@@ -3873,6 +3894,11 @@
* supported or met
* @exception ClassCastException if the component is not a canvas or
* window.
+ * @exception IllegalStateException if the component has no peer
+ * @exception IllegalArgumentException if {@code numBuffers} is less than two,
+ * or if {@code BufferCapabilities.isPageFlipping} is not
+ * {@code true}.
+ * @see #createBuffers(int, BufferCapabilities)
*/
protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps)
throws AWTException
@@ -8608,6 +8634,8 @@
{
objectLock = new Object();
+ acc = AccessController.getContext();
+
s.defaultReadObject();
appContext = AppContext.getAppContext();
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/EventQueue.java
--- a/src/share/classes/java/awt/EventQueue.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/EventQueue.java Fri Apr 08 10:27:23 2011 -0700
@@ -48,6 +48,12 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+import sun.misc.SharedSecrets;
+import sun.misc.JavaSecurityAccess;
+
/**
* EventQueue is a platform-independent class
* that queues events, both from the underlying peer classes
@@ -612,6 +618,9 @@
return null;
}
+ private static final JavaSecurityAccess javaSecurityAccess =
+ SharedSecrets.getJavaSecurityAccess();
+
/**
* Dispatches an event. The manner in which the event is
* dispatched depends upon the type of the event and the
@@ -650,13 +659,49 @@
* @throws NullPointerException if event is null
* @since 1.2
*/
- protected void dispatchEvent(AWTEvent event) {
+ protected void dispatchEvent(final AWTEvent event) {
+ final Object src = event.getSource();
+ final PrivilegedAction action = new PrivilegedAction() {
+ public Void run() {
+ dispatchEventImpl(event, src);
+ return null;
+ }
+ };
+
+ final AccessControlContext stack = AccessController.getContext();
+ final AccessControlContext srcAcc = getAccessControlContextFrom(src);
+ final AccessControlContext eventAcc = event.getAccessControlContext();
+ if (srcAcc == null) {
+ javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
+ } else {
+ javaSecurityAccess.doIntersectionPrivilege(
+ new PrivilegedAction() {
+ public Void run() {
+ javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
+ return null;
+ }
+ }, stack, srcAcc);
+ }
+ }
+
+ private static AccessControlContext getAccessControlContextFrom(Object src) {
+ return src instanceof Component ?
+ ((Component)src).getAccessControlContext() :
+ src instanceof MenuComponent ?
+ ((MenuComponent)src).getAccessControlContext() :
+ src instanceof TrayIcon ?
+ ((TrayIcon)src).getAccessControlContext() :
+ null;
+ }
+
+ /**
+ * Called from dispatchEvent() under a correct AccessControlContext
+ */
+ private void dispatchEventImpl(final AWTEvent event, final Object src) {
event.isPosted = true;
- Object src = event.getSource();
if (event instanceof ActiveEvent) {
// This could become the sole method of dispatching in time.
setCurrentEventAndMostRecentTimeImpl(event);
-
((ActiveEvent)event).dispatch();
} else if (src instanceof Component) {
((Component)src).dispatchEvent(event);
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/LinearGradientPaint.java
--- a/src/share/classes/java/awt/LinearGradientPaint.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/LinearGradientPaint.java Fri Apr 08 10:27:23 2011 -0700
@@ -57,8 +57,14 @@
*
*
*
- * The user may also select what action the {@code LinearGradientPaint}
- * should take when filling color outside the start and end points.
+ * The user may also select what action the {@code LinearGradientPaint} object
+ * takes when it is filling the space outside the start and end points by
+ * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}.
+ * The distances between any two colors in any of the reflected or repeated
+ * copies of the gradient are the same as the distance between those same two
+ * colors between the start and end points.
+ * Note that some minor variations in distances may occur due to sampling at
+ * the granularity of a pixel.
* If no cycle method is specified, {@code NO_CYCLE} will be chosen by
* default, which means the endpoint colors will be used to fill the
* remaining area.
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/MenuComponent.java
--- a/src/share/classes/java/awt/MenuComponent.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/MenuComponent.java Fri Apr 08 10:27:23 2011 -0700
@@ -33,6 +33,9 @@
import sun.awt.AWTAccessor;
import javax.accessibility.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+
/**
* The abstract class MenuComponent is the superclass
* of all menu-related components. In this respect, the class
@@ -100,6 +103,23 @@
boolean newEventsOnly = false;
/*
+ * The menu's AccessControlContext.
+ */
+ private transient volatile AccessControlContext acc =
+ AccessController.getContext();
+
+ /*
+ * Returns the acc this menu component was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException(
+ "MenuComponent is missing AccessControlContext");
+ }
+ return acc;
+ }
+
+ /*
* Internal constants for serialization.
*/
final static String actionListenerK = Component.actionListenerK;
@@ -402,6 +422,9 @@
throws ClassNotFoundException, IOException, HeadlessException
{
GraphicsEnvironment.checkHeadless();
+
+ acc = AccessController.getContext();
+
s.defaultReadObject();
appContext = AppContext.getAppContext();
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/MultipleGradientPaint.java
--- a/src/share/classes/java/awt/MultipleGradientPaint.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/MultipleGradientPaint.java Fri Apr 08 10:27:23 2011 -0700
@@ -286,6 +286,10 @@
/**
* Returns a copy of the transform applied to the gradient.
*
+ *
+ * Note that if no transform is applied to the gradient
+ * when it is created, the identity transform is used.
+ *
* @return a copy of the transform applied to the gradient
*/
public final AffineTransform getTransform() {
@@ -293,10 +297,12 @@
}
/**
- * Returns the transparency mode for this Paint object.
+ * Returns the transparency mode for this {@code Paint} object.
*
- * @return an integer value representing the transparency mode for
- * this Paint object
+ * @return {@code OPAQUE} if all colors used by this
+ * {@code Paint} object are opaque,
+ * {@code TRANSLUCENT} if at least one of the
+ * colors used by this {@code Paint} object is not opaque.
* @see java.awt.Transparency
*/
public final int getTransparency() {
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/RadialGradientPaint.java
--- a/src/share/classes/java/awt/RadialGradientPaint.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/RadialGradientPaint.java Fri Apr 08 10:27:23 2011 -0700
@@ -71,8 +71,24 @@
*
*
*
- * The user may also select what action the {@code RadialGradientPaint}
- * should take when filling color outside the bounds of the circle's radius.
+ * The user may also select what action the {@code RadialGradientPaint} object
+ * takes when it is filling the space outside the circle's radius by
+ * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}.
+ * The gradient color proportions are equal for any particular line drawn
+ * from the focus point. The following figure shows that the distance AB
+ * is equal to the distance BC, and the distance AD is equal to the distance DE.
+ *
+ *
+ *
+ * If the gradient and graphics rendering transforms are uniformly scaled and
+ * the user sets the focus so that it coincides with the center of the circle,
+ * the gradient color proportions are equal for any line drawn from the center.
+ * The following figure shows the distances AB, BC, AD, and DE. They are all equal.
+ *
+ *
+ *
+ * Note that some minor variations in distances may occur due to sampling at
+ * the granularity of a pixel.
* If no cycle method is specified, {@code NO_CYCLE} will be chosen by
* default, which means the the last keyframe color will be used to fill the
* remaining area.
@@ -604,7 +620,7 @@
}
/**
- * Returns a copy of the end point of the gradient axis.
+ * Returns a copy of the focus point of the radial gradient.
*
* @return a {@code Point2D} object that is a copy of the focus point
*/
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/TrayIcon.java
--- a/src/share/classes/java/awt/TrayIcon.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/TrayIcon.java Fri Apr 08 10:27:23 2011 -0700
@@ -40,6 +40,8 @@
import sun.awt.SunToolkit;
import sun.awt.HeadlessToolkit;
import java.util.EventObject;
+import java.security.AccessControlContext;
+import java.security.AccessController;
/**
* A TrayIcon object represents a tray icon that can be
@@ -90,6 +92,7 @@
* @author Anton Tarasov
*/
public class TrayIcon {
+
private Image image;
private String tooltip;
private PopupMenu popup;
@@ -103,6 +106,24 @@
transient MouseMotionListener mouseMotionListener;
transient ActionListener actionListener;
+ /*
+ * The tray icon's AccessControlContext.
+ *
+ * Unlike the acc in Component, this field is made final
+ * because TrayIcon is not serializable.
+ */
+ private final AccessControlContext acc = AccessController.getContext();
+
+ /*
+ * Returns the acc this tray icon was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException("TrayIcon is missing AccessControlContext");
+ }
+ return acc;
+ }
+
static {
Toolkit.loadLibraries();
if (!GraphicsEnvironment.isHeadless()) {
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/doc-files/RadialGradientPaint-3.png
Binary file src/share/classes/java/awt/doc-files/RadialGradientPaint-3.png has changed
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/doc-files/RadialGradientPaint-4.png
Binary file src/share/classes/java/awt/doc-files/RadialGradientPaint-4.png has changed
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/awt/image/PackedColorModel.java
--- a/src/share/classes/java/awt/image/PackedColorModel.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/awt/image/PackedColorModel.java Fri Apr 08 10:27:23 2011 -0700
@@ -343,8 +343,13 @@
if (bitMasks.length != maskArray.length) {
return false;
}
+
+ /* compare 'effective' masks only, i.e. only part of the mask
+ * which fits the capacity of the transfer type.
+ */
+ int maxMask = (int)((1L << DataBuffer.getDataTypeSize(transferType)) - 1);
for (int i=0; i < bitMasks.length; i++) {
- if (bitMasks[i] != maskArray[i]) {
+ if ((maxMask & bitMasks[i]) != (maxMask & maskArray[i])) {
return false;
}
}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/beans/DefaultPersistenceDelegate.java
--- a/src/share/classes/java/beans/DefaultPersistenceDelegate.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/beans/DefaultPersistenceDelegate.java Fri Apr 08 10:27:23 2011 -0700
@@ -35,7 +35,7 @@
* is the delegate used by default for classes about
* which no information is available. The DefaultPersistenceDelegate
* provides, version resilient, public API-based persistence for
- * classes that follow the JavaBeans conventions without any class specific
+ * classes that follow the JavaBeans™ conventions without any class specific
* configuration.
*
* The key assumptions are that the class has a nullary constructor
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/beans/DesignMode.java
--- a/src/share/classes/java/beans/DesignMode.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/beans/DesignMode.java Fri Apr 08 10:27:23 2011 -0700
@@ -31,7 +31,7 @@
* of java.beans.beancontext.BeanContext, in order to propagate to its nested hierarchy
* of java.beans.beancontext.BeanContextChild instances, the current "designTime" property.
*
- * The JavaBeans specification defines the notion of design time as is a
+ * The JavaBeans™ specification defines the notion of design time as is a
* mode in which JavaBeans instances should function during their composition
* and customization in a interactive design, composition or construction tool,
* as opposed to runtime when the JavaBean is part of an applet, application,
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/beans/IndexedPropertyChangeEvent.java
--- a/src/share/classes/java/beans/IndexedPropertyChangeEvent.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/beans/IndexedPropertyChangeEvent.java Fri Apr 08 10:27:23 2011 -0700
@@ -26,7 +26,7 @@
/**
* An "IndexedPropertyChange" event gets delivered whenever a component that
- * conforms to the JavaBeans specification (a "bean") changes a bound
+ * conforms to the JavaBeans™ specification (a "bean") changes a bound
* indexed property. This class is an extension of PropertyChangeEvent
* but contains the index of the property that has changed.
*
* For more information about introspection and design patterns, please
* consult the
- * JavaBeans specification.
+ * JavaBeans™ specification.
*/
public class Introspector {
@@ -1245,7 +1245,7 @@
try {
type = ClassFinder.findClass(name, type.getClassLoader());
// Each customizer should inherit java.awt.Component and implement java.beans.Customizer
- // according to the section 9.3 of JavaBeans specification
+ // according to the section 9.3 of JavaBeans™ specification
if (Component.class.isAssignableFrom(type) && Customizer.class.isAssignableFrom(type)) {
return type;
}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/beans/VetoableChangeSupport.java
--- a/src/share/classes/java/beans/VetoableChangeSupport.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/beans/VetoableChangeSupport.java Fri Apr 08 10:27:23 2011 -0700
@@ -474,7 +474,7 @@
/**
* @serialField children Hashtable
* @serialField source Object
- * @serialField propertyChangeSupportSerializedDataVersion int
+ * @serialField vetoableChangeSupportSerializedDataVersion int
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("children", Hashtable.class),
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/beans/package.html
--- a/src/share/classes/java/beans/package.html Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/beans/package.html Fri Apr 08 10:27:23 2011 -0700
@@ -29,7 +29,7 @@
Contains classes related to developing
beans -- components
-based on the JavaBeansTM architecture.
+based on the JavaBeans™ architecture.
A few of the
classes are used by beans while they run in an application.
For example, the event classes are
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/CallSite.java
--- a/src/share/classes/java/dyn/CallSite.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/*
- * 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
- * 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;
-
-import sun.dyn.*;
-import sun.dyn.empty.Empty;
-import sun.misc.Unsafe;
-import java.util.Collection;
-
-/**
- * A {@code CallSite} is a holder for a variable {@link MethodHandle},
- * which is called its {@code target}.
- * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
- * all calls to the site's current target.
- * A {@code CallSite} may be associated with several {@code invokedynamic}
- * instructions, or it may be "free floating", associated with none.
- * In any case, it may be invoked through an associated method handle
- * called its {@linkplain #dynamicInvoker dynamic invoker}.
- *
- * {@code CallSite} is an abstract class which does not allow
- * direct subclassing by users. It has three immediate,
- * concrete subclasses that may be either instantiated or subclassed.
- *
- *
If a mutable target is not required, an {@code invokedynamic} instruction
- * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
- *
If a mutable target is required which has volatile variable semantics,
- * because updates to the target must be immediately and reliably witnessed by other threads,
- * a {@linkplain VolatileCallSite volatile call site} may be used.
- *
Otherwise, if a mutable target is required,
- * a {@linkplain MutableCallSite mutable call site} may be used.
- *
- *
- * A non-constant call site may be relinked by changing its target.
- * The new target must have the same {@linkplain MethodHandle#type() type}
- * as the previous target.
- * Thus, though a call site can be relinked to a series of
- * successive targets, it cannot change its type.
- *
- * Here is a sample use of call sites and bootstrap methods which links every
- * dynamic call site to print its arguments:
-
-static void test() throws Throwable {
- // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
- InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
-}
-private static void printArgs(Object... args) {
- System.out.println(java.util.Arrays.deepToString(args));
-}
-private static final MethodHandle printArgs;
-static {
- MethodHandles.Lookup lookup = MethodHandles.lookup();
- Class thisClass = lookup.lookupClass(); // (who am I?)
- printArgs = lookup.findStatic(thisClass,
- "printArgs", MethodType.methodType(void.class, Object[].class));
-}
-private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
- // ignore caller and name, but match the type:
- return new ConstantCallSite(printArgs.asType(type));
-}
-
- * @author John Rose, JSR 292 EG
- */
-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)
- private int vmindex; // supplied by the JVM (BCI within calling method)
-
- // The actual payload of this call site:
- /*package-private*/
- MethodHandle target;
-
- // Remove this field for PFD and delete deprecated methods:
- private MemberName calleeNameRemoveForPFD;
-
- /**
- * 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.
- *
- * Before this {@code CallSite} object is returned from a bootstrap method,
- * it is usually provided with a more useful target method,
- * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
- * @throws NullPointerException if the proposed type is null
- */
- /*package-private*/
- CallSite(MethodType type) {
- target = MethodHandles.invokers(type).uninitializedCallSite();
- }
-
- /**
- * 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
- * @throws NullPointerException if the proposed target is null
- */
- /*package-private*/
- CallSite(MethodHandle target) {
- target.type(); // null check
- this.target = target;
- }
-
- /**
- * 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
- */
- public MethodType type() {
- return target.type();
- }
-
- /** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
- * The parameters are JVM-specific.
- */
- void initializeFromJVM(String name,
- MethodType type,
- MemberName callerMethod,
- int callerBCI) {
- if (this.vmmethod != null) {
- // FIXME
- throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
- }
- if (!this.type().equals(type)) {
- throw wrongTargetType(target, type);
- }
- this.vmindex = callerBCI;
- this.vmmethod = callerMethod;
- }
-
- /**
- * 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 abstract MethodHandle getTarget();
-
- /**
- * 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.
- *
- * 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
- * @see CallSite#getTarget
- * @see ConstantCallSite#setTarget
- * @see MutableCallSite#setTarget
- * @see VolatileCallSite#setTarget
- */
- public abstract void setTarget(MethodHandle newTarget);
-
- void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
- MethodType oldType = oldTarget.type();
- MethodType newType = newTarget.type(); // null check!
- if (!newType.equals(oldType))
- throw wrongTargetType(newTarget, oldType);
- }
-
- private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
- return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
- }
-
- /**
- * Produce a method handle equivalent to an invokedynamic instruction
- * which has been linked to this call site.
- *
- * This method is equivalent to the following code:
- *
- *
- * @return a method handle which always invokes this call site's current target
- */
- 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 (ReflectiveOperationException ignore) {
- throw new InternalError();
- }
- }
-
- /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
- /*package-private*/
- static Empty uninitializedCallSite() {
- throw new IllegalStateException("uninitialized call site");
- }
-
- // unsafe stuff:
- private static final Unsafe unsafe = Unsafe.getUnsafe();
- private static final long TARGET_OFFSET;
-
- static {
- try {
- TARGET_OFFSET = unsafe.objectFieldOffset(CallSite.class.getDeclaredField("target"));
- } catch (Exception ex) { throw new Error(ex); }
- }
-
- /*package-private*/
- void setTargetNormal(MethodHandle newTarget) {
- target = newTarget;
- //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
- }
- /*package-private*/
- MethodHandle getTargetVolatile() {
- return (MethodHandle) unsafe.getObjectVolatile(this, TARGET_OFFSET);
- }
- /*package-private*/
- void setTargetVolatile(MethodHandle newTarget) {
- unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
- //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/ClassValue.java
--- a/src/share/classes/java/dyn/ClassValue.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * 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;
-
-import java.util.WeakHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.lang.reflect.UndeclaredThrowableException;
-
-/**
- * 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 abstract class ClassValue {
- /**
- * Compute the given class's derived value for this {@code ClassValue}.
- *
- * This method will be invoked within the first thread that accesses
- * the value with the {@link #get get} method.
- *
- * Normally, this method is invoked at most once per class,
- * but it may be invoked again if there has been a call to
- * {@link #remove remove}.
- *
- * 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
- * @see #get
- * @see #remove
- */
- protected abstract T computeValue(Class> type);
-
- /**
- * Returns the value for the given class.
- * If no value has yet been computed, it is obtained by
- * an invocation of the {@link #computeValue computeValue} method.
- *
- * The actual installation of the value on the class
- * is performed atomically.
- * 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);
- if (map != null) {
- Object x = map.get(this);
- if (x != null) {
- return (T) map.unmaskNull(x);
- }
- }
- return setComputedValue(type);
- }
-
- /**
- * Removes the associated value for the given class.
- * If this value is subsequently {@linkplain #get read} for the same class,
- * its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
- * This may result in an additional invocation of the
- * {@code computeValue computeValue} method for the given class.
- *
- * 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:
- *
- *
{@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
- *
- * 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);
- if (map != null) {
- synchronized (map) {
- map.remove(this);
- }
- }
- }
-
- /// Implementation...
-
- // 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();
-
- private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
-
- /** Slow path for {@link #get}. */
- private T setComputedValue(Class> type) {
- ClassValueMap map = getMap(type);
- if (map == null) {
- map = initializeMap(type);
- }
- T value = computeValue(type);
- STORE_BARRIER.lazySet(0);
- // All stores pending from computeValue are completed.
- synchronized (map) {
- // Warm up the table with a null entry.
- map.preInitializeEntry(this);
- }
- STORE_BARRIER.lazySet(0);
- // All stores pending from table expansion are completed.
- synchronized (map) {
- value = (T) map.initializeEntry(this, value);
- // One might fear a possible race condition here
- // if the code for map.put has flushed the write
- // to map.table[*] before the writes to the Map.Entry
- // are done. This is not possible, since we have
- // warmed up the table with an empty entry.
- }
- return value;
- }
-
- // Replace this map by a per-class slot.
- private static final WeakHashMap, ClassValueMap> ROOT
- = new WeakHashMap, ClassValueMap>();
-
- private static ClassValueMap getMap(Class> type) {
- return ROOT.get(type);
- }
-
- private static ClassValueMap initializeMap(Class> type) {
- synchronized (ClassValue.class) {
- ClassValueMap map = ROOT.get(type);
- if (map == null)
- ROOT.put(type, map = new ClassValueMap());
- return map;
- }
- }
-
- static class ClassValueMap extends WeakHashMap {
- /** Make sure this table contains an Entry for the given key, even if it is empty. */
- void preInitializeEntry(ClassValue key) {
- if (!this.containsKey(key))
- this.put(key, null);
- }
- /** Make sure this table contains a non-empty Entry for the given key. */
- Object initializeEntry(ClassValue key, Object value) {
- Object prior = this.get(key);
- if (prior != null) {
- return unmaskNull(prior);
- }
- this.put(key, maskNull(value));
- return value;
- }
-
- Object maskNull(Object x) {
- return x == null ? this : x;
- }
- Object unmaskNull(Object x) {
- return x == this ? null : x;
- }
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/ConstantCallSite.java
--- a/src/share/classes/java/dyn/ConstantCallSite.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * 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 ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
- * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
- * bound to the call site's target.
- * @author John Rose, JSR 292 EG
- */
-public class ConstantCallSite extends CallSite {
- /**
- * 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;
- }
-
- /**
- * 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 -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/InvokeDynamic.java
--- a/src/share/classes/java/dyn/InvokeDynamic.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +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;
-
-/**
- * This is a place-holder class. Some HotSpot implementations need to see it.
- */
-final class InvokeDynamic {
- private InvokeDynamic() { throw new InternalError(); } // do not instantiate
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
--- a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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 an {@code invokedynamic} instruction has
- * failed to find its
- * {@linkplain BootstrapMethod bootstrap method},
- * or the bootstrap method has
- * failed to provide a
- * {@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
- */
-public class InvokeDynamicBootstrapError extends LinkageError {
- private static final long serialVersionUID = 292L;
-
- /**
- * Constructs an {@code InvokeDynamicBootstrapError} with no detail message.
- */
- public InvokeDynamicBootstrapError() {
- super();
- }
-
- /**
- * Constructs an {@code InvokeDynamicBootstrapError} with the specified
- * detail message.
- *
- * @param s the detail message.
- */
- public InvokeDynamicBootstrapError(String s) {
- super(s);
- }
-
- /**
- * Constructs a {@code InvokeDynamicBootstrapError} with the specified
- * detail message and cause.
- *
- * @param s the detail message.
- * @param cause the cause, may be {@code null}.
- */
- public InvokeDynamicBootstrapError(String s, Throwable cause) {
- super(s, cause);
- }
-
- /**
- * Constructs a {@code InvokeDynamicBootstrapError} with the specified
- * cause.
- *
- * @param cause the cause, may be {@code null}.
- */
- public InvokeDynamicBootstrapError(Throwable cause) {
- // cf. Throwable(Throwable cause) constructor.
- super(cause == null ? null : cause.toString());
- initCause(cause);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/Linkage.java
--- a/src/share/classes/java/dyn/Linkage.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +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;
-
-import java.dyn.MethodHandles.Lookup;
-import java.util.WeakHashMap;
-import sun.dyn.Access;
-import sun.dyn.MethodHandleImpl;
-import sun.dyn.util.VerifyAccess;
-import sun.reflect.Reflection;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-
-/**
- * CLASS WILL BE REMOVED FOR PFD:
- * Static routines for controlling invokedynamic behavior.
- * Replaced by non-static APIs.
- * @author John Rose, JSR 292 EG
- * @deprecated This class will be removed in the Public Final Draft.
- */
-public class Linkage {
- private static final Access IMPL_TOKEN = Access.getToken();
-
- private Linkage() {} // do not instantiate
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Register a bootstrap method to use when linking dynamic call sites within
- * a given caller class.
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
- Class callc = Reflection.getCallerClass(2);
- if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
- throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
- MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
- }
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Simplified version of {@code registerBootstrapMethod} for self-registration,
- * to be called from a static initializer.
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(Class> runtime, String name) {
- Class callerClass = Reflection.getCallerClass(2);
- registerBootstrapMethodLookup(callerClass, runtime, name);
- }
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Simplified version of {@code registerBootstrapMethod} for self-registration,
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(String name) {
- Class callerClass = Reflection.getCallerClass(2);
- registerBootstrapMethodLookup(callerClass, callerClass, name);
- }
-
- private static
- void registerBootstrapMethodLookup(Class> callerClass, Class> runtime, String name) {
- Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
- MethodHandle bootstrapMethod;
- try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
- } catch (ReflectiveOperationException ex) {
- throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
- }
- MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
- }
-
- private static final MethodType BOOTSTRAP_METHOD_TYPE
- = MethodType.methodType(CallSite.class,
- Class.class, String.class, MethodType.class);
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Invalidate all invokedynamic call sites everywhere.
- * @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() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * 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 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) {
- throw new UnsupportedOperationException();
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/MethodHandle.java
--- a/src/share/classes/java/dyn/MethodHandle.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1009 +0,0 @@
-/*
- * 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
- * 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;
-
-//import sun.dyn.*;
-
-import sun.dyn.Access;
-import sun.dyn.MethodHandleImpl;
-
-import static java.dyn.MethodHandles.invokers; // package-private API
-import static sun.dyn.MemberName.newIllegalArgumentException; // utility
-
-/**
- * A method handle is a typed, 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
- * {@linkplain #asType conversion},
- * {@linkplain #bindTo insertion},
- * {@linkplain java.dyn.MethodHandles#dropArguments deletion},
- * and {@linkplain java.dyn.MethodHandles#filterArguments substitution}.
- *
- * Note: The super-class of MethodHandle is Object.
- * Any other super-class visible in the Reference Implementation
- * will be removed before the Proposed Final Draft.
- * Also, the final version will not include any public or
- * protected constructors.
- *
- *
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.
- * 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).
- *
- * 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 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 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.
- *
- * (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}).
- *
- * 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.
- *
- * 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.
- *
- * 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 example, a static method handle can be obtained
- * from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
- * 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
- * receiver argument, prepended before any other arguments.
- * In the method handle's type, the initial receiver argument is typed
- * according to the class under which the method was initially requested.
- * (E.g., if a non-static method handle is obtained via {@code ldc},
- * the type of the receiver is the class named in the constant pool entry.)
- *
- * 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 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.
- *
- *
- * 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:
- *
- * A signature polymorphic method will be declared with the following properties:
- *
- *
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.
- *
- * 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.
- *
- * 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:
- *
- *
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}.
- *
- * (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.)
- *
- * 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.
- *
- *
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.
- *
Method types can specify arguments of primitive types,
- * which Java generic types cannot range over.
- *
Higher order functions over method handles (combinators) are
- * often generic across a wide range of function types, including
- * those of multiple arities. It is impossible to represent such
- * genericity with a Java type parameter.
- *
- *
- * @see MethodType
- * @see MethodHandles
- * @author John Rose, JSR 292 EG
- */
-public abstract class MethodHandle
- // Note: This is an implementation inheritance hack, and will be removed
- // with a JVM change which moves the required hidden state onto this class.
- extends 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.
- */
- @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
- @interface PolymorphicSignature { }
-
- private MethodType type;
-
- /**
- * Report the type of this method handle.
- * Every invocation of this method handle via {@code invokeExact} must exactly match this type.
- * @return the method handle type
- */
- public MethodType type() {
- return type;
- }
-
- /**
- * CONSTRUCTOR WILL BE REMOVED FOR PFD:
- * Temporary constructor in early versions of the Reference Implementation.
- * Method handle inheritance (if any) will be contained completely within
- * the {@code java.dyn} package.
- */
- // The constructor for MethodHandle may only be called by privileged code.
- // Subclasses may be in other packages, but must possess
- // a token which they obtained from MH with a security check.
- // @param token non-null object which proves access permission
- // @param type type (permanently assigned) of the new method handle
- protected MethodHandle(Access token, MethodType type) {
- super(token);
- Access.check(token);
- this.type = type;
- }
-
- private void initType(MethodType type) {
- type.getClass(); // elicit NPE
- if (this.type != null) throw new InternalError();
- this.type = type;
- }
-
- static {
- // This hack allows the implementation package special access to
- // the internals of MethodHandle. In particular, the MTImpl has all sorts
- // of cached information useful to the implementation code.
- MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() {
- public void initType(MethodHandle mh, MethodType type) { mh.initType(type); }
- });
- }
-
- /**
- * 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.
- *
- * 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 type descriptor,
- * and optionally performing conversions on arguments and return values.
- *
- * 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
- * adjusted by calling {@link #asType asType} to adjust this method handle
- * to the required type, and then the call proceeds as if by
- * {@link #invokeExact invokeExact} on the adjusted method handle.
- *
- * There is no guarantee that the {@code asType} call is actually made.
- * If the JVM can predict the results of making the call, it may perform
- * adaptations directly on the caller's arguments,
- * and call the target method handle according to its own exact type.
- *
- * 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,
- * 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;
-
- /**
- * Perform a varargs invocation, passing the arguments in the given array
- * to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
- * which mentions only the type {@code Object}, and whose arity is the length
- * of the argument array.
- *
- * Specifically, execution proceeds as if by the following steps,
- * although the methods are not guaranteed to be called if the JVM
- * can predict their effects.
- *
- *
Determine the length of the argument array as {@code N}.
- * For a null reference, {@code N=0}.
- *
Determine the generic type {@code TN} of {@code N} arguments as
- * as {@code TN=MethodType.genericMethodType(N)}.
- *
Force the original target method handle {@code MH0} to the
- * required type, as {@code MH1 = MH0.asType(TN)}.
- *
Spread the array into {@code N} separate arguments {@code A0, ...}.
- *
Invoke the type-adjusted method handle on the unpacked arguments:
- * MH1.invokeExact(A0, ...).
- *
Take the return value as an {@code Object} reference.
- *
- *
- * Because of the action of the {@code asType} step, the following argument
- * conversions are applied as necessary:
- *
- *
reference casting
- *
unboxing
- *
widening primitive conversions
- *
- *
- * The result returned by the call is boxed if it is a primitive,
- * or forced to null if the return type is void.
- *
- * This call is equivalent to the following code:
- *
- * 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 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#spreadInvoker
- */
- public Object invokeWithArguments(Object... arguments) throws Throwable {
- int argc = arguments == null ? 0 : arguments.length;
- MethodType type = type();
- if (type.parameterCount() != argc) {
- // simulate invokeGeneric
- return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
- }
- if (argc <= 10) {
- MethodHandle invoker = invokers(type).genericInvoker();
- switch (argc) {
- case 0: return invoker.invokeExact(this);
- case 1: return invoker.invokeExact(this,
- arguments[0]);
- case 2: return invoker.invokeExact(this,
- arguments[0], arguments[1]);
- case 3: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2]);
- case 4: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3]);
- case 5: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4]);
- case 6: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5]);
- case 7: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5],
- arguments[6]);
- case 8: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5],
- arguments[6], arguments[7]);
- case 9: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5],
- arguments[6], arguments[7], arguments[8]);
- case 10: return invoker.invokeExact(this,
- arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5],
- arguments[6], arguments[7], arguments[8],
- arguments[9]);
- }
- }
-
- // more than ten arguments get boxed in a varargs list:
- MethodHandle invoker = invokers(type).spreadInvoker(0);
- return invoker.invokeExact(this, arguments);
- }
- /** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */
- public Object invokeWithArguments(java.util.List> arguments) throws Throwable {
- return invokeWithArguments(arguments.toArray());
- }
-
- /**
- * Produce an adapter method handle which adapts the type of the
- * current method handle to a new type
- * The resulting method handle is guaranteed to report a type
- * which is equal to the desired new type.
- *
- * If the original type and new type are equal, returns {@code this}.
- *
- * This method provides the crucial behavioral difference between
- * {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. The two methods
- * perform the same steps when the caller's type descriptor is identical
- * with the callee's, but when the types differ, {@link #invokeGeneric invokeGeneric}
- * also calls {@code asType} (or some internal equivalent) in order
- * to match up the caller's and callee's types.
- *
- * This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
- * 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
- * any necessary argument conversions, and arranges for any
- * necessary return value conversions
- * @throws WrongMethodTypeException if the conversion cannot be made
- * @see MethodHandles#convertArguments
- */
- public MethodHandle asType(MethodType newType) {
- return MethodHandles.convertArguments(this, newType);
- }
-
- /**
- * 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 the original target,
- * the original target is adapted to take the array elements directly,
- * as if by a call to {@link #asType asType}.
- *
- * When called, the adapter replaces a trailing array argument
- * by the array's elements, each as its own argument to the target.
- * (The order of the arguments is preserved.)
- * They are converted pairwise by casting and/or unboxing
- * to the types of the trailing parameters of the target.
- * Finally the target is called.
- * What the target eventually returns is returned unchanged by the adapter.
- *
- * Before calling the target, the adapter verifies that the array
- * contains exactly enough elements to provide a correct argument count
- * to the target method handle.
- * (The array may also be null when zero elements are required.)
- * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
- * @param arrayLength the number of arguments to spread from an incoming array argument
- * @return a new method handle which spreads its final array argument,
- * before calling the original method handle
- * @throws IllegalArgumentException if {@code arrayType} is not an array type
- * @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 MethodHandle asSpreader(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 < arrayLength) throw newIllegalArgumentException("bad spread array length");
- int keepPosArgs = nargs - arrayLength;
- MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
- newType = newType.insertParameterTypes(keepPosArgs, arrayType);
- return MethodHandles.spreadArguments(this, newType);
- }
-
- /**
- * 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 the original target,
- * the original target is adapted to take the array type directly,
- * as if by a call to {@link #asType asType}.
- *
- * When called, the adapter replaces its trailing {@code arrayLength}
- * arguments by a single new array of type {@code arrayType}, whose elements
- * comprise (in order) the replaced arguments.
- * Finally the target is called.
- * What the target eventually returns is returned unchanged by the adapter.
- *
- * (The array may also be a shared constant when {@code arrayLength} is zero.)
- *
- * (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,
- * or {@code arrayLength} is not a legal array size
- * @throws WrongMethodTypeException if the implied {@code asType} call fails
- * @see #asSpreader
- * @see #asVarargsCollector
- */
- 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));
- return MethodHandles.collectArguments(this, newType);
- }
-
- /**
- * 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:
- *
- * 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:
- *
- *
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
- *
- * @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.
- *
- * When called, the bound handle inserts the given value {@code x}
- * as a new leading argument to the target. The other arguments are
- * also passed unchanged.
- * What the target eventually returns is returned unchanged by the bound handle.
- *
- * The reference {@code x} must be convertible to the first parameter
- * type of the target.
- * @param x the value to bind to the first argument of the target
- * @return a new method handle which collects some trailing argument
- * into an array, before calling the original method handle
- * @throws IllegalArgumentException if the target does not have a
- * leading parameter type that is a reference type
- * @throws ClassCastException if {@code x} cannot be converted
- * to the leading parameter type of the target
- * @see MethodHandles#insertArguments
- */
- public MethodHandle bindTo(Object x) {
- return MethodHandles.insertArguments(this, 0, x);
- }
-
- /**
- * 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);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/MethodHandles.java
--- a/src/share/classes/java/dyn/MethodHandles.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2339 +0,0 @@
-/*
- * 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
- * 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;
-
-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;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Arrays;
-import sun.dyn.Invokers;
-import sun.dyn.MethodTypeImpl;
-import sun.reflect.Reflection;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-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:
- *
- *
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
- */
-public class MethodHandles {
-
- private MethodHandles() { } // do not instantiate
-
- private static final Access IMPL_TOKEN = Access.getToken();
- private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
- static { MethodHandleImpl.initStatics(); }
- // See IMPL_LOOKUP below.
-
- //// Method handle creation from ordinary methods.
-
- /**
- * Return a {@link Lookup lookup object} on the caller,
- * which has the capability to access any method handle that the caller has access to,
- * including direct method handles to private fields and methods.
- * This lookup object is a capability which may be delegated to trusted agents.
- * Do not store it in place where untrusted code can access it.
- */
- public static Lookup lookup() {
- return new Lookup();
- }
-
- /**
- * Return a {@link Lookup lookup object} which is trusted minimally.
- * It can only be used to create method handles to
- * publicly accessible fields and methods.
- *
- * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
- * of this lookup object will be {@link java.lang.Object}.
- *
- * The lookup class can be changed to any other class {@code C} using an expression of the form
- * {@linkplain Lookup#in publicLookup().in(C.class)}.
- * Since all classes have equal access to public names,
- * such a change would confer no new access rights.
- */
- public static Lookup publicLookup() {
- return Lookup.PUBLIC_LOOKUP;
- }
-
- /**
- * A lookup object is a factory for creating method handles,
- * when the creation requires access checking.
- * Method handles do not perform
- * access checks when they are called, but rather when they are created.
- * 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 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.
- *
- * 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 {@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.
- *
- * 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.
- * 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
- * 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, 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}
- * can access private members within other related classes such as
- * {@code C}, {@code C.D.E}, or {@code C.B},
- * but the Java compiler may need to generate wrapper methods in
- * those related classes. In such cases, a {@code Lookup} object on
- * {@code C.E} would be unable to those private members.
- * 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, {@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}.
- *
- * 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 {
- /** The class on behalf of whom the lookup is being performed. */
- private final Class> lookupClass;
-
- /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
- private final int allowedModes;
-
- /** A single-bit mask representing {@code public} access,
- * which may contribute to the result of {@link #lookupModes lookupModes}.
- * The value, {@code 0x01}, happens to be the same as the value of the
- * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
- */
- public static final int PUBLIC = Modifier.PUBLIC;
-
- /** A single-bit mask representing {@code private} access,
- * which may contribute to the result of {@link #lookupModes lookupModes}.
- * The value, {@code 0x02}, happens to be the same as the value of the
- * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
- */
- public static final int PRIVATE = Modifier.PRIVATE;
-
- /** A single-bit mask representing {@code protected} access,
- * which may contribute to the result of {@link #lookupModes lookupModes}.
- * The value, {@code 0x04}, happens to be the same as the value of the
- * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
- */
- public static final int PROTECTED = Modifier.PROTECTED;
-
- /** A single-bit mask representing {@code package} access (default access),
- * which may contribute to the result of {@link #lookupModes lookupModes}.
- * The value is {@code 0x08}, which does not correspond meaningfully to
- * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
- */
- public static final int PACKAGE = Modifier.STATIC;
-
- private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
- private static final int TRUSTED = -1;
-
- private static int fixmods(int mods) {
- mods &= (ALL_MODES - PACKAGE);
- return (mods != 0) ? mods : PACKAGE;
- }
-
- /** Tells which class is performing the lookup. It is this class against
- * which checks are performed for visibility and access permissions.
- *
- * The class implies a maximum level of access permission,
- * but the permissions may be additionally limited by the bitmask
- * {@link #lookupModes lookupModes}, which controls whether non-public members
- * can be accessed.
- */
- public Class> lookupClass() {
- return lookupClass;
- }
-
- // This is just for calling out to MethodHandleImpl.
- private Class> lookupClassOrNull() {
- return (allowedModes == TRUSTED) ? null : lookupClass;
- }
-
- /** 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)},
- * {@linkplain #PROTECTED PROTECTED (0x04)},
- * and {@linkplain #PACKAGE PACKAGE (0x08)}.
- *
- * A freshly-created lookup object
- * on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
- * has all possible bits set, since the caller class can access all its own members.
- * A lookup object on a new lookup class
- * {@linkplain java.dyn.MethodHandles.Lookup#in created from a previous lookup object}
- * may have some mode bits set to zero.
- * The purpose of this is to restrict access via the new lookup object,
- * so that it can access only names which can be reached by the original
- * lookup object, and also by the new lookup class.
- */
- public int lookupModes() {
- return allowedModes & ALL_MODES;
- }
-
- /** Embody the current class (the lookupClass) as a lookup class
- * for method handle creation.
- * Must be called by from a method in this package,
- * which in turn is called by a method not in this package.
- *
- * Also, don't make it private, lest javac interpose
- * an access$N method.
- */
- Lookup() {
- this(getCallerClassAtEntryPoint(), ALL_MODES);
- // make sure we haven't accidentally picked up a privileged class:
- checkUnprivilegedlookupClass(lookupClass);
- }
-
- Lookup(Access token, Class> lookupClass) {
- this(lookupClass, ALL_MODES);
- Access.check(token);
- }
-
- private Lookup(Class> lookupClass, int allowedModes) {
- this.lookupClass = lookupClass;
- this.allowedModes = allowedModes;
- }
-
- /**
- * Creates a lookup on the specified new lookup class.
- * The resulting object will report the specified
- * class as its own {@link #lookupClass lookupClass}.
- *
- * However, the resulting {@code Lookup} object is guaranteed
- * to have no more access capabilities than the original.
- * In particular, access capabilities can be lost as follows:
- *
If the new lookup class differs from the old one,
- * protected members will not be accessible by virtue of inheritance.
- * (Protected members may continue to be accessible because of package sharing.)
- *
If the new lookup class is in a different package
- * than the old one, protected and default (package) members will not be accessible.
- *
If the new lookup class is not within the same package member
- * as the old one, private members will not be accessible.
- *
If the new lookup class is not accessible to the old lookup class,
- * 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
- if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
- return new Lookup(requestedLookupClass, ALL_MODES);
- if (requestedLookupClass == this.lookupClass)
- return this; // keep same capabilities
- int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
- if ((newModes & PACKAGE) != 0
- && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
- newModes &= ~(PACKAGE|PRIVATE);
- }
- // Allow nestmate lookups to be created without special privilege:
- if ((newModes & PRIVATE) != 0
- && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
- newModes &= ~PRIVATE;
- }
- if (newModes == PUBLIC
- && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass)) {
- // The requested class it not accessible from the lookup class.
- // No permissions.
- newModes = 0;
- }
- checkUnprivilegedlookupClass(requestedLookupClass);
- return new Lookup(requestedLookupClass, newModes);
- }
-
- // Make sure outer class is initialized first.
- static { IMPL_TOKEN.getClass(); }
-
- /** Version of lookup which is trusted minimally.
- * It can only be used to create method handles to
- * publicly accessible members.
- */
- static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
-
- /** Package-private version of lookup which is trusted. */
- static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
- static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
-
- private static void checkUnprivilegedlookupClass(Class> lookupClass) {
- String name = lookupClass.getName();
- if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn."))
- throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
- }
-
- /**
- * 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 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".
- *
If only public and package access are allowed, the suffix is "/package".
- *
If only public, package, and private access are allowed, the suffix is "/private".
- *
- * If none of the above cases apply, it is the case that full
- * 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}
- * 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 0: // no privileges
- return cname + "/noaccess";
- case PUBLIC:
- return cname + "/public";
- case PUBLIC|PACKAGE:
- return cname + "/package";
- case ALL_MODES & ~PROTECTED:
- return cname + "/private";
- case ALL_MODES:
- return cname;
- 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;
- }
- }
-
- // call this from an entry point method in Lookup with extraFrames=0.
- private static Class> getCallerClassAtEntryPoint() {
- final int CALLER_DEPTH = 4;
- // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
- // 2: Lookup., 3: MethodHandles.*, 4: caller
- // Note: This should be the only use of getCallerClass in this file.
- assert(Reflection.getCallerClass(CALLER_DEPTH-1) == MethodHandles.class);
- return Reflection.getCallerClass(CALLER_DEPTH);
- }
-
- /**
- * 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 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
- * @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 NoSuchMethodException, IllegalAccessException {
- MemberName method = resolveOrFail(refc, name, type, true);
- checkMethod(refc, method, true);
- return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
- }
-
- /**
- * 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.
- *
- * When called, the handle will treat the first argument as a receiver
- * and dispatch on the receiver's type to determine which method
- * 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
- * @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 NoSuchMethodException, IllegalAccessException {
- MemberName method = resolveOrFail(refc, name, type, false);
- checkMethod(refc, method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
- return restrictProtectedReceiver(method, mh);
- }
-
- /**
- * 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.
- * The constructor and all its argument types must be accessible to the lookup class.
- * If the constructor's class has not yet been initialized, that is done
- * 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 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
- * @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 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());
- 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);
- }
- }
-
- /**
- * 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,
- * with a suitably restricted receiver type (such as {@code caller}) prepended.
- * The method and all its argument types must be accessible
- * to the caller.
- *
- * When called, the handle will treat the first argument as a receiver,
- * but will not dispatch on the receiver's type.
- * (This direct invocation action is identical with that performed by an
- * {@code invokespecial} instruction.)
- *
- * 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
- * @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 NoSuchMethodException, IllegalAccessException {
- checkSpecialCaller(specialCaller);
- MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
- checkMethod(refc, method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
- return restrictReceiver(method, mh, specialCaller);
- }
-
- /**
- * 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
- * @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 NoSuchFieldException, IllegalAccessException {
- return makeAccessor(refc, name, type, false, false);
- }
-
- /**
- * 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
- * @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 NoSuchFieldException, IllegalAccessException {
- return makeAccessor(refc, name, type, false, true);
- }
-
- /**
- * 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
- * @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 NoSuchFieldException, IllegalAccessException {
- return makeAccessor(refc, name, type, true, false);
- }
-
- /**
- * 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
- * @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 NoSuchFieldException, IllegalAccessException {
- return makeAccessor(refc, name, type, true, true);
- }
-
- /**
- * 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.
- * The type of the method handle will be that of the method,
- * without any insertion of an additional receiver parameter.
- * The given receiver will be bound into the method handle,
- * so that every call to the method handle will invoke the
- * requested method on the given receiver.
- *
- * 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.)
- *
- * 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
- * @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 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, this);
- if (dmh.type().parameterCount() == 0)
- return dmh; // bound the trailing parameter; no varargs possible
- return fixVarargs(bmh, dmh);
- }
-
- /**
- * Make a direct method handle to m, if the lookup class has permission.
- * If m is non-static, the receiver argument is treated as an initial argument.
- * If m is virtual, overriding is respected on every call.
- * Unlike the Core Reflection API, exceptions are not wrapped.
- * The type of the method handle will be that of the method,
- * with the receiver type prepended (but only if it is non-static).
- * 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.
- *
- * 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
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- public MethodHandle unreflect(Method m) throws IllegalAccessException {
- MemberName method = new MemberName(m);
- assert(method.isMethod());
- if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic());
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
- if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh);
- return mh;
- }
-
- /**
- * 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,
- * with the special caller type prepended (and not the receiver of the method).
- * 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
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if any argument is null
- */
- public MethodHandle unreflectSpecial(Method m, Class> specialCaller) throws IllegalAccessException {
- checkSpecialCaller(specialCaller);
- MemberName method = new MemberName(m);
- assert(method.isMethod());
- // ignore m.isAccessible: this is a new kind of access
- checkMethod(m.getDeclaringClass(), method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
- return restrictReceiver(method, mh, specialCaller);
- }
-
- /**
- * 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,
- * creating a new instance of the constructor's class on the
- * arguments passed to the method handle.
- *
- * If the constructor's {@code accessible} flag is not set,
- * access checking is performed immediately on behalf of the lookup class.
- *
- * 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
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- 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());
- MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
- return fixVarargs(allocator, rawCtor);
- }
-
- /**
- * 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.
- * Otherwise, its single argument will be the instance containing
- * the field.
- * If the method's {@code accessible} flag is not set,
- * access checking is performed immediately on behalf of the lookup class.
- * @param f the reflected field
- * @return a method handle which can load values from the reflected field
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
- return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false);
- }
-
- /**
- * 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.
- * Otherwise, the two arguments will be the instance containing
- * the field, and the value to be stored.
- * If the method's {@code accessible} flag is not set,
- * access checking is performed immediately on behalf of the lookup class.
- * @param f the reflected field
- * @return a method handle which can store values into the reflected field
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- 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 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(),
- NoSuchFieldException.class);
- }
-
- 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(),
- NoSuchMethodException.class);
- }
-
- MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic,
- 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,
- NoSuchMethodException.class);
- }
-
- 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), this);
- }
-
- void checkMethod(Class> refc, MemberName m, boolean wantStatic) throws IllegalAccessException {
- String message;
- if (m.isConstructor())
- message = "expected a method, not a constructor";
- else if (!m.isMethod())
- message = "expected a method";
- else if (wantStatic != m.isStatic())
- message = wantStatic ? "expected a static method" : "expected a non-static method";
- else
- { checkAccess(refc, m); return; }
- throw newNoAccessException(message, m, this);
- }
-
- void checkAccess(Class> refc, MemberName m) throws IllegalAccessException {
- int allowedModes = this.allowedModes;
- if (allowedModes == TRUSTED) return;
- int mods = m.getModifiers();
- if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
- return; // common case
- int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
- if ((requestedModes & allowedModes) != 0
- && VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
- mods, lookupClass()))
- return;
- if (((requestedModes & ~allowedModes) & PROTECTED) != 0
- && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
- // Protected members can also be checked as if they were package-private.
- return;
- throw newNoAccessException(accessFailedMessage(refc, m), m, this);
- }
-
- String accessFailedMessage(Class> refc, MemberName m) {
- Class> defc = m.getDeclaringClass();
- int mods = m.getModifiers();
- // 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 (Modifier.isPublic(mods))
- return "access to public member failed"; // (how?)
- if (Modifier.isPrivate(mods))
- return "member is private";
- if (Modifier.isProtected(mods))
- return "member is protected";
- return "member is private to package";
- }
-
- private static final boolean ALLOW_NESTMATE_ACCESS = false;
-
- 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), this);
- }
-
- 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()
- || allowedModes == TRUSTED
- || method.getDeclaringClass() == lookupClass()
- || (ALLOW_NESTMATE_ACCESS &&
- VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
- return mh;
- else
- return restrictReceiver(method, mh, lookupClass());
- }
- 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)) {
- throw newNoAccessException("caller class must be a subclass below the method", method, caller);
- }
- MethodType rawType = mh.type();
- if (rawType.parameterType(0) == caller) return mh;
- MethodType narrowType = rawType.changeParameterType(0, caller);
- 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 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, this);
- return makeAccessor(refc, field, false, isSetter);
- }
-
- MethodHandle makeAccessor(Class> refc, MemberName field,
- boolean trusted, boolean isSetter) throws IllegalAccessException {
- assert(field.isField());
- if (trusted)
- return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
- checkAccess(refc, field);
- MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
- return restrictProtectedReceiver(field, mh);
- }
- }
-
- /**
- * 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
- MethodHandle arrayElementGetter(Class> arrayClass) throws IllegalArgumentException {
- return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
- }
-
- /**
- * 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
- MethodHandle arrayElementSetter(Class> arrayClass) throws IllegalArgumentException {
- return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
- }
-
- /// method handle invocation (reflective style)
-
- /**
- * 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
- * arguments:
- *
- *
a single {@code MethodHandle} target
- *
zero or more {@code Object} values (counted by {@code objectArgCount})
- *
an {@code Object[]} array containing more arguments
- *
- *
- * The invoker will 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 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}, except for
- * the last parameter type, which will be the array type {@code Object[]}.
- *
- * Before invoking its target, the invoker will spread the varargs array, apply
- * reference casts as necessary, and unbox and widen primitive arguments.
- * The return value of the invoker will be an {@code Object} reference,
- * boxing a primitive value if the original type returns a primitive,
- * and always null if the original type returns void.
- *
- * This method is equivalent to the following code (though it may be more efficient):
- *
- * 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 spreadInvoker(MethodType type, int objectArgCount) {
- if (objectArgCount < 0 || objectArgCount > type.parameterCount())
- throw new IllegalArgumentException("bad argument count "+objectArgCount);
- return invokers(type).spreadInvoker(objectArgCount);
- }
-
- /**
- * 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):
- *
- * 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
- */
- static public
- MethodHandle exactInvoker(MethodType type) {
- 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):
- *
- * 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);
- }
-
- /**
- * 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.
- * The following checks and conversions are made:
- *
- *
If T0 and T1 are references, then a cast to T1 is applied.
- * (The types do not need to be related in any particular way.)
- *
If T0 and T1 are primitives, then a widening or narrowing
- * conversion is applied, if one exists.
- *
If T0 is a primitive and T1 a reference, and
- * T0 has a wrapper type TW, a boxing conversion to TW is applied,
- * possibly followed by a reference conversion.
- * T1 must be TW or a supertype.
- *
If T0 is a reference and T1 a primitive, and
- * T1 has a wrapper type TW, an unboxing conversion is applied,
- * possibly preceded by a reference conversion.
- * T0 must be TW or a supertype.
- *
If T1 is void, the return value is discarded
- *
If T0 is void and T1 a reference, a null value is introduced.
- *
If T0 is void and T1 a primitive, a zero value is introduced.
- *
- * If the value is discarded, null will be returned.
- * @param valueType
- * @param value
- * @return the value, converted if necessary
- * @throws java.lang.ClassCastException if a cast fails
- */
- static
- T1 checkValue(Class t0, Class t1, Object value)
- throws ClassCastException
- {
- if (t0 == t1) {
- // no conversion needed; just reassert the same type
- if (t0.isPrimitive())
- return Wrapper.asPrimitiveType(t1).cast(value);
- else
- return Wrapper.OBJECT.convert(value, t1);
- }
- boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
- if (!prim0) {
- // check contract with caller
- Wrapper.OBJECT.convert(value, t0);
- if (!prim1) {
- return Wrapper.OBJECT.convert(value, t1);
- }
- // convert reference to primitive by unboxing
- Wrapper w1 = Wrapper.forPrimitiveType(t1);
- return w1.convert(value, t1);
- }
- // check contract with caller:
- Wrapper.asWrapperType(t0).cast(value);
- Wrapper w1 = Wrapper.forPrimitiveType(t1);
- return w1.convert(value, t1);
- }
-
- static
- Object checkValue(Class> T1, Object value)
- throws ClassCastException
- {
- Class> T0;
- if (value == null)
- T0 = Object.class;
- else
- T0 = value.getClass();
- return checkValue(T0, T1, value);
- }
-
- /// method handle modification (creation from other method handles)
-
- /**
- * 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
- * which is equal to the desired new type.
- *
- * If the original type and new type are equal, returns target.
- *
- * The following conversions are applied as needed both to
- * arguments and return types. Let T0 and T1 be the differing
- * new and old parameter types (or old and new return types)
- * for corresponding values passed by the new and old method types.
- * Given those types T0, T1, one of the following conversions is applied
- * if possible:
- *
- *
If T0 and T1 are references, then a cast to T1 is applied.
- * (The types do not need to be related in any particular way.)
- *
If T0 and T1 are primitives, then a Java method invocation
- * conversion (JLS 5.3) is applied, if one exists.
- *
If T0 is a primitive and T1 a reference, a boxing
- * conversion is applied if one exists, possibly followed by
- * a reference conversion to a superclass.
- * T1 must be a wrapper class or a supertype of one.
- *
If T0 is a reference and T1 a primitive, an unboxing
- * conversion will be applied at runtime, possibly followed
- * by a Java method invocation conversion (JLS 5.3)
- * on the primitive value. (These are the widening conversions.)
- * T0 must be a wrapper class or a supertype of one.
- * (In the case where T0 is Object, these are the conversions
- * allowed by java.lang.reflect.Method.invoke.)
- *
If the return type T1 is void, any returned value is discarded
- *
If the return type T0 is void and T1 a reference, a null value is introduced.
- *
If the return type T0 is void and T1 a primitive, a zero value is introduced.
- *
- * @param target the method handle to invoke after arguments are retyped
- * @param newType the expected type of the new method handle
- * @return a method handle which delegates to {@code target} after performing
- * any necessary argument conversions, and arranges for any
- * necessary return value conversions
- * @throws NullPointerException if either argument is null
- * @throws WrongMethodTypeException if the conversion cannot be made
- * @see MethodHandle#asType
- * @see MethodHandles#explicitCastArguments
- */
- public static
- MethodHandle convertArguments(MethodHandle target, MethodType newType) {
- MethodType oldType = target.type();
- if (oldType.equals(newType))
- return target;
- MethodHandle res = null;
- try {
- res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
- newType, oldType, null);
- } catch (IllegalArgumentException ex) {
- }
- if (res == null)
- throw new WrongMethodTypeException("cannot convert to "+newType+": "+target);
- return res;
- }
-
- /**
- * 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
- * which is equal to the desired new type.
- *
- * If the original type and new type are equal, returns target.
- *
- * The same conversions are allowed as for {@link #convertArguments convertArguments},
- * and some additional conversions are also applied if those conversions fail.
- * Given types T0, T1, one of the following conversions is applied
- * in addition, if the conversions specified for {@code convertArguments}
- * would be insufficient:
- *
- *
If T0 and T1 are references, and T1 is an interface type,
- * then the value of type T0 is passed as a T1 without a cast.
- * (This treatment of interfaces follows the usage of the bytecode verifier.)
- *
If T0 and T1 are primitives and one is boolean,
- * the boolean is treated as a one-bit unsigned integer.
- * (This treatment follows the usage of the bytecode verifier.)
- * A conversion from another primitive type behaves as if
- * it first converts to byte, and then masks all but the low bit.
- *
If a primitive value would be converted by {@code convertArguments}
- * using Java method invocation conversion (JLS 5.3),
- * Java casting conversion (JLS 5.5) may be used also.
- * This allows primitives to be narrowed as well as widened.
- *
- * @param target the method handle to invoke after arguments are retyped
- * @param newType the expected type of the new method handle
- * @return a method handle which delegates to {@code target} after performing
- * any necessary argument conversions, and arranges for any
- * necessary return value conversions
- * @throws NullPointerException if either argument is null
- * @throws WrongMethodTypeException if the conversion cannot be made
- * @see MethodHandle#asType
- * @see MethodHandles#convertArguments
- */
- public static
- MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
- return convertArguments(target, newType); // FIXME!
- }
-
- /*
- FIXME: Reconcile javadoc with 10/22/2010 EG notes on conversion:
-
- Both converters arrange for their method handles to convert arguments
- and return values. The conversion rules are the same for arguments
- and return values, and depend only on source and target types, S and
- T. The conversions allowed by castConvertArguments are a strict
- superset of those performed by convertArguments.
-
- In all cases, if S and T are references, a simple checkcast is done.
- If neither S nor T is a primitive, no attempt is made to unbox and
- box. A failed conversion throws ClassCastException.
-
- If T is void, the value is dropped.
-
- For compatibility with reflection, if S is void and T is a reference,
- a null value is produced.
-
- For compatibility with reflection, if S is a reference and T is a
- primitive, S is first unboxed and then undergoes primitive conversion.
- In the case of 'convertArguments', only assignment conversion is
- performed (no narrowing primitive conversion).
-
- If S is a primitive, S is boxed, and then the above rules are applied.
- If S and T are both primitives, the boxing will be undetectable; only
- the primitive conversions will be apparent to the user. The key point
- is that if S is a primitive type, the implementation may box it and
- treat is as Object, without loss of information, or it may use a "fast
- path" which does not use boxing.
-
- Notwithstanding the rules above, for compatibility with the verifier,
- if T is an interface, it is treated as if it were Object. [KEEP THIS?]
-
- Also, for compatibility with the verifier, a boolean may be undergo
- widening or narrowing conversion to any other primitive type. [KEEP THIS?]
- */
-
- /**
- * 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.
- *
- * The given array controls the reordering.
- * Call {@code #I} the number of incoming parameters (the value
- * {@code newType.parameterCount()}, and call {@code #O} the number
- * of outgoing parameters (the value {@code target.type().parameterCount()}).
- * Then the length of the reordering array must be {@code #O},
- * and each element must be a non-negative number less than {@code #I}.
- * For every {@code N} less than {@code #O}, the {@code N}-th
- * outgoing argument will be taken from the {@code I}-th incoming
- * argument, where {@code I} is {@code reorder[N]}.
- *
- * No argument or return value conversions are applied.
- * The type of each incoming argument, as determined by {@code newType},
- * must be identical to the type of the corresponding outgoing argument
- * or arguments in the target method handle.
- * The return type of {@code newType} must be identical to the return
- * type of the original target.
- *
- * The reordering array need not specify an actual permutation.
- * An incoming argument will be duplicated if its index appears
- * more than once in the array, and an incoming argument will be dropped
- * if its index does not appear in the array.
- * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
- * incoming arguments which are not mentioned in the reordering array
- * are may be any type, as determined only by {@code newType}.
- *
- * @param target the method handle to invoke after arguments are reordered
- * @param newType the expected type of the new method handle
- * @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) {
- MethodType oldType = target.type();
- checkReorder(reorder, newType, oldType);
- return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
- newType, oldType,
- reorder);
- }
-
- private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
- if (reorder.length == oldType.parameterCount()) {
- int limit = newType.parameterCount();
- boolean bad = false;
- for (int i : reorder) {
- if (i < 0 || i >= limit) {
- bad = true; break;
- }
- }
- if (!bad) return;
- }
- throw newIllegalArgumentException("bad reorder array");
- }
-
- /**
- * Equivalent to the following code:
- *
- * @param target the method handle to invoke after argument collection
- * @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
- */
- /*non-public*/ static
- MethodHandle collectArguments(MethodHandle target, MethodType newType) {
- MethodType oldType = target.type();
- int inargs = newType.parameterCount();
- int outargs = oldType.parameterCount();
- int collectPos = outargs - 1;
- int numCollect = (inargs - collectPos);
- if (collectPos < 0 || numCollect < 0)
- throw newIllegalArgumentException("wrong number of arguments");
- MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null);
- if (res == null) {
- throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType);
- }
- return res;
- }
-
- /**
- * 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.
- * If the requested type is primitive, widening primitive conversions are attempted,
- * else reference conversions are attempted.
- *
The returned method handle is equivalent to {@code identity(type).bindTo(value)},
- * unless the type is {@code void}, in which case it is {@code identity(type)}.
- * @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 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)
- throw newIllegalArgumentException("void type");
- Wrapper w = Wrapper.forPrimitiveType(type);
- return identity(type).bindTo(w.convert(value, type));
- } else {
- return identity(type).bindTo(type.cast(value));
- }
- }
-
- /**
- * 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 identity(Class> type) {
- if (type == void.class)
- throw newIllegalArgumentException("void type");
- return ValueConversions.identity(type);
- }
-
- /**
- * 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
- * will contain bindings for those parameters take from {@code values}.
- * The type of the new method handle will drop the types for the bound
- * parameters from the original target type, since the new method handle
- * will no longer require those arguments to be supplied by its callers.
- *
- * Each given argument object must match the corresponding bound parameter type.
- * If a bound parameter type is a primitive, the argument object
- * must be a wrapper, and will be unboxed to produce the primitive value.
- *
- * The pos may range between zero and N (inclusively),
- * where N is the number of argument types in resulting method handle
- * (after bound parameter types are dropped).
- * @param target the method handle to invoke after the argument is inserted
- * @param pos where to insert the argument (zero for the first)
- * @param 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
- MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
- int insCount = values.length;
- MethodType oldType = target.type();
- ArrayList> ptypes =
- new ArrayList>(oldType.parameterList());
- int outargs = oldType.parameterCount();
- int inargs = outargs - insCount;
- if (inargs < 0)
- throw newIllegalArgumentException("too many values to insert");
- if (pos < 0 || pos > inargs)
- throw newIllegalArgumentException("no argument type to append");
- MethodHandle result = target;
- for (int i = 0; i < insCount; i++) {
- Object value = values[i];
- Class> valueType = oldType.parameterType(pos+i);
- value = checkValue(valueType, value);
- if (pos == 0 && !valueType.isPrimitive()) {
- // At least for now, make bound method handles a special case.
- MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value);
- if (bmh != null) {
- result = bmh;
- continue;
- }
- // else fall through to general adapter machinery
- }
- result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value);
- }
- return result;
- }
-
- /**
- * 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.
- *
- * The pos may range between zero and N,
- * where N is the number of argument types in target,
- * meaning to drop the first or last argument (respectively),
- * or an argument somewhere in between.
- *
- * @param target the method handle to invoke after the arguments are dropped
- * @param valueTypes the type(s) of the argument(s) to drop
- * @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) {
- if (valueTypes.size() == 0) return target;
- MethodType oldType = target.type();
- int outargs = oldType.parameterCount();
- int inargs = outargs + valueTypes.size();
- if (pos < 0 || pos >= inargs)
- throw newIllegalArgumentException("no argument type to remove");
- ArrayList> ptypes =
- new ArrayList>(oldType.parameterList());
- ptypes.addAll(pos, valueTypes);
- MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
- return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
- }
-
- /**
- * 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.
- * This method is equivalent to the following code:
- *
- * {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
- *
- * @param target the method handle to invoke after the arguments are dropped
- * @param valueTypes the type(s) of the argument(s) to drop
- * @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) {
- return dropArguments(target, pos, Arrays.asList(valueTypes));
- }
-
- /**
- * Adapt a target method handle {@code target} by pre-processing
- * one or more of its arguments, each with its own unary filter function,
- * and then calling the target with each pre-processed argument
- * replaced by the result of its corresponding filter function.
- *
- * The pre-processing is performed by one or more method handles,
- * specified in the elements of the {@code filters} array.
- * 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
- * the method handle, then {@code F} must be a method handle which
- * takes exactly one argument. The type of {@code F}'s sole argument
- * replaces the corresponding argument type of the target
- * in the resulting adapted method handle.
- * The return type of {@code F} must be identical to the corresponding
- * parameter type of the target.
- *
- * It is an error if there are elements of {@code filters}
- * which do not correspond to argument positions in the target.
- * Example:
- *
- *
- * @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 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) {
- MethodType targetType = target.type();
- MethodHandle adapter = target;
- MethodType adapterType = targetType;
- int maxPos = targetType.parameterCount();
- if (pos + filters.length > maxPos)
- throw newIllegalArgumentException("too many filters");
- int curPos = pos-1; // pre-incremented
- for (MethodHandle filter : 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);
- }
- MethodType midType = adapter.type();
- if (midType != adapterType)
- adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null);
- return adapter;
- }
-
- /**
- * Adapt a target method handle {@code target} by post-processing
- * its return value with a unary filter function.
- *
- * If a filter {@code F} applies to the return value of
- * the target method handle, then {@code F} must be a method handle which
- * takes exactly one argument. The return type of {@code F}
- * replaces the return type of the target
- * in the resulting adapted method handle.
- * The argument type of {@code F} must be identical to the
- * return type of the target.
- * Example:
- *
- * @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 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
- MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
- MethodType targetType = target.type();
- MethodType filterType = filter.type();
- 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, 1, targetType.parameterList());
- return foldArguments(returner, target);
- }
-
- /**
- * Adapt a target method handle {@code target} by pre-processing
- * some of its arguments, and then calling the target with
- * the result of the pre-processing, plus all original arguments.
- *
- * The pre-processing is performed by a second method handle, the {@code combiner}.
- * The first {@code N} arguments passed to the adapter,
- * are copied to the combiner, which then produces a result.
- * (Here, {@code N} is defined as the parameter count of the adapter.)
- * After this, control passes to the {@code target}, with both the result
- * of the combiner, and all the original incoming arguments.
- *
- * The first argument type of the target must be identical with the
- * return type of the combiner.
- * The resulting adapter is the same type as the target, except that the
- * initial argument type of the target is dropped.
- *
- * (Note that {@link #dropArguments(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 asCollector} instead, since those
- * arguments will not need to be live on the stack on entry to the
- * target.)
- *
- * The first argument of the target must be identical with the
- * return value of the combiner.
- *
Here is pseudocode for the resulting adapter:
- *
- * // there are N arguments in the A sequence
- * T target(V, A[N]..., B...);
- * V combiner(A...);
- * T adapter(A... a, B... b) {
- * V v = combiner(a...);
- * return target(v, a..., b...);
- * }
- *
- * @param target the method handle to invoke after arguments are combined
- * @param combiner method handle to call initially on the incoming arguments
- * @return method handle which incorporates the specified argument folding logic
- * @throws 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}
- * are not identical with the argument types of {@code combiner}
- */
- public static
- MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
- MethodType targetType = target.type();
- MethodType combinerType = combiner.type();
- int foldArgs = combinerType.parameterCount();
- boolean ok = (targetType.parameterCount() >= 1 + foldArgs);
- if (ok && !combinerType.parameterList().equals(targetType.parameterList().subList(1, foldArgs+1)))
- ok = false;
- if (ok && !combinerType.returnType().equals(targetType.parameterType(0)))
- ok = false;
- if (!ok)
- throw misMatchedTypes("target and combiner types", targetType, combinerType);
- MethodType newType = targetType.dropParameterTypes(0, 1);
- return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner);
- }
-
- /**
- * Make a method handle which adapts a target method handle,
- * by guarding it with a test, a boolean-valued method handle.
- * If the guard fails, a fallback handle is called instead.
- * All three method handles must have the same corresponding
- * argument and return types, except that the return type
- * of the test must be boolean, and the test is allowed
- * to have fewer arguments than the other two method handles.
- *
Here is pseudocode for the resulting adapter:
- *
- * boolean test(A...);
- * T target(A...,B...);
- * T fallback(A...,B...);
- * T adapter(A... a,B... b) {
- * if (test(a...))
- * return target(a..., b...);
- * else
- * return fallback(a..., b...);
- * }
- *
- * Note that the test arguments ({@code a...} in the pseudocode) cannot
- * be modified by execution of the test, and so are passed unchanged
- * from the caller to the target or fallback as appropriate.
- * @param test method handle used for test, must return boolean
- * @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}).
- */
- public static
- MethodHandle guardWithTest(MethodHandle test,
- MethodHandle target,
- MethodHandle fallback) {
- MethodType gtype = test.type();
- MethodType ttype = target.type();
- MethodType ftype = fallback.type();
- if (!ttype.equals(ftype))
- throw misMatchedTypes("target and fallback types", ttype, ftype);
- if (gtype.returnType() != boolean.class)
- throw newIllegalArgumentException("guard type is not a predicate "+gtype);
- List> targs = ttype.parameterList();
- List> gargs = gtype.parameterList();
- if (!targs.equals(gargs)) {
- int gpc = gargs.size(), tpc = targs.size();
- if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
- throw misMatchedTypes("target and test types", ttype, gtype);
- test = dropArguments(test, gpc, targs.subList(gpc, tpc));
- gtype = test.type();
- }
- return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
- }
-
- static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
- return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
- }
-
- /**
- * Make a method handle which adapts a target method handle,
- * by running it inside an exception handler.
- * If the target returns normally, the adapter returns that value.
- * If an exception matching the specified type is thrown, the fallback
- * handle is called instead on the exception, plus the original arguments.
- *
- * The target and handler must have the same corresponding
- * argument and return types, except that handler may omit trailing arguments
- * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
- * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
- *
Here is pseudocode for the resulting adapter:
- *
- * T target(A..., B...);
- * T handler(ExType, A...);
- * T adapter(A... a, B... b) {
- * try {
- * return target(a..., b...);
- * } catch (ExType ex) {
- * return handler(ex, a...);
- * }
- * }
- *
- * Note that the saved arguments ({@code a...} in the pseudocode) cannot
- * be modified by execution of the target, and so are passed unchanged
- * from the caller to the handler, if the handler is invoked.
- *
- * The target and handler must return the same type, even if the handler
- * always throws. (This might happen, for instance, because the handler
- * is simulating a {@code finally} clause).
- * To create such a throwing handler, compose the handler creation logic
- * with {@link #throwException throwException},
- * in order to create a method handle of the correct return type.
- * @param target method handle to call
- * @param exType the type of exception which the handler will catch
- * @param handler method handle to call if a matching exception is thrown
- * @return method handle which incorporates the specified try/catch logic
- * @throws 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
- * corresponding parameters
- */
- public static
- MethodHandle catchException(MethodHandle target,
- Class extends Throwable> exType,
- MethodHandle handler) {
- MethodType ttype = target.type();
- MethodType htype = handler.type();
- if (htype.parameterCount() < 1 ||
- !htype.parameterType(0).isAssignableFrom(exType))
- throw newIllegalArgumentException("handler does not accept exception type "+exType);
- if (htype.returnType() != ttype.returnType())
- throw misMatchedTypes("target and handler return types", ttype, htype);
- List> targs = ttype.parameterList();
- List> hargs = htype.parameterList();
- hargs = hargs.subList(1, hargs.size()); // omit leading parameter from handler
- if (!targs.equals(hargs)) {
- int hpc = hargs.size(), tpc = targs.size();
- if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
- throw misMatchedTypes("target and handler types", ttype, htype);
- handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc));
- htype = handler.type();
- }
- return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
- }
-
- /**
- * 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) {
- return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
- }
-
- /**
- * 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.
- * 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.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)
- * not declared by the SAM type's single abstract method.
- * If this happens, the throwable will be wrapped in an instance of
- * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
- * and thrown in that wrapped form.
- *
- * 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.
- *
- * 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 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
- */
- // 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
- final Method sam = getSamMethod(samType);
- if (sam == null)
- throw new IllegalArgumentException("not a SAM type: "+samType.getName());
- MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes());
- 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, WrapperInstance.class },
- new InvocationHandler() {
- private Object getArg(String name) {
- 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() == WrapperInstance.class)
- return getArg(method.getName());
- if (method.equals(sam))
- return vaTarget.invokeExact(args);
- if (isObjectMethod(method))
- return callObjectMethod(this, method, args);
- throw new InternalError();
- }
- }));
- }
-
- /**
- * 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 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
- boolean isObjectMethod(Method m) {
- switch (m.getName()) {
- case "toString":
- return (m.getReturnType() == String.class
- && m.getParameterTypes().length == 0);
- case "hashCode":
- return (m.getReturnType() == int.class
- && m.getParameterTypes().length == 0);
- case "equals":
- return (m.getReturnType() == boolean.class
- && m.getParameterTypes().length == 1
- && m.getParameterTypes()[0] == Object.class);
- }
- return false;
- }
-
- private static
- Object callObjectMethod(Object self, Method m, Object[] args) {
- assert(isObjectMethod(m)) : m;
- switch (m.getName()) {
- case "toString":
- return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
- case "hashCode":
- return System.identityHashCode(self);
- case "equals":
- return (self == args[0]);
- }
- return null;
- }
-
- private static
- Method getSamMethod(Class> samType) {
- Method sam = null;
- for (Method m : samType.getMethods()) {
- int mod = m.getModifiers();
- if (Modifier.isAbstract(mod)) {
- if (sam != null && !isObjectMethod(sam))
- return null; // too many abstract methods
- sam = m;
- }
- }
- if (!samType.isInterface() && getSamConstructor(samType) == null)
- return null; // wrong kind of constructor
- return sam;
- }
-
- private static
- Constructor getSamConstructor(Class> samType) {
- for (Constructor c : samType.getDeclaredConstructors()) {
- if (c.getParameterTypes().length == 0) {
- int mod = c.getModifiers();
- if (Modifier.isPublic(mod) || Modifier.isProtected(mod))
- return c;
- }
- }
- return null;
- }
-
- /*non-public*/
- static MethodHandle asVarargsCollector(MethodHandle target, Class> arrayType) {
- return MethodHandleImpl.asVarargsCollector(IMPL_TOKEN, target, arrayType);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/MethodType.java
--- a/src/share/classes/java/dyn/MethodType.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,865 +0,0 @@
-/*
- * 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
- * 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;
-
-import java.util.Arrays;
-import java.util.Collections;
-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;
-
-/**
- * A method type represents the arguments and return type accepted and
- * returned by a method handle, or the arguments and return type passed
- * 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 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.
- * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
- * (For ease of exposition, we treat {@code void} as if it were a type.
- * In fact, it denotes the absence of a return type.)
- *
- * All instances of {@code MethodType} are immutable.
- * Two instances are completely interchangeable if they compare equal.
- * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
- *
- * This type can be created only by factory methods.
- * All factory methods may cache values, though caching is not guaranteed.
- * Some factory methods are static, while others are virtual methods which
- * modify precursor method types, e.g., by changing a selected parameter.
- *
- * Factory methods which operate on groups of parameter types
- * are systematically presented in two versions, so that both Java arrays and
- * Java lists can be used to work with groups of parameter types.
- * The query methods {@code parameterArray} and {@code parameterList}
- * also provide a choice between arrays and lists.
- *
- * {@code MethodType} objects are sometimes derived from bytecode instructions
- * such as {@code invokedynamic}, specifically from the type descriptor strings associated
- * 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.
- * 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.
- *
- * When the JVM materializes a {@code MethodType} from a descriptor string,
- * all classes named in the descriptor must be accessible, and will be loaded.
- * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
- * This loading may occur at any time before the {@code MethodType} object is first derived.
- * @author John Rose, JSR 292 EG
- */
-public final
-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
-
- private static final Access IMPL_TOKEN = Access.getToken();
-
- // share a cache with a friend in this package
- Invokers getInvokers() { return invokers; }
- void setInvokers(Invokers inv) { invokers = inv; }
-
- static {
- // This hack allows the implementation package special access to
- // the internals of MethodType. In particular, the MTImpl has all sorts
- // of cached information useful to the implementation code.
- MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
- public Class>[] ptypes(MethodType mt) { return mt.ptypes; }
- public MethodTypeImpl form(MethodType mt) { return mt.form; }
- public void setForm(MethodType mt, MethodTypeImpl form) {
- assert(mt.form == null);
- mt.form = (MethodTypeForm) form;
- }
- public MethodType makeImpl(Class> rtype, Class>[] ptypes, boolean trusted) {
- return MethodType.makeImpl(rtype, ptypes, trusted);
- }
- public MethodTypeImpl newMethodTypeForm(MethodType mt) {
- return new MethodTypeForm(mt);
- }
- public Invokers getInvokers(MethodType mt) { return mt.invokers; }
- public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; }
- });
- }
-
- /**
- * Check the given parameters for validity and store them into the final fields.
- */
- private MethodType(Class> rtype, Class>[] ptypes) {
- checkRtype(rtype);
- checkPtypes(ptypes);
- this.rtype = rtype;
- this.ptypes = ptypes;
- }
-
- private static void checkRtype(Class> rtype) {
- rtype.equals(rtype); // null check
- }
- 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) {
- 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
- = new HashMap();
-
- static final Class>[] NO_PTYPES = {};
-
- /**
- * 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 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);
- }
-
- /**
- * 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> ptypes) {
- boolean notrust = false; // random List impl. could return evil ptypes array
- return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
- }
-
- /**
- * 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) {
- Class>[] ptypes1 = new Class>[1+ptypes.length];
- ptypes1[0] = ptype0;
- System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
- return makeImpl(rtype, ptypes1, true);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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) {
- return makeImpl(rtype, ptypes.ptypes, true);
- }
-
- /**
- * Sole factory method to find or create an interned method type.
- * @param rtype desired return type
- * @param ptypes desired parameter types
- * @param trusted whether the ptypes can be used without cloning
- * @return the unique method type of the desired structure
- */
- private static
- MethodType makeImpl(Class> rtype, Class>[] ptypes, boolean trusted) {
- if (ptypes == null || ptypes.length == 0) {
- ptypes = NO_PTYPES; trusted = true;
- }
- MethodType mt1 = new MethodType(rtype, ptypes);
- MethodType mt0;
- synchronized (internTable) {
- mt0 = internTable.get(mt1);
- if (mt0 != null)
- return mt0;
- }
- if (!trusted)
- // defensively copy the array passed in by the user
- mt1 = new MethodType(rtype, ptypes.clone());
- // promote the object to the Real Thing, and reprobe
- MethodTypeImpl.initForm(IMPL_TOKEN, mt1);
- synchronized (internTable) {
- mt0 = internTable.get(mt1);
- if (mt0 != null)
- return mt0;
- internTable.put(mt1, mt1);
- }
- return mt1;
- }
-
- // Entry point from JVM. TODO: Change the name & signature.
- private static MethodType makeImpl(Class> rtype, Class>[] ptypes,
- boolean ignore1, boolean ignore2) {
- return makeImpl(rtype, ptypes, true);
- }
-
- private static final MethodType[] objectOnlyTypes = new MethodType[20];
-
- /**
- * 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) {
- mt = objectOnlyTypes[ootIndex];
- if (mt != null) return mt;
- }
- Class>[] ptypes = new Class>[objectArgCount + ivarargs];
- Arrays.fill(ptypes, Object.class);
- if (ivarargs != 0) ptypes[objectArgCount] = Object[].class;
- mt = makeImpl(Object.class, ptypes, true);
- if (ootIndex < objectOnlyTypes.length) {
- objectOnlyTypes[ootIndex] = mt; // cache it here also!
- }
- return mt;
- }
-
- /**
- * 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
- MethodType genericMethodType(int objectArgCount) {
- return genericMethodType(objectArgCount, false);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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 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 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);
- System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
- System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
- return makeImpl(rtype, nptypes, true);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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 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));
- }
-
- /**
- * 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 newIndexOutOfBoundsException("start="+start+" end="+end);
- if (start == end) return this;
- Class>[] nptypes;
- if (start == 0) {
- if (end == len) {
- // drop all parameters
- nptypes = NO_PTYPES;
- } else {
- // drop initial parameter(s)
- nptypes = Arrays.copyOfRange(ptypes, end, len);
- }
- } else {
- if (end == len) {
- // drop trailing parameter(s)
- nptypes = Arrays.copyOfRange(ptypes, 0, start);
- } else {
- int tail = len - end;
- nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
- System.arraycopy(ptypes, end, nptypes, start, tail);
- }
- }
- return makeImpl(rtype, nptypes, true);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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
- */
- public boolean hasPrimitives() {
- return form.hasPrimitives();
- }
-
- /**
- * 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
- */
- public boolean hasWrappers() {
- return unwrap() != this;
- }
-
- /**
- * 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
- */
- public MethodType erase() {
- return form.erasedType();
- }
-
- /**
- * 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
- */
- public MethodType generic() {
- return genericMethodType(parameterCount());
- }
-
- /**
- * 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
- * as {@code type.generic()}.
- * @return a version of the original type with all primitive types replaced
- */
- public MethodType wrap() {
- return hasPrimitives() ? wrapWithPrims(this) : this;
- }
-
- /**
- * 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
- */
- public MethodType unwrap() {
- MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
- return unwrapWithNoPrims(noprims);
- }
-
- private static MethodType wrapWithPrims(MethodType pt) {
- assert(pt.hasPrimitives());
- MethodType wt = pt.wrapAlt;
- if (wt == null) {
- // fill in lazily
- wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP);
- assert(wt != null);
- pt.wrapAlt = wt;
- }
- return wt;
- }
-
- private static MethodType unwrapWithNoPrims(MethodType wt) {
- assert(!wt.hasPrimitives());
- MethodType uwt = wt.wrapAlt;
- if (uwt == null) {
- // fill in lazily
- uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP);
- if (uwt == null)
- uwt = wt; // type has no wrappers or prims at all
- wt.wrapAlt = uwt;
- }
- return uwt;
- }
-
- /**
- * 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];
- }
- /**
- * Returns the number of parameter types in this method type.
- * @return the number of parameter types
- */
- public int parameterCount() {
- return ptypes.length;
- }
- /**
- * Returns the return type of this method type.
- * @return the return type
- */
- public Class> returnType() {
- return rtype;
- }
-
- /**
- * 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() {
- return Collections.unmodifiableList(Arrays.asList(ptypes));
- }
-
- /**
- * 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)
- */
- public Class>[] parameterArray() {
- return ptypes.clone();
- }
-
- /**
- * Compares the specified object with this type for equality.
- * That is, it returns true if and only if the specified object
- * is also a method type with exactly the same parameters and return type.
- * @param x object to compare
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(Object x) {
- return this == x || x instanceof MethodType && equals((MethodType)x);
- }
-
- private boolean equals(MethodType that) {
- return this.rtype == that.rtype
- && Arrays.equals(this.ptypes, that.ptypes);
- }
-
- /**
- * Returns the hash code value for this method type.
- * It is defined to be the same as the hashcode of a List
- * whose elements are the return type followed by the
- * parameter types.
- * @return the hash code value for this method type
- * @see Object#hashCode()
- * @see #equals(Object)
- * @see List#hashCode()
- */
- @Override
- public int hashCode() {
- int hashCode = 31 + rtype.hashCode();
- for (Class> ptype : ptypes)
- hashCode = 31*hashCode + ptype.hashCode();
- return hashCode;
- }
-
- /**
- * 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}.
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("(");
- for (int i = 0; i < ptypes.length; i++) {
- if (i > 0) sb.append(",");
- sb.append(ptypes[i].getSimpleName());
- }
- sb.append(")");
- sb.append(rtype.getSimpleName());
- return sb.toString();
- }
-
- /// Queries which have to do with the bytecode architecture
-
- /** 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() 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();
- }
-
- /** 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
- * according to their trailing edge. Thus, to obtain the depth
- * in the outgoing call stack of parameter {@code N}, obtain
- * the {@code parameterSlotDepth} of its trailing edge
- * at position {@code N+1}.
- *
- * Parameters of type {@code long} and {@code double} occupy
- * two stack slots (for historical reasons) and all others occupy one.
- * Therefore, the number returned is the number of arguments
- * including and after the given parameter,
- * plus the number of long or double arguments
- * at or after after the argument for the given parameter.
- *
- * This method is included for the benfit of applications that must
- * generate bytecodes that process method handles and invokedynamic.
- * @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)
- parameterType(num); // force a range check
- return form.parameterToArgSlot(num-1);
- }
-
- /** 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.
- *
- * 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();
- }
-
- /**
- * 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).
- *
- * Note that it is possible to encounter method types which cannot be
- * constructed by this method, because their component types are
- * 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 {@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 type descriptor
- * @throws IllegalArgumentException if the string is not well-formed
- * @throws TypeNotPresentException if a named type cannot be found
- */
- public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
- throws IllegalArgumentException, TypeNotPresentException
- {
- List> types = BytecodeDescriptor.parseMethod(descriptor, loader);
- Class> rtype = types.remove(types.size() - 1);
- Class>[] ptypes = types.toArray(NO_PTYPES);
- return makeImpl(rtype, ptypes, true);
- }
-
- /**
- * Produces a bytecode descriptor representation of the method type.
- *
- * 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 {@code invokedynamic}.
- * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
- * because the latter requires a suitable class loader argument.
- * @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:
- *
- * 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 -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/MethodTypeForm.java
--- a/src/share/classes/java/dyn/MethodTypeForm.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 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;
-
-/**
- * TO DO: Temporary shim; remove after refactoring effects are complete in JVM.
- * @author John Rose
- */
-import sun.dyn.MethodTypeImpl;
-
-class MethodTypeForm extends MethodTypeImpl {
-
- MethodTypeForm(MethodType erasedType) {
- super(erasedType);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/MutableCallSite.java
--- a/src/share/classes/java/dyn/MutableCallSite.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-/*
- * 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
- * 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;
-
-import sun.dyn.*;
-import sun.dyn.empty.Empty;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A {@code MutableCallSite} is a {@link CallSite} whose target variable
- * behaves like an ordinary field.
- * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
- * all calls to the site's current target.
- * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
- * also delegates each call to the site's current target.
- *
- * Here is an example of a mutable call site which introduces a
- * state variable into a method handle chain.
- *
-MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
-MethodHandle MH_name = name.dynamicInvoker();
-MethodType MT_str2 = MethodType.methodType(String.class, String.class);
-MethodHandle MH_upcase = MethodHandles.lookup()
- .findVirtual(String.class, "toUpperCase", MT_str2);
-MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
-name.setTarget(MethodHandles.constant(String.class, "Rocky"));
-assertEquals("ROCKY", (String) worker1.invokeExact());
-name.setTarget(MethodHandles.constant(String.class, "Fred"));
-assertEquals("FRED", (String) worker1.invokeExact());
-// (mutation can be continued indefinitely)
- *
- *
- * The same call site may be used in several places at once.
- *
- * Non-synchronization of target values:
- * A write to a mutable call site's target does not force other threads
- * to become aware of the updated value. Threads which do not perform
- * suitable synchronization actions relative to the updated call site
- * may cache the old target value and delay their use of the new target
- * value indefinitely.
- * (This is a normal consequence of the Java Memory Model as applied
- * to object fields.)
- *
- * 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
- * a {@linkplain VolatileCallSite volatile call site} instead.
- * @author John Rose, JSR 292 EG
- */
-public class MutableCallSite extends CallSite {
- /**
- * 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) {
- super(type);
- }
-
- /**
- * 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) {
- super(target);
- }
-
- /**
- * 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.
- *
- * This operation does not reverse any calls that have already started
- * on an old target value.
- * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
- *
- * 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 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 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 syncAll} that confirms the value).
- * On the other hand, reader threads may observe previous versions of
- * 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
- * that may access one of the affected call sites.
- *
- * The following effects are apparent, for each individual call site {@code S}:
- *
- *
A new volatile variable {@code V} is created, and written by the current thread.
- * As defined by the JMM, this write is a global synchronization event.
- *
As is normal with thread-local ordering of write events,
- * every action already performed by the current thread is
- * taken to happen before the volatile write to {@code V}.
- * (In some implementations, this means that the current thread
- * performs a global release operation.)
- *
Specifically, the write to the current target of {@code S} is
- * taken to happen before the volatile write to {@code V}.
- *
The volatile write to {@code V} is placed
- * (in an implementation specific manner)
- * in the global synchronization order.
- *
Consider an arbitrary thread {@code T} (other than the current thread).
- * If {@code T} executes a synchronization action {@code A}
- * after the volatile write to {@code V} (in the global synchronization order),
- * it is therefore required to see either the current target
- * of {@code S}, or a later write to that target,
- * if it executes a read on the target of {@code S}.
- * (This constraint is called "synchronization-order consistency".)
- *
The JMM specifically allows optimizing compilers to elide
- * reads or writes of variables that are known to be useless.
- * Such elided reads and writes have no effect on the happens-before
- * relation. Regardless of this fact, the volatile {@code V}
- * will not be elided, even though its written value is
- * indeterminate and its read value is not used.
- *
- * Because of the last point, the implementation behaves as if a
- * volatile read of {@code V} were performed by {@code T}
- * immediately after its action {@code A}. In the local ordering
- * of actions in {@code T}, this read happens before any future
- * read of the target of {@code S}. It is as if the
- * implementation arbitrarily picked a read of {@code S}'s target
- * by {@code T}, and forced a read of {@code V} to precede it,
- * 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 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.
- *
- *
- * 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.
- * 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 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.
- *
- *
- * 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 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 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 -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/SwitchPoint.java
--- a/src/share/classes/java/dyn/SwitchPoint.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * 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:
- *
-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]));
- }
-}
- *
- * @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.
- *
- * 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 -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/VolatileCallSite.java
--- a/src/share/classes/java/dyn/VolatileCallSite.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * 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;
-
-import java.util.List;
-
-/**
- * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
- * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
- * to its call site target immediately, even if the update occurs in another thread.
- * There may be a performance penalty for such tight coupling between threads.
- *
- * Unlike {@code MutableCallSite}, there is no
- * {@linkplain MutableCallSite#syncAll syncAll operation} on volatile
- * call sites, since every write to a volatile variable is implicitly
- * synchronized with reader threads.
- *
- * In other respects, a {@code VolatileCallSite} is interchangeable
- * with {@code MutableCallSite}.
- * @see MutableCallSite
- * @author John Rose, JSR 292 EG
- */
-public class VolatileCallSite extends CallSite {
- /**
- * 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);
- }
-
- /**
- * 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);
- }
-
- /**
- * 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();
- }
-
- /**
- * 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 -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/WrongMethodTypeException.java
--- a/src/share/classes/java/dyn/WrongMethodTypeException.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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 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 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
- * matched up correctly. This amounts to an early evaluation
- * of the type mismatch, at method handle construction time,
- * instead of when the mismatched method handle is called.
- *
- * @author John Rose, JSR 292 EG
- * @since 1.7
- */
-public class WrongMethodTypeException extends RuntimeException {
- private static final long serialVersionUID = 292L;
-
- /**
- * Constructs a {@code WrongMethodTypeException} with no detail message.
- */
- public WrongMethodTypeException() {
- super();
- }
-
- /**
- * Constructs a {@code WrongMethodTypeException} with the specified
- * detail message.
- *
- * @param s the detail message.
- */
- public WrongMethodTypeException(String s) {
- super(s);
- }
-}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/dyn/package-info.java
--- a/src/share/classes/java/dyn/package-info.java Thu Mar 03 14:16:57 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,478 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-/**
- * 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:
- *
- *
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
- * the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
- *
- *
- *
- *
Corresponding JVM bytecode format changes
- * The following low-level information is presented here as a preview of
- * changes being made to the Java Virtual Machine specification for JSR 292.
- * This information will be incorporated in a future version of the JVM specification.
- *
- *
{@code invokedynamic} instruction format
- * In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
- * The first byte is the opcode 186 (hexadecimal {@code BA}).
- * The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
- * 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 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 type descriptor in a UTF8 string)
- *
optionally, a sequence of additional static arguments to the bootstrap method ({@code ldc}-type constants)
- *
- *
- * Each instance of an {@code invokedynamic} instruction is called a dynamic call site.
- * Multiple instances of an {@code invokedynamic} instruction can share a single
- * {@code CONSTANT_InvokeDynamic} entry.
- * In any case, distinct call sites always have distinct linkage state.
- *
- * A dynamic call site is originally in an unlinked state. In this state, there is
- * no target method for the call site to invoke.
- * A dynamic call site is linked by means of a bootstrap method,
- * as described below.
- *
- *
- * 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.
- *
- *
constant pool entries for {@code invokedynamic} instructions
- * If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
- * it must contain exactly four more bytes after the tag.
- * These bytes are interpreted as two 16-bit indexes, in the usual {@code u2} format.
- * The first pair of bytes after the tag must be an index into a side table called the
- * 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}.
- *
- * 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.
- *
- *
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 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 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
- * references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
- *
- *
constant pool entries for {@linkplain java.dyn.MethodHandle method handles}
- * If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
- * it must contain exactly three more bytes. The first byte after the tag is a subtag
- * value which must be in the range 1 through 9, and the last two must be an index to a
- * {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
- * {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
- * for which a method handle is to be created.
- * Furthermore, the subtag value and the type of the constant index value
- * must agree according to the table below.
- *
- * The JVM will ensure that on first execution of an {@code ldc} instruction
- * for this entry, a {@link java.dyn.MethodHandle MethodHandle} will be created which represents
- * the field or method reference, according to the specific mode implied by the subtag.
- *
- * As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
- * the {@code Class} or {@code MethodType} object which reifies the field or method's
- * 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*}.
- *
- * 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.
- * 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 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.
- *
- * Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
- * resolve class names, they do not force class initialization.
- * Method handle constants for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
- * may force class initialization on their first invocation, just like the corresponding bytecodes.
- *
- * The rules of section 5.4.3 of the
- * JVM Specification
- * apply to the resolution of {@code CONSTANT_MethodType}, {@code CONSTANT_MethodHandle},
- * and {@code CONSTANT_InvokeDynamic} constants,
- * 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 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 {@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.
- *
- *
Bootstrap Methods
- * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
- * the call site must first be linked.
- * Linking is accomplished by calling a bootstrap method
- * which is given the static information content of the call site,
- * and which must produce a {@link java.dyn.MethodHandle method handle}
- * that gives the behavior of the call site.
- *
- * 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 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 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 at least four values being stacked:
- *
- *
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 descriptor of the call
- * 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's type descriptor and passed to
- * the bootstrap method.
- * The call site then becomes permanently linked to the dynamic call site.
- *
- * As long as each bootstrap method can be correctly invoked
- * by invokeGeneric, its detailed type is arbitrary.
- * For example, the first argument could be {@code Object}
- * instead of {@code MethodHandles.Lookup}, and the return type
- * could also be {@code Object} instead of {@code CallSite}.
- *
- * As with any method handle constant, a {@code varargs} modifier bit
- * on the bootstrap method is ignored.
- *
- * Note that the first argument of the bootstrap method cannot be
- * a simple {@code Class} reference. (This is a change from earlier
- * versions of this specification. If the caller class is needed,
- * it is easy to {@linkplain java.dyn.MethodHandles.Lookup#lookupClass() extract it}
- * from the {@code Lookup} object.)
- *
- * After resolution, the linkage process may fail in a variety of ways.
- * All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
- * which is thrown as the abnormal termination of the dynamic call
- * site execution.
- * The following circumstances will cause this:
- *
- *
the index to the bootstrap method specifier is out of range
- *
the bootstrap method cannot be resolved
- *
the {@code MethodType} to pass to the bootstrap method cannot be resolved
- *
a static argument to the bootstrap method cannot be resolved
- * (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
- * or {@code CONSTANT_MethodHandle} argument cannot be linked)
- *
the bootstrap method has the wrong arity,
- * causing {@code invokeGeneric} to throw {@code WrongMethodTypeException}
- *
the bootstrap method has a wrong argument or return type
- *
the bootstrap method invocation completes abnormally
- *
the result from the bootstrap invocation is not a reference to
- * an object of type {@link java.dyn.CallSite CallSite}
- *
the target of the {@code CallSite} does not have a target of
- * the expected {@code MethodType}
- *
- *
- *
timing of linkage
- * A dynamic call site is linked just before its first execution.
- * The bootstrap method call implementing the linkage occurs within
- * a thread that is attempting a first execution.
- *
- * If there are several such threads, the bootstrap method may be
- * invoked in several threads concurrently.
- * Therefore, bootstrap methods which access global application
- * data must take the usual precautions against race conditions.
- * In any case, every {@code invokedynamic} instruction is either
- * unlinked or linked to a unique {@code CallSite} object.
- *
- * In an application which requires dynamic call sites with individually
- * mutable behaviors, their bootstrap methods should produce distinct
- * {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
- * Alternatively, an application can link a single {@code CallSite} object
- * to several {@code invokedynamic} instructions, in which case
- * a change to the target method will become visible at each of
- * the instructions.
- *
- * If several threads simultaneously execute a bootstrap method for a single dynamic
- * call site, the JVM must choose one {@code CallSite} object and install it visibly to
- * all threads. Any other bootstrap method calls are allowed to complete, but their
- * results are ignored, and their dynamic call site invocations proceed with the originally
- * chosen target object.
- *
- *
- * 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.
- *
- *
- * Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
- * a bootstrap method specifier; all such specifiers are contained in a separate array.
- * This array is defined by a class attribute named {@code BootstrapMethods}.
- * The body of this attribute consists of a sequence of byte pairs, all interpreted as
- * as 16-bit counts or constant pool indexes, in the {@code u2} format.
- * The attribute body starts with a count of bootstrap method specifiers,
- * which is immediately followed by the sequence of specifiers.
- *
- * Each bootstrap method specifier contains an index to a
- * {@code CONSTANT_MethodHandle} constant, which is the bootstrap
- * method itself.
- * This is followed by a count, and then a sequence (perhaps empty) of
- * indexes to additional static arguments
- * for the bootstrap method.
- *
- * During class loading, the verifier must check the structure of the
- * {@code BootstrapMethods} attribute. In particular, each constant
- * pool index must be of the correct type. A bootstrap method index
- * must refer to a {@code CONSTANT_MethodHandle} (tag 15).
- * Every other index must refer to a valid operand of an
- * {@code ldc_w} or {@code ldc2_w} instruction (tag 3..8 or 15..16).
- *
- *
- * An {@code invokedynamic} instruction specifies at least three arguments
- * to pass to its bootstrap method:
- * The caller class (expressed as a {@link java.dyn.MethodHandles.Lookup Lookup object},
- * the name (extracted from the {@code CONSTANT_NameAndType} entry),
- * and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
- * The {@code invokedynamic} instruction may specify additional metadata values
- * to pass to its bootstrap method.
- * Collectively, these values are called static arguments to the
- * {@code invokedynamic} instruction, because they are used once at link
- * time to determine the instruction's behavior on subsequent sets of
- * dynamic arguments.
- *
- * Static arguments are used to communicate application-specific meta-data
- * to the bootstrap method.
- * Drawn from the constant pool, they may include references to classes, method handles,
- * strings, or numeric data that may be relevant to the task of linking that particular call site.
- *
- * 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.
- * The valid constant pool entries are listed in this table:
- *
- *
- *
entry type
argument type
argument value
- *
CONSTANT_String
java.lang.String
the indexed string literal
- *
CONSTANT_Class
java.lang.Class
the indexed class, resolved
- *
CONSTANT_Integer
java.lang.Integer
the indexed int value
- *
CONSTANT_Long
java.lang.Long
the indexed long value
- *
CONSTANT_Float
java.lang.Float
the indexed float value
- *
CONSTANT_Double
java.lang.Double
the indexed double value
- *
CONSTANT_MethodHandle
java.dyn.MethodHandle
the indexed method handle constant
- *
CONSTANT_MethodType
java.dyn.MethodType
the indexed method type constant
- *
- *
- *
- * If a given {@code invokedynamic} instruction specifies no static arguments,
- * the instruction's bootstrap method will be invoked on three arguments,
- * conveying the instruction's caller class, name, and method type.
- * If the {@code invokedynamic} instruction specifies one or more static arguments,
- * those values will be passed as additional arguments to the method handle.
- * (Note that because there is a limit of 255 arguments to any method,
- * at most 252 extra arguments can be supplied.)
- * The bootstrap method will be invoked as if by either {@code invokeGeneric}
- * or {@code invokeWithArguments}. (There is no way to tell the difference.)
- *
- * The normal argument conversion rules for {@code invokeGeneric} apply to all stacked arguments.
- * For example, if a pushed value is a primitive type, it may be converted to a reference by boxing conversion.
- * If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
- * then some or all of the arguments specified here may be collected into a trailing array parameter.
- * (This is not a special rule, but rather a useful consequence of the interaction
- * between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
- * and the {@code java.dyn.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
- *
- * Given these rules, here are examples of legal bootstrap method declarations,
- * given various numbers {@code N} of extra arguments.
- * The first rows (marked {@code *}) will work for any number of extra arguments.
- *
- *
- *
- * The last example assumes that the extra arguments are of type
- * {@code CONSTANT_String} and {@code CONSTANT_Integer}, respectively.
- * The second-to-last example assumes that all extra arguments are of type
- * {@code CONSTANT_String}.
- * The other examples work with all types of extra arguments.
- *
- * As noted above, the actual method type of the bootstrap method can vary.
- * For example, the fourth argument could be {@code MethodHandle},
- * if that is the type of the corresponding constant in
- * the {@code CONSTANT_InvokeDynamic} entry.
- * In that case, the {@code invokeGeneric} call will pass the extra method handle
- * constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
- * will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
- * (If a string constant were passed instead, by badly generated code, that cast would then fail,
- * resulting in an {@code InvokeDynamicBootstrapError}.)
- *
- * Extra bootstrap method arguments are intended to allow language implementors
- * to safely and compactly encode metadata.
- * In principle, the name and extra arguments are redundant,
- * since each call site could be given its own unique bootstrap method.
- * Such a practice is likely to produce large class files and constant pools.
- *
- *
Structure Summary
- *
// summary of constant and attribute structures
-struct CONSTANT_MethodHandle_info {
- u1 tag = 15;
- u1 reference_kind; // 1..8 (one of REF_invokeVirtual, etc.)
- u2 reference_index; // index to CONSTANT_Fieldref or *Methodref
-}
-struct CONSTANT_MethodType_info {
- u1 tag = 16;
- u2 descriptor_index; // index to CONSTANT_Utf8, as in NameAndType
-}
-struct CONSTANT_InvokeDynamic_info {
- u1 tag = 18;
- u2 bootstrap_method_attr_index; // index into BootstrapMethods_attr
- u2 name_and_type_index; // index to CONSTANT_NameAndType, as in Methodref
-}
-struct BootstrapMethods_attr {
- u2 name; // CONSTANT_Utf8 = "BootstrapMethods"
- u4 size;
- u2 bootstrap_method_count;
- struct bootstrap_method_specifier {
- u2 bootstrap_method_ref; // index to CONSTANT_MethodHandle
- u2 bootstrap_argument_count;
- u2 bootstrap_arguments[bootstrap_argument_count]; // constant pool indexes
- } bootstrap_methods[bootstrap_method_count];
-}
- *
- *
- * @author John Rose, JSR 292 EG
- */
-
-package java.dyn;
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/ArithmeticException.java
--- a/src/share/classes/java/lang/ArithmeticException.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/lang/ArithmeticException.java Fri Apr 08 10:27:23 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -30,15 +30,18 @@
* example, an integer "divide by zero" throws an
* instance of this class.
*
+ * {@code ArithmeticException} objects may be constructed by the
+ * virtual machine as if {@linkplain Throwable#Throwable(String,
+ * Throwable, boolean) suppression were disabled}.
+ *
* @author unascribed
* @since JDK1.0
*/
-public
-class ArithmeticException extends RuntimeException {
+public class ArithmeticException extends RuntimeException {
private static final long serialVersionUID = 2256477558314496007L;
/**
- * Constructs an ArithmeticException with no detail
+ * Constructs an {@code ArithmeticException} with no detail
* message.
*/
public ArithmeticException() {
@@ -46,7 +49,7 @@
}
/**
- * Constructs an ArithmeticException with the specified
+ * Constructs an {@code ArithmeticException} with the specified
* detail message.
*
* @param s the detail message.
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/BootstrapMethodError.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/BootstrapMethodError.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,80 @@
+/*
+ * 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
+ * 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.lang;
+
+/**
+ * Thrown to indicate that an {@code invokedynamic} instruction has
+ * failed to find its bootstrap method,
+ * or the bootstrap method has failed to provide a
+ * {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
+ * of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class BootstrapMethodError extends LinkageError {
+ private static final long serialVersionUID = 292L;
+
+ /**
+ * Constructs an {@code BootstrapMethodError} with no detail message.
+ */
+ public BootstrapMethodError() {
+ super();
+ }
+
+ /**
+ * Constructs an {@code BootstrapMethodError} with the specified
+ * detail message.
+ *
+ * @param s the detail message.
+ */
+ public BootstrapMethodError(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with the specified
+ * detail message and cause.
+ *
+ * @param s the detail message.
+ * @param cause the cause, may be {@code null}.
+ */
+ public BootstrapMethodError(String s, Throwable cause) {
+ super(s, cause);
+ }
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with the specified
+ * cause.
+ *
+ * @param cause the cause, may be {@code null}.
+ */
+ public BootstrapMethodError(Throwable cause) {
+ // cf. Throwable(Throwable cause) constructor.
+ super(cause == null ? null : cause.toString());
+ initCause(cause);
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/ClassValue.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/ClassValue.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,231 @@
+/*
+ * 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.lang;
+
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 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
+ * @since 1.7
+ */
+public abstract class ClassValue {
+ /**
+ * Computes the given class's derived value for this {@code ClassValue}.
+ *
+ * This method will be invoked within the first thread that accesses
+ * the value with the {@link #get get} method.
+ *
+ * Normally, this method is invoked at most once per class,
+ * but it may be invoked again if there has been a call to
+ * {@link #remove remove}.
+ *
+ * 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
+ * @see #get
+ * @see #remove
+ */
+ protected abstract T computeValue(Class> type);
+
+ /**
+ * Returns the value for the given class.
+ * If no value has yet been computed, it is obtained by
+ * an invocation of the {@link #computeValue computeValue} method.
+ *
+ * The actual installation of the value on the class
+ * is performed atomically.
+ * 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);
+ if (map != null) {
+ Object x = map.get(this);
+ if (x != null) {
+ return (T) map.unmaskNull(x);
+ }
+ }
+ return setComputedValue(type);
+ }
+
+ /**
+ * Removes the associated value for the given class.
+ * If this value is subsequently {@linkplain #get read} for the same class,
+ * its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
+ * This may result in an additional invocation of the
+ * {@code computeValue computeValue} method for the given class.
+ *
+ * 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:
+ *
+ *
{@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
+ *
+ * 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);
+ if (map != null) {
+ synchronized (map) {
+ map.remove(this);
+ }
+ }
+ }
+
+ /// Implementation...
+ // FIXME: Use a data structure here similar that of ThreadLocal (7030453).
+
+ private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+
+ /** Slow path for {@link #get}. */
+ private T setComputedValue(Class> type) {
+ ClassValueMap map = getMap(type);
+ if (map == null) {
+ map = initializeMap(type);
+ }
+ T value = computeValue(type);
+ STORE_BARRIER.lazySet(0);
+ // All stores pending from computeValue are completed.
+ synchronized (map) {
+ // Warm up the table with a null entry.
+ map.preInitializeEntry(this);
+ }
+ STORE_BARRIER.lazySet(0);
+ // All stores pending from table expansion are completed.
+ synchronized (map) {
+ value = (T) map.initializeEntry(this, value);
+ // One might fear a possible race condition here
+ // if the code for map.put has flushed the write
+ // to map.table[*] before the writes to the Map.Entry
+ // are done. This is not possible, since we have
+ // warmed up the table with an empty entry.
+ }
+ return value;
+ }
+
+ // Replace this map by a per-class slot.
+ private static final WeakHashMap, ClassValueMap> ROOT
+ = new WeakHashMap, ClassValueMap>();
+
+ private static ClassValueMap getMap(Class> type) {
+ return ROOT.get(type);
+ }
+
+ private static ClassValueMap initializeMap(Class> type) {
+ synchronized (ClassValue.class) {
+ ClassValueMap map = ROOT.get(type);
+ if (map == null)
+ ROOT.put(type, map = new ClassValueMap());
+ return map;
+ }
+ }
+
+ static class ClassValueMap extends WeakHashMap {
+ /** Make sure this table contains an Entry for the given key, even if it is empty. */
+ void preInitializeEntry(ClassValue key) {
+ if (!this.containsKey(key))
+ this.put(key, null);
+ }
+ /** Make sure this table contains a non-empty Entry for the given key. */
+ Object initializeEntry(ClassValue key, Object value) {
+ Object prior = this.get(key);
+ if (prior != null) {
+ return unmaskNull(prior);
+ }
+ this.put(key, maskNull(value));
+ return value;
+ }
+
+ Object maskNull(Object x) {
+ return x == null ? this : x;
+ }
+ Object unmaskNull(Object x) {
+ return x == this ? null : x;
+ }
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/NullPointerException.java
--- a/src/share/classes/java/lang/NullPointerException.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/lang/NullPointerException.java Fri Apr 08 10:27:23 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -26,20 +26,24 @@
package java.lang;
/**
- * Thrown when an application attempts to use null in a
+ * Thrown when an application attempts to use {@code null} in a
* case where an object is required. These include:
*
- *
Calling the instance method of a null object.
- *
Accessing or modifying the field of a null object.
- *
Taking the length of null as if it were an array.
- *
Accessing or modifying the slots of null as if it
+ *
Calling the instance method of a {@code null} object.
+ *
Accessing or modifying the field of a {@code null} object.
+ *
Taking the length of {@code null} as if it were an array.
+ *
Accessing or modifying the slots of {@code null} as if it
* were an array.
- *
Throwing null as if it were a Throwable
+ *
Throwing {@code null} as if it were a {@code Throwable}
* value.
*
*
* Applications should throw instances of this class to indicate
- * other illegal uses of the null object.
+ * other illegal uses of the {@code null} object.
+ *
+ * {@code NullPointerException} objects may be constructed by the
+ * virtual machine as if {@linkplain Throwable#Throwable(String,
+ * Throwable, boolean) suppression were disabled}.
*
* @author unascribed
* @since JDK1.0
@@ -49,14 +53,14 @@
private static final long serialVersionUID = 5162710183389028792L;
/**
- * Constructs a NullPointerException with no detail message.
+ * Constructs a {@code NullPointerException} with no detail message.
*/
public NullPointerException() {
super();
}
/**
- * Constructs a NullPointerException with the specified
+ * Constructs a {@code NullPointerException} with the specified
* detail message.
*
* @param s the detail message.
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/OutOfMemoryError.java
--- a/src/share/classes/java/lang/OutOfMemoryError.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/lang/OutOfMemoryError.java Fri Apr 08 10:27:23 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -30,22 +30,25 @@
* because it is out of memory, and no more memory could be made
* available by the garbage collector.
*
+ * {@code OutOfMemoryError} objects may be constructed by the virtual
+ * machine as if {@linkplain Throwable#Throwable(String, Throwable,
+ * boolean) suppression were disabled}.
+ *
* @author unascribed
* @since JDK1.0
*/
-public
-class OutOfMemoryError extends VirtualMachineError {
+public class OutOfMemoryError extends VirtualMachineError {
private static final long serialVersionUID = 8228564086184010517L;
/**
- * Constructs an OutOfMemoryError with no detail message.
+ * Constructs an {@code OutOfMemoryError} with no detail message.
*/
public OutOfMemoryError() {
super();
}
/**
- * Constructs an OutOfMemoryError with the specified
+ * Constructs an {@code OutOfMemoryError} with the specified
* detail message.
*
* @param s the detail message.
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/Throwable.java
--- a/src/share/classes/java/lang/Throwable.java Thu Mar 03 14:16:57 2011 -0800
+++ b/src/share/classes/java/lang/Throwable.java Fri Apr 08 10:27:23 2011 -0700
@@ -52,7 +52,7 @@
* throwable can {@linkplain Throwable#addSuppressed suppress} other
* throwables from being propagated. Finally, the throwable can also
* contain a cause: another throwable that caused this
- * throwable to get thrown. The recording of this causal information
+ * throwable to be constructed. The recording of this causal information
* is referred to as the chained exception facility, as the
* cause can, itself, have a cause, and so on, leading to a "chain" of
* exceptions, each caused by another.
@@ -283,6 +283,41 @@
}
/**
+ * Constructs a new throwable with the specified detail message,
+ * cause, and {@linkplain #addSuppressed suppression} enabled or
+ * disabled. If suppression is disabled, {@link #getSuppressed}
+ * for this object will return a zero-length array and calls to
+ * {@link #addSuppressed} that would otherwise append an exception
+ * to the suppressed list will have no effect.
+ *
+ *
Note that the other constructors of {@code Throwable} treat
+ * suppression as being enabled. Subclasses of {@code Throwable}
+ * should document any conditions under which suppression is
+ * disabled. Disabling of suppression should only occur in
+ * exceptional circumstances where special requirements exist,
+ * such as a virtual machine reusing exception objects under
+ * low-memory situations.
+ *
+ * @param message the detail message.
+ * @param cause the cause. (A {@code null} value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ * @param enableSuppression whether or not suppression is enabled or disabled
+ *
+ * @see OutOfMemoryError
+ * @see NullPointerException
+ * @see ArithmeticException
+ * @since 1.7
+ */
+ protected Throwable(String message, Throwable cause,
+ boolean enableSuppression) {
+ fillInStackTrace();
+ detailMessage = message;
+ this.cause = cause;
+ if (!enableSuppression)
+ suppressedExceptions = null;
+ }
+
+ /**
* Returns the detail message string of this throwable.
*
* @return the detail message string of this {@code Throwable} instance
@@ -830,13 +865,10 @@
* typically called (automatically and implicitly) by the {@code
* try}-with-resources statement.
*
- * If the first exception to be suppressed is {@code null}, that
- * indicates suppressed exception information will not be
- * recorded for this exception. Subsequent calls to this method
- * will not record any suppressed exceptions. Otherwise,
- * attempting to suppress {@code null} after an exception has
- * already been successfully suppressed results in a {@code
- * NullPointerException}.
+ *
The suppression behavior is enabled unless disabled
+ * {@linkplain #Throwable(String, Throwable, boolean) via a
+ * constructor}. When suppression is disabled, this method does
+ * nothing other than to validate its argument.
*
*
Note that when one exception {@linkplain
* #initCause(Throwable) causes} another exception, the first
@@ -874,33 +906,23 @@
* suppressed exceptions
* @throws IllegalArgumentException if {@code exception} is this
* throwable; a throwable cannot suppress itself.
- * @throws NullPointerException if {@code exception} is null and
- * an exception has already been suppressed by this exception
+ * @throws NullPointerException if {@code exception} is {@code null}
* @since 1.7
*/
public final synchronized void addSuppressed(Throwable exception) {
if (exception == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
- if (exception == null) {
- if (suppressedExceptions == SUPPRESSED_SENTINEL) {
- suppressedExceptions = null; // No suppression information recorded
- return;
- } else
- throw new NullPointerException(NULL_CAUSE_MESSAGE);
- } else {
- assert exception != null && exception != this;
+ if (exception == null)
+ throw new NullPointerException(NULL_CAUSE_MESSAGE);
- if (suppressedExceptions == null) // Suppressed exceptions not recorded
- return;
+ if (suppressedExceptions == null) // Suppressed exceptions not recorded
+ return;
- if (suppressedExceptions == SUPPRESSED_SENTINEL)
- suppressedExceptions = new ArrayList<>(1);
+ if (suppressedExceptions == SUPPRESSED_SENTINEL)
+ suppressedExceptions = new ArrayList<>(1);
- assert suppressedExceptions != SUPPRESSED_SENTINEL;
-
- suppressedExceptions.add(exception);
- }
+ suppressedExceptions.add(exception);
}
private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
@@ -910,7 +932,9 @@
* suppressed, typically by the {@code try}-with-resources
* statement, in order to deliver this exception.
*
- * If no exceptions were suppressed, an empty array is returned.
+ * If no exceptions were suppressed or {@linkplain
+ * Throwable(String, Throwable, boolean) suppression is disabled},
+ * an empty array is returned.
*
* @return an array containing all of the exceptions that were
* suppressed to deliver this exception.
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/AdapterMethodHandle.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,943 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.util.VerifyType;
+import sun.invoke.util.Wrapper;
+import java.util.Arrays;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * This method handle performs simple conversion or checking of a single argument.
+ * @author jrose
+ */
+class AdapterMethodHandle extends BoundMethodHandle {
+
+ //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
+ //Object argument; // parameter to the conversion if needed
+ //int vmargslot; // which argument slot is affected
+ private final int conversion; // the type of conversion: RETYPE_ONLY, etc.
+
+ // Constructors in this class *must* be package scoped or private.
+ private AdapterMethodHandle(MethodHandle target, MethodType newType,
+ long conv, Object convArg) {
+ super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
+ this.conversion = convCode(conv);
+ // JVM might update VM-specific bits of conversion (ignore)
+ MethodHandleNatives.init(this, target, convArgPos(conv));
+ }
+ private AdapterMethodHandle(MethodHandle target, MethodType newType,
+ long conv) {
+ this(target, newType, conv, null);
+ }
+
+ // TO DO: When adapting another MH with a null conversion, clone
+ // the target and change its type, instead of adding another layer.
+
+ /** Can a JVM-level adapter directly implement the proposed
+ * argument conversions, as if by MethodHandles.convertArguments?
+ */
+ static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
+ // same number of args, of course
+ int len = newType.parameterCount();
+ if (len != oldType.parameterCount())
+ return false;
+
+ // Check return type. (Not much can be done with it.)
+ Class> exp = newType.returnType();
+ Class> ret = oldType.returnType();
+ if (!VerifyType.isNullConversion(ret, exp))
+ return false;
+
+ // Check args pairwise.
+ for (int i = 0; i < len; i++) {
+ Class> src = newType.parameterType(i); // source type
+ Class> dst = oldType.parameterType(i); // destination type
+ if (!canConvertArgument(src, dst))
+ return false;
+ }
+
+ return true;
+ }
+
+ /** Can a JVM-level adapter directly implement the proposed
+ * argument conversion, as if by MethodHandles.convertArguments?
+ */
+ static boolean canConvertArgument(Class> src, Class> dst) {
+ // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
+ // so we don't need to repeat so much decision making.
+ if (VerifyType.isNullConversion(src, dst)) {
+ return true;
+ } else if (src.isPrimitive()) {
+ if (dst.isPrimitive())
+ return canPrimCast(src, dst);
+ else
+ return canBoxArgument(src, dst);
+ } else {
+ if (dst.isPrimitive())
+ return canUnboxArgument(src, dst);
+ else
+ return true; // any two refs can be interconverted
+ }
+ }
+
+ /**
+ * Create a JVM-level adapter method handle to conform the given method
+ * handle to the similar newType, using only pairwise argument conversions.
+ * For each argument, convert incoming argument to the exact type needed.
+ * Only null conversions are allowed on the return value (until
+ * the JVM supports ricochet adapters).
+ * The argument conversions allowed are casting, unboxing,
+ * integral widening or narrowing, and floating point widening or narrowing.
+ * @param newType required call type
+ * @param target original method handle
+ * @return an adapter to the original handle with the desired new type,
+ * or the original target if the types are already identical
+ * or null if the adaptation cannot be made
+ */
+ static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target) {
+ MethodType oldType = target.type();
+ if (newType == oldType) return target;
+
+ if (!canPairwiseConvert(newType, oldType))
+ return null;
+ // (after this point, it is an assertion error to fail to convert)
+
+ // Find last non-trivial conversion (if any).
+ int lastConv = newType.parameterCount()-1;
+ while (lastConv >= 0) {
+ Class> src = newType.parameterType(lastConv); // source type
+ Class> dst = oldType.parameterType(lastConv); // destination type
+ if (VerifyType.isNullConversion(src, dst)) {
+ --lastConv;
+ } else {
+ break;
+ }
+ }
+ // Now build a chain of one or more adapters.
+ MethodHandle adapter = target;
+ MethodType midType = oldType.changeReturnType(newType.returnType());
+ for (int i = 0; i <= lastConv; i++) {
+ Class> src = newType.parameterType(i); // source type
+ Class> dst = midType.parameterType(i); // destination type
+ if (VerifyType.isNullConversion(src, dst)) {
+ // do nothing: difference is trivial
+ continue;
+ }
+ // Work the current type backward toward the desired caller type:
+ if (i != lastConv) {
+ midType = midType.changeParameterType(i, src);
+ } else {
+ // When doing the last (or only) real conversion,
+ // force all remaining null conversions to happen also.
+ assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
+ midType = newType;
+ }
+
+ // Tricky case analysis follows.
+ // It parallels canConvertArgument() above.
+ if (src.isPrimitive()) {
+ if (dst.isPrimitive()) {
+ adapter = makePrimCast(midType, adapter, i, dst);
+ } else {
+ adapter = makeBoxArgument(midType, adapter, i, dst);
+ }
+ } else {
+ if (dst.isPrimitive()) {
+ // Caller has boxed a primitive. Unbox it for the target.
+ // The box type must correspond exactly to the primitive type.
+ // This is simpler than the powerful set of widening
+ // conversions supported by reflect.Method.invoke.
+ // Those conversions require a big nest of if/then/else logic,
+ // which we prefer to make a user responsibility.
+ adapter = makeUnboxArgument(midType, adapter, i, dst);
+ } else {
+ // Simple reference conversion.
+ // Note: Do not check for a class hierarchy relation
+ // between src and dst. In all cases a 'null' argument
+ // will pass the cast conversion.
+ adapter = makeCheckCast(midType, adapter, i, dst);
+ }
+ }
+ assert(adapter != null);
+ assert(adapter.type() == midType);
+ }
+ if (adapter.type() != newType) {
+ // Only trivial conversions remain.
+ adapter = makeRetypeOnly(newType, adapter);
+ assert(adapter != null);
+ // Actually, that's because there were no non-trivial ones:
+ assert(lastConv == -1);
+ }
+ assert(adapter.type() == newType);
+ return adapter;
+ }
+
+ /**
+ * Create a JVM-level adapter method handle to permute the arguments
+ * of the given method.
+ * @param newType required call type
+ * @param target original method handle
+ * @param argumentMap for each target argument, position of its source in newType
+ * @return an adapter to the original handle with the desired new type,
+ * or the original target if the types are already identical
+ * and the permutation is null
+ * @throws IllegalArgumentException if the adaptation cannot be made
+ * directly by a JVM-level adapter, without help from Java code
+ */
+ static MethodHandle makePermutation(MethodType newType, MethodHandle target,
+ int[] argumentMap) {
+ MethodType oldType = target.type();
+ boolean nullPermutation = true;
+ for (int i = 0; i < argumentMap.length; i++) {
+ int pos = argumentMap[i];
+ if (pos != i)
+ nullPermutation = false;
+ if (pos < 0 || pos >= newType.parameterCount()) {
+ argumentMap = new int[0]; break;
+ }
+ }
+ if (argumentMap.length != oldType.parameterCount())
+ throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
+ if (nullPermutation) {
+ MethodHandle res = makePairwiseConvert(newType, target);
+ // well, that was easy
+ if (res == null)
+ throw newIllegalArgumentException("cannot convert pairwise: "+newType);
+ return res;
+ }
+
+ // Check return type. (Not much can be done with it.)
+ Class> exp = newType.returnType();
+ Class> ret = oldType.returnType();
+ if (!VerifyType.isNullConversion(ret, exp))
+ throw newIllegalArgumentException("bad return conversion for "+newType);
+
+ // See if the argument types match up.
+ for (int i = 0; i < argumentMap.length; i++) {
+ int j = argumentMap[i];
+ Class> src = newType.parameterType(j);
+ Class> dst = oldType.parameterType(i);
+ if (!VerifyType.isNullConversion(src, dst))
+ throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
+ }
+
+ // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
+ // A workable greedy algorithm is as follows:
+ // Drop unused outgoing arguments (right to left: shallowest first).
+ // Duplicate doubly-used outgoing arguments (left to right: deepest first).
+ // Then the remaining problem is a true argument permutation.
+ // Marshal the outgoing arguments as required from left to right.
+ // That is, find the deepest outgoing stack position that does not yet
+ // have the correct argument value, and correct at least that position
+ // by swapping or rotating in the misplaced value (from a shallower place).
+ // If the misplaced value is followed by one or more consecutive values
+ // (also misplaced) issue a rotation which brings as many as possible
+ // into position. Otherwise make progress with either a swap or a
+ // rotation. Prefer the swap as cheaper, but do not use it if it
+ // breaks a slot pair. Prefer the rotation over the swap if it would
+ // preserve more consecutive values shallower than the target position.
+ // When more than one rotation will work (because the required value
+ // is already adjacent to the target position), then use a rotation
+ // which moves the old value in the target position adjacent to
+ // one of its consecutive values. Also, prefer shorter rotation
+ // spans, since they use fewer memory cycles for shuffling.
+
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ private static byte basicType(Class> type) {
+ if (type == null) return T_VOID;
+ switch (Wrapper.forBasicType(type)) {
+ case BOOLEAN: return T_BOOLEAN;
+ case CHAR: return T_CHAR;
+ case FLOAT: return T_FLOAT;
+ case DOUBLE: return T_DOUBLE;
+ case BYTE: return T_BYTE;
+ case SHORT: return T_SHORT;
+ case INT: return T_INT;
+ case LONG: return T_LONG;
+ case OBJECT: return T_OBJECT;
+ case VOID: return T_VOID;
+ }
+ return 99; // T_ILLEGAL or some such
+ }
+
+ /** Number of stack slots for the given type.
+ * Two for T_DOUBLE and T_FLOAT, one for the rest.
+ */
+ private static int type2size(int type) {
+ assert(type >= T_BOOLEAN && type <= T_OBJECT);
+ return (type == T_LONG || type == T_DOUBLE) ? 2 : 1;
+ }
+ private static int type2size(Class> type) {
+ return type2size(basicType(type));
+ }
+
+ /** The given stackMove is the number of slots pushed.
+ * It might be negative. Scale it (multiply) by the
+ * VM's notion of how an address changes with a push,
+ * to get the raw SP change for stackMove.
+ * Then shift and mask it into the correct field.
+ */
+ private static long insertStackMove(int stackMove) {
+ // following variable must be long to avoid sign extension after '<<'
+ long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT;
+ return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT;
+ }
+
+ /** Construct an adapter conversion descriptor for a single-argument conversion. */
+ private static long makeConv(int convOp, int argnum, int src, int dest) {
+ assert(src == (src & 0xF));
+ assert(dest == (dest & 0xF));
+ assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF);
+ int stackMove = type2size(dest) - type2size(src);
+ return ((long) argnum << 32 |
+ (long) convOp << CONV_OP_SHIFT |
+ (int) src << CONV_SRC_TYPE_SHIFT |
+ (int) dest << CONV_DEST_TYPE_SHIFT |
+ insertStackMove(stackMove)
+ );
+ }
+ private static long makeConv(int convOp, int argnum, int stackMove) {
+ assert(convOp >= OP_DUP_ARGS && convOp <= OP_SPREAD_ARGS);
+ byte src = 0, dest = 0;
+ if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
+ src = dest = T_OBJECT;
+ return ((long) argnum << 32 |
+ (long) convOp << CONV_OP_SHIFT |
+ (int) src << CONV_SRC_TYPE_SHIFT |
+ (int) dest << CONV_DEST_TYPE_SHIFT |
+ insertStackMove(stackMove)
+ );
+ }
+ private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) {
+ assert(convOp >= OP_SWAP_ARGS && convOp <= OP_ROT_ARGS);
+ return ((long) srcArg << 32 |
+ (long) convOp << CONV_OP_SHIFT |
+ (int) type << CONV_SRC_TYPE_SHIFT |
+ (int) type << CONV_DEST_TYPE_SHIFT |
+ (int) destSlot << CONV_VMINFO_SHIFT
+ );
+ }
+ private static long makeConv(int convOp) {
+ assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW);
+ return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT); // stackMove, src, dst all zero
+ }
+ private static int convCode(long conv) {
+ return (int)conv;
+ }
+ private static int convArgPos(long conv) {
+ return (int)(conv >>> 32);
+ }
+ private static boolean convOpSupported(int convOp) {
+ assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
+ return ((1<> CONV_OP_SHIFT; }
+
+ /* Return one plus the position of the first non-trivial difference
+ * between the given types. This is not a symmetric operation;
+ * we are considering adapting the targetType to adapterType.
+ * Trivial differences are those which could be ignored by the JVM
+ * without subverting the verifier. Otherwise, adaptable differences
+ * are ones for which we could create an adapter to make the type change.
+ * Return zero if there are no differences (other than trivial ones).
+ * Return 1+N if N is the only adaptable argument difference.
+ * Return the -2-N where N is the first of several adaptable
+ * argument differences.
+ * Return -1 if there there are differences which are not adaptable.
+ */
+ private static int diffTypes(MethodType adapterType,
+ MethodType targetType,
+ boolean raw) {
+ int diff;
+ diff = diffReturnTypes(adapterType, targetType, raw);
+ if (diff != 0) return diff;
+ int nargs = adapterType.parameterCount();
+ if (nargs != targetType.parameterCount())
+ return -1;
+ diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
+ //System.out.println("diff "+adapterType);
+ //System.out.println(" "+diff+" "+targetType);
+ return diff;
+ }
+ private static int diffReturnTypes(MethodType adapterType,
+ MethodType targetType,
+ boolean raw) {
+ Class> src = targetType.returnType();
+ Class> dst = adapterType.returnType();
+ if ((!raw
+ ? VerifyType.canPassUnchecked(src, dst)
+ : VerifyType.canPassRaw(src, dst)
+ ) > 0)
+ return 0; // no significant difference
+ if (raw && !src.isPrimitive() && !dst.isPrimitive())
+ return 0; // can force a reference return (very carefully!)
+ //if (false) return 1; // never adaptable!
+ return -1; // some significant difference
+ }
+ private static int diffParamTypes(MethodType adapterType, int astart,
+ MethodType targetType, int tstart,
+ int nargs, boolean raw) {
+ assert(nargs >= 0);
+ int res = 0;
+ for (int i = 0; i < nargs; i++) {
+ Class> src = adapterType.parameterType(astart+i);
+ Class> dest = targetType.parameterType(tstart+i);
+ if ((!raw
+ ? VerifyType.canPassUnchecked(src, dest)
+ : VerifyType.canPassRaw(src, dest)
+ ) <= 0) {
+ // found a difference; is it the only one so far?
+ if (res != 0)
+ return -1-res; // return -2-i for prev. i
+ res = 1+i;
+ }
+ }
+ return res;
+ }
+
+ /** Can a retyping adapter (alone) validly convert the target to newType? */
+ static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
+ return canRetype(newType, targetType, false);
+ }
+ /** Can a retyping adapter (alone) convert the target to newType?
+ * It is allowed to widen subword types and void to int, to make bitwise
+ * conversions between float/int and double/long, and to perform unchecked
+ * reference conversions on return. This last feature requires that the
+ * caller be trusted, and perform explicit cast conversions on return values.
+ */
+ static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
+ return canRetype(newType, targetType, true);
+ }
+ static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
+ if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)) return false;
+ int diff = diffTypes(newType, targetType, raw);
+ // %%% This assert is too strong. Factor diff into VerifyType and reconcile.
+ assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType));
+ return diff == 0;
+ }
+
+ /** Factory method: Performs no conversions; simply retypes the adapter.
+ * Allows unchecked argument conversions pairwise, if they are safe.
+ * Returns null if not possible.
+ */
+ static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
+ return makeRetype(newType, target, false);
+ }
+ static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) {
+ return makeRetype(newType, target, true);
+ }
+ static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) {
+ MethodType oldType = target.type();
+ if (oldType == newType) return target;
+ if (!canRetype(newType, oldType, raw))
+ return null;
+ // TO DO: clone the target guy, whatever he is, with new type.
+ return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
+ }
+
+ static MethodHandle makeVarargsCollector(MethodHandle target, Class> arrayType) {
+ return new AsVarargsCollector(target, arrayType);
+ }
+
+ static class AsVarargsCollector extends AdapterMethodHandle {
+ final MethodHandle target;
+ final Class> arrayType;
+ MethodHandle cache;
+
+ AsVarargsCollector(MethodHandle target, Class> arrayType) {
+ super(target, target.type(), makeConv(OP_RETYPE_ONLY));
+ this.target = target;
+ this.arrayType = arrayType;
+ this.cache = target.asCollector(arrayType, 0);
+ }
+
+ @Override
+ public boolean isVarargsCollector() {
+ return true;
+ }
+
+ @Override
+ public MethodHandle asType(MethodType newType) {
+ MethodType type = this.type();
+ int collectArg = type.parameterCount() - 1;
+ int newArity = newType.parameterCount();
+ if (newArity == collectArg+1 &&
+ type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
+ // if arity and trailing parameter are compatible, do normal thing
+ return super.asType(newType);
+ }
+ // check cache
+ if (cache.type().parameterCount() == newArity)
+ return cache.asType(newType);
+ // build and cache a collector
+ int arrayLength = newArity - collectArg;
+ MethodHandle collector;
+ try {
+ collector = target.asCollector(arrayType, arrayLength);
+ } catch (IllegalArgumentException ex) {
+ throw new WrongMethodTypeException("cannot build collector");
+ }
+ cache = collector;
+ return collector.asType(newType);
+ }
+
+ @Override
+ public MethodHandle asVarargsCollector(Class> arrayType) {
+ MethodType type = this.type();
+ if (type.parameterType(type.parameterCount()-1) == arrayType)
+ return this;
+ return super.asVarargsCollector(arrayType);
+ }
+ }
+
+ /** Can a checkcast adapter validly convert the target to newType?
+ * The JVM supports all kind of reference casts, even silly ones.
+ */
+ static boolean canCheckCast(MethodType newType, MethodType targetType,
+ int arg, Class> castType) {
+ if (!convOpSupported(OP_CHECK_CAST)) return false;
+ Class> src = newType.parameterType(arg);
+ Class> dst = targetType.parameterType(arg);
+ if (!canCheckCast(src, castType)
+ || !VerifyType.isNullConversion(castType, dst))
+ return false;
+ int diff = diffTypes(newType, targetType, false);
+ return (diff == arg+1); // arg is sole non-trivial diff
+ }
+ /** Can an primitive conversion adapter validly convert src to dst? */
+ static boolean canCheckCast(Class> src, Class> dst) {
+ return (!src.isPrimitive() && !dst.isPrimitive());
+ }
+
+ /** Factory method: Forces a cast at the given argument.
+ * The castType is the target of the cast, and can be any type
+ * with a null conversion to the corresponding target parameter.
+ * Return null if this cannot be done.
+ */
+ static MethodHandle makeCheckCast(MethodType newType, MethodHandle target,
+ int arg, Class> castType) {
+ if (!canCheckCast(newType, target.type(), arg, castType))
+ return null;
+ long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
+ return new AdapterMethodHandle(target, newType, conv, castType);
+ }
+
+ /** Can an primitive conversion adapter validly convert the target to newType?
+ * The JVM currently supports all conversions except those between
+ * floating and integral types.
+ */
+ static boolean canPrimCast(MethodType newType, MethodType targetType,
+ int arg, Class> convType) {
+ if (!convOpSupported(OP_PRIM_TO_PRIM)) return false;
+ Class> src = newType.parameterType(arg);
+ Class> dst = targetType.parameterType(arg);
+ if (!canPrimCast(src, convType)
+ || !VerifyType.isNullConversion(convType, dst))
+ return false;
+ int diff = diffTypes(newType, targetType, false);
+ return (diff == arg+1); // arg is sole non-trivial diff
+ }
+ /** Can an primitive conversion adapter validly convert src to dst? */
+ static boolean canPrimCast(Class> src, Class> dst) {
+ if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
+ return false;
+ } else if (Wrapper.forPrimitiveType(dst).isFloating()) {
+ // both must be floating types
+ return Wrapper.forPrimitiveType(src).isFloating();
+ } else {
+ // both are integral, and all combinations work fine
+ assert(Wrapper.forPrimitiveType(src).isIntegral() &&
+ Wrapper.forPrimitiveType(dst).isIntegral());
+ return true;
+ }
+ }
+
+ /** Factory method: Truncate the given argument with zero or sign extension,
+ * and/or convert between single and doubleword versions of integer or float.
+ * The convType is the target of the conversion, and can be any type
+ * with a null conversion to the corresponding target parameter.
+ * Return null if this cannot be done.
+ */
+ static MethodHandle makePrimCast(MethodType newType, MethodHandle target,
+ int arg, Class> convType) {
+ MethodType oldType = target.type();
+ if (!canPrimCast(newType, oldType, arg, convType))
+ return null;
+ Class> src = newType.parameterType(arg);
+ long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
+ return new AdapterMethodHandle(target, newType, conv);
+ }
+
+ /** Can an unboxing conversion validly convert src to dst?
+ * The JVM currently supports all kinds of casting and unboxing.
+ * The convType is the unboxed type; it can be either a primitive or wrapper.
+ */
+ static boolean canUnboxArgument(MethodType newType, MethodType targetType,
+ int arg, Class> convType) {
+ if (!convOpSupported(OP_REF_TO_PRIM)) return false;
+ Class> src = newType.parameterType(arg);
+ Class> dst = targetType.parameterType(arg);
+ Class> boxType = Wrapper.asWrapperType(convType);
+ convType = Wrapper.asPrimitiveType(convType);
+ if (!canCheckCast(src, boxType)
+ || boxType == convType
+ || !VerifyType.isNullConversion(convType, dst))
+ return false;
+ int diff = diffTypes(newType, targetType, false);
+ return (diff == arg+1); // arg is sole non-trivial diff
+ }
+ /** Can an primitive unboxing adapter validly convert src to dst? */
+ static boolean canUnboxArgument(Class> src, Class> dst) {
+ return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
+ }
+
+ /** Factory method: Unbox the given argument.
+ * Return null if this cannot be done.
+ */
+ static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target,
+ int arg, Class> convType) {
+ MethodType oldType = target.type();
+ Class> src = newType.parameterType(arg);
+ Class> dst = oldType.parameterType(arg);
+ Class> boxType = Wrapper.asWrapperType(convType);
+ Class> primType = Wrapper.asPrimitiveType(convType);
+ if (!canUnboxArgument(newType, oldType, arg, convType))
+ return null;
+ MethodType castDone = newType;
+ if (!VerifyType.isNullConversion(src, boxType))
+ castDone = newType.changeParameterType(arg, boxType);
+ long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
+ MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
+ if (castDone == newType)
+ return adapter;
+ return makeCheckCast(newType, adapter, arg, boxType);
+ }
+
+ /** Can an primitive boxing adapter validly convert src to dst? */
+ static boolean canBoxArgument(Class> src, Class> dst) {
+ if (!convOpSupported(OP_PRIM_TO_REF)) return false;
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ /** Factory method: Unbox the given argument.
+ * Return null if this cannot be done.
+ */
+ static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target,
+ int arg, Class> convType) {
+ // this is difficult to do in the JVM because it must GC
+ return null;
+ }
+
+ /** Can an adapter simply drop arguments to convert the target to newType? */
+ static boolean canDropArguments(MethodType newType, MethodType targetType,
+ int dropArgPos, int dropArgCount) {
+ if (dropArgCount == 0)
+ return canRetypeOnly(newType, targetType);
+ if (!convOpSupported(OP_DROP_ARGS)) return false;
+ if (diffReturnTypes(newType, targetType, false) != 0)
+ return false;
+ int nptypes = newType.parameterCount();
+ // parameter types must be the same up to the drop point
+ if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
+ return false;
+ int afterPos = dropArgPos + dropArgCount;
+ int afterCount = nptypes - afterPos;
+ if (dropArgPos < 0 || dropArgPos >= nptypes ||
+ dropArgCount < 1 || afterPos > nptypes ||
+ targetType.parameterCount() != nptypes - dropArgCount)
+ return false;
+ // parameter types after the drop point must also be the same
+ if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
+ return false;
+ return true;
+ }
+
+ /** Factory method: Drop selected arguments.
+ * Allow unchecked retyping of remaining arguments, pairwise.
+ * Return null if this is not possible.
+ */
+ static MethodHandle makeDropArguments(MethodType newType, MethodHandle target,
+ int dropArgPos, int dropArgCount) {
+ if (dropArgCount == 0)
+ return makeRetypeOnly(newType, target);
+ if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
+ return null;
+ // in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
+ // out arglist: [0: ...keep1 | dpos: keep2... ]
+ int keep2InPos = dropArgPos + dropArgCount;
+ int dropSlot = newType.parameterSlotDepth(keep2InPos);
+ int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
+ int slotCount = keep1InSlot - dropSlot;
+ assert(slotCount >= dropArgCount);
+ assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
+ long conv = makeConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
+ return new AdapterMethodHandle(target, newType, conv);
+ }
+
+ /** Can an adapter duplicate an argument to convert the target to newType? */
+ static boolean canDupArguments(MethodType newType, MethodType targetType,
+ int dupArgPos, int dupArgCount) {
+ if (!convOpSupported(OP_DUP_ARGS)) return false;
+ if (diffReturnTypes(newType, targetType, false) != 0)
+ return false;
+ int nptypes = newType.parameterCount();
+ if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
+ return false;
+ if (targetType.parameterCount() != nptypes + dupArgCount)
+ return false;
+ // parameter types must be the same up to the duplicated arguments
+ if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
+ return false;
+ // duplicated types must be, well, duplicates
+ if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
+ return false;
+ return true;
+ }
+
+ /** Factory method: Duplicate the selected argument.
+ * Return null if this is not possible.
+ */
+ static MethodHandle makeDupArguments(MethodType newType, MethodHandle target,
+ int dupArgPos, int dupArgCount) {
+ if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
+ return null;
+ if (dupArgCount == 0)
+ return target;
+ // in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
+ // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
+ int keep2InPos = dupArgPos + dupArgCount;
+ int dupSlot = newType.parameterSlotDepth(keep2InPos);
+ int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
+ int slotCount = keep1InSlot - dupSlot;
+ assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
+ long conv = makeConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
+ return new AdapterMethodHandle(target, newType, conv);
+ }
+
+ /** Can an adapter swap two arguments to convert the target to newType? */
+ static boolean canSwapArguments(MethodType newType, MethodType targetType,
+ int swapArg1, int swapArg2) {
+ if (!convOpSupported(OP_SWAP_ARGS)) return false;
+ if (diffReturnTypes(newType, targetType, false) != 0)
+ return false;
+ if (swapArg1 >= swapArg2) return false; // caller resp
+ int nptypes = newType.parameterCount();
+ if (targetType.parameterCount() != nptypes)
+ return false;
+ if (swapArg1 < 0 || swapArg2 >= nptypes)
+ return false;
+ if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
+ return false;
+ if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
+ return false;
+ if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
+ return false;
+ if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
+ return false;
+ if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
+ return false;
+ return true;
+ }
+
+ /** Factory method: Swap the selected arguments.
+ * Return null if this is not possible.
+ */
+ static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
+ int swapArg1, int swapArg2) {
+ if (swapArg1 == swapArg2)
+ return target;
+ if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
+ if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
+ return null;
+ Class> swapType = newType.parameterType(swapArg1);
+ // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
+ // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
+ int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1);
+ long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2);
+ return new AdapterMethodHandle(target, newType, conv);
+ }
+
+ static int positiveRotation(int argCount, int rotateBy) {
+ assert(argCount > 0);
+ if (rotateBy >= 0) {
+ if (rotateBy < argCount)
+ return rotateBy;
+ return rotateBy % argCount;
+ } else if (rotateBy >= -argCount) {
+ return rotateBy + argCount;
+ } else {
+ return (-1-((-1-rotateBy) % argCount)) + argCount;
+ }
+ }
+
+ final static int MAX_ARG_ROTATION = 1;
+
+ /** Can an adapter rotate arguments to convert the target to newType? */
+ static boolean canRotateArguments(MethodType newType, MethodType targetType,
+ int firstArg, int argCount, int rotateBy) {
+ if (!convOpSupported(OP_ROT_ARGS)) return false;
+ if (argCount <= 2) return false; // must be a swap, not a rotate
+ rotateBy = positiveRotation(argCount, rotateBy);
+ if (rotateBy == 0) return false; // no rotation
+ if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
+ return false; // too many argument positions
+ // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
+ if (diffReturnTypes(newType, targetType, false) != 0)
+ return false;
+ int nptypes = newType.parameterCount();
+ if (targetType.parameterCount() != nptypes)
+ return false;
+ if (firstArg < 0 || firstArg >= nptypes) return false;
+ int argLimit = firstArg + argCount;
+ if (argLimit > nptypes) return false;
+ if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0)
+ return false;
+ int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy;
+ // swap new chunk1 with target chunk2
+ if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0)
+ return false;
+ // swap new chunk2 with target chunk1
+ if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0)
+ return false;
+ return true;
+ }
+
+ /** Factory method: Rotate the selected argument range.
+ * Return null if this is not possible.
+ */
+ static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target,
+ int firstArg, int argCount, int rotateBy) {
+ rotateBy = positiveRotation(argCount, rotateBy);
+ if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
+ return null;
+ // Decide whether it should be done as a right or left rotation,
+ // on the JVM stack. Return the number of stack slots to rotate by,
+ // positive if right, negative if left.
+ int limit = firstArg + argCount;
+ int depth0 = newType.parameterSlotDepth(firstArg);
+ int depth1 = newType.parameterSlotDepth(limit-rotateBy);
+ int depth2 = newType.parameterSlotDepth(limit);
+ int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
+ int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
+ // From here on out, it assumes a single-argument shift.
+ assert(MAX_ARG_ROTATION == 1);
+ int srcArg, dstArg;
+ byte basicType;
+ if (chunk2Slots <= chunk1Slots) {
+ // Rotate right/down N (rotateBy = +N, N small, c2 small):
+ // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ]
+ // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
+ srcArg = limit-1;
+ dstArg = firstArg;
+ basicType = basicType(newType.parameterType(srcArg));
+ assert(chunk2Slots == type2size(basicType));
+ } else {
+ // Rotate left/up N (rotateBy = -N, N small, c1 small):
+ // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ]
+ // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
+ srcArg = firstArg;
+ dstArg = limit-1;
+ basicType = basicType(newType.parameterType(srcArg));
+ assert(chunk1Slots == type2size(basicType));
+ }
+ int dstSlot = newType.parameterSlotDepth(dstArg + 1);
+ long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
+ return new AdapterMethodHandle(target, newType, conv);
+ }
+
+ /** Can an adapter spread an argument to convert the target to newType? */
+ static boolean canSpreadArguments(MethodType newType, MethodType targetType,
+ Class> spreadArgType, int spreadArgPos, int spreadArgCount) {
+ if (!convOpSupported(OP_SPREAD_ARGS)) return false;
+ if (diffReturnTypes(newType, targetType, false) != 0)
+ return false;
+ int nptypes = newType.parameterCount();
+ // parameter types must be the same up to the spread point
+ if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
+ return false;
+ int afterPos = spreadArgPos + spreadArgCount;
+ int afterCount = nptypes - (spreadArgPos + 1);
+ if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
+ spreadArgCount < 0 ||
+ targetType.parameterCount() != afterPos + afterCount)
+ return false;
+ // parameter types after the spread point must also be the same
+ if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
+ return false;
+ // match the array element type to the spread arg types
+ Class> rawSpreadArgType = newType.parameterType(spreadArgPos);
+ if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
+ return false;
+ for (int i = 0; i < spreadArgCount; i++) {
+ Class> src = VerifyType.spreadArgElementType(spreadArgType, i);
+ Class> dst = targetType.parameterType(spreadArgPos + i);
+ if (src == null || !VerifyType.isNullConversion(src, dst))
+ return false;
+ }
+ return true;
+ }
+
+
+ /** Factory method: Spread selected argument. */
+ static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target,
+ Class> spreadArgType, int spreadArgPos, int spreadArgCount) {
+ MethodType targetType = target.type();
+ if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
+ return null;
+ // in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ]
+ // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
+ int keep2OutPos = spreadArgPos + spreadArgCount;
+ int spreadSlot = targetType.parameterSlotDepth(keep2OutPos);
+ int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos);
+ int slotCount = keep1OutSlot - spreadSlot;
+ assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+1));
+ assert(slotCount >= spreadArgCount);
+ long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, slotCount-1);
+ MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType);
+ assert(res.type().parameterType(spreadArgPos) == spreadArgType);
+ return res;
+ }
+
+ // TO DO: makeCollectArguments, makeFlyby, makeRicochet
+
+ @Override
+ public String toString() {
+ return getNameString(nonAdapter((MethodHandle)vmtarget), this);
+ }
+
+ private static MethodHandle nonAdapter(MethodHandle mh) {
+ while (mh instanceof AdapterMethodHandle) {
+ mh = (MethodHandle) mh.vmtarget;
+ }
+ return mh;
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/BoundMethodHandle.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,188 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.util.VerifyType;
+import sun.invoke.util.Wrapper;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * The flavor of method handle which emulates an invoke instruction
+ * on a predetermined argument. The JVM dispatches to the correct method
+ * when the handle is created, not when it is invoked.
+ * @author jrose
+ */
+class BoundMethodHandle extends MethodHandle {
+ //MethodHandle vmtarget; // next BMH or final DMH or methodOop
+ private final Object argument; // argument to insert
+ private final int vmargslot; // position at which it is inserted
+
+ // Constructors in this class *must* be package scoped or private.
+
+ /** Bind a direct MH to its receiver (or first ref. argument).
+ * The JVM will pre-dispatch the MH if it is not already static.
+ */
+ /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
+ super(mh.type().dropParameterTypes(0, 1));
+ // check the type now, once for all:
+ this.argument = checkReferenceArgument(argument, mh, 0);
+ this.vmargslot = this.type().parameterSlotCount();
+ initTarget(mh, 0);
+ }
+
+ /** Insert an argument into an arbitrary method handle.
+ * If argnum is zero, inserts the first argument, etc.
+ * The argument type must be a reference.
+ */
+ /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
+ this(mh.type().dropParameterTypes(argnum, argnum+1),
+ mh, argument, argnum);
+ }
+
+ /** Insert an argument into an arbitrary method handle.
+ * If argnum is zero, inserts the first argument, etc.
+ */
+ /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
+ super(type);
+ if (mh.type().parameterType(argnum).isPrimitive())
+ this.argument = bindPrimitiveArgument(argument, mh, argnum);
+ else {
+ this.argument = checkReferenceArgument(argument, mh, argnum);
+ }
+ this.vmargslot = type.parameterSlotDepth(argnum);
+ initTarget(mh, argnum);
+ }
+
+ private void initTarget(MethodHandle mh, int argnum) {
+ //this.vmtarget = mh; // maybe updated by JVM
+ MethodHandleNatives.init(this, mh, argnum);
+ }
+
+ /** For the AdapterMethodHandle subclass.
+ */
+ /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
+ super(type);
+ this.argument = argument;
+ this.vmargslot = vmargslot;
+ assert(this instanceof AdapterMethodHandle);
+ }
+
+ /** Initialize the current object as a self-bound method handle, binding it
+ * as the first argument of the method handle {@code entryPoint}.
+ * The invocation type of the resulting method handle will be the
+ * same as {@code entryPoint}, except that the first argument
+ * type will be dropped.
+ */
+ /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) {
+ super(entryPoint.type().dropParameterTypes(0, 1));
+ this.argument = this; // kludge; get rid of
+ this.vmargslot = this.type().parameterSlotDepth(0);
+ initTarget(entryPoint, 0);
+ }
+
+ /** Make sure the given {@code argument} can be used as {@code argnum}-th
+ * parameter of the given method handle {@code mh}, which must be a reference.
+ *
+ * If this fails, throw a suitable {@code WrongMethodTypeException},
+ * which will prevent the creation of an illegally typed bound
+ * method handle.
+ */
+ final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
+ Class> ptype = mh.type().parameterType(argnum);
+ if (ptype.isPrimitive()) {
+ // fail
+ } else if (argument == null) {
+ return null;
+ } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
+ return argument;
+ }
+ throw badBoundArgumentException(argument, mh, argnum);
+ }
+
+ /** Make sure the given {@code argument} can be used as {@code argnum}-th
+ * parameter of the given method handle {@code mh}, which must be a primitive.
+ *
+ * If this fails, throw a suitable {@code WrongMethodTypeException},
+ * which will prevent the creation of an illegally typed bound
+ * method handle.
+ */
+ final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
+ Class> ptype = mh.type().parameterType(argnum);
+ Wrapper wrap = Wrapper.forPrimitiveType(ptype);
+ Object zero = wrap.zero();
+ if (zero == null) {
+ // fail
+ } else if (argument == null) {
+ if (ptype != int.class && wrap.isSubwordOrInt())
+ return Integer.valueOf(0);
+ else
+ return zero;
+ } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
+ if (ptype != int.class && wrap.isSubwordOrInt())
+ return Wrapper.INT.wrap(argument);
+ else
+ return argument;
+ }
+ throw badBoundArgumentException(argument, mh, argnum);
+ }
+
+ final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
+ String atype = (argument == null) ? "null" : argument.getClass().toString();
+ return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
+ }
+
+ @Override
+ public String toString() {
+ return addTypeString(baseName(), this);
+ }
+
+ /** Component of toString() before the type string. */
+ protected String baseName() {
+ MethodHandle mh = this;
+ while (mh instanceof BoundMethodHandle) {
+ Object info = MethodHandleNatives.getTargetInfo(mh);
+ if (info instanceof MethodHandle) {
+ mh = (MethodHandle) info;
+ } else {
+ String name = null;
+ if (info instanceof MemberName)
+ name = ((MemberName)info).getName();
+ if (name != null)
+ return name;
+ else
+ return noParens(super.toString()); // "invoke", probably
+ }
+ assert(mh != this);
+ }
+ return noParens(mh.toString());
+ }
+
+ private static String noParens(String str) {
+ int paren = str.indexOf('(');
+ if (paren >= 0) str = str.substring(0, paren);
+ return str;
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/CallSite.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/CallSite.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,323 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.empty.Empty;
+import sun.misc.Unsafe;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
+ * all calls to the site's current target.
+ * A {@code CallSite} may be associated with several {@code invokedynamic}
+ * instructions, or it may be "free floating", associated with none.
+ * In any case, it may be invoked through an associated method handle
+ * called its {@linkplain #dynamicInvoker dynamic invoker}.
+ *
+ * {@code CallSite} is an abstract class which does not allow
+ * direct subclassing by users. It has three immediate,
+ * concrete subclasses that may be either instantiated or subclassed.
+ *
+ *
If a mutable target is not required, an {@code invokedynamic} instruction
+ * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
+ *
If a mutable target is required which has volatile variable semantics,
+ * because updates to the target must be immediately and reliably witnessed by other threads,
+ * a {@linkplain VolatileCallSite volatile call site} may be used.
+ *
Otherwise, if a mutable target is required,
+ * a {@linkplain MutableCallSite mutable call site} may be used.
+ *
+ *
+ * A non-constant call site may be relinked by changing its target.
+ * The new target must have the same {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
+ *
+ * Here is a sample use of call sites and bootstrap methods which links every
+ * dynamic call site to print its arguments:
+
+static void test() throws Throwable {
+ // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
+ InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
+}
+private static void printArgs(Object... args) {
+ System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class thisClass = lookup.lookupClass(); // (who am I?)
+ printArgs = lookup.findStatic(thisClass,
+ "printArgs", MethodType.methodType(void.class, Object[].class));
+}
+private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
+ // ignore caller and name, but match the type:
+ return new ConstantCallSite(printArgs.asType(type));
+}
+
+ * @author John Rose, JSR 292 EG
+ */
+abstract
+public class CallSite {
+ 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)
+ private int vmindex; // supplied by the JVM (BCI within calling method)
+
+ // The actual payload of this call site:
+ /*package-private*/
+ MethodHandle target;
+
+ /**
+ * 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.
+ *
+ * Before this {@code CallSite} object is returned from a bootstrap method,
+ * it is usually provided with a more useful target method,
+ * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+ * @throws NullPointerException if the proposed type is null
+ */
+ /*package-private*/
+ CallSite(MethodType type) {
+ target = type.invokers().uninitializedCallSite();
+ }
+
+ /**
+ * 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
+ * @throws NullPointerException if the proposed target is null
+ */
+ /*package-private*/
+ CallSite(MethodHandle target) {
+ target.type(); // null check
+ this.target = target;
+ }
+
+ /**
+ * 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
+ */
+ public MethodType type() {
+ return target.type();
+ }
+
+ /** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
+ * The parameters are JVM-specific.
+ */
+ void initializeFromJVM(String name,
+ MethodType type,
+ MemberName callerMethod,
+ int callerBCI) {
+ if (this.vmmethod != null) {
+ // FIXME
+ throw new BootstrapMethodError("call site has already been linked to an invokedynamic instruction");
+ }
+ if (!this.type().equals(type)) {
+ throw wrongTargetType(target, type);
+ }
+ this.vmindex = callerBCI;
+ this.vmmethod = callerMethod;
+ }
+
+ /**
+ * 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 abstract MethodHandle getTarget();
+
+ /**
+ * 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.
+ *
+ * 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
+ * @see CallSite#getTarget
+ * @see ConstantCallSite#setTarget
+ * @see MutableCallSite#setTarget
+ * @see VolatileCallSite#setTarget
+ */
+ public abstract void setTarget(MethodHandle newTarget);
+
+ void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
+ MethodType oldType = oldTarget.type();
+ MethodType newType = newTarget.type(); // null check!
+ if (!newType.equals(oldType))
+ throw wrongTargetType(newTarget, oldType);
+ }
+
+ private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
+ return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
+ }
+
+ /**
+ * Produces a method handle equivalent to an invokedynamic instruction
+ * which has been linked to this call site.
+ *
+ * This method is equivalent to the following code:
+ *
+ * A call is "generic" (in MethodHandle terms) if its MethodType features
+ * only Object arguments. A non-generic call therefore features
+ * primitives and/or reference types other than Object.
+ * An adapter has types for its incoming and outgoing calls.
+ * The incoming call type is simply determined by the adapter's type
+ * (the MethodType it presents to callers). The outgoing call type
+ * is determined by the adapter's target (a MethodHandle that the adapter
+ * either binds internally or else takes as a leading argument).
+ * (To stretch the term, adapter-like method handles may have multiple
+ * targets or be polymorphic across multiple call types.)
+ * @author jrose
+ */
+class FromGeneric {
+ // type for the outgoing call (may have primitives, etc.)
+ private final MethodType targetType;
+ // type of the outgoing call internal to the adapter
+ private final MethodType internalType;
+ // prototype adapter (clone and customize for each new target!)
+ private final Adapter adapter;
+ // entry point for adapter (Adapter mh, a...) => ...
+ private final MethodHandle entryPoint;
+ // unboxing invoker of type (MH, Object**N) => raw return value
+ // it makes up the difference of internalType => targetType
+ private final MethodHandle unboxingInvoker;
+ // conversion which boxes a the target's raw return value
+ private final MethodHandle returnConversion;
+
+ /** Compute and cache information common to all unboxing adapters
+ * that can call out to targets of the erasure-family of the given erased type.
+ */
+ private FromGeneric(MethodType targetType) {
+ this.targetType = targetType;
+ MethodType internalType0;
+ // the target invoker will generally need casts on reference arguments
+ Adapter ad = findAdapter(internalType0 = targetType.erase());
+ if (ad != null) {
+ // Immediate hit to exactly the adapter we want,
+ // with no monkeying around with primitive types.
+ this.internalType = internalType0;
+ this.adapter = ad;
+ this.entryPoint = ad.prototypeEntryPoint();
+ this.returnConversion = computeReturnConversion(targetType, internalType0);
+ this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
+ return;
+ }
+
+ // outgoing primitive arguments will be wrapped; unwrap them
+ MethodType primsAsObj = targetType.form().primArgsAsBoxes();
+ MethodType objArgsRawRet = primsAsObj.form().primsAsInts();
+ if (objArgsRawRet != targetType)
+ ad = findAdapter(internalType0 = objArgsRawRet);
+ if (ad == null) {
+ ad = buildAdapterFromBytecodes(internalType0 = targetType);
+ }
+ this.internalType = internalType0;
+ this.adapter = ad;
+ MethodType tepType = targetType.insertParameterTypes(0, adapter.getClass());
+ this.entryPoint = ad.prototypeEntryPoint();
+ this.returnConversion = computeReturnConversion(targetType, internalType0);
+ this.unboxingInvoker = computeUnboxingInvoker(targetType, internalType0);
+ }
+
+ /**
+ * The typed target will be called according to targetType.
+ * The adapter code will in fact see the raw result from internalType,
+ * and must box it into an object. Produce a converter for this.
+ */
+ private static MethodHandle computeReturnConversion(
+ MethodType targetType, MethodType internalType) {
+ Class> tret = targetType.returnType();
+ Class> iret = internalType.returnType();
+ Wrapper wrap = Wrapper.forBasicType(tret);
+ if (!iret.isPrimitive()) {
+ assert(iret == Object.class);
+ return ValueConversions.identity();
+ } else if (wrap.primitiveType() == iret) {
+ return ValueConversions.box(wrap, false);
+ } else {
+ assert(tret == double.class ? iret == long.class : iret == int.class);
+ return ValueConversions.boxRaw(wrap, false);
+ }
+ }
+
+ /**
+ * The typed target will need an exact invocation point; provide it here.
+ * The adapter will possibly need to make a slightly different call,
+ * so adapt the invoker. This way, the logic for making up the
+ * difference between what the adapter can call and what the target
+ * needs can be cached once per type.
+ */
+ private static MethodHandle computeUnboxingInvoker(
+ MethodType targetType, MethodType internalType) {
+ // All the adapters we have here have reference-untyped internal calls.
+ assert(internalType == internalType.erase());
+ MethodHandle invoker = targetType.invokers().exactInvoker();
+ // cast all narrow reference types, unbox all primitive arguments:
+ MethodType fixArgsType = internalType.changeReturnType(targetType.returnType());
+ MethodHandle fixArgs = MethodHandleImpl.convertArguments(
+ invoker, Invokers.invokerType(fixArgsType),
+ invoker.type(), null);
+ if (fixArgs == null)
+ throw new InternalError("bad fixArgs");
+ // reinterpret the calling sequence as raw:
+ MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(
+ Invokers.invokerType(internalType), fixArgs);
+ if (retyper == null)
+ throw new InternalError("bad retyper");
+ return retyper;
+ }
+
+ Adapter makeInstance(MethodHandle typedTarget) {
+ MethodType type = typedTarget.type();
+ if (type == targetType) {
+ return adapter.makeInstance(entryPoint, unboxingInvoker, returnConversion, typedTarget);
+ }
+ // my erased-type is not exactly the same as the desired type
+ assert(type.erase() == targetType); // else we are busted
+ MethodHandle invoker = computeUnboxingInvoker(type, internalType);
+ return adapter.makeInstance(entryPoint, invoker, returnConversion, typedTarget);
+ }
+
+ /** Build an adapter of the given generic type, which invokes typedTarget
+ * on the incoming arguments, after unboxing as necessary.
+ * The return value is boxed if necessary.
+ * @param genericType the required type of the result
+ * @param typedTarget the target
+ * @return an adapter method handle
+ */
+ public static MethodHandle make(MethodHandle typedTarget) {
+ MethodType type = typedTarget.type();
+ if (type == type.generic()) return typedTarget;
+ return FromGeneric.of(type).makeInstance(typedTarget);
+ }
+
+ /** Return the adapter information for this type's erasure. */
+ static FromGeneric of(MethodType type) {
+ MethodTypeForm form = type.form();
+ FromGeneric fromGen = form.fromGeneric;
+ if (fromGen == null)
+ form.fromGeneric = fromGen = new FromGeneric(form.erasedType());
+ return fromGen;
+ }
+
+ public String toString() {
+ return "FromGeneric"+targetType;
+ }
+
+ /* Create an adapter that handles spreading calls for the given type. */
+ static Adapter findAdapter(MethodType internalType) {
+ MethodType entryType = internalType.generic();
+ MethodTypeForm form = internalType.form();
+ Class> rtype = internalType.returnType();
+ int argc = form.parameterCount();
+ int lac = form.longPrimitiveParameterCount();
+ int iac = form.primitiveParameterCount() - lac;
+ String intsAndLongs = (iac > 0 ? "I"+iac : "")+(lac > 0 ? "J"+lac : "");
+ String rawReturn = String.valueOf(Wrapper.forPrimitiveType(rtype).basicTypeChar());
+ String cname0 = rawReturn + argc;
+ String cname1 = "A" + argc;
+ String[] cnames = { cname0+intsAndLongs, cname0, cname1+intsAndLongs, cname1 };
+ String iname = "invoke_"+cname0+intsAndLongs;
+ // e.g., D5I2, D5, L5I2, L5; invoke_D5
+ for (String cname : cnames) {
+ Class extends Adapter> acls = Adapter.findSubClass(cname);
+ if (acls == null) continue;
+ // see if it has the required invoke method
+ MethodHandle entryPoint = null;
+ try {
+ entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+ } catch (ReflectiveOperationException ex) {
+ }
+ if (entryPoint == null) continue;
+ Constructor extends Adapter> ctor = null;
+ try {
+ ctor = acls.getDeclaredConstructor(MethodHandle.class);
+ } catch (NoSuchMethodException ex) {
+ } catch (SecurityException ex) {
+ }
+ if (ctor == null) continue;
+ try {
+ // Produce an instance configured as a prototype.
+ return ctor.newInstance(entryPoint);
+ } catch (IllegalArgumentException ex) {
+ } catch (InvocationTargetException wex) {
+ Throwable ex = wex.getTargetException();
+ if (ex instanceof Error) throw (Error)ex;
+ if (ex instanceof RuntimeException) throw (RuntimeException)ex;
+ } catch (InstantiationException ex) {
+ } catch (IllegalAccessException ex) {
+ }
+ }
+ return null;
+ }
+
+ static Adapter buildAdapterFromBytecodes(MethodType internalType) {
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ /**
+ * This adapter takes some untyped arguments, and returns an untyped result.
+ * Internally, it applies the invoker to the target, which causes the
+ * objects to be unboxed; the result is a raw type in L/I/J/F/D.
+ * This result is passed to convert, which is responsible for
+ * converting the raw result into a boxed object.
+ * The invoker is kept separate from the target because it can be
+ * generated once per type erasure family, and reused across adapters.
+ */
+ static abstract class Adapter extends BoundMethodHandle {
+ /*
+ * class X<> extends Adapter {
+ * (MH, Object**N)=>raw(R) invoker;
+ * (any**N)=>R target;
+ * raw(R)=>Object convert;
+ * Object invoke(Object**N a) = convert(invoker(target, a...))
+ * }
+ */
+ protected final MethodHandle invoker; // (MH, Object**N) => raw(R)
+ protected final MethodHandle convert; // raw(R) => Object
+ protected final MethodHandle target; // (any**N) => R
+
+ @Override
+ public String toString() {
+ return addTypeString(target, this);
+ }
+
+ protected boolean isPrototype() { return target == null; }
+ protected Adapter(MethodHandle entryPoint) {
+ this(entryPoint, null, entryPoint, null);
+ assert(isPrototype());
+ }
+ protected MethodHandle prototypeEntryPoint() {
+ if (!isPrototype()) throw new InternalError();
+ return convert;
+ }
+
+ protected Adapter(MethodHandle entryPoint,
+ MethodHandle invoker, MethodHandle convert, MethodHandle target) {
+ super(entryPoint);
+ this.invoker = invoker;
+ this.convert = convert;
+ this.target = target;
+ }
+
+ /** Make a copy of self, with new fields. */
+ protected abstract Adapter makeInstance(MethodHandle entryPoint,
+ MethodHandle invoker, MethodHandle convert, MethodHandle target);
+ // { return new ThisType(entryPoint, convert, target); }
+
+ /// Conversions on the value returned from the target.
+ protected Object convert_L(Object result) throws Throwable { return convert.invokeExact(result); }
+ protected Object convert_I(int result) throws Throwable { return convert.invokeExact(result); }
+ protected Object convert_J(long result) throws Throwable { return convert.invokeExact(result); }
+ protected Object convert_F(float result) throws Throwable { return convert.invokeExact(result); }
+ protected Object convert_D(double result) throws Throwable { return convert.invokeExact(result); }
+
+ static private final String CLASS_PREFIX; // "java.lang.invoke.FromGeneric$"
+ static {
+ String aname = Adapter.class.getName();
+ String sname = Adapter.class.getSimpleName();
+ if (!aname.endsWith(sname)) throw new InternalError();
+ CLASS_PREFIX = aname.substring(0, aname.length() - sname.length());
+ }
+ /** Find a sibing class of Adapter. */
+ static Class extends Adapter> findSubClass(String name) {
+ String cname = Adapter.CLASS_PREFIX + name;
+ try {
+ return Class.forName(cname).asSubclass(Adapter.class);
+ } catch (ClassNotFoundException ex) {
+ return null;
+ } catch (ClassCastException ex) {
+ return null;
+ }
+ }
+ }
+
+ /* generated classes follow this pattern:
+ static class xA2 extends Adapter {
+ protected xA2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected xA2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new xA2(e, i, c, t); }
+ protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
+ }
+ // */
+
+/*
+: SHELL; n=FromGeneric; cp -p $n.java $n.java-; sed < $n.java- > $n.java+ -e '/{{*{{/,/}}*}}/w /tmp/genclasses.java' -e '/}}*}}/q'; (cd /tmp; javac -d . genclasses.java; java -cp . genclasses) >> $n.java+; echo '}' >> $n.java+; mv $n.java+ $n.java; mv $n.java- $n.java~
+//{{{
+import java.util.*;
+class genclasses {
+ static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
+ static String[] WRAPS = { " ", "(Integer)", "(Long) ", "(Float) ", "(Double) " };
+ static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
+ static String[][] TEMPLATES = { {
+ "@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0",
+ " //@each-cat@",
+ " static class @cat@ extends Adapter {",
+ " protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
+ " protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
+ " { super(e, i, c, t); }",
+ " protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
+ " { return new @cat@(e, i, c, t); }",
+ " //@each-R@",
+ " protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@((@R@)@W@invoker.invokeExact(target@av@)); }",
+ " //@end-R@",
+ " }",
+ } };
+ static final String NEWLINE_INDENT = "\n ";
+ enum VAR {
+ cat, catN, R, Rc, W, av, Tvav, Ovav;
+ public final String pattern = "@"+toString().replace('_','.')+"@";
+ public String binding;
+ static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
+ int nargs = nrefs + nints + nlongs;
+ if (topLevel)
+ VAR.cat.binding = catstr(ALL_RETURN_TYPES ? TYPES.length : rcat, nrefs, nints, nlongs);
+ VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
+ VAR.R.binding = TYPES[rcat];
+ VAR.Rc.binding = TCHARS[rcat];
+ VAR.W.binding = WRAPS[rcat];
+ String[] Tv = new String[nargs];
+ String[] av = new String[nargs];
+ String[] Tvav = new String[nargs];
+ String[] Ovav = new String[nargs];
+ for (int i = 0; i < nargs; i++) {
+ int tcat = (i < nrefs) ? 0 : (i < nrefs + nints) ? 1 : 2;
+ Tv[i] = TYPES[tcat];
+ av[i] = arg(i);
+ Tvav[i] = param(Tv[i], av[i]);
+ Ovav[i] = param("Object", av[i]);
+ }
+ VAR.av.binding = comma(", ", av);
+ VAR.Tvav.binding = comma(Tvav);
+ VAR.Ovav.binding = comma(Ovav);
+ }
+ static String arg(int i) { return "a"+i; }
+ static String param(String t, String a) { return t+" "+a; }
+ static String comma(String[] v) { return comma("", v); }
+ static String comma(String sep, String[] v) {
+ if (v.length == 0) return "";
+ String res = sep+v[0];
+ for (int i = 1; i < v.length; i++) res += ", "+v[i];
+ return res;
+ }
+ static String transform(String string) {
+ for (VAR var : values())
+ string = string.replaceAll(var.pattern, var.binding);
+ return string;
+ }
+ }
+ static String[] stringsIn(String[] strings, int beg, int end) {
+ return Arrays.copyOfRange(strings, beg, Math.min(end, strings.length));
+ }
+ static String[] stringsBefore(String[] strings, int pos) {
+ return stringsIn(strings, 0, pos);
+ }
+ static String[] stringsAfter(String[] strings, int pos) {
+ return stringsIn(strings, pos, strings.length);
+ }
+ static int indexAfter(String[] strings, int pos, String tag) {
+ return Math.min(indexBefore(strings, pos, tag) + 1, strings.length);
+ }
+ static int indexBefore(String[] strings, int pos, String tag) {
+ for (int i = pos, end = strings.length; ; i++) {
+ if (i == end || strings[i].endsWith(tag)) return i;
+ }
+ }
+ static int MIN_ARITY, MAX_ARITY, MAX_RCAT, MAX_REFS, MAX_INTS, MAX_LONGS;
+ static boolean ALL_ARG_TYPES, ALL_RETURN_TYPES;
+ static HashSet done = new HashSet();
+ public static void main(String... av) {
+ for (String[] template : TEMPLATES) {
+ int forLinesLimit = indexBefore(template, 0, "@each-cat@");
+ String[] forLines = stringsBefore(template, forLinesLimit);
+ template = stringsAfter(template, forLinesLimit);
+ for (String forLine : forLines)
+ expandTemplate(forLine, template);
+ }
+ }
+ static void expandTemplate(String forLine, String[] template) {
+ String[] params = forLine.split("[^0-9]+");
+ if (params[0].length() == 0) params = stringsAfter(params, 1);
+ System.out.println("//params="+Arrays.asList(params));
+ int pcur = 0;
+ MIN_ARITY = Integer.valueOf(params[pcur++]);
+ MAX_ARITY = Integer.valueOf(params[pcur++]);
+ MAX_RCAT = Integer.valueOf(params[pcur++]);
+ MAX_REFS = Integer.valueOf(params[pcur++]);
+ MAX_INTS = Integer.valueOf(params[pcur++]);
+ MAX_LONGS = Integer.valueOf(params[pcur++]);
+ if (pcur != params.length) throw new RuntimeException("bad extra param: "+forLine);
+ if (MAX_RCAT >= TYPES.length) MAX_RCAT = TYPES.length - 1;
+ ALL_ARG_TYPES = (indexBefore(template, 0, "@each-Tv@") < template.length);
+ ALL_RETURN_TYPES = (indexBefore(template, 0, "@each-R@") < template.length);
+ for (int nargs = MIN_ARITY; nargs <= MAX_ARITY; nargs++) {
+ for (int rcat = 0; rcat <= MAX_RCAT; rcat++) {
+ expandTemplate(template, true, rcat, nargs, 0, 0);
+ if (ALL_ARG_TYPES) break;
+ expandTemplateForPrims(template, true, rcat, nargs, 1, 1);
+ if (ALL_RETURN_TYPES) break;
+ }
+ }
+ }
+ static String catstr(int rcat, int nrefs, int nints, int nlongs) {
+ int nargs = nrefs + nints + nlongs;
+ String cat = TCHARS[rcat] + nargs;
+ if (!ALL_ARG_TYPES) cat += (nints==0?"":"I"+nints)+(nlongs==0?"":"J"+nlongs);
+ return cat;
+ }
+ static void expandTemplateForPrims(String[] template, boolean topLevel, int rcat, int nargs, int minints, int minlongs) {
+ for (int isLong = 0; isLong <= 1; isLong++) {
+ for (int nprims = 1; nprims <= nargs; nprims++) {
+ int nrefs = nargs - nprims;
+ int nints = ((1-isLong) * nprims);
+ int nlongs = (isLong * nprims);
+ expandTemplate(template, topLevel, rcat, nrefs, nints, nlongs);
+ }
+ }
+ }
+ static void expandTemplate(String[] template, boolean topLevel,
+ int rcat, int nrefs, int nints, int nlongs) {
+ int nargs = nrefs + nints + nlongs;
+ if (nrefs > MAX_REFS || nints > MAX_INTS || nlongs > MAX_LONGS) return;
+ VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+ if (topLevel && !done.add(VAR.cat.binding)) {
+ System.out.println(" //repeat "+VAR.cat.binding);
+ return;
+ }
+ for (int i = 0; i < template.length; i++) {
+ String line = template[i];
+ if (line.endsWith("@each-cat@")) {
+ // ignore
+ } else if (line.endsWith("@each-R@")) {
+ int blockEnd = indexAfter(template, i, "@end-R@");
+ String[] block = stringsIn(template, i+1, blockEnd-1);
+ for (int rcat1 = rcat; rcat1 <= MAX_RCAT; rcat1++)
+ expandTemplate(block, false, rcat1, nrefs, nints, nlongs);
+ VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+ i = blockEnd-1; continue;
+ } else if (line.endsWith("@each-Tv@")) {
+ int blockEnd = indexAfter(template, i, "@end-Tv@");
+ String[] block = stringsIn(template, i+1, blockEnd-1);
+ expandTemplate(block, false, rcat, nrefs, nints, nlongs);
+ expandTemplateForPrims(block, false, rcat, nargs, nints+1, nlongs+1);
+ VAR.makeBindings(topLevel, rcat, nrefs, nints, nlongs);
+ i = blockEnd-1; continue;
+ } else {
+ System.out.println(VAR.transform(line));
+ }
+ }
+ }
+}
+//}}} */
+//params=[0, 10, 4, 99, 0, 0]
+ static class A0 extends Adapter {
+ protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A0(e, i, c, t); }
+ protected Object invoke_L0() throws Throwable { return convert_L((Object)invoker.invokeExact(target)); }
+ protected Object invoke_I0() throws Throwable { return convert_I((int) invoker.invokeExact(target)); }
+ protected Object invoke_J0() throws Throwable { return convert_J((long) invoker.invokeExact(target)); }
+ protected Object invoke_F0() throws Throwable { return convert_F((float) invoker.invokeExact(target)); }
+ protected Object invoke_D0() throws Throwable { return convert_D((double)invoker.invokeExact(target)); }
+ }
+ static class A1 extends Adapter {
+ protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A1(e, i, c, t); }
+ protected Object invoke_L1(Object a0) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0)); }
+ protected Object invoke_I1(Object a0) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0)); }
+ protected Object invoke_J1(Object a0) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0)); }
+ protected Object invoke_F1(Object a0) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0)); }
+ protected Object invoke_D1(Object a0) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0)); }
+ }
+ static class A2 extends Adapter {
+ protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A2(e, i, c, t); }
+ protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
+ protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
+ }
+ static class A3 extends Adapter {
+ protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A3(e, i, c, t); }
+ protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2)); }
+ protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2)); }
+ protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2)); }
+ protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2)); }
+ protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2)); }
+ }
+ static class A4 extends Adapter {
+ protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A4(e, i, c, t); }
+ protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3)); }
+ protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3)); }
+ protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3)); }
+ protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3)); }
+ protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3)); }
+ }
+ static class A5 extends Adapter {
+ protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A5(e, i, c, t); }
+ protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
+ protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
+ protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
+ protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
+ protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
+ }
+ static class A6 extends Adapter {
+ protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A6(e, i, c, t); }
+ protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
+ protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
+ protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
+ protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
+ protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
+ }
+ static class A7 extends Adapter {
+ protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A7(e, i, c, t); }
+ protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
+ protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
+ protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
+ protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
+ protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
+ }
+ static class A8 extends Adapter {
+ protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A8(e, i, c, t); }
+ protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+ protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+ protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+ protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+ protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
+ }
+ static class A9 extends Adapter {
+ protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A9(e, i, c, t); }
+ protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+ protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+ protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+ protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+ protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
+ }
+ static class A10 extends Adapter {
+ protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
+ protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { super(e, i, c, t); }
+ protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
+ { return new A10(e, i, c, t); }
+ protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+ protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+ protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+ protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+ protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/InvokeDynamic.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/InvokeDynamic.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+/**
+ * This is a place-holder class. Some HotSpot implementations need to see it.
+ */
+final class InvokeDynamic {
+ private InvokeDynamic() { throw new InternalError(); } // do not instantiate
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/InvokeGeneric.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/InvokeGeneric.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2009, 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.lang.invoke;
+
+import sun.invoke.util.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * Adapters which manage MethodHandle.invokeGeneric calls.
+ * The JVM calls one of these when the exact type match fails.
+ * @author jrose
+ */
+class InvokeGeneric {
+ // erased type for the call, which originates from an invokeGeneric site
+ private final MethodType erasedCallerType;
+ // an invoker of type (MT, MH; A...) -> R
+ private final MethodHandle initialInvoker;
+
+ /** Compute and cache information for this adapter, so that it can
+ * call out to targets of the erasure-family of the given erased type.
+ */
+ /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
+ assert(erasedCallerType.equals(erasedCallerType.erase()));
+ this.erasedCallerType = erasedCallerType;
+ this.initialInvoker = makeInitialInvoker();
+ assert initialInvoker.type().equals(erasedCallerType
+ .insertParameterTypes(0, MethodType.class, MethodHandle.class))
+ : initialInvoker.type();
+ }
+
+ private static MethodHandles.Lookup lookup() {
+ return IMPL_LOOKUP;
+ }
+
+ /** Return the adapter information for this type's erasure. */
+ /*non-public*/ static MethodHandle genericInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
+ InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
+ return gen.initialInvoker;
+ }
+
+ private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
+ // postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
+ MethodHandle postDispatch = makePostDispatchInvoker();
+ MethodHandle invoker;
+ if (returnConversionPossible()) {
+ invoker = MethodHandles.foldArguments(postDispatch,
+ dispatcher("dispatchWithConversion"));
+ } else {
+ invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
+ }
+ return invoker;
+ }
+
+ private static final Class>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
+ private MethodHandle makePostDispatchInvoker() {
+ // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
+ MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
+ return invokerType.invokers().exactInvoker();
+ }
+ private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
+ assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
+ return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
+ }
+
+ private MethodHandle dispatcher(String dispatchName) throws ReflectiveOperationException {
+ return lookup().bind(this, dispatchName,
+ MethodType.methodType(MethodHandle.class,
+ MethodType.class, MethodHandle.class));
+ }
+
+ static final boolean USE_AS_TYPE_PATH = true;
+
+ /** Return a method handle to invoke on the callerType, target, and remaining arguments.
+ * The method handle must finish the call.
+ * This is the first look at the caller type and target.
+ */
+ private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
+ MethodType targetType = target.type();
+ if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
+ MethodHandle newTarget = target.asType(callerType);
+ targetType = callerType;
+ Invokers invokers = targetType.invokers();
+ MethodHandle invoker = invokers.erasedInvokerWithDrops;
+ if (invoker == null) {
+ invokers.erasedInvokerWithDrops = invoker =
+ dropDispatchArguments(invokers.erasedInvoker());
+ }
+ return invoker.bindTo(newTarget);
+ }
+ throw new RuntimeException("NYI");
+ }
+
+ private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
+ MethodHandle finisher = dispatch(callerType, target);
+ if (returnConversionNeeded(callerType, target))
+ finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow
+ return finisher;
+ }
+
+ private boolean returnConversionPossible() {
+ Class> needType = erasedCallerType.returnType();
+ return !needType.isPrimitive();
+ }
+ private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
+ Class> needType = callerType.returnType();
+ if (needType == erasedCallerType.returnType())
+ return false; // no conversions possible, since must be primitive or Object
+ Class> haveType = target.type().returnType();
+ if (VerifyType.isNullConversion(haveType, needType))
+ return false;
+ return true;
+ }
+ private MethodHandle addReturnConversion(MethodHandle target, Class> type) {
+ if (true) throw new RuntimeException("NYI");
+ // FIXME: This is slow because it creates a closure node on every call that requires a return cast.
+ MethodType targetType = target.type();
+ MethodHandle caster = ValueConversions.identity(type);
+ caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
+ // Drop irrelevant arguments, because we only care about the return value:
+ caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
+ MethodHandle result = MethodHandles.foldArguments(caster, target);
+ return result.asType(target.type());
+ }
+
+ public String toString() {
+ return "InvokeGeneric"+erasedCallerType;
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/Invokers.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/Invokers.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,144 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * Construction and caching of often-used invokers.
+ * @author jrose
+ */
+class Invokers {
+ // exact type (sans leading taget MH) for the outgoing call
+ private final MethodType targetType;
+
+ // exact invoker for the outgoing call
+ private /*lazy*/ MethodHandle exactInvoker;
+
+ // erased (partially untyped but with primitives) invoker for the outgoing call
+ private /*lazy*/ MethodHandle erasedInvoker;
+ /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
+
+ // generic (untyped) invoker for the outgoing call
+ private /*lazy*/ MethodHandle genericInvoker;
+
+ // generic (untyped) invoker for the outgoing call; accepts a single Object[]
+ private final /*lazy*/ MethodHandle[] spreadInvokers;
+
+ // invoker for an unbound callsite
+ private /*lazy*/ MethodHandle uninitializedCallSite;
+
+ /** Compute and cache information common to all collecting adapters
+ * that implement members of the erasure-family of the given erased type.
+ */
+ /*non-public*/ Invokers(MethodType targetType) {
+ this.targetType = targetType;
+ this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
+ }
+
+ /*non-public*/ static MethodType invokerType(MethodType targetType) {
+ return targetType.insertParameterTypes(0, MethodHandle.class);
+ }
+
+ /*non-public*/ MethodHandle exactInvoker() {
+ MethodHandle invoker = exactInvoker;
+ if (invoker != null) return invoker;
+ try {
+ invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
+ } catch (ReflectiveOperationException ex) {
+ throw new InternalError("JVM cannot find invoker for "+targetType);
+ }
+ assert(invokerType(targetType) == invoker.type());
+ exactInvoker = invoker;
+ return invoker;
+ }
+
+ /*non-public*/ MethodHandle genericInvoker() {
+ MethodHandle invoker1 = exactInvoker();
+ MethodHandle invoker = genericInvoker;
+ if (invoker != null) return invoker;
+ MethodType genericType = targetType.generic();
+ invoker = MethodHandles.convertArguments(invoker1, invokerType(genericType));
+ genericInvoker = invoker;
+ return invoker;
+ }
+
+ /*non-public*/ MethodHandle erasedInvoker() {
+ MethodHandle invoker1 = exactInvoker();
+ MethodHandle invoker = erasedInvoker;
+ if (invoker != null) return invoker;
+ MethodType erasedType = targetType.erase();
+ if (erasedType == targetType.generic())
+ invoker = genericInvoker();
+ else
+ invoker = MethodHandles.convertArguments(invoker1, invokerType(erasedType));
+ erasedInvoker = invoker;
+ return invoker;
+ }
+
+ /*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
+ MethodHandle vaInvoker = spreadInvokers[objectArgCount];
+ if (vaInvoker != null) return vaInvoker;
+ MethodHandle gInvoker = genericInvoker();
+ vaInvoker = gInvoker.asSpreader(Object[].class, targetType.parameterCount() - objectArgCount);
+ spreadInvokers[objectArgCount] = vaInvoker;
+ return vaInvoker;
+ }
+
+ private static MethodHandle THROW_UCS = null;
+
+ /*non-public*/ MethodHandle uninitializedCallSite() {
+ MethodHandle invoker = uninitializedCallSite;
+ if (invoker != null) return invoker;
+ if (targetType.parameterCount() > 0) {
+ MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
+ Invokers invokers0 = type0.invokers();
+ invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
+ 0, targetType.parameterList());
+ assert(invoker.type().equals(targetType));
+ uninitializedCallSite = invoker;
+ return invoker;
+ }
+ if (THROW_UCS == null) {
+ try {
+ THROW_UCS = IMPL_LOOKUP
+ .findStatic(CallSite.class, "uninitializedCallSite",
+ MethodType.methodType(Empty.class));
+ } catch (ReflectiveOperationException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS);
+ assert(invoker.type().equals(targetType));
+ uninitializedCallSite = invoker;
+ return invoker;
+ }
+
+ public String toString() {
+ return "Invokers"+targetType;
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/MemberName.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/MemberName.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,718 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.util.BytecodeDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A {@code MemberName} is a compact symbolic datum which fully characterizes
+ * a method or field reference.
+ * A member name refers to a field, method, constructor, or member type.
+ * Every member name has a simple name (a string) and a type (either a Class or MethodType).
+ * A member name may also have a non-null declaring class, or it may be simply
+ * a naked name/type pair.
+ * A member name may also have non-zero modifier flags.
+ * Finally, a member name may be either resolved or unresolved.
+ * If it is resolved, the existence of the named
+ *
+ * Whether resolved or not, a member name provides no access rights or
+ * invocation capability to its possessor. It is merely a compact
+ * representation of all symbolic information necessary to link to
+ * and properly use the named member.
+ *
+ * When resolved, a member name's internal implementation may include references to JVM metadata.
+ * This representation is stateless and only decriptive.
+ * It provides no private information and no capability to use the member.
+ *
+ * By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
+ * about the internals of a method (except its bytecodes) and also
+ * allows invocation. A MemberName is much lighter than a Method,
+ * since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
+ * and those seven fields omit much of the information in Method.
+ * @author jrose
+ */
+/*non-public*/ final class MemberName implements Member, Cloneable {
+ private Class> clazz; // class in which the method is defined
+ private String name; // may be null if not yet materialized
+ private Object type; // may be null if not yet materialized
+ private int flags; // modifier bits; see reflect.Modifier
+
+ private Object vmtarget; // VM-specific target value
+ private int vmindex; // method index within class or interface
+
+ { vmindex = VM_INDEX_UNINITIALIZED; }
+
+ /** Return the declaring class of this member.
+ * In the case of a bare name and type, the declaring class will be null.
+ */
+ public Class> getDeclaringClass() {
+ if (clazz == null && isResolved()) {
+ expandFromVM();
+ }
+ return clazz;
+ }
+
+ /** Utility method producing the class loader of the declaring class. */
+ public ClassLoader getClassLoader() {
+ return clazz.getClassLoader();
+ }
+
+ /** Return the simple name of this member.
+ * For a type, it is the same as {@link Class#getSimpleName}.
+ * For a method or field, it is the simple name of the member.
+ * For a constructor, it is always {@code "<init>"}.
+ */
+ public String getName() {
+ if (name == null) {
+ expandFromVM();
+ if (name == null) return null;
+ }
+ return name;
+ }
+
+ /** Return the declared type of this member, which
+ * must be a method or constructor.
+ */
+ public MethodType getMethodType() {
+ if (type == null) {
+ expandFromVM();
+ if (type == null) return null;
+ }
+ if (!isInvocable())
+ throw newIllegalArgumentException("not invocable, no method type");
+ if (type instanceof MethodType) {
+ return (MethodType) type;
+ }
+ if (type instanceof String) {
+ String sig = (String) type;
+ MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
+ this.type = res;
+ return res;
+ }
+ if (type instanceof Object[]) {
+ Object[] typeInfo = (Object[]) type;
+ Class>[] ptypes = (Class>[]) typeInfo[1];
+ Class> rtype = (Class>) typeInfo[0];
+ MethodType res = MethodType.methodType(rtype, ptypes);
+ this.type = res;
+ return res;
+ }
+ throw new InternalError("bad method type "+type);
+ }
+
+ /** Return the actual type under which this method or constructor must be invoked.
+ * For non-static methods or constructors, this is the type with a leading parameter,
+ * a reference to declaring class. For static methods, it is the same as the declared type.
+ */
+ public MethodType getInvocationType() {
+ MethodType itype = getMethodType();
+ if (!isStatic())
+ itype = itype.insertParameterTypes(0, clazz);
+ return itype;
+ }
+
+ /** Utility method producing the parameter types of the method type. */
+ public Class>[] getParameterTypes() {
+ return getMethodType().parameterArray();
+ }
+
+ /** Utility method producing the return type of the method type. */
+ public Class> getReturnType() {
+ return getMethodType().returnType();
+ }
+
+ /** Return the declared type of this member, which
+ * must be a field or type.
+ * If it is a type member, that type itself is returned.
+ */
+ public Class> getFieldType() {
+ if (type == null) {
+ expandFromVM();
+ if (type == null) return null;
+ }
+ if (isInvocable())
+ throw newIllegalArgumentException("not a field or nested class, no simple type");
+ if (type instanceof Class>) {
+ return (Class>) type;
+ }
+ if (type instanceof String) {
+ String sig = (String) type;
+ MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
+ Class> res = mtype.returnType();
+ this.type = res;
+ return res;
+ }
+ throw new InternalError("bad field type "+type);
+ }
+
+ /** Utility method to produce either the method type or field type of this member. */
+ public Object getType() {
+ return (isInvocable() ? getMethodType() : getFieldType());
+ }
+
+ /** Utility method to produce the signature of this member,
+ * used within the class file format to describe its type.
+ */
+ public String getSignature() {
+ if (type == null) {
+ expandFromVM();
+ if (type == null) return null;
+ }
+ if (type instanceof String)
+ return (String) type;
+ if (isInvocable())
+ return BytecodeDescriptor.unparse(getMethodType());
+ else
+ return BytecodeDescriptor.unparse(getFieldType());
+ }
+
+ /** Return the modifier flags of this member.
+ * @see java.lang.reflect.Modifier
+ */
+ public int getModifiers() {
+ return (flags & RECOGNIZED_MODIFIERS);
+ }
+
+ private void setFlags(int flags) {
+ this.flags = flags;
+ assert(testAnyFlags(ALL_KINDS));
+ }
+
+ private boolean testFlags(int mask, int value) {
+ return (flags & mask) == value;
+ }
+ private boolean testAllFlags(int mask) {
+ return testFlags(mask, mask);
+ }
+ private boolean testAnyFlags(int mask) {
+ return !testFlags(mask, 0);
+ }
+
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isStatic() {
+ return Modifier.isStatic(flags);
+ }
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isPublic() {
+ return Modifier.isPublic(flags);
+ }
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isPrivate() {
+ return Modifier.isPrivate(flags);
+ }
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isProtected() {
+ return Modifier.isProtected(flags);
+ }
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isFinal() {
+ return Modifier.isFinal(flags);
+ }
+ /** Utility method to query the modifier flags of this member. */
+ public boolean isAbstract() {
+ return Modifier.isAbstract(flags);
+ }
+ // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
+
+ // unofficial modifier flags, used by HotSpot:
+ static final int BRIDGE = 0x00000040;
+ static final int VARARGS = 0x00000080;
+ static final int SYNTHETIC = 0x00001000;
+ static final int ANNOTATION= 0x00002000;
+ static final int ENUM = 0x00004000;
+ /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
+ public boolean isBridge() {
+ return testAllFlags(IS_METHOD | BRIDGE);
+ }
+ /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
+ public boolean isVarargs() {
+ return testAllFlags(VARARGS) && isInvocable();
+ }
+ /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
+ public boolean isSynthetic() {
+ return testAllFlags(SYNTHETIC);
+ }
+
+ static final String CONSTRUCTOR_NAME = ""; // the ever-popular
+
+ // modifiers exported by the JVM:
+ static final int RECOGNIZED_MODIFIERS = 0xFFFF;
+
+ // private flags, not part of RECOGNIZED_MODIFIERS:
+ static final int
+ IS_METHOD = MN_IS_METHOD, // method (not constructor)
+ IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
+ IS_FIELD = MN_IS_FIELD, // field
+ IS_TYPE = MN_IS_TYPE; // nested type
+ static final int // for MethodHandleNatives.getMembers
+ SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
+ SEARCH_INTERFACES = MN_SEARCH_INTERFACES;
+
+ static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
+ static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
+ static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
+ static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
+ static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
+
+ /** Utility method to query whether this member is a method or constructor. */
+ public boolean isInvocable() {
+ return testAnyFlags(IS_INVOCABLE);
+ }
+ /** Utility method to query whether this member is a method, constructor, or field. */
+ public boolean isFieldOrMethod() {
+ return testAnyFlags(IS_FIELD_OR_METHOD);
+ }
+ /** Query whether this member is a method. */
+ public boolean isMethod() {
+ return testAllFlags(IS_METHOD);
+ }
+ /** Query whether this member is a constructor. */
+ public boolean isConstructor() {
+ return testAllFlags(IS_CONSTRUCTOR);
+ }
+ /** Query whether this member is a field. */
+ public boolean isField() {
+ return testAllFlags(IS_FIELD);
+ }
+ /** Query whether this member is a type. */
+ public boolean isType() {
+ return testAllFlags(IS_TYPE);
+ }
+ /** Utility method to query whether this member is neither public, private, nor protected. */
+ public boolean isPackage() {
+ return !testAnyFlags(ALL_ACCESS);
+ }
+
+ /** Initialize a query. It is not resolved. */
+ private void init(Class> defClass, String name, Object type, int flags) {
+ // defining class is allowed to be null (for a naked name/type pair)
+ //name.toString(); // null check
+ //type.equals(type); // null check
+ // fill in fields:
+ this.clazz = defClass;
+ this.name = name;
+ this.type = type;
+ setFlags(flags);
+ assert(!isResolved());
+ }
+
+ private void expandFromVM() {
+ if (!isResolved()) return;
+ if (type instanceof Object[])
+ type = null; // don't saddle JVM w/ typeInfo
+ MethodHandleNatives.expand(this);
+ }
+
+ // Capturing information from the Core Reflection API:
+ private static int flagsMods(int flags, int mods) {
+ assert((flags & RECOGNIZED_MODIFIERS) == 0);
+ assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
+ return flags | mods;
+ }
+ /** Create a name for the given reflected method. The resulting name will be in a resolved state. */
+ public MemberName(Method m) {
+ Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
+ init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
+ // fill in vmtarget, vmindex while we have m in hand:
+ MethodHandleNatives.init(this, m);
+ assert(isResolved());
+ }
+ /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
+ public MemberName(Constructor ctor) {
+ Object[] typeInfo = { void.class, ctor.getParameterTypes() };
+ init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
+ // fill in vmtarget, vmindex while we have ctor in hand:
+ MethodHandleNatives.init(this, ctor);
+ assert(isResolved());
+ }
+ /** Create a name for the given reflected field. The resulting name will be in a resolved state. */
+ public MemberName(Field fld) {
+ init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
+ // fill in vmtarget, vmindex while we have fld in hand:
+ MethodHandleNatives.init(this, fld);
+ assert(isResolved());
+ }
+ /** Create a name for the given class. The resulting name will be in a resolved state. */
+ public MemberName(Class> type) {
+ init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
+ vmindex = 0; // isResolved
+ assert(isResolved());
+ }
+
+ // bare-bones constructor; the JVM will fill it in
+ MemberName() { }
+
+ // locally useful cloner
+ @Override protected MemberName clone() {
+ try {
+ return (MemberName) super.clone();
+ } catch (CloneNotSupportedException ex) {
+ throw new InternalError();
+ }
+ }
+
+ // %%% define equals/hashcode?
+
+ // Construction from symbolic parts, for queries:
+ /** Create a field or type name from the given components: Declaring class, name, type, modifiers.
+ * The declaring class may be supplied as null if this is to be a bare name and type.
+ * The resulting name will in an unresolved state.
+ */
+ public MemberName(Class> defClass, String name, Class> type, int modifiers) {
+ init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
+ }
+ /** Create a field or type name from the given components: Declaring class, name, type.
+ * The declaring class may be supplied as null if this is to be a bare name and type.
+ * The modifier flags default to zero.
+ * The resulting name will in an unresolved state.
+ */
+ public MemberName(Class> defClass, String name, Class> type) {
+ this(defClass, name, type, 0);
+ }
+ /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
+ * It will be a constructor if and only if the name is {@code "<init>"}.
+ * The declaring class may be supplied as null if this is to be a bare name and type.
+ * The resulting name will in an unresolved state.
+ */
+ public MemberName(Class> defClass, String name, MethodType type, int modifiers) {
+ int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
+ init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
+ }
+ /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
+ * It will be a constructor if and only if the name is {@code "<init>"}.
+ * The declaring class may be supplied as null if this is to be a bare name and type.
+ * The modifier flags default to zero.
+ * The resulting name will in an unresolved state.
+ */
+ public MemberName(Class> defClass, String name, MethodType type) {
+ this(defClass, name, type, 0);
+ }
+
+ /** Query whether this member name is resolved.
+ * A resolved member name is one for which the JVM has found
+ * a method, constructor, field, or type binding corresponding exactly to the name.
+ * (Document?)
+ */
+ public boolean isResolved() {
+ return (vmindex != VM_INDEX_UNINITIALIZED);
+ }
+
+ /** Query whether this member name is resolved to a non-static, non-final method.
+ */
+ public boolean hasReceiverTypeDispatch() {
+ return (isMethod() && getVMIndex() >= 0);
+ }
+
+ /** Produce a string form of this member name.
+ * For types, it is simply the type's own string (as reported by {@code toString}).
+ * For fields, it is {@code "DeclaringClass.name/type"}.
+ * For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
+ * If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
+ * If the member is unresolved, a prefix {@code "*."} is prepended.
+ */
+ @Override
+ public String toString() {
+ if (isType())
+ return type.toString(); // class java.lang.String
+ // else it is a field, method, or constructor
+ StringBuilder buf = new StringBuilder();
+ if (getDeclaringClass() != null) {
+ buf.append(getName(clazz));
+ buf.append('.');
+ }
+ String name = getName();
+ buf.append(name == null ? "*" : name);
+ Object type = getType();
+ if (!isInvocable()) {
+ buf.append('/');
+ buf.append(type == null ? "*" : getName(type));
+ } else {
+ buf.append(type == null ? "(*)*" : getName(type));
+ }
+ /*
+ buf.append('/');
+ // key: Public, private, pRotected, sTatic, Final, sYnchronized,
+ // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
+ // (annotation), Enum, (unused)
+ final String FIELD_MOD_CHARS = "PprTF?vt????Y?E?";
+ final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
+ String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
+ for (int i = 0; i < modChars.length(); i++) {
+ if ((flags & (1 << i)) != 0) {
+ char mc = modChars.charAt(i);
+ if (mc != '?')
+ buf.append(mc);
+ }
+ }
+ */
+ return buf.toString();
+ }
+ private static String getName(Object obj) {
+ if (obj instanceof Class>)
+ return ((Class>)obj).getName();
+ return String.valueOf(obj);
+ }
+
+ // Queries to the JVM:
+ /** Document? */
+ /*non-public*/ int getVMIndex() {
+ if (!isResolved())
+ throw newIllegalStateException("not resolved", this);
+ return vmindex;
+ }
+// /*non-public*/ Object getVMTarget() {
+// if (!isResolved())
+// throw newIllegalStateException("not resolved", this);
+// return vmtarget;
+// }
+
+ public IllegalAccessException makeAccessException(String message, Object from) {
+ message = message + ": "+ toString();
+ if (from != null) message += ", from " + from;
+ return new IllegalAccessException(message);
+ }
+ public ReflectiveOperationException makeAccessException(String message) {
+ message = message + ": "+ toString();
+ if (isResolved())
+ return new IllegalAccessException(message);
+ else if (isConstructor())
+ return new NoSuchMethodException(message);
+ else if (isMethod())
+ return new NoSuchMethodException(message);
+ else
+ return new NoSuchFieldException(message);
+ }
+
+ /** Actually making a query requires an access check. */
+ /*non-public*/ static Factory getFactory() {
+ return Factory.INSTANCE;
+ }
+ /** A factory type for resolving member names with the help of the VM.
+ * TBD: Define access-safe public constructors for this factory.
+ */
+ public static class Factory {
+ private Factory() { } // singleton pattern
+ static Factory INSTANCE = new Factory();
+
+ private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
+
+ /// Queries
+ List getMembers(Class> defc,
+ String matchName, Object matchType,
+ int matchFlags, Class> lookupClass) {
+ matchFlags &= ALLOWED_FLAGS;
+ String matchSig = null;
+ if (matchType != null) {
+ matchSig = BytecodeDescriptor.unparse(matchType);
+ if (matchSig.startsWith("("))
+ matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
+ else
+ matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
+ }
+ final int BUF_MAX = 0x2000;
+ int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
+ MemberName[] buf = newMemberBuffer(len1);
+ int totalCount = 0;
+ ArrayList bufs = null;
+ int bufCount = 0;
+ for (;;) {
+ bufCount = MethodHandleNatives.getMembers(defc,
+ matchName, matchSig, matchFlags,
+ lookupClass,
+ totalCount, buf);
+ if (bufCount <= buf.length) {
+ if (bufCount < 0) bufCount = 0;
+ totalCount += bufCount;
+ break;
+ }
+ // JVM returned to us with an intentional overflow!
+ totalCount += buf.length;
+ int excess = bufCount - buf.length;
+ if (bufs == null) bufs = new ArrayList(1);
+ bufs.add(buf);
+ int len2 = buf.length;
+ len2 = Math.max(len2, excess);
+ len2 = Math.max(len2, totalCount / 4);
+ buf = newMemberBuffer(Math.min(BUF_MAX, len2));
+ }
+ ArrayList result = new ArrayList(totalCount);
+ if (bufs != null) {
+ for (MemberName[] buf0 : bufs) {
+ Collections.addAll(result, buf0);
+ }
+ }
+ result.addAll(Arrays.asList(buf).subList(0, bufCount));
+ // Signature matching is not the same as type matching, since
+ // one signature might correspond to several types.
+ // So if matchType is a Class or MethodType, refilter the results.
+ if (matchType != null && matchType != matchSig) {
+ for (Iterator it = result.iterator(); it.hasNext();) {
+ MemberName m = it.next();
+ if (!matchType.equals(m.getType()))
+ it.remove();
+ }
+ }
+ return result;
+ }
+ boolean resolveInPlace(MemberName m, boolean searchSupers, Class> lookupClass) {
+ if (m.name == null || m.type == null) { // find unique non-overloaded name
+ Class> defc = m.getDeclaringClass();
+ List choices = null;
+ if (m.isMethod())
+ choices = getMethods(defc, searchSupers, m.name, (MethodType) m.type, lookupClass);
+ else if (m.isConstructor())
+ choices = getConstructors(defc, lookupClass);
+ else if (m.isField())
+ choices = getFields(defc, searchSupers, m.name, (Class>) m.type, lookupClass);
+ //System.out.println("resolving "+m+" to "+choices);
+ if (choices == null || choices.size() != 1)
+ return false;
+ if (m.name == null) m.name = choices.get(0).name;
+ if (m.type == null) m.type = choices.get(0).type;
+ }
+ MethodHandleNatives.resolve(m, lookupClass);
+ if (m.isResolved()) return true;
+ int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+ String matchSig = m.getSignature();
+ MemberName[] buf = { m };
+ int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
+ m.getName(), matchSig, matchFlags, lookupClass, 0, buf);
+ if (n != 1) return false;
+ return m.isResolved();
+ }
+ /** Produce a resolved version of the given member.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * If lookup fails or access is not permitted, null is returned.
+ * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
+ */
+ public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class> lookupClass) {
+ MemberName result = m.clone();
+ if (resolveInPlace(result, searchSupers, lookupClass))
+ return result;
+ return null;
+ }
+ /** Produce a resolved version of the given member.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
+ * Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
+ */
+ public
+
+ MemberName resolveOrFail(MemberName m, boolean searchSupers, Class> lookupClass,
+ Class nsmClass)
+ throws IllegalAccessException, NoSuchMemberException {
+ MemberName result = resolveOrNull(m, searchSupers, lookupClass);
+ if (result != null)
+ return result;
+ ReflectiveOperationException ex = m.makeAccessException("no access");
+ if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
+ throw nsmClass.cast(ex);
+ }
+ /** Return a list of all methods defined by the given class.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getMethods(Class> defc, boolean searchSupers,
+ Class> lookupClass) {
+ return getMethods(defc, searchSupers, null, null, lookupClass);
+ }
+ /** Return a list of matching methods defined by the given class.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Returned methods will match the name (if not null) and the type (if not null).
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getMethods(Class> defc, boolean searchSupers,
+ String name, MethodType type, Class> lookupClass) {
+ int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+ return getMembers(defc, name, type, matchFlags, lookupClass);
+ }
+ /** Return a list of all constructors defined by the given class.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getConstructors(Class> defc, Class> lookupClass) {
+ return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
+ }
+ /** Return a list of all fields defined by the given class.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getFields(Class> defc, boolean searchSupers,
+ Class> lookupClass) {
+ return getFields(defc, searchSupers, null, null, lookupClass);
+ }
+ /** Return a list of all fields defined by the given class.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Returned fields will match the name (if not null) and the type (if not null).
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getFields(Class> defc, boolean searchSupers,
+ String name, Class> type, Class> lookupClass) {
+ int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+ return getMembers(defc, name, type, matchFlags, lookupClass);
+ }
+ /** Return a list of all nested types defined by the given class.
+ * Super types are searched (for inherited members) if {@code searchSupers} is true.
+ * Access checking is performed on behalf of the given {@code lookupClass}.
+ * Inaccessible members are not added to the last.
+ */
+ public List getNestedTypes(Class> defc, boolean searchSupers,
+ Class> lookupClass) {
+ int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
+ return getMembers(defc, null, null, matchFlags, lookupClass);
+ }
+ private static MemberName[] newMemberBuffer(int length) {
+ MemberName[] buf = new MemberName[length];
+ // fill the buffer with dummy structs for the JVM to fill in
+ for (int i = 0; i < length; i++)
+ buf[i] = new MemberName();
+ return buf;
+ }
+ }
+
+// static {
+// System.out.println("Hello world! My methods are:");
+// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
+// }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/MethodHandle.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,1028 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * 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
+ * {@linkplain #asType conversion},
+ * {@linkplain #bindTo insertion},
+ * {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
+ * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
+ *
+ *
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.
+ * This type descriptor is a {@link java.lang.invoke.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).
+ *
+ * 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 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 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.
+ *
+ * (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}).
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
+ * For example, a static method handle can be obtained
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
+ * There are also conversion methods from Core Reflection API objects,
+ * such as {@link java.lang.invoke.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
+ * receiver argument, prepended before any other arguments.
+ * In the method handle's type, the initial receiver argument is typed
+ * according to the class under which the method was initially requested.
+ * (E.g., if a non-static method handle is obtained via {@code ldc},
+ * the type of the receiver is the class named in the constant pool entry.)
+ *
+ * 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 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.
+ *
+ *
+ * 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.lang.invoke.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:
+ *
+ * A signature polymorphic method will be declared with the following properties:
+ *
+ *
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.lang.invoke} package.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ *
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}.
+ *
+ * (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.)
+ *
+ * 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.lang.invoke.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.lang.invoke.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.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
+ * or {@link java.lang.invoke.MethodHandles#genericInvoker MethodHandles.genericInvoker}.
+ * The {@link java.lang.invoke.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.
+ *
+ *
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.
+ *
Method types can specify arguments of primitive types,
+ * which Java generic types cannot range over.
+ *
Higher order functions over method handles (combinators) are
+ * often generic across a wide range of function types, including
+ * those of multiple arities. It is impossible to represent such
+ * genericity with a Java type parameter.
+ *
+ *
+ * @see MethodType
+ * @see MethodHandles
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class MethodHandle {
+ // { JVM internals:
+
+ private byte vmentry; // adapter stub or method entry point
+ //private int vmslots; // optionally, hoist type.form.vmslots
+ /*non-public*/ Object vmtarget; // VM-specific, class-specific target value
+
+ // TO DO: vmtarget should be invisible to Java, since the JVM puts internal
+ // managed pointers into it. Making it visible exposes it to debuggers,
+ // which can cause errors when they treat the pointer as an Object.
+
+ // These two dummy fields are present to force 'I' and 'J' signatures
+ // into this class's constant pool, so they can be transferred
+ // to vmentry when this class is loaded.
+ static final int INT_FIELD = 0;
+ static final long LONG_FIELD = 0;
+
+ // vmentry (a void* field) is used *only* by the JVM.
+ // The JVM adjusts its type to int or long depending on system wordsize.
+ // Since it is statically typed as neither int nor long, it is impossible
+ // to use this field from Java bytecode. (Please don't try to, either.)
+
+ // The vmentry is an assembly-language stub which is jumped to
+ // immediately after the method type is verified.
+ // For a direct MH, this stub loads the vmtarget's entry point
+ // and jumps to it.
+
+ // } End of JVM internals.
+
+ 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.
+ */
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+ @interface PolymorphicSignature { }
+
+ private MethodType type;
+
+ /**
+ * Reports the type of this method handle.
+ * Every invocation of this method handle via {@code invokeExact} must exactly match this type.
+ * @return the method handle type
+ */
+ public MethodType type() {
+ return type;
+ }
+
+ /**
+ * Package-private constructor for the method handle implementation hierarchy.
+ * Method handle inheritance will be contained completely within
+ * the {@code java.lang.invoke} package.
+ */
+ // @param type type (permanently assigned) of the new method handle
+ /*non-public*/ MethodHandle(MethodType type) {
+ type.getClass(); // elicit NPE
+ this.type = type;
+ }
+
+ /**
+ * Invokes 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.
+ *
+ * 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.lang.invoke.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;
+
+ /**
+ * Invokes the method handle, allowing any caller type descriptor,
+ * and optionally performing conversions on arguments and return values.
+ *
+ * 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
+ * adjusted by calling {@link #asType asType} to adjust this method handle
+ * to the required type, and then the call proceeds as if by
+ * {@link #invokeExact invokeExact} on the adjusted method handle.
+ *
+ * There is no guarantee that the {@code asType} call is actually made.
+ * If the JVM can predict the results of making the call, it may perform
+ * adaptations directly on the caller's arguments,
+ * and call the target method handle according to its own exact type.
+ *
+ * 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,
+ * 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.lang.invoke.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;
+
+ /**
+ * Performs a varargs invocation, passing the arguments in the given array
+ * to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
+ * which mentions only the type {@code Object}, and whose arity is the length
+ * of the argument array.
+ *
+ * Specifically, execution proceeds as if by the following steps,
+ * although the methods are not guaranteed to be called if the JVM
+ * can predict their effects.
+ *
+ *
Determine the length of the argument array as {@code N}.
+ * For a null reference, {@code N=0}.
+ *
Determine the generic type {@code TN} of {@code N} arguments as
+ * as {@code TN=MethodType.genericMethodType(N)}.
+ *
Force the original target method handle {@code MH0} to the
+ * required type, as {@code MH1 = MH0.asType(TN)}.
+ *
Spread the array into {@code N} separate arguments {@code A0, ...}.
+ *
Invoke the type-adjusted method handle on the unpacked arguments:
+ * MH1.invokeExact(A0, ...).
+ *
Take the return value as an {@code Object} reference.
+ *
+ *
+ * Because of the action of the {@code asType} step, the following argument
+ * conversions are applied as necessary:
+ *
+ *
reference casting
+ *
unboxing
+ *
widening primitive conversions
+ *
+ *
+ * The result returned by the call is boxed if it is a primitive,
+ * or forced to null if the return type is void.
+ *
+ * This call is equivalent to the following code:
+ *
+ * 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 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#spreadInvoker
+ */
+ public Object invokeWithArguments(Object... arguments) throws Throwable {
+ int argc = arguments == null ? 0 : arguments.length;
+ MethodType type = type();
+ if (type.parameterCount() != argc) {
+ // simulate invokeGeneric
+ return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
+ }
+ if (argc <= 10) {
+ MethodHandle invoker = type.invokers().genericInvoker();
+ switch (argc) {
+ case 0: return invoker.invokeExact(this);
+ case 1: return invoker.invokeExact(this,
+ arguments[0]);
+ case 2: return invoker.invokeExact(this,
+ arguments[0], arguments[1]);
+ case 3: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2]);
+ case 4: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3]);
+ case 5: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4]);
+ case 6: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4], arguments[5]);
+ case 7: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4], arguments[5],
+ arguments[6]);
+ case 8: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4], arguments[5],
+ arguments[6], arguments[7]);
+ case 9: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4], arguments[5],
+ arguments[6], arguments[7], arguments[8]);
+ case 10: return invoker.invokeExact(this,
+ arguments[0], arguments[1], arguments[2],
+ arguments[3], arguments[4], arguments[5],
+ arguments[6], arguments[7], arguments[8],
+ arguments[9]);
+ }
+ }
+
+ // more than ten arguments get boxed in a varargs list:
+ MethodHandle invoker = type.invokers().spreadInvoker(0);
+ return invoker.invokeExact(this, arguments);
+ }
+
+ /**
+ * Performs a varargs invocation, passing the arguments in the given array
+ * to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
+ * which mentions only the type {@code Object}, and whose arity is the length
+ * of the argument array.
+ *
+ * This method is also equivalent to the following code:
+ *
+ *
+ * @param arguments the arguments to pass to the target
+ * @return the result returned by the target
+ * @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
+ */
+ public Object invokeWithArguments(java.util.List> arguments) throws Throwable {
+ return invokeWithArguments(arguments.toArray());
+ }
+
+ /**
+ * Produces an adapter method handle which adapts the type of the
+ * current method handle to a new type.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ *
+ * If the original type and new type are equal, returns {@code this}.
+ *
+ * This method provides the crucial behavioral difference between
+ * {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. The two methods
+ * perform the same steps when the caller's type descriptor is identical
+ * with the callee's, but when the types differ, {@link #invokeGeneric invokeGeneric}
+ * also calls {@code asType} (or some internal equivalent) in order
+ * to match up the caller's and callee's types.
+ *
+ * This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
+ * 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
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
+ * @throws WrongMethodTypeException if the conversion cannot be made
+ * @see MethodHandles#convertArguments
+ */
+ public MethodHandle asType(MethodType newType) {
+ return MethodHandles.convertArguments(this, newType);
+ }
+
+ /**
+ * Makes 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 the original target,
+ * the original target is adapted to take the array elements directly,
+ * as if by a call to {@link #asType asType}.
+ *
+ * When called, the adapter replaces a trailing array argument
+ * by the array's elements, each as its own argument to the target.
+ * (The order of the arguments is preserved.)
+ * They are converted pairwise by casting and/or unboxing
+ * to the types of the trailing parameters of the target.
+ * Finally the target is called.
+ * What the target eventually returns is returned unchanged by the adapter.
+ *
+ * Before calling the target, the adapter verifies that the array
+ * contains exactly enough elements to provide a correct argument count
+ * to the target method handle.
+ * (The array may also be null when zero elements are required.)
+ * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
+ * @param arrayLength the number of arguments to spread from an incoming array argument
+ * @return a new method handle which spreads its final array argument,
+ * before calling the original method handle
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * @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 MethodHandle asSpreader(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 < arrayLength) throw newIllegalArgumentException("bad spread array length");
+ int keepPosArgs = nargs - arrayLength;
+ MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
+ newType = newType.insertParameterTypes(keepPosArgs, arrayType);
+ return MethodHandles.spreadArguments(this, newType);
+ }
+
+ /**
+ * Makes 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 the original target,
+ * the original target is adapted to take the array type directly,
+ * as if by a call to {@link #asType asType}.
+ *
+ * When called, the adapter replaces its trailing {@code arrayLength}
+ * arguments by a single new array of type {@code arrayType}, whose elements
+ * comprise (in order) the replaced arguments.
+ * Finally the target is called.
+ * What the target eventually returns is returned unchanged by the adapter.
+ *
+ * (The array may also be a shared constant when {@code arrayLength} is zero.)
+ *
+ * (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,
+ * or {@code arrayLength} is not a legal array size
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ * @see #asSpreader
+ * @see #asVarargsCollector
+ */
+ 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));
+ return MethodHandles.collectArguments(this, newType);
+ }
+
+ /**
+ * Makes 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:
+ *
+ * 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);
+ }
+
+ /**
+ * Determines if this method handle
+ * supports {@linkplain #asVarargsCollector variable arity} calls.
+ * Such method handles arise from the following sources:
+ *
+ *
a call to {@linkplain #asVarargsCollector asVarargsCollector}
+ *
a call to a {@linkplain java.lang.invoke.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
+ *
+ * @return true if this method handle accepts more than one arity of {@code invokeGeneric} calls
+ * @see #asVarargsCollector
+ */
+ public boolean isVarargsCollector() {
+ return false;
+ }
+
+ /**
+ * Binds a value {@code x} to the first argument of a method handle, without invoking it.
+ * The new method handle adapts, as its target,
+ * the current method handle by binding it to the given argument.
+ * The type of the bound handle will be
+ * the same as the type of the target, except that a single leading
+ * reference parameter will be omitted.
+ *
+ * When called, the bound handle inserts the given value {@code x}
+ * as a new leading argument to the target. The other arguments are
+ * also passed unchanged.
+ * What the target eventually returns is returned unchanged by the bound handle.
+ *
+ * The reference {@code x} must be convertible to the first parameter
+ * type of the target.
+ *
+ * (Note: Because method handles are immutable, the target method handle
+ * retains its original type and behavior.)
+ * @param x the value to bind to the first argument of the target
+ * @return a new method handle which prepends the given value to the incoming
+ * argument list, before calling the original method handle
+ * @throws IllegalArgumentException if the target does not have a
+ * leading parameter type that is a reference type
+ * @throws ClassCastException if {@code x} cannot be converted
+ * to the leading parameter type of the target
+ * @see MethodHandles#insertArguments
+ */
+ public MethodHandle bindTo(Object x) {
+ Class> ptype;
+ if (type().parameterCount() == 0 ||
+ (ptype = type().parameterType(0)).isPrimitive())
+ throw newIllegalArgumentException("no leading reference parameter", x);
+ x = MethodHandles.checkValue(ptype, x);
+ // Cf. MethodHandles.insertArguments for the following logic:
+ MethodHandle bmh = MethodHandleImpl.bindReceiver(this, x);
+ if (bmh != null) return bmh;
+ return MethodHandleImpl.bindArgument(this, 0, x);
+ }
+
+ /**
+ * 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 getNameString(this);
+ }
+}
diff -r fe27fe44ac51 -r afcc1530e68b src/share/classes/java/lang/invoke/MethodHandleImpl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Apr 08 10:27:23 2011 -0700
@@ -0,0 +1,1106 @@
+/*
+ * 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
+ * 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.lang.invoke;
+
+import sun.invoke.util.VerifyType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import sun.invoke.empty.Empty;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.Wrapper;
+import sun.misc.Unsafe;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * Trusted implementation code for MethodHandle.
+ * @author jrose
+ */
+/*non-public*/ abstract class MethodHandleImpl {
+ /// Factory methods to create method handles:
+
+ private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
+
+ static void initStatics() {
+ // Trigger preceding sequence.
+ }
+
+ /** Look up a given method.
+ * Callable only from sun.invoke and related packages.
+ *
+ * The resulting method handle type will be of the given type,
+ * with a receiver type {@code rcvc} prepended if the member is not static.
+ *
+ * Access checks are made as of the given lookup class.
+ * In particular, if the method is protected and {@code defc} is in a
+ * different package from the lookup class, then {@code rcvc} must be
+ * the lookup class or a subclass.
+ * @param token Proof that the lookup class has access to this package.
+ * @param member Resolved method or constructor to call.
+ * @param name Name of the desired method.
+ * @param rcvc Receiver type of desired non-static method (else null)
+ * @param doDispatch whether the method handle will test the receiver type
+ * @param lookupClass access-check relative to this class
+ * @return a direct handle to the matching method
+ * @throws IllegalAccessException if the given method cannot be accessed by the lookup class
+ */
+ static
+ MethodHandle findMethod(MemberName method,
+ boolean doDispatch, Class> lookupClass) throws IllegalAccessException {
+ MethodType mtype = method.getMethodType();
+ if (!method.isStatic()) {
+ // adjust the advertised receiver type to be exactly the one requested
+ // (in the case of invokespecial, this will be the calling class)
+ Class> recvType = method.getDeclaringClass();
+ mtype = mtype.insertParameterTypes(0, recvType);
+ }
+ DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
+ if (!mh.isValid())
+ throw method.makeAccessException("no access", lookupClass);
+ assert(mh.type() == mtype);
+ if (!method.isVarargs())
+ return mh;
+ else
+ return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
+ }
+
+ static
+ MethodHandle makeAllocator(MethodHandle rawConstructor) {
+ MethodType rawConType = rawConstructor.type();
+ // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
+ MethodHandle allocator
+ = AllocateObject.make(rawConType.parameterType(0), rawConstructor);
+ assert(allocator.type()
+ .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
+ return allocator;
+ }
+
+ static final class AllocateObject extends BoundMethodHandle {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ private final Class allocateClass;
+ private final MethodHandle rawConstructor;
+
+ private AllocateObject(MethodHandle invoker,
+ Class allocateClass, MethodHandle rawConstructor) {
+ super(invoker);
+ this.allocateClass = allocateClass;
+ this.rawConstructor = rawConstructor;
+ }
+ static MethodHandle make(Class> allocateClass, MethodHandle rawConstructor) {
+ MethodType rawConType = rawConstructor.type();
+ assert(rawConType.parameterType(0) == allocateClass);
+ MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
+ int nargs = rawConType.parameterCount() - 1;
+ if (nargs < INVOKES.length) {
+ MethodHandle invoke = INVOKES[nargs];
+ MethodType conType = CON_TYPES[nargs];
+ MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
+ if (gcon == null) return null;
+ MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
+ assert(galloc.type() == newType.generic());
+ return convertArguments(galloc, newType, galloc.type(), null);
+ } else {
+ MethodHandle invoke = VARARGS_INVOKE;
+ MethodType conType = CON_TYPES[nargs];
+ MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
+ if (gcon == null) return null;
+ MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
+ return collectArguments(galloc, newType, 1, null);
+ }
+ }
+ @Override
+ public String toString() {
+ return addTypeString(allocateClass.getSimpleName(), this);
+ }
+ @SuppressWarnings("unchecked")
+ private C allocate() throws InstantiationException {
+ return (C) unsafe.allocateInstance(allocateClass);
+ }
+ private C invoke_V(Object... av) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, av);
+ return obj;
+ }
+ private C invoke_L0() throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj);
+ return obj;
+ }
+ private C invoke_L1(Object a0) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0);
+ return obj;
+ }
+ private C invoke_L2(Object a0, Object a1) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1);
+ return obj;
+ }
+ private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2);
+ return obj;
+ }
+ private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3);
+ return obj;
+ }
+ private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4);
+ return obj;
+ }
+ private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
+ return obj;
+ }
+ private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
+ return obj;
+ }
+ private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
+ C obj = allocate();
+ rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
+ return obj;
+ }
+ static MethodHandle[] makeInvokes() {
+ ArrayList invokes = new ArrayList();
+ MethodHandles.Lookup lookup = IMPL_LOOKUP;
+ for (;;) {
+ int nargs = invokes.size();
+ String name = "invoke_L"+nargs;
+ MethodHandle invoke = null;
+ try {
+ invoke = lookup.findVirtual(AllocateObject.class, name, MethodType.genericMethodType(nargs));
+ } catch (ReflectiveOperationException ex) {
+ }
+ if (invoke == null) break;
+ invokes.add(invoke);
+ }
+ assert(invokes.size() == 9); // current number of methods
+ return invokes.toArray(new MethodHandle[0]);
+ };
+ static final MethodHandle[] INVOKES = makeInvokes();
+ // For testing use this:
+ //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
+ static final MethodHandle VARARGS_INVOKE;
+ static {
+ try {
+ VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
+ } catch (ReflectiveOperationException ex) {
+ throw uncaughtException(ex);
+ }
+ }
+ // Corresponding generic constructor types:
+ static final MethodType[] CON_TYPES = new MethodType[INVOKES.length];
+ static {
+ for (int i = 0; i < INVOKES.length; i++)
+ CON_TYPES[i] = makeConType(INVOKES[i]);
+ }
+ static final MethodType VARARGS_CON_TYPE = makeConType(VARARGS_INVOKE);
+ static MethodType makeConType(MethodHandle invoke) {
+ MethodType invType = invoke.type();
+ return invType.changeParameterType(0, Object.class).changeReturnType(void.class);
+ }
+ }
+
+ static
+ MethodHandle accessField(MemberName member, boolean isSetter,
+ Class> lookupClass) {
+ // Use sun. misc.Unsafe to dig up the dirt on the field.
+ MethodHandle mh = new FieldAccessor(member, isSetter);
+ return mh;
+ }
+
+ static
+ MethodHandle accessArrayElement(Class> arrayClass, boolean isSetter) {
+ if (!arrayClass.isArray())
+ throw newIllegalArgumentException("not an array: "+arrayClass);
+ Class> elemClass = arrayClass.getComponentType();
+ MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
+ if (mhs == null) {
+ if (!FieldAccessor.doCache(elemClass))
+ return FieldAccessor.ahandle(arrayClass, isSetter);
+ mhs = new MethodHandle[] {
+ FieldAccessor.ahandle(arrayClass, false),
+ FieldAccessor.ahandle(arrayClass, true)
+ };
+ if (mhs[0].type().parameterType(0) == Class.class) {
+ mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
+ mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
+ }
+ synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier
+ FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
+ }
+ return mhs[isSetter ? 1 : 0];
+ }
+
+ static final class FieldAccessor extends BoundMethodHandle {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ final Object base; // for static refs only
+ final long offset;
+ final String name;
+
+ FieldAccessor(MemberName field, boolean isSetter) {
+ super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
+ this.offset = (long) field.getVMIndex();
+ this.name = field.getName();
+ this.base = staticBase(field);
+ }
+ @Override
+ public String toString() { return addTypeString(name, this); }
+
+ int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
+ void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
+ long getFieldJ(C obj) { return unsafe.getLong(obj, offset); }
+ void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); }
+ float getFieldF(C obj) { return unsafe.getFloat(obj, offset); }
+ void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); }
+ double getFieldD(C obj) { return unsafe.getDouble(obj, offset); }
+ void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); }
+ boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); }
+ void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
+ byte getFieldB(C obj) { return unsafe.getByte(obj, offset); }
+ void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); }
+ short getFieldS(C obj) { return unsafe.getShort(obj, offset); }
+ void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); }
+ char getFieldC(C obj) { return unsafe.getChar(obj, offset); }
+ void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); }
+ @SuppressWarnings("unchecked")
+ V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); }
+ @SuppressWarnings("unchecked")
+ void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
+ // cast (V) is OK here, since we wrap convertArguments around the MH.
+
+ static Object staticBase(MemberName field) {
+ if (!field.isStatic()) return null;
+ Class c = field.getDeclaringClass();
+ java.lang.reflect.Field f;
+ try {
+ // FIXME: Should not have to create 'f' to get this value.
+ f = c.getDeclaredField(field.getName());
+ return unsafe.staticFieldBase(f);
+ } catch (Exception ee) {
+ throw uncaughtException(ee);
+ }
+ }
+
+ int getStaticI() { return unsafe.getInt(base, offset); }
+ void setStaticI(int x) { unsafe.putInt(base, offset, x); }
+ long getStaticJ() { return unsafe.getLong(base, offset); }
+ void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
+ float getStaticF() { return unsafe.getFloat(base, offset); }
+ void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
+ double getStaticD() { return unsafe.getDouble(base, offset); }
+ void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
+ boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
+ void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
+ byte getStaticB() { return unsafe.getByte(base, offset); }
+ void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
+ short getStaticS() { return unsafe.getShort(base, offset); }
+ void setStaticS(short x) { unsafe.putShort(base, offset, x); }
+ char getStaticC() { return unsafe.getChar(base, offset); }
+ void setStaticC(char x) { unsafe.putChar(base, offset, x); }
+ V getStaticL() { return (V) unsafe.getObject(base, offset); }
+ void setStaticL(V x) { unsafe.putObject(base, offset, x); }
+
+ static String fname(Class> vclass, boolean isSetter, boolean isStatic) {
+ String stem;
+ if (!isStatic)
+ stem = (!isSetter ? "getField" : "setField");
+ else
+ stem = (!isSetter ? "getStatic" : "setStatic");
+ return stem + Wrapper.basicTypeChar(vclass);
+ }
+ static MethodType ftype(Class> cclass, Class> vclass, boolean isSetter, boolean isStatic) {
+ MethodType type;
+ if (!isStatic) {
+ if (!isSetter)
+ return MethodType.methodType(vclass, cclass);
+ else
+ return MethodType.methodType(void.class, cclass, vclass);
+ } else {
+ if (!isSetter)
+ return MethodType.methodType(vclass);
+ else
+ return MethodType.methodType(void.class, vclass);
+ }
+ }
+ static MethodHandle fhandle(Class> cclass, Class> vclass, boolean isSetter, boolean isStatic) {
+ String name = FieldAccessor.fname(vclass, isSetter, isStatic);
+ if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass);
+ Class> ecclass = Object.class; //erase this type
+ Class> evclass = vclass;
+ if (!evclass.isPrimitive()) evclass = Object.class;
+ MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
+ MethodHandle mh;
+ try {
+ mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
+ } catch (ReflectiveOperationException ex) {
+ throw uncaughtException(ex);
+ }
+ if (evclass != vclass || (!isStatic && ecclass != cclass)) {
+ MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
+ strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
+ mh = MethodHandles.convertArguments(mh, strongType);
+ }
+ return mh;
+ }
+
+ /// Support for array element access
+ static final HashMap, MethodHandle[]> ARRAY_CACHE =
+ new HashMap, MethodHandle[]>();
+ // FIXME: Cache on the classes themselves, not here.
+ static boolean doCache(Class> elemClass) {
+ if (elemClass.isPrimitive()) return true;
+ ClassLoader cl = elemClass.getClassLoader();
+ return cl == null || cl == ClassLoader.getSystemClassLoader();
+ }
+ static int getElementI(int[] a, int i) { return a[i]; }
+ static void setElementI(int[] a, int i, int x) { a[i] = x; }
+ static long getElementJ(long[] a, int i) { return a[i]; }
+ static void setElementJ(long[] a, int i, long x) { a[i] = x; }
+ static float getElementF(float[] a, int i) { return a[i]; }
+ static void setElementF(float[] a, int i, float x) { a[i] = x; }
+ static double getElementD(double[] a, int i) { return a[i]; }
+ static void setElementD(double[] a, int i, double x) { a[i] = x; }
+ static boolean getElementZ(boolean[] a, int i) { return a[i]; }
+ static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
+ static byte getElementB(byte[] a, int i) { return a[i]; }
+ static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
+ static short getElementS(short[] a, int i) { return a[i]; }
+ static void setElementS(short[] a, int i, short x) { a[i] = x; }
+ static char getElementC(char[] a, int i) { return a[i]; }
+ static void setElementC(char[] a, int i, char x) { a[i] = x; }
+ static Object getElementL(Object[] a, int i) { return a[i]; }
+ static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
+ static V getElementL(Class aclass, V[] a, int i) { return aclass.cast(a)[i]; }
+ static void setElementL(Class aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
+
+ static String aname(Class> aclass, boolean isSetter) {
+ Class> vclass = aclass.getComponentType();
+ if (vclass == null) throw new IllegalArgumentException();
+ return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
+ }
+ static MethodType atype(Class> aclass, boolean isSetter) {
+ Class> vclass = aclass.getComponentType();
+ if (!isSetter)
+ return MethodType.methodType(vclass, aclass, int.class);
+ else
+ return MethodType.methodType(void.class, aclass, int.class, vclass);
+ }
+ static MethodHandle ahandle(Class> aclass, boolean isSetter) {
+ Class> vclass = aclass.getComponentType();
+ String name = FieldAccessor.aname(aclass, isSetter);
+ Class> caclass = null;
+ if (!vclass.isPrimitive() && vclass != Object.class) {
+ caclass = aclass;
+ aclass = Object[].class;
+ vclass = Object.class;
+ }
+ MethodType type = FieldAccessor.atype(aclass, isSetter);
+ if (caclass != null)
+ type = type.insertParameterTypes(0, Class.class);
+ MethodHandle mh;
+ try {
+ mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
+ } catch (ReflectiveOperationException ex) {
+ throw uncaughtException(ex);
+ }
+ if (caclass != null) {
+ MethodType strongType = FieldAccessor.atype(caclass, isSetter);
+ mh = MethodHandles.insertArguments(mh, 0, caclass);
+ mh = MethodHandles.convertArguments(mh, strongType);
+ }
+ return mh;
+ }
+ }
+
+ /** Bind a predetermined first argument to the given direct method handle.
+ * Callable only from MethodHandles.
+ * @param token Proof that the caller has access to this package.
+ * @param target Any direct method handle.
+ * @param receiver Receiver (or first static method argument) to pre-bind.
+ * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
+ */
+ static
+ MethodHandle bindReceiver(MethodHandle target, Object receiver) {
+ if (target instanceof AdapterMethodHandle &&
+ ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
+ ) {
+ Object info = MethodHandleNatives.getTargetInfo(target);
+ if (info instanceof DirectMethodHandle) {
+ DirectMethodHandle dmh = (DirectMethodHandle) info;
+ if (receiver == null ||
+ dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
+ MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
+ MethodType newType = target.type().dropParameterTypes(0, 1);
+ return convertArguments(bmh, newType, bmh.type(), null);
+ }
+ }
+ }
+ if (target instanceof DirectMethodHandle)
+ return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
+ return null; // let caller try something else
+ }
+
+ /** Bind a predetermined argument to the given arbitrary method handle.
+ * Callable only from MethodHandles.
+ * @param token Proof that the caller has access to this package.
+ * @param target Any method handle.
+ * @param receiver Argument (which can be a boxed primitive) to pre-bind.
+ * @return a suitable BoundMethodHandle
+ */
+ static
+ MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
+ return new BoundMethodHandle(target, receiver, argnum);
+ }
+
+ static MethodHandle convertArguments(MethodHandle target,
+ MethodType newType,
+ MethodType oldType,
+ int[] permutationOrNull) {
+ assert(oldType.parameterCount() == target.type().parameterCount());
+ if (permutationOrNull != null) {
+ int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
+ if (permutationOrNull.length != outargs)
+ throw newIllegalArgumentException("wrong number of arguments in permutation");
+ // Make the individual outgoing argument types match up first.
+ Class>[] callTypeArgs = new Class>[outargs];
+ for (int i = 0; i < outargs; i++)
+ callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
+ MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
+ target = convertArguments(target, callType, oldType, null);
+ assert(target != null);
+ oldType = target.type();
+ List goal = new ArrayList(); // i*TOKEN
+ List state = new ArrayList(); // i*TOKEN
+ List drops = new ArrayList(); // not tokens
+ List dups = new ArrayList(); // not tokens
+ final int TOKEN = 10; // to mark items which are symbolic only
+ // state represents the argument values coming into target
+ for (int i = 0; i < outargs; i++) {
+ state.add(permutationOrNull[i] * TOKEN);
+ }
+ // goal represents the desired state
+ for (int i = 0; i < inargs; i++) {
+ if (state.contains(i * TOKEN)) {
+ goal.add(i * TOKEN);
+ } else {
+ // adapter must initially drop all unused arguments
+ drops.add(i);
+ }
+ }
+ // detect duplications
+ while (state.size() > goal.size()) {
+ for (int i2 = 0; i2 < state.size(); i2++) {
+ int arg1 = state.get(i2);
+ int i1 = state.indexOf(arg1);
+ if (i1 != i2) {
+ // found duplicate occurrence at i2
+ int arg2 = (inargs++) * TOKEN;
+ state.set(i2, arg2);
+ dups.add(goal.indexOf(arg1));
+ goal.add(arg2);
+ }
+ }
+ }
+ assert(state.size() == goal.size());
+ int size = goal.size();
+ while (!state.equals(goal)) {
+ // Look for a maximal sequence of adjacent misplaced arguments,
+ // and try to rotate them into place.
+ int bestRotArg = -10 * TOKEN, bestRotLen = 0;
+ int thisRotArg = -10 * TOKEN, thisRotLen = 0;
+ for (int i = 0; i < size; i++) {
+ int arg = state.get(i);
+ // Does this argument match the current run?
+ if (arg == thisRotArg + TOKEN) {
+ thisRotArg = arg;
+ thisRotLen += 1;
+ if (bestRotLen < thisRotLen) {
+ bestRotLen = thisRotLen;
+ bestRotArg = thisRotArg;
+ }
+ } else {
+ // The old sequence (if any) stops here.
+ thisRotLen = 0;
+ thisRotArg = -10 * TOKEN;
+ // But maybe a new one starts here also.
+ int wantArg = goal.get(i);
+ final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
+ if (arg != wantArg &&
+ arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
+ arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
+ thisRotArg = arg;
+ thisRotLen = 1;
+ }
+ }
+ }
+ if (bestRotLen >= 2) {
+ // Do a rotation if it can improve argument positioning
+ // by at least 2 arguments. This is not always optimal,
+ // but it seems to catch common cases.
+ int dstEnd = state.indexOf(bestRotArg);
+ int srcEnd = goal.indexOf(bestRotArg);
+ int rotBy = dstEnd - srcEnd;
+ int dstBeg = dstEnd - (bestRotLen - 1);
+ int srcBeg = srcEnd - (bestRotLen - 1);
+ assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
+ // Make a span which covers both source and destination.
+ int rotBeg = Math.min(dstBeg, srcBeg);
+ int rotEnd = Math.max(dstEnd, srcEnd);
+ int score = 0;
+ for (int i = rotBeg; i <= rotEnd; i++) {
+ if ((int)state.get(i) != (int)goal.get(i))
+ score += 1;
+ }
+ List rotSpan = state.subList(rotBeg, rotEnd+1);
+ Collections.rotate(rotSpan, -rotBy); // reverse direction
+ for (int i = rotBeg; i <= rotEnd; i++) {
+ if ((int)state.get(i) != (int)goal.get(i))
+ score -= 1;
+ }
+ if (score >= 2) {
+ // Improved at least two argument positions. Do it.
+ List> ptypes = Arrays.asList(oldType.parameterArray());
+ Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
+ MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
+ MethodHandle nextTarget
+ = AdapterMethodHandle.makeRotateArguments(rotType, target,
+ rotBeg, rotSpan.size(), rotBy);
+ if (nextTarget != null) {
+ //System.out.println("Rot: "+rotSpan+" by "+rotBy);
+ target = nextTarget;
+ oldType = rotType;
+ continue;
+ }
+ }
+ // Else de-rotate, and drop through to the swap-fest.
+ Collections.rotate(rotSpan, rotBy);
+ }
+
+ // Now swap like the wind!
+ List> ptypes = Arrays.asList(oldType.parameterArray());
+ for (int i = 0; i < size; i++) {
+ // What argument do I want here?
+ int arg = goal.get(i);
+ if (arg != state.get(i)) {
+ // Where is it now?
+ int j = state.indexOf(arg);
+ Collections.swap(ptypes, i, j);
+ MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
+ target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
+ if (target == null) throw newIllegalArgumentException("cannot swap");
+ assert(target.type() == swapType);
+ oldType = swapType;
+ Collections.swap(state, i, j);
+ }
+ }
+ // One pass of swapping must finish the job.
+ assert(state.equals(goal));
+ }
+ while (!dups.isEmpty()) {
+ // Grab a contiguous trailing sequence of dups.
+ int grab = dups.size() - 1;
+ int dupArgPos = dups.get(grab), dupArgCount = 1;
+ while (grab - 1 >= 0) {
+ int dup0 = dups.get(grab - 1);
+ if (dup0 != dupArgPos - 1) break;
+ dupArgPos -= 1;
+ dupArgCount += 1;
+ grab -= 1;
+ }
+ //if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
+ dups.subList(grab, dups.size()).clear();
+ // In the new target type drop that many args from the tail:
+ List> ptypes = oldType.parameterList();
+ ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
+ MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
+ target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
+ if (target == null)
+ throw newIllegalArgumentException("cannot dup");
+ oldType = target.type();
+ }
+ while (!drops.isEmpty()) {
+ // Grab a contiguous initial sequence of drops.
+ int dropArgPos = drops.get(0), dropArgCount = 1;
+ while (dropArgCount < drops.size()) {
+ int drop1 = drops.get(dropArgCount);
+ if (drop1 != dropArgPos + dropArgCount) break;
+ dropArgCount += 1;
+ }
+ //if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount));
+ drops.subList(0, dropArgCount).clear();
+ List> dropTypes = newType.parameterList()
+ .subList(dropArgPos, dropArgPos + dropArgCount);
+ MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
+ target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
+ if (target == null) throw newIllegalArgumentException("cannot drop");
+ oldType = target.type();
+ }
+ }
+ if (newType == oldType)
+ return target;
+ if (oldType.parameterCount() != newType.parameterCount())
+ throw newIllegalArgumentException("mismatched parameter count");
+ MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
+ if (res != null)
+ return res;
+ int argc = oldType.parameterCount();
+ // The JVM can't do it directly, so fill in the gap with a Java adapter.
+ // TO DO: figure out what to put here from case-by-case experience
+ // Use a heavier method: Convert all the arguments to Object,
+ // then back to the desired types. We might have to use Java-based
+ // method handles to do this.
+ MethodType objType = MethodType.genericMethodType(argc);
+ MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
+ if (objTarget == null)
+ objTarget = FromGeneric.make(target);
+ res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
+ if (res != null)
+ return res;
+ return ToGeneric.make(newType, objTarget);
+ }
+
+ static MethodHandle spreadArguments(MethodHandle target,
+ MethodType newType,
+ int spreadArg) {
+ // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
+ MethodType oldType = target.type();
+ // spread the last argument of newType to oldType
+ int spreadCount = oldType.parameterCount() - spreadArg;
+ Class