Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
bd11b4f3
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
bd11b4f3
编写于
6月 04, 2011
作者:
M
mullan
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
ddbee460
6fa56bb2
变更
93
显示空白变更内容
内联
并排
Showing
93 changed file
with
2299 addition
and
1377 deletion
+2299
-1377
.hgtags
.hgtags
+1
-0
make/common/Defs-embedded.gmk
make/common/Defs-embedded.gmk
+11
-0
make/common/Release-embedded.gmk
make/common/Release-embedded.gmk
+19
-21
src/linux/doc/man/ja/keytool.1
src/linux/doc/man/ja/keytool.1
+1
-1
src/linux/doc/man/keytool.1
src/linux/doc/man/keytool.1
+1
-1
src/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk.properties
...sses/com/sun/java/swing/plaf/gtk/resources/gtk.properties
+4
-4
src/share/classes/java/awt/Toolkit.java
src/share/classes/java/awt/Toolkit.java
+5
-5
src/share/classes/java/io/SerialCallbackContext.java
src/share/classes/java/io/SerialCallbackContext.java
+1
-3
src/share/classes/java/lang/BootstrapMethodError.java
src/share/classes/java/lang/BootstrapMethodError.java
+2
-2
src/share/classes/java/lang/ClassValue.java
src/share/classes/java/lang/ClassValue.java
+9
-1
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
+79
-20
src/share/classes/java/lang/invoke/BoundMethodHandle.java
src/share/classes/java/lang/invoke/BoundMethodHandle.java
+2
-2
src/share/classes/java/lang/invoke/CallSite.java
src/share/classes/java/lang/invoke/CallSite.java
+23
-3
src/share/classes/java/lang/invoke/ConstantCallSite.java
src/share/classes/java/lang/invoke/ConstantCallSite.java
+45
-2
src/share/classes/java/lang/invoke/FilterGeneric.java
src/share/classes/java/lang/invoke/FilterGeneric.java
+1
-1
src/share/classes/java/lang/invoke/FilterOneArgument.java
src/share/classes/java/lang/invoke/FilterOneArgument.java
+1
-1
src/share/classes/java/lang/invoke/FromGeneric.java
src/share/classes/java/lang/invoke/FromGeneric.java
+1
-1
src/share/classes/java/lang/invoke/InvokeGeneric.java
src/share/classes/java/lang/invoke/InvokeGeneric.java
+6
-9
src/share/classes/java/lang/invoke/Invokers.java
src/share/classes/java/lang/invoke/Invokers.java
+33
-19
src/share/classes/java/lang/invoke/MemberName.java
src/share/classes/java/lang/invoke/MemberName.java
+13
-3
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+334
-189
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+106
-28
src/share/classes/java/lang/invoke/MethodHandleNatives.java
src/share/classes/java/lang/invoke/MethodHandleNatives.java
+1
-1
src/share/classes/java/lang/invoke/MethodHandleProxies.java
src/share/classes/java/lang/invoke/MethodHandleProxies.java
+257
-0
src/share/classes/java/lang/invoke/MethodHandleStatics.java
src/share/classes/java/lang/invoke/MethodHandleStatics.java
+2
-0
src/share/classes/java/lang/invoke/MethodHandles.java
src/share/classes/java/lang/invoke/MethodHandles.java
+326
-534
src/share/classes/java/lang/invoke/MethodType.java
src/share/classes/java/lang/invoke/MethodType.java
+68
-12
src/share/classes/java/lang/invoke/MethodTypeForm.java
src/share/classes/java/lang/invoke/MethodTypeForm.java
+2
-0
src/share/classes/java/lang/invoke/MutableCallSite.java
src/share/classes/java/lang/invoke/MutableCallSite.java
+7
-4
src/share/classes/java/lang/invoke/SpreadGeneric.java
src/share/classes/java/lang/invoke/SpreadGeneric.java
+2
-2
src/share/classes/java/lang/invoke/SwitchPoint.java
src/share/classes/java/lang/invoke/SwitchPoint.java
+19
-4
src/share/classes/java/lang/invoke/ToGeneric.java
src/share/classes/java/lang/invoke/ToGeneric.java
+2
-2
src/share/classes/java/lang/invoke/package-info.java
src/share/classes/java/lang/invoke/package-info.java
+30
-292
src/share/classes/java/nio/file/Path.java
src/share/classes/java/nio/file/Path.java
+8
-10
src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
...re/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
+4
-0
src/share/classes/javax/swing/text/Utilities.java
src/share/classes/javax/swing/text/Utilities.java
+33
-8
src/share/classes/sun/font/FileFontStrike.java
src/share/classes/sun/font/FileFontStrike.java
+0
-1
src/share/classes/sun/font/FontScaler.java
src/share/classes/sun/font/FontScaler.java
+0
-1
src/share/classes/sun/font/FreetypeFontScaler.java
src/share/classes/sun/font/FreetypeFontScaler.java
+3
-3
src/share/classes/sun/font/NullFontScaler.java
src/share/classes/sun/font/NullFontScaler.java
+1
-1
src/share/classes/sun/invoke/util/ValueConversions.java
src/share/classes/sun/invoke/util/ValueConversions.java
+7
-4
src/share/classes/sun/invoke/util/VerifyAccess.java
src/share/classes/sun/invoke/util/VerifyAccess.java
+33
-7
src/share/classes/sun/invoke/util/Wrapper.java
src/share/classes/sun/invoke/util/Wrapper.java
+2
-4
src/share/classes/sun/io/ByteToCharCp833.java
src/share/classes/sun/io/ByteToCharCp833.java
+1
-1
src/share/classes/sun/io/CharToByteCp833.java
src/share/classes/sun/io/CharToByteCp833.java
+1
-1
src/share/classes/sun/misc/FpUtils.java
src/share/classes/sun/misc/FpUtils.java
+1
-1
src/share/classes/sun/security/provider/certpath/URICertStore.java
.../classes/sun/security/provider/certpath/URICertStore.java
+1
-1
src/share/native/sun/font/freetypeScaler.c
src/share/native/sun/font/freetypeScaler.c
+1
-1
src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java
src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java
+27
-5
src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
+2
-2
src/solaris/doc/sun/man/man1/ja/keytool.1
src/solaris/doc/sun/man/man1/ja/keytool.1
+1
-1
src/solaris/doc/sun/man/man1/keytool.1
src/solaris/doc/sun/man/man1/keytool.1
+1
-1
src/solaris/native/sun/java2d/x11/XRBackendNative.c
src/solaris/native/sun/java2d/x11/XRBackendNative.c
+114
-15
src/windows/native/sun/windows/awt_Component.cpp
src/windows/native/sun/windows/awt_Component.cpp
+4
-1
src/windows/native/sun/windows/awt_Object.cpp
src/windows/native/sun/windows/awt_Object.cpp
+4
-1
src/windows/native/sun/windows/awt_Toolkit.cpp
src/windows/native/sun/windows/awt_Toolkit.cpp
+3
-1
test/com/sun/net/httpserver/Test10.java
test/com/sun/net/httpserver/Test10.java
+1
-1
test/java/awt/List/ScrollOutside/ScrollOut.java
test/java/awt/List/ScrollOutside/ScrollOut.java
+1
-1
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java
.../MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java
+1
-1
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java
...ouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java
+1
-1
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java
...ouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java
+1
-1
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java
...ouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java
+1
-1
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java
...ouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java
+1
-1
test/java/awt/image/IncorrectSampleMaskTest.java
test/java/awt/image/IncorrectSampleMaskTest.java
+5
-5
test/java/lang/invoke/6991596/Test6991596.java
test/java/lang/invoke/6991596/Test6991596.java
+2
-2
test/java/lang/invoke/6998541/Test6998541.java
test/java/lang/invoke/6998541/Test6998541.java
+2
-10
test/java/lang/invoke/InvokeDynamicPrintArgs.java
test/java/lang/invoke/InvokeDynamicPrintArgs.java
+49
-10
test/java/lang/invoke/InvokeGenericTest.java
test/java/lang/invoke/InvokeGenericTest.java
+42
-15
test/java/lang/invoke/JavaDocExamplesTest.java
test/java/lang/invoke/JavaDocExamplesTest.java
+296
-24
test/java/lang/invoke/MethodHandlesTest.java
test/java/lang/invoke/MethodHandlesTest.java
+79
-40
test/java/lang/invoke/MethodTypeTest.java
test/java/lang/invoke/MethodTypeTest.java
+5
-7
test/java/lang/invoke/indify/Indify.java
test/java/lang/invoke/indify/Indify.java
+2
-0
test/java/rmi/server/UnicastRemoteObject/exportObject/GcDuringExport.java
...rver/UnicastRemoteObject/exportObject/GcDuringExport.java
+1
-1
test/java/util/EnumMap/DistinctEntrySetElements.java
test/java/util/EnumMap/DistinctEntrySetElements.java
+1
-1
test/java/util/EnumMap/EntrySetIteratorRemoveInvalidatesEntry.java
.../util/EnumMap/EntrySetIteratorRemoveInvalidatesEntry.java
+1
-1
test/java/util/EnumMap/SimpleSerialization.java
test/java/util/EnumMap/SimpleSerialization.java
+1
-1
test/java/util/EnumSet/LargeEnumIteratorRemoveResilience.java
.../java/util/EnumSet/LargeEnumIteratorRemoveResilience.java
+1
-1
test/java/util/EnumSet/SmallEnumIteratorRemoveResilience.java
.../java/util/EnumSet/SmallEnumIteratorRemoveResilience.java
+1
-1
test/java/util/Hashtable/SerializationDeadlock.java
test/java/util/Hashtable/SerializationDeadlock.java
+1
-1
test/java/util/Hashtable/SimpleSerialization.java
test/java/util/Hashtable/SimpleSerialization.java
+1
-1
test/java/util/IdentityHashMap/DistinctEntrySetElements.java
test/java/util/IdentityHashMap/DistinctEntrySetElements.java
+1
-1
test/java/util/IdentityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java
...entityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java
+1
-1
test/java/util/Vector/SerializationDeadlock.java
test/java/util/Vector/SerializationDeadlock.java
+1
-1
test/java/util/Vector/SimpleSerialization.java
test/java/util/Vector/SimpleSerialization.java
+1
-1
test/java/util/concurrent/ConcurrentHashMap/DistinctEntrySetElements.java
...oncurrent/ConcurrentHashMap/DistinctEntrySetElements.java
+1
-1
test/java/util/zip/ZipFile/ClearStaleZipFileInputStreams.java
.../java/util/zip/ZipFile/ClearStaleZipFileInputStreams.java
+1
-1
test/javax/swing/plaf/nimbus/Test7048204.java
test/javax/swing/plaf/nimbus/Test7048204.java
+47
-0
test/javax/swing/text/Utilities/bug7045593.java
test/javax/swing/text/Utilities/bug7045593.java
+78
-0
test/sun/net/InetAddress/nameservice/chaining/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor
...NF/services/sun.net.spi.nameservice.NameServiceDescriptor
+1
-1
test/tools/launcher/TestHelper.java
test/tools/launcher/TestHelper.java
+1
-1
test/tools/pack200/CommandLineTests.java
test/tools/pack200/CommandLineTests.java
+1
-1
test/tools/pack200/Pack200Test.java
test/tools/pack200/Pack200Test.java
+1
-1
test/tools/pack200/Utils.java
test/tools/pack200/Utils.java
+1
-1
未找到文件。
.hgtags
浏览文件 @
bd11b4f3
...
...
@@ -118,3 +118,4 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143
23bdcede4e3945894574892e80b848bd9f15b5f3 jdk7-b144
make/common/Defs-embedded.gmk
浏览文件 @
bd11b4f3
...
...
@@ -49,5 +49,16 @@ RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX)
JRE_REDUCED_HEADLESS_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-headless-image
JRE_REDUCED_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-image
# Override on linux to further reduce binary/lib sizes in product build
ifeq ($(PLATFORM), linux)
ifeq ($(VARIANT), OPT)
ifneq ($(NO_STRIP), true)
ifneq ($(DEBUG_BINARIES), true)
POST_STRIP_PROCESS = $(STRIP) --strip-unneeded
endif
endif
endif
endif
endif # JAVASE_EMBEDDED
make/common/Release-embedded.gmk
浏览文件 @
bd11b4f3
...
...
@@ -53,25 +53,30 @@ $(NOT_HEADLESS_RT_JAR_LIST): $(NOT_RT_JAR_LIST)
$(RM) $(HEADLESS_CLASSLIST)
$(RM) $(NOT_HEADLESS_RT_JAR_LIST)
$(CP) $(NOT_RT_JAR_LIST) $(NOT_HEADLESS_RT_JAR_LIST)
# List all the packages to be excluded
$(ECHO) "sun/awt/motif/" >> $@
$(ECHO) "sun/awt/X11/" >> $@
$(ECHO) "sun/applet/" >> $@
$(ECHO) "sun/java2d/opengl/" >> $@
$(ECHO) "com/sun/java/swing/plaf/" >> $@
$(ECHO) "sun/awt/motif/MFontConfiguration" >$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppContextCreator" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppletAudioClip" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXVolatileSurfaceManager" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/OGLSurfaceData" >>$(HEADLESS_CLASSLIST)
# List all the individual classes to be included
$(ECHO) "sun/awt/motif/MFontConfiguration.class" >$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppContextCreator.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppletAudioClip.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXVolatileSurfaceManager.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/OGLSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(TOTAL_HEADLESS_JAR_FILELIST): $(JARREORDER_JARFILE) $(NOT_HEADLESS_RT_JAR_LIST)
$(prep-target)
$(RM) $@.temp
$(CD) $(CLASSBINDIR) ; \
$(BOOT_JAVA_CMD) -jar $(JARREORDER_JARFILE) \
-o $@.temp $(HEADLESS_CLASSLIST) $(NOT_HEADLESS_RT_JAR_LIST) .
-o $@.temp - $(NOT_HEADLESS_RT_JAR_LIST) .
# Add on the explicitly included class files from the otherwise excluded packages
$(CAT) $(HEADLESS_CLASSLIST) >> $@.temp
$(MV) $@.temp $@
@$(CD) $(CLASSBINDIR); $(java-vm-cleanup)
...
...
@@ -124,13 +129,9 @@ NOT_REDUCEDJRE_LIB = \
$(LIBARCH)/libjavaplugin_nscp.so \
$(LIBARCH)/libjavaplugin_oji.so
ifeq ($(PLATFORM), linux)
STRIP_OPTS = --strip-unneeded
else
STRIP_OPTS = -x
endif
# JRE docs that don't get included in reduced jre image top directory
NOT_REDUCEDJRE_DOC = \
Welcome.html
reduced-image-jre::
@$(ECHO) Starting to Produce Reduced JRE
...
...
@@ -142,12 +143,6 @@ reduced-image-jre::
$(CD) $(JRE_IMAGE_DIR); \
$(TAR) cf - . | ($(CD) $(JRE_REDUCED_IMAGE_DIR); $(TAR) xf - );
@# strip the main .so files
$(STRIP) $(STRIP_OPTS) $(JRE_REDUCED_IMAGE_DIR)/lib/$(LIBARCH)/client/libjvm.so
ifndef BUILD_CLIENT_ONLY
$(STRIP) $(STRIP_OPTS) $(JRE_REDUCED_IMAGE_DIR)/lib/$(LIBARCH)/server/libjvm.so
endif
@#
@# Remove all of the files that are not needed for the
@# reduced JRE
...
...
@@ -158,6 +153,9 @@ endif
for l in $(NOT_REDUCEDJRE_LIB) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/lib/$$l ; \
done
for l in $(NOT_REDUCEDJRE_DOC) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/$$l ; \
done
@# Remove misc. other files
$(RM) -r $(JRE_REDUCED_IMAGE_DIR)/man
...
...
src/linux/doc/man/ja/keytool.1
浏览文件 @
bd11b4f3
." Copyright (c) 1998
-2011 keytool tool
, Oracle and/or its affiliates. All rights reserved.
." Copyright (c) 1998
, 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
...
...
src/linux/doc/man/keytool.1
浏览文件 @
bd11b4f3
." Copyright (c) 1998
-2011 keytool tool
, Oracle and/or its affiliates. All rights reserved.
." Copyright (c) 1998
, 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
...
...
src/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk.properties
浏览文件 @
bd11b4f3
...
...
@@ -56,9 +56,9 @@ FileChooser.deleteFileButtonMnemonic=76
FileChooser.renameFileButtonText
=
Rename File
FileChooser.renameFileButtonMnemonic
=
82
FileChooser.cancelButtonText
=
Cancel
#
FileChooser.cancelButtonMnemonic=67
FileChooser.cancelButtonMnemonic
=
67
FileChooser.saveButtonText
=
OK
#
FileChooser.saveButtonMnemonic=79
FileChooser.saveButtonMnemonic
=
79
FileChooser.openButtonText
=
OK
FileChooser.openButtonMnemonic
=
79
FileChooser.saveDialogTitleText
=
Save
...
...
@@ -79,5 +79,5 @@ FileChooser.renameFileDialogText=Rename file "{0}" to
FileChooser.renameFileErrorTitle
=
Error
FileChooser.renameFileErrorText
=
Error renaming file "{0}" to "{1}"
#
OptionPane.okButtonMnemonic=79
#
OptionPane.cancelButtonMnemonic=67
OptionPane.okButtonMnemonic
=
79
OptionPane.cancelButtonMnemonic
=
67
src/share/classes/java/awt/Toolkit.java
浏览文件 @
bd11b4f3
...
...
@@ -1857,7 +1857,7 @@ public abstract class Toolkit {
/**
* Adds the specified property change listener for the named desktop
* property. When a {@link PropertyChangeListenerProxy} object is added,
* property. When a {@link
java.beans.
PropertyChangeListenerProxy} object is added,
* its property name is ignored, and the wrapped listener is added.
* If {@code name} is {@code null} or {@code pcl} is {@code null},
* no exception is thrown and no action is performed.
...
...
@@ -1874,7 +1874,7 @@ public abstract class Toolkit {
/**
* Removes the specified property change listener for the named
* desktop property. When a {@link PropertyChangeListenerProxy} object
* desktop property. When a {@link
java.beans.
PropertyChangeListenerProxy} object
* is removed, its property name is ignored, and
* the wrapped listener is removed.
* If {@code name} is {@code null} or {@code pcl} is {@code null},
...
...
@@ -1893,11 +1893,11 @@ public abstract class Toolkit {
/**
* Returns an array of all the property change listeners
* registered on this toolkit. The returned array
* contains {@
code
PropertyChangeListenerProxy} objects
* contains {@
link java.beans.
PropertyChangeListenerProxy} objects
* that associate listeners with the names of desktop properties.
*
* @return all of this toolkit's {@
code
PropertyChangeListener}
* objects wrapped in {@code PropertyChangeListenerProxy} objects
* @return all of this toolkit's {@
link
PropertyChangeListener}
* objects wrapped in {@code
java.beans.
PropertyChangeListenerProxy} objects
* or an empty array if no listeners are added
*
* @see PropertyChangeSupport#getPropertyChangeListeners()
...
...
src/share/classes/java/io/SerialCallbackContext.java
浏览文件 @
bd11b4f3
/*
* %W% %E%
*
* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
...
...
src/share/classes/java/lang/BootstrapMethodError.java
浏览文件 @
bd11b4f3
...
...
@@ -39,14 +39,14 @@ public class BootstrapMethodError extends LinkageError {
private
static
final
long
serialVersionUID
=
292L
;
/**
* Constructs a
n
{@code BootstrapMethodError} with no detail message.
* Constructs a {@code BootstrapMethodError} with no detail message.
*/
public
BootstrapMethodError
()
{
super
();
}
/**
* Constructs a
n
{@code BootstrapMethodError} with the specified
* Constructs a {@code BootstrapMethodError} with the specified
* detail message.
*
* @param s the detail message.
...
...
src/share/classes/java/lang/ClassValue.java
浏览文件 @
bd11b4f3
...
...
@@ -38,6 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* @since 1.7
*/
public
abstract
class
ClassValue
<
T
>
{
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected
ClassValue
()
{
}
/**
* Computes the given class's derived value for this {@code ClassValue}.
* <p>
...
...
@@ -100,7 +107,7 @@ public abstract class ClassValue<T> {
* 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.
* {@code computeValue} method for the given class.
* <p>
* 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
...
...
@@ -193,6 +200,7 @@ public abstract class ClassValue<T> {
=
new
WeakHashMap
<
Class
<?>,
ClassValueMap
>();
private
static
ClassValueMap
getMap
(
Class
<?>
type
)
{
type
.
getClass
();
// test for null
return
ROOT
.
get
(
type
);
}
...
...
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
浏览文件 @
bd11b4f3
...
...
@@ -29,6 +29,8 @@ import sun.invoke.util.VerifyType;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.ValueConversions
;
import
java.util.Arrays
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
...
...
@@ -62,7 +64,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// 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
?
* argument conversions, as if by
fixed-arity MethodHandle.asType
?
*/
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
,
int
level
)
{
// same number of args, of course
...
...
@@ -92,7 +94,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by
MethodHandles.convertArguments
?
* argument conversion, as if by
fixed-arity MethodHandle.asType
?
*/
static
boolean
canConvertArgument
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
...
...
@@ -141,7 +143,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
while
(
lastConv
>=
0
)
{
Class
<?>
src
=
newType
.
parameterType
(
lastConv
);
// source type
Class
<?>
dst
=
oldType
.
parameterType
(
lastConv
);
// destination type
if
(
VerifyType
.
isNullConversion
(
src
,
dst
))
{
if
(
isTrivialConversion
(
src
,
dst
,
level
))
{
--
lastConv
;
}
else
{
break
;
...
...
@@ -150,7 +152,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class
<?>
needReturn
=
newType
.
returnType
();
Class
<?>
haveReturn
=
oldType
.
returnType
();
boolean
retConv
=
!
VerifyType
.
isNullConversion
(
haveReturn
,
needReturn
);
boolean
retConv
=
!
isTrivialConversion
(
haveReturn
,
needReturn
,
level
);
// Now build a chain of one or more adapters.
MethodHandle
adapter
=
target
,
adapter2
;
...
...
@@ -158,7 +160,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
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
))
{
if
(
isTrivialConversion
(
src
,
dst
,
level
))
{
// do nothing: difference is trivial
continue
;
}
...
...
@@ -219,6 +221,22 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
adapter
;
}
private
static
boolean
isTrivialConversion
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
if
(
src
==
dst
||
dst
==
void
.
class
)
return
true
;
if
(!
VerifyType
.
isNullConversion
(
src
,
dst
))
return
false
;
if
(
level
>
1
)
return
true
;
// explicitCastArguments
boolean
sp
=
src
.
isPrimitive
();
boolean
dp
=
dst
.
isPrimitive
();
if
(
sp
!=
dp
)
return
false
;
if
(
sp
)
{
// in addition to being a null conversion, forbid boolean->int etc.
return
Wrapper
.
forPrimitiveType
(
dst
)
.
isConvertibleFrom
(
Wrapper
.
forPrimitiveType
(
src
));
}
else
{
return
dst
.
isAssignableFrom
(
src
);
}
}
private
static
MethodHandle
makeReturnConversion
(
MethodHandle
target
,
Class
<?>
haveReturn
,
Class
<?>
needReturn
)
{
MethodHandle
adjustReturn
;
if
(
haveReturn
==
void
.
class
)
{
...
...
@@ -530,6 +548,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
static
MethodHandle
makeVarargsCollector
(
MethodHandle
target
,
Class
<?>
arrayType
)
{
MethodType
type
=
target
.
type
();
int
last
=
type
.
parameterCount
()
-
1
;
if
(
type
.
parameterType
(
last
)
!=
arrayType
)
target
=
target
.
asType
(
type
.
changeParameterType
(
last
,
arrayType
));
target
=
target
.
asFixedArity
();
// make sure this attribute is turned off
return
new
AsVarargsCollector
(
target
,
arrayType
);
}
...
...
@@ -550,6 +573,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
true
;
}
@Override
public
MethodHandle
asFixedArity
()
{
return
target
;
}
@Override
public
MethodHandle
asType
(
MethodType
newType
)
{
MethodType
type
=
this
.
type
();
...
...
@@ -574,14 +602,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
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?
...
...
@@ -596,7 +616,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
||
!
VerifyType
.
isNullConversion
(
castType
,
dst
))
return
false
;
int
diff
=
diffTypes
(
newType
,
targetType
,
false
);
return
(
diff
==
arg
+
1
);
// arg is sole non-trivial diff
return
(
diff
==
arg
+
1
)
||
(
diff
==
0
)
;
// arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
static
boolean
canCheckCast
(
Class
<?>
src
,
Class
<?>
dst
)
{
...
...
@@ -727,8 +747,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
,
level
))
return
null
;
MethodType
castDone
=
newType
;
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
{
// Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
if
(
level
!=
0
)
{
// must include additional conversions
if
(
src
==
Object
.
class
||
!
Wrapper
.
isWrapperType
(
src
))
{
// src must be examined at runtime, to detect Byte, Character, etc.
MethodHandle
unboxMethod
=
(
level
==
1
?
ValueConversions
.
unbox
(
dst
)
:
ValueConversions
.
unboxCast
(
dst
));
long
conv
=
makeConv
(
OP_COLLECT_ARGS
,
arg
,
basicType
(
src
),
basicType
(
dst
));
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
unboxMethod
);
}
// Example: Byte->int
// Do this by reformulating the problem to Byte->byte.
Class
<?>
srcPrim
=
Wrapper
.
forWrapperType
(
src
).
primitiveType
();
MethodType
midType
=
newType
.
changeParameterType
(
arg
,
srcPrim
);
MethodHandle
fixPrim
;
// makePairwiseConvert(midType, target, 0);
if
(
canPrimCast
(
midType
,
oldType
,
arg
,
dst
))
fixPrim
=
makePrimCast
(
midType
,
target
,
arg
,
dst
);
else
fixPrim
=
target
;
return
makeUnboxArgument
(
newType
,
fixPrim
,
arg
,
srcPrim
,
0
);
}
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
)
...
...
@@ -897,6 +940,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(
swapArg1
==
swapArg2
)
return
target
;
if
(
swapArg1
>
swapArg2
)
{
int
t
=
swapArg1
;
swapArg1
=
swapArg2
;
swapArg2
=
t
;
}
if
(
type2size
(
newType
.
parameterType
(
swapArg1
))
!=
type2size
(
newType
.
parameterType
(
swapArg2
)))
{
// turn a swap into a pair of rotates:
// [x a b c y] => [a b c y x] => [y a b c x]
int
argc
=
swapArg2
-
swapArg1
+
1
;
final
int
ROT
=
1
;
ArrayList
<
Class
<?>>
rot1Params
=
new
ArrayList
<
Class
<?>>(
target
.
type
().
parameterList
());
Collections
.
rotate
(
rot1Params
.
subList
(
swapArg1
,
swapArg1
+
argc
),
-
ROT
);
MethodType
rot1Type
=
MethodType
.
methodType
(
target
.
type
().
returnType
(),
rot1Params
);
MethodHandle
rot1
=
makeRotateArguments
(
rot1Type
,
target
,
swapArg1
,
argc
,
+
ROT
);
if
(
argc
==
2
)
return
rot1
;
MethodHandle
rot2
=
makeRotateArguments
(
newType
,
rot1
,
swapArg1
,
argc
-
1
,
-
ROT
);
return
rot2
;
}
if
(!
canSwapArguments
(
newType
,
target
.
type
(),
swapArg1
,
swapArg2
))
return
null
;
Class
<?>
swapType
=
newType
.
parameterType
(
swapArg1
);
...
...
@@ -926,7 +983,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
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
)
...
...
@@ -972,6 +1028,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// From here on out, it assumes a single-argument shift.
assert
(
MAX_ARG_ROTATION
==
1
);
int
srcArg
,
dstArg
;
int
dstSlot
;
byte
basicType
;
if
(
chunk2Slots
<=
chunk1Slots
)
{
// Rotate right/down N (rotateBy = +N, N small, c2 small):
...
...
@@ -979,6 +1036,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
srcArg
=
limit
-
1
;
dstArg
=
firstArg
;
dstSlot
=
depth0
-
chunk2Slots
;
basicType
=
basicType
(
newType
.
parameterType
(
srcArg
));
assert
(
chunk2Slots
==
type2size
(
basicType
));
}
else
{
...
...
@@ -987,10 +1045,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
srcArg
=
firstArg
;
dstArg
=
limit
-
1
;
dstSlot
=
depth2
;
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
);
}
...
...
@@ -1033,8 +1091,9 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class
<?>
spreadArgType
,
int
spreadArgPos
,
int
spreadArgCount
)
{
// FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
MethodType
targetType
=
target
.
type
();
if
(!
canSpreadArguments
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
))
return
null
;
assert
(
canSpreadArguments
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
))
:
"[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
+
Arrays
.
asList
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
);
// dest is not significant; remove?
int
dest
=
T_VOID
;
for
(
int
i
=
0
;
i
<
spreadArgCount
;
i
++)
{
...
...
@@ -1127,7 +1186,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
getNameString
(
nonAdapter
((
MethodHandle
)
vmtarget
),
this
);
}
...
...
src/share/classes/java/lang/invoke/BoundMethodHandle.java
浏览文件 @
bd11b4f3
...
...
@@ -151,11 +151,11 @@ class BoundMethodHandle extends MethodHandle {
final
static
RuntimeException
badBoundArgumentException
(
Object
argument
,
MethodHandle
mh
,
int
argnum
)
{
String
atype
=
(
argument
==
null
)
?
"null"
:
argument
.
getClass
().
toString
();
return
new
WrongMethodType
Exception
(
"cannot bind "
+
atype
+
" argument to parameter #"
+
argnum
+
" of "
+
mh
.
type
());
return
new
ClassCast
Exception
(
"cannot bind "
+
atype
+
" argument to parameter #"
+
argnum
+
" of "
+
mh
.
type
());
}
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
baseName
(),
this
);
}
...
...
src/share/classes/java/lang/invoke/CallSite.java
浏览文件 @
bd11b4f3
...
...
@@ -111,7 +111,7 @@ public class CallSite {
}
/**
* Make a
blank call site object, possibly
equipped with an initial target method handle.
* Make a
call site object
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
*/
...
...
@@ -121,6 +121,25 @@ public class CallSite {
this
.
target
=
target
;
}
/**
* Make a call site object equipped with an initial target method handle.
* @param targetType the desired type of the call site
* @param createTargetHook a hook which will bind the call site to the target method handle
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
/*package-private*/
CallSite
(
MethodType
targetType
,
MethodHandle
createTargetHook
)
throws
Throwable
{
this
(
targetType
);
ConstantCallSite
selfCCS
=
(
ConstantCallSite
)
this
;
MethodHandle
boundTarget
=
(
MethodHandle
)
createTargetHook
.
invokeWithArguments
(
selfCCS
);
checkTargetChange
(
this
.
target
,
boundTarget
);
this
.
target
=
boundTarget
;
}
/**
* 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.
...
...
@@ -129,6 +148,7 @@ public class CallSite {
* @return the type of the current target, which is also the type of any future target
*/
public
MethodType
type
()
{
// warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
return
target
.
type
();
}
...
...
@@ -294,8 +314,8 @@ public class CallSite {
}
else
{
throw
new
ClassCastException
(
"bootstrap method failed to produce a CallSite"
);
}
assert
(
site
.
getTarget
()
!=
null
);
assert
(
site
.
getTarget
().
type
().
equals
(
type
));
if
(!
site
.
getTarget
().
type
().
equals
(
type
))
throw
new
WrongMethodTypeException
(
"wrong type: "
+
site
.
getTarget
(
));
}
catch
(
Throwable
ex
)
{
BootstrapMethodError
bex
;
if
(
ex
instanceof
BootstrapMethodError
)
...
...
src/share/classes/java/lang/invoke/ConstantCallSite.java
浏览文件 @
bd11b4f3
...
...
@@ -32,6 +32,8 @@ package java.lang.invoke;
* @author John Rose, JSR 292 EG
*/
public
class
ConstantCallSite
extends
CallSite
{
private
final
boolean
isFrozen
;
/**
* Creates a call site with a permanent target.
* @param target the target to be permanently associated with this call site
...
...
@@ -39,6 +41,45 @@ public class ConstantCallSite extends CallSite {
*/
public
ConstantCallSite
(
MethodHandle
target
)
{
super
(
target
);
isFrozen
=
true
;
}
/**
* Creates a call site with a permanent target, possibly bound to the call site itself.
* <p>
* During construction of the call site, the {@code createTargetHook} is invoked to
* produce the actual target, as if by a call of the form
* {@code (MethodHandle) createTargetHook.invoke(this)}.
* <p>
* Note that user code cannot perform such an action directly in a subclass constructor,
* since the target must be fixed before the {@code ConstantCallSite} constructor returns.
* <p>
* The hook is said to bind the call site to a target method handle,
* and a typical action would be {@code someTarget.bindTo(this)}.
* However, the hook is free to take any action whatever,
* including ignoring the call site and returning a constant target.
* <p>
* The result returned by the hook must be a method handle of exactly
* the same type as the call site.
* <p>
* While the hook is being called, the new {@code ConstantCallSite}
* object is in a partially constructed state.
* In this state,
* a call to {@code getTarget}, or any other attempt to use the target,
* will result in an {@code IllegalStateException}.
* It is legal at all times to obtain the call site's type using the {@code type} method.
*
* @param targetType the type of the method handle to be permanently associated with this call site
* @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
protected
ConstantCallSite
(
MethodType
targetType
,
MethodHandle
createTargetHook
)
throws
Throwable
{
super
(
targetType
,
createTargetHook
);
isFrozen
=
true
;
}
/**
...
...
@@ -48,9 +89,10 @@ public class ConstantCallSite extends CallSite {
* 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
* @throws
IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/
@Override
public
final
MethodHandle
getTarget
()
{
if
(!
isFrozen
)
throw
new
IllegalStateException
();
return
target
;
}
...
...
@@ -61,7 +103,7 @@ public class ConstantCallSite extends CallSite {
* @throws UnsupportedOperationException because this kind of call site cannot change its target
*/
@Override
public
final
void
setTarget
(
MethodHandle
ignore
)
{
throw
new
UnsupportedOperationException
(
"ConstantCallSite"
);
throw
new
UnsupportedOperationException
();
}
/**
...
...
@@ -69,6 +111,7 @@ public class ConstantCallSite extends CallSite {
* 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
* @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/
@Override
public
final
MethodHandle
dynamicInvoker
()
{
...
...
src/share/classes/java/lang/invoke/FilterGeneric.java
浏览文件 @
bd11b4f3
...
...
@@ -234,7 +234,7 @@ class FilterGeneric {
protected
final
MethodHandle
target
;
// ultimate target
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
target
,
this
);
}
...
...
src/share/classes/java/lang/invoke/FilterOneArgument.java
浏览文件 @
bd11b4f3
...
...
@@ -41,7 +41,7 @@ class FilterOneArgument extends BoundMethodHandle {
protected
final
MethodHandle
target
;
// Object -> Object
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
target
.
toString
();
}
...
...
src/share/classes/java/lang/invoke/FromGeneric.java
浏览文件 @
bd11b4f3
...
...
@@ -260,7 +260,7 @@ class FromGeneric {
protected
final
MethodHandle
target
;
// (any**N) => R
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
target
,
this
);
}
...
...
src/share/classes/java/lang/invoke/InvokeGeneric.java
浏览文件 @
bd11b4f3
...
...
@@ -129,20 +129,17 @@ class InvokeGeneric {
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
))
if
(
VerifyType
.
isNullConversion
(
haveType
,
needType
)
&&
!
needType
.
isInterface
()
)
return
false
;
return
true
;
}
private
MethodHandle
addReturnConversion
(
MethodHandle
target
,
Class
<?>
type
)
{
if
(
true
)
throw
new
RuntimeException
(
"NYI"
);
private
MethodHandle
addReturnConversion
(
MethodHandle
finisher
,
Class
<?>
type
)
{
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType
targetType
=
target
.
type
();
MethodType
finisherType
=
finisher
.
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
());
caster
=
caster
.
asType
(
caster
.
type
().
changeParameterType
(
0
,
finisherType
.
returnType
()));
finisher
=
MethodHandles
.
filterReturnValue
(
finisher
,
caster
);
return
finisher
.
asType
(
finisherType
);
}
public
String
toString
()
{
...
...
src/share/classes/java/lang/invoke/Invokers.java
浏览文件 @
bd11b4f3
...
...
@@ -46,7 +46,10 @@ class Invokers {
// general invoker for the outgoing call
private
/*lazy*/
MethodHandle
generalInvoker
;
// general invoker for the outgoing call; accepts a single Object[]
// general invoker for the outgoing call, uses varargs
private
/*lazy*/
MethodHandle
varargsInvoker
;
// general invoker for the outgoing call; accepts a trailing Object[]
private
final
/*lazy*/
MethodHandle
[]
spreadInvokers
;
// invoker for an unbound callsite
...
...
@@ -67,45 +70,56 @@ class Invokers {
/*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
());
invoker
=
lookupInvoker
(
"invokeExact"
);
exactInvoker
=
invoker
;
return
invoker
;
}
/*non-public*/
MethodHandle
generalInvoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker
=
generalInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
generalType
=
targetType
.
generic
();
invoker
=
invoker1
.
asType
(
invokerType
(
generalType
));
invoker
=
lookupInvoker
(
"invoke"
);
generalInvoker
=
invoker
;
return
invoker
;
}
private
MethodHandle
lookupInvoker
(
String
name
)
{
MethodHandle
invoker
;
try
{
invoker
=
IMPL_LOOKUP
.
findVirtual
(
MethodHandle
.
class
,
name
,
targetType
);
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
InternalError
(
"JVM cannot find invoker for "
+
targetType
);
}
assert
(
invokerType
(
targetType
)
==
invoker
.
type
());
assert
(!
invoker
.
isVarargsCollector
());
return
invoker
;
}
/*non-public*/
MethodHandle
erasedInvoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
xinvoker
=
exactInvoker
();
MethodHandle
invoker
=
erasedInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
erasedType
=
targetType
.
erase
();
if
(
erasedType
==
targetType
.
generic
())
invoker
=
generalInvoker
();
else
invoker
=
invoker1
.
asType
(
invokerType
(
erasedType
));
invoker
=
xinvoker
.
asType
(
invokerType
(
erasedType
));
erasedInvoker
=
invoker
;
return
invoker
;
}
/*non-public*/
MethodHandle
spreadInvoker
(
int
object
ArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
object
ArgCount
];
/*non-public*/
MethodHandle
spreadInvoker
(
int
leading
ArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
leading
ArgCount
];
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
MethodHandle
gInvoker
=
generalInvoker
();
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
int
spreadArgCount
=
targetType
.
parameterCount
()
-
leadingArgCount
;
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
spreadArgCount
);
spreadInvokers
[
leadingArgCount
]
=
vaInvoker
;
return
vaInvoker
;
}
/*non-public*/
MethodHandle
varargsInvoker
()
{
MethodHandle
vaInvoker
=
varargsInvoker
;
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
vaInvoker
=
spreadInvoker
(
0
).
asType
(
invokerType
(
MethodType
.
genericMethodType
(
0
,
true
)));
varargsInvoker
=
vaInvoker
;
return
vaInvoker
;
}
...
...
src/share/classes/java/lang/invoke/MemberName.java
浏览文件 @
bd11b4f3
...
...
@@ -506,8 +506,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
if
(
from
!=
null
)
message
+=
", from "
+
from
;
return
new
IllegalAccessException
(
message
);
}
public
ReflectiveOperationException
makeAccessException
(
String
message
)
{
message
=
message
+
": "
+
toString
();
private
String
message
()
{
if
(
isResolved
())
return
"no access"
;
else
if
(
isConstructor
())
return
"no such constructor"
;
else
if
(
isMethod
())
return
"no such method"
;
else
return
"no such field"
;
}
public
ReflectiveOperationException
makeAccessException
()
{
String
message
=
message
()
+
": "
+
toString
();
if
(
isResolved
())
return
new
IllegalAccessException
(
message
);
else
if
(
isConstructor
())
...
...
@@ -641,7 +651,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
MemberName
result
=
resolveOrNull
(
m
,
searchSupers
,
lookupClass
);
if
(
result
!=
null
)
return
result
;
ReflectiveOperationException
ex
=
m
.
makeAccessException
(
"no access"
);
ReflectiveOperationException
ex
=
m
.
makeAccessException
();
if
(
ex
instanceof
IllegalAccessException
)
throw
(
IllegalAccessException
)
ex
;
throw
nsmClass
.
cast
(
ex
);
}
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
bd11b4f3
...
...
@@ -26,6 +26,7 @@
package
java.lang.invoke
;
import
java.util.ArrayList
;
import
sun.invoke.util.ValueConversions
;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
...
...
@@ -40,12 +41,12 @@ import static java.lang.invoke.MethodHandleStatics.*;
* and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
*
* <h3>Method handle contents</h3>
* Method handles are dynamically and strongly typed according to t
ype 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
}.
* Method handles are dynamically and strongly typed according to t
heir parameter and return types
.
* They are not distinguished by the name or
the
defining class of their underlying methods.
* A method handle must be invoked using
a symbolic
type descriptor which matches
* the method handle's own {@linkplain #type
type descriptor
}.
* <p>
* Every method handle reports its type via the {@link #type type} accessor.
* Every method handle reports its type
descriptor
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).
...
...
@@ -82,7 +83,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* 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,
* {@code Object} return types and variable
arity {@code Object} arguments,
* but they have an additional quality called <em>signature polymorphism</em>
* which connects this freedom of invocation directly to the JVM execution stack.
* <p>
...
...
@@ -92,17 +93,17 @@ import static java.lang.invoke.MethodHandleStatics.*;
* 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
* The compiler then calls the method handle with a
symbolic
type descriptor which
* describes the argument and return types.
* <p>
* To issue a complete type descriptor, the compiler must also determine
* To issue a complete
symbolic
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}).
* <p>
* As a corner case, an uncasted {@code null} argument is given
* a type descriptor of {@code java.lang.Void}.
* a
symbolic
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.
*
...
...
@@ -111,16 +112,16 @@ import static java.lang.invoke.MethodHandleStatics.*;
* 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 invoke}.
* In this case, the type descriptor emitted by the compiler is checked for
* In this case, the
symbolic
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
* as the
symbolic
type descriptor is syntactically well-formed
* and the types exist.
* <p>
* 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.
* to ensure that it matches the
symbolic type
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.
...
...
@@ -137,7 +138,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* (or other behavior, as the case may be).
* <p>
* A call to plain {@code invoke} works the same as a call to
* {@code invokeExact}, if the type descriptor specified by the caller
* {@code invokeExact}, if the
symbolic
type descriptor specified by the caller
* exactly matches the method handle's own type.
* If there is a type mismatch, {@code invoke} attempts
* to adjust the type of the receiving method handle,
...
...
@@ -164,9 +165,9 @@ import static java.lang.invoke.MethodHandleStatics.*;
* 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
* method handle calls are type-safe, because the caller's
symbolic
type
* descriptor, as resolved in {@code L2},
* is matched against the original callee method's type descriptor,
* is matched against the original callee method's
symbolic
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
...
...
@@ -242,24 +243,24 @@ mt = MethodType.methodType(String.class, char.class, char.class);
mh = lookup.findVirtual(String.class, "replace", mt);
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assert
(s.equals("nanny")
);
assert
Equals(s, "nanny"
);
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
assert
(s.equals("savvy")
);
assert
Equals(s, "savvy"
);
// mt is (Object[])List
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(x.equals(java.util.Arrays.asList("one","two")
));
assert
Equals(x, java.util.Arrays.asList("one","two"
));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assert
(x.equals(java.util.Arrays.asList(1,2,3)
));
// mt is
int()
assert
Equals(x, java.util.Arrays.asList(1,2,3
));
// mt is
()int
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
...
...
@@ -272,7 +273,10 @@ mh.invokeExact(System.out, "Hello, world.");
* </pre></blockquote>
* Each of the above calls to {@code invokeExact} or plain {@code invoke}
* generates a single invokevirtual instruction with
* the type descriptor indicated in the following comment.
* the symbolic type descriptor indicated in the following comment.
* In these examples, the helper method {@code assertEquals} is assumed to
* be a method which calls {@link Objects.equals java.util.Objects#equals}
* on its arguments, and asserts that the result is true.
*
* <h3>Exceptions</h3>
* The methods {@code invokeExact} and {@code invoke} are declared
...
...
@@ -283,7 +287,7 @@ mh.invokeExact(System.out, "Hello, world.");
* 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
* throw {@code Throwable}, or else must catch all
* throwables locally, rethrowing only those which are legal in the context,
* and wrapping ones which are illegal.
*
...
...
@@ -291,77 +295,26 @@ mh.invokeExact(System.out, "Hello, world.");
* The unusual compilation and linkage behavior of
* {@code invokeExact} and plain {@code invoke}
* is referenced by the term <em>signature polymorphism</em>.
* A signature polymorphic method is one which can operate with
* As defined in the Java Language Specification,
* 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.
* <p>
* In source code, a call to a signature polymorphic method will
* compile, regardless of the requested type descriptor.
* compile, regardless of the requested
symbolic
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
* instruction with the given
symbolic
type descriptor against the named method.
* The unusual part is that the
symbolic
type descriptor is derived from
* the actual argument and return types, not from the method declaration.
* <p>
* When the JVM processes bytecode containing signature polymorphic calls,
* it will successfully link any such call, regardless of its type descriptor.
* it will successfully link any such call, regardless of its
symbolic
type descriptor.
* (In order to retain type safety, the JVM will guard such calls with suitable
* dynamic type checks, as described elsewhere.)
* <p>
* Bytecode generators, including the compiler back end, are required to emit
* untransformed type descriptors for these methods.
* untransformed
symbolic
type descriptors for these methods.
* Tools which determine symbolic linkage are required to accept such
* untransformed descriptors, without reporting linkage errors.
* <p>
* 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.
*
* <h3>Formal rules for processing signature polymorphic methods</h3>
* <p>
* The following methods (and no others) are signature polymorphic:
* <ul>
* <li>{@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke}
* </ul>
* <p>
* A signature polymorphic method will be declared with the following properties:
* <ul>
* <li>It must be native.
* <li>It must take a single varargs parameter of the form {@code Object...}.
* <li>It must produce a return value of type {@code Object}.
* <li>It must be contained within the {@code java.lang.invoke} package.
* </ul>
* 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.
* <p>
* 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.
* <p>
* 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.
* (<em>Note:</em> This typing rule allows the null type to have its own encoding in linkage information
* distinct from other types.
* <p>
* 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:
* <ul>
* <li>If the method invocation expression is an expression statement, the method is {@code void}.
* <li>Otherwise, if the method invocation expression is the immediate operand of a cast,
* the return type is the erasure of the cast type.
* <li>Otherwise, the return type is the method's nominal return type, {@code Object}.
* </ul>
* (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.)
* <p>
* 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.
*
* <h3>Interoperation between method handles and the Core Reflection API</h3>
* Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
...
...
@@ -385,14 +338,14 @@ mh.invokeExact(System.out, "Hello, world.");
* declared method, including in this case {@code native} and {@code varargs} bits.
* <p>
* As with any reflected method, these methods (when reflected) may be
* invoked via {@link java.lang.reflect.Method#invoke Method.invoke}.
* invoked via {@link java.lang.reflect.Method#invoke
java.lang.reflect.
Method.invoke}.
* However, such reflective calls do not result in method handle invocations.
* Such a call, if passed the required argument
* (a single one, of type {@code Object[]}), will ignore the argument and
* will throw an {@code UnsupportedOperationException}.
* <p>
* Since {@code invokevirtual} instructions can natively
* invoke method handles under any type descriptor, this reflective view conflicts
* invoke method handles under any
symbolic
type descriptor, this reflective view conflicts
* with the normal presentation of these methods via bytecodes.
* Thus, these two native methods, when reflectively viewed by
* {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
...
...
@@ -413,7 +366,7 @@ mh.invokeExact(System.out, "Hello, world.");
* 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
* types by their erasures when
it constructs the symbolic
type descriptor
* for the {@code invokevirtual} instruction.
* <p>
* Method handles do not represent
...
...
@@ -502,17 +455,17 @@ public abstract class MethodHandle {
/**
* 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
* The
symbolic
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.
* <p>
* 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,
* {@link java.lang.reflect.Method#invoke
java.lang.reflect.
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 WrongMethodTypeException if the target's type is not identical with the caller's
symbolic
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
;
...
...
@@ -521,7 +474,7 @@ public abstract class MethodHandle {
* Invokes the method handle, allowing any caller type descriptor,
* and optionally performing conversions on arguments and return values.
* <p>
* If the call site type descriptor exactly matches this method handle's {@link #type type},
* If the call site
's symbolic
type descriptor exactly matches this method handle's {@link #type type},
* the call proceeds as if by {@link #invokeExact invokeExact}.
* <p>
* Otherwise, the call proceeds as if this method handle were first
...
...
@@ -534,7 +487,7 @@ public abstract class MethodHandle {
* adaptations directly on the caller's arguments,
* and call the target method handle according to its own exact type.
* <p>
* The type descriptor at the call site of {@code invoke} must
* The
resolved
type descriptor at the call site of {@code invoke} 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,
...
...
@@ -543,24 +496,17 @@ public abstract class MethodHandle {
* 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,
* {@link java.lang.reflect.Method#invoke
java.lang.reflect.
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 WrongMethodTypeException if the target's type cannot be adjusted to the caller's
symbolic
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
invoke
(
Object
...
args
)
throws
Throwable
;
/**
* <em>Temporary alias</em> for {@link #invoke}, for backward compatibility with some versions of JSR 292.
* On some JVMs, support can be excluded by the flags {@code -XX:+UnlockExperimentalVMOptions -XX:-AllowInvokeGeneric}.
* @deprecated Will be removed for JSR 292 Proposed Final Draft.
*/
public
final
native
@PolymorphicSignature
Object
invokeGeneric
(
Object
...
args
)
throws
Throwable
;
/**
* Performs a varargs invocation, passing the arguments in the given array
* Performs a variable arity invocation, passing the arguments in the given array
* to the method handle, as if via an inexact {@link #invoke invoke} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
...
...
@@ -612,56 +558,16 @@ public abstract class MethodHandle {
public
Object
invokeWithArguments
(
Object
...
arguments
)
throws
Throwable
{
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
MethodType
type
=
type
();
if
(
type
.
parameterCount
()
!=
argc
)
{
if
(
type
.
parameterCount
()
!=
argc
||
isVarargsCollector
()
)
{
// simulate invoke
return
asType
(
MethodType
.
genericMethodType
(
argc
)).
invokeWithArguments
(
arguments
);
}
if
(
argc
<=
10
)
{
MethodHandle
invoker
=
type
.
invokers
().
generalInvoker
();
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
);
MethodHandle
invoker
=
type
.
invokers
().
varargsInvoker
();
return
invoker
.
invokeExact
(
this
,
arguments
);
}
/**
* Performs a var
args
invocation, passing the arguments in the given array
* Performs a var
iable arity
invocation, passing the arguments in the given array
* to the method handle, as if via an inexact {@link #invoke invoke} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
...
...
@@ -673,6 +579,7 @@ public abstract class MethodHandle {
*
* @param arguments the arguments to pass to the target
* @return the result returned by the target
* @throws NullPointerException if {@code arguments} is a null reference
* @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
...
...
@@ -689,32 +596,105 @@ public abstract class MethodHandle {
* <p>
* If the original type and new type are equal, returns {@code this}.
* <p>
* The new method handle, when invoked, will perform the following
* steps:
* <ul>
* <li>Convert the incoming argument list to match the original
* method handle's argument list.
* <li>Invoke the original method handle on the converted argument list.
* <li>Convert any result returned by the original method handle
* to the return type of new method handle.
* </ul>
* <p>
* This method provides the crucial behavioral difference between
* {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}. The two methods
* perform the same steps when the caller's type descriptor is identical
* with the callee's, but when the types differ, plain {@link #invoke invoke}
* {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.
* The two methods
* perform the same steps when the caller's type descriptor exactly m atches
* the callee's, but when the types differ, plain {@link #invoke invoke}
* also calls {@code asType} (or some internal equivalent) in order
* to match up the caller's and callee's types.
* <p>
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
* except for variable arity method handles produced by {@link #asVarargsCollector asVarargsCollector}.
* If the current method is a variable arity method handle
* argument list conversion may involve the conversion and collection
* of several arguments into an array, as
* {@linkplain #asVarargsCollector described elsewhere}.
* In every other case, all conversions are applied <em>pairwise</em>,
* which means that each argument or return value is converted to
* exactly one argument or return value (or no return value).
* The applied conversions are defined by consulting the
* the corresponding component types of the old and new
* method handle types.
* <p>
* Let <em>T0</em> and <em>T1</em> be corresponding new and old parameter types,
* or old and new return types. Specifically, for some valid index {@code i}, let
* <em>T0</em>{@code =newType.parameterType(i)} and <em>T1</em>{@code =this.type().parameterType(i)}.
* Or else, going the other way for return values, let
* <em>T0</em>{@code =this.type().returnType()} and <em>T1</em>{@code =newType.returnType()}.
* If the types are the same, the new method handle makes no change
* to the corresponding argument or return value (if any).
* Otherwise, one of the following conversions is applied
* if possible:
* <ul>
* <li>If <em>T0</em> and <em>T1</em> are references, then a cast to <em>T1</em> is applied.
* (The types do not need to be related in any particular way.
* This is because a dynamic value of null can convert to any reference type.)
* <li>If <em>T0</em> and <em>T1</em> are primitives, then a Java method invocation
* conversion (JLS 5.3) is applied, if one exists.
* (Specifically, <em>T0</em> must convert to <em>T1</em> by a widening primitive conversion.)
* <li>If <em>T0</em> is a primitive and <em>T1</em> a reference,
* a Java casting conversion (JLS 5.5) is applied if one exists.
* (Specifically, the value is boxed from <em>T0</em> to its wrapper class,
* which is then widened as needed to <em>T1</em>.)
* <li>If <em>T0</em> is a reference and <em>T1</em> 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 primitive widening conversions.)
* <em>T0</em> must be a wrapper class or a supertype of one.
* (In the case where <em>T0</em> is Object, these are the conversions
* allowed by {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.)
* The unboxing conversion must have a possibility of success, which means that
* if <em>T0</em> is not itself a wrapper class, there must exist at least one
* wrapper class <em>TW</em> which is a subtype of <em>T0</em> and whose unboxed
* primitive value can be widened to <em>T1</em>.
* <li>If the return type <em>T1</em> is marked as void, any returned value is discarded
* <li>If the return type <em>T0</em> is void and <em>T1</em> a reference, a null value is introduced.
* <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
* a zero value is introduced.
* </ul>
* (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
* because neither corresponds specifically to the <em>dynamic type</em> of any
* actual argument or return value.)
* <p>
* The method handle conversion cannot be made if any one of the required
* pairwise conversions cannot be made.
* <p>
* At runtime, the conversions applied to reference arguments
* or return values may require additional runtime checks which can fail.
* An unboxing operation may fail because the original reference is null,
* causing a {@link java.lang.NullPointerException NullPointerException}.
* An unboxing operation or a reference cast may also fail on a reference
* to an object of the wrong type,
* causing a {@link java.lang.ClassCastException ClassCastException}.
* Although an unboxing operation may accept several kinds of wrappers,
* if none are available, a {@code ClassCastException} will be thrown.
*
* @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 NullPointerException if {@code newType} is a null reference
* @throws WrongMethodTypeException if the conversion cannot be made
* @see MethodHandles#
conver
tArguments
* @see MethodHandles#
explicitCas
tArguments
*/
public
MethodHandle
asType
(
MethodType
newType
)
{
if
(!
type
.
isConvertibleTo
(
newType
))
{
throw
new
WrongMethodTypeException
(
"cannot convert "
+
t
ype
+
" to "
+
newType
);
throw
new
WrongMethodTypeException
(
"cannot convert "
+
t
his
+
" to "
+
newType
);
}
return
MethodHandle
s
.
convertArguments
(
this
,
newType
);
return
MethodHandle
Impl
.
convertArguments
(
this
,
newType
,
1
);
}
/**
* Makes an
adapter
which accepts a trailing array argument
* Makes an
<em>array-spreading</em> method handle,
which accepts a trailing array argument
* and spreads its elements as positional arguments.
* The new method handle adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
...
...
@@ -739,26 +719,103 @@ public abstract class MethodHandle {
* 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.)
* <p>
* Here are some simple examples of array-spreading method handles:
* <blockquote><pre>
MethodHandle equals = publicLookup()
.findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
assert( (boolean) equals.invokeExact("me", (Object)"me"));
assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
// spread both arguments from a 2-array:
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
// spread second arguments from a 1-array:
MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
// spread no arguments from a 0-array or null:
MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
// asSpreader and asCollector are approximate inverses:
for (int n = 0; n <= 2; n++) {
for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
assert( (boolean) equals2.invokeWithArguments("me", "me"));
assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
}
}
MethodHandle caToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
MethodHandle caString3 = caToString.asCollector(char[].class, 3);
assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
* </pre></blockquote>
* @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 NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* @throws IllegalArgumentException if target does not have at least
* {@code arrayLength} parameter types
* {@code arrayLength} parameter types,
* or if {@code arrayLength} is negative
* @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"
);
int
nargs
=
type
().
parameterCount
();
if
(
nargs
<
arrayLength
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
asSpreaderChecks
(
arrayType
,
arrayLength
);
return
MethodHandleImpl
.
spreadArguments
(
this
,
arrayType
,
arrayLength
);
}
private
void
asSpreaderChecks
(
Class
<?>
arrayType
,
int
arrayLength
)
{
spreadArrayChecks
(
arrayType
,
arrayLength
);
int
nargs
=
type
().
parameterCount
();
if
(
nargs
<
arrayLength
||
arrayLength
<
0
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
if
(
arrayType
!=
Object
[].
class
&&
arrayLength
!=
0
)
{
boolean
sawProblem
=
false
;
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
for
(
int
i
=
nargs
-
arrayLength
;
i
<
nargs
;
i
++)
{
if
(!
MethodType
.
canConvert
(
arrayElement
,
type
().
parameterType
(
i
)))
{
sawProblem
=
true
;
break
;
}
}
if
(
sawProblem
)
{
ArrayList
<
Class
<?>>
ptypes
=
new
ArrayList
<
Class
<?>>(
type
().
parameterList
());
for
(
int
i
=
nargs
-
arrayLength
;
i
<
nargs
;
i
++)
{
ptypes
.
set
(
i
,
arrayElement
);
}
// elicit an error:
this
.
asType
(
MethodType
.
methodType
(
type
().
returnType
(),
ptypes
));
}
}
}
private
void
spreadArrayChecks
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
,
arrayType
);
if
((
arrayLength
&
0x7F
)
!=
arrayLength
)
{
if
((
arrayLength
&
0xFF
)
!=
arrayLength
)
throw
newIllegalArgumentException
(
"array length is not legal"
,
arrayLength
);
assert
(
arrayLength
>=
128
);
if
(
arrayElement
==
long
.
class
||
arrayElement
==
double
.
class
)
throw
newIllegalArgumentException
(
"array length is not legal for long[] or double[]"
,
arrayLength
);
}
}
/**
* Makes an
adapter
which accepts a given number of trailing
* Makes an
<em>array-collecting</em> method handle,
which accepts a given number of trailing
* positional arguments and collects them into an array argument.
* The new method handle adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
...
...
@@ -785,10 +842,40 @@ public abstract class MethodHandle {
* <p>
* In order to create a collecting adapter which is not restricted to a particular
* number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
* <p>
* Here are some examples of array-collecting method handles:
* <blockquote><pre>
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));
MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
assertEquals(methodType(String.class, Object.class), ts1.type());
//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
// arrayType can be a subtype of Object[]
MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
assertEquals(methodType(String.class, String.class, String.class), ts2.type());
assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
assertEquals("[]", (String) ts0.invokeExact());
// collectors can be nested, Lisp-style
MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
// arrayType can be any primitive array type
MethodHandle bytesToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
.asCollector(byte[].class, 3);
assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
MethodHandle longsToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
.asCollector(long[].class, 1);
assertEquals("[123]", (String) longsToString.invokeExact((long)123));
* </pre></blockquote>
* @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 NullPointerException if {@code arrayType} is a null reference
* @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
...
...
@@ -802,12 +889,15 @@ public abstract class MethodHandle {
return
MethodHandleImpl
.
collectArguments
(
this
,
type
.
parameterCount
()-
1
,
collector
);
}
private
void
asCollectorChecks
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
,
arrayType
);
// private API: return true if last param exactly matches arrayType
private
boolean
asCollectorChecks
(
Class
<?>
arrayType
,
int
arrayLength
)
{
spreadArrayChecks
(
arrayType
,
arrayLength
);
int
nargs
=
type
().
parameterCount
();
if
(
nargs
==
0
||
!
type
().
parameterType
(
nargs
-
1
).
isAssignableFrom
(
arrayType
))
if
(
nargs
!=
0
)
{
Class
<?>
lastParam
=
type
().
parameterType
(
nargs
-
1
);
if
(
lastParam
==
arrayType
)
return
true
;
if
(
lastParam
.
isAssignableFrom
(
arrayType
))
return
false
;
}
throw
newIllegalArgumentException
(
"array type not assignable to trailing argument"
,
this
,
arrayType
);
}
...
...
@@ -825,6 +915,10 @@ public abstract class MethodHandle {
* {@code arrayType}, even if the target has a different
* last parameter type.
* <p>
* This transformation may return {@code this} if the method handle is
* already of variable arity and its trailing parameter type
* is identical to {@code arrayType}.
* <p>
* When called with {@link #invokeExact invokeExact}, the adapter invokes
* the target with no argument changes.
* (<em>Note:</em> This behavior is different from a
...
...
@@ -841,8 +935,8 @@ public abstract class MethodHandle {
* 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 invoke} in such a case.)
* as if by {@link
#asType asType} on a fixed arity
*
method handle.
* <p>
* Otherwise, the arities differ, or the adapter's trailing parameter
* type is not assignable from the corresponding caller type.
...
...
@@ -910,14 +1004,24 @@ public abstract class MethodHandle {
* <p>
* Here is an example, of a list-making variable arity method handle:
* <blockquote><pre>
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));
assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));
assertEquals("[won]", (String) ts1.invoke( "won" ));
assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
// findStatic of Arrays.asList(...) produces a variable arity method handle:
MethodHandle asList = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
assertEquals(methodType(List.class, Object[].class), asList.type());
assert(asList.isVarargsCollector());
assertEquals("[]", asList.invoke().toString());
assertEquals("[1]", asList.invoke(1).toString());
assertEquals("[two, too]", asList.invoke("two", "too").toString());
Object
[] argv = { "three", "thee", "tee" };
String
[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
List ls = (List) asList.invoke((Object)argv);
assertEquals(1, ls.size());
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
...
...
@@ -934,39 +1038,25 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
* 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.)
* <p style="font-size:smaller;">
* 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:
* <blockquote><pre>
MethodHandle vamh = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
assert(vamh.type().equals(mh.type()));
assertEquals("[1, 2, 3]", vamh.invoke(1,2,3).toString());
boolean failed = false;
try { mh.invoke(1,2,3); }
catch (WrongMethodTypeException ex) { failed = true; }
assert(failed);
* </pre></blockquote>
* This transformation has no behavioral effect if the method handle is
* not of variable arity.
* effect on this decision, only a comparison between the symbolic
* type descriptor of the call site and the type descriptor of the method handle.)
*
* @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 NullPointerException if {@code arrayType} is a null reference
* @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
* @see #asFixedArity
*/
public
MethodHandle
asVarargsCollector
(
Class
<?>
arrayType
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
return
MethodHandles
.
asVarargsCollector
(
this
,
arrayType
);
boolean
lastMatch
=
asCollectorChecks
(
arrayType
,
0
);
if
(
isVarargsCollector
()
&&
lastMatch
)
return
this
;
return
AdapterMethodHandle
.
makeVarargsCollector
(
this
,
arrayType
);
}
/**
...
...
@@ -982,11 +1072,60 @@ assert(failed);
* </ul>
* @return true if this method handle accepts more than one arity of plain, inexact {@code invoke} calls
* @see #asVarargsCollector
* @see #asFixedArity
*/
public
boolean
isVarargsCollector
()
{
return
false
;
}
/**
* Makes a <em>fixed arity</em> method handle which is otherwise
* equivalent to the the current method handle.
* <p>
* If the current method handle is not of
* {@linkplain #asVarargsCollector variable arity},
* the current method handle is returned.
* This is true even if the current method handle
* could not be a valid input to {@code asVarargsCollector}.
* <p>
* Otherwise, the resulting fixed-arity method handle has the same
* type and behavior of the current method handle,
* except that {@link #isVarargsCollector isVarargsCollector}
* will be false.
* The fixed-arity method handle may (or may not) be the
* a previous argument to {@code asVarargsCollector}.
* <p>
* Here is an example, of a list-making variable arity method handle:
* <blockquote><pre>
MethodHandle asListVar = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
MethodHandle asListFix = asListVar.asFixedArity();
assertEquals("[1]", asListVar.invoke(1).toString());
Exception caught = null;
try { asListFix.invoke((Object)1); }
catch (Exception ex) { caught = ex; }
assert(caught instanceof ClassCastException);
assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
try { asListFix.invoke("two", "too"); }
catch (Exception ex) { caught = ex; }
assert(caught instanceof WrongMethodTypeException);
Object[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* </pre></blockquote>
*
* @return a new method handle which accepts only a fixed number of arguments
* @see #asVarargsCollector
* @see #isVarargsCollector
*/
public
MethodHandle
asFixedArity
()
{
assert
(!
isVarargsCollector
());
return
this
;
}
/**
* Binds a value {@code x} to the first argument of a method handle, without invoking it.
* The new method handle adapts, as its <i>target</i>,
...
...
@@ -1043,6 +1182,12 @@ assert(failed);
*/
@Override
public
String
toString
()
{
if
(
DEBUG_METHOD_HANDLE_NAMES
)
return
debugString
();
return
"MethodHandle"
+
type
;
}
/*non-public*/
String
debugString
()
{
return
getNameString
(
this
);
}
}
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
bd11b4f3
...
...
@@ -82,20 +82,44 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
DirectMethodHandle
mh
=
new
DirectMethodHandle
(
mtype
,
method
,
doDispatch
,
lookupClass
);
if
(!
mh
.
isValid
())
throw
method
.
makeAccessException
(
"no
access
"
,
lookupClass
);
throw
method
.
makeAccessException
(
"no
direct method handle
"
,
lookupClass
);
assert
(
mh
.
type
()
==
mtype
);
if
(!
method
.
isVarargs
())
return
mh
;
else
return
mh
.
asVarargsCollector
(
mtype
.
parameterType
(
mtype
.
parameterCount
()-
1
));
int
argc
=
mtype
.
parameterCount
();
if
(
argc
!=
0
)
{
Class
<?>
arrayType
=
mtype
.
parameterType
(
argc
-
1
);
if
(
arrayType
.
isArray
())
return
AdapterMethodHandle
.
makeVarargsCollector
(
mh
,
arrayType
);
}
throw
method
.
makeAccessException
(
"cannot make variable arity"
,
null
);
}
static
MethodHandle
makeAllocator
(
MethodHandle
rawConstructor
)
{
MethodType
rawConType
=
rawConstructor
.
type
();
Class
<?>
allocateClass
=
rawConType
.
parameterType
(
0
);
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
if
(
AdapterMethodHandle
.
canCollectArguments
(
rawConType
,
MethodType
.
methodType
(
allocateClass
),
0
,
true
))
{
// allocator(arg...)
// [fold]=> cookedConstructor(obj=allocate(C), arg...)
// [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
MethodHandle
returner
=
MethodHandles
.
identity
(
allocateClass
);
MethodType
ctype
=
rawConType
.
insertParameterTypes
(
0
,
allocateClass
).
changeReturnType
(
allocateClass
);
MethodHandle
cookedConstructor
=
AdapterMethodHandle
.
makeCollectArguments
(
returner
,
rawConstructor
,
1
,
false
);
assert
(
cookedConstructor
.
type
().
equals
(
ctype
));
ctype
=
ctype
.
dropParameterTypes
(
0
,
1
);
cookedConstructor
=
AdapterMethodHandle
.
makeCollectArguments
(
cookedConstructor
,
returner
,
0
,
true
);
MethodHandle
allocator
=
new
AllocateObject
(
allocateClass
);
// allocate() => new C(void)
assert
(
allocator
.
type
().
equals
(
MethodType
.
methodType
(
allocateClass
)));
ctype
=
ctype
.
dropParameterTypes
(
0
,
1
);
MethodHandle
fold
=
foldArguments
(
cookedConstructor
,
ctype
,
0
,
allocator
);
return
fold
;
}
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
allocator
=
AllocateObject
.
make
(
rawConType
.
parameterType
(
0
)
,
rawConstructor
);
=
AllocateObject
.
make
(
allocateClass
,
rawConstructor
);
assert
(
allocator
.
type
()
.
equals
(
rawConType
.
dropParameterTypes
(
0
,
1
).
changeReturnType
(
rawConType
.
parameterType
(
0
))));
return
allocator
;
...
...
@@ -112,8 +136,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
super
(
invoker
);
this
.
allocateClass
=
allocateClass
;
this
.
rawConstructor
=
rawConstructor
;
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
}
// for allocation only:
private
AllocateObject
(
Class
<
C
>
allocateClass
)
{
super
(
ALLOCATE
.
asType
(
MethodType
.
methodType
(
allocateClass
,
AllocateObject
.
class
)));
this
.
allocateClass
=
allocateClass
;
this
.
rawConstructor
=
null
;
}
static
MethodHandle
make
(
Class
<?>
allocateClass
,
MethodHandle
rawConstructor
)
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodType
rawConType
=
rawConstructor
.
type
();
assert
(
rawConType
.
parameterType
(
0
)
==
allocateClass
);
MethodType
newType
=
rawConType
.
dropParameterTypes
(
0
,
1
).
changeReturnType
(
allocateClass
);
...
...
@@ -129,14 +161,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
else
{
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
conType
=
CON_TYPES
[
nargs
];
MethodHandle
gcon
=
spreadArguments
(
rawConstructor
,
conType
,
1
);
MethodHandle
gcon
=
spreadArguments
FromPos
(
rawConstructor
,
conType
,
1
);
if
(
gcon
==
null
)
return
null
;
MethodHandle
galloc
=
new
AllocateObject
(
invoke
,
allocateClass
,
gcon
);
return
collectArguments
(
galloc
,
newType
,
1
,
null
);
}
}
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
allocateClass
.
getSimpleName
(),
this
);
}
@SuppressWarnings
(
"unchecked"
)
...
...
@@ -214,9 +246,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// For testing use this:
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
static
final
MethodHandle
VARARGS_INVOKE
;
static
final
MethodHandle
ALLOCATE
;
static
{
try
{
VARARGS_INVOKE
=
IMPL_LOOKUP
.
findVirtual
(
AllocateObject
.
class
,
"invoke_V"
,
MethodType
.
genericMethodType
(
0
,
true
));
ALLOCATE
=
IMPL_LOOKUP
.
findVirtual
(
AllocateObject
.
class
,
"allocate"
,
MethodType
.
genericMethodType
(
0
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
uncaughtException
(
ex
);
}
...
...
@@ -278,7 +312,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
base
=
staticBase
(
field
);
}
@Override
public
String
to
String
()
{
return
addTypeString
(
name
,
this
);
}
String
debug
String
()
{
return
addTypeString
(
name
,
this
);
}
int
getFieldI
(
C
obj
)
{
return
unsafe
.
getInt
(
obj
,
offset
);
}
void
setFieldI
(
C
obj
,
int
x
)
{
unsafe
.
putInt
(
obj
,
offset
,
x
);
}
...
...
@@ -309,8 +343,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
try
{
// FIXME: Should not have to create 'f' to get this value.
f
=
c
.
getDeclaredField
(
field
.
getName
());
// Note: Previous line might invalidly throw SecurityException (7042829)
return
unsafe
.
staticFieldBase
(
f
);
}
catch
(
Exception
ee
)
{
}
catch
(
NoSuchField
Exception
ee
)
{
throw
uncaughtException
(
ee
);
}
}
...
...
@@ -455,14 +490,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
*/
static
MethodHandle
bindReceiver
(
MethodHandle
target
,
Object
receiver
)
{
if
(
receiver
==
null
)
return
null
;
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
()))
{
if
(
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
(),
0
);
...
...
@@ -668,7 +703,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot drop"
);
oldType
=
target
.
type
();
}
return
convertArguments
(
target
,
newType
,
oldType
,
0
);
target
=
convertArguments
(
target
,
newType
,
oldType
,
0
);
assert
(
target
!=
null
);
return
target
;
}
/*non-public*/
static
...
...
@@ -747,7 +784,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
.
insertParameterTypes
(
keepPosArgs
,
arrayType
);
return
spreadArguments
(
target
,
newType
,
keepPosArgs
,
arrayType
,
arrayLength
);
}
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
,
int
spreadArgPos
)
{
static
MethodHandle
spreadArguments
FromPos
(
MethodHandle
target
,
MethodType
newType
,
int
spreadArgPos
)
{
int
arrayLength
=
target
.
type
().
parameterCount
()
-
spreadArgPos
;
return
spreadArguments
(
target
,
newType
,
spreadArgPos
,
Object
[].
class
,
arrayLength
);
}
...
...
@@ -761,9 +798,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// spread the last argument of newType to oldType
assert
(
arrayLength
==
oldType
.
parameterCount
()
-
spreadArgPos
);
assert
(
newType
.
parameterType
(
spreadArgPos
)
==
arrayType
);
MethodHandle
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
arrayType
,
spreadArgPos
,
arrayLength
);
if
(
res
==
null
)
throw
new
IllegalArgumentException
(
"spread on "
+
target
+
" with "
+
arrayType
.
getSimpleName
());
return
res
;
return
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
arrayType
,
spreadArgPos
,
arrayLength
);
}
static
MethodHandle
collectArguments
(
MethodHandle
target
,
...
...
@@ -771,6 +806,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
collector
)
{
MethodType
type
=
target
.
type
();
Class
<?>
collectType
=
collector
.
type
().
returnType
();
assert
(
collectType
!=
void
.
class
);
// else use foldArguments
if
(
collectType
!=
type
.
parameterType
(
collectArg
))
target
=
target
.
asType
(
type
.
changeParameterType
(
collectArg
,
collectType
));
MethodType
newType
=
type
...
...
@@ -879,11 +915,15 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
target
=
target
;
this
.
fallback
=
fallback
;
}
// FIXME: Build the control flow out of foldArguments.
static
boolean
preferRicochetFrame
(
MethodType
type
)
{
return
(
type
.
parameterCount
()
>=
INVOKES
.
length
||
type
.
hasPrimitives
());
}
static
MethodHandle
make
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
MethodType
type
=
target
.
type
();
int
nargs
=
type
.
parameterCount
();
if
(
nargs
<
INVOKES
.
length
)
{
if
(
preferRicochetFrame
(
type
))
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodType
gtype
=
type
.
generic
();
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
...
...
@@ -894,19 +934,20 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
gtype
=
MethodType
.
genericMethodType
(
1
);
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
MethodHandle
gtest
=
spreadArguments
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
0
);
MethodHandle
gtarget
=
spreadArguments
(
target
,
gtype
,
0
);
MethodHandle
gfallback
=
spreadArguments
(
fallback
,
gtype
,
0
);
MethodHandle
gtest
=
spreadArguments
FromPos
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
0
);
MethodHandle
gtarget
=
spreadArguments
FromPos
(
target
,
gtype
,
0
);
MethodHandle
gfallback
=
spreadArguments
FromPos
(
fallback
,
gtype
,
0
);
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
if
(
gtest
==
null
||
gtarget
==
null
||
gfallback
==
null
)
return
null
;
return
collectArguments
(
gguard
,
type
,
0
,
null
);
}
}
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
target
,
this
);
}
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
...
...
@@ -989,10 +1030,50 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
}
static
MethodHandle
selectAlternative
(
boolean
testResult
,
MethodHandle
target
,
MethodHandle
fallback
)
{
return
testResult
?
target
:
fallback
;
}
static
MethodHandle
SELECT_ALTERNATIVE
;
static
MethodHandle
selectAlternative
()
{
if
(
SELECT_ALTERNATIVE
!=
null
)
return
SELECT_ALTERNATIVE
;
try
{
SELECT_ALTERNATIVE
=
IMPL_LOOKUP
.
findStatic
(
MethodHandleImpl
.
class
,
"selectAlternative"
,
MethodType
.
methodType
(
MethodHandle
.
class
,
boolean
.
class
,
MethodHandle
.
class
,
MethodHandle
.
class
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
return
SELECT_ALTERNATIVE
;
}
static
MethodHandle
makeGuardWithTest
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
// gwt(arg...)
// [fold]=> continueAfterTest(z=test(arg...), arg...)
// [filter]=> (tf=select(z))(arg...)
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
// [tailcall]=> tf(arg...)
assert
(
test
.
type
().
returnType
()
==
boolean
.
class
);
MethodType
targetType
=
target
.
type
();
MethodType
foldTargetType
=
targetType
.
insertParameterTypes
(
0
,
boolean
.
class
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
foldTargetType
,
test
.
type
(),
0
,
true
)
&&
GuardWithTest
.
preferRicochetFrame
(
targetType
))
{
// working backwards, as usual:
assert
(
target
.
type
().
equals
(
fallback
.
type
()));
MethodHandle
tailcall
=
MethodHandles
.
exactInvoker
(
target
.
type
());
MethodHandle
select
=
selectAlternative
();
select
=
bindArgument
(
select
,
2
,
fallback
);
select
=
bindArgument
(
select
,
1
,
target
);
// select(z: boolean) => (z ? target : fallback)
MethodHandle
filter
=
filterArgument
(
tailcall
,
0
,
select
);
assert
(
filter
.
type
().
parameterType
(
0
)
==
boolean
.
class
);
MethodHandle
fold
=
foldArguments
(
filter
,
filter
.
type
().
dropParameterTypes
(
0
,
1
),
0
,
test
);
return
fold
;
}
return
GuardWithTest
.
make
(
test
,
target
,
fallback
);
}
...
...
@@ -1012,7 +1093,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
catcher
=
catcher
;
}
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
target
,
this
);
}
private
Object
invoke_V
(
Object
...
av
)
throws
Throwable
{
...
...
@@ -1144,11 +1225,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
else
{
MethodType
gtype
=
MethodType
.
genericMethodType
(
0
,
true
);
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
MethodHandle
gtarget
=
spreadArguments
(
target
,
gtype
,
0
);
MethodHandle
gcatcher
=
spreadArguments
(
catcher
,
gcatchType
,
1
);
MethodHandle
gtarget
=
spreadArgumentsFromPos
(
target
,
gtype
,
0
);
catcher
=
catcher
.
asType
(
ctype
.
changeParameterType
(
0
,
Throwable
.
class
));
MethodHandle
gcatcher
=
spreadArgumentsFromPos
(
catcher
,
gcatchType
,
1
);
MethodHandle
gguard
=
new
GuardWithCatch
(
GuardWithCatch
.
VARARGS_INVOKE
,
gtarget
,
exType
,
gcatcher
);
if
(
gtarget
==
null
||
gcatcher
==
null
||
gguard
==
null
)
return
null
;
return
collectArguments
(
gguard
,
type
,
0
,
null
);
return
collectArguments
(
gguard
,
type
,
0
,
ValueConversions
.
varargsArray
(
nargs
)).
asType
(
type
);
}
}
...
...
@@ -1178,8 +1260,4 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static
MethodHandle
getBootstrap
(
Class
<?>
callerClass
)
{
return
MethodHandleNatives
.
getBootstrap
(
callerClass
);
}
static
MethodHandle
asVarargsCollector
(
MethodHandle
target
,
Class
<?>
arrayType
)
{
return
AdapterMethodHandle
.
makeVarargsCollector
(
target
,
arrayType
);
}
}
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
bd11b4f3
...
...
@@ -400,7 +400,7 @@ class MethodHandleNatives {
case
REF_newInvokeSpecial:
return
lookup
.
findConstructor
(
defc
,
(
MethodType
)
type
);
case
REF_invokeInterface:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
}
throw
new
I
llegalArgumentException
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
throw
new
I
nternalError
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
Error
err
=
new
IncompatibleClassChangeError
();
err
.
initCause
(
ex
);
...
...
src/share/classes/java/lang/invoke/MethodHandleProxies.java
0 → 100644
浏览文件 @
bd11b4f3
/*
* 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
java.lang.reflect.*
;
import
sun.invoke.WrapperInstance
;
/**
* This class consists exclusively of static methods that help adapt
* method handles to other JVM types, such as interfaces.
*/
public
class
MethodHandleProxies
{
private
MethodHandleProxies
()
{
}
// do not instantiate
/**
* Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
* <p>
* A single-method interface is an interface which declares a uniquely named method.
* When determining the uniquely named method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
* are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
* <p>
* The interface must be public. No additional access checks are performed.
* <p>
* The resulting instance of the required type will respond to
* invocation of the type's uniquely named method by calling
* the given target on the incoming arguments,
* and returning or throwing whatever the target
* returns or throws. The invocation will be as if by
* {@code target.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* <p>
* The uniquely named method is allowed to be multiply declared,
* with distinct type descriptors. (E.g., it can be overloaded,
* or can possess bridge methods.) All such declarations are
* connected directly to the target method handle.
* Argument and return types are adjusted by {@code asType}
* for each individual declaration.
* <p>
* The wrapper instance will implement the requested interface
* and its super-types, but no other single-method interfaces.
* This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
* multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the requested 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.
* <p>
* Like {@link java.lang.Integer#valueOf Integer.valueOf},
* {@code asInterfaceInstance} is a factory method whose results are defined
* by their behavior.
* It is not guaranteed to return a new instance for every call.
* <p>
* Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
* and other corner cases, the interface may also have several abstract methods
* with the same name but having distinct descriptors (types of returns and parameters).
* In this case, all the methods are bound in common to the one given target.
* The type check and effective {@code asType} conversion is applied to each
* method type descriptor, and all abstract methods are bound to the target in common.
* Beyond this type check, no further checks are made to determine that the
* abstract methods are related in any way.
* <p>
* 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 intfc the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given target
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the {@code intfc} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the target cannot
* be converted to the type required by the requested interface
*/
// Other notes to implementors:
// <p>
// No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
// classes might be used for the same type.
// <p>
// If the implementation is able
// to prove that a wrapper of the required 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.
// <p>
// 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 single-abstract-method 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
>
T
asInterfaceInstance
(
final
Class
<
T
>
intfc
,
final
MethodHandle
target
)
{
// POC implementation only; violates the above contract several ways
final
Method
sm
=
getSingleMethod
(
intfc
);
if
(
sm
==
null
)
throw
new
IllegalArgumentException
(
"not a single-method interface: "
+
intfc
.
getName
());
MethodType
smMT
=
MethodType
.
methodType
(
sm
.
getReturnType
(),
sm
.
getParameterTypes
());
MethodHandle
checkTarget
=
target
.
asType
(
smMT
);
// make throw WMT
checkTarget
=
checkTarget
.
asType
(
checkTarget
.
type
().
changeReturnType
(
Object
.
class
));
final
MethodHandle
vaTarget
=
checkTarget
.
asSpreader
(
Object
[].
class
,
smMT
.
parameterCount
());
return
intfc
.
cast
(
Proxy
.
newProxyInstance
(
intfc
.
getClassLoader
(),
new
Class
[]{
intfc
,
WrapperInstance
.
class
},
new
InvocationHandler
()
{
private
Object
getArg
(
String
name
)
{
if
((
Object
)
name
==
"getWrapperInstanceTarget"
)
return
target
;
if
((
Object
)
name
==
"getWrapperInstanceType"
)
return
intfc
;
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
(
sm
))
return
vaTarget
.
invokeExact
(
args
);
if
(
isObjectMethod
(
method
))
return
callObjectMethod
(
this
,
method
,
args
);
throw
new
InternalError
();
}
}));
}
/**
* Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* @param x any reference
* @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
*/
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 unique method of this wrapper instance.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return a method handle implementing the unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public
static
MethodHandle
wrapperInstanceTarget
(
Object
x
)
{
return
asWrapperInstance
(
x
).
getWrapperInstanceTarget
();
}
/**
* Recovers the unique single-method interface type for which this wrapper instance was created.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return the single-method interface 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
getSingleMethod
(
Class
<?>
intfc
)
{
if
(!
intfc
.
isInterface
())
return
null
;
Method
sm
=
null
;
for
(
Method
m
:
intfc
.
getMethods
())
{
int
mod
=
m
.
getModifiers
();
if
(
Modifier
.
isAbstract
(
mod
))
{
if
(
sm
!=
null
&&
!
isObjectMethod
(
sm
))
return
null
;
// too many abstract methods
sm
=
m
;
}
}
return
sm
;
}
}
src/share/classes/java/lang/invoke/MethodHandleStatics.java
浏览文件 @
bd11b4f3
...
...
@@ -35,6 +35,8 @@ package java.lang.invoke;
private
MethodHandleStatics
()
{
}
// do not instantiate
static
final
boolean
DEBUG_METHOD_HANDLE_NAMES
=
Boolean
.
getBoolean
(
"java.lang.invoke.MethodHandle.DEBUG_NAMES"
);
/*non-public*/
static
String
getNameString
(
MethodHandle
target
,
MethodType
type
)
{
if
(
type
==
null
)
type
=
target
.
type
();
...
...
src/share/classes/java/lang/invoke/MethodHandles.java
浏览文件 @
bd11b4f3
...
...
@@ -180,6 +180,10 @@ public class MethodHandles {
* The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
* for reflective objects corresponding to the given members.
* <p>
* In cases where the given member is of variable arity (i.e., a method or constructor)
* the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
* In all other cases, the returned method handle will be of fixed arity.
* <p>
* The equivalence between looked-up method handles and underlying
* class members can break down in a few ways:
* <ul>
...
...
@@ -201,7 +205,7 @@ public class MethodHandles {
* 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}
* {@link java.lang.reflect.Method#invoke
java.lang.reflect.
Method.invoke}
* performs access checking against every caller, on every call.
* <p>
* All access checks start from a {@code Lookup} object, which
...
...
@@ -267,7 +271,7 @@ public class MethodHandles {
* Access checks only apply to named and reflected methods,
* constructors, and fields.
* Other method handle creation methods, such as
* {@link
#convertArguments MethodHandles.convertArguments
},
* {@link
MethodHandle#asType MethodHandle.asType
},
* do not require any access checks, and are done
* with static methods of {@link MethodHandles},
* independently of any {@code Lookup} object.
...
...
@@ -296,6 +300,12 @@ public class MethodHandles {
* {@link SecurityManager#checkMemberAccess
* smgr.checkMemberAccess(defc, Member.DECLARED)} is called.
* (Note that {@code defc} might be the same as {@code refc}.)
* The default implementation of this security manager method
* inspects the stack to determine the original caller of
* the reflective request (such as {@code findStatic}),
* and performs additional permission checks if the
* class loader of {@code defc} differs from the class
* loader of the class from which the reflective request came.
* <li>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
...
...
@@ -304,8 +314,6 @@ public class MethodHandles {
* smgr.checkPackageAccess(defcPkg)} is called,
* where {@code defcPkg} is the package of {@code defc}.
* </ul>
* 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
{
...
...
@@ -559,7 +567,10 @@ public class MethodHandles {
* @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}
* @throws IllegalAccessException if access checking fails,
* or if the method is not {@code static},
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
...
...
@@ -567,6 +578,7 @@ public class MethodHandles {
public
MethodHandle
findStatic
(
Class
<?>
refc
,
String
name
,
MethodType
type
)
throws
NoSuchMethodException
,
IllegalAccessException
{
MemberName
method
=
resolveOrFail
(
refc
,
name
,
type
,
true
);
checkSecurityManager
(
refc
,
method
);
// stack walk magic: do not refactor
checkMethod
(
refc
,
method
,
true
);
return
MethodHandleImpl
.
findMethod
(
method
,
false
,
lookupClassOrNull
());
}
...
...
@@ -601,13 +613,17 @@ public class MethodHandles {
* @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}
* @throws IllegalAccessException if access checking fails,
* or if the method is {@code static}
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @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
);
checkSecurityManager
(
refc
,
method
);
// stack walk magic: do not refactor
checkMethod
(
refc
,
method
,
false
);
MethodHandle
mh
=
MethodHandleImpl
.
findMethod
(
method
,
true
,
lookupClassOrNull
());
return
restrictProtectedReceiver
(
method
,
mh
);
...
...
@@ -633,6 +649,8 @@ public class MethodHandles {
* @return the desired method handle
* @throws NoSuchMethodException if the constructor does not exist
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
...
...
@@ -641,6 +659,7 @@ public class MethodHandles {
String
name
=
"<init>"
;
MemberName
ctor
=
resolveOrFail
(
refc
,
name
,
type
,
false
,
false
,
lookupClassOrNull
());
assert
(
ctor
.
isConstructor
());
checkSecurityManager
(
refc
,
ctor
);
// stack walk magic: do not refactor
checkAccess
(
refc
,
ctor
);
MethodHandle
rawMH
=
MethodHandleImpl
.
findMethod
(
ctor
,
false
,
lookupClassOrNull
());
MethodHandle
allocMH
=
MethodHandleImpl
.
makeAllocator
(
rawMH
);
...
...
@@ -658,7 +677,7 @@ public class MethodHandles {
int
arity
=
type
.
parameterCount
();
return
mh
.
asVarargsCollector
(
type
.
parameterType
(
arity
-
1
));
}
else
{
throw
new
InternalError
(
"already varargs, but template is not: "
+
mh
);
return
mh
.
asFixedArity
(
);
}
}
...
...
@@ -690,6 +709,8 @@ public class MethodHandles {
* @return the desired method handle
* @throws NoSuchMethodException if the method does not exist
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
...
...
@@ -698,6 +719,7 @@ public class MethodHandles {
Class
<?>
specialCaller
)
throws
NoSuchMethodException
,
IllegalAccessException
{
checkSpecialCaller
(
specialCaller
);
MemberName
method
=
resolveOrFail
(
refc
,
name
,
type
,
false
,
false
,
specialCaller
);
checkSecurityManager
(
refc
,
method
);
// stack walk magic: do not refactor
checkMethod
(
refc
,
method
,
false
);
MethodHandle
mh
=
MethodHandleImpl
.
findMethod
(
method
,
false
,
specialCaller
);
return
restrictReceiver
(
method
,
mh
,
specialCaller
);
...
...
@@ -721,7 +743,9 @@ public class MethodHandles {
* @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
);
MemberName
field
=
resolveOrFail
(
refc
,
name
,
type
,
false
);
checkSecurityManager
(
refc
,
field
);
// stack walk magic: do not refactor
return
makeAccessor
(
refc
,
field
,
false
,
false
,
0
);
}
/**
...
...
@@ -742,7 +766,9 @@ public class MethodHandles {
* @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
);
MemberName
field
=
resolveOrFail
(
refc
,
name
,
type
,
false
);
checkSecurityManager
(
refc
,
field
);
// stack walk magic: do not refactor
return
makeAccessor
(
refc
,
field
,
false
,
true
,
0
);
}
/**
...
...
@@ -762,7 +788,9 @@ public class MethodHandles {
* @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
);
MemberName
field
=
resolveOrFail
(
refc
,
name
,
type
,
true
);
checkSecurityManager
(
refc
,
field
);
// stack walk magic: do not refactor
return
makeAccessor
(
refc
,
field
,
false
,
false
,
1
);
}
/**
...
...
@@ -782,7 +810,9 @@ public class MethodHandles {
* @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
);
MemberName
field
=
resolveOrFail
(
refc
,
name
,
type
,
true
);
checkSecurityManager
(
refc
,
field
);
// stack walk magic: do not refactor
return
makeAccessor
(
refc
,
field
,
false
,
true
,
1
);
}
/**
...
...
@@ -805,10 +835,13 @@ public class MethodHandles {
* <p>
* This is equivalent to the following code:
* <blockquote><pre>
MethodHandle mh0 = {@link #findVirtual findVirtual}(defc, name, type);
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle mh0 = lookup().{@link #findVirtual findVirtual}(defc, name, type);
MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver);
MethodType mt1 = mh1.type();
if (mh0.isVarargsCollector()
&& mt1.parameterCount() > 0) {
if (mh0.isVarargsCollector()
)
mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
return mh1;
* </pre></blockquote>
...
...
@@ -822,6 +855,8 @@ return mh1;
* @return the desired method handle
* @throws NoSuchMethodException if the method does not exist
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
...
...
@@ -829,13 +864,12 @@ return mh1;
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
);
checkSecurityManager
(
refc
,
method
);
// stack walk magic: do not refactor
checkMethod
(
refc
,
method
,
false
);
MethodHandle
dmh
=
MethodHandleImpl
.
findMethod
(
method
,
true
,
lookupClassOrNull
());
MethodHandle
bmh
=
MethodHandleImpl
.
bindReceiver
(
dmh
,
receiver
);
if
(
bmh
==
null
)
throw
method
.
makeAccessException
(
"no access"
,
this
);
if
(
dmh
.
type
().
parameterCount
()
==
0
)
return
dmh
;
// bound the trailing parameter; no varargs possible
return
fixVarargs
(
bmh
,
dmh
);
}
...
...
@@ -856,6 +890,8 @@ return mh1;
* @param m the reflected method
* @return a method handle which can invoke the reflected method
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
public
MethodHandle
unreflect
(
Method
m
)
throws
IllegalAccessException
{
...
...
@@ -884,6 +920,8 @@ return mh1;
* @param specialCaller the class nominally calling the method
* @return a method handle which can invoke the reflected method
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if any argument is null
*/
public
MethodHandle
unreflectSpecial
(
Method
m
,
Class
<?>
specialCaller
)
throws
IllegalAccessException
{
...
...
@@ -913,6 +951,8 @@ return mh1;
* @param c the reflected constructor
* @return a method handle which can invoke the reflected constructor
* @throws IllegalAccessException if access checking fails
* or if the method's variable arity modifier bit
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
public
MethodHandle
unreflectConstructor
(
Constructor
c
)
throws
IllegalAccessException
{
...
...
@@ -939,7 +979,7 @@ return mh1;
* @throws NullPointerException if the argument is null
*/
public
MethodHandle
unreflectGetter
(
Field
f
)
throws
IllegalAccessException
{
return
makeAccessor
(
f
.
getDeclaringClass
(),
new
MemberName
(
f
),
f
.
isAccessible
(),
false
);
return
makeAccessor
(
f
.
getDeclaringClass
(),
new
MemberName
(
f
),
f
.
isAccessible
(),
false
,
-
1
);
}
/**
...
...
@@ -957,7 +997,7 @@ return mh1;
* @throws NullPointerException if the argument is null
*/
public
MethodHandle
unreflectSetter
(
Field
f
)
throws
IllegalAccessException
{
return
makeAccessor
(
f
.
getDeclaringClass
(),
new
MemberName
(
f
),
f
.
isAccessible
(),
true
);
return
makeAccessor
(
f
.
getDeclaringClass
(),
new
MemberName
(
f
),
f
.
isAccessible
(),
true
,
-
1
);
}
/// Helper methods, all package-private.
...
...
@@ -993,6 +1033,46 @@ return mh1;
throw
new
MemberName
(
refc
).
makeAccessException
(
"symbolic reference class is not public"
,
this
);
}
/**
* Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
* This function performs stack walk magic: do not refactor it.
*/
void
checkSecurityManager
(
Class
<?>
refc
,
MemberName
m
)
{
SecurityManager
smgr
=
System
.
getSecurityManager
();
if
(
smgr
==
null
)
return
;
if
(
allowedModes
==
TRUSTED
)
return
;
// Step 1:
smgr
.
checkMemberAccess
(
refc
,
Member
.
PUBLIC
);
// Step 2:
if
(!
VerifyAccess
.
classLoaderIsAncestor
(
lookupClass
,
refc
))
smgr
.
checkPackageAccess
(
VerifyAccess
.
getPackageName
(
refc
));
// Step 3:
if
(
m
.
isPublic
())
return
;
Class
<?>
defc
=
m
.
getDeclaringClass
();
smgr
.
checkMemberAccess
(
defc
,
Member
.
DECLARED
);
// STACK WALK HERE
// Step 4:
if
(
defc
!=
refc
)
smgr
.
checkPackageAccess
(
VerifyAccess
.
getPackageName
(
defc
));
// Comment from SM.checkMemberAccess, where which=DECLARED:
/*
* stack depth of 4 should be the caller of one of the
* methods in java.lang.Class that invoke checkMember
* access. The stack should look like:
*
* someCaller [3]
* java.lang.Class.someReflectionAPI [2]
* java.lang.Class.checkMemberAccess [1]
* SecurityManager.checkMemberAccess [0]
*
*/
// For us it is this stack:
// someCaller [3]
// Lookup.findSomeMember [2]
// Lookup.checkSecurityManager [1]
// SecurityManager.checkMemberAccess [0]
}
void
checkMethod
(
Class
<?>
refc
,
MemberName
m
,
boolean
wantStatic
)
throws
IllegalAccessException
{
String
message
;
if
(
m
.
isConstructor
())
...
...
@@ -1065,6 +1145,7 @@ return mh1;
if
(!
method
.
isProtected
()
||
method
.
isStatic
()
||
allowedModes
==
TRUSTED
||
method
.
getDeclaringClass
()
==
lookupClass
()
||
VerifyAccess
.
isSamePackage
(
method
.
getDeclaringClass
(),
lookupClass
())
||
(
ALLOW_NESTMATE_ACCESS
&&
VerifyAccess
.
isSamePackageMember
(
method
.
getDeclaringClass
(),
lookupClass
())))
return
mh
;
...
...
@@ -1084,19 +1165,14 @@ return mh1;
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
field
.
makeAccessException
(
isStatic
?
"expected a static field"
:
"expected a non-static field"
,
this
);
return
makeAccessor
(
refc
,
field
,
false
,
isSetter
);
}
MethodHandle
makeAccessor
(
Class
<?>
refc
,
MemberName
field
,
boolean
trusted
,
boolean
isSetter
)
throws
IllegalAccessException
{
boolean
trusted
,
boolean
isSetter
,
int
checkStatic
)
throws
IllegalAccessException
{
assert
(
field
.
isField
());
if
(
checkStatic
>=
0
&&
(
checkStatic
!=
0
)
!=
field
.
isStatic
())
throw
field
.
makeAccessException
((
checkStatic
!=
0
)
?
"expected a static field"
:
"expected a non-static field"
,
this
);
if
(
trusted
)
return
MethodHandleImpl
.
accessField
(
field
,
isSetter
,
lookupClassOrNull
());
checkAccess
(
refc
,
field
);
...
...
@@ -1138,50 +1214,51 @@ return mh1;
/**
* Produces a method handle which will invoke any method handle of the
* given {@code type}
on a standard set of {@code Object} type arguments
* a
nd a
single trailing {@code Object[]} array.
* given {@code type}
, with a given number of trailing arguments replaced by
* a single trailing {@code Object[]} array.
* The resulting invoker will be a method handle with the following
* arguments:
* <ul>
* <li>a single {@code MethodHandle} target
* <li>zero or more
{@code Object} values (counted by {@code object
ArgCount})
* <li>an {@code Object[]} array containing
more
arguments
* <li>zero or more
leading values (counted by {@code leading
ArgCount})
* <li>an {@code Object[]} array containing
trailing
arguments
* </ul>
* <p>
* The invoker will
behave
like a call to {@link MethodHandle#invoke invoke} with
* The invoker will
invoke its target
like a call to {@link MethodHandle#invoke invoke} 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}.
* <p>
* 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[]}.
* will have all parameters except the first {@code leadingArgCount}
* replaced by a single array of type {@code Object[]}, which will be
* the final parameter.
* <p>
* Before invoking its target, the invoker will spread the
varargs
array, apply
* Before invoking its target, the invoker will spread the
final
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.
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
MethodHandle invoker = MethodHandles.invoker(type);
int spreadArgCount = type.parameterCount
- object
ArgCount;
int spreadArgCount = type.parameterCount
() - leading
ArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
* </pre></blockquote>
* <p>
* This method throws no reflective or security exceptions.
* @param type the desired target type
* @param
objectArgCount number of fixed (non-varargs) {@code Object} arguments
* @param
leadingArgCount number of fixed arguments, to be passed unchanged to the target
* @return a method handle suitable for invoking any method handle of the given type
* @throws NullPointerException if {@code type} is null
* @throws IllegalArgumentException if {@code leadingArgCount} is not in
* the range from 0 to {@code type.parameterCount()} inclusive
*/
static
public
MethodHandle
spreadInvoker
(
MethodType
type
,
int
object
ArgCount
)
{
if
(
objectArgCount
<
0
||
object
ArgCount
>
type
.
parameterCount
())
throw
new
IllegalArgumentException
(
"bad argument count "
+
object
ArgCount
);
return
type
.
invokers
().
spreadInvoker
(
object
ArgCount
);
MethodHandle
spreadInvoker
(
MethodType
type
,
int
leading
ArgCount
)
{
if
(
leadingArgCount
<
0
||
leading
ArgCount
>
type
.
parameterCount
())
throw
new
IllegalArgumentException
(
"bad argument count "
+
leading
ArgCount
);
return
type
.
invokers
().
spreadInvoker
(
leading
ArgCount
);
}
/**
...
...
@@ -1211,7 +1288,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* method handle values, as long as they are compatible with the type of {@code X}.
* <p>
* <em>(Note: The invoker method is not available via the Core Reflection API.
* An attempt to call {@linkplain java.lang.reflect.Method#invoke Method.invoke}
* An attempt to call {@linkplain java.lang.reflect.Method#invoke
java.lang.reflect.
Method.invoke}
* on the declared {@code invokeExact} or {@code invoke} method will raise an
* {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
* <p>
...
...
@@ -1231,12 +1308,18 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
* <p>
* Before invoking its target, the invoker will apply reference casts as
* Before invoking its target, if the target differs from the expected type,
* the invoker will apply reference casts as
* necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
* Similarly, the return value will be converted as necessary.
* If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
* the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
* <p>
* A {@linkplain MethodType#genericMethodType general method type},
* mentions only {@code Object} arguments and return values.
* An invoker for such a type is capable of calling any method handle
* of the same arity as the general type.
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
publicLookup().findVirtual(MethodHandle.class, "invoke", type)
...
...
@@ -1251,19 +1334,10 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
return
type
.
invokers
().
generalInvoker
();
}
/**
* <em>Temporary alias</em> for {@link #invoker}, for backward compatibility with some versions of JSR 292.
* @deprecated Will be removed for JSR 292 Proposed Final Draft.
*/
public
static
MethodHandle
genericInvoker
(
MethodType
type
)
{
return
invoker
(
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.
* or (if T0 is primitive) of the wrapper
class
corresponding to T0.
* The following checks and conversions are made:
* <ul>
* <li>If T0 and T1 are references, then a cast to T1 is applied.
...
...
@@ -1271,11 +1345,11 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* <li>If T0 and T1 are primitives, then a widening or narrowing
* conversion is applied, if one exists.
* <li>If T0 is a primitive and T1 a reference, and
* T0 has a wrapper
type
TW, a boxing conversion to TW is applied,
* T0 has a wrapper
class
TW, a boxing conversion to TW is applied,
* possibly followed by a reference conversion.
* T1 must be TW or a supertype.
* <li>If T0 is a reference and T1 a primitive, and
* T1 has a wrapper
type
TW, an unboxing conversion is applied,
* T1 has a wrapper
class
TW, an unboxing conversion is applied,
* possibly preceded by a reference conversion.
* T0 must be TW or a supertype.
* <li>If T1 is void, the return value is discarded
...
...
@@ -1288,6 +1362,7 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* @return the value, converted if necessary
* @throws java.lang.ClassCastException if a cast fails
*/
// FIXME: This is used in just one place. Refactor away.
static
<
T0
,
T1
>
T1
checkValue
(
Class
<
T0
>
t0
,
Class
<
T1
>
t1
,
Object
value
)
throws
ClassCastException
...
...
@@ -1316,6 +1391,8 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
return
w1
.
convert
(
value
,
t1
);
}
// FIXME: Delete this. It is used only for insertArguments & bindTo.
// Replace by a more standard check.
static
Object
checkValue
(
Class
<?>
T1
,
Object
value
)
throws
ClassCastException
...
...
@@ -1332,134 +1409,53 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
/**
* Produces a method handle which adapts the type of the
* given method handle to a new type by pairwise argument conversion.
* given method handle to a new type by pairwise argument
and return type
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.
* <p>
* If the original type and new type are equal, returns target.
* <p>
* 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:
* <ul>
* <li>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.)
* <li>If T0 and T1 are primitives, then a Java method invocation
* conversion (JLS 5.3) is applied, if one exists.
* <li>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.
* <li>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.)
* <li>If the return type T1 is void, any returned value is discarded
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
* </ul>
* @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
)
{
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
1
);
}
/**
* 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.
* <p>
* If the original type and new type are equal, returns target.
* <p>
* The same conversions are allowed as for {@link #convertArguments convertArguments},
* The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
* 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:
* Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
* if possible, before or instead of any conversions done by {@code asType}:
* <ul>
* <li>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.
* <li>If
<em>T0</em> and <em>T1</em> are references, and <em>T1</em>
is an interface type,
* then the value of type
<em>T0</em> is passed as a <em>T1</em>
without a cast.
* (This treatment of interfaces follows the usage of the bytecode verifier.)
* <li>If
T0 and T1 are primitives and one is boolean
,
* the boolean is
treated as a one-bit unsigned integer
.
* <li>If
<em>T0</em> is boolean and <em>T1</em> is another primitive
,
* the boolean is
converted to a byte value, 1 for true, 0 for false
.
* (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.
* <li>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.
* <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
* <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
* and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
* <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
* then a Java casting conversion (JLS 5.5) is applied.
* (Specifically, <em>T0</em> will convert to <em>T1</em> by
* widening and/or narrowing.)
* <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
* conversion will be applied at runtime, possibly followed
* by a Java casting conversion (JLS 5.5) on the primitive value,
* possibly followed by a conversion from byte to boolean by testing
* the low-order bit.
* <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
* and if the reference is null at runtime, a zero value is introduced.
* </ul>
* @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
* @return a method handle which delegates to
the 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
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
2
);
}
/*
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.
...
...
@@ -1478,8 +1474,8 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* <p>
* 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
argument
s in the target method handle.
* must be identical to the type of the corresponding outgoing
parameter
* or
parameter
s in the target method handle.
* The return type of {@code newType} must be identical to the return
* type of the original target.
* <p>
...
...
@@ -1491,25 +1487,33 @@ publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* incoming arguments which are not mentioned in the reordering array
* are may be any type, as determined only by {@code newType}.
* <blockquote><pre>
MethodType intfn1 = MethodType.methodType(int.class, int.class);
MethodType intfn2 = MethodType.methodType(int.class, int.class, int.class);
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodType intfn1 = methodType(int.class, int.class);
MethodType intfn2 = methodType(int.class, int.class, int.class);
MethodHandle sub = ... {int x, int y => x-y} ...;
assert(sub.type().equals(intfn2));
MethodHandle sub1 =
MethodHandles.
permuteArguments(sub, intfn2, 0, 1);
MethodHandle rsub =
MethodHandles.
permuteArguments(sub, intfn2, 1, 0);
MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
assert((int)rsub.invokeExact(1, 100) == 99);
MethodHandle add = ... {int x, int y => x+y} ...;
assert(add.type().equals(intfn2));
MethodHandle twice =
MethodHandles.
permuteArguments(add, intfn1, 0, 0);
MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
assert(twice.type().equals(intfn1));
assert((int)twice.invokeExact(21) == 42);
* </pre></blockquote>
* @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
* @param reorder a
n index array
which controls the reordering
* @return a method handle which delegates to
the target
after it
* drops unused arguments and moves and/or duplicates the other arguments
* @throws NullPointerException if any argument is null
* @throws IllegalArgumentException if the index array length is not equal to
* the arity of the target, or if any index array element
* not a valid index for a parameter of {@code newType},
* or if two corresponding parameter types in
* {@code target.type()} and {@code newType} are not identical,
*/
public
static
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
...
...
@@ -1543,70 +1547,6 @@ assert((int)twice.invokeExact(21) == 42);
throw
newIllegalArgumentException
(
"bad reorder array: "
+
Arrays
.
toString
(
reorder
));
}
/**
* Equivalent to the following code:
* <p><blockquote><pre>
* int spreadPos = newType.parameterCount() - 1;
* Class<?> spreadType = newType.parameterType(spreadPos);
* int spreadCount = target.type().parameterCount() - spreadPos;
* MethodHandle adapter = target.asSpreader(spreadType, spreadCount);
* adapter = adapter.asType(newType);
* return adapter;
* </pre></blockquote>
* @param target the method handle to invoke after argument spreading
* @param newType the expected type of the new method handle
* @return a method handle which spreads its final argument,
* before calling the original method handle
*/
/*non-public*/
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodType
oldType
=
target
.
type
();
int
inargs
=
newType
.
parameterCount
();
int
outargs
=
oldType
.
parameterCount
();
int
spreadPos
=
inargs
-
1
;
int
numSpread
=
(
outargs
-
spreadPos
);
MethodHandle
res
=
null
;
if
(
spreadPos
>=
0
&&
numSpread
>=
0
)
{
res
=
MethodHandleImpl
.
spreadArguments
(
target
,
newType
,
spreadPos
);
}
if
(
res
==
null
)
{
throw
newIllegalArgumentException
(
"cannot spread "
+
newType
+
" to "
+
oldType
);
}
return
res
;
}
/**
* Equivalent to the following code:
* <p><blockquote><pre>
* int collectPos = target.type().parameterCount() - 1;
* Class<?> collectType = target.type().parameterType(collectPos);
* if (!collectType.isArray()) collectType = Object[].class;
* int collectCount = newType.parameterCount() - collectPos;
* MethodHandle adapter = target.asCollector(collectType, collectCount);
* adapter = adapter.asType(newType);
* return adapter;
* </pre></blockquote>
* @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
(
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.
...
...
@@ -1614,8 +1554,7 @@ assert((int)twice.invokeExact(21) == 42);
* 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.
* <p>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)}.
* <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
* @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
...
...
@@ -1637,7 +1576,6 @@ assert((int)twice.invokeExact(21) == 42);
/**
* Produces a method handle which returns its sole argument when invoked.
* <p>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
...
...
@@ -1657,11 +1595,15 @@ assert((int)twice.invokeExact(21) == 42);
}
/**
* 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 <em>bound parameters</em>, because the new method
* will contain bindings for those parameters take from {@code values}.
* Provides a target method handle with one or more <em>bound arguments</em>
* in advance of the method handle's invocation.
* The formal parameters to the target corresponding to the bound
* arguments are called <em>bound parameters</em>.
* Returns a new method handle which saves away the bound arguments.
* When it is invoked, it receives arguments for any non-bound parameters,
* binds the saved arguments to their corresponding parameters,
* and calls the original target.
* <p>
* 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.
...
...
@@ -1670,15 +1612,16 @@ assert((int)twice.invokeExact(21) == 42);
* If a bound parameter type is a primitive, the argument object
* must be a wrapper, and will be unboxed to produce the primitive value.
* <p>
* The <i>pos</i> may range between zero and <i>N</i> (inclusively),
* where <i>N</i> is the number of argument types in resulting method handle
* (after bound parameter types are dropped).
* The {@code pos} argument selects which parameters are to be bound.
* It may range between zero and <i>N-L</i> (inclusively),
* where <i>N</i> is the arity of the target method handle
* and <i>L</i> is the length of the values array.
* @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} argumen
t or the {@code values} array is null
* @throws NullPointerException if the
targe
t or the {@code values} array is null
* @see MethodHandle#bindTo
*/
public
static
...
...
@@ -1711,15 +1654,17 @@ assert((int)twice.invokeExact(21) == 42);
}
/**
* 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.
* <p>
* The <i>pos</i> may range between zero and <i>N</i>,
* where <i>N</i> is the number of argument types in <i>target</i>,
* meaning to drop the first or last argument (respectively),
* or an argument somewhere in between.
* Produces a method handle which will discard some dummy arguments
* before calling some other specified <i>target</i> method handle.
* The type of the new method handle will be the same as the target's type,
* except it will also include the dummy argument types,
* at some given position.
* <p>
* The {@code pos} argument may range between zero and <i>N</i>,
* where <i>N</i> is the arity of the target.
* If {@code pos} is zero, the dummy arguments will precede
* the target's real arguments; if {@code pos} is <i>N</i>
* they will come after.
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
...
...
@@ -1744,14 +1689,16 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
* @param pos position of first argument to drop (zero for the leftmost)
* @return a method handle which drops arguments of the given types,
* before calling the original method handle
* @throws NullPointerException if the
{@code target} argumen
t is null,
* @throws NullPointerException if the
targe
t 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}
* @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
* or if {@code pos} is negative or greater than the arity of the target,
* or if the new method handle's type would have too many parameters
*/
public
static
MethodHandle
dropArguments
(
MethodHandle
target
,
int
pos
,
List
<
Class
<?>>
valueTypes
)
{
MethodType
oldType
=
target
.
type
();
// get NPE
if
(
valueTypes
.
size
()
==
0
)
return
target
;
MethodType
oldType
=
target
.
type
();
int
outargs
=
oldType
.
parameterCount
();
int
inargs
=
outargs
+
valueTypes
.
size
();
if
(
pos
<
0
||
pos
>=
inargs
)
...
...
@@ -1764,15 +1711,17 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
}
/**
* 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.
* <p>
* The <i>pos</i> may range between zero and <i>N</i>,
* where <i>N</i> is the number of argument types in <i>target</i>,
* meaning to drop the first or last argument (respectively),
* or an argument somewhere in between.
* Produces a method handle which will discard some dummy arguments
* before calling some other specified <i>target</i> method handle.
* The type of the new method handle will be the same as the target's type,
* except it will also include the dummy argument types,
* at some given position.
* <p>
* The {@code pos} argument may range between zero and <i>N</i>,
* where <i>N</i> is the arity of the target.
* If {@code pos} is zero, the dummy arguments will precede
* the target's real arguments; if {@code pos} is <i>N</i>
* they will come after.
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
...
...
@@ -1801,9 +1750,11 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* @param pos position of first argument to drop (zero for the leftmost)
* @return a method handle which drops arguments of the given types,
* before calling the original method handle
* @throws NullPointerException if the
{@code target} argumen
t is null,
* @throws NullPointerException if the
targe
t 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}
* @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
* or if {@code pos} is negative or greater than the arity of the target,
* or if the new method handle's type would have too many parameters
*/
public
static
MethodHandle
dropArguments
(
MethodHandle
target
,
int
pos
,
Class
<?>...
valueTypes
)
{
...
...
@@ -1811,19 +1762,23 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
}
/**
* Adapts a target method handle
{@code target}
by pre-processing
* Adapts a target method handle 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.
* <p>
* 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.
* The first element of the filter array corresponds to the {@code pos}
* argument of the target, and so on in sequence.
* <p>
* Null arguments in the array are treated as identity functions,
* 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.
* <p>
* 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
* the
target
, 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.
...
...
@@ -1831,6 +1786,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* parameter type of the target.
* <p>
* It is an error if there are elements of {@code filters}
* (null or not)
* which do not correspond to argument positions in the target.
* <b>Example:</b>
* <p><blockquote><pre>
...
...
@@ -1848,16 +1804,24 @@ MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
* </pre></blockquote>
* <p> Here is pseudocode for the resulting adapter:
* <blockquote><pre>
* V target(P... p, A[i]... a[i], B... b);
* A[i] filter[i](V[i]);
* T adapter(P... p, V[i]... v[i], B... b) {
* return target(p..., f[i](v[i])..., b...);
* }
* </pre></blockquote>
*
* @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} argumen
t is null
* @throws NullPointerException if the
targe
t 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,
* does not match a corresponding argument type of
target
as described above,
* or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()}
*/
public
static
...
...
@@ -1891,15 +1855,18 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
}
/**
* Adapts a target method handle {@code target} by post-processing
* its return value with a unary filter function.
* Adapts a target method handle by post-processing
* its return value (if any) with a filter (another method handle).
* The result of the filter is returned from the adapter.
* <p>
* 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}
* If the target returns a value, the filter must accept that value as
* its only argument.
* If the target returns void, the filter must accept no arguments.
* <p>
* The return type of the filter
* replaces the return type of the target
* in the resulting adapted method handle.
* The argument type of
{@code F}
must be identical to the
* The argument type of
the filter (if any)
must be identical to the
* return type of the target.
* <b>Example:</b>
* <p><blockquote><pre>
...
...
@@ -1913,13 +1880,36 @@ MethodHandle length = lookup().findVirtual(String.class,
System.out.println((String) cat.invokeExact("x", "y")); // xy
MethodHandle f0 = filterReturnValue(cat, length);
System.out.println((int) f0.invokeExact("x", "y")); // 2
* </pre></blockquote>
* <p> Here is pseudocode for the resulting adapter:
* <blockquote><pre>
* V target(A...);
* T filter(V);
* T adapter(A... a) {
* V v = target(a...);
* return filter(v);
* }
* // and if the target has a void return:
* void target2(A...);
* T filter2();
* T adapter2(A... a) {
* target2(a...);
* return filter2();
* }
* // and if the filter has a void return:
* V target3(A...);
* void filter3(V);
* void adapter3(A... a) {
* V v = target3(a...);
* filter3(v);
* }
* </pre></blockquote>
* @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
* @throws IllegalArgumentException if
the argument list of
{@code filter}
* does not match the return type of
target
as described above
*/
public
static
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
...
...
@@ -1948,55 +1938,87 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
* Adapts a target method handle
{@code target}
by pre-processing
* Adapts a target method handle by pre-processing
* some of its arguments, and then calling the target with
* the result of the pre-processing, plus all original arguments.
* <p>
* 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 result of the pre-processing, inserted into the original
* sequence of arguments.
* <p>
* The pre-processing is performed by {@code combiner}, a second method handle.
* Of the arguments passed to the adapter, the first {@code N} arguments
* are copied to the combiner, which is then called.
* (Here, {@code N} is defined as the parameter count of the combiner.)
* After this, control passes to the target, with any result
* from the combiner inserted before the original {@code N} incoming
* arguments.
* <p>
* If the combiner returns a value, the first parameter type of the target
* must be identical with the return type of the combiner, and the next
* {@code N} parameter types of the target must exactly match the parameters
* of the combiner.
* <p>
* If the combiner has a void return, no result will be inserted,
* and the first {@code N} parameter types of the target
* must exactly match the parameters of the combiner.
* <p>
* 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.
* first parameter type is dropped,
* if it corresponds to the result of the combiner.
* <p>
* (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.
* that either the
combiner or the 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.)
* <p>
* The first argument of the target must be identical with the
* return value of the combiner.
* <b>Example:</b>
* <p><blockquote><pre>
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
"println", methodType(void.class, String.class))
.bindTo(System.out);
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
MethodHandle catTrace = foldArguments(cat, trace);
// also prints "boo":
assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* </pre></blockquote>
* <p> Here is pseudocode for the resulting adapter:
* <blockquote><pre>
* // there are N arguments in
the A sequence
* // there are N arguments in
A...
* T target(V, A[N]..., B...);
* V combiner(A...);
* T adapter(A... a, B... b) {
* V v = combiner(a...);
* return target(v, a..., b...);
* }
* // and if the combiner has a void return:
* T target2(A[N]..., B...);
* void combiner2(A...);
* T adapter2(A... a, B... b) {
* combiner2(a...);
* return target2(a..., b...);
* }
* </pre></blockquote>
* @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}
* @throws IllegalArgumentException if {@code combiner}'s return type
* is non-void and not the same as the first argument type of
* the target, or if the initial {@code N} argument types
* of the target
* (skipping one matching the {@code combiner}'s return type)
* are not identical with the argument types of {@code combiner}
*/
public
static
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodHandle
combiner
)
{
int
pos
=
0
;
MethodType
targetType
=
target
.
type
();
MethodType
combinerType
=
combiner
.
type
();
int
foldPos
=
0
;
// always at the head, at present
int
foldPos
=
pos
;
int
foldArgs
=
combinerType
.
parameterCount
();
int
foldVals
=
combinerType
.
returnType
()
==
void
.
class
?
0
:
1
;
int
afterInsertPos
=
foldPos
+
foldVals
;
...
...
@@ -2045,7 +2067,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* @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}
).
* type of {@code test} changed to match that of
the target
).
*/
public
static
MethodHandle
guardWithTest
(
MethodHandle
test
,
...
...
@@ -2135,7 +2157,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
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
,
h
args
.
subList
(
hpc
,
tpc
));
handler
=
dropArguments
(
handler
,
1
+
hpc
,
t
args
.
subList
(
hpc
,
tpc
));
htype
=
handler
.
type
();
}
return
MethodHandleImpl
.
makeGuardWithCatch
(
target
,
exType
,
handler
);
...
...
@@ -2155,234 +2177,4 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
throwException
(
Class
<?>
returnType
,
Class
<?
extends
Throwable
>
exType
)
{
return
MethodHandleImpl
.
throwException
(
MethodType
.
methodType
(
returnType
,
exType
));
}
/**
* Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
* <p>
* A single-method interface is an interface which declares a unique method.
* When determining the unique method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
* are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
* <p>
* The type must be public. No additional access checks are performed.
* <p>
* The resulting instance of the required type will respond to
* invocation of the 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.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* <p>
* The wrapper instance will implement the requested interface
* and its super-types, but no other single-method interfaces.
* This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
* multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the requested 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.
* <p>
* 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.
* <p>
* Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
* and other corner cases, the interface may also have several abstract methods
* with the same name but having distinct descriptors (types of returns and parameters).
* In this case, all the methods are bound in common to the one given {@code target}.
* The type check and effective {@code asType} conversion is applied to each
* method type descriptor, and all abstract methods are bound to the {@code target} in common.
* Beyond this type check, no further checks are made to determine that the
* abstract methods are related in any way.
* <p>
* 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 smType the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given {@code target}
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the {@code smType} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the {@code target} cannot
* be converted to the type required by the requested interface
*/
// Other notes to implementors:
// <p>
// No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
// classes might be used for the same type.
// <p>
// If the implementation is able
// to prove that a wrapper of the required 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.
// <p>
// 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 single-abstract-method 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
>
T
asInstance
(
final
MethodHandle
target
,
final
Class
<
T
>
smType
)
{
// POC implementation only; violates the above contract several ways
final
Method
sm
=
getSingleMethod
(
smType
);
if
(
sm
==
null
)
throw
new
IllegalArgumentException
(
"not a single-method interface: "
+
smType
.
getName
());
MethodType
smMT
=
MethodType
.
methodType
(
sm
.
getReturnType
(),
sm
.
getParameterTypes
());
MethodHandle
checkTarget
=
target
.
asType
(
smMT
);
// make throw WMT
checkTarget
=
checkTarget
.
asType
(
checkTarget
.
type
().
changeReturnType
(
Object
.
class
));
final
MethodHandle
vaTarget
=
checkTarget
.
asSpreader
(
Object
[].
class
,
smMT
.
parameterCount
());
return
smType
.
cast
(
Proxy
.
newProxyInstance
(
smType
.
getClassLoader
(),
new
Class
[]{
smType
,
WrapperInstance
.
class
},
new
InvocationHandler
()
{
private
Object
getArg
(
String
name
)
{
if
((
Object
)
name
==
"getWrapperInstanceTarget"
)
return
target
;
if
((
Object
)
name
==
"getWrapperInstanceType"
)
return
smType
;
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
(
sm
))
return
vaTarget
.
invokeExact
(
args
);
if
(
isObjectMethod
(
method
))
return
callObjectMethod
(
this
,
method
,
args
);
throw
new
InternalError
();
}
}));
}
/**
* Determines 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 unique 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 unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public
static
MethodHandle
wrapperInstanceTarget
(
Object
x
)
{
return
asWrapperInstance
(
x
).
getWrapperInstanceTarget
();
}
/**
* Recovers the unique single-method interface 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 single-method interface 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
getSingleMethod
(
Class
<?>
smType
)
{
Method
sm
=
null
;
for
(
Method
m
:
smType
.
getMethods
())
{
int
mod
=
m
.
getModifiers
();
if
(
Modifier
.
isAbstract
(
mod
))
{
if
(
sm
!=
null
&&
!
isObjectMethod
(
sm
))
return
null
;
// too many abstract methods
sm
=
m
;
}
}
if
(!
smType
.
isInterface
()
&&
getSingleConstructor
(
smType
)
==
null
)
return
null
;
// wrong kind of constructor
return
sm
;
}
private
static
Constructor
getSingleConstructor
(
Class
<?>
smType
)
{
for
(
Constructor
c
:
smType
.
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
(
target
,
arrayType
);
}
}
src/share/classes/java/lang/invoke/MethodType.java
浏览文件 @
bd11b4f3
...
...
@@ -163,7 +163,13 @@ class MethodType implements java.io.Serializable {
public
static
MethodType
methodType
(
Class
<?>
rtype
,
List
<
Class
<?>>
ptypes
)
{
boolean
notrust
=
false
;
// random List impl. could return evil ptypes array
return
makeImpl
(
rtype
,
ptypes
.
toArray
(
NO_PTYPES
),
notrust
);
return
makeImpl
(
rtype
,
listToArray
(
ptypes
),
notrust
);
}
private
static
Class
<?>[]
listToArray
(
List
<
Class
<?>>
ptypes
)
{
// sanity check the size before the toArray call, since size might be huge
checkSlotCount
(
ptypes
.
size
());
return
ptypes
.
toArray
(
NO_PTYPES
);
}
/**
...
...
@@ -228,7 +234,7 @@ class MethodType implements java.io.Serializable {
*/
/*trusted*/
static
MethodType
makeImpl
(
Class
<?>
rtype
,
Class
<?>[]
ptypes
,
boolean
trusted
)
{
if
(
ptypes
==
null
||
ptypes
.
length
==
0
)
{
if
(
ptypes
.
length
==
0
)
{
ptypes
=
NO_PTYPES
;
trusted
=
true
;
}
MethodType
mt1
=
new
MethodType
(
rtype
,
ptypes
);
...
...
@@ -267,7 +273,7 @@ class MethodType implements java.io.Serializable {
* @param objectArgCount number of parameters (excluding the final array parameter if any)
* @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
* @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray})
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray}
is true
)
* @see #genericMethodType(int)
*/
public
static
...
...
@@ -372,7 +378,7 @@ class MethodType implements java.io.Serializable {
* @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
*/
public
MethodType
insertParameterTypes
(
int
num
,
List
<
Class
<?>>
ptypesToInsert
)
{
return
insertParameterTypes
(
num
,
ptypesToInsert
.
toArray
(
NO_PTYPES
));
return
insertParameterTypes
(
num
,
listToArray
(
ptypesToInsert
));
}
/**
...
...
@@ -449,7 +455,8 @@ class MethodType implements java.io.Serializable {
/**
* 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.
* The reference type {@code java.lang.Void} counts as a wrapper,
* if it occurs as a return type.
* @return true if any of the types are wrappers
*/
public
boolean
hasWrappers
()
{
...
...
@@ -641,15 +648,58 @@ class MethodType implements java.io.Serializable {
}
return
true
;
}
private
static
boolean
canConvert
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
||
dst
==
void
.
class
)
return
true
;
if
(
src
.
isPrimitive
()
&&
dst
.
isPrimitive
())
{
if
(!
Wrapper
.
forPrimitiveType
(
dst
)
.
isConvertibleFrom
(
Wrapper
.
forPrimitiveType
(
src
)))
return
false
;
/*non-public*/
static
boolean
canConvert
(
Class
<?>
src
,
Class
<?>
dst
)
{
// short-circuit a few cases:
if
(
src
==
dst
||
dst
==
Object
.
class
)
return
true
;
// the remainder of this logic is documented in MethodHandle.asType
if
(
src
.
isPrimitive
())
{
// can force void to an explicit null, a la reflect.Method.invoke
// can also force void to a primitive zero, by analogy
if
(
src
==
void
.
class
)
return
true
;
//or !dst.isPrimitive()?
Wrapper
sw
=
Wrapper
.
forPrimitiveType
(
src
);
if
(
dst
.
isPrimitive
())
{
// P->P must widen
return
Wrapper
.
forPrimitiveType
(
dst
).
isConvertibleFrom
(
sw
);
}
else
{
// P->R must box and widen
return
dst
.
isAssignableFrom
(
sw
.
wrapperType
());
}
}
else
if
(
dst
.
isPrimitive
())
{
// any value can be dropped
if
(
dst
==
void
.
class
)
return
true
;
Wrapper
dw
=
Wrapper
.
forPrimitiveType
(
dst
);
// R->P must be able to unbox (from a dynamically chosen type) and widen
// For example:
// Byte/Number/Comparable/Object -> dw:Byte -> byte.
// Character/Comparable/Object -> dw:Character -> char
// Boolean/Comparable/Object -> dw:Boolean -> boolean
// This means that dw must be cast-compatible with src.
if
(
src
.
isAssignableFrom
(
dw
.
wrapperType
()))
{
return
true
;
}
// The above does not work if the source reference is strongly typed
// to a wrapper whose primitive must be widened. For example:
// Byte -> unbox:byte -> short/int/long/float/double
// Character -> unbox:char -> int/long/float/double
if
(
Wrapper
.
isWrapperType
(
src
)
&&
dw
.
isConvertibleFrom
(
Wrapper
.
forWrapperType
(
src
)))
{
// can unbox from src and then widen to dst
return
true
;
}
// We have already covered cases which arise due to runtime unboxing
// of a reference type which covers several wrapper types:
// Object -> cast:Integer -> unbox:int -> long/float/double
// Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
// An marginal case is Number -> dw:Character -> char, which would be OK if there were a
// subclass of Number which wraps a value that can convert to char.
// Since there is none, we don't need an extra check here to cover char or boolean.
return
false
;
}
else
{
// R->R always works, since null is always valid dynamically
return
true
;
}
}
/// Queries which have to do with the bytecode architecture
...
...
@@ -733,15 +783,21 @@ class MethodType implements java.io.Serializable {
* @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 NullPointerException if the string is null
* @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
{
if
(!
descriptor
.
startsWith
(
"("
)
||
// also generates NPE if needed
descriptor
.
indexOf
(
')'
)
<
0
||
descriptor
.
indexOf
(
'.'
)
>=
0
)
throw
new
IllegalArgumentException
(
"not a method descriptor: "
+
descriptor
);
List
<
Class
<?>>
types
=
BytecodeDescriptor
.
parseMethod
(
descriptor
,
loader
);
Class
<?>
rtype
=
types
.
remove
(
types
.
size
()
-
1
);
Class
<?>[]
ptypes
=
types
.
toArray
(
NO_PTYPES
);
checkSlotCount
(
types
.
size
());
Class
<?>[]
ptypes
=
listToArray
(
types
);
return
makeImpl
(
rtype
,
ptypes
,
true
);
}
...
...
src/share/classes/java/lang/invoke/MethodTypeForm.java
浏览文件 @
bd11b4f3
...
...
@@ -448,6 +448,8 @@ class MethodTypeForm {
Class
<?>[]
cs
=
null
;
for
(
int
imax
=
ts
.
length
,
i
=
0
;
i
<
imax
;
i
++)
{
Class
<?>
c
=
canonicalize
(
ts
[
i
],
how
);
if
(
c
==
void
.
class
)
c
=
null
;
// a Void parameter was unwrapped to void; ignore
if
(
c
!=
null
)
{
if
(
cs
==
null
)
cs
=
ts
.
clone
();
...
...
src/share/classes/java/lang/invoke/MutableCallSite.java
浏览文件 @
bd11b4f3
...
...
@@ -37,12 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <!-- JavaDocExamplesTest.testMutableCallSite -->
* <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str
2 = MethodType.methodType(String.class,
String.class);
MethodType MT_str
1 = MethodType.methodType(
String.class);
MethodHandle MH_upcase = MethodHandles.lookup()
.findVirtual(String.class, "toUpperCase", MT_str
2
);
.findVirtual(String.class, "toUpperCase", MT_str
1
);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
...
...
@@ -53,8 +54,10 @@ assertEquals("FRED", (String) worker1.invokeExact());
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
...
...
src/share/classes/java/lang/invoke/SpreadGeneric.java
浏览文件 @
bd11b4f3
...
...
@@ -126,7 +126,7 @@ class SpreadGeneric {
return
spreadGen
;
}
public
String
to
String
()
{
String
debug
String
()
{
return
getClass
().
getSimpleName
()+
targetType
+
"["
+
spreadCount
+
"]"
;
}
...
...
@@ -224,7 +224,7 @@ class SpreadGeneric {
protected
final
MethodHandle
target
;
// (any**N) => R
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
addTypeString
(
target
,
this
);
}
...
...
src/share/classes/java/lang/invoke/SwitchPoint.java
浏览文件 @
bd11b4f3
...
...
@@ -56,16 +56,17 @@ package java.lang.invoke;
* <p>
* Here is an example of a switch point in action:
* <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", M
T_str2
);
.findVirtual(String.class, "concat", M
ethodType.methodType(String.class, String.class)
);
SwitchPoint spt = new SwitchPoint();
assert(spt.isValid());
// 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 worker1 =
MH_
strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(
MH_strcat, MH_strcat.type()
, 1, 0);
MethodHandle worker = spt.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(!spt.isValid());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* <p style="font-size:smaller;">
...
...
@@ -124,6 +125,19 @@ public class SwitchPoint {
this
.
mcsInvoker
=
mcs
.
dynamicInvoker
();
}
/**
* Determines if this switch point is still valid.
* <p>
* Since invalidation is a global and immediate operation,
* this query must be sequenced with any
* other threads that could invalidate this switch point.
* It may therefore be expensive.
* @return true if this switch point has never been invalidated
*/
public
boolean
isValid
()
{
return
(
mcs
.
getTarget
()
==
K_true
);
}
/**
* 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.
...
...
@@ -136,6 +150,7 @@ public class SwitchPoint {
* @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
* @throws IllegalArgumentException if the two method types do not match
* @see MethodHandles#guardWithTest
*/
public
MethodHandle
guardWithTest
(
MethodHandle
target
,
MethodHandle
fallback
)
{
...
...
src/share/classes/java/lang/invoke/ToGeneric.java
浏览文件 @
bd11b4f3
...
...
@@ -258,7 +258,7 @@ class ToGeneric {
return
toGen
;
}
public
String
to
String
()
{
String
debug
String
()
{
return
"ToGeneric"
+
entryType
+(
primsAtEndOrder
!=
null
?
"[reorder]"
:
""
);
}
...
...
@@ -340,7 +340,7 @@ class ToGeneric {
protected
final
MethodHandle
convert
;
// Object -> R
@Override
public
String
to
String
()
{
String
debug
String
()
{
return
target
==
null
?
"prototype:"
+
convert
:
addTypeString
(
target
,
this
);
}
...
...
src/share/classes/java/lang/invoke/package-info.java
浏览文件 @
bd11b4f3
...
...
@@ -28,7 +28,8 @@
* the Java core class libraries and virtual machine.
*
* <p>
* Certain types in this package have special relations to dynamic
* As described in the Java Virtual Machine Specification,
* certain types in this package have special relations to dynamic
* language support in the virtual machine:
* <ul>
* <li>The class {@link java.lang.invoke.MethodHandle MethodHandle} contains
...
...
@@ -42,177 +43,16 @@
* </li>
* </ul>
*
* <h2><a name="jvm_mods"></a>
Corresponding JVM bytecode format
changes</h2>
*
<em>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.</em>
* <h2><a name="jvm_mods"></a>
Summary of relevant Java Virtual Machine
changes</h2>
*
The following low-level information summarizes relevant parts of the
*
Java Virtual Machine specification. For full details, please see the
*
current version of that specification.
*
* <h3><a name="indyinsn"></a>{@code invokedynamic} instruction format</h3>
* 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:
* <ul>
* <li>a bootstrap method (a {@link java.lang.invoke.MethodHandle MethodHandle} constant)</li>
* <li>the dynamic invocation name (a UTF8 string)</li>
* <li>the argument and return types of the call (encoded as a type descriptor in a UTF8 string)</li>
* <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method ({@code ldc}-type constants)</li>
* </ul>
* <p>
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
* 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.
* <p>
* Each occurrence of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
* <h3><a name="indyinsn"></a>{@code invokedynamic} instructions</h3>
* 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 <a href="#bsm">described below</a>.
*
* <h3><a name="indycon"></a>constant pool entries for {@code invokedynamic} instructions</h3>
* 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
* <em>bootstrap method table</em>, which is stored in the {@code BootstrapMethods}
* attribute as <a href="#bsmattr">described below</a>.
* The second pair of bytes must be an index to a {@code CONSTANT_NameAndType}.
* <p>
* 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.
*
* <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodType method types}</h3>
* 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.
* <p>
* The JVM will ensure that on first
* execution of an {@code ldc} instruction for this entry, a {@link java.lang.invoke.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.
*
* <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodHandle method handles}</h3>
* 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.
* <p>
* The JVM will ensure that on first execution of an {@code ldc} instruction
* for this entry, a {@link java.lang.invoke.MethodHandle MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
* <p>
* 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.
* <p>
* Unlike the reflective {@code Lookup} API, there are no security manager calls made
* when these constants are resolved.
* <p>
* The method handle itself will have a type and behavior determined by the subtag as follows:
* <code>
* <table border=1 cellpadding=5 summary="CONSTANT_MethodHandle subtypes">
* <tr><th>N</th><th>subtag name</th><th>member</th><th>MH type</th><th>bytecode behavior</th><th>lookup expression</th></tr>
* <tr><td>1</td><td>REF_getField</td><td>C.f:T</td><td>(C)T</td><td>getfield C.f:T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}</td></tr>
* <tr><td>2</td><td>REF_getStatic</td><td>C.f:T</td><td>( )T</td><td>getstatic C.f:T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}</td></tr>
* <tr><td>3</td><td>REF_putField</td><td>C.f:T</td><td>(C,T)void</td><td>putfield C.f:T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}</td></tr>
* <tr><td>4</td><td>REF_putStatic</td><td>C.f:T</td><td>(T)void</td><td>putstatic C.f:T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}</td></tr>
* <tr><td>5</td><td>REF_invokeVirtual</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokevirtual C.m(A*)T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* <tr><td>6</td><td>REF_invokeStatic</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokestatic C.m(A*)T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}</td></tr>
* <tr><td>7</td><td>REF_invokeSpecial</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokespecial C.m(A*)T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}</td></tr>
* <tr><td>8</td><td>REF_newInvokeSpecial</td><td>C.<init>(A*)void</td><td>(A*)C</td><td>new C; dup; invokespecial C.<init>(A*)void</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}</td></tr>
* <tr><td>9</td><td>REF_invokeInterface</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokeinterface C.m(A*)T</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* </table>
* </code>
* 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*}.
* <p>
* Each method handle constant has an equivalent instruction sequence called its <em>bytecode behavior</em>.
* 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 <em>bytecode behavior</em>.
* 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 <em>bytecode behavior</em>.
* <p>
* Each method handle constant also has an equivalent reflective <em>lookup expression</em>,
* which is a query to a method in {@link java.lang.invoke.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.
* <p>
* The special name {@code <clinit>} is not allowed.
* The special name {@code <init>} is not allowed except for subtag 8 as shown.
* <p>
* 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.
* <p>
* 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.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code MethodHandle.invoke}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
* as if the {@code varargs} bit were not set.
* <p>
* 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.
* <p>
* The rules of section 5.4.3 of
* <cite>The Java™ Virtual Machine Specification</cite>
* 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.)
* <p>
* 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.
*
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
* the call site must first be <em>linked</em>.
* Linking is accomplished by calling a <em>bootstrap method</em>
...
...
@@ -234,15 +74,14 @@
* call site execution.
* Linkage does not trigger class initialization.
* <p>
*
Next, the bootstrap method call is started, with at least four values being stacked
:
*
The bootstrap method is invoked on at least three values
:
* <ul>
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
* <li>a {@code MethodHandles.Lookup}, a lookup object on the <em>caller class</em> in which dynamic call site occurs </li>
* <li>a {@code String}, the method name mentioned in the call site </li>
* <li>a {@code MethodType}, the resolved type descriptor of the call </li>
* <li>optionally,
one or more <a href="#args">additional static arguments</a>
</li>
* <li>optionally,
between 1 and 251 additional static arguments taken from the constant pool
</li>
* </ul>
*
The method handle is then applied to the other value
s as if by
*
Invocation i
s as if by
* {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke}.
* The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
* The type of the call site's target must be exactly equal to the type
...
...
@@ -250,38 +89,15 @@
* the bootstrap method.
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* As long as each bootstrap method can be correctly invoked
* by <code>MethodHandle.invoke</code>, 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}.
* (Note that the types and number of the stacked arguments limit
* the legal kinds of bootstrap methods to appropriately typed
* static methods and constructors of {@code CallSite} subclasses.)
* <p>
* After resolution, the linkage process may fail in a variety of ways.
* All failures are reported by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
* As documented in the JVM specification, all failures arising from
* the linkage of a dynamic call site are reported
* by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
* which is thrown as the abnormal termination of the dynamic call
* site execution.
* The following circumstances will cause this:
* <ul>
* <li>the index to the bootstrap method specifier is out of range </li>
* <li>the bootstrap method cannot be resolved </li>
* <li>the {@code MethodType} to pass to the bootstrap method cannot be resolved </li>
* <li>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) </li>
* <li>the bootstrap method has the wrong arity,
* causing {@code MethodHandle.invoke} to throw {@code WrongMethodTypeException} </li>
* <li>the bootstrap method has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* an object of type {@link java.lang.invoke.CallSite CallSite} </li>
* <li>the target of the {@code CallSite} does not have a target of
* the expected {@code MethodType} </li>
* </ul>
* If this happens, the same error will the thrown for all subsequent
* attempts to execute the dynamic call site.
*
* <h3>
<a name="linktime"></a>
timing of linkage</h3>
* <h3>timing of linkage</h3>
* 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.
...
...
@@ -306,7 +122,7 @@
* 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.
*
* <p style="font-size:smaller;">
* <em>Discussion:</em>
* These rules do not enable the JVM to duplicate dynamic call sites,
...
...
@@ -315,64 +131,15 @@
* just before its first invocation.
* There is no way to undo the effect of a completed bootstrap method call.
*
* <h3><a name="bsmattr">the {@code BootstrapMethods} attribute </h3>
* 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.
* <p>
* 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 <a href="#args">additional static arguments</a>
* for the bootstrap method.
* <p>
* 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).
*
* <h3><a name="args">static arguments to the bootstrap method</h3>
* An {@code invokedynamic} instruction specifies at least three arguments
* to pass to its bootstrap method:
* The caller class (expressed as a {@link java.lang.invoke.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 <em>static arguments</em> to the
* {@code invokedynamic} instruction, because they are used once at link
* time to determine the instruction's behavior on subsequent sets of
* <em>dynamic arguments</em>.
* <p>
* 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.
* <p>
* 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:
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>entry type</th><th>argument type</th><th>argument value</th></tr>
* <tr><td>CONSTANT_String</td><td><code>java.lang.String</code></td><td>the indexed string literal</td></tr>
* <tr><td>CONSTANT_Class</td><td><code>java.lang.Class</code></td><td>the indexed class, resolved</td></tr>
* <tr><td>CONSTANT_Integer</td><td><code>java.lang.Integer</code></td><td>the indexed int value</td></tr>
* <tr><td>CONSTANT_Long</td><td><code>java.lang.Long</code></td><td>the indexed long value</td></tr>
* <tr><td>CONSTANT_Float</td><td><code>java.lang.Float</code></td><td>the indexed float value</td></tr>
* <tr><td>CONSTANT_Double</td><td><code>java.lang.Double</code></td><td>the indexed double value</td></tr>
* <tr><td>CONSTANT_MethodHandle</td><td><code>java.lang.invoke.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
* <tr><td>CONSTANT_MethodType</td><td><code>java.lang.invoke.MethodType</code></td><td>the indexed method type constant</td></tr>
* </table>
* </code>
* <h3>types of bootstrap methods</h3>
* As long as each bootstrap method can be correctly invoked
* by {@code MethodHandle.invoke}, 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}.
* (Note that the types and number of the stacked arguments limit
* the legal kinds of bootstrap methods to appropriately typed
* static methods and constructors of {@code CallSite} subclasses.)
* <p>
* If a given {@code invokedynamic} instruction specifies no static arguments,
* the instruction's bootstrap method will be invoked on three arguments,
...
...
@@ -380,7 +147,8 @@
* 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.)
* at most 251 extra arguments can be supplied, since the bootstrap method
* handle itself and its first three arguments must also be stacked.)
* The bootstrap method will be invoked as if by either {@code MethodHandle.invoke}
* or {@code invokeWithArguments}. (There is no way to tell the difference.)
* <p>
...
...
@@ -390,12 +158,11 @@
* 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.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
* and the {@
link
java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
* <p>
* 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.
* <code>
* <table border=1 cellpadding=5 summary="Static argument types">
* <tr><th>N</th><th>sample bootstrap method</th></tr>
* <tr><td>*</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
...
...
@@ -408,7 +175,6 @@
* <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)</code></td></tr>
* <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)</code></td></tr>
* </table>
* </code>
* 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
...
...
@@ -431,34 +197,6 @@
* 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.
*
* <h2><a name="structs"></a>Structure Summary</h2>
* <blockquote><pre>// 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];
}
* </pre></blockquote>
*
* @author John Rose, JSR 292 EG
* @since 1.7
*/
...
...
src/share/classes/java/nio/file/Path.java
浏览文件 @
bd11b4f3
...
...
@@ -460,15 +460,13 @@ public interface Path
/**
* Returns a URI to represent this path.
*
* <p> This method constructs a hierarchical {@link URI} that is absolute
* with a non-empty path component. Its {@link URI#getScheme() scheme} is
* equal to the URI scheme that identifies the provider. The exact form of
* the other URI components is highly provider dependent. In particular, it
* is implementation dependent if its query, fragment, and authority
* components are defined or undefined.
*
* <p> For the default provider the {@link URI#getPath() path} component
* will represent the {@link #toAbsolutePath absolute} path; the query,
* <p> This method constructs an absolute {@link URI} with a {@link
* URI#getScheme() scheme} equal to the URI scheme that identifies the
* provider. The exact form of the scheme specific part is highly provider
* dependent.
*
* <p> In the case of the default provider, the URI is hierarchical with
* a {@link URI#getPath() path} component that is absolute. The query and
* fragment components are undefined. Whether the authority component is
* defined or not is implementation dependent. There is no guarantee that
* the {@code URI} may be used to construct a {@link java.io.File java.io.File}.
...
...
@@ -497,7 +495,7 @@ public interface Path
* A format for compound URIs is not defined in this release; such a scheme
* may be added in a future release.
*
* @return
an absolute, hierarchical URI with a non-empty path component
* @return
the URI representing this path
*
* @throws java.io.IOError
* if an I/O error occurs obtaining the absolute path, or where a
...
...
src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
浏览文件 @
bd11b4f3
...
...
@@ -588,6 +588,10 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
}
private
void
addDefault
(
String
key
,
Object
value
)
{
if
(
compiledDefaults
==
null
)
{
return
;
}
String
prefix
=
parsePrefix
(
key
);
if
(
prefix
!=
null
)
{
Map
<
String
,
Object
>
keys
=
compiledDefaults
.
get
(
prefix
);
...
...
src/share/classes/javax/swing/text/Utilities.java
浏览文件 @
bd11b4f3
...
...
@@ -337,8 +337,7 @@ public class Utilities {
// x before x0, return.
return
0
;
}
int
currX
=
x0
;
int
nextX
=
currX
;
int
nextX
=
x0
;
// s may be a shared segment, so it is copied prior to calling
// the tab expander
char
[]
txt
=
s
.
array
;
...
...
@@ -388,19 +387,45 @@ public class Utilities {
}
else
{
nextX
+=
metrics
.
charWidth
(
txt
[
i
]);
}
if
(
(
x
>=
currX
)
&&
(
x
<
nextX
)
)
{
if
(
x
<
nextX
)
{
// found the hit position... return the appropriate side
int
offset
=
((
round
==
false
)
||
((
x
-
currX
)
<
(
nextX
-
x
)))
?
(
i
-
txtOffset
)
:
(
i
+
1
-
txtOffset
);
int
offset
;
// the length of the string measured as a whole may differ from
// the sum of individual character lengths, for example if
// fractional metrics are enabled; and we must guard from this.
if
(
round
)
{
offset
=
i
+
1
-
txtOffset
;
int
width
=
metrics
.
charsWidth
(
txt
,
txtOffset
,
offset
);
int
span
=
x
-
x0
;
if
(
span
<
width
)
{
while
(
offset
>
0
)
{
int
nextWidth
=
offset
>
1
?
metrics
.
charsWidth
(
txt
,
txtOffset
,
offset
-
1
)
:
0
;
if
(
span
>=
nextWidth
)
{
if
(
span
-
nextWidth
<
width
-
span
)
{
offset
--;
}
break
;
}
width
=
nextWidth
;
offset
--;
}
}
}
else
{
offset
=
i
-
txtOffset
;
while
(
offset
>
0
&&
metrics
.
charsWidth
(
txt
,
txtOffset
,
offset
)
>
(
x
-
x0
))
{
offset
--;
}
}
return
offset
;
}
currX
=
nextX
;
}
// didn't find, return end offset
...
...
src/share/classes/sun/font/FileFontStrike.java
浏览文件 @
bd11b4f3
...
...
@@ -180,7 +180,6 @@ public class FileFontStrike extends PhysicalStrike {
pScalerContext
=
NullFontScaler
.
getNullScalerContext
();
}
else
{
pScalerContext
=
fileFont
.
getScaler
().
createScalerContext
(
matrix
,
fileFont
instanceof
TrueTypeFont
,
desc
.
aaHint
,
desc
.
fmHint
,
boldness
,
italic
,
disableHinting
);
}
...
...
src/share/classes/sun/font/FontScaler.java
浏览文件 @
bd11b4f3
...
...
@@ -242,7 +242,6 @@ public abstract class FontScaler implements DisposerRecord {
freed when corresponding strike is being released.
*/
abstract
long
createScalerContext
(
double
[]
matrix
,
boolean
fontType
,
int
aa
,
int
fm
,
float
boldness
,
float
italic
,
boolean
disableHinting
);
...
...
src/share/classes/sun/font/FreetypeFontScaler.java
浏览文件 @
bd11b4f3
...
...
@@ -210,12 +210,12 @@ class FreetypeFontScaler extends FontScaler {
return
getUnitsPerEMNative
(
nativeScaler
);
}
long
createScalerContext
(
double
[]
matrix
,
boolean
fontType
,
long
createScalerContext
(
double
[]
matrix
,
int
aa
,
int
fm
,
float
boldness
,
float
italic
,
boolean
disableHinting
)
{
if
(
nativeScaler
!=
0L
)
{
return
createScalerContextNative
(
nativeScaler
,
matrix
,
fontType
,
aa
,
fm
,
boldness
,
italic
);
aa
,
fm
,
boldness
,
italic
);
}
return
NullFontScaler
.
getNullScalerContext
();
}
...
...
@@ -254,7 +254,7 @@ class FreetypeFontScaler extends FontScaler {
private
native
long
getUnitsPerEMNative
(
long
pScaler
);
native
long
createScalerContextNative
(
long
pScaler
,
double
[]
matrix
,
boolean
fontType
,
int
aa
,
int
fm
,
float
boldness
,
float
italic
);
int
aa
,
int
fm
,
float
boldness
,
float
italic
);
/* Freetype scaler context does not contain any pointers that
has to be invalidated if native scaler is bad */
...
...
src/share/classes/sun/font/NullFontScaler.java
浏览文件 @
bd11b4f3
...
...
@@ -66,7 +66,7 @@ class NullFontScaler extends FontScaler {
long
getLayoutTableCache
()
{
return
0L
;}
long
createScalerContext
(
double
[]
matrix
,
boolean
fontType
,
int
aa
,
long
createScalerContext
(
double
[]
matrix
,
int
aa
,
int
fm
,
float
boldness
,
float
italic
,
boolean
disableHinting
)
{
return
getNullScalerContext
();
}
...
...
src/share/classes/sun/invoke/util/ValueConversions.java
浏览文件 @
bd11b4f3
...
...
@@ -198,27 +198,30 @@ public class ValueConversions {
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
true
,
false
);
}
static
private
final
Integer
ZERO_INT
=
0
,
ONE_INT
=
1
;
/// Primitive conversions
public
static
Number
primitiveConversion
(
Wrapper
wrap
,
Object
x
,
boolean
cast
)
{
// Maybe merge this code with Wrapper.convert/cast.
Number
res
=
null
;
if
(
x
==
null
)
{
if
(!
cast
)
return
null
;
x
=
wrap
.
zero
()
;
return
ZERO_INT
;
}
if
(
x
instanceof
Number
)
{
res
=
(
Number
)
x
;
}
else
if
(
x
instanceof
Boolean
)
{
res
=
((
boolean
)
x
?
1
:
0
);
res
=
((
boolean
)
x
?
ONE_INT
:
ZERO_INT
);
}
else
if
(
x
instanceof
Character
)
{
res
=
(
int
)(
char
)
x
;
}
else
{
// this will fail with the required ClassCastException:
res
=
(
Number
)
x
;
}
if
(!
cast
&&
!
wrap
.
isConvertibleFrom
(
Wrapper
.
forWrapperType
(
x
.
getClass
())))
Wrapper
xwrap
=
Wrapper
.
findWrapperType
(
x
.
getClass
());
if
(
xwrap
==
null
||
!
cast
&&
!
wrap
.
isConvertibleFrom
(
xwrap
))
// this will fail with the required ClassCastException:
re
s
=
(
Number
)
wrap
.
wrapperType
().
cast
(
x
);
re
turn
(
Number
)
wrap
.
wrapperType
().
cast
(
x
);
return
res
;
}
...
...
src/share/classes/sun/invoke/util/VerifyAccess.java
浏览文件 @
bd11b4f3
...
...
@@ -154,9 +154,10 @@ public class VerifyAccess {
* @return whether they are in the same package
*/
public
static
boolean
isSamePackage
(
Class
<?>
class1
,
Class
<?>
class2
)
{
assert
(!
class1
.
isArray
()
&&
!
class2
.
isArray
());
if
(
class1
==
class2
)
return
true
;
if
(!
loadersAreRelated
(
class1
.
getClassLoader
(),
class2
.
getClassLoader
()))
if
(!
loadersAreRelated
(
class1
.
getClassLoader
(),
class2
.
getClassLoader
()
,
false
))
return
false
;
String
name1
=
class1
.
getName
(),
name2
=
class2
.
getName
();
int
dot
=
name1
.
lastIndexOf
(
'.'
);
...
...
@@ -169,6 +170,16 @@ public class VerifyAccess {
return
true
;
}
/** Return the package name for this class.
*/
public
static
String
getPackageName
(
Class
<?>
cls
)
{
assert
(!
cls
.
isArray
());
String
name
=
cls
.
getName
();
int
dot
=
name
.
lastIndexOf
(
'.'
);
if
(
dot
<
0
)
return
""
;
return
name
.
substring
(
0
,
dot
);
}
/**
* Test if two classes are defined as part of the same package member (top-level class).
* If this is true, they can share private access with each other.
...
...
@@ -193,18 +204,33 @@ public class VerifyAccess {
return
pkgmem
;
}
private
static
boolean
loadersAreRelated
(
ClassLoader
loader1
,
ClassLoader
loader2
)
{
if
(
loader1
==
loader2
||
loader1
==
null
||
loader2
==
null
)
{
private
static
boolean
loadersAreRelated
(
ClassLoader
loader1
,
ClassLoader
loader2
,
boolean
loader1MustBeParent
)
{
if
(
loader1
==
loader2
||
loader1
==
null
||
(
loader2
==
null
&&
!
loader1MustBeParent
))
{
return
true
;
}
for
(
ClassLoader
scan1
=
loader1
;
scan1
!=
null
;
scan1
=
scan1
.
getParent
())
{
if
(
scan1
==
loader2
)
return
true
;
}
for
(
ClassLoader
scan2
=
loader2
;
scan2
!=
null
;
scan2
=
scan2
.
getParent
())
{
if
(
scan2
==
loader1
)
return
true
;
}
if
(
loader1MustBeParent
)
return
false
;
// see if loader2 is a parent of loader1:
for
(
ClassLoader
scan1
=
loader1
;
scan1
!=
null
;
scan1
=
scan1
.
getParent
())
{
if
(
scan1
==
loader2
)
return
true
;
}
return
false
;
}
/**
* Is the class loader of parentClass identical to, or an ancestor of,
* the class loader of childClass?
* @param parentClass
* @param childClass
* @return whether parentClass precedes or equals childClass in class loader order
*/
public
static
boolean
classLoaderIsAncestor
(
Class
<?>
parentClass
,
Class
<?>
childClass
)
{
return
loadersAreRelated
(
parentClass
.
getClassLoader
(),
childClass
.
getClassLoader
(),
true
);
}
}
src/share/classes/sun/invoke/util/Wrapper.java
浏览文件 @
bd11b4f3
...
...
@@ -135,7 +135,7 @@ public enum Wrapper {
* <li>any type converted to {@code void} (i.e., dropping a method call's value)
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* </ul>
* These are the cases allowed by MethodHandle.asType
and convertArguments
.
* These are the cases allowed by MethodHandle.asType.
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
...
...
@@ -258,7 +258,7 @@ public enum Wrapper {
}
/** Return the wrapper that wraps values into the given wrapper type.
* If it is {@code Object}
or an interface
, return {@code OBJECT}.
* If it is {@code Object}, return {@code OBJECT}.
* Otherwise, it must be a wrapper type.
* The type must not be a primitive type.
* @throws IllegalArgumentException for unexpected types
...
...
@@ -277,8 +277,6 @@ public enum Wrapper {
if
(
w
!=
null
&&
w
.
wrapperType
==
type
)
{
return
w
;
}
if
(
type
.
isInterface
())
return
OBJECT
;
return
null
;
}
...
...
src/share/classes/sun/io/ByteToCharCp833.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
src/share/classes/sun/io/CharToByteCp833.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
src/share/classes/sun/misc/FpUtils.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2003, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
...
...
src/share/classes/sun/security/provider/certpath/URICertStore.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 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
...
...
src/share/native/sun/font/freetypeScaler.c
浏览文件 @
bd11b4f3
...
...
@@ -367,7 +367,7 @@ static double euclidianDistance(double a, double b) {
JNIEXPORT
jlong
JNICALL
Java_sun_font_FreetypeFontScaler_createScalerContextNative
(
JNIEnv
*
env
,
jobject
scaler
,
jlong
pScaler
,
jdoubleArray
matrix
,
j
boolean
ttFont
,
j
int
aa
,
jint
fm
,
jfloat
boldness
,
jfloat
italic
)
{
jint
aa
,
jint
fm
,
jfloat
boldness
,
jfloat
italic
)
{
double
dmat
[
4
],
ptsz
;
FTScalerContext
*
context
=
(
FTScalerContext
*
)
calloc
(
1
,
sizeof
(
FTScalerContext
));
...
...
src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java
浏览文件 @
bd11b4f3
...
...
@@ -29,8 +29,6 @@ import java.awt.FileDialog;
import
java.awt.peer.FileDialogPeer
;
import
java.io.File
;
import
java.io.FilenameFilter
;
import
javax.swing.SwingUtilities
;
import
javax.swing.SwingWorker
;
import
sun.awt.AWTAccessor
;
/**
...
...
@@ -107,9 +105,7 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
if
(
b
)
{
Thread
t
=
new
Thread
()
{
public
void
run
()
{
GtkFileDialogPeer
.
this
.
run
(
fd
.
getTitle
(),
fd
.
getMode
(),
fd
.
getDirectory
(),
fd
.
getFile
(),
fd
.
getFilenameFilter
(),
fd
.
isMultipleMode
(),
fd
.
getX
(),
fd
.
getY
());
showNativeDialog
();
fd
.
setVisible
(
false
);
}
};
...
...
@@ -146,4 +142,30 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
// We do not implement this method because we
// have delegated to FileDialog#setFilenameFilter
}
private
void
showNativeDialog
()
{
String
dirname
=
fd
.
getDirectory
();
// File path has a priority against directory path.
String
filename
=
fd
.
getFile
();
if
(
filename
!=
null
)
{
final
File
file
=
new
File
(
filename
);
if
(
fd
.
getMode
()
==
FileDialog
.
LOAD
&&
dirname
!=
null
&&
file
.
getParent
()
==
null
)
{
// File path for gtk_file_chooser_set_filename.
filename
=
dirname
+
(
dirname
.
endsWith
(
File
.
separator
)
?
""
:
File
.
separator
)
+
filename
;
}
if
(
fd
.
getMode
()
==
FileDialog
.
SAVE
&&
file
.
getParent
()
!=
null
)
{
// Filename for gtk_file_chooser_set_current_name.
filename
=
file
.
getName
();
// Directory path for gtk_file_chooser_set_current_folder.
dirname
=
file
.
getParent
();
}
}
GtkFileDialogPeer
.
this
.
run
(
fd
.
getTitle
(),
fd
.
getMode
(),
dirname
,
filename
,
fd
.
getFilenameFilter
(),
fd
.
isMultipleMode
(),
fd
.
getX
(),
fd
.
getY
());
}
}
src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
浏览文件 @
bd11b4f3
...
...
@@ -121,7 +121,7 @@ public class X11GraphicsEnvironment
// only attempt to initialize Xrender if it was requested
if
(
xRenderRequested
)
{
xRenderAvailable
=
initXRender
();
xRenderAvailable
=
initXRender
(
xRenderVerbose
);
if
(
xRenderVerbose
&&
!
xRenderAvailable
)
{
System
.
out
.
println
(
"Could not enable XRender pipeline"
);
...
...
@@ -159,7 +159,7 @@ public class X11GraphicsEnvironment
private
static
boolean
xRenderVerbose
;
private
static
boolean
xRenderAvailable
;
private
static
native
boolean
initXRender
();
private
static
native
boolean
initXRender
(
boolean
verbose
);
public
static
boolean
isXRenderAvailable
()
{
return
xRenderAvailable
;
}
...
...
src/solaris/doc/sun/man/man1/ja/keytool.1
浏览文件 @
bd11b4f3
." Copyright (c) 1998
-2011 keytool tool
, Oracle and/or its affiliates. All rights reserved.
." Copyright (c) 1998
, 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
...
...
src/solaris/doc/sun/man/man1/keytool.1
浏览文件 @
bd11b4f3
." Copyright (c) 1998
-2011 keytool tool
, Oracle and/or its affiliates. All rights reserved.
." Copyright (c) 1998
, 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
...
...
src/solaris/native/sun/java2d/x11/XRBackendNative.c
浏览文件 @
bd11b4f3
...
...
@@ -66,9 +66,10 @@ typedef struct _XRadialGradient {
}
XRadialGradient
;
#endif
#include <dlfcn.h>
#ifdef __solaris__
/* Solaris 10 will not have these symbols at runtime */
#include <dlfcn.h>
#include <link.h>
typedef
Picture
(
*
XRenderCreateLinearGradientFuncType
)
...
...
@@ -104,12 +105,20 @@ static
TRANSFORM.matrix[2][2] = 1<<16; \
}
/* The xrender pipleine requires libXrender.so version 0.9.3 or later. */
#define REQUIRED_XRENDER_VER1 0
#define REQUIRED_XRENDER_VER2 9
#define REQUIRED_XRENDER_VER3 3
#define PKGINFO_LINE_LEN_MAX 256
#define PKGINFO_LINE_CNT_MAX 50
static
jboolean
IsXRenderAvailable
()
{
static
jboolean
IsXRenderAvailable
(
jboolean
verbose
)
{
void
*
xrenderlib
;
int
major_opcode
,
first_event
,
first_error
;
jboolean
available
=
JNI_TRUE
;
if
(
!
XQueryExtension
(
awt_display
,
"RENDER"
,
&
major_opcode
,
&
first_event
,
&
first_error
))
{
...
...
@@ -131,12 +140,102 @@ static jboolean IsXRenderAvailable() {
if
(
XRenderCreateLinearGradientFunc
==
NULL
||
XRenderCreateRadialGradientFunc
==
NULL
)
{
available
=
JNI_FALSE
;
}
dlclose
(
xrenderlib
);
return
JNI_FALSE
;
}
else
{
available
=
JNI_FALSE
;
}
#else
Dl_info
info
;
jboolean
versionInfoIsFound
=
JNI_FALSE
;
memset
(
&
info
,
0
,
sizeof
(
Dl_info
));
if
(
dladdr
(
&
XRenderChangePicture
,
&
info
)
&&
info
.
dli_fname
!=
NULL
)
{
char
pkgInfoPath
[
FILENAME_MAX
];
char
*
pkgFileName
=
"/pkgconfig/xrender.pc"
;
size_t
pkgFileNameLen
=
strlen
(
pkgFileName
);
size_t
pos
,
len
=
strlen
(
info
.
dli_fname
);
pos
=
len
;
while
(
pos
>
0
&&
info
.
dli_fname
[
pos
]
!=
'/'
)
{
pos
-=
1
;
}
if
(
pos
>
0
&&
pos
<
(
FILENAME_MAX
-
pkgFileNameLen
-
1
))
{
struct
stat
stat_info
;
// compose absolute filename to package config
strncpy
(
pkgInfoPath
,
info
.
dli_fname
,
pos
);
strcpy
(
pkgInfoPath
+
pos
,
pkgFileName
);
pkgInfoPath
[
pos
+
pkgFileNameLen
]
=
'\0'
;
// check whether the config file exist and is a regular file
if
((
stat
(
pkgInfoPath
,
&
stat_info
)
==
0
)
&&
S_ISREG
(
stat_info
.
st_mode
))
{
FILE
*
fp
=
fopen
(
pkgInfoPath
,
"r"
);
if
(
fp
!=
NULL
)
{
char
line
[
PKGINFO_LINE_LEN_MAX
];
int
lineCount
=
PKGINFO_LINE_CNT_MAX
;
char
*
versionPrefix
=
"Version: "
;
size_t
versionPrefixLen
=
strlen
(
versionPrefix
);
// look for version
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
&&
--
lineCount
>
0
)
{
size_t
lineLen
=
strlen
(
line
);
if
(
lineLen
>
versionPrefixLen
&&
strncmp
(
versionPrefix
,
line
,
versionPrefixLen
)
==
0
)
{
int
v1
=
0
,
v2
=
0
,
v3
=
0
;
int
numNeeded
=
3
,
numProcessed
;
char
*
version
=
line
+
versionPrefixLen
;
numProcessed
=
sscanf
(
version
,
"%d.%d.%d"
,
&
v1
,
&
v2
,
&
v3
);
if
(
numProcessed
==
numNeeded
)
{
// we successfuly read the library version
versionInfoIsFound
=
JNI_TRUE
;
if
(
REQUIRED_XRENDER_VER1
==
v1
&&
((
REQUIRED_XRENDER_VER2
>
v2
)
||
((
REQUIRED_XRENDER_VER2
==
v2
)
&&
(
REQUIRED_XRENDER_VER3
>
v3
))))
{
available
=
JNI_FALSE
;
if
(
verbose
)
{
printf
(
"INFO: the version %d.%d.%d of libXrender.so is "
"not supported.
\n\t
See release notes for more details.
\n
"
,
v1
,
v2
,
v3
);
fflush
(
stdout
);
}
}
else
{
if
(
verbose
)
{
printf
(
"INFO: The version of libXrender.so "
"is detected as %d.%d%d
\n
"
,
v1
,
v2
,
v3
);
fflush
(
stdout
);
}
}
}
break
;
}
}
fclose
(
fp
);
}
}
}
}
if
(
verbose
&&
!
versionInfoIsFound
)
{
printf
(
"WARNING: The version of libXrender.so cannot be detected.
\n
,"
"The pipe line will be enabled, but note that versions less than 0.9.3
\n
"
"may cause hangs and crashes
\n
"
"
\t
See the release notes for more details.
\n
"
);
fflush
(
stdout
);
}
#endif
return
JNI_TRUE
;
return
available
;
}
/*
* Class: sun_awt_X11GraphicsEnvironment
...
...
@@ -145,7 +244,7 @@ static jboolean IsXRenderAvailable() {
*/
JNIEXPORT
jboolean
JNICALL
Java_sun_awt_X11GraphicsEnvironment_initXRender
(
JNIEnv
*
env
,
jclass
x11g
e
)
(
JNIEnv
*
env
,
jclass
x11ge
,
jboolean
verbos
e
)
{
#ifndef HEADLESS
static
jboolean
xrenderAvailable
=
JNI_FALSE
;
...
...
@@ -153,7 +252,7 @@ Java_sun_awt_X11GraphicsEnvironment_initXRender
if
(
firstTime
)
{
AWT_LOCK
();
xrenderAvailable
=
IsXRenderAvailable
();
xrenderAvailable
=
IsXRenderAvailable
(
verbose
);
AWT_UNLOCK
();
firstTime
=
JNI_FALSE
;
}
...
...
src/windows/native/sun/windows/awt_Component.cpp
浏览文件 @
bd11b4f3
...
...
@@ -3715,7 +3715,10 @@ void AwtComponent::OpenCandidateWindow(int x, int y)
SetCandidateWindow
(
iCandType
,
x
-
rc
.
left
,
y
-
rc
.
top
);
}
if
(
m_bitsCandType
!=
0
)
{
::
DefWindowProc
(
GetHWnd
(),
WM_IME_NOTIFY
,
IMN_OPENCANDIDATE
,
m_bitsCandType
);
HWND
proxy
=
GetProxyFocusOwner
();
// REMIND: is there any chance GetProxyFocusOwner() returns NULL here?
::
DefWindowProc
((
proxy
!=
NULL
)
?
proxy
:
GetHWnd
(),
WM_IME_NOTIFY
,
IMN_OPENCANDIDATE
,
m_bitsCandType
);
}
}
...
...
src/windows/native/sun/windows/awt_Object.cpp
浏览文件 @
bd11b4f3
...
...
@@ -69,9 +69,12 @@ void AwtObject::_Dispose(jobject self)
CriticalSection
::
Lock
l
(
AwtToolkit
::
GetInstance
().
GetSyncCS
());
JNIEnv
*
env
=
(
JNIEnv
*
)
JNU_GetEnv
(
jvm
,
JNI_VERSION_1_2
);
jobject
selfGlobalRef
=
env
->
NewGlobalRef
(
self
);
// value 0 of lParam means that we should not attempt to enter the
// SyncCall critical section, as it was entered someshere earlier
AwtToolkit
::
GetInstance
().
SendMessage
(
WM_AWT_DISPOSE
,
(
WPARAM
)
self
,
(
LPARAM
)
0
);
AwtToolkit
::
GetInstance
().
SendMessage
(
WM_AWT_DISPOSE
,
(
WPARAM
)
self
GlobalRef
,
(
LPARAM
)
0
);
CATCH_BAD_ALLOC
;
}
...
...
src/windows/native/sun/windows/awt_Toolkit.cpp
浏览文件 @
bd11b4f3
...
...
@@ -741,7 +741,9 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
}
if
(
canDispose
)
{
if
(
wParam
!=
NULL
)
{
AwtObject
*
o
=
(
AwtObject
*
)
JNI_GET_PDATA
((
jobject
)
wParam
);
jobject
self
=
(
jobject
)
wParam
;
AwtObject
*
o
=
(
AwtObject
*
)
JNI_GET_PDATA
(
self
);
env
->
DeleteGlobalRef
(
self
);
if
(
o
!=
NULL
&&
theAwtObjectList
.
Remove
(
o
))
{
o
->
Dispose
();
}
...
...
test/com/sun/net/httpserver/Test10.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/java/awt/List/ScrollOutside/ScrollOut.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/java/awt/image/IncorrectSampleMaskTest.java
浏览文件 @
bd11b4f3
/*
* Copyright
2009 Sun Microsystems, Inc. All Rights R
eserved.
* Copyright
(c) 2009, Oracle and/or its affiliates. All rights r
eserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -16,10 +16,10 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact
Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
*
CA 95054 USA or visit www.sun.com if you need additional information or
*
have any
questions.
*/
* Please contact
Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
*
or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
...
...
test/java/lang/invoke/6991596/Test6991596.java
浏览文件 @
bd11b4f3
...
...
@@ -51,10 +51,10 @@ public class Test6991596 {
return
MethodHandles
.
lookup
().
findStatic
(
CLASS
,
NAME
,
MethodType
.
methodType
(
ret
,
arg
));
}
static
MethodHandle
getmh2
(
MethodHandle
mh1
,
Class
ret
,
Class
arg
)
{
return
MethodHandles
.
conver
tArguments
(
mh1
,
MethodType
.
methodType
(
ret
,
arg
));
return
MethodHandles
.
explicitCas
tArguments
(
mh1
,
MethodType
.
methodType
(
ret
,
arg
));
}
static
MethodHandle
getmh3
(
MethodHandle
mh1
,
Class
ret
,
Class
arg
)
{
return
MethodHandles
.
conver
tArguments
(
mh1
,
MethodType
.
methodType
(
ret
,
arg
));
return
MethodHandles
.
explicitCas
tArguments
(
mh1
,
MethodType
.
methodType
(
ret
,
arg
));
}
// test adapter_opt_i2i
...
...
test/java/lang/invoke/6998541/Test6998541.java
浏览文件 @
bd11b4f3
...
...
@@ -164,6 +164,7 @@ public class Test6998541 {
private
static
boolean
canDoAsType
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
)
return
true
;
if
(
dst
==
void
.
class
)
return
true
;
if
(
src
==
void
.
class
)
return
true
;
// allow void->zero
if
(!
src
.
isPrimitive
()
||
!
dst
.
isPrimitive
())
return
true
;
// primitive conversion works for asType only when it's widening
if
(
src
==
boolean
.
class
||
dst
==
boolean
.
class
)
return
false
;
...
...
@@ -451,7 +452,6 @@ public class Test6998541 {
private
final
static
MethodHandle
mh_dv
=
mh
(
double
.
class
);
private
static
void
void2prim
(
int
i
)
throws
Throwable
{
if
(!
DO_CASTS
)
return
;
assertEquals
(
false
,
(
boolean
)
mh_zv
.
invokeExact
());
// void -> boolean
assertEquals
((
byte
)
0
,
(
byte
)
mh_bv
.
invokeExact
());
// void -> byte
assertEquals
((
char
)
0
,
(
char
)
mh_cv
.
invokeExact
());
// void -> char
...
...
@@ -463,15 +463,7 @@ public class Test6998541 {
}
private
static
void
void2prim_invalid
(
double
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
assertEquals
(
false
,
(
boolean
)
mh_zv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> boolean
try
{
assertEquals
((
byte
)
0
,
(
byte
)
mh_bv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> byte
try
{
assertEquals
((
char
)
0
,
(
char
)
mh_cv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> char
try
{
assertEquals
((
short
)
0
,
(
short
)
mh_sv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> short
try
{
assertEquals
(
0
,
(
int
)
mh_iv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> int
try
{
assertEquals
(
0L
,
(
long
)
mh_jv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> long
try
{
assertEquals
(
0.0f
,
(
float
)
mh_fv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> float
try
{
assertEquals
(
0.0d
,
(
double
)
mh_dv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> double
// no cases
}
private
static
MethodHandle
mh_v
(
Class
arg
)
{
return
mh
(
void
.
class
,
arg
);
}
...
...
test/java/lang/invoke/InvokeDynamicPrintArgs.java
浏览文件 @
bd11b4f3
...
...
@@ -106,8 +106,10 @@ public class InvokeDynamicPrintArgs {
"Done printing argument lists."
};
private
static
boolean
doPrint
=
true
;
private
static
void
printArgs
(
Object
bsmInfo
,
Object
...
args
)
{
System
.
out
.
println
(
bsmInfo
+
Arrays
.
deepToString
(
args
));
String
message
=
bsmInfo
+
Arrays
.
deepToString
(
args
);
if
(
doPrint
)
System
.
out
.
println
(
message
);
}
private
static
MethodHandle
MH_printArgs
()
throws
ReflectiveOperationException
{
shouldNotCallThis
();
...
...
@@ -129,11 +131,48 @@ public class InvokeDynamicPrintArgs {
return
lookup
().
findStatic
(
lookup
().
lookupClass
(),
"bsm"
,
MT_bsm
());
}
private
static
CallSite
bsm2
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
arg
)
throws
ReflectiveOperationException
{
/* Example of a constant call site with user-data.
* In this case, the user data is exactly the BSM data.
* Note that a CCS with user data must use the "hooked" constructor
* to bind the CCS itself into the resulting target.
* A normal constructor would not allow a circular relation
* between the CCS and its target.
*/
public
static
class
PrintingCallSite
extends
ConstantCallSite
{
final
Lookup
caller
;
final
String
name
;
final
Object
[]
staticArgs
;
PrintingCallSite
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
staticArgs
)
throws
Throwable
{
super
(
type
,
MH_createTarget
());
this
.
caller
=
caller
;
this
.
name
=
name
;
this
.
staticArgs
=
staticArgs
;
}
public
MethodHandle
createTarget
()
{
try
{
return
lookup
().
bind
(
this
,
"runTarget"
,
genericMethodType
(
0
,
true
)).
asType
(
type
());
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
public
Object
runTarget
(
Object
...
dynamicArgs
)
{
List
<
Object
>
bsmInfo
=
new
ArrayList
<>(
Arrays
.
asList
(
caller
,
name
,
type
()));
bsmInfo
.
addAll
(
Arrays
.
asList
(
staticArgs
));
printArgs
(
bsmInfo
,
dynamicArgs
);
return
null
;
}
private
static
MethodHandle
MH_createTarget
()
throws
ReflectiveOperationException
{
shouldNotCallThis
();
return
lookup
().
findVirtual
(
lookup
().
lookupClass
(),
"createTarget"
,
methodType
(
MethodHandle
.
class
));
}
}
private
static
CallSite
bsm2
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
arg
)
throws
Throwable
{
// ignore caller and name, but match the type:
List
<
Object
>
bsmInfo
=
new
ArrayList
<>(
Arrays
.
asList
(
caller
,
name
,
type
));
bsmInfo
.
addAll
(
Arrays
.
asList
((
Object
[])
arg
));
return
new
ConstantCallSite
(
MH_printArgs
().
bindTo
(
bsmInfo
).
asCollector
(
Object
[].
class
,
type
.
parameterCount
()).
asType
(
type
));
return
new
PrintingCallSite
(
caller
,
name
,
type
,
arg
);
}
private
static
MethodType
MT_bsm2
()
{
shouldNotCallThis
();
...
...
@@ -146,33 +185,33 @@ public class InvokeDynamicPrintArgs {
private
static
MethodHandle
INDY_nothing
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm
().
invoke
(
lookup
(),
"nothing"
,
methodType
(
void
.
class
)
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_foo
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm
().
invoke
(
lookup
(),
"foo"
,
methodType
(
void
.
class
,
String
.
class
)
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_bar
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"bar"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
)
,
Void
.
class
,
"void type!"
,
1
,
234.5
F
,
67.5
,
(
long
)
89
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_bar2
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"bar2"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
)
,
Void
.
class
,
"void type!"
,
1
,
234.5
F
,
67.5
,
(
long
)
89
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_baz
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"baz"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
,
double
.
class
)
,
1234.5
)).
dynamicInvoker
();
...
...
test/java/lang/invoke/InvokeGenericTest.java
浏览文件 @
bd11b4f3
...
...
@@ -53,9 +53,9 @@ public class InvokeGenericTest {
if
(
vstr
!=
null
)
verbosity
=
Integer
.
parseInt
(
vstr
);
}
public
static
void
main
(
String
...
av
)
throws
Throwable
{
new
InvokeGenericTest
().
testFirst
();
}
//
public static void main(String... av) throws Throwable {
//
new InvokeGenericTest().testFirst();
//
}
@Test
public
void
testFirst
()
throws
Throwable
{
...
...
@@ -314,7 +314,7 @@ public class InvokeGenericTest {
ArrayList
<
Class
<?>>
argTypes
=
new
ArrayList
<
Class
<?>>(
targetType
.
parameterList
());
Collections
.
fill
(
argTypes
.
subList
(
beg
,
end
),
argType
);
MethodType
ttype2
=
MethodType
.
methodType
(
targetType
.
returnType
(),
argTypes
);
return
MethodHandles
.
convertArguments
(
target
,
ttype2
);
return
target
.
asType
(
ttype2
);
}
// This lookup is good for all members in and under InvokeGenericTest.
...
...
@@ -378,7 +378,7 @@ public class InvokeGenericTest {
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
Generic
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
res
=
resl
=
(
List
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
...
...
@@ -470,8 +470,6 @@ public class InvokeGenericTest {
return
allMethodTypes
(
argc
,
argc
,
types
);
}
interface
RandomInterface
{
}
MethodHandle
toString_MH
;
@Test
...
...
@@ -480,33 +478,62 @@ public class InvokeGenericTest {
toString_MH
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"toString"
,
MethodType
.
methodType
(
String
.
class
));
Object
[]
args
=
{
"one"
,
"two"
};
for
(
MethodType
type
:
allMethodTypes
(
2
,
Object
.
class
,
String
.
class
,
RandomInterfa
ce
.
class
))
{
for
(
MethodType
type
:
allMethodTypes
(
2
,
Object
.
class
,
String
.
class
,
CharSequen
ce
.
class
))
{
testReferenceConversions
(
type
,
args
);
}
}
public
void
testReferenceConversions
(
MethodType
type
,
Object
...
args
)
throws
Throwable
{
countTest
();
if
(
verbosity
>
3
)
System
.
out
.
println
(
"target type: "
+
type
);
int
nargs
=
args
.
length
;
List
<
Object
>
argList
=
Arrays
.
asList
(
args
);
String
expectString
=
argList
.
toString
();
if
(
verbosity
>
3
)
System
.
out
.
println
(
"target type: "
+
type
+
expectString
);
MethodHandle
mh
=
callable
(
type
.
parameterList
());
MethodHandle
tsdrop
=
MethodHandles
.
dropArguments
(
toString_MH
,
1
,
type
.
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
tsdrop
,
mh
);
mh
=
MethodHandles
.
filterReturnValue
(
mh
,
toString_MH
);
mh
=
mh
.
asType
(
type
);
Object
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
Object
res
=
null
;
if
(
nargs
==
2
)
{
res
=
mh
.
invoke
((
Object
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
mh
.
invoke
((
Object
)
args
[
0
],
(
String
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
String
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
CharSequence
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
mh
.
invoke
((
CharSequence
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
(
String
)
mh
.
invoke
((
Object
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
(
String
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
res
=
(
CharSequence
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
expectString
,
res
);
}
else
{
assert
(
false
);
// write this code
}
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
).
toString
(),
res
);
}
@Test
@Ignore
(
"known failure pending 6939861"
)
@Test
public
void
testBoxConversions
()
throws
Throwable
{
startTest
(
"testBoxConversions"
);
countTest
();
Object
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
int
.
class
);
Object
res
;
List
resl
;
Object
res
;
List
resl
;
int
resi
;
res
=
resl
=
(
List
)
mh
.
invoke
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
mh
=
MethodHandles
.
identity
(
int
.
class
);
mh
=
MethodHandles
.
dropArguments
(
mh
,
1
,
int
.
class
);
res
=
resi
=
(
int
)
mh
.
invoke
((
Object
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
args
[
0
],
res
);
res
=
resi
=
(
int
)
mh
.
invoke
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
assertEquals
(
args
[
0
],
res
);
}
}
test/java/lang/invoke/JavaDocExamplesTest.java
浏览文件 @
bd11b4f3
...
...
@@ -34,7 +34,7 @@
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-D
test.java.lang.invoke.
JavaDocExamplesTest.verbosity=1 \
-DJavaDocExamplesTest.verbosity=1 \
test.java.lang.invoke.JavaDocExamplesTest
----
*/
...
...
@@ -45,12 +45,10 @@ import java.lang.invoke.*;
import
static
java
.
lang
.
invoke
.
MethodHandles
.*;
import
static
java
.
lang
.
invoke
.
MethodType
.*;
import
java.lang.reflect.*
;
import
java.util.*
;
import
org.junit.*
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assume
.*;
/**
...
...
@@ -60,11 +58,29 @@ public class JavaDocExamplesTest {
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
*/
public
static
void
main
(
String
...
ignore
)
{
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
JavaDocExamplesTest
.
class
);
public
static
void
main
(
String
...
ignore
)
throws
Throwable
{
System
.
out
.
println
(
"can run this as:"
);
System
.
out
.
println
(
"$ java org.junit.runner.JUnitCore "
+
JavaDocExamplesTest
.
class
.
getName
());
new
JavaDocExamplesTest
().
run
();
}
public
void
run
()
throws
Throwable
{
testFindVirtual
();
testPermuteArguments
();
testDropArguments
();
testFilterArguments
();
testFoldArguments
();
testMethodHandlesSummary
();
testAsSpreader
();
testAsCollector
();
testAsVarargsCollector
();
testAsFixedArity
();
testAsTypeCornerCases
();
testMutableCallSite
();
}
// How much output?
static
int
verbosity
=
Integer
.
getInteger
(
"test.java.lang.invoke.JavaDocExamplesTest.verbosity"
,
0
);
static
final
Class
<?>
THIS_CLASS
=
JavaDocExamplesTest
.
class
;
static
int
verbosity
=
Integer
.
getInteger
(
THIS_CLASS
.
getSimpleName
()+
".verbosity"
,
0
);
{}
static
final
private
Lookup
LOOKUP
=
lookup
();
...
...
@@ -74,17 +90,23 @@ static final private Lookup LOOKUP = lookup();
// "hashCode", methodType(int.class));
// form required if ReflectiveOperationException is intercepted:
static
final
private
MethodHandle
CONCAT_2
,
HASHCODE
_2
;
static
final
private
MethodHandle
CONCAT_2
,
HASHCODE_2
,
ADD_2
,
SUB
_2
;
static
{
try
{
Class
<?>
THIS_CLASS
=
LOOKUP
.
lookupClass
();
CONCAT_2
=
LOOKUP
.
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
HASHCODE_2
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"hashCode"
,
methodType
(
int
.
class
));
ADD_2
=
LOOKUP
.
findStatic
(
THIS_CLASS
,
"add"
,
methodType
(
int
.
class
,
int
.
class
,
int
.
class
));
SUB_2
=
LOOKUP
.
findStatic
(
THIS_CLASS
,
"sub"
,
methodType
(
int
.
class
,
int
.
class
,
int
.
class
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
static
int
add
(
int
x
,
int
y
)
{
return
x
+
y
;
}
static
int
sub
(
int
x
,
int
y
)
{
return
x
-
y
;
}
{}
@Test
public
void
testFindVirtual
()
throws
Throwable
{
...
...
@@ -101,6 +123,39 @@ assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy"));
assertEquals
(
"xy"
.
hashCode
(),
(
int
)
HASHCODE_3
.
invokeExact
((
Object
)
"xy"
));
{}
}
@Test
public
void
testPermuteArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodType
intfn1
=
methodType
(
int
.
class
,
int
.
class
);
MethodType
intfn2
=
methodType
(
int
.
class
,
int
.
class
,
int
.
class
);
MethodHandle
sub
=
SUB_2
;
// ... {int x, int y => x-y} ...;
assert
(
sub
.
type
().
equals
(
intfn2
));
MethodHandle
sub1
=
permuteArguments
(
sub
,
intfn2
,
0
,
1
);
MethodHandle
rsub
=
permuteArguments
(
sub
,
intfn2
,
1
,
0
);
assert
((
int
)
rsub
.
invokeExact
(
1
,
100
)
==
99
);
MethodHandle
add
=
ADD_2
;
// ... {int x, int y => x+y} ...;
assert
(
add
.
type
().
equals
(
intfn2
));
MethodHandle
twice
=
permuteArguments
(
add
,
intfn1
,
0
,
0
);
assert
(
twice
.
type
().
equals
(
intfn1
));
assert
((
int
)
twice
.
invokeExact
(
21
)
==
42
);
}}
{{
{}
/// JAVADOC
MethodHandle
cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
assertEquals
(
"xy"
,
(
String
)
cat
.
invokeExact
(
"x"
,
"y"
));
MethodHandle
d0
=
dropArguments
(
cat
,
0
,
String
.
class
);
assertEquals
(
"yz"
,
(
String
)
d0
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d1
=
dropArguments
(
cat
,
1
,
String
.
class
);
assertEquals
(
"xz"
,
(
String
)
d1
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d2
=
dropArguments
(
cat
,
2
,
String
.
class
);
assertEquals
(
"xy"
,
(
String
)
d2
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d12
=
dropArguments
(
cat
,
1
,
int
.
class
,
boolean
.
class
);
assertEquals
(
"xz"
,
(
String
)
d12
.
invokeExact
(
"x"
,
12
,
true
,
"z"
));
}}
}
@Test
public
void
testDropArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
...
...
@@ -145,6 +200,21 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
}}
}
@Test
public
void
testFoldArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
trace
=
publicLookup
().
findVirtual
(
java
.
io
.
PrintStream
.
class
,
"println"
,
methodType
(
void
.
class
,
String
.
class
))
.
bindTo
(
System
.
out
);
MethodHandle
cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
assertEquals
(
"boojum"
,
(
String
)
cat
.
invokeExact
(
"boo"
,
"jum"
));
MethodHandle
catTrace
=
foldArguments
(
cat
,
trace
);
// also prints "boo":
assertEquals
(
"boojum"
,
(
String
)
catTrace
.
invokeExact
(
"boo"
,
"jum"
));
}}
}
static
void
assertEquals
(
Object
exp
,
Object
act
)
{
if
(
verbosity
>
0
)
System
.
out
.
println
(
"result: "
+
act
);
...
...
@@ -162,24 +232,24 @@ mt = MethodType.methodType(String.class, char.class, char.class);
mh
=
lookup
.
findVirtual
(
String
.
class
,
"replace"
,
mt
);
s
=
(
String
)
mh
.
invokeExact
(
"daddy"
,
'd'
,
'n'
);
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assert
(
s
.
equals
(
"nanny"
)
);
assert
Equals
(
s
,
"nanny"
);
// weakly typed invocation (using MHs.invoke)
s
=
(
String
)
mh
.
invokeWithArguments
(
"sappy"
,
'p'
,
'v'
);
assert
(
s
.
equals
(
"savvy"
)
);
assert
Equals
(
s
,
"savvy"
);
// mt is (Object[])List
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
assert
(
mh
.
isVarargsCollector
());
x
=
mh
.
invoke
(
"one"
,
"two"
);
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)
));
assert
Equals
(
x
,
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
));
// mt is (Object,Object,Object)Object
mt
=
MethodType
.
genericMethodType
(
3
);
mh
=
mh
.
asType
(
mt
);
x
=
mh
.
invokeExact
((
Object
)
1
,
(
Object
)
2
,
(
Object
)
3
);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
)
));
// mt is
{ => int}
assert
Equals
(
x
,
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
));
// mt is
()int
mt
=
MethodType
.
methodType
(
int
.
class
);
mh
=
lookup
.
findVirtual
(
java
.
util
.
List
.
class
,
"size"
,
mt
);
i
=
(
int
)
mh
.
invokeExact
(
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
));
...
...
@@ -193,37 +263,239 @@ mh.invokeExact(System.out, "Hello, world.");
}}
}
@Test
public
void
testAsSpreader
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
equals
=
publicLookup
()
.
findVirtual
(
String
.
class
,
"equals"
,
methodType
(
boolean
.
class
,
Object
.
class
));
assert
(
(
boolean
)
equals
.
invokeExact
(
"me"
,
(
Object
)
"me"
));
assert
(!(
boolean
)
equals
.
invokeExact
(
"me"
,
(
Object
)
"thee"
));
// spread both arguments from a 2-array:
MethodHandle
eq2
=
equals
.
asSpreader
(
Object
[].
class
,
2
);
assert
(
(
boolean
)
eq2
.
invokeExact
(
new
Object
[]{
"me"
,
"me"
}));
assert
(!(
boolean
)
eq2
.
invokeExact
(
new
Object
[]{
"me"
,
"thee"
}));
// spread both arguments from a String array:
MethodHandle
eq2s
=
equals
.
asSpreader
(
String
[].
class
,
2
);
assert
(
(
boolean
)
eq2s
.
invokeExact
(
new
String
[]{
"me"
,
"me"
}));
assert
(!(
boolean
)
eq2s
.
invokeExact
(
new
String
[]{
"me"
,
"thee"
}));
// spread second arguments from a 1-array:
MethodHandle
eq1
=
equals
.
asSpreader
(
Object
[].
class
,
1
);
assert
(
(
boolean
)
eq1
.
invokeExact
(
"me"
,
new
Object
[]{
"me"
}));
assert
(!(
boolean
)
eq1
.
invokeExact
(
"me"
,
new
Object
[]{
"thee"
}));
// spread no arguments from a 0-array or null:
MethodHandle
eq0
=
equals
.
asSpreader
(
Object
[].
class
,
0
);
assert
(
(
boolean
)
eq0
.
invokeExact
(
"me"
,
(
Object
)
"me"
,
new
Object
[
0
]));
assert
(!(
boolean
)
eq0
.
invokeExact
(
"me"
,
(
Object
)
"thee"
,
(
Object
[])
null
));
// asSpreader and asCollector are approximate inverses:
for
(
int
n
=
0
;
n
<=
2
;
n
++)
{
for
(
Class
<?>
a
:
new
Class
<?>[]{
Object
[].
class
,
String
[].
class
,
CharSequence
[].
class
})
{
MethodHandle
equals2
=
equals
.
asSpreader
(
a
,
n
).
asCollector
(
a
,
n
);
assert
(
(
boolean
)
equals2
.
invokeWithArguments
(
"me"
,
"me"
));
assert
(!(
boolean
)
equals2
.
invokeWithArguments
(
"me"
,
"thee"
));
}
}
MethodHandle
caToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
char
[].
class
));
assertEquals
(
"[A, B, C]"
,
(
String
)
caToString
.
invokeExact
(
"ABC"
.
toCharArray
()));
MethodHandle
caString3
=
caToString
.
asCollector
(
char
[].
class
,
3
);
assertEquals
(
"[A, B, C]"
,
(
String
)
caString3
.
invokeExact
(
'A'
,
'B'
,
'C'
));
MethodHandle
caToString2
=
caString3
.
asSpreader
(
char
[].
class
,
2
);
assertEquals
(
"[A, B, C]"
,
(
String
)
caToString2
.
invokeExact
(
'A'
,
"BC"
.
toCharArray
()));
}}
}
@Test
public
void
testAsCollector
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
deepToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"deepToString"
,
methodType
(
String
.
class
,
Object
[].
class
));
assertEquals
(
"[won]"
,
(
String
)
deepToString
.
invokeExact
(
new
Object
[]{
"won"
}));
MethodHandle
ts1
=
deepToString
.
asCollector
(
Object
[].
class
,
1
);
assertEquals
(
methodType
(
String
.
class
,
Object
.
class
),
ts1
.
type
());
//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
assertEquals
(
"[[won]]"
,
(
String
)
ts1
.
invokeExact
((
Object
)
new
Object
[]{
"won"
}));
// arrayType can be a subtype of Object[]
MethodHandle
ts2
=
deepToString
.
asCollector
(
String
[].
class
,
2
);
assertEquals
(
methodType
(
String
.
class
,
String
.
class
,
String
.
class
),
ts2
.
type
());
assertEquals
(
"[two, too]"
,
(
String
)
ts2
.
invokeExact
(
"two"
,
"too"
));
MethodHandle
ts0
=
deepToString
.
asCollector
(
Object
[].
class
,
0
);
assertEquals
(
"[]"
,
(
String
)
ts0
.
invokeExact
());
// collectors can be nested, Lisp-style
MethodHandle
ts22
=
deepToString
.
asCollector
(
Object
[].
class
,
3
).
asCollector
(
String
[].
class
,
2
);
assertEquals
(
"[A, B, [C, D]]"
,
((
String
)
ts22
.
invokeExact
((
Object
)
'A'
,
(
Object
)
"B"
,
"C"
,
"D"
)));
// arrayType can be any primitive array type
MethodHandle
bytesToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
byte
[].
class
))
.
asCollector
(
byte
[].
class
,
3
);
assertEquals
(
"[1, 2, 3]"
,
(
String
)
bytesToString
.
invokeExact
((
byte
)
1
,
(
byte
)
2
,
(
byte
)
3
));
MethodHandle
longsToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
long
[].
class
))
.
asCollector
(
long
[].
class
,
1
);
assertEquals
(
"[123]"
,
(
String
)
longsToString
.
invokeExact
((
long
)
123
));
}}
}
@Test
public
void
testAsVarargsCollector
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
deepToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"deepToString"
,
methodType
(
String
.
class
,
Object
[].
class
));
MethodHandle
ts1
=
deepToString
.
asVarargsCollector
(
Object
[].
class
);
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invokeExact
(
new
Object
[]{
"won"
}));
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invoke
(
new
Object
[]{
"won"
}));
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invoke
(
"won"
));
assertEquals
(
"[[won]]"
,
(
String
)
ts1
.
invoke
((
Object
)
new
Object
[]{
"won"
}));
// findStatic of Arrays.asList(...) produces a variable arity method handle:
MethodHandle
asList
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
));
assertEquals
(
methodType
(
List
.
class
,
Object
[].
class
),
asList
.
type
());
assert
(
asList
.
isVarargsCollector
());
assertEquals
(
"[]"
,
asList
.
invoke
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
(
"two"
,
"too"
).
toString
());
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
String
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
(
argv
).
toString
());
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
((
Object
[])
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
((
Object
)
argv
);
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
}}
}
@Test
public
void
test
VarargsCollectorSuppression
()
throws
Throwable
{
@Test
public
void
test
AsFixedArity
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
vamh
=
publicLookup
()
MethodHandle
asListVar
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
assert
(
vamh
.
type
().
equals
(
mh
.
type
()));
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
(
1
,
2
,
3
).
toString
());
boolean
failed
=
false
;
try
{
mh
.
invoke
(
1
,
2
,
3
);
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
assert
(
failed
);
MethodHandle
asListFix
=
asListVar
.
asFixedArity
();
assertEquals
(
"[1]"
,
asListVar
.
invoke
(
1
).
toString
());
Exception
caught
=
null
;
try
{
asListFix
.
invoke
((
Object
)
1
);
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
assertEquals
(
"[two, too]"
,
asListVar
.
invoke
(
"two"
,
"too"
).
toString
());
try
{
asListFix
.
invoke
(
"two"
,
"too"
);
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asListVar
.
invoke
(
argv
).
toString
());
assertEquals
(
"[three, thee, tee]"
,
asListFix
.
invoke
(
argv
).
toString
());
assertEquals
(
1
,
((
List
)
asListVar
.
invoke
((
Object
)
argv
)).
size
());
assertEquals
(
"[three, thee, tee]"
,
asListFix
.
invoke
((
Object
)
argv
).
toString
());
}}
}
@Test
public
void
testAsTypeCornerCases
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
i2s
=
publicLookup
()
.
findVirtual
(
Integer
.
class
,
"toString"
,
methodType
(
String
.
class
));
i2s
=
i2s
.
asType
(
i2s
.
type
().
unwrap
());
MethodHandle
l2s
=
publicLookup
()
.
findVirtual
(
Long
.
class
,
"toString"
,
methodType
(
String
.
class
));
l2s
=
l2s
.
asType
(
l2s
.
type
().
unwrap
());
Exception
caught
=
null
;
try
{
i2s
.
asType
(
methodType
(
String
.
class
,
String
.
class
));
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
i2s
.
asType
(
methodType
(
String
.
class
,
byte
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Byte
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Character
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Integer
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
byte
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Byte
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Character
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Integer
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Long
.
class
));
caught
=
null
;
try
{
i2s
.
asType
(
methodType
(
String
.
class
,
Long
.
class
));
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
MethodHandle
i2sGen
=
i2s
.
asType
(
methodType
(
String
.
class
,
Object
.
class
));
MethodHandle
l2sGen
=
l2s
.
asType
(
methodType
(
String
.
class
,
Object
.
class
));
i2sGen
.
invoke
(
42
);
// int -> Integer -> Object -> Integer -> int
i2sGen
.
invoke
((
byte
)
4
);
// byte -> Byte -> Object -> Byte -> byte -> int
l2sGen
.
invoke
(
42
);
// int -> Integer -> Object -> Integer -> int
l2sGen
.
invoke
((
byte
)
4
);
// byte -> Byte -> Object -> Byte -> byte -> int
l2sGen
.
invoke
(
0x420000000
L
);
caught
=
null
;
try
{
i2sGen
.
invoke
(
0x420000000
L
);
}
// long -> Long -> Object -> Integer CCE
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
caught
=
null
;
try
{
i2sGen
.
invoke
(
"asdf"
);
}
// String -> Object -> Integer CCE
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
{}
}}
}
@Test
public
void
testMutableCallSite
()
throws
Throwable
{
{{
{}
/// JAVADOC
MutableCallSite
name
=
new
MutableCallSite
(
MethodType
.
methodType
(
String
.
class
));
MethodHandle
MH_name
=
name
.
dynamicInvoker
();
MethodType
MT_str1
=
MethodType
.
methodType
(
String
.
class
);
MethodHandle
MH_upcase
=
MethodHandles
.
lookup
()
.
findVirtual
(
String
.
class
,
"toUpperCase"
,
MT_str1
);
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)
/*
* </pre></blockquote>
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
*/
MethodType
MT_str2
=
MethodType
.
methodType
(
String
.
class
,
String
.
class
);
MethodHandle
MH_cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
MethodHandle
MH_dear
=
MethodHandles
.
insertArguments
(
MH_cat
,
1
,
", dear?"
);
MethodHandle
worker2
=
MethodHandles
.
filterReturnValue
(
MH_name
,
MH_dear
);
assertEquals
(
"Fred, dear?"
,
(
String
)
worker2
.
invokeExact
());
name
.
setTarget
(
MethodHandles
.
constant
(
String
.
class
,
"Wilma"
));
assertEquals
(
"WILMA"
,
(
String
)
worker1
.
invokeExact
());
assertEquals
(
"Wilma, dear?"
,
(
String
)
worker2
.
invokeExact
());
{}
}}
}
@Test
public
void
testSwitchPoint
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
MH_strcat
=
MethodHandles
.
lookup
()
.
findVirtual
(
String
.
class
,
"concat"
,
MethodType
.
methodType
(
String
.
class
,
String
.
class
));
SwitchPoint
spt
=
new
SwitchPoint
();
assert
(
spt
.
isValid
());
// the following steps may be repeated to re-use the same switch point:
MethodHandle
worker1
=
MH_strcat
;
MethodHandle
worker2
=
MethodHandles
.
permuteArguments
(
MH_strcat
,
MH_strcat
.
type
(),
1
,
0
);
MethodHandle
worker
=
spt
.
guardWithTest
(
worker1
,
worker2
);
assertEquals
(
"method"
,
(
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
SwitchPoint
.
invalidateAll
(
new
SwitchPoint
[]{
spt
});
assert
(!
spt
.
isValid
());
assertEquals
(
"hodmet"
,
(
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
{}
}}
}
/* ---- TEMPLATE ----
@Test public void testFoo() throws Throwable {
{{
{} /// JAVADOC
{}
}}
}
*/
}
test/java/lang/invoke/MethodHandlesTest.java
浏览文件 @
bd11b4f3
...
...
@@ -100,6 +100,31 @@ public class MethodHandlesTest {
// ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
testInsertArguments
(
0
,
0
,
MAX_ARG_INCREASE
+
10
);
}
@Test
@Ignore
(
"permuteArguments has trouble with double slots"
)
public
void
testFail_7
()
throws
Throwable
{
testPermuteArguments
(
new
Object
[]{
10
,
200L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
},
new
int
[]{
1
,
0
});
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
0
,
1
});
//rot
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
1
,
2
,
0
});
//rot
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
1
,
0
});
//swap
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
0
,
1
,
2
,
2
});
//dup
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
0
,
1
,
2
});
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
2
,
0
,
1
});
testPermuteArguments
(
4
,
Integer
.
class
,
2
,
long
.
class
,
6
);
}
static
final
int
MAX_ARG_INCREASE
=
3
;
public
MethodHandlesTest
()
{
...
...
@@ -356,7 +381,7 @@ public class MethodHandlesTest {
ArrayList
<
Class
<?>>
argTypes
=
new
ArrayList
<
Class
<?>>(
targetType
.
parameterList
());
Collections
.
fill
(
argTypes
.
subList
(
beg
,
end
),
argType
);
MethodType
ttype2
=
MethodType
.
methodType
(
targetType
.
returnType
(),
argTypes
);
return
MethodHandles
.
convertArguments
(
target
,
ttype2
);
return
target
.
asType
(
ttype2
);
}
// This lookup is good for all members in and under MethodHandlesTest.
...
...
@@ -505,8 +530,15 @@ public class MethodHandlesTest {
System
.
out
.
print
(
':'
);
}
static
final
boolean
DEBUG_METHOD_HANDLE_NAMES
=
Boolean
.
getBoolean
(
"java.lang.invoke.MethodHandle.DEBUG_NAMES"
);
// rough check of name string
static
void
assertNameStringContains
(
Object
x
,
String
s
)
{
static
void
assertNameStringContains
(
MethodHandle
x
,
String
s
)
{
if
(!
DEBUG_METHOD_HANDLE_NAMES
)
{
// ignore s
assertEquals
(
"MethodHandle"
+
x
.
type
(),
x
.
toString
());
return
;
}
if
(
x
.
toString
().
contains
(
s
))
return
;
assertEquals
(
s
,
x
);
}
...
...
@@ -998,11 +1030,11 @@ public class MethodHandlesTest {
Class
<?>
vtype
=
ftype
;
if
(
ftype
!=
int
.
class
)
vtype
=
Object
.
class
;
if
(
isGetter
)
{
mh
=
MethodHandles
.
convertArguments
(
mh
,
mh
.
type
().
generic
()
mh
=
mh
.
asType
(
mh
.
type
().
generic
()
.
changeReturnType
(
vtype
));
}
else
{
int
last
=
mh
.
type
().
parameterCount
()
-
1
;
mh
=
MethodHandles
.
convertArguments
(
mh
,
mh
.
type
().
generic
()
mh
=
mh
.
asType
(
mh
.
type
().
generic
()
.
changeReturnType
(
void
.
class
)
.
changeParameterType
(
last
,
vtype
));
}
...
...
@@ -1132,7 +1164,7 @@ public class MethodHandlesTest {
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
MethodType
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
Integer
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeReturnType
(
void
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
mh
=
mh
.
asType
(
gtype
);
}
Object
sawValue
,
expValue
;
List
<
Object
>
model
=
array2list
(
array
);
...
...
@@ -1226,11 +1258,10 @@ public class MethodHandlesTest {
}
void
testConvert
(
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
testConvert
(
true
,
false
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
true
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
id
,
rtype
,
name
,
params
);
}
void
testConvert
(
boolean
positive
,
boolean
useAsType
,
void
testConvert
(
boolean
positive
,
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
countTest
(
positive
);
MethodType
idType
=
id
.
type
();
...
...
@@ -1258,10 +1289,7 @@ public class MethodHandlesTest {
MethodHandle
target
=
null
;
RuntimeException
error
=
null
;
try
{
if
(
useAsType
)
target
=
id
.
asType
(
newType
);
else
target
=
MethodHandles
.
convertArguments
(
id
,
newType
);
}
catch
(
RuntimeException
ex
)
{
error
=
ex
;
}
...
...
@@ -1286,11 +1314,11 @@ public class MethodHandlesTest {
MethodType
.
methodType
(
Object
.
class
,
String
.
class
,
Object
[].
class
));
vac0
=
vac0
.
bindTo
(
"vac"
);
MethodHandle
vac
=
vac0
.
asVarargsCollector
(
Object
[].
class
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
for
(
Class
<?>
at
:
new
Class
[]
{
Object
.
class
,
String
.
class
,
Integer
.
class
})
{
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
1
)),
null
,
"vac"
,
at
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
2
)),
null
,
"vac"
,
at
,
at
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
1
)),
null
,
"vac"
,
at
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
2
)),
null
,
"vac"
,
at
,
at
);
}
}
...
...
@@ -1299,8 +1327,8 @@ public class MethodHandlesTest {
if
(
CAN_SKIP_WORKING
)
return
;
startTest
(
"permuteArguments"
);
testPermuteArguments
(
4
,
Integer
.
class
,
2
,
String
.
class
,
0
);
//
testPermuteArguments(6, Integer.class, 0, null, 30);
//testPermuteArguments(4, Integer.class,
1, int.class, 6);
testPermuteArguments
(
6
,
Integer
.
class
,
0
,
null
,
30
);
//testPermuteArguments(4, Integer.class,
2, long.class, 6); // FIXME Fail_7
}
public
void
testPermuteArguments
(
int
max
,
Class
<?>
type1
,
int
t2c
,
Class
<?>
type2
,
int
dilution
)
throws
Throwable
{
if
(
verbosity
>=
2
)
...
...
@@ -1414,8 +1442,9 @@ public class MethodHandlesTest {
}
MethodType
inType
=
MethodType
.
methodType
(
Object
.
class
,
types
);
MethodType
outType
=
MethodType
.
methodType
(
Object
.
class
,
permTypes
);
MethodHandle
target
=
MethodHandles
.
convertArguments
(
varargsList
(
outargs
),
outType
);
MethodHandle
target
=
varargsList
(
outargs
).
asType
(
outType
);
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
if
(
verbosity
>=
5
)
System
.
out
.
println
(
"newTarget = "
+
newTarget
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
if
(!
expected
.
equals
(
result
))
{
...
...
@@ -1659,7 +1688,7 @@ public class MethodHandlesTest {
countTest
();
MethodHandle
target
=
varargsList
(
nargs
);
MethodHandle
filter
=
varargsList
(
1
);
filter
=
MethodHandles
.
convertArguments
(
filter
,
filter
.
type
().
generic
());
filter
=
filter
.
asType
(
filter
.
type
().
generic
());
Object
[]
argsToPass
=
randomArgs
(
nargs
,
Object
.
class
);
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"filter "
+
target
+
" at "
+
pos
+
" with "
+
filter
);
...
...
@@ -1800,7 +1829,7 @@ public class MethodHandlesTest {
// generic invoker
countTest
();
inv
=
MethodHandles
.
invoker
(
type
);
if
(
nargs
<=
3
)
{
if
(
nargs
<=
3
&&
type
==
type
.
generic
()
)
{
calledLog
.
clear
();
switch
(
nargs
)
{
case
0
:
...
...
@@ -1826,10 +1855,16 @@ public class MethodHandlesTest {
// varargs invoker #0
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
0
);
if
(
type
.
returnType
()
==
Object
.
class
)
{
result
=
inv
.
invokeExact
(
target
,
args
);
}
else
if
(
type
.
returnType
()
==
void
.
class
)
{
result
=
null
;
inv
.
invokeExact
(
target
,
args
);
}
else
{
result
=
inv
.
invokeWithArguments
(
target
,
(
Object
)
args
);
}
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
if
(
nargs
>=
1
)
{
if
(
nargs
>=
1
&&
type
==
type
.
generic
()
)
{
// varargs invoker #1
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
1
);
...
...
@@ -1837,7 +1872,7 @@ public class MethodHandlesTest {
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
}
if
(
nargs
>=
2
)
{
if
(
nargs
>=
2
&&
type
==
type
.
generic
()
)
{
// varargs invoker #2
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
2
);
...
...
@@ -1845,7 +1880,7 @@ public class MethodHandlesTest {
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
}
if
(
nargs
>=
3
)
{
if
(
nargs
>=
3
&&
type
==
type
.
generic
()
)
{
// varargs invoker #3
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
3
);
...
...
@@ -1858,6 +1893,10 @@ public class MethodHandlesTest {
countTest
();
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
k
);
MethodType
expType
=
(
type
.
dropParameterTypes
(
k
,
nargs
)
.
appendParameterTypes
(
Object
[].
class
)
.
insertParameterTypes
(
0
,
MethodHandle
.
class
));
assertEquals
(
expType
,
inv
.
type
());
List
<
Object
>
targetPlusVarArgs
=
new
ArrayList
<
Object
>(
targetPlusArgs
);
List
<
Object
>
tailList
=
targetPlusVarArgs
.
subList
(
1
+
k
,
1
+
nargs
);
Object
[]
tail
=
tailList
.
toArray
();
...
...
@@ -2038,7 +2077,7 @@ public class MethodHandlesTest {
//System.out.println("throwing with "+target+" : "+thrown);
MethodType
expectedType
=
MethodType
.
methodType
(
returnType
,
exType
);
assertEquals
(
expectedType
,
target
.
type
());
target
=
MethodHandles
.
convertArguments
(
target
,
target
.
type
().
generic
());
target
=
target
.
asType
(
target
.
type
().
generic
());
Throwable
caught
=
null
;
try
{
Object
res
=
target
.
invokeExact
((
Object
)
thrown
);
...
...
@@ -2110,12 +2149,12 @@ public class MethodHandlesTest {
if
(
mode
.
endsWith
(
"/return"
))
{
if
(
mode
.
equals
(
"unbox/return"
))
{
// fail on return to ((Integer)surprise).intValue
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
surprise
=
surprise
.
asType
(
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
identity
=
identity
.
asType
(
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
}
else
if
(
mode
.
equals
(
"cast/return"
))
{
// fail on return to (Integer)surprise
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
surprise
=
surprise
.
asType
(
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
identity
=
identity
.
asType
(
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
}
}
else
if
(
mode
.
endsWith
(
"/argument"
))
{
MethodHandle
callee
=
null
;
...
...
@@ -2127,14 +2166,14 @@ public class MethodHandlesTest {
callee
=
Surprise
.
BOX_IDENTITY
;
}
if
(
callee
!=
null
)
{
callee
=
MethodHandles
.
convertArguments
(
callee
,
MethodType
.
genericMethodType
(
1
));
callee
=
callee
.
asType
(
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
filterArguments
(
callee
,
0
,
surprise
);
identity
=
MethodHandles
.
filterArguments
(
callee
,
0
,
identity
);
}
}
assertNotSame
(
mode
,
surprise
,
surprise0
);
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
genericMethodType
(
1
));
identity
=
identity
.
asType
(
MethodType
.
genericMethodType
(
1
));
surprise
=
surprise
.
asType
(
MethodType
.
genericMethodType
(
1
));
Object
x
=
42
;
for
(
int
i
=
0
;
i
<
okCount
;
i
++)
{
Object
y
=
identity
.
invokeExact
(
x
);
...
...
@@ -2223,14 +2262,14 @@ public class MethodHandlesTest {
{
MethodType
mt
=
MethodType
.
methodType
(
void
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"runForRunnable"
,
mt
);
Runnable
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
Runnable
.
class
);
Runnable
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
Runnable
.
class
,
mh
);
proxy
.
run
();
assertCalled
(
"runForRunnable"
);
}
{
MethodType
mt
=
MethodType
.
methodType
(
Object
.
class
,
Fooable
.
class
,
Object
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"fooForFooable"
,
mt
);
Fooable
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
Fooable
.
class
);
Fooable
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
Fooable
.
class
,
mh
);
Object
[]
args
=
randomArgs
(
mt
.
parameterArray
());
Object
result
=
proxy
.
foo
((
Fooable
)
args
[
0
],
args
[
1
]);
assertCalled
(
"fooForFooable"
,
args
);
...
...
@@ -2244,7 +2283,7 @@ public class MethodHandlesTest {
})
{
MethodHandle
mh
=
MethodHandles
.
throwException
(
void
.
class
,
Throwable
.
class
);
mh
=
MethodHandles
.
insertArguments
(
mh
,
0
,
ex
);
WillThrow
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
WillThrow
.
class
);
WillThrow
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
WillThrow
.
class
,
mh
);
try
{
proxy
.
willThrow
();
System
.
out
.
println
(
"Failed to throw: "
+
ex
);
...
...
@@ -2272,7 +2311,7 @@ public class MethodHandlesTest {
CharSequence
.
class
,
Example
.
class
})
{
try
{
MethodHandle
s
.
asInstance
(
varargsArray
(
0
),
nonSAM
);
MethodHandle
Proxies
.
asInterfaceInstance
(
nonSAM
,
varargsArray
(
0
)
);
System
.
out
.
println
(
"Failed to throw"
);
assertTrue
(
false
);
}
catch
(
IllegalArgumentException
ex
)
{
...
...
test/java/lang/invoke/MethodTypeTest.java
浏览文件 @
bd11b4f3
/*
* Copyright
2008, 2011 Sun Microsystems, Inc. All Rights R
eserved.
* Copyright
(c) 2008, 2011, Oracle and/or its affiliates. All rights r
eserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
...
...
@@ -18,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact
Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
*
CA 95054 USA or visit www.sun.com if you need additional information or
*
have any
questions.
* Please contact
Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
*
or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
...
...
test/java/lang/invoke/indify/Indify.java
浏览文件 @
bd11b4f3
...
...
@@ -524,6 +524,8 @@ public class Indify {
if
(
verifySpecifierCount
>=
0
)
{
List
<
Object
[]>
specs
=
bootstrapMethodSpecifiers
(
false
);
int
specsLen
=
(
specs
==
null
?
0
:
specs
.
size
());
// Pass by specsLen == 0, to help with associated (inner) classes.
if
(
specsLen
==
0
)
specsLen
=
verifySpecifierCount
;
if
(
specsLen
!=
verifySpecifierCount
)
{
throw
new
IllegalArgumentException
(
"BootstrapMethods length is "
+
specsLen
+
" but should be "
+
verifySpecifierCount
);
}
...
...
test/java/rmi/server/UnicastRemoteObject/exportObject/GcDuringExport.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/EnumMap/DistinctEntrySetElements.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/EnumMap/EntrySetIteratorRemoveInvalidatesEntry.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/EnumMap/SimpleSerialization.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/EnumSet/LargeEnumIteratorRemoveResilience.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/EnumSet/SmallEnumIteratorRemoveResilience.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/Hashtable/SerializationDeadlock.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/java/util/Hashtable/SimpleSerialization.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/java/util/IdentityHashMap/DistinctEntrySetElements.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/IdentityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/Vector/SerializationDeadlock.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/java/util/Vector/SimpleSerialization.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/java/util/concurrent/ConcurrentHashMap/DistinctEntrySetElements.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/java/util/zip/ZipFile/ClearStaleZipFileInputStreams.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* 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
...
...
test/javax/swing/plaf/nimbus/Test7048204.java
0 → 100644
浏览文件 @
bd11b4f3
/*
* 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
@bug 7048204
@summary NPE from NimbusLookAndFeel.addDefault
@author Pavel Porvatov
*/
import
javax.swing.*
;
import
javax.swing.plaf.nimbus.NimbusLookAndFeel
;
public
class
Test7048204
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
UIManager
.
setLookAndFeel
(
new
NimbusLookAndFeel
());
SwingUtilities
.
invokeAndWait
(
new
Runnable
()
{
public
void
run
()
{
new
JLabel
();
UIDefaults
uid
=
UIManager
.
getDefaults
();
uid
.
putDefaults
(
new
Object
[
0
]);
uid
.
put
(
"what.ever"
,
"else"
);
}
});
}
}
test/javax/swing/text/Utilities/bug7045593.java
0 → 100644
浏览文件 @
bd11b4f3
/*
* 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7045593
* @summary Possible Regression : JTextfield cursor placement behavior algorithm has changed
* @author Pavel Porvatov
*/
import
sun.awt.SunToolkit
;
import
javax.swing.*
;
import
javax.swing.text.BadLocationException
;
import
java.awt.*
;
public
class
bug7045593
{
private
static
volatile
JTextField
jtf
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
SwingUtilities
.
invokeAndWait
(
new
Runnable
()
{
public
void
run
()
{
jtf
=
new
JTextField
(
"WW"
);
JFrame
frame
=
new
JFrame
();
frame
.
getContentPane
().
add
(
jtf
);
frame
.
pack
();
frame
.
setVisible
(
true
);
}
});
((
SunToolkit
)
SunToolkit
.
getDefaultToolkit
()).
realSync
();
SwingUtilities
.
invokeAndWait
(
new
Runnable
()
{
public
void
run
()
{
try
{
Rectangle
r
=
jtf
.
modelToView
(
1
);
int
delta
=
2
;
for
(
int
x
=
r
.
x
-
delta
;
x
<
r
.
x
+
delta
;
x
++)
{
assertEquals
(
jtf
.
viewToModel
(
new
Point
(
x
,
r
.
y
)),
1
);
}
System
.
out
.
println
(
"Passed."
);
}
catch
(
BadLocationException
e
)
{
throw
new
RuntimeException
(
"Test failed"
,
e
);
}
}
});
}
private
static
void
assertEquals
(
int
i1
,
int
i2
)
{
if
(
i1
!=
i2
)
{
throw
new
RuntimeException
(
"Test failed, "
+
i1
+
" != "
+
i2
);
}
}
}
test/sun/net/InetAddress/nameservice/chaining/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor
浏览文件 @
bd11b4f3
...
...
@@ -17,7 +17,7 @@
#
# 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
# questions
.
Simple1NameServiceDescriptor
Simple2NameServiceDescriptor
test/tools/launcher/TestHelper.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2008, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011
,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
test/tools/pack200/CommandLineTests.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/tools/pack200/Pack200Test.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
test/tools/pack200/Utils.java
浏览文件 @
bd11b4f3
/*
* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录