Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
8c50098c
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看板
提交
8c50098c
编写于
5月 24, 2011
作者:
M
mullan
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
09d91f41
80977770
变更
67
隐藏空白更改
内联
并排
Showing
67 changed file
with
4359 addition
and
1032 deletion
+4359
-1032
.hgtags
.hgtags
+1
-0
make/sun/rmi/rmi/Makefile
make/sun/rmi/rmi/Makefile
+12
-7
make/sun/xawt/mapfile-vers
make/sun/xawt/mapfile-vers
+0
-1
src/share/classes/java/awt/Component.java
src/share/classes/java/awt/Component.java
+6
-5
src/share/classes/java/awt/Container.java
src/share/classes/java/awt/Container.java
+25
-9
src/share/classes/java/awt/Toolkit.java
src/share/classes/java/awt/Toolkit.java
+27
-41
src/share/classes/java/lang/Throwable.java
src/share/classes/java/lang/Throwable.java
+6
-3
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
+259
-62
src/share/classes/java/lang/invoke/CallSite.java
src/share/classes/java/lang/invoke/CallSite.java
+4
-4
src/share/classes/java/lang/invoke/FilterGeneric.java
src/share/classes/java/lang/invoke/FilterGeneric.java
+4
-0
src/share/classes/java/lang/invoke/FilterOneArgument.java
src/share/classes/java/lang/invoke/FilterOneArgument.java
+4
-0
src/share/classes/java/lang/invoke/FromGeneric.java
src/share/classes/java/lang/invoke/FromGeneric.java
+8
-5
src/share/classes/java/lang/invoke/InvokeGeneric.java
src/share/classes/java/lang/invoke/InvokeGeneric.java
+3
-3
src/share/classes/java/lang/invoke/Invokers.java
src/share/classes/java/lang/invoke/Invokers.java
+11
-11
src/share/classes/java/lang/invoke/MemberName.java
src/share/classes/java/lang/invoke/MemberName.java
+1
-1
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+84
-64
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+316
-237
src/share/classes/java/lang/invoke/MethodHandleNatives.java
src/share/classes/java/lang/invoke/MethodHandleNatives.java
+68
-17
src/share/classes/java/lang/invoke/MethodHandleStatics.java
src/share/classes/java/lang/invoke/MethodHandleStatics.java
+18
-2
src/share/classes/java/lang/invoke/MethodHandles.java
src/share/classes/java/lang/invoke/MethodHandles.java
+85
-54
src/share/classes/java/lang/invoke/MethodType.java
src/share/classes/java/lang/invoke/MethodType.java
+34
-9
src/share/classes/java/lang/invoke/MethodTypeForm.java
src/share/classes/java/lang/invoke/MethodTypeForm.java
+4
-3
src/share/classes/java/lang/invoke/SpreadGeneric.java
src/share/classes/java/lang/invoke/SpreadGeneric.java
+4
-0
src/share/classes/java/lang/invoke/ToGeneric.java
src/share/classes/java/lang/invoke/ToGeneric.java
+11
-7
src/share/classes/java/lang/invoke/package-info.java
src/share/classes/java/lang/invoke/package-info.java
+8
-8
src/share/classes/javax/imageio/metadata/doc-files/jpeg_metadata.html
...asses/javax/imageio/metadata/doc-files/jpeg_metadata.html
+31
-4
src/share/classes/javax/swing/ComboBoxModel.java
src/share/classes/javax/swing/ComboBoxModel.java
+3
-1
src/share/classes/javax/swing/DefaultComboBoxModel.java
src/share/classes/javax/swing/DefaultComboBoxModel.java
+11
-22
src/share/classes/javax/swing/JComboBox.java
src/share/classes/javax/swing/JComboBox.java
+37
-35
src/share/classes/javax/swing/MutableComboBoxModel.java
src/share/classes/javax/swing/MutableComboBoxModel.java
+8
-6
src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
...e/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
+1
-1
src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
...re/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
+2
-2
src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
...are/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
+12
-0
src/share/classes/sun/invoke/util/ValueConversions.java
src/share/classes/sun/invoke/util/ValueConversions.java
+549
-144
src/share/classes/sun/invoke/util/VerifyType.java
src/share/classes/sun/invoke/util/VerifyType.java
+9
-2
src/share/classes/sun/invoke/util/Wrapper.java
src/share/classes/sun/invoke/util/Wrapper.java
+119
-18
src/share/classes/sun/java2d/opengl/OGLRenderer.java
src/share/classes/sun/java2d/opengl/OGLRenderer.java
+16
-2
src/share/classes/sun/java2d/pipe/AAShapePipe.java
src/share/classes/sun/java2d/pipe/AAShapePipe.java
+17
-13
src/share/classes/sun/java2d/pipe/AlphaColorPipe.java
src/share/classes/sun/java2d/pipe/AlphaColorPipe.java
+4
-0
src/share/classes/sun/java2d/pipe/BufferedRenderPipe.java
src/share/classes/sun/java2d/pipe/BufferedRenderPipe.java
+8
-0
src/share/classes/sun/java2d/pipe/LoopPipe.java
src/share/classes/sun/java2d/pipe/LoopPipe.java
+4
-0
src/share/classes/sun/java2d/pipe/ParallelogramPipe.java
src/share/classes/sun/java2d/pipe/ParallelogramPipe.java
+11
-1
src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java
...lasses/sun/java2d/pipe/PixelToParallelogramConverter.java
+24
-12
src/share/classes/sun/text/bidi/BidiBase.java
src/share/classes/sun/text/bidi/BidiBase.java
+0
-4
src/solaris/classes/sun/awt/X11/XRobotPeer.java
src/solaris/classes/sun/awt/X11/XRobotPeer.java
+1
-2
src/solaris/native/sun/awt/awt_Robot.c
src/solaris/native/sun/awt/awt_Robot.c
+3
-104
src/windows/classes/sun/awt/windows/WFramePeer.java
src/windows/classes/sun/awt/windows/WFramePeer.java
+10
-2
src/windows/classes/sun/java2d/d3d/D3DRenderer.java
src/windows/classes/sun/java2d/d3d/D3DRenderer.java
+16
-2
src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
+8
-0
src/windows/native/sun/windows/Devices.h
src/windows/native/sun/windows/Devices.h
+1
-1
src/windows/native/sun/windows/awt_Choice.cpp
src/windows/native/sun/windows/awt_Choice.cpp
+6
-0
src/windows/native/sun/windows/awt_Component.cpp
src/windows/native/sun/windows/awt_Component.cpp
+0
-1
src/windows/native/sun/windows/awt_Frame.cpp
src/windows/native/sun/windows/awt_Frame.cpp
+0
-11
test/java/awt/Component/Revalidate/Revalidate.java
test/java/awt/Component/Revalidate/Revalidate.java
+1
-1
test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java
...iner/ValidateRoot/InvalidateMustRespectValidateRoots.java
+1
-1
test/java/awt/Paint/PgramUserBoundsTest.java
test/java/awt/Paint/PgramUserBoundsTest.java
+126
-0
test/java/awt/Toolkit/Headless/ExceptionContract/ExceptionContract.java
...Toolkit/Headless/ExceptionContract/ExceptionContract.java
+336
-0
test/java/awt/geom/Arc2D/SerializationTest.java
test/java/awt/geom/Arc2D/SerializationTest.java
+100
-0
test/java/lang/invoke/6998541/Test6998541.java
test/java/lang/invoke/6998541/Test6998541.java
+513
-0
test/java/lang/invoke/InvokeGenericTest.java
test/java/lang/invoke/InvokeGenericTest.java
+41
-13
test/java/lang/invoke/JavaDocExamplesTest.java
test/java/lang/invoke/JavaDocExamplesTest.java
+9
-9
test/java/lang/invoke/MethodHandlesTest.java
test/java/lang/invoke/MethodHandlesTest.java
+108
-64
test/java/lang/invoke/RicochetTest.java
test/java/lang/invoke/RicochetTest.java
+582
-0
test/java/text/Bidi/Bug7041232.java
test/java/text/Bidi/Bug7041232.java
+48
-0
test/javax/swing/JComboBox/7031551/bug7031551.java
test/javax/swing/JComboBox/7031551/bug7031551.java
+123
-0
test/javax/swing/JTable/6788484/bug6788484.java
test/javax/swing/JTable/6788484/bug6788484.java
+9
-1
test/sun/invoke/util/ValueConversionsTest.java
test/sun/invoke/util/ValueConversionsTest.java
+448
-0
未找到文件。
.hgtags
浏览文件 @
8c50098c
...
@@ -117,3 +117,4 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139
...
@@ -117,3 +117,4 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139
9315c733fb17ddfb9fb44be7e0ffea37bf3c727d jdk7-b140
9315c733fb17ddfb9fb44be7e0ffea37bf3c727d jdk7-b140
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143
make/sun/rmi/rmi/Makefile
浏览文件 @
8c50098c
...
@@ -85,16 +85,21 @@ REMOTE_impls = \
...
@@ -85,16 +85,21 @@ REMOTE_impls = \
sun.rmi.registry.RegistryImpl
\
sun.rmi.registry.RegistryImpl
\
sun.rmi.transport.DGCImpl
sun.rmi.transport.DGCImpl
ifeq
($(PLATFORM), windows)
#
build
:
stubs
# The java-rmi.cgi script in bin/ only gets delivered in certain situations
else
# PLATFORM
#
ifneq
($(ARCH_DATA_MODEL), 32)
BUILD_TARGETS
=
stubs
build
:
stubs
ifeq
($(PLATFORM), linux)
else
# ARCH_DATA_MODEL
BUILD_TARGETS
+=
bin
build
:
stubs bin
endif
endif
ifeq
($(PLATFORM), solaris)
ifeq
($(ARCH_DATA_MODEL), 32)
BUILD_TARGETS
+=
bin
endif
endif
endif
build
:
$(BUILD_TARGETS)
clean clobber
::
bin.clean
clean clobber
::
bin.clean
...
...
make/sun/xawt/mapfile-vers
浏览文件 @
8c50098c
...
@@ -158,7 +158,6 @@ SUNWprivate_1.1 {
...
@@ -158,7 +158,6 @@ SUNWprivate_1.1 {
Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl;
Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl;
Java_sun_awt_X11_XRobotPeer_mouseWheelImpl;
Java_sun_awt_X11_XRobotPeer_mouseWheelImpl;
Java_sun_awt_X11_XRobotPeer_setup;
Java_sun_awt_X11_XRobotPeer_setup;
Java_sun_awt_X11_XRobotPeer__1dispose;
Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl;
Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl;
Java_java_awt_Component_initIDs;
Java_java_awt_Component_initIDs;
Java_java_awt_Container_initIDs;
Java_java_awt_Container_initIDs;
...
...
src/share/classes/java/awt/Component.java
浏览文件 @
8c50098c
...
@@ -2887,11 +2887,12 @@ public abstract class Component implements ImageObserver, MenuContainer,
...
@@ -2887,11 +2887,12 @@ public abstract class Component implements ImageObserver, MenuContainer,
/**
/**
* Invalidates this component and its ancestors.
* Invalidates this component and its ancestors.
* <p>
* <p>
* All the ancestors of this component up to the nearest validate root are
* By default, all the ancestors of the component up to the top-most
* marked invalid also. If there is no a validate root container for this
* container of the hierarchy are marked invalid. If the {@code
* component, all of its ancestors up to the root of the hierarchy are
* java.awt.smartInvalidate} system property is set to {@code true},
* marked invalid as well. Marking a container <i>invalid</i> indicates
* invalidation stops on the nearest validate root of this component.
* that the container needs to be laid out.
* Marking a container <i>invalid</i> indicates that the container needs to
* be laid out.
* <p>
* <p>
* This method is called automatically when any layout-related information
* This method is called automatically when any layout-related information
* changes (e.g. setting the bounds of the component, or adding the
* changes (e.g. setting the bounds of the component, or adding the
...
...
src/share/classes/java/awt/Container.java
浏览文件 @
8c50098c
...
@@ -41,6 +41,8 @@ import java.io.ObjectStreamField;
...
@@ -41,6 +41,8 @@ import java.io.ObjectStreamField;
import
java.io.PrintStream
;
import
java.io.PrintStream
;
import
java.io.PrintWriter
;
import
java.io.PrintWriter
;
import
java.security.AccessController
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.EventListener
;
import
java.util.EventListener
;
import
java.util.HashSet
;
import
java.util.HashSet
;
...
@@ -60,6 +62,8 @@ import sun.awt.dnd.SunDropTargetEvent;
...
@@ -60,6 +62,8 @@ import sun.awt.dnd.SunDropTargetEvent;
import
sun.java2d.pipe.Region
;
import
sun.java2d.pipe.Region
;
import
sun.security.action.GetBooleanAction
;
/**
/**
* A generic Abstract Window Toolkit(AWT) container object is a component
* A generic Abstract Window Toolkit(AWT) container object is a component
* that can contain other AWT components.
* that can contain other AWT components.
...
@@ -1506,12 +1510,18 @@ public class Container extends Component {
...
@@ -1506,12 +1510,18 @@ public class Container extends Component {
* Layout-related changes, such as bounds of the validate root descendants,
* Layout-related changes, such as bounds of the validate root descendants,
* do not affect the layout of the validate root parent. This peculiarity
* do not affect the layout of the validate root parent. This peculiarity
* enables the {@code invalidate()} method to stop invalidating the
* enables the {@code invalidate()} method to stop invalidating the
* component hierarchy when the method encounters a validate root.
* component hierarchy when the method encounters a validate root. However,
* to preserve backward compatibility this new optimized behavior is
* enabled only when the {@code java.awt.smartInvalidate} system property
* value is set to {@code true}.
* <p>
* <p>
* If a component hierarchy contains validate roots, the {@code validate()}
* If a component hierarchy contains validate roots and the new optimized
* method must be invoked on the validate root of a previously invalidated
* {@code invalidate()} behavior is enabled, the {@code validate()} method
* component, rather than on the top-level container (such as a {@code
* must be invoked on the validate root of a previously invalidated
* Frame} object) to restore the validity of the hierarchy later.
* component to restore the validity of the hierarchy later. Otherwise,
* calling the {@code validate()} method on the top-level container (such
* as a {@code Frame} object) should be used to restore the validity of the
* component hierarchy.
* <p>
* <p>
* The {@code Window} class and the {@code Applet} class are the validate
* The {@code Window} class and the {@code Applet} class are the validate
* roots in AWT. Swing introduces more validate roots.
* roots in AWT. Swing introduces more validate roots.
...
@@ -1527,13 +1537,20 @@ public class Container extends Component {
...
@@ -1527,13 +1537,20 @@ public class Container extends Component {
return
false
;
return
false
;
}
}
private
static
final
boolean
isJavaAwtSmartInvalidate
;
static
{
// Don't lazy-read because every app uses invalidate()
isJavaAwtSmartInvalidate
=
AccessController
.
doPrivileged
(
new
GetBooleanAction
(
"java.awt.smartInvalidate"
));
}
/**
/**
* Invalidates the parent of the container unless the container
* Invalidates the parent of the container unless the container
* is a validate root.
* is a validate root.
*/
*/
@Override
@Override
void
invalidateParent
()
{
void
invalidateParent
()
{
if
(!
isValidateRoot
())
{
if
(!
is
JavaAwtSmartInvalidate
||
!
is
ValidateRoot
())
{
super
.
invalidateParent
();
super
.
invalidateParent
();
}
}
}
}
...
@@ -1572,9 +1589,8 @@ public class Container extends Component {
...
@@ -1572,9 +1589,8 @@ public class Container extends Component {
* automatically. Note that the ancestors of the container may be
* automatically. Note that the ancestors of the container may be
* invalidated also (see {@link Component#invalidate} for details.)
* invalidated also (see {@link Component#invalidate} for details.)
* Therefore, to restore the validity of the hierarchy, the {@code
* Therefore, to restore the validity of the hierarchy, the {@code
* validate()} method should be invoked on a validate root of an
* validate()} method should be invoked on the top-most invalid
* invalidated component, or on the top-most container if the hierarchy
* container of the hierarchy.
* does not contain validate roots.
* <p>
* <p>
* Validating the container may be a quite time-consuming operation. For
* Validating the container may be a quite time-consuming operation. For
* performance reasons a developer may postpone the validation of the
* performance reasons a developer may postpone the validation of the
...
...
src/share/classes/java/awt/Toolkit.java
浏览文件 @
8c50098c
...
@@ -466,10 +466,7 @@ public abstract class Toolkit {
...
@@ -466,10 +466,7 @@ public abstract class Toolkit {
*/
*/
protected
void
loadSystemColors
(
int
[]
systemColors
)
protected
void
loadSystemColors
(
int
[]
systemColors
)
throws
HeadlessException
{
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
}
}
/**
/**
...
@@ -504,10 +501,7 @@ public abstract class Toolkit {
...
@@ -504,10 +501,7 @@ public abstract class Toolkit {
*/
*/
public
void
setDynamicLayout
(
boolean
dynamic
)
public
void
setDynamicLayout
(
boolean
dynamic
)
throws
HeadlessException
{
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
}
}
/**
/**
...
@@ -531,9 +525,8 @@ public abstract class Toolkit {
...
@@ -531,9 +525,8 @@ public abstract class Toolkit {
*/
*/
protected
boolean
isDynamicLayoutSet
()
protected
boolean
isDynamicLayoutSet
()
throws
HeadlessException
{
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutSet
();
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutSet
();
}
else
{
}
else
{
...
@@ -569,9 +562,8 @@ public abstract class Toolkit {
...
@@ -569,9 +562,8 @@ public abstract class Toolkit {
*/
*/
public
boolean
isDynamicLayoutActive
()
public
boolean
isDynamicLayoutActive
()
throws
HeadlessException
{
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutActive
();
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutActive
();
}
else
{
}
else
{
...
@@ -615,9 +607,7 @@ public abstract class Toolkit {
...
@@ -615,9 +607,7 @@ public abstract class Toolkit {
*/
*/
public
Insets
getScreenInsets
(
GraphicsConfiguration
gc
)
public
Insets
getScreenInsets
(
GraphicsConfiguration
gc
)
throws
HeadlessException
{
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getScreenInsets
(
gc
);
return
Toolkit
.
getDefaultToolkit
().
getScreenInsets
(
gc
);
}
else
{
}
else
{
...
@@ -1200,10 +1190,7 @@ public abstract class Toolkit {
...
@@ -1200,10 +1190,7 @@ public abstract class Toolkit {
* security manager's <code>checkPermission</code> method with a <code>
* security manager's <code>checkPermission</code> method with a <code>
* RuntimePermission("queuePrintJob")</code> permission.
* RuntimePermission("queuePrintJob")</code> permission.
*
*
* @param frame the parent of the print dialog. May be null if and only
* @param frame the parent of the print dialog. May not be null.
* if jobAttributes is not null and jobAttributes.getDialog()
* returns JobAttributes.DialogType.NONE or
* JobAttributes.DialogType.COMMON.
* @param jobtitle the title of the PrintJob. A null title is equivalent
* @param jobtitle the title of the PrintJob. A null title is equivalent
* to "".
* to "".
* @param jobAttributes a set of job attributes which will control the
* @param jobAttributes a set of job attributes which will control the
...
@@ -1359,9 +1346,8 @@ public abstract class Toolkit {
...
@@ -1359,9 +1346,8 @@ public abstract class Toolkit {
* @since 1.4
* @since 1.4
*/
*/
public
Clipboard
getSystemSelection
()
throws
HeadlessException
{
public
Clipboard
getSystemSelection
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getSystemSelection
();
return
Toolkit
.
getDefaultToolkit
().
getSystemSelection
();
}
else
{
}
else
{
...
@@ -1391,9 +1377,7 @@ public abstract class Toolkit {
...
@@ -1391,9 +1377,7 @@ public abstract class Toolkit {
* @since JDK1.1
* @since JDK1.1
*/
*/
public
int
getMenuShortcutKeyMask
()
throws
HeadlessException
{
public
int
getMenuShortcutKeyMask
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
return
Event
.
CTRL_MASK
;
return
Event
.
CTRL_MASK
;
}
}
...
@@ -1418,7 +1402,10 @@ public abstract class Toolkit {
...
@@ -1418,7 +1402,10 @@ public abstract class Toolkit {
* @since 1.3
* @since 1.3
*/
*/
public
boolean
getLockingKeyState
(
int
keyCode
)
public
boolean
getLockingKeyState
(
int
keyCode
)
throws
UnsupportedOperationException
{
throws
UnsupportedOperationException
{
GraphicsEnvironment
.
checkHeadless
();
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.getLockingKeyState"
);
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.getLockingKeyState"
);
...
@@ -1449,7 +1436,10 @@ public abstract class Toolkit {
...
@@ -1449,7 +1436,10 @@ public abstract class Toolkit {
* @since 1.3
* @since 1.3
*/
*/
public
void
setLockingKeyState
(
int
keyCode
,
boolean
on
)
public
void
setLockingKeyState
(
int
keyCode
,
boolean
on
)
throws
UnsupportedOperationException
{
throws
UnsupportedOperationException
{
GraphicsEnvironment
.
checkHeadless
();
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.setLockingKeyState"
);
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.setLockingKeyState"
);
...
@@ -1523,9 +1513,8 @@ public abstract class Toolkit {
...
@@ -1523,9 +1513,8 @@ public abstract class Toolkit {
*/
*/
public
Dimension
getBestCursorSize
(
int
preferredWidth
,
public
Dimension
getBestCursorSize
(
int
preferredWidth
,
int
preferredHeight
)
throws
HeadlessException
{
int
preferredHeight
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
// Override to implement custom cursor support.
// Override to implement custom cursor support.
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
return
Toolkit
.
getDefaultToolkit
().
...
@@ -1553,9 +1542,8 @@ public abstract class Toolkit {
...
@@ -1553,9 +1542,8 @@ public abstract class Toolkit {
* @since 1.2
* @since 1.2
*/
*/
public
int
getMaximumCursorColors
()
throws
HeadlessException
{
public
int
getMaximumCursorColors
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
// Override to implement custom cursor support.
// Override to implement custom cursor support.
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getMaximumCursorColors
();
return
Toolkit
.
getDefaultToolkit
().
getMaximumCursorColors
();
...
@@ -1605,9 +1593,8 @@ public abstract class Toolkit {
...
@@ -1605,9 +1593,8 @@ public abstract class Toolkit {
public
boolean
isFrameStateSupported
(
int
state
)
public
boolean
isFrameStateSupported
(
int
state
)
throws
HeadlessException
throws
HeadlessException
{
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
return
Toolkit
.
getDefaultToolkit
().
isFrameStateSupported
(
state
);
isFrameStateSupported
(
state
);
...
@@ -2614,9 +2601,8 @@ public abstract class Toolkit {
...
@@ -2614,9 +2601,8 @@ public abstract class Toolkit {
* @since 1.7
* @since 1.7
*/
*/
public
boolean
areExtraMouseButtonsEnabled
()
throws
HeadlessException
{
public
boolean
areExtraMouseButtonsEnabled
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
GraphicsEnvironment
.
checkHeadless
();
throw
new
HeadlessException
();
}
return
Toolkit
.
getDefaultToolkit
().
areExtraMouseButtonsEnabled
();
return
Toolkit
.
getDefaultToolkit
().
areExtraMouseButtonsEnabled
();
}
}
}
}
src/share/classes/java/lang/Throwable.java
浏览文件 @
8c50098c
...
@@ -777,7 +777,8 @@ public class Throwable implements Serializable {
...
@@ -777,7 +777,8 @@ public class Throwable implements Serializable {
* @see java.lang.Throwable#printStackTrace()
* @see java.lang.Throwable#printStackTrace()
*/
*/
public
synchronized
Throwable
fillInStackTrace
()
{
public
synchronized
Throwable
fillInStackTrace
()
{
if
(
stackTrace
!=
null
)
{
if
(
stackTrace
!=
null
||
backtrace
!=
null
/* Out of protocol state */
)
{
fillInStackTrace
(
0
);
fillInStackTrace
(
0
);
stackTrace
=
UNASSIGNED_STACK
;
stackTrace
=
UNASSIGNED_STACK
;
}
}
...
@@ -817,7 +818,8 @@ public class Throwable implements Serializable {
...
@@ -817,7 +818,8 @@ public class Throwable implements Serializable {
private
synchronized
StackTraceElement
[]
getOurStackTrace
()
{
private
synchronized
StackTraceElement
[]
getOurStackTrace
()
{
// Initialize stack trace field with information from
// Initialize stack trace field with information from
// backtrace if this is the first call to this method
// backtrace if this is the first call to this method
if
(
stackTrace
==
UNASSIGNED_STACK
)
{
if
(
stackTrace
==
UNASSIGNED_STACK
||
(
stackTrace
==
null
&&
backtrace
!=
null
)
/* Out of protocol state */
)
{
int
depth
=
getStackTraceDepth
();
int
depth
=
getStackTraceDepth
();
stackTrace
=
new
StackTraceElement
[
depth
];
stackTrace
=
new
StackTraceElement
[
depth
];
for
(
int
i
=
0
;
i
<
depth
;
i
++)
for
(
int
i
=
0
;
i
<
depth
;
i
++)
...
@@ -865,7 +867,8 @@ public class Throwable implements Serializable {
...
@@ -865,7 +867,8 @@ public class Throwable implements Serializable {
}
}
synchronized
(
this
)
{
synchronized
(
this
)
{
if
(
this
.
stackTrace
==
null
)
// Immutable stack
if
(
this
.
stackTrace
==
null
&&
// Immutable stack
backtrace
==
null
)
// Test for out of protocol state
return
;
return
;
this
.
stackTrace
=
defensiveCopy
;
this
.
stackTrace
=
defensiveCopy
;
}
}
...
...
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
浏览文件 @
8c50098c
...
@@ -27,6 +27,7 @@ package java.lang.invoke;
...
@@ -27,6 +27,7 @@ package java.lang.invoke;
import
sun.invoke.util.VerifyType
;
import
sun.invoke.util.VerifyType
;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.ValueConversions
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
...
@@ -55,29 +56,35 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -55,29 +56,35 @@ class AdapterMethodHandle extends BoundMethodHandle {
this
(
target
,
newType
,
conv
,
null
);
this
(
target
,
newType
,
conv
,
null
);
}
}
int
getConversion
()
{
return
conversion
;
}
// TO DO: When adapting another MH with a null conversion, clone
// TO DO: When adapting another MH with a null conversion, clone
// the target and change its type, instead of adding another layer.
// the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed
/** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by MethodHandles.convertArguments?
* argument conversions, as if by MethodHandles.convertArguments?
*/
*/
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
)
{
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
,
int
level
)
{
// same number of args, of course
// same number of args, of course
int
len
=
newType
.
parameterCount
();
int
len
=
newType
.
parameterCount
();
if
(
len
!=
oldType
.
parameterCount
())
if
(
len
!=
oldType
.
parameterCount
())
return
false
;
return
false
;
// Check return type.
(Not much can be done with it.)
// Check return type.
Class
<?>
exp
=
newType
.
returnType
();
Class
<?>
exp
=
newType
.
returnType
();
Class
<?>
ret
=
oldType
.
returnType
();
Class
<?>
ret
=
oldType
.
returnType
();
if
(!
VerifyType
.
isNullConversion
(
ret
,
exp
))
if
(!
VerifyType
.
isNullConversion
(
ret
,
exp
))
{
return
false
;
if
(!
convOpSupported
(
OP_COLLECT_ARGS
))
return
false
;
if
(!
canConvertArgument
(
ret
,
exp
,
level
))
return
false
;
}
// Check args pairwise.
// Check args pairwise.
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
dst
=
oldType
.
parameterType
(
i
);
// destination type
Class
<?>
dst
=
oldType
.
parameterType
(
i
);
// destination type
if
(!
canConvertArgument
(
src
,
dst
))
if
(!
canConvertArgument
(
src
,
dst
,
level
))
return
false
;
return
false
;
}
}
...
@@ -87,11 +94,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -87,11 +94,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
/** Can a JVM-level adapter directly implement the proposed
/** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by MethodHandles.convertArguments?
* argument conversion, as if by MethodHandles.convertArguments?
*/
*/
static
boolean
canConvertArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
static
boolean
canConvertArgument
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
// so we don't need to repeat so much decision making.
// so we don't need to repeat so much decision making.
if
(
VerifyType
.
isNullConversion
(
src
,
dst
))
{
if
(
VerifyType
.
isNullConversion
(
src
,
dst
))
{
return
true
;
return
true
;
}
else
if
(
convOpSupported
(
OP_COLLECT_ARGS
))
{
// If we can build filters, we can convert anything to anything.
return
true
;
}
else
if
(
src
.
isPrimitive
())
{
}
else
if
(
src
.
isPrimitive
())
{
if
(
dst
.
isPrimitive
())
if
(
dst
.
isPrimitive
())
return
canPrimCast
(
src
,
dst
);
return
canPrimCast
(
src
,
dst
);
...
@@ -99,7 +109,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -99,7 +109,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
canBoxArgument
(
src
,
dst
);
return
canBoxArgument
(
src
,
dst
);
}
else
{
}
else
{
if
(
dst
.
isPrimitive
())
if
(
dst
.
isPrimitive
())
return
canUnboxArgument
(
src
,
dst
);
return
canUnboxArgument
(
src
,
dst
,
level
);
else
else
return
true
;
// any two refs can be interconverted
return
true
;
// any two refs can be interconverted
}
}
...
@@ -109,21 +119,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -109,21 +119,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
* Create a JVM-level adapter method handle to conform the given method
* Create a JVM-level adapter method handle to conform the given method
* handle to the similar newType, using only pairwise argument conversions.
* handle to the similar newType, using only pairwise argument conversions.
* For each argument, convert incoming argument to the exact type needed.
* For each argument, convert incoming argument to the exact type needed.
* Only null conversions are allowed on the return value (until
* The argument conversions allowed are casting, boxing and unboxing,
* the JVM supports ricochet adapters).
* The argument conversions allowed are casting, unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
* integral widening or narrowing, and floating point widening or narrowing.
* @param newType required call type
* @param newType required call type
* @param target original method handle
* @param target original method handle
* @param level which strength of conversion is allowed
* @return an adapter to the original handle with the desired new type,
* @return an adapter to the original handle with the desired new type,
* or the original target if the types are already identical
* or the original target if the types are already identical
* or null if the adaptation cannot be made
* or null if the adaptation cannot be made
*/
*/
static
MethodHandle
makePairwiseConvert
(
MethodType
newType
,
MethodHandle
target
)
{
static
MethodHandle
makePairwiseConvert
(
MethodType
newType
,
MethodHandle
target
,
int
level
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
if
(
newType
==
oldType
)
return
target
;
if
(
newType
==
oldType
)
return
target
;
if
(!
canPairwiseConvert
(
newType
,
oldType
))
if
(!
canPairwiseConvert
(
newType
,
oldType
,
level
))
return
null
;
return
null
;
// (after this point, it is an assertion error to fail to convert)
// (after this point, it is an assertion error to fail to convert)
...
@@ -138,9 +147,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -138,9 +147,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
break
;
break
;
}
}
}
}
Class
<?>
needReturn
=
newType
.
returnType
();
Class
<?>
haveReturn
=
oldType
.
returnType
();
boolean
retConv
=
!
VerifyType
.
isNullConversion
(
haveReturn
,
needReturn
);
// Now build a chain of one or more adapters.
// Now build a chain of one or more adapters.
MethodHandle
adapter
=
target
;
MethodHandle
adapter
=
target
,
adapter2
;
MethodType
midType
=
oldType
.
changeReturnType
(
newType
.
returnType
())
;
MethodType
midType
=
oldType
;
for
(
int
i
=
0
;
i
<=
lastConv
;
i
++)
{
for
(
int
i
=
0
;
i
<=
lastConv
;
i
++)
{
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
dst
=
midType
.
parameterType
(
i
);
// destination type
Class
<?>
dst
=
midType
.
parameterType
(
i
);
// destination type
...
@@ -149,22 +163,23 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -149,22 +163,23 @@ class AdapterMethodHandle extends BoundMethodHandle {
continue
;
continue
;
}
}
// Work the current type backward toward the desired caller type:
// Work the current type backward toward the desired caller type:
if
(
i
!=
lastConv
)
{
midType
=
midType
.
changeParameterType
(
i
,
src
);
midType
=
midType
.
changeParameterType
(
i
,
src
);
if
(
i
==
lastConv
)
{
}
else
{
// When doing the last (or only) real conversion,
// When doing the last (or only) real conversion,
// force all remaining null conversions to happen also.
// force all remaining null conversions to happen also.
assert
(
VerifyType
.
isNullConversion
(
newType
,
midType
.
changeParameterType
(
i
,
src
)));
MethodType
lastMidType
=
newType
;
midType
=
newType
;
if
(
retConv
)
lastMidType
=
lastMidType
.
changeReturnType
(
haveReturn
);
assert
(
VerifyType
.
isNullConversion
(
lastMidType
,
midType
));
midType
=
lastMidType
;
}
}
// Tricky case analysis follows.
// Tricky case analysis follows.
// It parallels canConvertArgument() above.
// It parallels canConvertArgument() above.
if
(
src
.
isPrimitive
())
{
if
(
src
.
isPrimitive
())
{
if
(
dst
.
isPrimitive
())
{
if
(
dst
.
isPrimitive
())
{
adapter
=
makePrimCast
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makePrimCast
(
midType
,
adapter
,
i
,
dst
);
}
else
{
}
else
{
adapter
=
makeBoxArgument
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeBoxArgument
(
midType
,
adapter
,
i
,
src
);
}
}
}
else
{
}
else
{
if
(
dst
.
isPrimitive
())
{
if
(
dst
.
isPrimitive
())
{
...
@@ -174,29 +189,53 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -174,29 +189,53 @@ class AdapterMethodHandle extends BoundMethodHandle {
// conversions supported by reflect.Method.invoke.
// conversions supported by reflect.Method.invoke.
// Those conversions require a big nest of if/then/else logic,
// Those conversions require a big nest of if/then/else logic,
// which we prefer to make a user responsibility.
// which we prefer to make a user responsibility.
adapter
=
makeUnboxArgument
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeUnboxArgument
(
midType
,
adapter
,
i
,
dst
,
level
);
}
else
{
}
else
{
// Simple reference conversion.
// Simple reference conversion.
// Note: Do not check for a class hierarchy relation
// Note: Do not check for a class hierarchy relation
// between src and dst. In all cases a 'null' argument
// between src and dst. In all cases a 'null' argument
// will pass the cast conversion.
// will pass the cast conversion.
adapter
=
makeCheckCast
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeCheckCast
(
midType
,
adapter
,
i
,
dst
);
}
}
}
}
assert
(
adapter
!=
null
);
assert
(
adapter2
!=
null
)
:
Arrays
.
asList
(
src
,
dst
,
midType
,
adapter
,
i
,
target
,
newType
);
assert
(
adapter
.
type
()
==
midType
);
assert
(
adapter2
.
type
()
==
midType
);
adapter
=
adapter2
;
}
if
(
retConv
)
{
adapter2
=
makeReturnConversion
(
adapter
,
haveReturn
,
needReturn
);
assert
(
adapter2
!=
null
);
adapter
=
adapter2
;
}
}
if
(
adapter
.
type
()
!=
newType
)
{
if
(
adapter
.
type
()
!=
newType
)
{
// Only trivial conversions remain.
// Only trivial conversions remain.
adapter
=
makeRetypeOnly
(
newType
,
adapter
);
adapter2
=
makeRetypeOnly
(
newType
,
adapter
);
assert
(
adapter
!=
null
);
assert
(
adapter2
!=
null
);
adapter
=
adapter2
;
// Actually, that's because there were no non-trivial ones:
// Actually, that's because there were no non-trivial ones:
assert
(
lastConv
==
-
1
);
assert
(
lastConv
==
-
1
||
retConv
);
}
}
assert
(
adapter
.
type
()
==
newType
);
assert
(
adapter
.
type
()
==
newType
);
return
adapter
;
return
adapter
;
}
}
private
static
MethodHandle
makeReturnConversion
(
MethodHandle
target
,
Class
<?>
haveReturn
,
Class
<?>
needReturn
)
{
MethodHandle
adjustReturn
;
if
(
haveReturn
==
void
.
class
)
{
// synthesize a zero value for the given void
Object
zero
=
Wrapper
.
forBasicType
(
needReturn
).
zero
();
adjustReturn
=
MethodHandles
.
constant
(
needReturn
,
zero
);
}
else
{
MethodType
needConversion
=
MethodType
.
methodType
(
needReturn
,
haveReturn
);
adjustReturn
=
MethodHandles
.
identity
(
needReturn
).
asType
(
needConversion
);
}
if
(!
canCollectArguments
(
adjustReturn
.
type
(),
target
.
type
(),
0
,
false
))
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
throw
new
InternalError
(
"NYI"
);
}
return
makeCollectArguments
(
adjustReturn
,
target
,
0
,
false
);
}
/**
/**
* Create a JVM-level adapter method handle to permute the arguments
* Create a JVM-level adapter method handle to permute the arguments
* of the given method.
* of the given method.
...
@@ -224,7 +263,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -224,7 +263,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(
argumentMap
.
length
!=
oldType
.
parameterCount
())
if
(
argumentMap
.
length
!=
oldType
.
parameterCount
())
throw
newIllegalArgumentException
(
"bad permutation: "
+
Arrays
.
toString
(
argumentMap
));
throw
newIllegalArgumentException
(
"bad permutation: "
+
Arrays
.
toString
(
argumentMap
));
if
(
nullPermutation
)
{
if
(
nullPermutation
)
{
MethodHandle
res
=
makePairwiseConvert
(
newType
,
target
);
MethodHandle
res
=
makePairwiseConvert
(
newType
,
target
,
0
);
// well, that was easy
// well, that was easy
if
(
res
==
null
)
if
(
res
==
null
)
throw
newIllegalArgumentException
(
"cannot convert pairwise: "
+
newType
);
throw
newIllegalArgumentException
(
"cannot convert pairwise: "
+
newType
);
...
@@ -310,11 +349,25 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -310,11 +349,25 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
(
spChange
&
CONV_STACK_MOVE_MASK
)
<<
CONV_STACK_MOVE_SHIFT
;
return
(
spChange
&
CONV_STACK_MOVE_MASK
)
<<
CONV_STACK_MOVE_SHIFT
;
}
}
static
int
extractStackMove
(
int
convOp
)
{
int
spChange
=
convOp
>>
CONV_STACK_MOVE_SHIFT
;
return
spChange
/
MethodHandleNatives
.
JVM_STACK_MOVE_UNIT
;
}
static
int
extractStackMove
(
MethodHandle
target
)
{
if
(
target
instanceof
AdapterMethodHandle
)
{
AdapterMethodHandle
amh
=
(
AdapterMethodHandle
)
target
;
return
extractStackMove
(
amh
.
getConversion
());
}
else
{
return
0
;
}
}
/** Construct an adapter conversion descriptor for a single-argument conversion. */
/** Construct an adapter conversion descriptor for a single-argument conversion. */
private
static
long
makeConv
(
int
convOp
,
int
argnum
,
int
src
,
int
dest
)
{
private
static
long
makeConv
(
int
convOp
,
int
argnum
,
int
src
,
int
dest
)
{
assert
(
src
==
(
src
&
0xF
));
assert
(
src
==
(
src
&
CONV_TYPE_MASK
));
assert
(
dest
==
(
dest
&
0xF
));
assert
(
dest
==
(
dest
&
CONV_TYPE_MASK
));
assert
(
convOp
>=
OP_CHECK_CAST
&&
convOp
<=
OP_PRIM_TO_REF
);
assert
(
convOp
>=
OP_CHECK_CAST
&&
convOp
<=
OP_PRIM_TO_REF
||
convOp
==
OP_COLLECT_ARGS
);
int
stackMove
=
type2size
(
dest
)
-
type2size
(
src
);
int
stackMove
=
type2size
(
dest
)
-
type2size
(
src
);
return
((
long
)
argnum
<<
32
|
return
((
long
)
argnum
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
...
@@ -323,11 +376,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -323,11 +376,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
insertStackMove
(
stackMove
)
insertStackMove
(
stackMove
)
);
);
}
}
private
static
long
makeConv
(
int
convOp
,
int
argnum
,
int
stackMove
)
{
private
static
long
makeDupConv
(
int
convOp
,
int
argnum
,
int
stackMove
)
{
assert
(
convOp
>=
OP_DUP_ARGS
&&
convOp
<=
OP_SPREAD_ARGS
);
// simple argument motion, requiring one slot to specify
assert
(
convOp
==
OP_DUP_ARGS
||
convOp
==
OP_DROP_ARGS
);
byte
src
=
0
,
dest
=
0
;
byte
src
=
0
,
dest
=
0
;
if
(
convOp
>=
OP_COLLECT_ARGS
&&
convOp
<=
OP_SPREAD_ARGS
)
src
=
dest
=
T_OBJECT
;
return
((
long
)
argnum
<<
32
|
return
((
long
)
argnum
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
int
)
src
<<
CONV_SRC_TYPE_SHIFT
|
(
int
)
src
<<
CONV_SRC_TYPE_SHIFT
|
...
@@ -336,7 +388,8 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -336,7 +388,8 @@ class AdapterMethodHandle extends BoundMethodHandle {
);
);
}
}
private
static
long
makeSwapConv
(
int
convOp
,
int
srcArg
,
byte
type
,
int
destSlot
)
{
private
static
long
makeSwapConv
(
int
convOp
,
int
srcArg
,
byte
type
,
int
destSlot
)
{
assert
(
convOp
>=
OP_SWAP_ARGS
&&
convOp
<=
OP_ROT_ARGS
);
// more complex argument motion, requiring two slots to specify
assert
(
convOp
==
OP_SWAP_ARGS
||
convOp
==
OP_ROT_ARGS
);
return
((
long
)
srcArg
<<
32
|
return
((
long
)
srcArg
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
int
)
type
<<
CONV_SRC_TYPE_SHIFT
|
(
int
)
type
<<
CONV_SRC_TYPE_SHIFT
|
...
@@ -344,6 +397,18 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -344,6 +397,18 @@ class AdapterMethodHandle extends BoundMethodHandle {
(
int
)
destSlot
<<
CONV_VMINFO_SHIFT
(
int
)
destSlot
<<
CONV_VMINFO_SHIFT
);
);
}
}
private
static
long
makeSpreadConv
(
int
convOp
,
int
argnum
,
int
src
,
int
dest
,
int
stackMove
)
{
// spreading or collecting, at a particular slot location
assert
(
convOp
==
OP_SPREAD_ARGS
||
convOp
==
OP_COLLECT_ARGS
||
convOp
==
OP_FOLD_ARGS
);
// src = spread ? T_OBJECT (for array) : common type of collected args (else void)
// dest = spread ? element type of array : result type of collector (can be void)
return
((
long
)
argnum
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
int
)
src
<<
CONV_SRC_TYPE_SHIFT
|
(
int
)
dest
<<
CONV_DEST_TYPE_SHIFT
|
insertStackMove
(
stackMove
)
);
}
private
static
long
makeConv
(
int
convOp
)
{
private
static
long
makeConv
(
int
convOp
)
{
assert
(
convOp
==
OP_RETYPE_ONLY
||
convOp
==
OP_RETYPE_RAW
);
assert
(
convOp
==
OP_RETYPE_ONLY
||
convOp
==
OP_RETYPE_RAW
);
return
((
long
)-
1
<<
32
)
|
(
convOp
<<
CONV_OP_SHIFT
);
// stackMove, src, dst all zero
return
((
long
)-
1
<<
32
)
|
(
convOp
<<
CONV_OP_SHIFT
);
// stackMove, src, dst all zero
...
@@ -570,14 +635,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -570,14 +635,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
static
boolean
canPrimCast
(
Class
<?>
src
,
Class
<?>
dst
)
{
static
boolean
canPrimCast
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
||
!
src
.
isPrimitive
()
||
!
dst
.
isPrimitive
())
{
if
(
src
==
dst
||
!
src
.
isPrimitive
()
||
!
dst
.
isPrimitive
())
{
return
false
;
return
false
;
}
else
if
(
Wrapper
.
forPrimitiveType
(
dst
).
isFloating
())
{
// both must be floating types
return
Wrapper
.
forPrimitiveType
(
src
).
isFloating
();
}
else
{
}
else
{
// both are integral, and all combinations work fine
boolean
sflt
=
Wrapper
.
forPrimitiveType
(
src
).
isFloating
();
assert
(
Wrapper
.
forPrimitiveType
(
src
).
isIntegral
()
&&
boolean
dflt
=
Wrapper
.
forPrimitiveType
(
dst
).
isFloating
();
Wrapper
.
forPrimitiveType
(
dst
).
isIntegral
());
return
!(
sflt
|
dflt
);
// no float support at present
return
true
;
}
}
}
}
...
@@ -589,6 +650,29 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -589,6 +650,29 @@ class AdapterMethodHandle extends BoundMethodHandle {
*/
*/
static
MethodHandle
makePrimCast
(
MethodType
newType
,
MethodHandle
target
,
static
MethodHandle
makePrimCast
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
)
{
Class
<?>
src
=
newType
.
parameterType
(
arg
);
if
(
canPrimCast
(
src
,
convType
))
return
makePrimCastOnly
(
newType
,
target
,
arg
,
convType
);
Class
<?>
dst
=
convType
;
boolean
sflt
=
Wrapper
.
forPrimitiveType
(
src
).
isFloating
();
boolean
dflt
=
Wrapper
.
forPrimitiveType
(
dst
).
isFloating
();
if
(
sflt
|
dflt
)
{
MethodHandle
convMethod
;
if
(
sflt
)
convMethod
=
((
src
==
double
.
class
)
?
ValueConversions
.
convertFromDouble
(
dst
)
:
ValueConversions
.
convertFromFloat
(
dst
));
else
convMethod
=
((
dst
==
double
.
class
)
?
ValueConversions
.
convertToDouble
(
src
)
:
ValueConversions
.
convertToFloat
(
src
));
long
conv
=
makeConv
(
OP_COLLECT_ARGS
,
arg
,
basicType
(
src
),
basicType
(
dst
));
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
convMethod
);
}
throw
new
InternalError
(
"makePrimCast"
);
}
static
MethodHandle
makePrimCastOnly
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
if
(!
canPrimCast
(
newType
,
oldType
,
arg
,
convType
))
if
(!
canPrimCast
(
newType
,
oldType
,
arg
,
convType
))
return
null
;
return
null
;
...
@@ -602,7 +686,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -602,7 +686,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
* The convType is the unboxed type; it can be either a primitive or wrapper.
* The convType is the unboxed type; it can be either a primitive or wrapper.
*/
*/
static
boolean
canUnboxArgument
(
MethodType
newType
,
MethodType
targetType
,
static
boolean
canUnboxArgument
(
MethodType
newType
,
MethodType
targetType
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
,
int
level
)
{
if
(!
convOpSupported
(
OP_REF_TO_PRIM
))
return
false
;
if
(!
convOpSupported
(
OP_REF_TO_PRIM
))
return
false
;
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
targetType
.
parameterType
(
arg
);
Class
<?>
dst
=
targetType
.
parameterType
(
arg
);
...
@@ -616,21 +700,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -616,21 +700,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
(
diff
==
arg
+
1
);
// arg is sole non-trivial diff
return
(
diff
==
arg
+
1
);
// arg is sole non-trivial diff
}
}
/** Can an primitive unboxing adapter validly convert src to dst? */
/** Can an primitive unboxing adapter validly convert src to dst? */
static
boolean
canUnboxArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
static
boolean
canUnboxArgument
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
return
(!
src
.
isPrimitive
()
&&
Wrapper
.
asPrimitiveType
(
dst
).
isPrimitive
());
assert
(
dst
.
isPrimitive
());
// if we have JVM support for boxing, we can also do complex unboxing
if
(
convOpSupported
(
OP_PRIM_TO_REF
))
return
true
;
Wrapper
dw
=
Wrapper
.
forPrimitiveType
(
dst
);
// Level 0 means cast and unbox. This works on any reference.
if
(
level
==
0
)
return
!
src
.
isPrimitive
();
assert
(
level
>=
0
&&
level
<=
2
);
// Levels 1 and 2 allow widening and/or narrowing conversions.
// These are not supported directly by the JVM.
// But if the input reference is monomorphic, we can do it.
return
dw
.
wrapperType
()
==
src
;
}
}
/** Factory method: Unbox the given argument.
/** Factory method: Unbox the given argument.
* Return null if this cannot be done.
* Return null if this cannot be done.
*/
*/
static
MethodHandle
makeUnboxArgument
(
MethodType
newType
,
MethodHandle
target
,
static
MethodHandle
makeUnboxArgument
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
,
int
level
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
oldType
.
parameterType
(
arg
);
Class
<?>
dst
=
oldType
.
parameterType
(
arg
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
Class
<?>
primType
=
Wrapper
.
asPrimitiveType
(
convType
);
Class
<?>
primType
=
Wrapper
.
asPrimitiveType
(
convType
);
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
))
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
,
level
))
return
null
;
return
null
;
MethodType
castDone
=
newType
;
MethodType
castDone
=
newType
;
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
...
@@ -642,19 +736,46 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -642,19 +736,46 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
makeCheckCast
(
newType
,
adapter
,
arg
,
boxType
);
return
makeCheckCast
(
newType
,
adapter
,
arg
,
boxType
);
}
}
/** Can a boxing conversion validly convert src to dst? */
static
boolean
canBoxArgument
(
MethodType
newType
,
MethodType
targetType
,
int
arg
,
Class
<?>
convType
)
{
if
(!
convOpSupported
(
OP_PRIM_TO_REF
))
return
false
;
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
targetType
.
parameterType
(
arg
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
convType
=
Wrapper
.
asPrimitiveType
(
convType
);
if
(!
canCheckCast
(
boxType
,
dst
)
||
boxType
==
convType
||
!
VerifyType
.
isNullConversion
(
src
,
convType
))
return
false
;
int
diff
=
diffTypes
(
newType
,
targetType
,
false
);
return
(
diff
==
arg
+
1
);
// arg is sole non-trivial diff
}
/** Can an primitive boxing adapter validly convert src to dst? */
/** Can an primitive boxing adapter validly convert src to dst? */
static
boolean
canBoxArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
static
boolean
canBoxArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(!
convOpSupported
(
OP_PRIM_TO_REF
))
return
false
;
if
(!
convOpSupported
(
OP_PRIM_TO_REF
))
return
false
;
throw
new
UnsupportedOperationException
(
"NYI"
);
return
(
src
.
isPrimitive
()
&&
!
dst
.
isPrimitive
()
);
}
}
/** Factory method:
Unb
ox the given argument.
/** Factory method:
B
ox the given argument.
* Return null if this cannot be done.
* Return null if this cannot be done.
*/
*/
static
MethodHandle
makeBoxArgument
(
MethodType
newType
,
MethodHandle
target
,
static
MethodHandle
makeBoxArgument
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
)
{
// this is difficult to do in the JVM because it must GC
MethodType
oldType
=
target
.
type
();
return
null
;
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
oldType
.
parameterType
(
arg
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
Class
<?>
primType
=
Wrapper
.
asPrimitiveType
(
convType
);
if
(!
canBoxArgument
(
newType
,
oldType
,
arg
,
convType
))
{
return
null
;
}
if
(!
VerifyType
.
isNullConversion
(
boxType
,
dst
))
target
=
makeCheckCast
(
oldType
.
changeParameterType
(
arg
,
boxType
),
target
,
arg
,
dst
);
MethodHandle
boxerMethod
=
ValueConversions
.
box
(
Wrapper
.
forPrimitiveType
(
primType
));
long
conv
=
makeConv
(
OP_PRIM_TO_REF
,
arg
,
basicType
(
primType
),
T_OBJECT
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
boxerMethod
);
}
}
/** Can an adapter simply drop arguments to convert the target to newType? */
/** Can an adapter simply drop arguments to convert the target to newType? */
...
@@ -699,7 +820,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -699,7 +820,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int
slotCount
=
keep1InSlot
-
dropSlot
;
int
slotCount
=
keep1InSlot
-
dropSlot
;
assert
(
slotCount
>=
dropArgCount
);
assert
(
slotCount
>=
dropArgCount
);
assert
(
target
.
type
().
parameterSlotCount
()
+
slotCount
==
newType
.
parameterSlotCount
());
assert
(
target
.
type
().
parameterSlotCount
()
+
slotCount
==
newType
.
parameterSlotCount
());
long
conv
=
makeConv
(
OP_DROP_ARGS
,
dropArgPos
+
dropArgCount
-
1
,
-
slotCount
);
long
conv
=
make
Dup
Conv
(
OP_DROP_ARGS
,
dropArgPos
+
dropArgCount
-
1
,
-
slotCount
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
}
}
...
@@ -739,7 +860,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -739,7 +860,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int
keep1InSlot
=
newType
.
parameterSlotDepth
(
dupArgPos
);
int
keep1InSlot
=
newType
.
parameterSlotDepth
(
dupArgPos
);
int
slotCount
=
keep1InSlot
-
dupSlot
;
int
slotCount
=
keep1InSlot
-
dupSlot
;
assert
(
target
.
type
().
parameterSlotCount
()
-
slotCount
==
newType
.
parameterSlotCount
());
assert
(
target
.
type
().
parameterSlotCount
()
-
slotCount
==
newType
.
parameterSlotCount
());
long
conv
=
makeConv
(
OP_DUP_ARGS
,
dupArgPos
+
dupArgCount
-
1
,
slotCount
);
long
conv
=
make
Dup
Conv
(
OP_DUP_ARGS
,
dupArgPos
+
dupArgCount
-
1
,
slotCount
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
}
}
...
@@ -900,7 +1021,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -900,7 +1021,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
for
(
int
i
=
0
;
i
<
spreadArgCount
;
i
++)
{
for
(
int
i
=
0
;
i
<
spreadArgCount
;
i
++)
{
Class
<?>
src
=
VerifyType
.
spreadArgElementType
(
spreadArgType
,
i
);
Class
<?>
src
=
VerifyType
.
spreadArgElementType
(
spreadArgType
,
i
);
Class
<?>
dst
=
targetType
.
parameterType
(
spreadArgPos
+
i
);
Class
<?>
dst
=
targetType
.
parameterType
(
spreadArgPos
+
i
);
if
(
src
==
null
||
!
VerifyType
.
isNullConversion
(
src
,
dst
))
if
(
src
==
null
||
!
canConvertArgument
(
src
,
dst
,
1
))
return
false
;
return
false
;
}
}
return
true
;
return
true
;
...
@@ -910,24 +1031,100 @@ class AdapterMethodHandle extends BoundMethodHandle {
...
@@ -910,24 +1031,100 @@ class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Spread selected argument. */
/** Factory method: Spread selected argument. */
static
MethodHandle
makeSpreadArguments
(
MethodType
newType
,
MethodHandle
target
,
static
MethodHandle
makeSpreadArguments
(
MethodType
newType
,
MethodHandle
target
,
Class
<?>
spreadArgType
,
int
spreadArgPos
,
int
spreadArgCount
)
{
Class
<?>
spreadArgType
,
int
spreadArgPos
,
int
spreadArgCount
)
{
// FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
if
(!
canSpreadArguments
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
))
if
(!
canSpreadArguments
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
))
return
null
;
return
null
;
// dest is not significant; remove?
int
dest
=
T_VOID
;
for
(
int
i
=
0
;
i
<
spreadArgCount
;
i
++)
{
Class
<?>
arg
=
VerifyType
.
spreadArgElementType
(
spreadArgType
,
i
);
if
(
arg
==
null
)
arg
=
Object
.
class
;
int
dest2
=
basicType
(
arg
);
if
(
dest
==
T_VOID
)
dest
=
dest2
;
else
if
(
dest
!=
dest2
)
dest
=
T_VOID
;
if
(
dest
==
T_VOID
)
break
;
targetType
=
targetType
.
changeParameterType
(
spreadArgPos
+
i
,
arg
);
}
target
=
target
.
asType
(
targetType
);
int
arrayArgSize
=
1
;
// always a reference
// in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ]
// in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ]
// out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
// out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
int
keep2OutPos
=
spreadArgPos
+
spreadArgCount
;
int
keep2OutPos
=
spreadArgPos
+
spreadArgCount
;
int
spreadSlot
=
targetType
.
parameterSlotDepth
(
keep2OutPos
);
int
keep1OutSlot
=
targetType
.
parameterSlotDepth
(
spreadArgPos
);
// leading edge of |spread...|
int
keep1OutSlot
=
targetType
.
parameterSlotDepth
(
spreadArgPos
);
int
spreadSlot
=
targetType
.
parameterSlotDepth
(
keep2OutPos
);
// trailing edge of |spread...|
int
slotCount
=
keep1OutSlot
-
spreadSlot
;
assert
(
spreadSlot
==
newType
.
parameterSlotDepth
(
spreadArgPos
+
arrayArgSize
))
;
assert
(
spreadSlot
==
newType
.
parameterSlotDepth
(
spreadArgPos
+
1
));
int
slotCount
=
keep1OutSlot
-
spreadSlot
;
// slots in |spread...|
assert
(
slotCount
>=
spreadArgCount
);
assert
(
slotCount
>=
spreadArgCount
);
long
conv
=
makeConv
(
OP_SPREAD_ARGS
,
spreadArgPos
,
slotCount
-
1
);
int
stackMove
=
-
arrayArgSize
+
slotCount
;
// pop array, push N slots
long
conv
=
makeSpreadConv
(
OP_SPREAD_ARGS
,
spreadArgPos
,
T_OBJECT
,
dest
,
stackMove
);
MethodHandle
res
=
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
spreadArgType
);
MethodHandle
res
=
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
spreadArgType
);
assert
(
res
.
type
().
parameterType
(
spreadArgPos
)
==
spreadArgType
);
assert
(
res
.
type
().
parameterType
(
spreadArgPos
)
==
spreadArgType
);
return
res
;
return
res
;
}
}
// TO DO: makeCollectArguments, makeFlyby, makeRicochet
/** Can an adapter collect a series of arguments, replacing them by zero or one results? */
static
boolean
canCollectArguments
(
MethodType
targetType
,
MethodType
collectorType
,
int
collectArgPos
,
boolean
retainOriginalArgs
)
{
if
(!
convOpSupported
(
retainOriginalArgs
?
OP_FOLD_ARGS
:
OP_COLLECT_ARGS
))
return
false
;
int
collectArgCount
=
collectorType
.
parameterCount
();
Class
<?>
rtype
=
collectorType
.
returnType
();
assert
(
rtype
==
void
.
class
||
targetType
.
parameterType
(
collectArgPos
)
==
rtype
)
// [(Object)Object[], (Object[])Object[], 0, 1]
:
Arrays
.
asList
(
targetType
,
collectorType
,
collectArgPos
,
collectArgCount
)
;
return
true
;
}
/** Factory method: Collect or filter selected argument(s). */
static
MethodHandle
makeCollectArguments
(
MethodHandle
target
,
MethodHandle
collector
,
int
collectArgPos
,
boolean
retainOriginalArgs
)
{
assert
(
canCollectArguments
(
target
.
type
(),
collector
.
type
(),
collectArgPos
,
retainOriginalArgs
));
MethodType
targetType
=
target
.
type
();
MethodType
collectorType
=
collector
.
type
();
int
collectArgCount
=
collectorType
.
parameterCount
();
Class
<?>
collectValType
=
collectorType
.
returnType
();
int
collectValCount
=
(
collectValType
==
void
.
class
?
0
:
1
);
int
collectValSlots
=
collectorType
.
returnSlotCount
();
MethodType
newType
=
targetType
.
dropParameterTypes
(
collectArgPos
,
collectArgPos
+
collectValCount
);
if
(!
retainOriginalArgs
)
{
newType
=
newType
.
insertParameterTypes
(
collectArgPos
,
collectorType
.
parameterList
());
}
else
{
// parameter types at the fold point must be the same
assert
(
diffParamTypes
(
newType
,
collectArgPos
,
targetType
,
collectValCount
,
collectArgCount
,
false
)
==
0
)
:
Arrays
.
asList
(
target
,
collector
,
collectArgPos
,
retainOriginalArgs
);
}
// in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
// out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
// out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
int
keep2InPos
=
collectArgPos
+
collectArgCount
;
int
keep1InSlot
=
newType
.
parameterSlotDepth
(
collectArgPos
);
// leading edge of |collect...|
int
collectSlot
=
newType
.
parameterSlotDepth
(
keep2InPos
);
// trailing edge of |collect...|
int
slotCount
=
keep1InSlot
-
collectSlot
;
// slots in |collect...|
assert
(
slotCount
>=
collectArgCount
);
assert
(
collectSlot
==
targetType
.
parameterSlotDepth
(
collectArgPos
+
collectValCount
+
(
retainOriginalArgs
?
collectArgCount
:
0
)
));
int
dest
=
basicType
(
collectValType
);
int
src
=
T_VOID
;
// src is not significant; remove?
for
(
int
i
=
0
;
i
<
collectArgCount
;
i
++)
{
int
src2
=
basicType
(
collectorType
.
parameterType
(
i
));
if
(
src
==
T_VOID
)
src
=
src2
;
else
if
(
src
!=
src2
)
src
=
T_VOID
;
if
(
src
==
T_VOID
)
break
;
}
int
stackMove
=
collectValSlots
;
// push 0..2 results
if
(!
retainOriginalArgs
)
stackMove
-=
slotCount
;
// pop N arguments
int
lastCollectArg
=
keep2InPos
-
1
;
long
conv
=
makeSpreadConv
(
retainOriginalArgs
?
OP_FOLD_ARGS
:
OP_COLLECT_ARGS
,
lastCollectArg
,
src
,
dest
,
stackMove
);
MethodHandle
res
=
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
collector
);
assert
(
res
.
type
().
parameterList
().
subList
(
collectArgPos
,
collectArgPos
+
collectArgCount
)
.
equals
(
collector
.
type
().
parameterList
()));
return
res
;
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
...
...
src/share/classes/java/lang/invoke/CallSite.java
浏览文件 @
8c50098c
...
@@ -273,9 +273,9 @@ public class CallSite {
...
@@ -273,9 +273,9 @@ public class CallSite {
Object
binding
;
Object
binding
;
info
=
maybeReBox
(
info
);
info
=
maybeReBox
(
info
);
if
(
info
==
null
)
{
if
(
info
==
null
)
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
);
}
else
if
(!
info
.
getClass
().
isArray
())
{
}
else
if
(!
info
.
getClass
().
isArray
())
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
,
info
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
,
info
);
}
else
{
}
else
{
Object
[]
argv
=
(
Object
[])
info
;
Object
[]
argv
=
(
Object
[])
info
;
maybeReBoxElements
(
argv
);
maybeReBoxElements
(
argv
);
...
@@ -283,10 +283,10 @@ public class CallSite {
...
@@ -283,10 +283,10 @@ public class CallSite {
throw
new
BootstrapMethodError
(
"too many bootstrap method arguments"
);
throw
new
BootstrapMethodError
(
"too many bootstrap method arguments"
);
MethodType
bsmType
=
bootstrapMethod
.
type
();
MethodType
bsmType
=
bootstrapMethod
.
type
();
if
(
bsmType
.
parameterCount
()
==
4
&&
bsmType
.
parameterType
(
3
)
==
Object
[].
class
)
if
(
bsmType
.
parameterCount
()
==
4
&&
bsmType
.
parameterType
(
3
)
==
Object
[].
class
)
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
,
argv
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
,
argv
);
else
else
binding
=
MethodHandles
.
spreadInvoker
(
bsmType
,
3
)
binding
=
MethodHandles
.
spreadInvoker
(
bsmType
,
3
)
.
invoke
Generic
(
bootstrapMethod
,
caller
,
name
,
type
,
argv
);
.
invoke
(
bootstrapMethod
,
caller
,
name
,
type
,
argv
);
}
}
//System.out.println("BSM for "+name+type+" => "+binding);
//System.out.println("BSM for "+name+type+" => "+binding);
if
(
binding
instanceof
CallSite
)
{
if
(
binding
instanceof
CallSite
)
{
...
...
src/share/classes/java/lang/invoke/FilterGeneric.java
浏览文件 @
8c50098c
...
@@ -61,6 +61,10 @@ class FilterGeneric {
...
@@ -61,6 +61,10 @@ class FilterGeneric {
return
ad
;
return
ad
;
}
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
Adapter
makeInstance
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
Adapter
makeInstance
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
Adapter
ad
=
getAdapter
(
kind
,
pos
);
Adapter
ad
=
getAdapter
(
kind
,
pos
);
return
ad
.
makeInstance
(
ad
.
prototypeEntryPoint
(),
filter
,
target
);
return
ad
.
makeInstance
(
ad
.
prototypeEntryPoint
(),
filter
,
target
);
...
...
src/share/classes/java/lang/invoke/FilterOneArgument.java
浏览文件 @
8c50098c
...
@@ -67,6 +67,10 @@ class FilterOneArgument extends BoundMethodHandle {
...
@@ -67,6 +67,10 @@ class FilterOneArgument extends BoundMethodHandle {
this
.
target
=
target
;
this
.
target
=
target
;
}
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
public
static
MethodHandle
make
(
MethodHandle
filter
,
MethodHandle
target
)
{
public
static
MethodHandle
make
(
MethodHandle
filter
,
MethodHandle
target
)
{
if
(
filter
==
null
)
return
target
;
if
(
filter
==
null
)
return
target
;
if
(
target
==
null
)
return
filter
;
if
(
target
==
null
)
return
filter
;
...
...
src/share/classes/java/lang/invoke/FromGeneric.java
浏览文件 @
8c50098c
...
@@ -98,6 +98,10 @@ class FromGeneric {
...
@@ -98,6 +98,10 @@ class FromGeneric {
this
.
unboxingInvoker
=
computeUnboxingInvoker
(
targetType
,
internalType0
);
this
.
unboxingInvoker
=
computeUnboxingInvoker
(
targetType
,
internalType0
);
}
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/**
/**
* The typed target will be called according to targetType.
* The typed target will be called according to targetType.
* The adapter code will in fact see the raw result from internalType,
* The adapter code will in fact see the raw result from internalType,
...
@@ -112,10 +116,10 @@ class FromGeneric {
...
@@ -112,10 +116,10 @@ class FromGeneric {
assert
(
iret
==
Object
.
class
);
assert
(
iret
==
Object
.
class
);
return
ValueConversions
.
identity
();
return
ValueConversions
.
identity
();
}
else
if
(
wrap
.
primitiveType
()
==
iret
)
{
}
else
if
(
wrap
.
primitiveType
()
==
iret
)
{
return
ValueConversions
.
box
(
wrap
,
false
);
return
ValueConversions
.
box
(
wrap
);
}
else
{
}
else
{
assert
(
tret
==
double
.
class
?
iret
==
long
.
class
:
iret
==
int
.
class
);
assert
(
tret
==
double
.
class
?
iret
==
long
.
class
:
iret
==
int
.
class
);
return
ValueConversions
.
boxRaw
(
wrap
,
false
);
return
ValueConversions
.
boxRaw
(
wrap
);
}
}
}
}
...
@@ -135,7 +139,7 @@ class FromGeneric {
...
@@ -135,7 +139,7 @@ class FromGeneric {
MethodType
fixArgsType
=
internalType
.
changeReturnType
(
targetType
.
returnType
());
MethodType
fixArgsType
=
internalType
.
changeReturnType
(
targetType
.
returnType
());
MethodHandle
fixArgs
=
MethodHandleImpl
.
convertArguments
(
MethodHandle
fixArgs
=
MethodHandleImpl
.
convertArguments
(
invoker
,
Invokers
.
invokerType
(
fixArgsType
),
invoker
,
Invokers
.
invokerType
(
fixArgsType
),
invoker
.
type
(),
null
);
invoker
.
type
(),
0
);
if
(
fixArgs
==
null
)
if
(
fixArgs
==
null
)
throw
new
InternalError
(
"bad fixArgs"
);
throw
new
InternalError
(
"bad fixArgs"
);
// reinterpret the calling sequence as raw:
// reinterpret the calling sequence as raw:
...
@@ -160,7 +164,6 @@ class FromGeneric {
...
@@ -160,7 +164,6 @@ class FromGeneric {
/** Build an adapter of the given generic type, which invokes typedTarget
/** Build an adapter of the given generic type, which invokes typedTarget
* on the incoming arguments, after unboxing as necessary.
* on the incoming arguments, after unboxing as necessary.
* The return value is boxed if necessary.
* The return value is boxed if necessary.
* @param genericType the required type of the result
* @param typedTarget the target
* @param typedTarget the target
* @return an adapter method handle
* @return an adapter method handle
*/
*/
...
@@ -231,7 +234,7 @@ class FromGeneric {
...
@@ -231,7 +234,7 @@ class FromGeneric {
}
}
static
Adapter
buildAdapterFromBytecodes
(
MethodType
internalType
)
{
static
Adapter
buildAdapterFromBytecodes
(
MethodType
internalType
)
{
throw
new
UnsupportedOperationException
(
"NYI
"
);
throw
new
UnsupportedOperationException
(
"NYI
"
+
internalType
);
}
}
/**
/**
...
...
src/share/classes/java/lang/invoke/InvokeGeneric.java
浏览文件 @
8c50098c
...
@@ -29,12 +29,12 @@ import sun.invoke.util.*;
...
@@ -29,12 +29,12 @@ import sun.invoke.util.*;
import
static
java
.
lang
.
invoke
.
MethodHandles
.
Lookup
.
IMPL_LOOKUP
;
import
static
java
.
lang
.
invoke
.
MethodHandles
.
Lookup
.
IMPL_LOOKUP
;
/**
/**
* Adapters which manage
MethodHandle.invokeGeneric
calls.
* Adapters which manage
inexact MethodHandle.invoke
calls.
* The JVM calls one of these when the exact type match fails.
* The JVM calls one of these when the exact type match fails.
* @author jrose
* @author jrose
*/
*/
class
InvokeGeneric
{
class
InvokeGeneric
{
// erased type for the call, which originates from an in
vokeGeneric
site
// erased type for the call, which originates from an in
exact invoke
site
private
final
MethodType
erasedCallerType
;
private
final
MethodType
erasedCallerType
;
// an invoker of type (MT, MH; A...) -> R
// an invoker of type (MT, MH; A...) -> R
private
final
MethodHandle
initialInvoker
;
private
final
MethodHandle
initialInvoker
;
...
@@ -56,7 +56,7 @@ class InvokeGeneric {
...
@@ -56,7 +56,7 @@ class InvokeGeneric {
}
}
/** Return the adapter information for this type's erasure. */
/** Return the adapter information for this type's erasure. */
/*non-public*/
static
MethodHandle
gener
ic
InvokerOf
(
MethodType
erasedCallerType
)
throws
ReflectiveOperationException
{
/*non-public*/
static
MethodHandle
gener
al
InvokerOf
(
MethodType
erasedCallerType
)
throws
ReflectiveOperationException
{
InvokeGeneric
gen
=
new
InvokeGeneric
(
erasedCallerType
);
InvokeGeneric
gen
=
new
InvokeGeneric
(
erasedCallerType
);
return
gen
.
initialInvoker
;
return
gen
.
initialInvoker
;
}
}
...
...
src/share/classes/java/lang/invoke/Invokers.java
浏览文件 @
8c50098c
...
@@ -43,10 +43,10 @@ class Invokers {
...
@@ -43,10 +43,10 @@ class Invokers {
private
/*lazy*/
MethodHandle
erasedInvoker
;
private
/*lazy*/
MethodHandle
erasedInvoker
;
/*lazy*/
MethodHandle
erasedInvokerWithDrops
;
// for InvokeGeneric
/*lazy*/
MethodHandle
erasedInvokerWithDrops
;
// for InvokeGeneric
// gener
ic (untyped)
invoker for the outgoing call
// gener
al
invoker for the outgoing call
private
/*lazy*/
MethodHandle
gener
ic
Invoker
;
private
/*lazy*/
MethodHandle
gener
al
Invoker
;
// gener
ic (untyped)
invoker for the outgoing call; accepts a single Object[]
// gener
al
invoker for the outgoing call; accepts a single Object[]
private
final
/*lazy*/
MethodHandle
[]
spreadInvokers
;
private
final
/*lazy*/
MethodHandle
[]
spreadInvokers
;
// invoker for an unbound callsite
// invoker for an unbound callsite
...
@@ -77,13 +77,13 @@ class Invokers {
...
@@ -77,13 +77,13 @@ class Invokers {
return
invoker
;
return
invoker
;
}
}
/*non-public*/
MethodHandle
gener
ic
Invoker
()
{
/*non-public*/
MethodHandle
gener
al
Invoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker
=
gener
ic
Invoker
;
MethodHandle
invoker
=
gener
al
Invoker
;
if
(
invoker
!=
null
)
return
invoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
gener
ic
Type
=
targetType
.
generic
();
MethodType
gener
al
Type
=
targetType
.
generic
();
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
generic
Type
));
invoker
=
invoker1
.
asType
(
invokerType
(
general
Type
));
gener
ic
Invoker
=
invoker
;
gener
al
Invoker
=
invoker
;
return
invoker
;
return
invoker
;
}
}
...
@@ -93,9 +93,9 @@ class Invokers {
...
@@ -93,9 +93,9 @@ class Invokers {
if
(
invoker
!=
null
)
return
invoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
erasedType
=
targetType
.
erase
();
MethodType
erasedType
=
targetType
.
erase
();
if
(
erasedType
==
targetType
.
generic
())
if
(
erasedType
==
targetType
.
generic
())
invoker
=
gener
ic
Invoker
();
invoker
=
gener
al
Invoker
();
else
else
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
erasedType
));
invoker
=
invoker1
.
asType
(
invokerType
(
erasedType
));
erasedInvoker
=
invoker
;
erasedInvoker
=
invoker
;
return
invoker
;
return
invoker
;
}
}
...
@@ -103,7 +103,7 @@ class Invokers {
...
@@ -103,7 +103,7 @@ class Invokers {
/*non-public*/
MethodHandle
spreadInvoker
(
int
objectArgCount
)
{
/*non-public*/
MethodHandle
spreadInvoker
(
int
objectArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
objectArgCount
];
MethodHandle
vaInvoker
=
spreadInvokers
[
objectArgCount
];
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
MethodHandle
gInvoker
=
gener
ic
Invoker
();
MethodHandle
gInvoker
=
gener
al
Invoker
();
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
return
vaInvoker
;
return
vaInvoker
;
...
...
src/share/classes/java/lang/invoke/MemberName.java
浏览文件 @
8c50098c
...
@@ -525,7 +525,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -525,7 +525,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
/** A factory type for resolving member names with the help of the VM.
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
* TBD: Define access-safe public constructors for this factory.
*/
*/
public
static
class
Factory
{
/*non-public*/
static
class
Factory
{
private
Factory
()
{
}
// singleton pattern
private
Factory
()
{
}
// singleton pattern
static
Factory
INSTANCE
=
new
Factory
();
static
Factory
INSTANCE
=
new
Factory
();
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
8c50098c
...
@@ -26,6 +26,7 @@
...
@@ -26,6 +26,7 @@
package
java.lang.invoke
;
package
java.lang.invoke
;
import
sun.invoke.util.ValueConversions
;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
/**
/**
...
@@ -53,12 +54,12 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -53,12 +54,12 @@ import static java.lang.invoke.MethodHandleStatics.*;
* and the kinds of transformations that apply to it.
* and the kinds of transformations that apply to it.
* <p>
* <p>
* A method handle contains a pair of special invoker methods
* A method handle contains a pair of special invoker methods
* called {@link #invokeExact invokeExact} and {@link #invoke
Generic invokeGeneric
}.
* called {@link #invokeExact invokeExact} and {@link #invoke
invoke
}.
* Both invoker methods provide direct access to the method handle's
* Both invoker methods provide direct access to the method handle's
* underlying method, constructor, field, or other operation,
* underlying method, constructor, field, or other operation,
* as modified by transformations of arguments and return values.
* as modified by transformations of arguments and return values.
* Both invokers accept calls which exactly match the method handle's own type.
* Both invokers accept calls which exactly match the method handle's own type.
* The
{@code invokeGeneric}
invoker also accepts a range of other call types.
* The
plain, inexact
invoker also accepts a range of other call types.
* <p>
* <p>
* Method handles are immutable and have no visible state.
* Method handles are immutable and have no visible state.
* Of course, they can be bound to underlying methods or data which exhibit state.
* Of course, they can be bound to underlying methods or data which exhibit state.
...
@@ -76,7 +77,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -76,7 +77,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* may change from time to time or across implementations from different vendors.
* may change from time to time or across implementations from different vendors.
*
*
* <h3>Method handle compilation</h3>
* <h3>Method handle compilation</h3>
* A Java method call expression naming {@code invokeExact} or {@code invoke
Generic
}
* A Java method call expression naming {@code invokeExact} or {@code invoke}
* can invoke a method handle from Java source code.
* can invoke a method handle from Java source code.
* From the viewpoint of source code, these methods can take any arguments
* From the viewpoint of source code, these methods can take any arguments
* and their result can be cast to any return type.
* and their result can be cast to any return type.
...
@@ -86,7 +87,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -86,7 +87,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* which connects this freedom of invocation directly to the JVM execution stack.
* which connects this freedom of invocation directly to the JVM execution stack.
* <p>
* <p>
* As is usual with virtual methods, source-level calls to {@code invokeExact}
* As is usual with virtual methods, source-level calls to {@code invokeExact}
* and {@code invoke
Generic
} compile to an {@code invokevirtual} instruction.
* and {@code invoke} compile to an {@code invokevirtual} instruction.
* More unusually, the compiler must record the actual argument types,
* More unusually, the compiler must record the actual argument types,
* and may not perform method invocation conversions on the arguments.
* and may not perform method invocation conversions on the arguments.
* Instead, it must push them on the stack according to their own unconverted types.
* Instead, it must push them on the stack according to their own unconverted types.
...
@@ -109,7 +110,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -109,7 +110,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* The first time a {@code invokevirtual} instruction is executed
* The first time a {@code invokevirtual} instruction is executed
* it is linked, by symbolically resolving the names in the instruction
* it is linked, by symbolically resolving the names in the instruction
* and verifying that the method call is statically legal.
* and verifying that the method call is statically legal.
* This is true of calls to {@code invokeExact} and {@code invoke
Generic
}.
* 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 type descriptor emitted by the compiler is checked for
* correct syntax and names it contains are resolved.
* correct syntax and names it contains are resolved.
* Thus, an {@code invokevirtual} instruction which invokes
* Thus, an {@code invokevirtual} instruction which invokes
...
@@ -127,18 +128,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -127,18 +128,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
* In the case of {@code invokeExact}, the type descriptor of the invocation
* In the case of {@code invokeExact}, the type descriptor of the invocation
* (after resolving symbolic type names) must exactly match the method type
* (after resolving symbolic type names) must exactly match the method type
* of the receiving method handle.
* of the receiving method handle.
* In the case of
{@code invokeGeneric
}, the resolved type descriptor
* In the case of
plain, inexact {@code invoke
}, the resolved type descriptor
* must be a valid argument to the receiver's {@link #asType asType} method.
* must be a valid argument to the receiver's {@link #asType asType} method.
* Thus,
{@code invokeGeneric
} is more permissive than {@code invokeExact}.
* Thus,
plain {@code invoke
} is more permissive than {@code invokeExact}.
* <p>
* <p>
* After type matching, a call to {@code invokeExact} directly
* After type matching, a call to {@code invokeExact} directly
* and immediately invoke the method handle's underlying method
* and immediately invoke the method handle's underlying method
* (or other behavior, as the case may be).
* (or other behavior, as the case may be).
* <p>
* <p>
* A call to
{@code invokeGeneric
} works the same as a call to
* 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 type descriptor specified by the caller
* exactly matches the method handle's own type.
* exactly matches the method handle's own type.
* If there is a type mismatch, {@code invoke
Generic
} attempts
* If there is a type mismatch, {@code invoke} attempts
* to adjust the type of the receiving method handle,
* to adjust the type of the receiving method handle,
* as if by a call to {@link #asType asType},
* as if by a call to {@link #asType asType},
* to obtain an exactly invokable method handle {@code M2}.
* to obtain an exactly invokable method handle {@code M2}.
...
@@ -152,7 +153,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -152,7 +153,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* In typical programs, method handle type matching will usually succeed.
* In typical programs, method handle type matching will usually succeed.
* But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
* But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
* either directly (in the case of {@code invokeExact}) or indirectly as if
* either directly (in the case of {@code invokeExact}) or indirectly as if
* by a failed call to {@code asType} (in the case of {@code invoke
Generic
}).
* by a failed call to {@code asType} (in the case of {@code invoke}).
* <p>
* <p>
* Thus, a method type mismatch which might show up as a linkage error
* Thus, a method type mismatch which might show up as a linkage error
* in a statically typed program can show up as
* in a statically typed program can show up as
...
@@ -249,8 +250,8 @@ assert(s.equals("savvy"));
...
@@ -249,8 +250,8 @@ assert(s.equals("savvy"));
mt = MethodType.methodType(java.util.List.class, Object[].class);
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
assert(mh.isVarargsCollector());
x = mh.invoke
Generic
("one", "two");
x = mh.invoke("one", "two");
// invoke
Generic
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert(x.equals(java.util.Arrays.asList("one","two")));
assert(x.equals(java.util.Arrays.asList("one","two")));
// mt is (Object,Object,Object)Object
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mt = MethodType.genericMethodType(3);
...
@@ -269,12 +270,12 @@ mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
...
@@ -269,12 +270,12 @@ mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
* </pre></blockquote>
* </pre></blockquote>
* Each of the above calls to {@code invokeExact} or
{@code invokeGeneric
}
* Each of the above calls to {@code invokeExact} or
plain {@code invoke
}
* generates a single invokevirtual instruction with
* generates a single invokevirtual instruction with
* the type descriptor indicated in the following comment.
* the type descriptor indicated in the following comment.
*
*
* <h3>Exceptions</h3>
* <h3>Exceptions</h3>
* The methods {@code invokeExact} and {@code invoke
Generic
} are declared
* The methods {@code invokeExact} and {@code invoke} are declared
* to throw {@link java.lang.Throwable Throwable},
* to throw {@link java.lang.Throwable Throwable},
* which is to say that there is no static restriction on what a method handle
* which is to say that there is no static restriction on what a method handle
* can throw. Since the JVM does not distinguish between checked
* can throw. Since the JVM does not distinguish between checked
...
@@ -288,7 +289,7 @@ mh.invokeExact(System.out, "Hello, world.");
...
@@ -288,7 +289,7 @@ mh.invokeExact(System.out, "Hello, world.");
*
*
* <h3><a name="sigpoly"></a>Signature polymorphism</h3>
* <h3><a name="sigpoly"></a>Signature polymorphism</h3>
* The unusual compilation and linkage behavior of
* The unusual compilation and linkage behavior of
* {@code invokeExact} and
{@code invokeGeneric
}
* {@code invokeExact} and
plain {@code invoke
}
* is referenced by the term <em>signature polymorphism</em>.
* is referenced by the term <em>signature polymorphism</em>.
* A signature polymorphic method is one which can operate with
* A signature polymorphic method is one which can operate with
* any of a wide range of call signatures and return types.
* any of a wide range of call signatures and return types.
...
@@ -322,7 +323,7 @@ mh.invokeExact(System.out, "Hello, world.");
...
@@ -322,7 +323,7 @@ mh.invokeExact(System.out, "Hello, world.");
* The following methods (and no others) are signature polymorphic:
* The following methods (and no others) are signature polymorphic:
* <ul>
* <ul>
* <li>{@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.lang.invoke.MethodHandle#invoke
Generic MethodHandle.invokeGeneric
}
* <li>{@link java.lang.invoke.MethodHandle#invoke
MethodHandle.invoke
}
* </ul>
* </ul>
* <p>
* <p>
* A signature polymorphic method will be declared with the following properties:
* A signature polymorphic method will be declared with the following properties:
...
@@ -374,24 +375,34 @@ mh.invokeExact(System.out, "Hello, world.");
...
@@ -374,24 +375,34 @@ mh.invokeExact(System.out, "Hello, world.");
* <p>
* <p>
* As a special case,
* As a special case,
* when the Core Reflection API is used to view the signature polymorphic
* when the Core Reflection API is used to view the signature polymorphic
* methods {@code invokeExact} or {@code invokeGeneric} in this class,
* methods {@code invokeExact} or plain {@code invoke} in this class,
* they appear as single, non-polymorphic native methods.
* they appear as ordinary non-polymorphic methods.
* Calls to these native methods do not result in method handle invocations.
* Their reflective appearance, as viewed by
* {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
* is unaffected by their special status in this API.
* For example, {@link java.lang.reflect.Method#getModifiers Method.getModifiers}
* will report exactly those modifier bits required for any similarly
* 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}.
* 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
* Since {@code invokevirtual} instructions can natively
* invoke method handles under any type descriptor, this reflective view conflicts
* invoke method handles under any type descriptor, this reflective view conflicts
* with the normal presentation via bytecodes.
* with the normal presentation of these methods via bytecodes.
* Thus, these two native methods, as viewed by
* Thus, these two native methods, when reflectively viewed by
* {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
* {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
* are placeholders only.
* If invoked via {@link java.lang.reflect.Method#invoke Method.invoke},
* they will throw {@code UnsupportedOperationException}.
* <p>
* <p>
* In order to obtain an invoker method for a particular type descriptor,
* In order to obtain an invoker method for a particular type descriptor,
* use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
* use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
* or {@link java.lang.invoke.MethodHandles#
genericInvoker MethodHandles.genericI
nvoker}.
* or {@link java.lang.invoke.MethodHandles#
invoker MethodHandles.i
nvoker}.
* The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* API is also able to return a method handle
* API is also able to return a method handle
* to call {@code invokeExact} or
{@code invokeGeneric
},
* to call {@code invokeExact} or
plain {@code invoke
},
* for any specified type descriptor .
* for any specified type descriptor .
*
*
* <h3>Interoperation between method handles and Java generics</h3>
* <h3>Interoperation between method handles and Java generics</h3>
...
@@ -523,7 +534,7 @@ public abstract class MethodHandle {
...
@@ -523,7 +534,7 @@ public abstract class MethodHandle {
* adaptations directly on the caller's arguments,
* adaptations directly on the caller's arguments,
* and call the target method handle according to its own exact type.
* and call the target method handle according to its own exact type.
* <p>
* <p>
* The type descriptor at the call site of {@code invoke
Generic
} must
* The type descriptor at the call site of {@code invoke} must
* be a valid argument to the receivers {@code asType} method.
* be a valid argument to the receivers {@code asType} method.
* In particular, the caller must specify the same argument arity
* In particular, the caller must specify the same argument arity
* as the callee's type,
* as the callee's type,
...
@@ -539,11 +550,18 @@ public abstract class MethodHandle {
...
@@ -539,11 +550,18 @@ public abstract class MethodHandle {
* @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
* @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
* @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
;
public
final
native
@PolymorphicSignature
Object
invokeGeneric
(
Object
...
args
)
throws
Throwable
;
/**
/**
* Performs a varargs invocation, passing the arguments in the given array
* Performs a varargs invocation, passing the arguments in the given array
* to the method handle, as if via
{@link #invokeGeneric invokeGeneric
} from a call site
* 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
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
* of the argument array.
* <p>
* <p>
...
@@ -553,7 +571,7 @@ public abstract class MethodHandle {
...
@@ -553,7 +571,7 @@ public abstract class MethodHandle {
* <ul>
* <ul>
* <li>Determine the length of the argument array as {@code N}.
* <li>Determine the length of the argument array as {@code N}.
* For a null reference, {@code N=0}. </li>
* For a null reference, {@code N=0}. </li>
* <li>Determine the gener
ic
type {@code TN} of {@code N} arguments as
* <li>Determine the gener
al
type {@code TN} of {@code N} arguments as
* as {@code TN=MethodType.genericMethodType(N)}.</li>
* as {@code TN=MethodType.genericMethodType(N)}.</li>
* <li>Force the original target method handle {@code MH0} to the
* <li>Force the original target method handle {@code MH0} to the
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
...
@@ -580,7 +598,7 @@ public abstract class MethodHandle {
...
@@ -580,7 +598,7 @@ public abstract class MethodHandle {
* Object result = invoker.invokeExact(this, arguments);
* Object result = invoker.invokeExact(this, arguments);
* </pre></blockquote>
* </pre></blockquote>
* <p>
* <p>
* Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke
Generic
},
* Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
* {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
* {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
* It can therefore be used as a bridge between native or reflective code and method handles.
* It can therefore be used as a bridge between native or reflective code and method handles.
*
*
...
@@ -595,11 +613,11 @@ public abstract class MethodHandle {
...
@@ -595,11 +613,11 @@ public abstract class MethodHandle {
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
MethodType
type
=
type
();
MethodType
type
=
type
();
if
(
type
.
parameterCount
()
!=
argc
)
{
if
(
type
.
parameterCount
()
!=
argc
)
{
// simulate invoke
Generic
// simulate invoke
return
asType
(
MethodType
.
genericMethodType
(
argc
)).
invokeWithArguments
(
arguments
);
return
asType
(
MethodType
.
genericMethodType
(
argc
)).
invokeWithArguments
(
arguments
);
}
}
if
(
argc
<=
10
)
{
if
(
argc
<=
10
)
{
MethodHandle
invoker
=
type
.
invokers
().
gener
ic
Invoker
();
MethodHandle
invoker
=
type
.
invokers
().
gener
al
Invoker
();
switch
(
argc
)
{
switch
(
argc
)
{
case
0
:
return
invoker
.
invokeExact
(
this
);
case
0
:
return
invoker
.
invokeExact
(
this
);
case
1
:
return
invoker
.
invokeExact
(
this
,
case
1
:
return
invoker
.
invokeExact
(
this
,
...
@@ -644,7 +662,7 @@ public abstract class MethodHandle {
...
@@ -644,7 +662,7 @@ public abstract class MethodHandle {
/**
/**
* Performs a varargs invocation, passing the arguments in the given array
* Performs a varargs invocation, passing the arguments in the given array
* to the method handle, as if via
{@link #invokeGeneric invokeGeneric
} from a call site
* 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
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
* of the argument array.
* <p>
* <p>
...
@@ -672,9 +690,9 @@ public abstract class MethodHandle {
...
@@ -672,9 +690,9 @@ public abstract class MethodHandle {
* If the original type and new type are equal, returns {@code this}.
* If the original type and new type are equal, returns {@code this}.
* <p>
* <p>
* This method provides the crucial behavioral difference between
* This method provides the crucial behavioral difference between
* {@link #invokeExact invokeExact} and
{@link #invokeGeneric invokeGeneric
}. The two methods
* {@link #invokeExact invokeExact} and
plain, inexact {@link #invoke invoke
}. The two methods
* perform the same steps when the caller's type descriptor is identical
* perform the same steps when the caller's type descriptor is identical
* with the callee's, but when the types differ,
{@link #invokeGeneric invokeGeneric
}
* with the callee's, but when the types differ,
plain {@link #invoke invoke
}
* also calls {@code asType} (or some internal equivalent) in order
* also calls {@code asType} (or some internal equivalent) in order
* to match up the caller's and callee's types.
* to match up the caller's and callee's types.
* <p>
* <p>
...
@@ -689,6 +707,9 @@ public abstract class MethodHandle {
...
@@ -689,6 +707,9 @@ public abstract class MethodHandle {
* @see MethodHandles#convertArguments
* @see MethodHandles#convertArguments
*/
*/
public
MethodHandle
asType
(
MethodType
newType
)
{
public
MethodHandle
asType
(
MethodType
newType
)
{
if
(!
type
.
isConvertibleTo
(
newType
))
{
throw
new
WrongMethodTypeException
(
"cannot convert "
+
type
+
" to "
+
newType
);
}
return
MethodHandles
.
convertArguments
(
this
,
newType
);
return
MethodHandles
.
convertArguments
(
this
,
newType
);
}
}
...
@@ -731,13 +752,9 @@ public abstract class MethodHandle {
...
@@ -731,13 +752,9 @@ public abstract class MethodHandle {
public
MethodHandle
asSpreader
(
Class
<?>
arrayType
,
int
arrayLength
)
{
public
MethodHandle
asSpreader
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
MethodType
oldType
=
type
();
int
nargs
=
type
().
parameterCount
();
int
nargs
=
oldType
.
parameterCount
();
if
(
nargs
<
arrayLength
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
if
(
nargs
<
arrayLength
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
int
keepPosArgs
=
nargs
-
arrayLength
;
return
MethodHandleImpl
.
spreadArguments
(
this
,
arrayType
,
arrayLength
);
MethodType
newType
=
oldType
.
dropParameterTypes
(
keepPosArgs
,
nargs
);
newType
=
newType
.
insertParameterTypes
(
keepPosArgs
,
arrayType
);
return
MethodHandles
.
spreadArguments
(
this
,
newType
);
}
}
/**
/**
...
@@ -780,15 +797,18 @@ public abstract class MethodHandle {
...
@@ -780,15 +797,18 @@ public abstract class MethodHandle {
* @see #asVarargsCollector
* @see #asVarargsCollector
*/
*/
public
MethodHandle
asCollector
(
Class
<?>
arrayType
,
int
arrayLength
)
{
public
MethodHandle
asCollector
(
Class
<?>
arrayType
,
int
arrayLength
)
{
asCollectorChecks
(
arrayType
,
arrayLength
);
MethodHandle
collector
=
ValueConversions
.
varargsArray
(
arrayType
,
arrayLength
);
return
MethodHandleImpl
.
collectArguments
(
this
,
type
.
parameterCount
()-
1
,
collector
);
}
private
void
asCollectorChecks
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
if
(
arrayElement
==
null
)
MethodType
oldType
=
type
();
throw
newIllegalArgumentException
(
"not an array type"
,
arrayType
);
int
nargs
=
oldType
.
parameterCount
();
int
nargs
=
type
().
parameterCount
();
if
(
nargs
==
0
)
throw
newIllegalArgumentException
(
"no trailing argument"
);
if
(
nargs
==
0
||
!
type
().
parameterType
(
nargs
-
1
).
isAssignableFrom
(
arrayType
))
MethodType
newType
=
oldType
.
dropParameterTypes
(
nargs
-
1
,
nargs
);
throw
newIllegalArgumentException
(
"array type not assignable to trailing argument"
,
this
,
arrayType
);
newType
=
newType
.
insertParameterTypes
(
nargs
-
1
,
java
.
util
.
Collections
.<
Class
<?>>
nCopies
(
arrayLength
,
arrayElement
));
return
MethodHandles
.
collectArguments
(
this
,
newType
);
}
}
/**
/**
...
@@ -798,7 +818,7 @@ public abstract class MethodHandle {
...
@@ -798,7 +818,7 @@ public abstract class MethodHandle {
* <p>
* <p>
* The type and behavior of the adapter will be the same as
* The type and behavior of the adapter will be the same as
* the type and behavior of the target, except that certain
* the type and behavior of the target, except that certain
* {@code invoke
Generic
} and {@code asType} requests can lead to
* {@code invoke} and {@code asType} requests can lead to
* trailing positional arguments being collected into target's
* trailing positional arguments being collected into target's
* trailing parameter.
* trailing parameter.
* Also, the last parameter type of the adapter will be
* Also, the last parameter type of the adapter will be
...
@@ -812,17 +832,17 @@ public abstract class MethodHandle {
...
@@ -812,17 +832,17 @@ public abstract class MethodHandle {
* since it accepts a whole array of indeterminate length,
* since it accepts a whole array of indeterminate length,
* rather than a fixed number of arguments.)
* rather than a fixed number of arguments.)
* <p>
* <p>
* When called with
{@link #invokeGeneric invokeGeneric
}, if the caller
* When called with
plain, inexact {@link #invoke invoke
}, if the caller
* type is the same as the adapter, the adapter invokes the target as with
* type is the same as the adapter, the adapter invokes the target as with
* {@code invokeExact}.
* {@code invokeExact}.
* (This is the normal behavior for {@code invoke
Generic
} when types match.)
* (This is the normal behavior for {@code invoke} when types match.)
* <p>
* <p>
* Otherwise, if the caller and adapter arity are the same, and the
* Otherwise, if the caller and adapter arity are the same, and the
* trailing parameter type of the caller is a reference type identical to
* trailing parameter type of the caller is a reference type identical to
* or assignable to the trailing parameter type of the adapter,
* or assignable to the trailing parameter type of the adapter,
* the arguments and return values are converted pairwise,
* the arguments and return values are converted pairwise,
* as if by {@link MethodHandles#convertArguments convertArguments}.
* as if by {@link MethodHandles#convertArguments convertArguments}.
* (This is also normal behavior for {@code invoke
Generic
} in such a case.)
* (This is also normal behavior for {@code invoke} in such a case.)
* <p>
* <p>
* Otherwise, the arities differ, or the adapter's trailing parameter
* Otherwise, the arities differ, or the adapter's trailing parameter
* type is not assignable from the corresponding caller type.
* type is not assignable from the corresponding caller type.
...
@@ -838,7 +858,7 @@ public abstract class MethodHandle {
...
@@ -838,7 +858,7 @@ public abstract class MethodHandle {
* where {@code N} is the arity of the target.
* where {@code N} is the arity of the target.
* Also, there must exist conversions from the incoming arguments
* Also, there must exist conversions from the incoming arguments
* to the target's arguments.
* to the target's arguments.
* As with other uses of
{@code invokeGeneric
}, if these basic
* As with other uses of
plain {@code invoke
}, if these basic
* requirements are not fulfilled, a {@code WrongMethodTypeException}
* requirements are not fulfilled, a {@code WrongMethodTypeException}
* may be thrown.
* may be thrown.
* <p>
* <p>
...
@@ -856,7 +876,7 @@ public abstract class MethodHandle {
...
@@ -856,7 +876,7 @@ public abstract class MethodHandle {
* <p>
* <p>
* The behavior of {@link #asType asType} is also specialized for
* The behavior of {@link #asType asType} is also specialized for
* variable arity adapters, to maintain the invariant that
* variable arity adapters, to maintain the invariant that
*
{@code invokeGeneric
} is always equivalent to an {@code asType}
*
plain, inexact {@code invoke
} is always equivalent to an {@code asType}
* call to adjust the target type, followed by {@code invokeExact}.
* call to adjust the target type, followed by {@code invokeExact}.
* Therefore, a variable arity adapter responds
* Therefore, a variable arity adapter responds
* to an {@code asType} request by building a fixed arity collector,
* to an {@code asType} request by building a fixed arity collector,
...
@@ -893,12 +913,12 @@ public abstract class MethodHandle {
...
@@ -893,12 +913,12 @@ public abstract class MethodHandle {
MethodHandle asList = publicLookup()
MethodHandle asList = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
.asVarargsCollector(Object[].class);
assertEquals("[]", asList.invoke
Generic
().toString());
assertEquals("[]", asList.invoke().toString());
assertEquals("[1]", asList.invoke
Generic
(1).toString());
assertEquals("[1]", asList.invoke(1).toString());
assertEquals("[two, too]", asList.invoke
Generic
("two", "too").toString());
assertEquals("[two, too]", asList.invoke("two", "too").toString());
Object[] argv = { "three", "thee", "tee" };
Object[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asList.invoke
Generic
(argv).toString());
assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
List ls = (List) asList.invoke
Generic
((Object)argv);
List ls = (List) asList.invoke((Object)argv);
assertEquals(1, ls.size());
assertEquals(1, ls.size());
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
* </pre></blockquote>
* </pre></blockquote>
...
@@ -926,9 +946,9 @@ MethodHandle vamh = publicLookup()
...
@@ -926,9 +946,9 @@ MethodHandle vamh = publicLookup()
.asVarargsCollector(Object[].class);
.asVarargsCollector(Object[].class);
MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
assert(vamh.type().equals(mh.type()));
assert(vamh.type().equals(mh.type()));
assertEquals("[1, 2, 3]", vamh.invoke
Generic
(1,2,3).toString());
assertEquals("[1, 2, 3]", vamh.invoke(1,2,3).toString());
boolean failed = false;
boolean failed = false;
try { mh.invoke
Generic
(1,2,3); }
try { mh.invoke(1,2,3); }
catch (WrongMethodTypeException ex) { failed = true; }
catch (WrongMethodTypeException ex) { failed = true; }
assert(failed);
assert(failed);
* </pre></blockquote>
* </pre></blockquote>
...
@@ -960,7 +980,7 @@ assert(failed);
...
@@ -960,7 +980,7 @@ assert(failed);
* <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
* <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
* which resolves to a variable arity Java method or constructor
* which resolves to a variable arity Java method or constructor
* </ul>
* </ul>
* @return true if this method handle accepts more than one arity of
{@code invokeGeneric
} calls
* @return true if this method handle accepts more than one arity of
plain, inexact {@code invoke
} calls
* @see #asVarargsCollector
* @see #asVarargsCollector
*/
*/
public
boolean
isVarargsCollector
()
{
public
boolean
isVarargsCollector
()
{
...
...
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
8c50098c
...
@@ -121,11 +121,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -121,11 +121,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
nargs
<
INVOKES
.
length
)
{
if
(
nargs
<
INVOKES
.
length
)
{
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodType
conType
=
CON_TYPES
[
nargs
];
MethodType
conType
=
CON_TYPES
[
nargs
];
MethodHandle
gcon
=
convertArguments
(
rawConstructor
,
conType
,
rawConType
,
null
);
MethodHandle
gcon
=
convertArguments
(
rawConstructor
,
conType
,
rawConType
,
0
);
if
(
gcon
==
null
)
return
null
;
if
(
gcon
==
null
)
return
null
;
MethodHandle
galloc
=
new
AllocateObject
(
invoke
,
allocateClass
,
gcon
);
MethodHandle
galloc
=
new
AllocateObject
(
invoke
,
allocateClass
,
gcon
);
assert
(
galloc
.
type
()
==
newType
.
generic
());
assert
(
galloc
.
type
()
==
newType
.
generic
());
return
convertArguments
(
galloc
,
newType
,
galloc
.
type
(),
null
);
return
convertArguments
(
galloc
,
newType
,
galloc
.
type
(),
0
);
}
else
{
}
else
{
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
conType
=
CON_TYPES
[
nargs
];
MethodType
conType
=
CON_TYPES
[
nargs
];
...
@@ -256,8 +256,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -256,8 +256,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
FieldAccessor
.
ahandle
(
arrayClass
,
true
)
FieldAccessor
.
ahandle
(
arrayClass
,
true
)
};
};
if
(
mhs
[
0
].
type
().
parameterType
(
0
)
==
Class
.
class
)
{
if
(
mhs
[
0
].
type
().
parameterType
(
0
)
==
Class
.
class
)
{
mhs
[
0
]
=
MethodHandles
.
insertArguments
(
mhs
[
0
],
0
,
elemClass
);
mhs
[
0
]
=
mhs
[
0
].
bindTo
(
elemClass
);
mhs
[
1
]
=
MethodHandles
.
insertArguments
(
mhs
[
1
],
0
,
elemClass
);
mhs
[
1
]
=
mhs
[
1
].
bindTo
(
elemClass
);
}
}
synchronized
(
FieldAccessor
.
ARRAY_CACHE
)
{}
// memory barrier
synchronized
(
FieldAccessor
.
ARRAY_CACHE
)
{}
// memory barrier
FieldAccessor
.
ARRAY_CACHE
.
put
(
elemClass
,
mhs
);
FieldAccessor
.
ARRAY_CACHE
.
put
(
elemClass
,
mhs
);
...
@@ -372,7 +372,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -372,7 +372,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
evclass
!=
vclass
||
(!
isStatic
&&
ecclass
!=
cclass
))
{
if
(
evclass
!=
vclass
||
(!
isStatic
&&
ecclass
!=
cclass
))
{
MethodType
strongType
=
FieldAccessor
.
ftype
(
cclass
,
vclass
,
isSetter
,
isStatic
);
MethodType
strongType
=
FieldAccessor
.
ftype
(
cclass
,
vclass
,
isSetter
,
isStatic
);
strongType
=
strongType
.
insertParameterTypes
(
0
,
FieldAccessor
.
class
);
strongType
=
strongType
.
insertParameterTypes
(
0
,
FieldAccessor
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
strongType
);
mh
=
convertArguments
(
mh
,
strongType
,
0
);
}
}
return
mh
;
return
mh
;
}
}
...
@@ -439,8 +439,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -439,8 +439,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
}
if
(
caclass
!=
null
)
{
if
(
caclass
!=
null
)
{
MethodType
strongType
=
FieldAccessor
.
atype
(
caclass
,
isSetter
);
MethodType
strongType
=
FieldAccessor
.
atype
(
caclass
,
isSetter
);
mh
=
MethodHandles
.
insertArguments
(
mh
,
0
,
caclass
);
mh
=
mh
.
bindTo
(
caclass
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
strongType
);
mh
=
convertArguments
(
mh
,
strongType
,
0
);
}
}
return
mh
;
return
mh
;
}
}
...
@@ -465,7 +465,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -465,7 +465,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
dmh
.
type
().
parameterType
(
0
).
isAssignableFrom
(
receiver
.
getClass
()))
{
dmh
.
type
().
parameterType
(
0
).
isAssignableFrom
(
receiver
.
getClass
()))
{
MethodHandle
bmh
=
new
BoundMethodHandle
(
dmh
,
receiver
,
0
);
MethodHandle
bmh
=
new
BoundMethodHandle
(
dmh
,
receiver
,
0
);
MethodType
newType
=
target
.
type
().
dropParameterTypes
(
0
,
1
);
MethodType
newType
=
target
.
type
().
dropParameterTypes
(
0
,
1
);
return
convertArguments
(
bmh
,
newType
,
bmh
.
type
(),
null
);
return
convertArguments
(
bmh
,
newType
,
bmh
.
type
(),
0
);
}
}
}
}
}
}
...
@@ -486,301 +486,378 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -486,301 +486,378 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return
new
BoundMethodHandle
(
target
,
receiver
,
argnum
);
return
new
BoundMethodHandle
(
target
,
receiver
,
argnum
);
}
}
static
MethodHandle
convert
Arguments
(
MethodHandle
target
,
static
MethodHandle
permute
Arguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
newType
,
MethodType
oldType
,
MethodType
oldType
,
int
[]
permutationOrNull
)
{
int
[]
permutationOrNull
)
{
assert
(
oldType
.
parameterCount
()
==
target
.
type
().
parameterCount
());
assert
(
oldType
.
parameterCount
()
==
target
.
type
().
parameterCount
());
if
(
permutationOrNull
!=
null
)
{
int
outargs
=
oldType
.
parameterCount
(),
inargs
=
newType
.
parameterCount
();
int
outargs
=
oldType
.
parameterCount
(),
inargs
=
newType
.
parameterCount
();
if
(
permutationOrNull
.
length
!=
outargs
)
if
(
permutationOrNull
.
length
!=
outargs
)
throw
newIllegalArgumentException
(
"wrong number of arguments in permutation"
);
throw
newIllegalArgumentException
(
"wrong number of arguments in permutation"
);
// Make the individual outgoing argument types match up first.
// Make the individual outgoing argument types match up first.
Class
<?>[]
callTypeArgs
=
new
Class
<?>[
outargs
];
Class
<?>[]
callTypeArgs
=
new
Class
<?>[
outargs
];
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
callTypeArgs
[
i
]
=
newType
.
parameterType
(
permutationOrNull
[
i
]);
callTypeArgs
[
i
]
=
newType
.
parameterType
(
permutationOrNull
[
i
]);
MethodType
callType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
callTypeArgs
);
MethodType
callType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
callTypeArgs
);
target
=
convertArguments
(
target
,
callType
,
oldType
,
0
);
target
=
convertArguments
(
target
,
callType
,
oldType
,
null
);
assert
(
target
!=
null
);
assert
(
target
!=
null
);
oldType
=
target
.
type
();
oldType
=
target
.
type
();
List
<
Integer
>
goal
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
goal
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
state
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
state
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
drops
=
new
ArrayList
<
Integer
>();
// not tokens
List
<
Integer
>
drops
=
new
ArrayList
<
Integer
>();
// not tokens
List
<
Integer
>
dups
=
new
ArrayList
<
Integer
>();
// not tokens
List
<
Integer
>
dups
=
new
ArrayList
<
Integer
>();
// not tokens
final
int
TOKEN
=
10
;
// to mark items which are symbolic only
final
int
TOKEN
=
10
;
// to mark items which are symbolic only
// state represents the argument values coming into target
// state represents the argument values coming into target
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
{
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
{
state
.
add
(
permutationOrNull
[
i
]
*
TOKEN
);
state
.
add
(
permutationOrNull
[
i
]
*
TOKEN
);
}
// goal represents the desired state
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
if
(
state
.
contains
(
i
*
TOKEN
))
{
goal
.
add
(
i
*
TOKEN
);
}
else
{
// adapter must initially drop all unused arguments
drops
.
add
(
i
);
}
}
// goal represents the desired state
}
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
// detect duplications
if
(
state
.
contains
(
i
*
TOKEN
))
{
while
(
state
.
size
()
>
goal
.
size
())
{
goal
.
add
(
i
*
TOKEN
);
for
(
int
i2
=
0
;
i2
<
state
.
size
();
i2
++)
{
}
else
{
int
arg1
=
state
.
get
(
i2
);
// adapter must initially drop all unused arguments
int
i1
=
state
.
indexOf
(
arg1
);
drops
.
add
(
i
);
if
(
i1
!=
i2
)
{
// found duplicate occurrence at i2
int
arg2
=
(
inargs
++)
*
TOKEN
;
state
.
set
(
i2
,
arg2
);
dups
.
add
(
goal
.
indexOf
(
arg1
));
goal
.
add
(
arg2
);
}
}
}
}
// detect duplications
}
while
(
state
.
size
()
>
goal
.
size
())
{
assert
(
state
.
size
()
==
goal
.
size
());
for
(
int
i2
=
0
;
i2
<
state
.
size
();
i2
++)
{
int
size
=
goal
.
size
();
int
arg1
=
state
.
get
(
i2
);
while
(!
state
.
equals
(
goal
))
{
int
i1
=
state
.
indexOf
(
arg1
);
// Look for a maximal sequence of adjacent misplaced arguments,
if
(
i1
!=
i2
)
{
// and try to rotate them into place.
// found duplicate occurrence at i2
int
bestRotArg
=
-
10
*
TOKEN
,
bestRotLen
=
0
;
int
arg2
=
(
inargs
++)
*
TOKEN
;
int
thisRotArg
=
-
10
*
TOKEN
,
thisRotLen
=
0
;
state
.
set
(
i2
,
arg2
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
dups
.
add
(
goal
.
indexOf
(
arg1
));
int
arg
=
state
.
get
(
i
);
goal
.
add
(
arg2
);
// Does this argument match the current run?
if
(
arg
==
thisRotArg
+
TOKEN
)
{
thisRotArg
=
arg
;
thisRotLen
+=
1
;
if
(
bestRotLen
<
thisRotLen
)
{
bestRotLen
=
thisRotLen
;
bestRotArg
=
thisRotArg
;
}
}
}
}
else
{
}
// The old sequence (if any) stops here.
assert
(
state
.
size
()
==
goal
.
size
());
thisRotLen
=
0
;
int
size
=
goal
.
size
();
thisRotArg
=
-
10
*
TOKEN
;
while
(!
state
.
equals
(
goal
))
{
// But maybe a new one starts here also.
// Look for a maximal sequence of adjacent misplaced arguments,
int
wantArg
=
goal
.
get
(
i
);
// and try to rotate them into place.
final
int
MAX_ARG_ROTATION
=
AdapterMethodHandle
.
MAX_ARG_ROTATION
;
int
bestRotArg
=
-
10
*
TOKEN
,
bestRotLen
=
0
;
if
(
arg
!=
wantArg
&&
int
thisRotArg
=
-
10
*
TOKEN
,
thisRotLen
=
0
;
arg
>=
wantArg
-
TOKEN
*
MAX_ARG_ROTATION
&&
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
arg
<=
wantArg
+
TOKEN
*
MAX_ARG_ROTATION
)
{
int
arg
=
state
.
get
(
i
);
// Does this argument match the current run?
if
(
arg
==
thisRotArg
+
TOKEN
)
{
thisRotArg
=
arg
;
thisRotArg
=
arg
;
thisRotLen
+=
1
;
thisRotLen
=
1
;
if
(
bestRotLen
<
thisRotLen
)
{
bestRotLen
=
thisRotLen
;
bestRotArg
=
thisRotArg
;
}
}
else
{
// The old sequence (if any) stops here.
thisRotLen
=
0
;
thisRotArg
=
-
10
*
TOKEN
;
// But maybe a new one starts here also.
int
wantArg
=
goal
.
get
(
i
);
final
int
MAX_ARG_ROTATION
=
AdapterMethodHandle
.
MAX_ARG_ROTATION
;
if
(
arg
!=
wantArg
&&
arg
>=
wantArg
-
TOKEN
*
MAX_ARG_ROTATION
&&
arg
<=
wantArg
+
TOKEN
*
MAX_ARG_ROTATION
)
{
thisRotArg
=
arg
;
thisRotLen
=
1
;
}
}
}
}
}
if
(
bestRotLen
>=
2
)
{
}
// Do a rotation if it can improve argument positioning
if
(
bestRotLen
>=
2
)
{
// by at least 2 arguments. This is not always optimal,
// Do a rotation if it can improve argument positioning
// but it seems to catch common cases.
// by at least 2 arguments. This is not always optimal,
int
dstEnd
=
state
.
indexOf
(
bestRotArg
);
// but it seems to catch common cases.
int
srcEnd
=
goal
.
indexOf
(
bestRotArg
);
int
dstEnd
=
state
.
indexOf
(
bestRotArg
);
int
rotBy
=
dstEnd
-
srcEnd
;
int
srcEnd
=
goal
.
indexOf
(
bestRotArg
);
int
dstBeg
=
dstEnd
-
(
bestRotLen
-
1
);
int
rotBy
=
dstEnd
-
srcEnd
;
int
srcBeg
=
srcEnd
-
(
bestRotLen
-
1
);
int
dstBeg
=
dstEnd
-
(
bestRotLen
-
1
);
assert
((
dstEnd
|
dstBeg
|
srcEnd
|
srcBeg
)
>=
0
);
// no negs
int
srcBeg
=
srcEnd
-
(
bestRotLen
-
1
);
// Make a span which covers both source and destination.
assert
((
dstEnd
|
dstBeg
|
srcEnd
|
srcBeg
)
>=
0
);
// no negs
int
rotBeg
=
Math
.
min
(
dstBeg
,
srcBeg
);
// Make a span which covers both source and destination.
int
rotEnd
=
Math
.
max
(
dstEnd
,
srcEnd
);
int
rotBeg
=
Math
.
min
(
dstBeg
,
srcBeg
);
int
score
=
0
;
int
rotEnd
=
Math
.
max
(
dstEnd
,
srcEnd
);
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
int
score
=
0
;
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
score
+=
1
;
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
}
score
+=
1
;
List
<
Integer
>
rotSpan
=
state
.
subList
(
rotBeg
,
rotEnd
+
1
);
Collections
.
rotate
(
rotSpan
,
-
rotBy
);
// reverse direction
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
score
-=
1
;
}
if
(
score
>=
2
)
{
// Improved at least two argument positions. Do it.
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
Collections
.
rotate
(
ptypes
.
subList
(
rotBeg
,
rotEnd
+
1
),
-
rotBy
);
MethodType
rotType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
MethodHandle
nextTarget
=
AdapterMethodHandle
.
makeRotateArguments
(
rotType
,
target
,
rotBeg
,
rotSpan
.
size
(),
rotBy
);
if
(
nextTarget
!=
null
)
{
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
target
=
nextTarget
;
oldType
=
rotType
;
continue
;
}
}
// Else de-rotate, and drop through to the swap-fest.
Collections
.
rotate
(
rotSpan
,
rotBy
);
}
}
List
<
Integer
>
rotSpan
=
state
.
subList
(
rotBeg
,
rotEnd
+
1
);
// Now swap like the wind!
Collections
.
rotate
(
rotSpan
,
-
rotBy
);
// reverse direction
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
// What argument do I want here?
score
-=
1
;
int
arg
=
goal
.
get
(
i
);
}
if
(
arg
!=
state
.
get
(
i
))
{
if
(
score
>=
2
)
{
// Where is it now?
// Improved at least two argument positions. Do it.
int
j
=
state
.
indexOf
(
arg
);
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
Collections
.
swap
(
ptypes
,
i
,
j
);
Collections
.
rotate
(
ptypes
.
subList
(
rotBeg
,
rotEnd
+
1
),
-
rotBy
);
MethodType
swapType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
MethodType
rotType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeSwapArguments
(
swapType
,
target
,
i
,
j
);
MethodHandle
nextTarget
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot swap"
);
=
AdapterMethodHandle
.
makeRotateArguments
(
rotType
,
target
,
assert
(
target
.
type
()
==
swapType
);
rotBeg
,
rotSpan
.
size
(),
rotBy
);
oldType
=
swapType
;
if
(
nextTarget
!=
null
)
{
Collections
.
swap
(
state
,
i
,
j
);
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
target
=
nextTarget
;
oldType
=
rotType
;
continue
;
}
}
}
}
//
One pass of swapping must finish the job
.
//
Else de-rotate, and drop through to the swap-fest
.
assert
(
state
.
equals
(
goal
)
);
Collections
.
rotate
(
rotSpan
,
rotBy
);
}
}
while
(!
dups
.
isEmpty
())
{
// Grab a contiguous trailing sequence of dups.
// Now swap like the wind!
int
grab
=
dups
.
size
()
-
1
;
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
int
dupArgPos
=
dups
.
get
(
grab
),
dupArgCount
=
1
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
while
(
grab
-
1
>=
0
)
{
// What argument do I want here?
int
dup0
=
dups
.
get
(
grab
-
1
);
int
arg
=
goal
.
get
(
i
);
if
(
dup0
!=
dupArgPos
-
1
)
break
;
if
(
arg
!=
state
.
get
(
i
))
{
dupArgPos
-=
1
;
// Where is it now?
dupArgCount
+=
1
;
int
j
=
state
.
indexOf
(
arg
);
grab
-=
1
;
Collections
.
swap
(
ptypes
,
i
,
j
);
MethodType
swapType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeSwapArguments
(
swapType
,
target
,
i
,
j
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot swap"
);
assert
(
target
.
type
()
==
swapType
);
oldType
=
swapType
;
Collections
.
swap
(
state
,
i
,
j
);
}
}
//if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
dups
.
subList
(
grab
,
dups
.
size
()).
clear
();
// In the new target type drop that many args from the tail:
List
<
Class
<?>>
ptypes
=
oldType
.
parameterList
();
ptypes
=
ptypes
.
subList
(
0
,
ptypes
.
size
()
-
dupArgCount
);
MethodType
dupType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeDupArguments
(
dupType
,
target
,
dupArgPos
,
dupArgCount
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot dup"
);
oldType
=
target
.
type
();
}
}
while
(!
drops
.
isEmpty
())
{
// One pass of swapping must finish the job.
// Grab a contiguous initial sequence of drops.
assert
(
state
.
equals
(
goal
));
int
dropArgPos
=
drops
.
get
(
0
),
dropArgCount
=
1
;
}
while
(
dropArgCount
<
drops
.
size
())
{
while
(!
dups
.
isEmpty
())
{
int
drop1
=
drops
.
get
(
dropArgCount
);
// Grab a contiguous trailing sequence of dups.
if
(
drop1
!=
dropArgPos
+
dropArgCount
)
break
;
int
grab
=
dups
.
size
()
-
1
;
dropArgCount
+=
1
;
int
dupArgPos
=
dups
.
get
(
grab
),
dupArgCount
=
1
;
}
while
(
grab
-
1
>=
0
)
{
//if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount));
int
dup0
=
dups
.
get
(
grab
-
1
);
drops
.
subList
(
0
,
dropArgCount
).
clear
();
if
(
dup0
!=
dupArgPos
-
1
)
break
;
List
<
Class
<?>>
dropTypes
=
newType
.
parameterList
()
dupArgPos
-=
1
;
.
subList
(
dropArgPos
,
dropArgPos
+
dropArgCount
);
dupArgCount
+=
1
;
MethodType
dropType
=
oldType
.
insertParameterTypes
(
dropArgPos
,
dropTypes
);
grab
-=
1
;
target
=
AdapterMethodHandle
.
makeDropArguments
(
dropType
,
target
,
dropArgPos
,
dropArgCount
);
}
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot drop"
);
//if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
oldType
=
target
.
type
();
dups
.
subList
(
grab
,
dups
.
size
()).
clear
();
// In the new target type drop that many args from the tail:
List
<
Class
<?>>
ptypes
=
oldType
.
parameterList
();
ptypes
=
ptypes
.
subList
(
0
,
ptypes
.
size
()
-
dupArgCount
);
MethodType
dupType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeDupArguments
(
dupType
,
target
,
dupArgPos
,
dupArgCount
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot dup"
);
oldType
=
target
.
type
();
}
while
(!
drops
.
isEmpty
())
{
// Grab a contiguous initial sequence of drops.
int
dropArgPos
=
drops
.
get
(
0
),
dropArgCount
=
1
;
while
(
dropArgCount
<
drops
.
size
())
{
int
drop1
=
drops
.
get
(
dropArgCount
);
if
(
drop1
!=
dropArgPos
+
dropArgCount
)
break
;
dropArgCount
+=
1
;
}
}
//if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount));
drops
.
subList
(
0
,
dropArgCount
).
clear
();
List
<
Class
<?>>
dropTypes
=
newType
.
parameterList
()
.
subList
(
dropArgPos
,
dropArgPos
+
dropArgCount
);
MethodType
dropType
=
oldType
.
insertParameterTypes
(
dropArgPos
,
dropTypes
);
target
=
AdapterMethodHandle
.
makeDropArguments
(
dropType
,
target
,
dropArgPos
,
dropArgCount
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot drop"
);
oldType
=
target
.
type
();
}
return
convertArguments
(
target
,
newType
,
oldType
,
0
);
}
/*non-public*/
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
,
int
level
)
{
MethodType
oldType
=
target
.
type
();
if
(
oldType
.
equals
(
newType
))
return
target
;
assert
(
level
>
1
||
oldType
.
isConvertibleTo
(
newType
));
MethodHandle
retFilter
=
null
;
Class
<?>
oldRT
=
oldType
.
returnType
();
Class
<?>
newRT
=
newType
.
returnType
();
if
(!
VerifyType
.
isNullConversion
(
oldRT
,
newRT
))
{
if
(
oldRT
==
void
.
class
)
{
Wrapper
wrap
=
newRT
.
isPrimitive
()
?
Wrapper
.
forPrimitiveType
(
newRT
)
:
Wrapper
.
OBJECT
;
retFilter
=
ValueConversions
.
zeroConstantFunction
(
wrap
);
}
else
{
retFilter
=
MethodHandles
.
identity
(
newRT
);
retFilter
=
convertArguments
(
retFilter
,
retFilter
.
type
().
changeParameterType
(
0
,
oldRT
),
level
);
}
newType
=
newType
.
changeReturnType
(
oldRT
);
}
MethodHandle
res
=
null
;
Exception
ex
=
null
;
try
{
res
=
convertArguments
(
target
,
newType
,
oldType
,
level
);
}
catch
(
IllegalArgumentException
ex1
)
{
ex
=
ex1
;
}
}
if
(
res
==
null
)
{
WrongMethodTypeException
wmt
=
new
WrongMethodTypeException
(
"cannot convert to "
+
newType
+
": "
+
target
);
wmt
.
initCause
(
ex
);
throw
wmt
;
}
if
(
retFilter
!=
null
)
res
=
MethodHandles
.
filterReturnValue
(
res
,
retFilter
);
return
res
;
}
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
oldType
,
int
level
)
{
assert
(
oldType
.
parameterCount
()
==
target
.
type
().
parameterCount
());
if
(
newType
==
oldType
)
if
(
newType
==
oldType
)
return
target
;
return
target
;
if
(
oldType
.
parameterCount
()
!=
newType
.
parameterCount
())
if
(
oldType
.
parameterCount
()
!=
newType
.
parameterCount
())
throw
newIllegalArgumentException
(
"mismatched parameter count"
);
throw
newIllegalArgumentException
(
"mismatched parameter count"
,
oldType
,
newType
);
MethodHandle
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
target
);
MethodHandle
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
target
,
level
);
if
(
res
!=
null
)
if
(
res
!=
null
)
return
res
;
return
res
;
// We can come here in the case of target(int)void => (Object)void,
// because the unboxing logic for Object => int is complex.
int
argc
=
oldType
.
parameterCount
();
int
argc
=
oldType
.
parameterCount
();
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
// The JVM can't do it directly, so fill in the gap with a Java adapter.
// The JVM can't do it directly, so fill in the gap with a Java adapter.
// TO DO: figure out what to put here from case-by-case experience
// TO DO: figure out what to put here from case-by-case experience
// Use a heavier method: Convert all the arguments to Object,
// Use a heavier method: Convert all the arguments to Object,
// then back to the desired types. We might have to use Java-based
// then back to the desired types. We might have to use Java-based
// method handles to do this.
// method handles to do this.
MethodType
objType
=
MethodType
.
genericMethodType
(
argc
);
MethodType
objType
=
MethodType
.
genericMethodType
(
argc
);
MethodHandle
objTarget
=
AdapterMethodHandle
.
makePairwiseConvert
(
objType
,
target
);
MethodHandle
objTarget
=
AdapterMethodHandle
.
makePairwiseConvert
(
objType
,
target
,
level
);
if
(
objTarget
==
null
)
if
(
objTarget
==
null
)
objTarget
=
FromGeneric
.
make
(
target
);
objTarget
=
FromGeneric
.
make
(
target
);
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
objTarget
);
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
objTarget
,
level
);
if
(
res
!=
null
)
if
(
res
!=
null
)
return
res
;
return
res
;
return
ToGeneric
.
make
(
newType
,
objTarget
);
return
ToGeneric
.
make
(
newType
,
objTarget
);
}
}
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
Class
<?>
arrayType
,
int
arrayLength
)
{
MethodType
oldType
=
target
.
type
();
int
nargs
=
oldType
.
parameterCount
();
int
keepPosArgs
=
nargs
-
arrayLength
;
MethodType
newType
=
oldType
.
dropParameterTypes
(
keepPosArgs
,
nargs
)
.
insertParameterTypes
(
keepPosArgs
,
arrayType
);
return
spreadArguments
(
target
,
newType
,
keepPosArgs
,
arrayType
,
arrayLength
);
}
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
,
int
spreadArgPos
)
{
int
arrayLength
=
target
.
type
().
parameterCount
()
-
spreadArgPos
;
return
spreadArguments
(
target
,
newType
,
spreadArgPos
,
Object
[].
class
,
arrayLength
);
}
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
static
MethodHandle
spreadArguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
newType
,
int
spreadArg
)
{
int
spreadArgPos
,
Class
<?>
arrayType
,
int
arrayLength
)
{
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
// spread the last argument of newType to oldType
// spread the last argument of newType to oldType
int
spreadCount
=
oldType
.
parameterCount
()
-
spreadArg
;
assert
(
arrayLength
==
oldType
.
parameterCount
()
-
spreadArgPos
);
Class
<
Object
[]>
spreadArgType
=
Object
[].
class
;
assert
(
newType
.
parameterType
(
spreadArgPos
)
==
arrayType
);
MethodHandle
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
spreadArgType
,
spreadArg
,
spreadCount
);
MethodHandle
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
arrayType
,
spreadArgPos
,
arrayLength
);
if
(
res
!=
null
)
if
(
res
==
null
)
throw
new
IllegalArgumentException
(
"spread on "
+
target
+
" with "
+
arrayType
.
getSimpleName
());
return
res
;
// try an intermediate adapter
Class
<?>
spreadType
=
null
;
if
(
spreadArg
<
0
||
spreadArg
>=
newType
.
parameterCount
()
||
!
VerifyType
.
isSpreadArgType
(
spreadType
=
newType
.
parameterType
(
spreadArg
)))
throw
newIllegalArgumentException
(
"no restarg in "
+
newType
);
Class
<?>[]
ptypes
=
oldType
.
parameterArray
();
for
(
int
i
=
0
;
i
<
spreadCount
;
i
++)
ptypes
[
spreadArg
+
i
]
=
VerifyType
.
spreadArgElementType
(
spreadType
,
i
);
MethodType
midType
=
MethodType
.
methodType
(
newType
.
returnType
(),
ptypes
);
// after spreading, some arguments may need further conversion
MethodHandle
target2
=
convertArguments
(
target
,
midType
,
oldType
,
null
);
if
(
target2
==
null
)
throw
new
UnsupportedOperationException
(
"NYI: convert "
+
midType
+
" =calls=> "
+
oldType
);
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target2
,
spreadArgType
,
spreadArg
,
spreadCount
);
if
(
res
!=
null
)
return
res
;
res
=
SpreadGeneric
.
make
(
target2
,
spreadCount
);
if
(
res
!=
null
)
res
=
convertArguments
(
res
,
newType
,
res
.
type
(),
null
);
return
res
;
return
res
;
}
}
static
MethodHandle
collectArguments
(
MethodHandle
target
,
int
collectArg
,
MethodHandle
collector
)
{
MethodType
type
=
target
.
type
();
Class
<?>
collectType
=
collector
.
type
().
returnType
();
if
(
collectType
!=
type
.
parameterType
(
collectArg
))
target
=
target
.
asType
(
type
.
changeParameterType
(
collectArg
,
collectType
));
MethodType
newType
=
type
.
dropParameterTypes
(
collectArg
,
collectArg
+
1
)
.
insertParameterTypes
(
collectArg
,
collector
.
type
().
parameterArray
());
return
collectArguments
(
target
,
newType
,
collectArg
,
collector
);
}
static
MethodHandle
collectArguments
(
MethodHandle
target
,
static
MethodHandle
collectArguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
newType
,
int
collectArg
,
int
collectArg
,
MethodHandle
collector
)
{
MethodHandle
collector
)
{
MethodType
oldType
=
target
.
type
();
// (a...,c)=>r
MethodType
oldType
=
target
.
type
();
// (a...,c)=>r
if
(
collector
==
null
)
{
int
numCollect
=
newType
.
parameterCount
()
-
oldType
.
parameterCount
()
+
1
;
collector
=
ValueConversions
.
varargsArray
(
numCollect
);
}
// newType // (a..., b...)=>r
// newType // (a..., b...)=>r
MethodType
colType
=
collector
.
type
();
// (b...)=>c
MethodType
colType
=
collector
.
type
();
// (b...)=>c
// oldType // (a..., b...)=>r
// oldType // (a..., b...)=>r
assert
(
newType
.
parameterCount
()
==
collectArg
+
colType
.
parameterCount
());
assert
(
newType
.
parameterCount
()
==
collectArg
+
colType
.
parameterCount
());
assert
(
oldType
.
parameterCount
()
==
collectArg
+
1
);
assert
(
oldType
.
parameterCount
()
==
collectArg
+
1
);
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
null
);
MethodHandle
result
=
null
;
MethodHandle
gcollector
=
convertArguments
(
collector
,
colType
.
generic
(),
colType
,
null
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
oldType
,
colType
,
collectArg
,
false
))
{
if
(
gtarget
==
null
||
gcollector
==
null
)
return
null
;
result
=
AdapterMethodHandle
.
makeCollectArguments
(
target
,
collector
,
collectArg
,
false
);
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentCollector
(
gcollector
,
gtarget
);
}
MethodHandle
result
=
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
null
);
if
(
result
==
null
)
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
0
);
MethodHandle
gcollector
=
convertArguments
(
collector
,
colType
.
generic
(),
colType
,
0
);
if
(
gtarget
==
null
||
gcollector
==
null
)
return
null
;
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentCollector
(
gcollector
,
gtarget
);
result
=
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
0
);
}
return
result
;
return
result
;
}
}
static
MethodHandle
filterArgument
(
MethodHandle
target
,
static
MethodHandle
filterArgument
(
MethodHandle
target
,
int
pos
,
int
pos
,
MethodHandle
filter
)
{
MethodHandle
filter
)
{
MethodType
ttype
=
target
.
type
(),
gttype
=
ttype
.
generic
();
MethodType
ttype
=
target
.
type
();
MethodType
ftype
=
filter
.
type
();
assert
(
ftype
.
parameterCount
()
==
1
);
MethodType
rtype
=
ttype
.
changeParameterType
(
pos
,
ftype
.
parameterType
(
0
));
MethodType
gttype
=
ttype
.
generic
();
if
(
ttype
!=
gttype
)
{
if
(
ttype
!=
gttype
)
{
target
=
convertArguments
(
target
,
gttype
,
ttype
,
null
);
target
=
convertArguments
(
target
,
gttype
,
ttype
,
0
);
ttype
=
gttype
;
ttype
=
gttype
;
}
}
MethodType
ftype
=
filter
.
type
(),
gftype
=
ftype
.
generic
();
MethodType
gftype
=
ftype
.
generic
();
if
(
ftype
.
parameterCount
()
!=
1
)
throw
new
InternalError
();
if
(
ftype
!=
gftype
)
{
if
(
ftype
!=
gftype
)
{
filter
=
convertArguments
(
filter
,
gftype
,
ftype
,
null
);
filter
=
convertArguments
(
filter
,
gftype
,
ftype
,
0
);
ftype
=
gftype
;
ftype
=
gftype
;
}
}
if
(
ftype
==
ttype
)
{
MethodHandle
result
=
null
;
if
(
AdapterMethodHandle
.
canCollectArguments
(
ttype
,
ftype
,
pos
,
false
))
{
result
=
AdapterMethodHandle
.
makeCollectArguments
(
target
,
filter
,
pos
,
false
);
}
if
(
result
==
null
)
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
if
(
ftype
==
ttype
)
{
// simple unary case
// simple unary case
return
FilterOneArgument
.
make
(
filter
,
target
);
result
=
FilterOneArgument
.
make
(
filter
,
target
);
}
else
{
result
=
FilterGeneric
.
makeArgumentFilter
(
pos
,
filter
,
target
);
}
}
}
return
FilterGeneric
.
makeArgumentFilter
(
pos
,
filter
,
target
);
if
(
result
.
type
()
!=
rtype
)
result
=
result
.
asType
(
rtype
);
return
result
;
}
}
static
MethodHandle
foldArguments
(
MethodHandle
target
,
static
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
newType
,
MethodHandle
combiner
)
{
int
foldPos
,
MethodHandle
combiner
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
MethodType
ctype
=
combiner
.
type
();
MethodType
ctype
=
combiner
.
type
();
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
null
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
oldType
,
ctype
,
foldPos
,
true
))
{
MethodHandle
gcombiner
=
convertArguments
(
combiner
,
ctype
.
generic
(),
ctype
,
null
);
MethodHandle
res
=
AdapterMethodHandle
.
makeCollectArguments
(
target
,
combiner
,
foldPos
,
true
);
if
(
res
!=
null
)
return
res
;
}
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
if
(
foldPos
!=
0
)
return
null
;
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
0
);
MethodHandle
gcombiner
=
convertArguments
(
combiner
,
ctype
.
generic
(),
ctype
,
0
);
if
(
ctype
.
returnType
()
==
void
.
class
)
{
gtarget
=
dropArguments
(
gtarget
,
oldType
.
generic
().
insertParameterTypes
(
foldPos
,
Object
.
class
),
foldPos
);
}
if
(
gtarget
==
null
||
gcombiner
==
null
)
return
null
;
if
(
gtarget
==
null
||
gcombiner
==
null
)
return
null
;
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentFolder
(
gcombiner
,
gtarget
);
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentFolder
(
gcombiner
,
gtarget
);
MethodHandle
result
=
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
null
);
return
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
0
);
return
result
;
}
}
static
static
...
@@ -802,6 +879,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -802,6 +879,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
target
=
target
;
this
.
target
=
target
;
this
.
fallback
=
fallback
;
this
.
fallback
=
fallback
;
}
}
// FIXME: Build the control flow out of foldArguments.
static
MethodHandle
make
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
static
MethodHandle
make
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
MethodType
type
=
target
.
type
();
MethodType
type
=
target
.
type
();
int
nargs
=
type
.
parameterCount
();
int
nargs
=
type
.
parameterCount
();
...
@@ -809,12 +887,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -809,12 +887,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodType
gtype
=
type
.
generic
();
MethodType
gtype
=
type
.
generic
();
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
MethodHandle
gtest
=
convertArguments
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
test
.
type
(),
null
);
MethodHandle
gtest
=
convertArguments
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
test
.
type
(),
0
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
null
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
0
);
MethodHandle
gfallback
=
convertArguments
(
fallback
,
gtype
,
type
,
null
);
MethodHandle
gfallback
=
convertArguments
(
fallback
,
gtype
,
type
,
0
);
if
(
gtest
==
null
||
gtarget
==
null
||
gfallback
==
null
)
return
null
;
if
(
gtest
==
null
||
gtarget
==
null
||
gfallback
==
null
)
return
null
;
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
return
convertArguments
(
gguard
,
type
,
gtype
,
null
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
}
else
{
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
gtype
=
MethodType
.
genericMethodType
(
1
);
MethodType
gtype
=
MethodType
.
genericMethodType
(
1
);
...
@@ -925,8 +1003,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -925,8 +1003,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
GuardWithCatch
(
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
GuardWithCatch
(
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
this
(
INVOKES
[
target
.
type
().
parameterCount
()],
target
,
exType
,
catcher
);
this
(
INVOKES
[
target
.
type
().
parameterCount
()],
target
,
exType
,
catcher
);
}
}
GuardWithCatch
(
MethodHandle
invoker
,
// FIXME: Build the control flow out of foldArguments.
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
GuardWithCatch
(
MethodHandle
invoker
,
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
super
(
invoker
);
super
(
invoker
);
this
.
target
=
target
;
this
.
target
=
target
;
this
.
exType
=
exType
;
this
.
exType
=
exType
;
...
@@ -1057,11 +1136,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...
@@ -1057,11 +1136,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
nargs
<
GuardWithCatch
.
INVOKES
.
length
)
{
if
(
nargs
<
GuardWithCatch
.
INVOKES
.
length
)
{
MethodType
gtype
=
type
.
generic
();
MethodType
gtype
=
type
.
generic
();
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
null
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
0
);
MethodHandle
gcatcher
=
convertArguments
(
catcher
,
gcatchType
,
ctype
,
null
);
MethodHandle
gcatcher
=
convertArguments
(
catcher
,
gcatchType
,
ctype
,
0
);
MethodHandle
gguard
=
new
GuardWithCatch
(
gtarget
,
exType
,
gcatcher
);
MethodHandle
gguard
=
new
GuardWithCatch
(
gtarget
,
exType
,
gcatcher
);
if
(
gtarget
==
null
||
gcatcher
==
null
||
gguard
==
null
)
return
null
;
if
(
gtarget
==
null
||
gcatcher
==
null
||
gguard
==
null
)
return
null
;
return
convertArguments
(
gguard
,
type
,
gtype
,
null
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
}
else
{
MethodType
gtype
=
MethodType
.
genericMethodType
(
0
,
true
);
MethodType
gtype
=
MethodType
.
genericMethodType
(
0
,
true
);
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
...
...
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
8c50098c
...
@@ -115,6 +115,8 @@ class MethodHandleNatives {
...
@@ -115,6 +115,8 @@ class MethodHandleNatives {
/** Which conv-ops are implemented by the JVM? */
/** Which conv-ops are implemented by the JVM? */
static
final
int
CONV_OP_IMPLEMENTED_MASK
;
static
final
int
CONV_OP_IMPLEMENTED_MASK
;
/** Derived mode flag. Only false on some old JVM implementations. */
static
final
boolean
HAVE_RICOCHET_FRAMES
;
private
static
native
void
registerNatives
();
private
static
native
void
registerNatives
();
static
{
static
{
...
@@ -141,6 +143,7 @@ class MethodHandleNatives {
...
@@ -141,6 +143,7 @@ class MethodHandleNatives {
if
(
CONV_OP_IMPLEMENTED_MASK_
==
0
)
if
(
CONV_OP_IMPLEMENTED_MASK_
==
0
)
CONV_OP_IMPLEMENTED_MASK_
=
DEFAULT_CONV_OP_IMPLEMENTED_MASK
;
CONV_OP_IMPLEMENTED_MASK_
=
DEFAULT_CONV_OP_IMPLEMENTED_MASK
;
CONV_OP_IMPLEMENTED_MASK
=
CONV_OP_IMPLEMENTED_MASK_
;
CONV_OP_IMPLEMENTED_MASK
=
CONV_OP_IMPLEMENTED_MASK_
;
HAVE_RICOCHET_FRAMES
=
(
CONV_OP_IMPLEMENTED_MASK
&
(
1
<<
OP_COLLECT_ARGS
))
!=
0
;
}
}
// All compile-time constants go here.
// All compile-time constants go here.
...
@@ -186,25 +189,26 @@ class MethodHandleNatives {
...
@@ -186,25 +189,26 @@ class MethodHandleNatives {
*/
*/
static
final
int
static
final
int
OP_RETYPE_ONLY
=
0x0
,
// no argument changes; straight retype
OP_RETYPE_ONLY
=
0x0
,
// no argument changes; straight retype
OP_RETYPE_RAW
=
0x1
,
//
no argument changes; straight retype
OP_RETYPE_RAW
=
0x1
,
//
straight retype, trusted (void->int, Object->T)
OP_CHECK_CAST
=
0x2
,
// ref-to-ref conversion; requires a Class argument
OP_CHECK_CAST
=
0x2
,
// ref-to-ref conversion; requires a Class argument
OP_PRIM_TO_PRIM
=
0x3
,
// converts from one primitive to another
OP_PRIM_TO_PRIM
=
0x3
,
// converts from one primitive to another
OP_REF_TO_PRIM
=
0x4
,
// unboxes a wrapper to produce a primitive
OP_REF_TO_PRIM
=
0x4
,
// unboxes a wrapper to produce a primitive
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
(NYI)
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
OP_SWAP_ARGS
=
0x6
,
// swap arguments (vminfo is 2nd arg)
OP_SWAP_ARGS
=
0x6
,
// swap arguments (vminfo is 2nd arg)
OP_ROT_ARGS
=
0x7
,
// rotate arguments (vminfo is displaced arg)
OP_ROT_ARGS
=
0x7
,
// rotate arguments (vminfo is displaced arg)
OP_DUP_ARGS
=
0x8
,
// duplicates one or more arguments (at TOS)
OP_DUP_ARGS
=
0x8
,
// duplicates one or more arguments (at TOS)
OP_DROP_ARGS
=
0x9
,
// remove one or more argument slots
OP_DROP_ARGS
=
0x9
,
// remove one or more argument slots
OP_COLLECT_ARGS
=
0xA
,
// combine
one or more arguments into a varargs (NYI)
OP_COLLECT_ARGS
=
0xA
,
// combine
arguments using an auxiliary function
OP_SPREAD_ARGS
=
0xB
,
// expand in place a varargs array (of known size)
OP_SPREAD_ARGS
=
0xB
,
// expand in place a varargs array (of known size)
OP_F
LYBY
=
0xC
,
// operate first on reified argument list (NYI)
OP_F
OLD_ARGS
=
0xC
,
// combine but do not remove arguments; prepend result
OP_RICOCHET
=
0xD
,
// run an adapter chain on the return value (NYI)
//OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists
CONV_OP_LIMIT
=
0xE
;
// limit of CONV_OP enumeration
CONV_OP_LIMIT
=
0xE
;
// limit of CONV_OP enumeration
/** Shift and mask values for decoding the AMH.conversion field.
/** Shift and mask values for decoding the AMH.conversion field.
* These numbers are shared with the JVM for creating AMHs.
* These numbers are shared with the JVM for creating AMHs.
*/
*/
static
final
int
static
final
int
CONV_OP_MASK
=
0xF00
,
// this nybble contains the conversion op field
CONV_OP_MASK
=
0xF00
,
// this nybble contains the conversion op field
CONV_TYPE_MASK
=
0x0F
,
// fits T_ADDRESS and below
CONV_VMINFO_MASK
=
0x0FF
,
// LSB is reserved for JVM use
CONV_VMINFO_MASK
=
0x0FF
,
// LSB is reserved for JVM use
CONV_VMINFO_SHIFT
=
0
,
// position of bits in CONV_VMINFO_MASK
CONV_VMINFO_SHIFT
=
0
,
// position of bits in CONV_VMINFO_MASK
CONV_OP_SHIFT
=
8
,
// position of bits in CONV_OP_MASK
CONV_OP_SHIFT
=
8
,
// position of bits in CONV_OP_MASK
...
@@ -244,8 +248,9 @@ class MethodHandleNatives {
...
@@ -244,8 +248,9 @@ class MethodHandleNatives {
T_LONG
=
11
,
T_LONG
=
11
,
T_OBJECT
=
12
,
T_OBJECT
=
12
,
//T_ARRAY = 13
//T_ARRAY = 13
T_VOID
=
14
;
T_VOID
=
14
,
//T_ADDRESS = 15
//T_ADDRESS = 15
T_ILLEGAL
=
99
;
/**
/**
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
...
@@ -273,16 +278,29 @@ class MethodHandleNatives {
...
@@ -273,16 +278,29 @@ class MethodHandleNatives {
try
{
try
{
Field
con
=
Constants
.
class
.
getDeclaredField
(
name
);
Field
con
=
Constants
.
class
.
getDeclaredField
(
name
);
int
jval
=
con
.
getInt
(
null
);
int
jval
=
con
.
getInt
(
null
);
if
(
jval
!=
vmval
)
if
(
jval
==
vmval
)
continue
;
throw
new
InternalError
(
name
+
": JVM has "
+
vmval
+
" while Java has "
+
jval
);
String
err
=
(
name
+
": JVM has "
+
vmval
+
" while Java has "
+
jval
);
if
(
name
.
equals
(
"CONV_OP_LIMIT"
))
{
System
.
err
.
println
(
"warning: "
+
err
);
continue
;
}
throw
new
InternalError
(
err
);
}
catch
(
Exception
ex
)
{
}
catch
(
Exception
ex
)
{
if
(
ex
instanceof
NoSuchFieldException
)
{
String
err
=
(
name
+
": JVM has "
+
vmval
+
" which Java does not define"
);
// ignore exotic ops the JVM cares about; we just wont issue them
if
(
name
.
startsWith
(
"OP_"
)
||
name
.
startsWith
(
"GC_"
))
{
System
.
err
.
println
(
"warning: "
+
err
);
continue
;
}
}
throw
new
InternalError
(
name
+
": access failed, got "
+
ex
);
throw
new
InternalError
(
name
+
": access failed, got "
+
ex
);
}
}
}
}
return
true
;
return
true
;
}
}
static
{
static
{
verifyConstants
(
);
assert
(
verifyConstants
()
);
}
}
// Up-calls from the JVM.
// Up-calls from the JVM.
...
@@ -313,7 +331,7 @@ class MethodHandleNatives {
...
@@ -313,7 +331,7 @@ class MethodHandleNatives {
}
}
/**
/**
* The JVM wants to use a MethodType with in
vokeGeneric
. Give the runtime fair warning.
* The JVM wants to use a MethodType with in
exact invoke
. Give the runtime fair warning.
*/
*/
static
void
notifyGenericMethodType
(
MethodType
type
)
{
static
void
notifyGenericMethodType
(
MethodType
type
)
{
type
.
form
().
notifyGenericMethodType
();
type
.
form
().
notifyGenericMethodType
();
...
@@ -323,15 +341,39 @@ class MethodHandleNatives {
...
@@ -323,15 +341,39 @@ class MethodHandleNatives {
* The JVM wants to raise an exception. Here's the path.
* The JVM wants to raise an exception. Here's the path.
*/
*/
static
void
raiseException
(
int
code
,
Object
actual
,
Object
required
)
{
static
void
raiseException
(
int
code
,
Object
actual
,
Object
required
)
{
String
message
;
String
message
=
null
;
switch
(
code
)
{
case
190
:
// arraylength
try
{
String
reqLength
=
""
;
if
(
required
instanceof
AdapterMethodHandle
)
{
int
conv
=
((
AdapterMethodHandle
)
required
).
getConversion
();
int
spChange
=
AdapterMethodHandle
.
extractStackMove
(
conv
);
reqLength
=
" of length "
+(
spChange
+
1
);
}
int
actualLength
=
actual
==
null
?
0
:
java
.
lang
.
reflect
.
Array
.
getLength
(
actual
);
message
=
"required array"
+
reqLength
+
", but encountered wrong length "
+
actualLength
;
break
;
}
catch
(
IllegalArgumentException
ex
)
{
}
required
=
Object
[].
class
;
// should have been an array
code
=
192
;
// checkcast
break
;
}
// disregard the identity of the actual object, if it is not a class:
// disregard the identity of the actual object, if it is not a class:
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
if
(
message
==
null
)
{
actual
=
actual
.
getClass
();
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
if
(
actual
!=
null
)
actual
=
actual
.
getClass
();
message
=
"required "
+
required
+
" but encountered "
+
actual
;
if
(
actual
!=
null
)
else
message
=
"required "
+
required
+
" but encountered "
+
actual
;
message
=
"required "
+
required
;
else
message
=
"required "
+
required
;
}
switch
(
code
)
{
switch
(
code
)
{
case
190
:
// arraylength
throw
new
ArrayIndexOutOfBoundsException
(
message
);
case
50
:
//_aaload
throw
new
ClassCastException
(
message
);
case
192
:
// checkcast
case
192
:
// checkcast
throw
new
ClassCastException
(
message
);
throw
new
ClassCastException
(
message
);
default
:
default
:
...
@@ -365,4 +407,13 @@ class MethodHandleNatives {
...
@@ -365,4 +407,13 @@ class MethodHandleNatives {
throw
err
;
throw
err
;
}
}
}
}
/**
* This assertion marks code which was written before ricochet frames were implemented.
* Such code will go away when the ports catch up.
*/
static
boolean
workaroundWithoutRicochetFrames
()
{
assert
(!
HAVE_RICOCHET_FRAMES
)
:
"this code should not be executed if `-XX:+UseRicochetFrames is enabled"
;
return
true
;
}
}
}
src/share/classes/java/lang/invoke/MethodHandleStatics.java
浏览文件 @
8c50098c
...
@@ -63,8 +63,17 @@ package java.lang.invoke;
...
@@ -63,8 +63,17 @@ package java.lang.invoke;
}
}
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
if
(
av
==
null
?
n
!=
0
:
((
Object
[])
av
).
length
!=
n
)
if
(
av
==
null
)
{
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
if
(
n
==
0
)
return
;
}
else
if
(
av
instanceof
Object
[])
{
int
len
=
((
Object
[])
av
).
length
;
if
(
len
==
n
)
return
;
}
else
{
int
len
=
java
.
lang
.
reflect
.
Array
.
getLength
(
av
);
if
(
len
==
n
)
return
;
}
// fall through to error:
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
}
}
// handy shared exception makers (they simplify the common case code)
// handy shared exception makers (they simplify the common case code)
...
@@ -80,6 +89,9 @@ package java.lang.invoke;
...
@@ -80,6 +89,9 @@ package java.lang.invoke;
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
obj
)
{
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
obj
)
{
return
new
IllegalArgumentException
(
message
(
message
,
obj
));
return
new
IllegalArgumentException
(
message
(
message
,
obj
));
}
}
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
obj
,
Object
obj2
)
{
return
new
IllegalArgumentException
(
message
(
message
,
obj
,
obj2
));
}
/*non-public*/
static
Error
uncaughtException
(
Exception
ex
)
{
/*non-public*/
static
Error
uncaughtException
(
Exception
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
err
.
initCause
(
ex
);
...
@@ -89,4 +101,8 @@ package java.lang.invoke;
...
@@ -89,4 +101,8 @@ package java.lang.invoke;
if
(
obj
!=
null
)
message
=
message
+
": "
+
obj
;
if
(
obj
!=
null
)
message
=
message
+
": "
+
obj
;
return
message
;
return
message
;
}
}
private
static
String
message
(
String
message
,
Object
obj
,
Object
obj2
)
{
if
(
obj
!=
null
||
obj2
!=
null
)
message
=
message
+
": "
+
obj
+
", "
+
obj2
;
return
message
;
}
}
}
src/share/classes/java/lang/invoke/MethodHandles.java
浏览文件 @
8c50098c
...
@@ -190,7 +190,7 @@ public class MethodHandles {
...
@@ -190,7 +190,7 @@ public class MethodHandles {
* is not symbolically accessible from the lookup class's loader,
* is not symbolically accessible from the lookup class's loader,
* the lookup can still succeed.
* the lookup can still succeed.
* For example, lookups for {@code MethodHandle.invokeExact} and
* For example, lookups for {@code MethodHandle.invokeExact} and
* {@code MethodHandle.invoke
Generic
} will always succeed, regardless of requested type.
* {@code MethodHandle.invoke} will always succeed, regardless of requested type.
* <li>If there is a security manager installed, it can forbid the lookup
* <li>If there is a security manager installed, it can forbid the lookup
* on various grounds (<a href="#secmgr">see below</a>).
* on various grounds (<a href="#secmgr">see below</a>).
* By contrast, the {@code ldc} instruction is not subject to
* By contrast, the {@code ldc} instruction is not subject to
...
@@ -590,10 +590,10 @@ public class MethodHandles {
...
@@ -590,10 +590,10 @@ public class MethodHandles {
* Because of the general equivalence between {@code invokevirtual}
* Because of the general equivalence between {@code invokevirtual}
* instructions and method handles produced by {@code findVirtual},
* instructions and method handles produced by {@code findVirtual},
* if the class is {@code MethodHandle} and the name string is
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invoke
Generic
}, the resulting
* {@code invokeExact} or {@code invoke}, the resulting
* method handle is equivalent to one produced by
* method handle is equivalent to one produced by
* {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
* {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
* {@link java.lang.invoke.MethodHandles#
genericInvoker MethodHandles.genericI
nvoker}
* {@link java.lang.invoke.MethodHandles#
invoker MethodHandles.i
nvoker}
* with the same {@code type} argument.
* with the same {@code type} argument.
*
*
* @param refc the class or interface from which the method is accessed
* @param refc the class or interface from which the method is accessed
...
@@ -1080,7 +1080,7 @@ return mh1;
...
@@ -1080,7 +1080,7 @@ return mh1;
MethodType
rawType
=
mh
.
type
();
MethodType
rawType
=
mh
.
type
();
if
(
rawType
.
parameterType
(
0
)
==
caller
)
return
mh
;
if
(
rawType
.
parameterType
(
0
)
==
caller
)
return
mh
;
MethodType
narrowType
=
rawType
.
changeParameterType
(
0
,
caller
);
MethodType
narrowType
=
rawType
.
changeParameterType
(
0
,
caller
);
MethodHandle
narrowMH
=
MethodHandleImpl
.
convertArguments
(
mh
,
narrowType
,
rawType
,
null
);
MethodHandle
narrowMH
=
MethodHandleImpl
.
convertArguments
(
mh
,
narrowType
,
rawType
,
0
);
return
fixVarargs
(
narrowMH
,
mh
);
return
fixVarargs
(
narrowMH
,
mh
);
}
}
...
@@ -1148,7 +1148,7 @@ return mh1;
...
@@ -1148,7 +1148,7 @@ return mh1;
* <li>an {@code Object[]} array containing more arguments
* <li>an {@code Object[]} array containing more arguments
* </ul>
* </ul>
* <p>
* <p>
* The invoker will behave like a call to {@link MethodHandle#invoke
Generic invokeGeneric
} with
* The invoker will behave like a call to {@link MethodHandle#invoke
invoke
} with
* the indicated {@code type}.
* the indicated {@code type}.
* That is, if the target is exactly of the given {@code type}, it will behave
* 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}
* like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
...
@@ -1166,7 +1166,7 @@ return mh1;
...
@@ -1166,7 +1166,7 @@ return mh1;
* <p>
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
* <p><blockquote><pre>
MethodHandle invoker = MethodHandles.
genericI
nvoker(type);
MethodHandle invoker = MethodHandles.
i
nvoker(type);
int spreadArgCount = type.parameterCount - objectArgCount;
int spreadArgCount = type.parameterCount - objectArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
return invoker;
...
@@ -1186,7 +1186,7 @@ return invoker;
...
@@ -1186,7 +1186,7 @@ return invoker;
/**
/**
* Produces a special <em>invoker method handle</em> which can be used to
* Produces a special <em>invoker method handle</em> which can be used to
* invoke any method handle of the given type, as if by {@
code
invokeExact}.
* invoke any method handle of the given type, as if by {@
link MethodHandle#invokeExact
invokeExact}.
* The resulting invoker will have a type which is
* The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
* an additional leading argument of type {@code MethodHandle}.
...
@@ -1203,7 +1203,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
...
@@ -1203,7 +1203,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* For example, to emulate an {@code invokeExact} call to a variable method
* For example, to emulate an {@code invokeExact} call to a variable method
* handle {@code M}, extract its type {@code T},
* handle {@code M}, extract its type {@code T},
* look up the invoker method {@code X} for {@code T},
* look up the invoker method {@code X} for {@code T},
* and call the invoker method, as {@code X.invoke
Generic
(T, A...)}.
* and call the invoker method, as {@code X.invoke(T, A...)}.
* (It would not work to call {@code X.invokeExact}, since the type {@code T}
* (It would not work to call {@code X.invokeExact}, since the type {@code T}
* is unknown.)
* is unknown.)
* If spreading, collecting, or other argument transformations are required,
* If spreading, collecting, or other argument transformations are required,
...
@@ -1212,7 +1212,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
...
@@ -1212,7 +1212,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* <p>
* <p>
* <em>(Note: The invoker method is not available via the Core Reflection API.
* <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 Method.invoke}
* on the declared {@code invokeExact} or {@code invoke
Generic
} method will raise an
* on the declared {@code invokeExact} or {@code invoke} method will raise an
* {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
* {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
* <p>
* <p>
* This method throws no reflective or security exceptions.
* This method throws no reflective or security exceptions.
...
@@ -1226,20 +1226,20 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
...
@@ -1226,20 +1226,20 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
/**
/**
* Produces a special <em>invoker method handle</em> which can be used to
* Produces a special <em>invoker method handle</em> which can be used to
* invoke any method handle
of the given type, as if by {@code invokeGeneric
}.
* invoke any method handle
compatible with the given type, as if by {@link MethodHandle#invoke invoke
}.
* The resulting invoker will have a type which is
* The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
* an additional leading argument of type {@code MethodHandle}.
* <p>
* <p>
* Before invoking its target, the invoker will apply reference casts as
* Before invoking its target, the invoker will apply reference casts as
* necessary and
unbox and widen primitive arguments, as if by {@link #convertArguments convertArguments
}.
* necessary and
box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType
}.
*
The return value of the invoker will be an {@code Object} reference,
*
Similarly, the return value will be converted as necessary.
*
boxing a primitive value if the original type returns a primitive
,
*
If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle}
,
*
and always null if the original type returns void
.
*
the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}
.
* <p>
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
* <p><blockquote><pre>
publicLookup().findVirtual(MethodHandle.class, "invoke
Generic
", type)
publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* </pre></blockquote>
* </pre></blockquote>
* <p>
* <p>
* This method throws no reflective or security exceptions.
* This method throws no reflective or security exceptions.
...
@@ -1247,8 +1247,17 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
...
@@ -1247,8 +1247,17 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
* @return a method handle suitable for invoking any method handle convertible to the given type
* @return a method handle suitable for invoking any method handle convertible to the given type
*/
*/
static
public
static
public
MethodHandle
invoker
(
MethodType
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
)
{
MethodHandle
genericInvoker
(
MethodType
type
)
{
return
type
.
invokers
().
genericInvoker
(
);
return
invoker
(
type
);
}
}
/**
/**
...
@@ -1368,18 +1377,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
...
@@ -1368,18 +1377,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
*/
public
static
public
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodType
oldType
=
target
.
type
();
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
1
);
if
(
oldType
.
equals
(
newType
))
return
target
;
MethodHandle
res
=
null
;
try
{
res
=
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
oldType
,
null
);
}
catch
(
IllegalArgumentException
ex
)
{
}
if
(
res
==
null
)
throw
new
WrongMethodTypeException
(
"cannot convert to "
+
newType
+
": "
+
target
);
return
res
;
}
}
/**
/**
...
@@ -1422,7 +1420,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
...
@@ -1422,7 +1420,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
*/
public
static
public
static
MethodHandle
explicitCastArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodHandle
explicitCastArguments
(
MethodHandle
target
,
MethodType
newType
)
{
return
convertArguments
(
target
,
newType
);
// FIXME!
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
2
);
}
}
/*
/*
...
@@ -1517,23 +1515,32 @@ assert((int)twice.invokeExact(21) == 42);
...
@@ -1517,23 +1515,32 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
MethodType
oldType
=
target
.
type
();
MethodType
oldType
=
target
.
type
();
checkReorder
(
reorder
,
newType
,
oldType
);
checkReorder
(
reorder
,
newType
,
oldType
);
return
MethodHandleImpl
.
convert
Arguments
(
target
,
return
MethodHandleImpl
.
permute
Arguments
(
target
,
newType
,
oldType
,
newType
,
oldType
,
reorder
);
reorder
);
}
}
private
static
void
checkReorder
(
int
[]
reorder
,
MethodType
newType
,
MethodType
oldType
)
{
private
static
void
checkReorder
(
int
[]
reorder
,
MethodType
newType
,
MethodType
oldType
)
{
if
(
newType
.
returnType
()
!=
oldType
.
returnType
())
throw
newIllegalArgumentException
(
"return types do not match"
,
oldType
,
newType
);
if
(
reorder
.
length
==
oldType
.
parameterCount
())
{
if
(
reorder
.
length
==
oldType
.
parameterCount
())
{
int
limit
=
newType
.
parameterCount
();
int
limit
=
newType
.
parameterCount
();
boolean
bad
=
false
;
boolean
bad
=
false
;
for
(
int
i
:
reorder
)
{
for
(
int
j
=
0
;
j
<
reorder
.
length
;
j
++)
{
int
i
=
reorder
[
j
];
if
(
i
<
0
||
i
>=
limit
)
{
if
(
i
<
0
||
i
>=
limit
)
{
bad
=
true
;
break
;
bad
=
true
;
break
;
}
}
Class
<?>
src
=
newType
.
parameterType
(
i
);
Class
<?>
dst
=
oldType
.
parameterType
(
j
);
if
(
src
!=
dst
)
throw
newIllegalArgumentException
(
"parameter types do not match after reorder"
,
oldType
,
newType
);
}
}
if
(!
bad
)
return
;
if
(!
bad
)
return
;
}
}
throw
newIllegalArgumentException
(
"bad reorder array
"
);
throw
newIllegalArgumentException
(
"bad reorder array
: "
+
Arrays
.
toString
(
reorder
)
);
}
}
/**
/**
...
@@ -1622,7 +1629,7 @@ assert((int)twice.invokeExact(21) == 42);
...
@@ -1622,7 +1629,7 @@ assert((int)twice.invokeExact(21) == 42);
if
(
type
==
void
.
class
)
if
(
type
==
void
.
class
)
throw
newIllegalArgumentException
(
"void type"
);
throw
newIllegalArgumentException
(
"void type"
);
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
type
);
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
type
);
return
i
dentity
(
type
).
bindTo
(
w
.
convert
(
value
,
type
));
return
i
nsertArguments
(
identity
(
type
),
0
,
w
.
convert
(
value
,
type
));
}
else
{
}
else
{
return
identity
(
type
).
bindTo
(
type
.
cast
(
value
));
return
identity
(
type
).
bindTo
(
type
.
cast
(
value
));
}
}
...
@@ -1857,7 +1864,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
...
@@ -1857,7 +1864,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
MethodHandle
filterArguments
(
MethodHandle
target
,
int
pos
,
MethodHandle
...
filters
)
{
MethodHandle
filterArguments
(
MethodHandle
target
,
int
pos
,
MethodHandle
...
filters
)
{
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
MethodHandle
adapter
=
target
;
MethodHandle
adapter
=
target
;
MethodType
adapterType
=
targetType
;
MethodType
adapterType
=
null
;
assert
((
adapterType
=
targetType
)
!=
null
);
int
maxPos
=
targetType
.
parameterCount
();
int
maxPos
=
targetType
.
parameterCount
();
if
(
pos
+
filters
.
length
>
maxPos
)
if
(
pos
+
filters
.
length
>
maxPos
)
throw
newIllegalArgumentException
(
"too many filters"
);
throw
newIllegalArgumentException
(
"too many filters"
);
...
@@ -1865,19 +1873,23 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
...
@@ -1865,19 +1873,23 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
for
(
MethodHandle
filter
:
filters
)
{
for
(
MethodHandle
filter
:
filters
)
{
curPos
+=
1
;
curPos
+=
1
;
if
(
filter
==
null
)
continue
;
// ignore null elements of filters
if
(
filter
==
null
)
continue
;
// ignore null elements of filters
MethodType
filterType
=
filter
.
type
();
adapter
=
filterArgument
(
adapter
,
curPos
,
filter
);
if
(
filterType
.
parameterCount
()
!=
1
assert
((
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filter
.
type
().
parameterType
(
0
)))
!=
null
);
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
curPos
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filterType
.
parameterType
(
0
));
adapter
=
MethodHandleImpl
.
filterArgument
(
adapter
,
curPos
,
filter
);
}
}
MethodType
midType
=
adapter
.
type
();
assert
(
adapterType
.
equals
(
adapter
.
type
()));
if
(
midType
!=
adapterType
)
adapter
=
MethodHandleImpl
.
convertArguments
(
adapter
,
adapterType
,
midType
,
null
);
return
adapter
;
return
adapter
;
}
}
/*non-public*/
static
MethodHandle
filterArgument
(
MethodHandle
target
,
int
pos
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
pos
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
,
targetType
,
filterType
);
return
MethodHandleImpl
.
filterArgument
(
target
,
pos
,
filter
);
}
/**
/**
* Adapts a target method handle {@code target} by post-processing
* Adapts a target method handle {@code target} by post-processing
* its return value with a unary filter function.
* its return value with a unary filter function.
...
@@ -1913,14 +1925,26 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
...
@@ -1913,14 +1925,26 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
Class
<?>
rtype
=
targetType
.
returnType
();
||
filterType
.
parameterType
(
0
)
!=
targetType
.
returnType
())
int
filterValues
=
filterType
.
parameterCount
();
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
if
(
filterValues
==
0
?
(
rtype
!=
void
.
class
)
:
(
rtype
!=
filterType
.
parameterType
(
0
)))
throw
newIllegalArgumentException
(
"target and filter types do not match"
,
target
,
filter
);
// result = fold( lambda(retval, arg...) { filter(retval) },
// result = fold( lambda(retval, arg...) { filter(retval) },
// lambda( arg...) { target(arg...) } )
// lambda( arg...) { target(arg...) } )
MethodType
newType
=
targetType
.
changeReturnType
(
filterType
.
returnType
());
MethodHandle
result
=
null
;
if
(
AdapterMethodHandle
.
canCollectArguments
(
filterType
,
targetType
,
0
,
false
))
{
result
=
AdapterMethodHandle
.
makeCollectArguments
(
filter
,
target
,
0
,
false
);
if
(
result
!=
null
)
return
result
;
}
// FIXME: Too many nodes here.
// FIXME: Too many nodes here.
MethodHandle
returner
=
dropArguments
(
filter
,
1
,
targetType
.
parameterList
());
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
return
foldArguments
(
returner
,
target
);
MethodHandle
returner
=
dropArguments
(
filter
,
filterValues
,
targetType
.
parameterList
());
result
=
foldArguments
(
returner
,
target
);
assert
(
result
.
type
().
equals
(
newType
));
return
result
;
}
}
/**
/**
...
@@ -1972,16 +1996,23 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
...
@@ -1972,16 +1996,23 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodHandle
combiner
)
{
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodHandle
combiner
)
{
MethodType
targetType
=
target
.
type
();
MethodType
targetType
=
target
.
type
();
MethodType
combinerType
=
combiner
.
type
();
MethodType
combinerType
=
combiner
.
type
();
int
foldPos
=
0
;
// always at the head, at present
int
foldArgs
=
combinerType
.
parameterCount
();
int
foldArgs
=
combinerType
.
parameterCount
();
boolean
ok
=
(
targetType
.
parameterCount
()
>=
1
+
foldArgs
);
int
foldVals
=
combinerType
.
returnType
()
==
void
.
class
?
0
:
1
;
if
(
ok
&&
!
combinerType
.
parameterList
().
equals
(
targetType
.
parameterList
().
subList
(
1
,
foldArgs
+
1
)))
int
afterInsertPos
=
foldPos
+
foldVals
;
boolean
ok
=
(
targetType
.
parameterCount
()
>=
afterInsertPos
+
foldArgs
);
if
(
ok
&&
!(
combinerType
.
parameterList
()
.
equals
(
targetType
.
parameterList
().
subList
(
afterInsertPos
,
afterInsertPos
+
foldArgs
))))
ok
=
false
;
ok
=
false
;
if
(
ok
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
if
(
ok
&&
foldVals
!=
0
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
ok
=
false
;
ok
=
false
;
if
(!
ok
)
if
(!
ok
)
throw
misMatchedTypes
(
"target and combiner types"
,
targetType
,
combinerType
);
throw
misMatchedTypes
(
"target and combiner types"
,
targetType
,
combinerType
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
0
,
1
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
foldPos
,
afterInsertPos
);
return
MethodHandleImpl
.
foldArguments
(
target
,
newType
,
combiner
);
MethodHandle
res
=
MethodHandleImpl
.
foldArguments
(
target
,
newType
,
foldPos
,
combiner
);
if
(
res
==
null
)
throw
newIllegalArgumentException
(
"cannot fold from "
+
newType
+
" to "
+
targetType
);
return
res
;
}
}
/**
/**
...
@@ -2142,7 +2173,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
...
@@ -2142,7 +2173,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* the given {@code target} on the incoming arguments,
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* returns or throws. The invocation will be as if by
* {@code target.invoke
Generic
}.
* {@code target.invoke}.
* The target's type will be checked before the
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* which may result in a {@code WrongMethodTypeException}.
...
...
src/share/classes/java/lang/invoke/MethodType.java
浏览文件 @
8c50098c
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
package
java.lang.invoke
;
package
java.lang.invoke
;
import
sun.invoke.util.Wrapper
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashMap
;
...
@@ -39,7 +40,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
...
@@ -39,7 +40,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* matched between a method handle and all its callers,
* matched between a method handle and all its callers,
* and the JVM's operations enforce this matching at, specifically
* and the JVM's operations enforce this matching at, specifically
* during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
* during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
* and {@link MethodHandle#invoke
Generic MethodHandle.invokeGeneric
}, and during execution
* and {@link MethodHandle#invoke
MethodHandle.invoke
}, and during execution
* of {@code invokedynamic} instructions.
* of {@code invokedynamic} instructions.
* <p>
* <p>
* The structure is a return type accompanied by any number of parameter types.
* The structure is a return type accompanied by any number of parameter types.
...
@@ -262,18 +263,18 @@ class MethodType implements java.io.Serializable {
...
@@ -262,18 +263,18 @@ class MethodType implements java.io.Serializable {
* Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
* Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be {@code Object},
* All parameters and the return type will be {@code Object},
* except the final
varargs
parameter if any, which will be {@code Object[]}.
* except the final
array
parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the
varargs
parameter if any)
* @param objectArgCount number of parameters (excluding the
final array
parameter if any)
* @param
varargs whether there will be a varargs
parameter, of type {@code Object[]}
* @param
finalArray whether there will be a trailing array
parameter, of type {@code Object[]}
* @return a
totally generic method type, given only its count of parameters and vararg
s
* @return a
generally applicable method type, for all calls of the given fixed argument count and a collected array of further argument
s
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
(or 254, if {@code finalArray})
* @see #genericMethodType(int)
* @see #genericMethodType(int)
*/
*/
public
static
public
static
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
varargs
)
{
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
finalArray
)
{
MethodType
mt
;
MethodType
mt
;
checkSlotCount
(
objectArgCount
);
checkSlotCount
(
objectArgCount
);
int
ivarargs
=
(!
varargs
?
0
:
1
);
int
ivarargs
=
(!
finalArray
?
0
:
1
);
int
ootIndex
=
objectArgCount
*
2
+
ivarargs
;
int
ootIndex
=
objectArgCount
*
2
+
ivarargs
;
if
(
ootIndex
<
objectOnlyTypes
.
length
)
{
if
(
ootIndex
<
objectOnlyTypes
.
length
)
{
mt
=
objectOnlyTypes
[
ootIndex
];
mt
=
objectOnlyTypes
[
ootIndex
];
...
@@ -294,7 +295,7 @@ class MethodType implements java.io.Serializable {
...
@@ -294,7 +295,7 @@ class MethodType implements java.io.Serializable {
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be Object.
* All parameters and the return type will be Object.
* @param objectArgCount number of parameters
* @param objectArgCount number of parameters
* @return a
totally generic method type, given only its count of parameters
* @return a
generally applicable method type, for all calls of the given argument count
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* @see #genericMethodType(int, boolean)
* @see #genericMethodType(int, boolean)
*/
*/
...
@@ -626,6 +627,30 @@ class MethodType implements java.io.Serializable {
...
@@ -626,6 +627,30 @@ class MethodType implements java.io.Serializable {
return
sb
.
toString
();
return
sb
.
toString
();
}
}
/*non-public*/
boolean
isConvertibleTo
(
MethodType
newType
)
{
if
(!
canConvert
(
returnType
(),
newType
.
returnType
()))
return
false
;
int
argc
=
parameterCount
();
if
(
argc
!=
newType
.
parameterCount
())
return
false
;
for
(
int
i
=
0
;
i
<
argc
;
i
++)
{
if
(!
canConvert
(
newType
.
parameterType
(
i
),
parameterType
(
i
)))
return
false
;
}
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
;
}
return
true
;
}
/// Queries which have to do with the bytecode architecture
/// Queries which have to do with the bytecode architecture
/** Reports the number of JVM stack slots required to invoke a method
/** Reports the number of JVM stack slots required to invoke a method
...
...
src/share/classes/java/lang/invoke/MethodTypeForm.java
浏览文件 @
8c50098c
...
@@ -46,6 +46,7 @@ class MethodTypeForm {
...
@@ -46,6 +46,7 @@ class MethodTypeForm {
final
long
argCounts
;
// packed slot & value counts
final
long
argCounts
;
// packed slot & value counts
final
long
primCounts
;
// packed prim & double counts
final
long
primCounts
;
// packed prim & double counts
final
int
vmslots
;
// total number of parameter slots
final
int
vmslots
;
// total number of parameter slots
private
Object
vmlayout
;
// vm-specific information for calls
final
MethodType
erasedType
;
// the canonical erasure
final
MethodType
erasedType
;
// the canonical erasure
/*lazy*/
MethodType
primsAsBoxes
;
// replace prims by wrappers
/*lazy*/
MethodType
primsAsBoxes
;
// replace prims by wrappers
...
@@ -59,7 +60,7 @@ class MethodTypeForm {
...
@@ -59,7 +60,7 @@ class MethodTypeForm {
/*lazy*/
FromGeneric
fromGeneric
;
// convert cs. w/o prims to with
/*lazy*/
FromGeneric
fromGeneric
;
// convert cs. w/o prims to with
/*lazy*/
SpreadGeneric
[]
spreadGeneric
;
// expand one argument to many
/*lazy*/
SpreadGeneric
[]
spreadGeneric
;
// expand one argument to many
/*lazy*/
FilterGeneric
filterGeneric
;
// convert argument(s) on the fly
/*lazy*/
FilterGeneric
filterGeneric
;
// convert argument(s) on the fly
/*lazy*/
MethodHandle
genericInvoker
;
// hook for in
vokeGeneric
/*lazy*/
MethodHandle
genericInvoker
;
// hook for in
exact invoke
public
MethodType
erasedType
()
{
public
MethodType
erasedType
()
{
return
erasedType
;
return
erasedType
;
...
@@ -460,9 +461,9 @@ class MethodTypeForm {
...
@@ -460,9 +461,9 @@ class MethodTypeForm {
if
(
genericInvoker
!=
null
)
return
;
if
(
genericInvoker
!=
null
)
return
;
try
{
try
{
// Trigger adapter creation.
// Trigger adapter creation.
genericInvoker
=
InvokeGeneric
.
gener
ic
InvokerOf
(
erasedType
);
genericInvoker
=
InvokeGeneric
.
gener
al
InvokerOf
(
erasedType
);
}
catch
(
Exception
ex
)
{
}
catch
(
Exception
ex
)
{
Error
err
=
new
InternalError
(
"Exception while resolving in
vokeGeneric
"
);
Error
err
=
new
InternalError
(
"Exception while resolving in
exact invoke
"
);
err
.
initCause
(
ex
);
err
.
initCause
(
ex
);
throw
err
;
throw
err
;
}
}
...
...
src/share/classes/java/lang/invoke/SpreadGeneric.java
浏览文件 @
8c50098c
...
@@ -66,6 +66,10 @@ class SpreadGeneric {
...
@@ -66,6 +66,10 @@ class SpreadGeneric {
this
.
entryPoint
=
ep
[
0
];
this
.
entryPoint
=
ep
[
0
];
}
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/** From targetType remove the last spreadCount arguments, and instead
/** From targetType remove the last spreadCount arguments, and instead
* append a simple Object argument.
* append a simple Object argument.
*/
*/
...
...
src/share/classes/java/lang/invoke/ToGeneric.java
浏览文件 @
8c50098c
...
@@ -96,7 +96,7 @@ class ToGeneric {
...
@@ -96,7 +96,7 @@ class ToGeneric {
ToGeneric
va2
=
ToGeneric
.
of
(
primsAtEnd
);
ToGeneric
va2
=
ToGeneric
.
of
(
primsAtEnd
);
this
.
adapter
=
va2
.
adapter
;
this
.
adapter
=
va2
.
adapter
;
if
(
true
)
throw
new
UnsupportedOperationException
(
"NYI: primitive parameters must follow references; entryType = "
+
entryType
);
if
(
true
)
throw
new
UnsupportedOperationException
(
"NYI: primitive parameters must follow references; entryType = "
+
entryType
);
this
.
entryPoint
=
MethodHandleImpl
.
convert
Arguments
(
this
.
entryPoint
=
MethodHandleImpl
.
permute
Arguments
(
va2
.
entryPoint
,
primsAtEnd
,
entryType
,
primsAtEndOrder
);
va2
.
entryPoint
,
primsAtEnd
,
entryType
,
primsAtEndOrder
);
// example: for entryType of (int,Object,Object), the reordered
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
// type is (Object,Object,int) and the order is {1,2,0},
...
@@ -128,7 +128,7 @@ class ToGeneric {
...
@@ -128,7 +128,7 @@ class ToGeneric {
assert
(
eptWithInts
.
parameterType
(
i
)
==
int
.
class
);
assert
(
eptWithInts
.
parameterType
(
i
)
==
int
.
class
);
MethodType
nextType
=
midType
.
changeParameterType
(
i
,
int
.
class
);
MethodType
nextType
=
midType
.
changeParameterType
(
i
,
int
.
class
);
rawEntryPoint
=
MethodHandleImpl
.
convertArguments
(
rawEntryPoint
=
MethodHandleImpl
.
convertArguments
(
rawEntryPoint
,
nextType
,
midType
,
null
);
rawEntryPoint
,
nextType
,
midType
,
0
);
midType
=
nextType
;
midType
=
nextType
;
}
}
}
}
...
@@ -152,6 +152,10 @@ class ToGeneric {
...
@@ -152,6 +152,10 @@ class ToGeneric {
this
.
invoker
=
makeRawArgumentFilter
(
invoker0
,
rawEntryTypeInit
,
entryType
);
this
.
invoker
=
makeRawArgumentFilter
(
invoker0
,
rawEntryTypeInit
,
entryType
);
}
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/** A generic argument list will be created by a call of type 'raw'.
/** A generic argument list will be created by a call of type 'raw'.
* The values need to be reboxed for to match 'cooked'.
* The values need to be reboxed for to match 'cooked'.
* Do this on the fly.
* Do this on the fly.
...
@@ -171,7 +175,7 @@ class ToGeneric {
...
@@ -171,7 +175,7 @@ class ToGeneric {
invoker
.
type
().
generic
(),
invoker
,
0
,
MethodHandle
.
class
);
invoker
.
type
().
generic
(),
invoker
,
0
,
MethodHandle
.
class
);
if
(
filteredInvoker
==
null
)
throw
new
UnsupportedOperationException
(
"NYI"
);
if
(
filteredInvoker
==
null
)
throw
new
UnsupportedOperationException
(
"NYI"
);
}
}
MethodHandle
reboxer
=
ValueConversions
.
rebox
(
dst
,
false
);
MethodHandle
reboxer
=
ValueConversions
.
rebox
(
dst
);
filteredInvoker
=
FilterGeneric
.
makeArgumentFilter
(
1
+
i
,
reboxer
,
filteredInvoker
);
filteredInvoker
=
FilterGeneric
.
makeArgumentFilter
(
1
+
i
,
reboxer
,
filteredInvoker
);
if
(
filteredInvoker
==
null
)
throw
new
InternalError
();
if
(
filteredInvoker
==
null
)
throw
new
InternalError
();
}
}
...
@@ -199,13 +203,13 @@ class ToGeneric {
...
@@ -199,13 +203,13 @@ class ToGeneric {
assert
(!
rret
.
isPrimitive
());
assert
(!
rret
.
isPrimitive
());
if
(
rret
==
Object
.
class
&&
!
mustCast
)
if
(
rret
==
Object
.
class
&&
!
mustCast
)
return
null
;
return
null
;
return
ValueConversions
.
cast
(
tret
,
false
);
return
ValueConversions
.
cast
(
tret
);
}
else
if
(
tret
==
rret
)
{
}
else
if
(
tret
==
rret
)
{
return
ValueConversions
.
unbox
(
tret
,
false
);
return
ValueConversions
.
unbox
(
tret
);
}
else
{
}
else
{
assert
(
rret
.
isPrimitive
());
assert
(
rret
.
isPrimitive
());
assert
(
tret
==
double
.
class
?
rret
==
long
.
class
:
rret
==
int
.
class
);
assert
(
tret
==
double
.
class
?
rret
==
long
.
class
:
rret
==
int
.
class
);
return
ValueConversions
.
unboxRaw
(
tret
,
false
);
return
ValueConversions
.
unboxRaw
(
tret
);
}
}
}
}
...
@@ -311,7 +315,7 @@ class ToGeneric {
...
@@ -311,7 +315,7 @@ class ToGeneric {
}
}
static
Adapter
buildAdapterFromBytecodes
(
MethodType
entryPointType
)
{
static
Adapter
buildAdapterFromBytecodes
(
MethodType
entryPointType
)
{
throw
new
UnsupportedOperationException
(
"NYI
"
);
throw
new
UnsupportedOperationException
(
"NYI
: "
+
entryPointType
);
}
}
/**
/**
...
...
src/share/classes/java/lang/invoke/package-info.java
浏览文件 @
8c50098c
...
@@ -185,7 +185,7 @@
...
@@ -185,7 +185,7 @@
* The method handle constant produced for such a method behaves as if
* The method handle constant produced for such a method behaves as if
* it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code
invokeGeneric
}.
* when invoked via {@code
MethodHandle.invoke
}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
* as if the {@code varargs} bit were not set.
* as if the {@code varargs} bit were not set.
* <p>
* <p>
...
@@ -243,7 +243,7 @@
...
@@ -243,7 +243,7 @@
* <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
* <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* </ul>
* The method handle is then applied to the other values as if by
* The method handle is then applied to the other values as if by
* {@link java.lang.invoke.MethodHandle#invoke
Generic invokeGeneric
}.
* {@link java.lang.invoke.MethodHandle#invoke
MethodHandle.invoke
}.
* The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
* 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
* The type of the call site's target must be exactly equal to the type
* derived from the dynamic call site's type descriptor and passed to
* derived from the dynamic call site's type descriptor and passed to
...
@@ -251,7 +251,7 @@
...
@@ -251,7 +251,7 @@
* The call site then becomes permanently linked to the dynamic call site.
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* <p>
* As long as each bootstrap method can be correctly invoked
* As long as each bootstrap method can be correctly invoked
* by <code>
invokeGeneric
</code>, its detailed type is arbitrary.
* by <code>
MethodHandle.invoke
</code>, its detailed type is arbitrary.
* For example, the first argument could be {@code Object}
* For example, the first argument could be {@code Object}
* instead of {@code MethodHandles.Lookup}, and the return type
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
* could also be {@code Object} instead of {@code CallSite}.
...
@@ -272,7 +272,7 @@
...
@@ -272,7 +272,7 @@
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
* <li>the bootstrap method has the wrong arity,
* <li>the bootstrap method has the wrong arity,
* causing {@code
invokeGeneric
} to throw {@code WrongMethodTypeException} </li>
* 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 has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* <li>the result from the bootstrap invocation is not a reference to
...
@@ -381,10 +381,10 @@
...
@@ -381,10 +381,10 @@
* those values will be passed as additional arguments to the method handle.
* 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,
* (Note that because there is a limit of 255 arguments to any method,
* at most 252 extra arguments can be supplied.)
* at most 252 extra arguments can be supplied.)
* The bootstrap method will be invoked as if by either {@code
invokeGeneric
}
* The bootstrap method will be invoked as if by either {@code
MethodHandle.invoke
}
* or {@code invokeWithArguments}. (There is no way to tell the difference.)
* or {@code invokeWithArguments}. (There is no way to tell the difference.)
* <p>
* <p>
* The normal argument conversion rules for {@code
invokeGeneric
} apply to all stacked arguments.
* The normal argument conversion rules for {@code
MethodHandle.invoke
} apply to all stacked arguments.
* For example, if a pushed value is a primitive type, it may be converted to a reference by boxing conversion.
* For example, if a pushed value is a primitive type, it may be converted to a reference by boxing conversion.
* If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
* If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
* then some or all of the arguments specified here may be collected into a trailing array parameter.
* then some or all of the arguments specified here may be collected into a trailing array parameter.
...
@@ -419,8 +419,8 @@
...
@@ -419,8 +419,8 @@
* For example, the fourth argument could be {@code MethodHandle},
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
* if that is the type of the corresponding constant in
* the {@code CONSTANT_InvokeDynamic} entry.
* the {@code CONSTANT_InvokeDynamic} entry.
* In that case, the {@code
invokeGeneric
} call will pass the extra method handle
* In that case, the {@code
MethodHandle.invoke
} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code
invokeGeneric
}
* constant as an {@code Object}, but the type matching machinery of {@code
MethodHandle.invoke
}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail,
* (If a string constant were passed instead, by badly generated code, that cast would then fail,
* resulting in a {@code BootstrapMethodError}.)
* resulting in a {@code BootstrapMethodError}.)
...
...
src/share/classes/javax/imageio/metadata/doc-files/jpeg_metadata.html
浏览文件 @
8c50098c
...
@@ -211,6 +211,20 @@ to any listeners.
...
@@ -211,6 +211,20 @@ to any listeners.
<p>
<p>
<a
name=
optcolor
><b>
Optional ColorSpace support:
</b></a>
Handling of PhotoYCC (YCC), PhotoYCCA (YCCA), RGBA and YCbCrA color spaces
by the standard plugin, as described below, is dependent on capabilities
of the libraries used to interpret the JPEG data. Thus all consequential
behaviors are optional. If the support is not available when decoding,
the color space will be treated as unrecognized and the appropriate
default color space for the specified number of component channels
may be used.
When writing, an Exception may be thrown if no suitable conversion
can be applied before encoding.
But where the support for these color spaces is available, the behavior
must be as documented.
<p>
When reading, the contents of the stream are interpreted by the usual
When reading, the contents of the stream are interpreted by the usual
JPEG conventions, as follows:
JPEG conventions, as follows:
...
@@ -241,8 +255,11 @@ JPEG conventions, as follows:
...
@@ -241,8 +255,11 @@ JPEG conventions, as follows:
2-channel images are assumed to be grayscale with an alpha channel.
2-channel images are assumed to be grayscale with an alpha channel.
For 3- and 4-channel images, the component ids are consulted. If these
For 3- and 4-channel images, the component ids are consulted. If these
values are 1-3 for a 3-channel image, then the image is assumed to be
values are 1-3 for a 3-channel image, then the image is assumed to be
YCbCr. If these values are 1-4 for a 4-channel image, then the image
YCbCr. Subject to the availability of the
is assumed to be YCbCrA. If these values are > 4, they are checked
<a
href=
#optcolor
>
optional color space support
</a>
described above, if these values are 1-4 for a 4-channel image,
then the image is assumed to be YCbCrA.
If these values are > 4, they are checked
against the ASCII codes for 'R', 'G', 'B', 'A', 'C', 'c'. These can
against the ASCII codes for 'R', 'G', 'B', 'A', 'C', 'c'. These can
encode the following colorspaces:
encode the following colorspaces:
<p>
<p>
...
@@ -346,12 +363,16 @@ If no metadata object is specified, then the following defaults apply:
...
@@ -346,12 +363,16 @@ If no metadata object is specified, then the following defaults apply:
component ids in the frame and scan headers are set to 1, 2, and 3.
component ids in the frame and scan headers are set to 1, 2, and 3.
<li>
RGBA images are converted to YCbCrA, subsampled in the
<li>
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
RGBA images are converted to YCbCrA, subsampled in the
chrominance channels by half both vertically and horizontally, and
chrominance channels by half both vertically and horizontally, and
written without any special marker segments. The component ids
written without any special marker segments. The component ids
in the frame and scan headers are set to 1, 2, 3, and 4.
in the frame and scan headers are set to 1, 2, 3, and 4.
<li>
PhotoYCC and YCCAimages are subsampled by half in the chrominance
<li>
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
PhotoYCC and YCCAimages are subsampled by half in the chrominance
channels both vertically and horizontally and written with an
channels both vertically and horizontally and written with an
Adobe
<code>
APP14
</code>
marker segment and 'Y','C', and 'c' (and
Adobe
<code>
APP14
</code>
marker segment and 'Y','C', and 'c' (and
'A' if an alpha channel is present) as component ids in the frame
'A' if an alpha channel is present) as component ids in the frame
...
@@ -433,6 +454,8 @@ in the frame header node of the metadata object, regardless of color space.)
...
@@ -433,6 +454,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
</ul>
<li>
RGBA images:
<li>
RGBA images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<ul>
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
it is ignored and a warning is sent to listeners, as JFIF does not
it is ignored and a warning is sent to listeners, as JFIF does not
...
@@ -456,6 +479,8 @@ in the frame header node of the metadata object, regardless of color space.)
...
@@ -456,6 +479,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
</ul>
<li>
PhotoYCC Images:
<li>
PhotoYCC Images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<ul>
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
the image is converted to sRGB, and then to YCbCr during encoding,
the image is converted to sRGB, and then to YCbCr during encoding,
...
@@ -471,6 +496,8 @@ in the frame header node of the metadata object, regardless of color space.)
...
@@ -471,6 +496,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
</ul>
<li>
PhotoYCCA Images:
<li>
PhotoYCCA Images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<ul>
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
<li>
If an
<code>
app0JFIF
</code>
node is present in the metadata object,
it is ignored and a warning is sent to listeners, as JFIF does not
it is ignored and a warning is sent to listeners, as JFIF does not
...
...
src/share/classes/javax/swing/ComboBoxModel.java
浏览文件 @
8c50098c
...
@@ -33,9 +33,11 @@ package javax.swing;
...
@@ -33,9 +33,11 @@ package javax.swing;
* <code>ListModel</code>. This disjoint behavior allows for the temporary
* <code>ListModel</code>. This disjoint behavior allows for the temporary
* storage and retrieval of a selected item in the model.
* storage and retrieval of a selected item in the model.
*
*
* @param <E> the type of the elements of this model
*
* @author Arnaud Weber
* @author Arnaud Weber
*/
*/
public
interface
ComboBoxModel
extends
ListModel
{
public
interface
ComboBoxModel
<
E
>
extends
ListModel
<
E
>
{
/**
/**
* Set the selected item. The implementation of this method should notify
* Set the selected item. The implementation of this method should notify
...
...
src/share/classes/javax/swing/DefaultComboBoxModel.java
浏览文件 @
8c50098c
...
@@ -24,39 +24,28 @@
...
@@ -24,39 +24,28 @@
*/
*/
package
javax.swing
;
package
javax.swing
;
import
java.beans.*
;
import
java.util.*
;
import
java.util.*
;
import
java.awt.*
;
import
java.awt.event.*
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
java.io.ObjectOutputStream
;
import
java.io.ObjectInputStream
;
import
java.io.IOException
;
import
javax.swing.event.*
;
import
javax.swing.plaf.*
;
import
javax.swing.border.*
;
import
javax.accessibility.*
;
/**
/**
* The default model for combo boxes.
* The default model for combo boxes.
*
*
* @param <E> the type of the elements of this model
*
* @author Arnaud Weber
* @author Arnaud Weber
* @author Tom Santos
* @author Tom Santos
*/
*/
public
class
DefaultComboBoxModel
extends
AbstractListModel
implements
MutableComboBoxModel
,
Serializable
{
public
class
DefaultComboBoxModel
<
E
>
extends
AbstractListModel
<
E
>
implements
MutableComboBoxModel
<
E
>
,
Serializable
{
Vector
objects
;
Vector
<
E
>
objects
;
Object
selectedObject
;
Object
selectedObject
;
/**
/**
* Constructs an empty DefaultComboBoxModel object.
* Constructs an empty DefaultComboBoxModel object.
*/
*/
public
DefaultComboBoxModel
()
{
public
DefaultComboBoxModel
()
{
objects
=
new
Vector
();
objects
=
new
Vector
<
E
>
();
}
}
/**
/**
...
@@ -65,8 +54,8 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
...
@@ -65,8 +54,8 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
*
*
* @param items an array of Object objects
* @param items an array of Object objects
*/
*/
public
DefaultComboBoxModel
(
final
Object
items
[])
{
public
DefaultComboBoxModel
(
final
E
items
[])
{
objects
=
new
Vector
();
objects
=
new
Vector
<
E
>
();
objects
.
ensureCapacity
(
items
.
length
);
objects
.
ensureCapacity
(
items
.
length
);
int
i
,
c
;
int
i
,
c
;
...
@@ -84,7 +73,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
...
@@ -84,7 +73,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
*
*
* @param v a Vector object ...
* @param v a Vector object ...
*/
*/
public
DefaultComboBoxModel
(
Vector
<
?
>
v
)
{
public
DefaultComboBoxModel
(
Vector
<
E
>
v
)
{
objects
=
v
;
objects
=
v
;
if
(
getSize
()
>
0
)
{
if
(
getSize
()
>
0
)
{
...
@@ -117,7 +106,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
...
@@ -117,7 +106,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
}
// implements javax.swing.ListModel
// implements javax.swing.ListModel
public
Object
getElementAt
(
int
index
)
{
public
E
getElementAt
(
int
index
)
{
if
(
index
>=
0
&&
index
<
objects
.
size
()
)
if
(
index
>=
0
&&
index
<
objects
.
size
()
)
return
objects
.
elementAt
(
index
);
return
objects
.
elementAt
(
index
);
else
else
...
@@ -136,7 +125,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
...
@@ -136,7 +125,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
}
// implements javax.swing.MutableComboBoxModel
// implements javax.swing.MutableComboBoxModel
public
void
addElement
(
Object
anObject
)
{
public
void
addElement
(
E
anObject
)
{
objects
.
addElement
(
anObject
);
objects
.
addElement
(
anObject
);
fireIntervalAdded
(
this
,
objects
.
size
()-
1
,
objects
.
size
()-
1
);
fireIntervalAdded
(
this
,
objects
.
size
()-
1
,
objects
.
size
()-
1
);
if
(
objects
.
size
()
==
1
&&
selectedObject
==
null
&&
anObject
!=
null
)
{
if
(
objects
.
size
()
==
1
&&
selectedObject
==
null
&&
anObject
!=
null
)
{
...
@@ -145,7 +134,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
...
@@ -145,7 +134,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
}
// implements javax.swing.MutableComboBoxModel
// implements javax.swing.MutableComboBoxModel
public
void
insertElementAt
(
Object
anObject
,
int
index
)
{
public
void
insertElementAt
(
E
anObject
,
int
index
)
{
objects
.
insertElementAt
(
anObject
,
index
);
objects
.
insertElementAt
(
anObject
,
index
);
fireIntervalAdded
(
this
,
index
,
index
);
fireIntervalAdded
(
this
,
index
,
index
);
}
}
...
...
src/share/classes/javax/swing/JComboBox.java
浏览文件 @
8c50098c
...
@@ -69,6 +69,8 @@ import javax.accessibility.*;
...
@@ -69,6 +69,8 @@ import javax.accessibility.*;
* @see ComboBoxModel
* @see ComboBoxModel
* @see DefaultComboBoxModel
* @see DefaultComboBoxModel
*
*
* @param <E> the type of the elements of this combo box
*
* @beaninfo
* @beaninfo
* attribute: isContainer false
* attribute: isContainer false
* description: A combination of a text field and a drop-down list.
* description: A combination of a text field and a drop-down list.
...
@@ -76,7 +78,7 @@ import javax.accessibility.*;
...
@@ -76,7 +78,7 @@ import javax.accessibility.*;
* @author Arnaud Weber
* @author Arnaud Weber
* @author Mark Davidson
* @author Mark Davidson
*/
*/
public
class
JComboBox
extends
JComponent
public
class
JComboBox
<
E
>
extends
JComponent
implements
ItemSelectable
,
ListDataListener
,
ActionListener
,
Accessible
{
implements
ItemSelectable
,
ListDataListener
,
ActionListener
,
Accessible
{
/**
/**
* @see #getUIClassID
* @see #getUIClassID
...
@@ -91,7 +93,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -91,7 +93,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #getModel
* @see #getModel
* @see #setModel
* @see #setModel
*/
*/
protected
ComboBoxModel
dataModel
;
protected
ComboBoxModel
<
E
>
dataModel
;
/**
/**
* This protected field is implementation specific. Do not access directly
* This protected field is implementation specific. Do not access directly
* or override. Use the accessor methods instead.
* or override. Use the accessor methods instead.
...
@@ -99,7 +101,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -99,7 +101,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #getRenderer
* @see #getRenderer
* @see #setRenderer
* @see #setRenderer
*/
*/
protected
ListCellRenderer
renderer
;
protected
ListCellRenderer
<?
super
E
>
renderer
;
/**
/**
* This protected field is implementation specific. Do not access directly
* This protected field is implementation specific. Do not access directly
* or override. Use the accessor methods instead.
* or override. Use the accessor methods instead.
...
@@ -156,7 +158,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -156,7 +158,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
*/
protected
Object
selectedItemReminder
=
null
;
protected
Object
selectedItemReminder
=
null
;
private
Object
prototypeDisplayValue
;
private
E
prototypeDisplayValue
;
// Flag to ensure that infinite loops do not occur with ActionEvents.
// Flag to ensure that infinite loops do not occur with ActionEvents.
private
boolean
firingActionEvent
=
false
;
private
boolean
firingActionEvent
=
false
;
...
@@ -175,7 +177,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -175,7 +177,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* displayed list of items
* displayed list of items
* @see DefaultComboBoxModel
* @see DefaultComboBoxModel
*/
*/
public
JComboBox
(
ComboBoxModel
aModel
)
{
public
JComboBox
(
ComboBoxModel
<
E
>
aModel
)
{
super
();
super
();
setModel
(
aModel
);
setModel
(
aModel
);
init
();
init
();
...
@@ -189,9 +191,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -189,9 +191,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @param items an array of objects to insert into the combo box
* @param items an array of objects to insert into the combo box
* @see DefaultComboBoxModel
* @see DefaultComboBoxModel
*/
*/
public
JComboBox
(
final
Object
items
[]
)
{
public
JComboBox
(
E
[]
items
)
{
super
();
super
();
setModel
(
new
DefaultComboBoxModel
(
items
));
setModel
(
new
DefaultComboBoxModel
<
E
>
(
items
));
init
();
init
();
}
}
...
@@ -203,9 +205,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -203,9 +205,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @param items an array of vectors to insert into the combo box
* @param items an array of vectors to insert into the combo box
* @see DefaultComboBoxModel
* @see DefaultComboBoxModel
*/
*/
public
JComboBox
(
Vector
<
?
>
items
)
{
public
JComboBox
(
Vector
<
E
>
items
)
{
super
();
super
();
setModel
(
new
DefaultComboBoxModel
(
items
));
setModel
(
new
DefaultComboBoxModel
<
E
>
(
items
));
init
();
init
();
}
}
...
@@ -219,7 +221,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -219,7 +221,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
*/
public
JComboBox
()
{
public
JComboBox
()
{
super
();
super
();
setModel
(
new
DefaultComboBoxModel
());
setModel
(
new
DefaultComboBoxModel
<
E
>
());
init
();
init
();
}
}
...
@@ -263,7 +265,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -263,7 +265,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
public
void
updateUI
()
{
public
void
updateUI
()
{
setUI
((
ComboBoxUI
)
UIManager
.
getUI
(
this
));
setUI
((
ComboBoxUI
)
UIManager
.
getUI
(
this
));
ListCellRenderer
renderer
=
getRenderer
();
ListCellRenderer
<?
super
E
>
renderer
=
getRenderer
();
if
(
renderer
instanceof
Component
)
{
if
(
renderer
instanceof
Component
)
{
SwingUtilities
.
updateComponentTreeUI
((
Component
)
renderer
);
SwingUtilities
.
updateComponentTreeUI
((
Component
)
renderer
);
}
}
...
@@ -302,8 +304,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -302,8 +304,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* bound: true
* bound: true
* description: Model that the combo box uses to get data to display.
* description: Model that the combo box uses to get data to display.
*/
*/
public
void
setModel
(
ComboBoxModel
aModel
)
{
public
void
setModel
(
ComboBoxModel
<
E
>
aModel
)
{
ComboBoxModel
oldModel
=
dataModel
;
ComboBoxModel
<
E
>
oldModel
=
dataModel
;
if
(
oldModel
!=
null
)
{
if
(
oldModel
!=
null
)
{
oldModel
.
removeListDataListener
(
this
);
oldModel
.
removeListDataListener
(
this
);
}
}
...
@@ -322,7 +324,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -322,7 +324,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @return the <code>ComboBoxModel</code> that provides the displayed
* @return the <code>ComboBoxModel</code> that provides the displayed
* list of items
* list of items
*/
*/
public
ComboBoxModel
getModel
()
{
public
ComboBoxModel
<
E
>
getModel
()
{
return
dataModel
;
return
dataModel
;
}
}
...
@@ -461,8 +463,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -461,8 +463,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* expert: true
* expert: true
* description: The renderer that paints the item selected in the list.
* description: The renderer that paints the item selected in the list.
*/
*/
public
void
setRenderer
(
ListCellRenderer
aRenderer
)
{
public
void
setRenderer
(
ListCellRenderer
<?
super
E
>
aRenderer
)
{
ListCellRenderer
oldRenderer
=
renderer
;
ListCellRenderer
<?
super
E
>
oldRenderer
=
renderer
;
renderer
=
aRenderer
;
renderer
=
aRenderer
;
firePropertyChange
(
"renderer"
,
oldRenderer
,
renderer
);
firePropertyChange
(
"renderer"
,
oldRenderer
,
renderer
);
invalidate
();
invalidate
();
...
@@ -475,7 +477,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -475,7 +477,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @return the <code>ListCellRenderer</code> that displays
* @return the <code>ListCellRenderer</code> that displays
* the selected item.
* the selected item.
*/
*/
public
ListCellRenderer
getRenderer
()
{
public
ListCellRenderer
<?
super
E
>
getRenderer
()
{
return
renderer
;
return
renderer
;
}
}
...
@@ -558,7 +560,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -558,7 +560,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
// will be rejected.
// will be rejected.
boolean
found
=
false
;
boolean
found
=
false
;
for
(
int
i
=
0
;
i
<
dataModel
.
getSize
();
i
++)
{
for
(
int
i
=
0
;
i
<
dataModel
.
getSize
();
i
++)
{
Object
element
=
dataModel
.
getElementAt
(
i
);
E
element
=
dataModel
.
getElementAt
(
i
);
if
(
anObject
.
equals
(
element
))
{
if
(
anObject
.
equals
(
element
))
{
found
=
true
;
found
=
true
;
objectToSelect
=
element
;
objectToSelect
=
element
;
...
@@ -640,7 +642,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -640,7 +642,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
public
int
getSelectedIndex
()
{
public
int
getSelectedIndex
()
{
Object
sObject
=
dataModel
.
getSelectedItem
();
Object
sObject
=
dataModel
.
getSelectedItem
();
int
i
,
c
;
int
i
,
c
;
Object
obj
;
E
obj
;
for
(
i
=
0
,
c
=
dataModel
.
getSize
();
i
<
c
;
i
++
)
{
for
(
i
=
0
,
c
=
dataModel
.
getSize
();
i
<
c
;
i
++
)
{
obj
=
dataModel
.
getElementAt
(
i
);
obj
=
dataModel
.
getElementAt
(
i
);
...
@@ -658,7 +660,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -658,7 +660,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #setPrototypeDisplayValue
* @see #setPrototypeDisplayValue
* @since 1.4
* @since 1.4
*/
*/
public
Object
getPrototypeDisplayValue
()
{
public
E
getPrototypeDisplayValue
()
{
return
prototypeDisplayValue
;
return
prototypeDisplayValue
;
}
}
...
@@ -683,7 +685,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -683,7 +685,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* attribute: visualUpdate true
* attribute: visualUpdate true
* description: The display prototype value, used to compute display width and height.
* description: The display prototype value, used to compute display width and height.
*/
*/
public
void
setPrototypeDisplayValue
(
Object
prototypeDisplayValue
)
{
public
void
setPrototypeDisplayValue
(
E
prototypeDisplayValue
)
{
Object
oldValue
=
this
.
prototypeDisplayValue
;
Object
oldValue
=
this
.
prototypeDisplayValue
;
this
.
prototypeDisplayValue
=
prototypeDisplayValue
;
this
.
prototypeDisplayValue
=
prototypeDisplayValue
;
firePropertyChange
(
"prototypeDisplayValue"
,
oldValue
,
prototypeDisplayValue
);
firePropertyChange
(
"prototypeDisplayValue"
,
oldValue
,
prototypeDisplayValue
);
...
@@ -708,12 +710,12 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -708,12 +710,12 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* }
* }
* </pre>
* </pre>
*
*
* @param
anObject the Object
to add to the list
* @param
item the item
to add to the list
* @see MutableComboBoxModel
* @see MutableComboBoxModel
*/
*/
public
void
addItem
(
Object
anObject
)
{
public
void
addItem
(
E
item
)
{
checkMutableComboBoxModel
();
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
addElement
(
anObject
);
((
MutableComboBoxModel
<
E
>)
dataModel
).
addElement
(
item
);
}
}
/**
/**
...
@@ -721,14 +723,14 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -721,14 +723,14 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* This method works only if the <code>JComboBox</code> uses a
* This method works only if the <code>JComboBox</code> uses a
* mutable data model.
* mutable data model.
*
*
* @param
anObject the <code>Object</code>
to add to the list
* @param
item the item
to add to the list
* @param index an integer specifying the position at which
* @param index an integer specifying the position at which
* to add the item
* to add the item
* @see MutableComboBoxModel
* @see MutableComboBoxModel
*/
*/
public
void
insertItemAt
(
Object
anObject
,
int
index
)
{
public
void
insertItemAt
(
E
item
,
int
index
)
{
checkMutableComboBoxModel
();
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
insertElementAt
(
anObject
,
index
);
((
MutableComboBoxModel
<
E
>)
dataModel
).
insertElementAt
(
item
,
index
);
}
}
/**
/**
...
@@ -756,7 +758,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -756,7 +758,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
*/
public
void
removeItemAt
(
int
anIndex
)
{
public
void
removeItemAt
(
int
anIndex
)
{
checkMutableComboBoxModel
();
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
removeElementAt
(
anIndex
);
((
MutableComboBoxModel
<
E
>
)
dataModel
).
removeElementAt
(
anIndex
);
}
}
/**
/**
...
@@ -764,7 +766,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -764,7 +766,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
*/
public
void
removeAllItems
()
{
public
void
removeAllItems
()
{
checkMutableComboBoxModel
();
checkMutableComboBoxModel
();
MutableComboBoxModel
model
=
(
MutableComboBoxModel
)
dataModel
;
MutableComboBoxModel
<
E
>
model
=
(
MutableComboBoxModel
<
E
>
)
dataModel
;
int
size
=
model
.
getSize
();
int
size
=
model
.
getSize
();
if
(
model
instanceof
DefaultComboBoxModel
)
{
if
(
model
instanceof
DefaultComboBoxModel
)
{
...
@@ -772,7 +774,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -772,7 +774,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
}
}
else
{
else
{
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
Object
element
=
model
.
getElementAt
(
0
);
E
element
=
model
.
getElementAt
(
0
);
model
.
removeElement
(
element
);
model
.
removeElement
(
element
);
}
}
}
}
...
@@ -1188,11 +1190,11 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -1188,11 +1190,11 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
private
static
class
ComboBoxActionPropertyChangeListener
private
static
class
ComboBoxActionPropertyChangeListener
extends
ActionPropertyChangeListener
<
JComboBox
>
{
extends
ActionPropertyChangeListener
<
JComboBox
<?>
>
{
ComboBoxActionPropertyChangeListener
(
JComboBox
b
,
Action
a
)
{
ComboBoxActionPropertyChangeListener
(
JComboBox
<?>
b
,
Action
a
)
{
super
(
b
,
a
);
super
(
b
,
a
);
}
}
protected
void
actionPropertyChanged
(
JComboBox
cb
,
protected
void
actionPropertyChanged
(
JComboBox
<?>
cb
,
Action
action
,
Action
action
,
PropertyChangeEvent
e
)
{
PropertyChangeEvent
e
)
{
if
(
AbstractAction
.
shouldReconfigure
(
e
))
{
if
(
AbstractAction
.
shouldReconfigure
(
e
))
{
...
@@ -1454,10 +1456,10 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
...
@@ -1454,10 +1456,10 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*
*
* @param index an integer indicating the list position, where the first
* @param index an integer indicating the list position, where the first
* item starts at zero
* item starts at zero
* @return the
<code>Object</code>
at that list position; or
* @return the
item
at that list position; or
* <code>null</code> if out of range
* <code>null</code> if out of range
*/
*/
public
Object
getItemAt
(
int
index
)
{
public
E
getItemAt
(
int
index
)
{
return
dataModel
.
getElementAt
(
index
);
return
dataModel
.
getElementAt
(
index
);
}
}
...
...
src/share/classes/javax/swing/MutableComboBoxModel.java
浏览文件 @
8c50098c
...
@@ -27,19 +27,21 @@ package javax.swing;
...
@@ -27,19 +27,21 @@ package javax.swing;
/**
/**
* A mutable version of <code>ComboBoxModel</code>.
* A mutable version of <code>ComboBoxModel</code>.
*
*
* @param <E> the type of the elements of this model
*
* @author Tom Santos
* @author Tom Santos
*/
*/
public
interface
MutableComboBoxModel
extends
ComboBoxModel
{
public
interface
MutableComboBoxModel
<
E
>
extends
ComboBoxModel
<
E
>
{
/**
/**
* Adds an item at the end of the model. The implementation of this method
* Adds an item at the end of the model. The implementation of this method
* should notify all registered <code>ListDataListener</code>s that the
* should notify all registered <code>ListDataListener</code>s that the
* item has been added.
* item has been added.
*
*
* @param
obj the <code>Object</code>
to be added
* @param
item the item
to be added
*/
*/
public
void
addElement
(
Object
obj
);
public
void
addElement
(
E
item
);
/**
/**
* Removes an item from the model. The implementation of this method should
* Removes an item from the model. The implementation of this method should
...
@@ -55,17 +57,17 @@ public interface MutableComboBoxModel extends ComboBoxModel {
...
@@ -55,17 +57,17 @@ public interface MutableComboBoxModel extends ComboBoxModel {
* should notify all registered <code>ListDataListener</code>s that the
* should notify all registered <code>ListDataListener</code>s that the
* item has been added.
* item has been added.
*
*
* @param
obj the <code>Object</code>
to be added
* @param
item the item
to be added
* @param index location to add the object
* @param index location to add the object
*/
*/
public
void
insertElementAt
(
Object
obj
,
int
index
);
public
void
insertElementAt
(
E
item
,
int
index
);
/**
/**
* Removes an item at a specific index. The implementation of this method
* Removes an item at a specific index. The implementation of this method
* should notify all registered <code>ListDataListener</code>s that the
* should notify all registered <code>ListDataListener</code>s that the
* item has been removed.
* item has been removed.
*
*
* @param index location of
object
to be removed
* @param index location of
the item
to be removed
*/
*/
public
void
removeElementAt
(
int
index
);
public
void
removeElementAt
(
int
index
);
}
}
src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
浏览文件 @
8c50098c
...
@@ -40,7 +40,7 @@ import sun.awt.shell.ShellFolder;
...
@@ -40,7 +40,7 @@ import sun.awt.shell.ShellFolder;
*
*
* @author Jeff Dinkins
* @author Jeff Dinkins
*/
*/
public
class
BasicDirectoryModel
extends
AbstractListModel
implements
PropertyChangeListener
{
public
class
BasicDirectoryModel
extends
AbstractListModel
<
Object
>
implements
PropertyChangeListener
{
private
JFileChooser
filechooser
=
null
;
private
JFileChooser
filechooser
=
null
;
// PENDING(jeff) pick the size more sensibly
// PENDING(jeff) pick the size more sensibly
...
...
src/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java
浏览文件 @
8c50098c
...
@@ -906,7 +906,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI {
...
@@ -906,7 +906,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI {
/**
/**
* Data model for a type-face selection combo-box.
* Data model for a type-face selection combo-box.
*/
*/
protected
class
DirectoryComboBoxModel
extends
AbstractListModel
implements
ComboBoxModel
{
protected
class
DirectoryComboBoxModel
extends
AbstractListModel
<
Object
>
implements
ComboBoxModel
<
Object
>
{
Vector
<
File
>
directories
=
new
Vector
<
File
>();
Vector
<
File
>
directories
=
new
Vector
<
File
>();
int
[]
depths
=
null
;
int
[]
depths
=
null
;
File
selectedDirectory
=
null
;
File
selectedDirectory
=
null
;
...
@@ -1063,7 +1063,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI {
...
@@ -1063,7 +1063,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI {
/**
/**
* Data model for a type-face selection combo-box.
* Data model for a type-face selection combo-box.
*/
*/
protected
class
FilterComboBoxModel
extends
AbstractListModel
implements
ComboBoxModel
,
PropertyChangeListener
{
protected
class
FilterComboBoxModel
extends
AbstractListModel
<
Object
>
implements
ComboBoxModel
<
Object
>
,
PropertyChangeListener
{
protected
FileFilter
[]
filters
;
protected
FileFilter
[]
filters
;
protected
FilterComboBoxModel
()
{
protected
FilterComboBoxModel
()
{
super
();
super
();
...
...
src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
浏览文件 @
8c50098c
...
@@ -488,6 +488,18 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI
...
@@ -488,6 +488,18 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI
paintContentBorder
(
tabContentContext
,
g
,
tabPlacement
,
selectedIndex
);
paintContentBorder
(
tabContentContext
,
g
,
tabPlacement
,
selectedIndex
);
}
}
protected
void
paintTabArea
(
Graphics
g
,
int
tabPlacement
,
int
selectedIndex
)
{
// This can be invoked from ScrollabeTabPanel
Insets
insets
=
tabPane
.
getInsets
();
int
x
=
insets
.
left
;
int
y
=
insets
.
top
;
int
width
=
tabPane
.
getWidth
()
-
insets
.
left
-
insets
.
right
;
int
height
=
tabPane
.
getHeight
()
-
insets
.
top
-
insets
.
bottom
;
paintTabArea
(
tabAreaContext
,
g
,
tabPlacement
,
selectedIndex
,
new
Rectangle
(
x
,
y
,
width
,
height
));
}
private
void
paintTabArea
(
SynthContext
ss
,
Graphics
g
,
private
void
paintTabArea
(
SynthContext
ss
,
Graphics
g
,
int
tabPlacement
,
int
selectedIndex
,
int
tabPlacement
,
int
selectedIndex
,
...
...
src/share/classes/sun/invoke/util/ValueConversions.java
浏览文件 @
8c50098c
...
@@ -31,10 +31,15 @@ import java.lang.invoke.MethodHandles.Lookup;
...
@@ -31,10 +31,15 @@ import java.lang.invoke.MethodHandles.Lookup;
import
java.lang.invoke.MethodType
;
import
java.lang.invoke.MethodType
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.EnumMap
;
import
java.util.EnumMap
;
import
java.util.List
;
import
java.util.List
;
public
class
ValueConversions
{
public
class
ValueConversions
{
private
static
final
Class
<?>
THIS_CLASS
=
ValueConversions
.
class
;
// Do not adjust this except for special platforms:
private
static
final
int
MAX_ARITY
=
Integer
.
getInteger
(
THIS_CLASS
.
getName
()+
".MAX_ARITY"
,
255
);
private
static
final
Lookup
IMPL_LOOKUP
=
MethodHandles
.
lookup
();
private
static
final
Lookup
IMPL_LOOKUP
=
MethodHandles
.
lookup
();
private
static
EnumMap
<
Wrapper
,
MethodHandle
>[]
newWrapperCaches
(
int
n
)
{
private
static
EnumMap
<
Wrapper
,
MethodHandle
>[]
newWrapperCaches
(
int
n
)
{
...
@@ -42,88 +47,101 @@ public class ValueConversions {
...
@@ -42,88 +47,101 @@ public class ValueConversions {
EnumMap
<
Wrapper
,
MethodHandle
>[]
caches
EnumMap
<
Wrapper
,
MethodHandle
>[]
caches
=
(
EnumMap
<
Wrapper
,
MethodHandle
>[])
new
EnumMap
[
n
];
// unchecked warning expected here
=
(
EnumMap
<
Wrapper
,
MethodHandle
>[])
new
EnumMap
[
n
];
// unchecked warning expected here
for
(
int
i
=
0
;
i
<
n
;
i
++)
for
(
int
i
=
0
;
i
<
n
;
i
++)
caches
[
i
]
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
caches
[
i
]
=
new
EnumMap
<>(
Wrapper
.
class
);
return
caches
;
return
caches
;
}
}
/// Converting references to values.
/// Converting references to values.
static
int
unboxInteger
(
Object
x
)
{
// There are several levels of this unboxing conversions:
if
(
x
==
null
)
return
0
;
// never NPE
// no conversions: exactly Integer.valueOf, etc.
return
((
Integer
)
x
).
intValue
();
// implicit conversions sanctioned by JLS 5.1.2, etc.
// explicit conversions as allowed by explicitCastArguments
static
int
unboxInteger
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Integer
)
return
((
Integer
)
x
).
intValue
();
return
primitiveConversion
(
Wrapper
.
INT
,
x
,
cast
).
intValue
();
}
}
static
byte
unboxByte
(
Object
x
)
{
static
byte
unboxByte
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Byte
)
return
((
Byte
)
x
).
byteValue
();
return
((
Byte
)
x
).
byteValue
();
return
primitiveConversion
(
Wrapper
.
BYTE
,
x
,
cast
).
byteValue
();
}
}
static
short
unboxShort
(
Object
x
)
{
static
short
unboxShort
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Short
)
return
((
Short
)
x
).
shortValue
();
return
((
Short
)
x
).
shortValue
();
return
primitiveConversion
(
Wrapper
.
SHORT
,
x
,
cast
).
shortValue
();
}
}
static
boolean
unboxBoolean
(
Object
x
)
{
static
boolean
unboxBoolean
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
false
;
// never NPE
if
(
x
instanceof
Boolean
)
return
((
Boolean
)
x
).
booleanValue
();
return
((
Boolean
)
x
).
booleanValue
();
return
(
primitiveConversion
(
Wrapper
.
BOOLEAN
,
x
,
cast
).
intValue
()
&
1
)
!=
0
;
}
}
static
char
unboxCharacter
(
Object
x
)
{
static
char
unboxCharacter
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Character
)
return
((
Character
)
x
).
charValue
();
return
((
Character
)
x
).
charValue
();
return
(
char
)
primitiveConversion
(
Wrapper
.
CHAR
,
x
,
cast
).
intValue
();
}
}
static
long
unboxLong
(
Object
x
)
{
static
long
unboxLong
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Long
)
return
((
Long
)
x
).
longValue
();
return
((
Long
)
x
).
longValue
();
return
primitiveConversion
(
Wrapper
.
LONG
,
x
,
cast
).
longValue
();
}
}
static
float
unboxFloat
(
Object
x
)
{
static
float
unboxFloat
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Float
)
return
((
Float
)
x
).
floatValue
();
return
((
Float
)
x
).
floatValue
();
return
primitiveConversion
(
Wrapper
.
FLOAT
,
x
,
cast
).
floatValue
();
}
}
static
double
unboxDouble
(
Object
x
)
{
static
double
unboxDouble
(
Object
x
,
boolean
cast
)
{
if
(
x
==
null
)
return
0
;
// never NPE
if
(
x
instanceof
Double
)
return
((
Double
)
x
).
doubleValue
();
return
((
Double
)
x
).
doubleValue
();
return
primitiveConversion
(
Wrapper
.
DOUBLE
,
x
,
cast
).
doubleValue
();
}
}
/// Converting references to "raw" values.
/// Converting references to "raw" values.
/// A raw primitive value is always an int or long.
/// A raw primitive value is always an int or long.
static
int
unboxByteRaw
(
Object
x
)
{
static
int
unboxByteRaw
(
Object
x
,
boolean
cast
)
{
return
unboxByte
(
x
);
return
unboxByte
(
x
,
cast
);
}
}
static
int
unboxShortRaw
(
Object
x
)
{
static
int
unboxShortRaw
(
Object
x
,
boolean
cast
)
{
return
unboxShort
(
x
);
return
unboxShort
(
x
,
cast
);
}
}
static
int
unboxBooleanRaw
(
Object
x
)
{
static
int
unboxBooleanRaw
(
Object
x
,
boolean
cast
)
{
return
unboxBoolean
(
x
)
?
1
:
0
;
return
unboxBoolean
(
x
,
cast
)
?
1
:
0
;
}
}
static
int
unboxCharacterRaw
(
Object
x
)
{
static
int
unboxCharacterRaw
(
Object
x
,
boolean
cast
)
{
return
unboxCharacter
(
x
);
return
unboxCharacter
(
x
,
cast
);
}
}
static
int
unboxFloatRaw
(
Object
x
)
{
static
int
unboxFloatRaw
(
Object
x
,
boolean
cast
)
{
return
Float
.
floatToIntBits
(
unboxFloat
(
x
));
return
Float
.
floatToIntBits
(
unboxFloat
(
x
,
cast
));
}
}
static
long
unboxDoubleRaw
(
Object
x
)
{
static
long
unboxDoubleRaw
(
Object
x
,
boolean
cast
)
{
return
Double
.
doubleToRawLongBits
(
unboxDouble
(
x
));
return
Double
.
doubleToRawLongBits
(
unboxDouble
(
x
,
cast
));
}
}
private
static
MethodType
unboxType
(
Wrapper
wrap
,
boolean
raw
)
{
private
static
MethodType
unboxType
(
Wrapper
wrap
,
boolean
raw
)
{
return
MethodType
.
methodType
(
rawWrapper
(
wrap
,
raw
).
primitiveType
(),
wrap
.
wrapperType
()
);
return
MethodType
.
methodType
(
rawWrapper
(
wrap
,
raw
).
primitiveType
(),
Object
.
class
,
boolean
.
class
);
}
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>[]
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>[]
UNBOX_CONVERSIONS
=
newWrapperCaches
(
4
);
UNBOX_CONVERSIONS
=
newWrapperCaches
(
4
);
private
static
MethodHandle
unbox
(
Wrapper
wrap
,
boolean
exact
,
boolean
raw
)
{
private
static
MethodHandle
unbox
(
Wrapper
wrap
,
boolean
raw
,
boolean
cast
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
UNBOX_CONVERSIONS
[(
exac
t
?
1
:
0
)+(
raw
?
2
:
0
)];
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
UNBOX_CONVERSIONS
[(
cas
t
?
1
:
0
)+(
raw
?
2
:
0
)];
MethodHandle
mh
=
cache
.
get
(
wrap
);
MethodHandle
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
{
if
(
mh
!=
null
)
{
return
mh
;
return
mh
;
...
@@ -136,7 +154,7 @@ public class ValueConversions {
...
@@ -136,7 +154,7 @@ public class ValueConversions {
mh
=
raw
?
ALWAYS_ZERO
:
IGNORE
;
break
;
mh
=
raw
?
ALWAYS_ZERO
:
IGNORE
;
break
;
case
INT:
case
LONG:
case
INT:
case
LONG:
// these guys don't need separate raw channels
// these guys don't need separate raw channels
if
(
raw
)
mh
=
unbox
(
wrap
,
exact
,
false
);
if
(
raw
)
mh
=
unbox
(
wrap
,
false
,
cast
);
break
;
break
;
}
}
if
(
mh
!=
null
)
{
if
(
mh
!=
null
)
{
...
@@ -146,37 +164,62 @@ public class ValueConversions {
...
@@ -146,37 +164,62 @@ public class ValueConversions {
// look up the method
// look up the method
String
name
=
"unbox"
+
wrap
.
simpleName
()
+
(
raw
?
"Raw"
:
""
);
String
name
=
"unbox"
+
wrap
.
simpleName
()
+
(
raw
?
"Raw"
:
""
);
MethodType
type
=
unboxType
(
wrap
,
raw
);
MethodType
type
=
unboxType
(
wrap
,
raw
);
if
(!
exact
)
{
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
// actually, type is wrong; the Java method takes Object
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
.
erase
());
mh
=
null
;
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
unbox
(
wrap
,
!
exact
,
raw
).
asType
(
type
);
}
}
if
(
mh
!=
null
)
{
if
(
mh
!=
null
)
{
mh
=
MethodHandles
.
insertArguments
(
mh
,
1
,
cast
);
cache
.
put
(
wrap
,
mh
);
cache
.
put
(
wrap
,
mh
);
return
mh
;
return
mh
;
}
}
throw
new
IllegalArgumentException
(
"cannot find unbox adapter for "
+
wrap
+
(
raw
?
" (raw)"
:
""
));
throw
new
IllegalArgumentException
(
"cannot find unbox adapter for "
+
wrap
+
(
cast
?
" (cast)"
:
""
)
+
(
raw
?
" (raw)"
:
""
));
}
}
public
static
MethodHandle
unbox
(
Wrapper
type
,
boolean
exact
)
{
public
static
MethodHandle
unbox
Cast
(
Wrapper
type
)
{
return
unbox
(
type
,
exact
,
fals
e
);
return
unbox
(
type
,
false
,
tru
e
);
}
}
public
static
MethodHandle
unboxRaw
(
Wrapper
type
,
boolean
exact
)
{
public
static
MethodHandle
unboxRaw
(
Wrapper
type
)
{
return
unbox
(
type
,
exact
,
tru
e
);
return
unbox
(
type
,
true
,
fals
e
);
}
}
public
static
MethodHandle
unbox
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
unbox
(
Class
<?>
type
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
false
);
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
false
,
false
);
}
}
public
static
MethodHandle
unboxRaw
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
unboxCast
(
Class
<?>
type
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
true
);
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
false
,
true
);
}
public
static
MethodHandle
unboxRaw
(
Class
<?>
type
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
true
,
false
);
}
/// 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
();
}
if
(
x
instanceof
Number
)
{
res
=
(
Number
)
x
;
}
else
if
(
x
instanceof
Boolean
)
{
res
=
((
boolean
)
x
?
1
:
0
);
}
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
())))
// this will fail with the required ClassCastException:
res
=
(
Number
)
wrap
.
wrapperType
().
cast
(
x
);
return
res
;
}
}
/// Converting primitives to references
/// Converting primitives to references
...
@@ -285,7 +328,7 @@ public class ValueConversions {
...
@@ -285,7 +328,7 @@ public class ValueConversions {
MethodType
type
=
boxType
(
wrap
,
raw
);
MethodType
type
=
boxType
(
wrap
,
raw
);
if
(
exact
)
{
if
(
exact
)
{
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
mh
=
null
;
}
}
...
@@ -296,22 +339,31 @@ public class ValueConversions {
...
@@ -296,22 +339,31 @@ public class ValueConversions {
cache
.
put
(
wrap
,
mh
);
cache
.
put
(
wrap
,
mh
);
return
mh
;
return
mh
;
}
}
throw
new
IllegalArgumentException
(
"cannot find box adapter for "
+
wrap
+
(
raw
?
" (raw)"
:
""
));
throw
new
IllegalArgumentException
(
"cannot find box adapter for "
+
wrap
+
(
exact
?
" (exact)"
:
""
)
+
(
raw
?
" (raw)"
:
""
));
}
}
public
static
MethodHandle
box
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
box
(
Class
<?>
type
)
{
boolean
exact
=
false
;
// e.g., boxShort(short)Short if exact,
// e.g., boxShort(short)Object if !exact
return
box
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
false
);
return
box
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
false
);
}
}
public
static
MethodHandle
boxRaw
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
boxRaw
(
Class
<?>
type
)
{
boolean
exact
=
false
;
// e.g., boxShortRaw(int)Short if exact
// e.g., boxShortRaw(int)Object if !exact
return
box
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
true
);
return
box
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
true
);
}
}
public
static
MethodHandle
box
(
Wrapper
type
,
boolean
exact
)
{
public
static
MethodHandle
box
(
Wrapper
type
)
{
boolean
exact
=
false
;
return
box
(
type
,
exact
,
false
);
return
box
(
type
,
exact
,
false
);
}
}
public
static
MethodHandle
boxRaw
(
Wrapper
type
,
boolean
exact
)
{
public
static
MethodHandle
boxRaw
(
Wrapper
type
)
{
boolean
exact
=
false
;
return
box
(
type
,
exact
,
true
);
return
box
(
type
,
exact
,
true
);
}
}
...
@@ -319,16 +371,16 @@ public class ValueConversions {
...
@@ -319,16 +371,16 @@ public class ValueConversions {
static
int
unboxRawInteger
(
Object
x
)
{
static
int
unboxRawInteger
(
Object
x
)
{
if
(
x
instanceof
Integer
)
if
(
x
instanceof
Integer
)
return
unboxInteger
(
x
)
;
return
(
int
)
x
;
else
else
return
(
int
)
unboxLong
(
x
);
return
(
int
)
unboxLong
(
x
,
false
);
}
}
static
Integer
reboxRawInteger
(
Object
x
)
{
static
Integer
reboxRawInteger
(
Object
x
)
{
if
(
x
instanceof
Integer
)
if
(
x
instanceof
Integer
)
return
(
Integer
)
x
;
return
(
Integer
)
x
;
else
else
return
(
int
)
unboxLong
(
x
);
return
(
int
)
unboxLong
(
x
,
false
);
}
}
static
Byte
reboxRawByte
(
Object
x
)
{
static
Byte
reboxRawByte
(
Object
x
)
{
...
@@ -362,7 +414,7 @@ public class ValueConversions {
...
@@ -362,7 +414,7 @@ public class ValueConversions {
static
Double
reboxRawDouble
(
Object
x
)
{
static
Double
reboxRawDouble
(
Object
x
)
{
if
(
x
instanceof
Double
)
return
(
Double
)
x
;
if
(
x
instanceof
Double
)
return
(
Double
)
x
;
return
boxDoubleRaw
(
unboxLong
(
x
));
return
boxDoubleRaw
(
unboxLong
(
x
,
true
));
}
}
private
static
MethodType
reboxType
(
Wrapper
wrap
)
{
private
static
MethodType
reboxType
(
Wrapper
wrap
)
{
...
@@ -371,7 +423,7 @@ public class ValueConversions {
...
@@ -371,7 +423,7 @@ public class ValueConversions {
}
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>[]
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>[]
REBOX_CONVERSIONS
=
newWrapperCaches
(
2
);
REBOX_CONVERSIONS
=
newWrapperCaches
(
1
);
/**
/**
* Because we normalize primitive types to reduce the number of signatures,
* Because we normalize primitive types to reduce the number of signatures,
...
@@ -380,10 +432,10 @@ public class ValueConversions {
...
@@ -380,10 +432,10 @@ public class ValueConversions {
* When the erased primitive value is then boxed into an Integer or Long,
* When the erased primitive value is then boxed into an Integer or Long,
* the final boxed primitive is sometimes required. This transformation
* the final boxed primitive is sometimes required. This transformation
* is called a "rebox". It takes an Integer or Long and produces some
* is called a "rebox". It takes an Integer or Long and produces some
* other boxed value
.
* other boxed value
, typed (inexactly) as an Object
*/
*/
public
static
MethodHandle
rebox
(
Wrapper
wrap
,
boolean
exact
)
{
public
static
MethodHandle
rebox
(
Wrapper
wrap
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
REBOX_CONVERSIONS
[
exact
?
1
:
0
];
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
REBOX_CONVERSIONS
[
0
];
MethodHandle
mh
=
cache
.
get
(
wrap
);
MethodHandle
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
{
if
(
mh
!=
null
)
{
return
mh
;
return
mh
;
...
@@ -402,14 +454,11 @@ public class ValueConversions {
...
@@ -402,14 +454,11 @@ public class ValueConversions {
// look up the method
// look up the method
String
name
=
"reboxRaw"
+
wrap
.
simpleName
();
String
name
=
"reboxRaw"
+
wrap
.
simpleName
();
MethodType
type
=
reboxType
(
wrap
);
MethodType
type
=
reboxType
(
wrap
);
if
(
exact
)
{
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
mh
=
mh
.
asType
(
IDENTITY
.
type
());
}
catch
(
ReflectiveOperationException
ex
)
{
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
mh
=
null
;
}
}
else
{
mh
=
rebox
(
wrap
,
!
exact
).
asType
(
IDENTITY
.
type
());
}
}
if
(
mh
!=
null
)
{
if
(
mh
!=
null
)
{
cache
.
put
(
wrap
,
mh
);
cache
.
put
(
wrap
,
mh
);
...
@@ -418,8 +467,8 @@ public class ValueConversions {
...
@@ -418,8 +467,8 @@ public class ValueConversions {
throw
new
IllegalArgumentException
(
"cannot find rebox adapter for "
+
wrap
);
throw
new
IllegalArgumentException
(
"cannot find rebox adapter for "
+
wrap
);
}
}
public
static
MethodHandle
rebox
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
rebox
(
Class
<?>
type
)
{
return
rebox
(
Wrapper
.
forPrimitiveType
(
type
)
,
exact
);
return
rebox
(
Wrapper
.
forPrimitiveType
(
type
));
}
}
/// Width-changing conversions between int and long.
/// Width-changing conversions between int and long.
...
@@ -486,9 +535,10 @@ public class ValueConversions {
...
@@ -486,9 +535,10 @@ public class ValueConversions {
case
VOID:
case
VOID:
mh
=
EMPTY
;
mh
=
EMPTY
;
break
;
break
;
case
OBJECT:
case
INT:
case
LONG:
case
FLOAT:
case
DOUBLE:
case
INT:
case
LONG:
case
FLOAT:
case
DOUBLE:
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zero"
+
wrap
.
simpleName
(),
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"zero"
+
wrap
.
simpleName
(),
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
mh
=
null
;
}
}
...
@@ -592,7 +642,7 @@ public class ValueConversions {
...
@@ -592,7 +642,7 @@ public class ValueConversions {
return
t
.
cast
(
x
);
return
t
.
cast
(
x
);
}
}
private
static
final
MethodHandle
IDENTITY
,
IDENTITY_I
,
IDENTITY_J
,
CAST_REFERENCE
,
ALWAYS_NULL
,
ALWAYS_ZERO
,
ZERO_OBJECT
,
IGNORE
,
EMPTY
;
private
static
final
MethodHandle
IDENTITY
,
IDENTITY_I
,
IDENTITY_J
,
CAST_REFERENCE
,
ALWAYS_NULL
,
ALWAYS_ZERO
,
ZERO_OBJECT
,
IGNORE
,
EMPTY
,
NEW_ARRAY
;
static
{
static
{
try
{
try
{
MethodType
idType
=
MethodType
.
genericMethodType
(
1
);
MethodType
idType
=
MethodType
.
genericMethodType
(
1
);
...
@@ -600,40 +650,56 @@ public class ValueConversions {
...
@@ -600,40 +650,56 @@ public class ValueConversions {
MethodType
alwaysZeroType
=
idType
.
changeReturnType
(
int
.
class
);
MethodType
alwaysZeroType
=
idType
.
changeReturnType
(
int
.
class
);
MethodType
ignoreType
=
idType
.
changeReturnType
(
void
.
class
);
MethodType
ignoreType
=
idType
.
changeReturnType
(
void
.
class
);
MethodType
zeroObjectType
=
MethodType
.
genericMethodType
(
0
);
MethodType
zeroObjectType
=
MethodType
.
genericMethodType
(
0
);
IDENTITY
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
idType
);
IDENTITY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
idType
);
IDENTITY_I
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
class
));
IDENTITY_I
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
class
));
IDENTITY_J
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
MethodType
.
methodType
(
long
.
class
,
long
.
class
));
IDENTITY_J
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
MethodType
.
methodType
(
long
.
class
,
long
.
class
));
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
CAST_REFERENCE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"castReference"
,
castType
);
CAST_REFERENCE
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"castReference"
,
castType
);
ALWAYS_NULL
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"alwaysNull"
,
idType
);
ALWAYS_NULL
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"alwaysNull"
,
idType
);
ALWAYS_ZERO
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"alwaysZero"
,
alwaysZeroType
);
ALWAYS_ZERO
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"alwaysZero"
,
alwaysZeroType
);
ZERO_OBJECT
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zeroObject"
,
zeroObjectType
);
ZERO_OBJECT
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"zeroObject"
,
zeroObjectType
);
IGNORE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"ignore"
,
ignoreType
);
IGNORE
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"ignore"
,
ignoreType
);
EMPTY
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"empty"
,
ignoreType
.
dropParameterTypes
(
0
,
1
));
EMPTY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"empty"
,
ignoreType
.
dropParameterTypes
(
0
,
1
));
}
catch
(
Exception
ex
)
{
NEW_ARRAY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"newArray"
,
MethodType
.
methodType
(
Object
[].
class
,
int
.
class
));
}
catch
(
NoSuchMethodException
|
IllegalAccessException
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
err
.
initCause
(
ex
);
throw
err
;
throw
err
;
}
}
}
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>
WRAPPER_CASTS
// Varargs methods need to be in a separately initialized class, to bootstrapping problems.
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
static
class
LazyStatics
{
private
static
final
MethodHandle
COPY_AS_REFERENCE_ARRAY
,
COPY_AS_PRIMITIVE_ARRAY
,
MAKE_LIST
;
static
{
try
{
//MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
COPY_AS_REFERENCE_ARRAY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"copyAsReferenceArray"
,
MethodType
.
methodType
(
Object
[].
class
,
Class
.
class
,
Object
[].
class
));
COPY_AS_PRIMITIVE_ARRAY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"copyAsPrimitiveArray"
,
MethodType
.
methodType
(
Object
.
class
,
Wrapper
.
class
,
Object
[].
class
));
MAKE_LIST
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"makeList"
,
MethodType
.
methodType
(
List
.
class
,
Object
[].
class
));
}
catch
(
ReflectiveOperationException
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
throw
err
;
}
}
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>
EXACT_
WRAPPER_CASTS
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>
[]
WRAPPER_CASTS
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
=
new
WrapperCaches
(
2
);
/** Return a method that casts its sole argument (an Object) to the given type
/** Return a method that casts its sole argument (an Object) to the given type
* and returns it as the given type (if exact is true), or as plain Object (if erase is true).
* and returns it as the given type (if exact is true), or as plain Object (if erase is true).
*/
*/
public
static
MethodHandle
cast
(
Class
<?>
type
,
boolean
exact
)
{
public
static
MethodHandle
cast
(
Class
<?>
type
)
{
boolean
exact
=
false
;
if
(
type
.
isPrimitive
())
throw
new
IllegalArgumentException
(
"cannot cast primitive type "
+
type
);
if
(
type
.
isPrimitive
())
throw
new
IllegalArgumentException
(
"cannot cast primitive type "
+
type
);
MethodHandle
mh
=
null
;
MethodHandle
mh
=
null
;
Wrapper
wrap
=
null
;
Wrapper
wrap
=
null
;
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
null
;
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
null
;
if
(
Wrapper
.
isWrapperType
(
type
))
{
if
(
Wrapper
.
isWrapperType
(
type
))
{
wrap
=
Wrapper
.
forWrapperType
(
type
);
wrap
=
Wrapper
.
forWrapperType
(
type
);
cache
=
(
exact
?
EXACT_WRAPPER_CASTS
:
WRAPPER_CASTS
)
;
cache
=
WRAPPER_CASTS
[
exact
?
1
:
0
]
;
mh
=
cache
.
get
(
wrap
);
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
return
mh
;
if
(
mh
!=
null
)
return
mh
;
}
}
...
@@ -673,7 +739,7 @@ public class ValueConversions {
...
@@ -673,7 +739,7 @@ public class ValueConversions {
if
(
wrap
!=
Wrapper
.
VOID
)
if
(
wrap
!=
Wrapper
.
VOID
)
type
=
type
.
appendParameterTypes
(
wrap
.
primitiveType
());
type
=
type
.
appendParameterTypes
(
wrap
.
primitiveType
());
try
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
mh
=
null
;
}
}
...
@@ -692,6 +758,210 @@ public class ValueConversions {
...
@@ -692,6 +758,210 @@ public class ValueConversions {
throw
new
IllegalArgumentException
(
"cannot find identity for "
+
wrap
);
throw
new
IllegalArgumentException
(
"cannot find identity for "
+
wrap
);
}
}
/// Float/non-float conversions.
static
float
doubleToFloat
(
double
x
)
{
return
(
float
)
x
;
}
static
double
floatToDouble
(
float
x
)
{
return
x
;
}
// narrow double to integral type
static
long
doubleToLong
(
double
x
)
{
return
(
long
)
x
;
}
static
int
doubleToInt
(
double
x
)
{
return
(
int
)
x
;
}
static
short
doubleToShort
(
double
x
)
{
return
(
short
)
x
;
}
static
char
doubleToChar
(
double
x
)
{
return
(
char
)
x
;
}
static
byte
doubleToByte
(
double
x
)
{
return
(
byte
)
x
;
}
static
boolean
doubleToBoolean
(
double
x
)
{
return
toBoolean
((
byte
)
x
);
}
// narrow float to integral type
static
long
floatToLong
(
float
x
)
{
return
(
long
)
x
;
}
static
int
floatToInt
(
float
x
)
{
return
(
int
)
x
;
}
static
short
floatToShort
(
float
x
)
{
return
(
short
)
x
;
}
static
char
floatToChar
(
float
x
)
{
return
(
char
)
x
;
}
static
byte
floatToByte
(
float
x
)
{
return
(
byte
)
x
;
}
static
boolean
floatToBoolean
(
float
x
)
{
return
toBoolean
((
byte
)
x
);
}
// widen integral type to double
static
double
longToDouble
(
long
x
)
{
return
x
;
}
static
double
intToDouble
(
int
x
)
{
return
x
;
}
static
double
shortToDouble
(
short
x
)
{
return
x
;
}
static
double
charToDouble
(
char
x
)
{
return
x
;
}
static
double
byteToDouble
(
byte
x
)
{
return
x
;
}
static
double
booleanToDouble
(
boolean
x
)
{
return
fromBoolean
(
x
);
}
// widen integral type to float
static
float
longToFloat
(
long
x
)
{
return
x
;
}
static
float
intToFloat
(
int
x
)
{
return
x
;
}
static
float
shortToFloat
(
short
x
)
{
return
x
;
}
static
float
charToFloat
(
char
x
)
{
return
x
;
}
static
float
byteToFloat
(
byte
x
)
{
return
x
;
}
static
float
booleanToFloat
(
boolean
x
)
{
return
fromBoolean
(
x
);
}
static
boolean
toBoolean
(
byte
x
)
{
// see javadoc for MethodHandles.explicitCastArguments
return
((
x
&
1
)
!=
0
);
}
static
byte
fromBoolean
(
boolean
x
)
{
// see javadoc for MethodHandles.explicitCastArguments
return
(
x
?
(
byte
)
1
:
(
byte
)
0
);
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>[]
CONVERT_FLOAT_FUNCTIONS
=
newWrapperCaches
(
4
);
static
MethodHandle
convertFloatFunction
(
Wrapper
wrap
,
boolean
toFloat
,
boolean
doubleSize
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
CONVERT_FLOAT_FUNCTIONS
[(
toFloat
?
1
:
0
)+(
doubleSize
?
2
:
0
)];
MethodHandle
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
{
return
mh
;
}
// slow path
Wrapper
fwrap
=
(
doubleSize
?
Wrapper
.
DOUBLE
:
Wrapper
.
FLOAT
);
Class
<?>
fix
=
wrap
.
primitiveType
();
Class
<?>
flt
=
(
doubleSize
?
double
.
class
:
float
.
class
);
Class
<?>
src
=
toFloat
?
fix
:
flt
;
Class
<?>
dst
=
toFloat
?
flt
:
fix
;
if
(
src
==
dst
)
return
identity
(
wrap
);
MethodType
type
=
MethodType
.
methodType
(
dst
,
src
);
switch
(
wrap
)
{
case
VOID:
mh
=
toFloat
?
zeroConstantFunction
(
fwrap
)
:
MethodHandles
.
dropArguments
(
EMPTY
,
0
,
flt
);
break
;
case
OBJECT:
mh
=
toFloat
?
unbox
(
flt
)
:
box
(
flt
);
break
;
default
:
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
src
.
getSimpleName
()+
"To"
+
capitalize
(
dst
.
getSimpleName
()),
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
break
;
}
if
(
mh
!=
null
)
{
assert
(
mh
.
type
()
==
type
)
:
mh
;
cache
.
put
(
wrap
,
mh
);
return
mh
;
}
throw
new
IllegalArgumentException
(
"cannot find float conversion constant for "
+
src
.
getSimpleName
()+
" -> "
+
dst
.
getSimpleName
());
}
public
static
MethodHandle
convertFromFloat
(
Class
<?>
fixType
)
{
Wrapper
wrap
=
Wrapper
.
forPrimitiveType
(
fixType
);
return
convertFloatFunction
(
wrap
,
false
,
false
);
}
public
static
MethodHandle
convertFromDouble
(
Class
<?>
fixType
)
{
Wrapper
wrap
=
Wrapper
.
forPrimitiveType
(
fixType
);
return
convertFloatFunction
(
wrap
,
false
,
true
);
}
public
static
MethodHandle
convertToFloat
(
Class
<?>
fixType
)
{
Wrapper
wrap
=
Wrapper
.
forPrimitiveType
(
fixType
);
return
convertFloatFunction
(
wrap
,
true
,
false
);
}
public
static
MethodHandle
convertToDouble
(
Class
<?>
fixType
)
{
Wrapper
wrap
=
Wrapper
.
forPrimitiveType
(
fixType
);
return
convertFloatFunction
(
wrap
,
true
,
true
);
}
private
static
String
capitalize
(
String
x
)
{
return
Character
.
toUpperCase
(
x
.
charAt
(
0
))+
x
.
substring
(
1
);
}
/// Collection of multiple arguments.
public
static
Object
convertArrayElements
(
Class
<?>
arrayType
,
Object
array
)
{
Class
<?>
src
=
array
.
getClass
().
getComponentType
();
Class
<?>
dst
=
arrayType
.
getComponentType
();
if
(
src
==
null
||
dst
==
null
)
throw
new
IllegalArgumentException
(
"not array type"
);
Wrapper
sw
=
(
src
.
isPrimitive
()
?
Wrapper
.
forPrimitiveType
(
src
)
:
null
);
Wrapper
dw
=
(
dst
.
isPrimitive
()
?
Wrapper
.
forPrimitiveType
(
dst
)
:
null
);
int
length
;
if
(
sw
==
null
)
{
Object
[]
a
=
(
Object
[])
array
;
length
=
a
.
length
;
if
(
dw
==
null
)
return
Arrays
.
copyOf
(
a
,
length
,
arrayType
.
asSubclass
(
Object
[].
class
));
Object
res
=
dw
.
makeArray
(
length
);
dw
.
copyArrayUnboxing
(
a
,
0
,
res
,
0
,
length
);
return
res
;
}
length
=
java
.
lang
.
reflect
.
Array
.
getLength
(
array
);
Object
[]
res
;
if
(
dw
==
null
)
{
res
=
Arrays
.
copyOf
(
NO_ARGS_ARRAY
,
length
,
arrayType
.
asSubclass
(
Object
[].
class
));
}
else
{
res
=
new
Object
[
length
];
}
sw
.
copyArrayBoxing
(
array
,
0
,
res
,
0
,
length
);
if
(
dw
==
null
)
return
res
;
Object
a
=
dw
.
makeArray
(
length
);
dw
.
copyArrayUnboxing
(
res
,
0
,
a
,
0
,
length
);
return
a
;
}
private
static
MethodHandle
findCollector
(
String
name
,
int
nargs
,
Class
<?>
rtype
,
Class
<?>...
ptypes
)
{
MethodType
type
=
MethodType
.
genericMethodType
(
nargs
)
.
changeReturnType
(
rtype
)
.
insertParameterTypes
(
0
,
ptypes
);
try
{
return
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
return
null
;
}
}
private
static
final
Object
[]
NO_ARGS_ARRAY
=
{};
private
static
final
Object
[]
NO_ARGS_ARRAY
=
{};
private
static
Object
[]
makeArray
(
Object
...
args
)
{
return
args
;
}
private
static
Object
[]
makeArray
(
Object
...
args
)
{
return
args
;
}
private
static
Object
[]
array
()
{
return
NO_ARGS_ARRAY
;
}
private
static
Object
[]
array
()
{
return
NO_ARGS_ARRAY
;
}
...
@@ -723,36 +993,176 @@ public class ValueConversions {
...
@@ -723,36 +993,176 @@ public class ValueConversions {
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
,
Object
a9
)
Object
a8
,
Object
a9
)
{
return
makeArray
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
{
return
makeArray
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
static
MethodHandle
[]
makeArrays
()
{
private
static
MethodHandle
[]
makeArrays
()
{
ArrayList
<
MethodHandle
>
arrays
=
new
ArrayList
<
MethodHandle
>();
ArrayList
<
MethodHandle
>
mhs
=
new
ArrayList
<>();
MethodHandles
.
Lookup
lookup
=
IMPL_LOOKUP
;
for
(;;)
{
for
(;;)
{
int
nargs
=
arrays
.
size
();
MethodHandle
mh
=
findCollector
(
"array"
,
mhs
.
size
(),
Object
[].
class
);
MethodType
type
=
MethodType
.
genericMethodType
(
nargs
).
changeReturnType
(
Object
[].
class
);
if
(
mh
==
null
)
break
;
String
name
=
"array"
;
mhs
.
add
(
mh
);
MethodHandle
array
=
null
;
try
{
array
=
lookup
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
if
(
array
==
null
)
break
;
arrays
.
add
(
array
);
}
}
assert
(
arrays
.
size
()
==
11
);
// current number of methods
assert
(
mhs
.
size
()
==
11
);
// current number of methods
return
arrays
.
toArray
(
new
MethodHandle
[
0
]);
return
mhs
.
toArray
(
new
MethodHandle
[
MAX_ARITY
+
1
]);
}
private
static
final
MethodHandle
[]
ARRAYS
=
makeArrays
();
// mh-fill versions of the above:
private
static
Object
[]
newArray
(
int
len
)
{
return
new
Object
[
len
];
}
private
static
void
fillWithArguments
(
Object
[]
a
,
int
pos
,
Object
...
args
)
{
System
.
arraycopy
(
args
,
0
,
a
,
pos
,
args
.
length
);
}
// using Integer pos instead of int pos to avoid bootstrapping problems
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
)
{
fillWithArguments
(
a
,
pos
,
a0
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
,
Object
a5
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
,
a5
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
,
Object
a5
,
Object
a6
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
);
return
a
;
}
private
static
Object
[]
fillArray
(
Object
[]
a
,
Integer
pos
,
Object
a0
,
Object
a1
,
Object
a2
,
Object
a3
,
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
,
Object
a9
)
{
fillWithArguments
(
a
,
pos
,
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
return
a
;
}
private
static
MethodHandle
[]
makeFillArrays
()
{
ArrayList
<
MethodHandle
>
mhs
=
new
ArrayList
<>();
mhs
.
add
(
null
);
// there is no empty fill; at least a0 is required
for
(;;)
{
MethodHandle
mh
=
findCollector
(
"fillArray"
,
mhs
.
size
(),
Object
[].
class
,
Object
[].
class
,
Integer
.
class
);
if
(
mh
==
null
)
break
;
mhs
.
add
(
mh
);
}
assert
(
mhs
.
size
()
==
11
);
// current number of methods
return
mhs
.
toArray
(
new
MethodHandle
[
0
]);
}
private
static
final
MethodHandle
[]
FILL_ARRAYS
=
makeFillArrays
();
private
static
Object
[]
copyAsReferenceArray
(
Class
<?
extends
Object
[]>
arrayType
,
Object
...
a
)
{
return
Arrays
.
copyOf
(
a
,
a
.
length
,
arrayType
);
}
private
static
Object
copyAsPrimitiveArray
(
Wrapper
w
,
Object
...
boxes
)
{
Object
a
=
w
.
makeArray
(
boxes
.
length
);
w
.
copyArrayUnboxing
(
boxes
,
0
,
a
,
0
,
boxes
.
length
);
return
a
;
}
}
static
final
MethodHandle
[]
ARRAYS
=
makeArrays
();
/** Return a method handle that takes the indicated number of Object
/** Return a method handle that takes the indicated number of Object
* arguments and returns an Object array of them, as if for varargs.
* arguments and returns an Object array of them, as if for varargs.
*/
*/
public
static
MethodHandle
varargsArray
(
int
nargs
)
{
public
static
MethodHandle
varargsArray
(
int
nargs
)
{
if
(
nargs
<
ARRAYS
.
length
)
MethodHandle
mh
=
ARRAYS
[
nargs
];
return
ARRAYS
[
nargs
];
if
(
mh
!=
null
)
return
mh
;
// else need to spin bytecode or do something else fancy
mh
=
findCollector
(
"array"
,
nargs
,
Object
[].
class
);
throw
new
UnsupportedOperationException
(
"NYI: cannot form a varargs array of length "
+
nargs
);
if
(
mh
!=
null
)
return
ARRAYS
[
nargs
]
=
mh
;
MethodHandle
producer
=
filler
(
0
);
// identity function produces result
return
ARRAYS
[
nargs
]
=
buildVarargsArray
(
producer
,
nargs
);
}
private
static
MethodHandle
buildVarargsArray
(
MethodHandle
producer
,
int
nargs
)
{
// Build up the result mh as a sequence of fills like this:
// producer(fill(fill(fill(newArray(23),0,x1..x10),10,x11..x20),20,x21..x23))
// The various fill(_,10*I,___*[J]) are reusable.
MethodHandle
filler
=
filler
(
nargs
);
MethodHandle
mh
=
producer
;
mh
=
MethodHandles
.
dropArguments
(
mh
,
1
,
filler
.
type
().
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
mh
,
filler
);
mh
=
MethodHandles
.
foldArguments
(
mh
,
buildNewArray
(
nargs
));
return
mh
;
}
}
private
static
MethodHandle
buildNewArray
(
int
nargs
)
{
return
MethodHandles
.
insertArguments
(
NEW_ARRAY
,
0
,
(
int
)
nargs
);
}
private
static
final
MethodHandle
[]
FILLERS
=
new
MethodHandle
[
MAX_ARITY
+
1
];
// filler(N).invoke(a, arg0..arg[N-1]) fills a[0]..a[N-1]
private
static
MethodHandle
filler
(
int
nargs
)
{
MethodHandle
filler
=
FILLERS
[
nargs
];
if
(
filler
!=
null
)
return
filler
;
return
FILLERS
[
nargs
]
=
buildFiller
(
nargs
);
}
private
static
MethodHandle
buildFiller
(
int
nargs
)
{
if
(
nargs
==
0
)
return
MethodHandles
.
identity
(
Object
[].
class
);
final
int
CHUNK
=
(
FILL_ARRAYS
.
length
-
1
);
int
rightLen
=
nargs
%
CHUNK
;
int
leftLen
=
nargs
-
rightLen
;
if
(
rightLen
==
0
)
{
leftLen
=
nargs
-
(
rightLen
=
CHUNK
);
if
(
FILLERS
[
leftLen
]
==
null
)
{
// build some precursors from left to right
for
(
int
j
=
0
;
j
<
leftLen
;
j
+=
CHUNK
)
filler
(
j
);
}
}
MethodHandle
leftFill
=
filler
(
leftLen
);
// recursive fill
MethodHandle
rightFill
=
FILL_ARRAYS
[
rightLen
];
rightFill
=
MethodHandles
.
insertArguments
(
rightFill
,
1
,
(
int
)
leftLen
);
// [leftLen..nargs-1]
// Combine the two fills: right(left(newArray(nargs), x1..x20), x21..x23)
MethodHandle
mh
=
filler
(
0
);
// identity function produces result
mh
=
MethodHandles
.
dropArguments
(
mh
,
1
,
rightFill
.
type
().
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
mh
,
rightFill
);
if
(
leftLen
>
0
)
{
mh
=
MethodHandles
.
dropArguments
(
mh
,
1
,
leftFill
.
type
().
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
mh
,
leftFill
);
}
return
mh
;
}
// Type-polymorphic version of varargs maker.
private
static
final
ClassValue
<
MethodHandle
[]>
TYPED_COLLECTORS
=
new
ClassValue
<
MethodHandle
[]>()
{
protected
MethodHandle
[]
computeValue
(
Class
<?>
type
)
{
return
new
MethodHandle
[
256
];
}
};
/** Return a method handle that takes the indicated number of
* typed arguments and returns an array of them.
* The type argument is the array type.
*/
public
static
MethodHandle
varargsArray
(
Class
<?>
arrayType
,
int
nargs
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
if
(
elemType
==
null
)
throw
new
IllegalArgumentException
(
"not an array: "
+
arrayType
);
// FIXME: Need more special casing and caching here.
if
(
elemType
==
Object
.
class
)
return
varargsArray
(
nargs
);
// other cases: primitive arrays, subtypes of Object[]
MethodHandle
cache
[]
=
TYPED_COLLECTORS
.
get
(
elemType
);
MethodHandle
mh
=
nargs
<
cache
.
length
?
cache
[
nargs
]
:
null
;
if
(
mh
!=
null
)
return
mh
;
MethodHandle
producer
=
buildArrayProducer
(
arrayType
);
mh
=
buildVarargsArray
(
producer
,
nargs
);
mh
=
mh
.
asType
(
MethodType
.
methodType
(
arrayType
,
Collections
.<
Class
<?>>
nCopies
(
nargs
,
elemType
)));
cache
[
nargs
]
=
mh
;
return
mh
;
}
private
static
MethodHandle
buildArrayProducer
(
Class
<?>
arrayType
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
if
(
elemType
.
isPrimitive
())
return
LazyStatics
.
COPY_AS_PRIMITIVE_ARRAY
.
bindTo
(
Wrapper
.
forPrimitiveType
(
elemType
));
else
return
LazyStatics
.
COPY_AS_REFERENCE_ARRAY
.
bindTo
(
arrayType
);
}
// List version of varargs maker.
private
static
final
List
<
Object
>
NO_ARGS_LIST
=
Arrays
.
asList
(
NO_ARGS_ARRAY
);
private
static
final
List
<
Object
>
NO_ARGS_LIST
=
Arrays
.
asList
(
NO_ARGS_ARRAY
);
private
static
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
private
static
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
private
static
List
<
Object
>
list
()
{
return
NO_ARGS_LIST
;
}
private
static
List
<
Object
>
list
()
{
return
NO_ARGS_LIST
;
}
...
@@ -784,34 +1194,29 @@ public class ValueConversions {
...
@@ -784,34 +1194,29 @@ public class ValueConversions {
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
,
Object
a9
)
Object
a8
,
Object
a9
)
{
return
makeList
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
{
return
makeList
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
static
MethodHandle
[]
makeLists
()
{
private
static
MethodHandle
[]
makeLists
()
{
ArrayList
<
MethodHandle
>
arrays
=
new
ArrayList
<
MethodHandle
>();
ArrayList
<
MethodHandle
>
mhs
=
new
ArrayList
<>();
MethodHandles
.
Lookup
lookup
=
IMPL_LOOKUP
;
for
(;;)
{
for
(;;)
{
int
nargs
=
arrays
.
size
();
MethodHandle
mh
=
findCollector
(
"list"
,
mhs
.
size
(),
List
.
class
);
MethodType
type
=
MethodType
.
genericMethodType
(
nargs
).
changeReturnType
(
List
.
class
);
if
(
mh
==
null
)
break
;
String
name
=
"list"
;
mhs
.
add
(
mh
);
MethodHandle
array
=
null
;
try
{
array
=
lookup
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
if
(
array
==
null
)
break
;
arrays
.
add
(
array
);
}
}
assert
(
array
s
.
size
()
==
11
);
// current number of methods
assert
(
mh
s
.
size
()
==
11
);
// current number of methods
return
arrays
.
toArray
(
new
MethodHandle
[
0
]);
return
mhs
.
toArray
(
new
MethodHandle
[
MAX_ARITY
+
1
]);
}
}
static
final
MethodHandle
[]
LISTS
=
makeLists
();
private
static
final
MethodHandle
[]
LISTS
=
makeLists
();
/** Return a method handle that takes the indicated number of Object
/** Return a method handle that takes the indicated number of Object
* arguments and returns List.
* arguments and returns
a
List.
*/
*/
public
static
MethodHandle
varargsList
(
int
nargs
)
{
public
static
MethodHandle
varargsList
(
int
nargs
)
{
if
(
nargs
<
LISTS
.
length
)
MethodHandle
mh
=
LISTS
[
nargs
];
return
LISTS
[
nargs
];
if
(
mh
!=
null
)
return
mh
;
// else need to spin bytecode or do something else fancy
mh
=
findCollector
(
"list"
,
nargs
,
List
.
class
);
throw
new
UnsupportedOperationException
(
"NYI"
);
if
(
mh
!=
null
)
return
LISTS
[
nargs
]
=
mh
;
return
LISTS
[
nargs
]
=
buildVarargsList
(
nargs
);
}
private
static
MethodHandle
buildVarargsList
(
int
nargs
)
{
return
MethodHandles
.
filterReturnValue
(
varargsArray
(
nargs
),
LazyStatics
.
MAKE_LIST
);
}
}
}
}
src/share/classes/sun/invoke/util/VerifyType.java
浏览文件 @
8c50098c
...
@@ -54,9 +54,15 @@ public class VerifyType {
...
@@ -54,9 +54,15 @@ public class VerifyType {
if
(
dst
==
void
.
class
)
return
true
;
// drop any return value
if
(
dst
==
void
.
class
)
return
true
;
// drop any return value
if
(
isNullType
(
src
))
return
!
dst
.
isPrimitive
();
if
(
isNullType
(
src
))
return
!
dst
.
isPrimitive
();
if
(!
src
.
isPrimitive
())
return
dst
.
isAssignableFrom
(
src
);
if
(!
src
.
isPrimitive
())
return
dst
.
isAssignableFrom
(
src
);
if
(!
dst
.
isPrimitive
())
return
false
;
// Verifier allows an int to carry byte, short, char, or even boolean:
// Verifier allows an int to carry byte, short, char, or even boolean:
if
(
dst
==
int
.
class
)
return
Wrapper
.
forPrimitiveType
(
src
).
isSubwordOrInt
();
Wrapper
sw
=
Wrapper
.
forPrimitiveType
(
src
);
return
false
;
if
(
dst
==
int
.
class
)
return
sw
.
isSubwordOrInt
();
Wrapper
dw
=
Wrapper
.
forPrimitiveType
(
dst
);
if
(!
sw
.
isSubwordOrInt
())
return
false
;
if
(!
dw
.
isSubwordOrInt
())
return
false
;
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
return
false
;
return
dw
.
bitWidth
()
>
sw
.
bitWidth
();
}
}
/**
/**
...
@@ -155,6 +161,7 @@ public class VerifyType {
...
@@ -155,6 +161,7 @@ public class VerifyType {
return
-
1
;
// truncation may be required
return
-
1
;
// truncation may be required
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
return
-
1
;
// sign elimination may be required
return
-
1
;
// sign elimination may be required
return
1
;
}
}
if
(
src
==
float
.
class
||
dst
==
float
.
class
)
{
if
(
src
==
float
.
class
||
dst
==
float
.
class
)
{
if
(
src
==
double
.
class
||
dst
==
double
.
class
)
if
(
src
==
double
.
class
||
dst
==
double
.
class
)
...
...
src/share/classes/sun/invoke/util/Wrapper.java
浏览文件 @
8c50098c
...
@@ -26,37 +26,47 @@
...
@@ -26,37 +26,47 @@
package
sun.invoke.util
;
package
sun.invoke.util
;
public
enum
Wrapper
{
public
enum
Wrapper
{
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
Format
.
unsigned
(
1
)),
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
new
boolean
[
0
],
Format
.
unsigned
(
1
)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
Format
.
signed
(
8
)),
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
new
byte
[
0
],
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
Format
.
signed
(
16
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
new
short
[
0
],
Format
.
signed
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
Format
.
unsigned
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
new
char
[
0
],
Format
.
unsigned
(
16
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
Format
.
signed
(
32
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
new
int
[
0
],
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
Format
.
signed
(
64
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
new
long
[
0
],
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
Format
.
floating
(
32
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
new
float
[
0
],
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
Format
.
floating
(
64
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
new
double
[
0
],
Format
.
floating
(
64
)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
//NULL(Null.class, null.class, 'N', null,
null,
Format.other(1)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
Format
.
other
(
1
)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
new
Object
[
0
],
Format
.
other
(
1
)),
// VOID must be the last type, since it is "assignable" from any other type:
// VOID must be the last type, since it is "assignable" from any other type:
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
Format
.
other
(
0
)),
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
null
,
Format
.
other
(
0
)),
;
;
private
final
Class
<?>
wrapperType
;
private
final
Class
<?>
wrapperType
;
private
final
Class
<?>
primitiveType
;
private
final
Class
<?>
primitiveType
;
private
final
char
basicTypeChar
;
private
final
char
basicTypeChar
;
private
final
Object
zero
;
private
final
Object
zero
;
private
final
Object
emptyArray
;
private
final
int
format
;
private
final
int
format
;
private
final
String
simpleName
;
private
final
String
simpleName
;
private
Wrapper
(
Class
<?>
wtype
,
Class
<?>
ptype
,
char
tchar
,
Object
zero
,
int
format
)
{
private
Wrapper
(
Class
<?>
wtype
,
Class
<?>
ptype
,
char
tchar
,
Object
zero
,
Object
emptyArray
,
int
format
)
{
this
.
wrapperType
=
wtype
;
this
.
wrapperType
=
wtype
;
this
.
primitiveType
=
ptype
;
this
.
primitiveType
=
ptype
;
this
.
basicTypeChar
=
tchar
;
this
.
basicTypeChar
=
tchar
;
this
.
zero
=
zero
;
this
.
zero
=
zero
;
this
.
emptyArray
=
emptyArray
;
this
.
format
=
format
;
this
.
format
=
format
;
this
.
simpleName
=
wtype
.
getSimpleName
();
this
.
simpleName
=
wtype
.
getSimpleName
();
}
}
/** For debugging, give the details of this wrapper. */
public
String
detailString
()
{
return
simpleName
+
java
.
util
.
Arrays
.
asList
(
wrapperType
,
primitiveType
,
basicTypeChar
,
zero
,
"0x"
+
Integer
.
toHexString
(
format
));
}
private
static
abstract
class
Format
{
private
static
abstract
class
Format
{
static
final
int
SLOT_SHIFT
=
0
,
SIZE_SHIFT
=
2
,
KIND_SHIFT
=
12
;
static
final
int
SLOT_SHIFT
=
0
,
SIZE_SHIFT
=
2
,
KIND_SHIFT
=
12
;
static
final
int
static
final
int
...
@@ -114,16 +124,18 @@ public enum Wrapper {
...
@@ -114,16 +124,18 @@ public enum Wrapper {
public
boolean
isUnsigned
()
{
return
format
>=
Format
.
BOOLEAN
&&
format
<
Format
.
FLOAT
;
}
public
boolean
isUnsigned
()
{
return
format
>=
Format
.
BOOLEAN
&&
format
<
Format
.
FLOAT
;
}
/** Is the wrapped type either float or double? */
/** Is the wrapped type either float or double? */
public
boolean
isFloating
()
{
return
format
>=
Format
.
FLOAT
;
}
public
boolean
isFloating
()
{
return
format
>=
Format
.
FLOAT
;
}
/** Is the wrapped type either void or a reference? */
public
boolean
isOther
()
{
return
(
format
&
~
Format
.
SLOT_MASK
)
==
0
;
}
/** Does the J
VM verifier
allow a variable of this wrapper's
/** Does the J
LS 5.1.2
allow a variable of this wrapper's
* primitive type to be assigned from a value of the given wrapper's primitive type?
* primitive type to be assigned from a value of the given wrapper's primitive type?
* Cases:
* Cases:
* <ul>
* <ul>
* <li>unboxing followed by widening primitive conversion
* <li>unboxing followed by widening primitive conversion
* <li>any type converted to {@code void}
* <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}
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* <li>conversion of {@code boolean} to any type
* </ul>
* </ul>
* These are the cases allowed by MethodHandle.asType and convertArguments.
*/
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
if
(
this
==
source
)
return
true
;
...
@@ -131,13 +143,75 @@ public enum Wrapper {
...
@@ -131,13 +143,75 @@ public enum Wrapper {
// At best, this is a narrowing conversion.
// At best, this is a narrowing conversion.
return
false
;
return
false
;
}
}
if
((
this
.
format
^
source
.
format
)
==
(
Format
.
SHORT
^
Format
.
CHAR
))
{
// All conversions are allowed in the enum order between floats and signed ints.
assert
(
this
==
SHORT
&&
source
==
CHAR
)
||
(
this
==
CHAR
&&
source
==
SHORT
);
// First detect non-signed non-float types (boolean, char, Object, void).
boolean
floatOrSigned
=
(((
this
.
format
&
source
.
format
)
&
Format
.
SIGNED
)
!=
0
);
if
(!
floatOrSigned
)
{
if
(
this
.
isOther
())
return
true
;
// can convert char to int or wider, but nothing else
if
(
source
.
format
==
Format
.
CHAR
)
return
true
;
// no other conversions are classified as widening
return
false
;
return
false
;
}
}
// All signed and float conversions in the enum order are widening.
assert
(
this
.
isFloating
()
||
this
.
isSigned
());
assert
(
source
.
isFloating
()
||
source
.
isSigned
());
return
true
;
return
true
;
}
}
static
{
assert
(
checkConvertibleFrom
());
}
private
static
boolean
checkConvertibleFrom
()
{
// Check the matrix for correct classification of widening conversions.
for
(
Wrapper
w
:
values
())
{
assert
(
w
.
isConvertibleFrom
(
w
));
assert
(
VOID
.
isConvertibleFrom
(
w
));
if
(
w
!=
VOID
)
{
assert
(
OBJECT
.
isConvertibleFrom
(
w
));
assert
(!
w
.
isConvertibleFrom
(
VOID
));
}
// check relations with unsigned integral types:
if
(
w
!=
CHAR
)
{
assert
(!
CHAR
.
isConvertibleFrom
(
w
));
if
(!
w
.
isConvertibleFrom
(
INT
))
assert
(!
w
.
isConvertibleFrom
(
CHAR
));
}
if
(
w
!=
BOOLEAN
)
{
assert
(!
BOOLEAN
.
isConvertibleFrom
(
w
));
if
(
w
!=
VOID
&&
w
!=
OBJECT
)
assert
(!
w
.
isConvertibleFrom
(
BOOLEAN
));
}
// check relations with signed integral types:
if
(
w
.
isSigned
())
{
for
(
Wrapper
x
:
values
())
{
if
(
w
==
x
)
continue
;
if
(
x
.
isFloating
())
assert
(!
w
.
isConvertibleFrom
(
x
));
else
if
(
x
.
isSigned
())
{
if
(
w
.
compareTo
(
x
)
<
0
)
assert
(!
w
.
isConvertibleFrom
(
x
));
else
assert
(
w
.
isConvertibleFrom
(
x
));
}
}
}
// check relations with floating types:
if
(
w
.
isFloating
())
{
for
(
Wrapper
x
:
values
())
{
if
(
w
==
x
)
continue
;
if
(
x
.
isSigned
())
assert
(
w
.
isConvertibleFrom
(
x
));
else
if
(
x
.
isFloating
())
{
if
(
w
.
compareTo
(
x
)
<
0
)
assert
(!
w
.
isConvertibleFrom
(
x
));
else
assert
(
w
.
isConvertibleFrom
(
x
));
}
}
}
}
return
true
;
// i.e., assert(true)
}
/** Produce a zero value for the given wrapper type.
/** Produce a zero value for the given wrapper type.
* This will be a numeric zero for a number or character,
* This will be a numeric zero for a number or character,
* false for a boolean, and null for a reference or void.
* false for a boolean, and null for a reference or void.
...
@@ -549,7 +623,7 @@ public enum Wrapper {
...
@@ -549,7 +623,7 @@ public enum Wrapper {
}
}
private
static
boolean
boolValue
(
long
bits
)
{
private
static
boolean
boolValue
(
long
bits
)
{
//
bits &= 1; // simple 31-bit zero extension
bits
&=
1
;
// simple 31-bit zero extension
return
(
bits
!=
0
);
return
(
bits
!=
0
);
}
}
...
@@ -559,4 +633,31 @@ public enum Wrapper {
...
@@ -559,4 +633,31 @@ public enum Wrapper {
private
static
RuntimeException
newIllegalArgumentException
(
String
message
)
{
private
static
RuntimeException
newIllegalArgumentException
(
String
message
)
{
return
new
IllegalArgumentException
(
message
);
return
new
IllegalArgumentException
(
message
);
}
}
// primitive array support
public
Object
makeArray
(
int
len
)
{
return
java
.
lang
.
reflect
.
Array
.
newInstance
(
primitiveType
,
len
);
}
public
Class
<?>
arrayType
()
{
return
emptyArray
.
getClass
();
}
public
void
copyArrayUnboxing
(
Object
[]
values
,
int
vpos
,
Object
a
,
int
apos
,
int
length
)
{
if
(
a
.
getClass
()
!=
arrayType
())
arrayType
().
cast
(
a
);
// throw NPE or CCE if bad type
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
Object
value
=
values
[
i
+
vpos
];
value
=
convert
(
value
,
primitiveType
);
java
.
lang
.
reflect
.
Array
.
set
(
a
,
i
+
apos
,
value
);
}
}
public
void
copyArrayBoxing
(
Object
a
,
int
apos
,
Object
[]
values
,
int
vpos
,
int
length
)
{
if
(
a
.
getClass
()
!=
arrayType
())
arrayType
().
cast
(
a
);
// throw NPE or CCE if bad type
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
Object
value
=
java
.
lang
.
reflect
.
Array
.
get
(
a
,
i
+
apos
);
//Already done: value = convert(value, primitiveType);
assert
(
value
.
getClass
()
==
wrapperType
);
values
[
i
+
vpos
]
=
value
;
}
}
}
}
src/share/classes/sun/java2d/opengl/OGLRenderer.java
浏览文件 @
8c50098c
...
@@ -102,15 +102,20 @@ class OGLRenderer extends BufferedRenderPipe {
...
@@ -102,15 +102,20 @@ class OGLRenderer extends BufferedRenderPipe {
final
ParallelogramPipe
realpipe
=
oglr
.
getAAParallelogramPipe
();
final
ParallelogramPipe
realpipe
=
oglr
.
getAAParallelogramPipe
();
return
new
ParallelogramPipe
()
{
return
new
ParallelogramPipe
()
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLFillAAParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"OGLFillAAParallelogram"
);
realpipe
.
fillParallelogram
(
sg2d
,
realpipe
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
@@ -118,6 +123,7 @@ class OGLRenderer extends BufferedRenderPipe {
...
@@ -118,6 +123,7 @@ class OGLRenderer extends BufferedRenderPipe {
{
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLDrawAAParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"OGLDrawAAParallelogram"
);
realpipe
.
drawParallelogram
(
sg2d
,
realpipe
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
lw1
,
lw2
);
}
}
...
@@ -166,21 +172,29 @@ class OGLRenderer extends BufferedRenderPipe {
...
@@ -166,21 +172,29 @@ class OGLRenderer extends BufferedRenderPipe {
oglr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
oglr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLFillParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"OGLFillParallelogram"
);
oglr
.
fillParallelogram
(
sg2d
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
oglr
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
double
lw1
,
double
lw2
)
double
lw1
,
double
lw2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLDrawParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"OGLDrawParallelogram"
);
oglr
.
drawParallelogram
(
sg2d
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
oglr
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
}
}
public
void
copyArea
(
SunGraphics2D
sg2d
,
public
void
copyArea
(
SunGraphics2D
sg2d
,
int
x
,
int
y
,
int
w
,
int
h
,
int
dx
,
int
dy
)
int
x
,
int
y
,
int
w
,
int
h
,
int
dx
,
int
dy
)
...
...
src/share/classes/sun/java2d/pipe/AAShapePipe.java
浏览文件 @
8c50098c
...
@@ -68,21 +68,23 @@ public class AAShapePipe
...
@@ -68,21 +68,23 @@ public class AAShapePipe
renderPath
(
sg
,
s
,
null
);
renderPath
(
sg
,
s
,
null
);
}
}
private
static
Rectangle2D
computeBBox
(
double
x
,
double
y
,
private
static
Rectangle2D
computeBBox
(
double
ux1
,
double
uy1
,
double
dx1
,
double
dy1
,
double
ux2
,
double
uy2
)
double
dx2
,
double
dy2
)
{
{
double
lox
,
loy
,
hix
,
hiy
;
if
((
ux2
-=
ux1
)
<
0
)
{
lox
=
hix
=
x
;
ux1
+=
ux2
;
loy
=
hiy
=
y
;
ux2
=
-
ux2
;
if
(
dx1
<
0
)
{
lox
+=
dx1
;
}
else
{
hix
+=
dx1
;
}
}
if
(
dy1
<
0
)
{
loy
+=
dy1
;
}
else
{
hiy
+=
dy1
;
}
if
((
uy2
-=
uy1
)
<
0
)
{
if
(
dx2
<
0
)
{
lox
+=
dx2
;
}
else
{
hix
+=
dx2
;
}
uy1
+=
uy2
;
if
(
dy2
<
0
)
{
loy
+=
dy2
;
}
else
{
hiy
+=
dy2
;
}
uy2
=
-
uy2
;
return
new
Rectangle2D
.
Double
(
lox
,
loy
,
hix
-
lox
,
hiy
-
loy
);
}
return
new
Rectangle2D
.
Double
(
ux1
,
uy1
,
ux2
,
uy2
);
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg
,
public
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
...
@@ -97,10 +99,12 @@ public class AAShapePipe
...
@@ -97,10 +99,12 @@ public class AAShapePipe
return
;
return
;
}
}
renderTiles
(
sg
,
computeBBox
(
x
,
y
,
dx1
,
dy1
,
dx2
,
d
y2
),
aatg
,
abox
);
renderTiles
(
sg
,
computeBBox
(
ux1
,
uy1
,
ux2
,
u
y2
),
aatg
,
abox
);
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg
,
public
void
drawParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
@@ -118,7 +122,7 @@ public class AAShapePipe
...
@@ -118,7 +122,7 @@ public class AAShapePipe
// Note that bbox is of the original shape, not the wide path.
// Note that bbox is of the original shape, not the wide path.
// This is appropriate for handing to Paint methods...
// This is appropriate for handing to Paint methods...
renderTiles
(
sg
,
computeBBox
(
x
,
y
,
dx1
,
dy1
,
dx2
,
d
y2
),
aatg
,
abox
);
renderTiles
(
sg
,
computeBBox
(
ux1
,
uy1
,
ux2
,
u
y2
),
aatg
,
abox
);
}
}
private
static
byte
[]
theTile
;
private
static
byte
[]
theTile
;
...
...
src/share/classes/sun/java2d/pipe/AlphaColorPipe.java
浏览文件 @
8c50098c
...
@@ -66,6 +66,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
...
@@ -66,6 +66,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg
,
public
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
...
@@ -75,6 +77,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
...
@@ -75,6 +77,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg
,
public
void
drawParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/BufferedRenderPipe.java
浏览文件 @
8c50098c
...
@@ -408,6 +408,8 @@ public abstract class BufferedRenderPipe
...
@@ -408,6 +408,8 @@ public abstract class BufferedRenderPipe
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
...
@@ -429,6 +431,8 @@ public abstract class BufferedRenderPipe
...
@@ -429,6 +431,8 @@ public abstract class BufferedRenderPipe
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
@@ -454,6 +458,8 @@ public abstract class BufferedRenderPipe
...
@@ -454,6 +458,8 @@ public abstract class BufferedRenderPipe
private
class
AAParallelogramPipe
implements
ParallelogramPipe
{
private
class
AAParallelogramPipe
implements
ParallelogramPipe
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
...
@@ -475,6 +481,8 @@ public abstract class BufferedRenderPipe
...
@@ -475,6 +481,8 @@ public abstract class BufferedRenderPipe
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/LoopPipe.java
浏览文件 @
8c50098c
...
@@ -352,6 +352,8 @@ public class LoopPipe
...
@@ -352,6 +352,8 @@ public class LoopPipe
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
...
@@ -362,6 +364,8 @@ public class LoopPipe
...
@@ -362,6 +364,8 @@ public class LoopPipe
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/ParallelogramPipe.java
浏览文件 @
8c50098c
/*
/*
* Copyright (c) 2008, 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.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -40,9 +40,17 @@ import sun.java2d.SunGraphics2D;
...
@@ -40,9 +40,17 @@ import sun.java2d.SunGraphics2D;
* => (x+dx2, y+dy2)
* => (x+dx2, y+dy2)
* => origin
* => origin
* </pre>
* </pre>
* The four u[xy][12] parameters are the unsorted extreme coordinates
* of the primitive in user space. They may have been generated by a
* line or a rectangle so they could have u[xy]2 < u[xy]1 in some cases.
* They should be sorted before calculating the bounds of the original
* primitive (such as for calculating the user space bounds for the
* Paint.createContext() method).
*/
*/
public
interface
ParallelogramPipe
{
public
interface
ParallelogramPipe
{
public
void
fillParallelogram
(
SunGraphics2D
sg
,
public
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
);
double
dx2
,
double
dy2
);
...
@@ -59,6 +67,8 @@ public interface ParallelogramPipe {
...
@@ -59,6 +67,8 @@ public interface ParallelogramPipe {
* difference between the outer and inner parallelograms.
* difference between the outer and inner parallelograms.
*/
*/
public
void
drawParallelogram
(
SunGraphics2D
sg
,
public
void
drawParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java
浏览文件 @
8c50098c
...
@@ -175,8 +175,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -175,8 +175,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
}
}
public
boolean
drawGeneralLine
(
SunGraphics2D
sg2d
,
public
boolean
drawGeneralLine
(
SunGraphics2D
sg2d
,
double
x1
,
double
y1
,
double
ux1
,
double
u
y1
,
double
x2
,
double
y2
)
double
ux2
,
double
u
y2
)
{
{
if
(
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_CUSTOM
||
if
(
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_CUSTOM
||
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_THINDASHED
)
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_THINDASHED
)
...
@@ -194,13 +194,14 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -194,13 +194,14 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
double
lw
=
bs
.
getLineWidth
();
double
lw
=
bs
.
getLineWidth
();
// Save the original dx, dy in case we need it to transform
// Save the original dx, dy in case we need it to transform
// the linewidth as a perpendicular vector below
// the linewidth as a perpendicular vector below
double
dx
=
x2
-
x1
;
double
dx
=
ux2
-
ux1
;
double
dy
=
y2
-
y1
;
double
dy
=
uy2
-
uy1
;
double
x1
,
y1
,
x2
,
y2
;
switch
(
sg2d
.
transformState
)
{
switch
(
sg2d
.
transformState
)
{
case
SunGraphics2D
.
TRANSFORM_GENERIC
:
case
SunGraphics2D
.
TRANSFORM_GENERIC
:
case
SunGraphics2D
.
TRANSFORM_TRANSLATESCALE
:
case
SunGraphics2D
.
TRANSFORM_TRANSLATESCALE
:
{
{
double
coords
[]
=
{
x1
,
y1
,
x2
,
y2
};
double
coords
[]
=
{
ux1
,
uy1
,
ux2
,
u
y2
};
sg2d
.
transform
.
transform
(
coords
,
0
,
coords
,
0
,
2
);
sg2d
.
transform
.
transform
(
coords
,
0
,
coords
,
0
,
2
);
x1
=
coords
[
0
];
x1
=
coords
[
0
];
y1
=
coords
[
1
];
y1
=
coords
[
1
];
...
@@ -213,13 +214,17 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -213,13 +214,17 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
{
{
double
tx
=
sg2d
.
transform
.
getTranslateX
();
double
tx
=
sg2d
.
transform
.
getTranslateX
();
double
ty
=
sg2d
.
transform
.
getTranslateY
();
double
ty
=
sg2d
.
transform
.
getTranslateY
();
x1
+=
tx
;
x1
=
ux1
+
tx
;
y1
+=
ty
;
y1
=
uy1
+
ty
;
x2
+=
tx
;
x2
=
ux2
+
tx
;
y2
+=
ty
;
y2
=
uy2
+
ty
;
}
}
break
;
break
;
case
SunGraphics2D
.
TRANSFORM_ISIDENT
:
case
SunGraphics2D
.
TRANSFORM_ISIDENT
:
x1
=
ux1
;
y1
=
uy1
;
x2
=
ux2
;
y2
=
uy2
;
break
;
break
;
default
:
default
:
throw
new
InternalError
(
"unknown TRANSFORM state..."
);
throw
new
InternalError
(
"unknown TRANSFORM state..."
);
...
@@ -279,7 +284,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -279,7 +284,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
dx
+=
udx
;
dx
+=
udx
;
dy
+=
udy
;
dy
+=
udy
;
}
}
outrenderer
.
fillParallelogram
(
sg2d
,
px
,
py
,
-
udy
,
udx
,
dx
,
dy
);
outrenderer
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
px
,
py
,
-
udy
,
udx
,
dx
,
dy
);
return
true
;
return
true
;
}
}
...
@@ -313,7 +319,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -313,7 +319,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
px
=
newx
;
px
=
newx
;
py
=
newy
;
py
=
newy
;
}
}
outrenderer
.
fillParallelogram
(
sg2d
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
);
outrenderer
.
fillParallelogram
(
sg2d
,
rx
,
ry
,
rx
+
rw
,
ry
+
rh
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
public
void
drawRectangle
(
SunGraphics2D
sg2d
,
public
void
drawRectangle
(
SunGraphics2D
sg2d
,
...
@@ -360,10 +367,12 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -360,10 +367,12 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
// entire hole in the middle of the parallelogram
// entire hole in the middle of the parallelogram
// so we can just fill the outer parallelogram.
// so we can just fill the outer parallelogram.
fillOuterParallelogram
(
sg2d
,
fillOuterParallelogram
(
sg2d
,
rx
,
ry
,
rx
+
rw
,
ry
+
rh
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
len1
,
len2
,
lw1
,
lw2
);
len1
,
len2
,
lw1
,
lw2
);
}
else
{
}
else
{
outrenderer
.
drawParallelogram
(
sg2d
,
outrenderer
.
drawParallelogram
(
sg2d
,
rx
,
ry
,
rx
+
rw
,
ry
+
rh
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
/
len1
,
lw2
/
len2
);
lw1
/
len1
,
lw2
/
len2
);
}
}
...
@@ -377,6 +386,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -377,6 +386,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
* and issues a single fillParallelogram request to fill it.
* and issues a single fillParallelogram request to fill it.
*/
*/
public
void
fillOuterParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillOuterParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
px
,
double
py
,
double
px
,
double
py
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
@@ -412,6 +423,7 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
...
@@ -412,6 +423,7 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
dx2
+=
udx2
;
dx2
+=
udx2
;
dy2
+=
udy2
;
dy2
+=
udy2
;
outrenderer
.
fillParallelogram
(
sg2d
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
);
outrenderer
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
}
}
src/share/classes/sun/text/bidi/BidiBase.java
浏览文件 @
8c50098c
...
@@ -2889,10 +2889,6 @@ public class BidiBase {
...
@@ -2889,10 +2889,6 @@ public class BidiBase {
verifyValidPara
();
verifyValidPara
();
verifyRange
(
start
,
0
,
limit
);
verifyRange
(
start
,
0
,
limit
);
verifyRange
(
limit
,
0
,
length
+
1
);
verifyRange
(
limit
,
0
,
length
+
1
);
if
(
getParagraphIndex
(
start
)
!=
getParagraphIndex
(
limit
-
1
))
{
/* the line crosses a paragraph boundary */
throw
new
IllegalArgumentException
();
}
return
BidiLine
.
setLine
(
bidi
,
this
,
newBidi
,
newBidiBase
,
start
,
limit
);
return
BidiLine
.
setLine
(
bidi
,
this
,
newBidi
,
newBidiBase
,
start
,
limit
);
}
}
...
...
src/solaris/classes/sun/awt/X11/XRobotPeer.java
浏览文件 @
8c50098c
...
@@ -48,7 +48,7 @@ class XRobotPeer implements RobotPeer {
...
@@ -48,7 +48,7 @@ class XRobotPeer implements RobotPeer {
}
}
public
void
dispose
()
{
public
void
dispose
()
{
_dispose
();
// does nothing
}
}
public
void
mouseMove
(
int
x
,
int
y
)
{
public
void
mouseMove
(
int
x
,
int
y
)
{
...
@@ -88,7 +88,6 @@ class XRobotPeer implements RobotPeer {
...
@@ -88,7 +88,6 @@ class XRobotPeer implements RobotPeer {
}
}
private
static
native
synchronized
void
setup
(
int
numberOfButtons
,
int
[]
buttonDownMasks
);
private
static
native
synchronized
void
setup
(
int
numberOfButtons
,
int
[]
buttonDownMasks
);
private
static
native
synchronized
void
_dispose
();
private
static
native
synchronized
void
mouseMoveImpl
(
X11GraphicsConfig
xgc
,
int
x
,
int
y
);
private
static
native
synchronized
void
mouseMoveImpl
(
X11GraphicsConfig
xgc
,
int
x
,
int
y
);
private
static
native
synchronized
void
mousePressImpl
(
int
buttons
);
private
static
native
synchronized
void
mousePressImpl
(
int
buttons
);
...
...
src/solaris/native/sun/awt/awt_Robot.c
浏览文件 @
8c50098c
...
@@ -48,28 +48,12 @@
...
@@ -48,28 +48,12 @@
#ifdef __linux__
#ifdef __linux__
#include <sys/socket.h>
#include <sys/socket.h>
#endif
#endif
#include <dlfcn.h>
extern
struct
X11GraphicsConfigIDs
x11GraphicsConfigIDs
;
extern
struct
X11GraphicsConfigIDs
x11GraphicsConfigIDs
;
static
jint
*
masks
;
static
jint
*
masks
;
static
jint
num_buttons
;
static
jint
num_buttons
;
static
unsigned
int
s_robotInstanceCounter
=
0
;
static
void
*
xcompositeLibHandle
=
NULL
;
static
Bool
xcompositeExtAvailable
=
False
;
static
Bool
xcompositeExtTested
=
False
;
typedef
Status
(
*
T_XCompositeQueryVersion
)(
Display
*
dpy
,
int
*
major_versionp
,
int
*
minor_versionp
);
typedef
Window
(
*
T_XCompositeGetOverlayWindow
)(
Display
*
dpy
,
Window
window
);
typedef
void
(
*
T_XCompositeReleaseOverlayWindow
)(
Display
*
dpy
,
Window
window
);
static
T_XCompositeQueryVersion
XCompositeQueryVersion
=
NULL
;
static
T_XCompositeGetOverlayWindow
XCompositeGetOverlayWindow
=
NULL
;
static
T_XCompositeReleaseOverlayWindow
XCompositeReleaseOverlayWindow
=
NULL
;
static
int32_t
isXTestAvailable
()
{
static
int32_t
isXTestAvailable
()
{
int32_t
major_opcode
,
first_event
,
first_error
;
int32_t
major_opcode
,
first_event
,
first_error
;
int32_t
event_basep
,
error_basep
,
majorp
,
minorp
;
int32_t
event_basep
,
error_basep
,
majorp
,
minorp
;
...
@@ -210,80 +194,8 @@ Java_sun_awt_X11_XRobotPeer_setup (JNIEnv * env, jclass cls, jint numberOfButton
...
@@ -210,80 +194,8 @@ Java_sun_awt_X11_XRobotPeer_setup (JNIEnv * env, jclass cls, jint numberOfButton
}
}
AWT_UNLOCK
();
AWT_UNLOCK
();
s_robotInstanceCounter
++
;
}
}
JNIEXPORT
void
JNICALL
Java_sun_awt_X11_XRobotPeer__1dispose
(
JNIEnv
*
env
,
jclass
cls
)
{
if
(
--
s_robotInstanceCounter
)
{
return
;
}
// This is the last instance of the XRobotPeer being released
if
(
xcompositeExtTested
&&
xcompositeExtAvailable
&&
xcompositeLibHandle
)
{
// The lib is loaded in IsXCompositeAvailable(). Unload under AWT_LOCK
// so that the shutdown function of the lib behaves correctly.
AWT_LOCK
();
dlclose
(
xcompositeLibHandle
);
AWT_UNLOCK
();
}
xcompositeExtTested
=
False
;
xcompositeExtAvailable
=
False
;
xcompositeLibHandle
=
NULL
;
}
/*
* Returns True only if XCOMPOSITE is of version 0.3 or higher.
* The functions that we need are available since that version.
*
* Must be invoked under AWT_LOCK.
*
* Leaves the library loaded if the version is correct.
*/
static
Bool
IsXCompositeAvailable
()
{
if
(
!
xcompositeExtTested
)
{
int
opcode
,
eventb
,
errorb
;
if
(
XQueryExtension
(
awt_display
,
"Composite"
,
&
opcode
,
&
eventb
,
&
errorb
))
{
xcompositeLibHandle
=
dlopen
(
"libXcomposite.so.1"
,
RTLD_LAZY
|
RTLD_GLOBAL
);
#ifndef __linux__
/* SOLARIS */
if
(
xcompositeLibHandle
==
NULL
)
{
xcompositeLibHandle
=
dlopen
(
"/usr/sfw/lib/libXcomposite.so.1"
,
RTLD_LAZY
|
RTLD_GLOBAL
);
}
#endif
if
(
xcompositeLibHandle
)
{
int
major
,
minor
;
XCompositeQueryVersion
=
(
T_XCompositeQueryVersion
)
dlsym
(
xcompositeLibHandle
,
"XCompositeQueryVersion"
);
if
(
XCompositeQueryVersion
&&
XCompositeQueryVersion
(
awt_display
,
&
major
,
&
minor
))
{
if
(
major
>=
0
&&
minor
>=
3
)
{
XCompositeGetOverlayWindow
=
(
T_XCompositeGetOverlayWindow
)
dlsym
(
xcompositeLibHandle
,
"XCompositeGetOverlayWindow"
);
XCompositeReleaseOverlayWindow
=
(
T_XCompositeReleaseOverlayWindow
)
dlsym
(
xcompositeLibHandle
,
"XCompositeReleaseOverlayWindow"
);
if
(
XCompositeGetOverlayWindow
&&
XCompositeReleaseOverlayWindow
)
{
xcompositeExtAvailable
=
True
;
}
}
}
if
(
!
xcompositeExtAvailable
)
{
dlclose
(
xcompositeLibHandle
);
}
/* else the lib is unloaded in _dispose() */
}
}
xcompositeExtTested
=
True
;
}
return
xcompositeExtAvailable
;
}
JNIEXPORT
void
JNICALL
JNIEXPORT
void
JNICALL
Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl
(
JNIEnv
*
env
,
Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl
(
JNIEnv
*
env
,
...
@@ -299,7 +211,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
...
@@ -299,7 +211,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
jint
*
ary
;
/* Array of jints for sending pixel values back
jint
*
ary
;
/* Array of jints for sending pixel values back
* to parent process.
* to parent process.
*/
*/
Window
w
indow
;
Window
rootW
indow
;
AwtGraphicsConfigDataPtr
adata
;
AwtGraphicsConfigDataPtr
adata
;
DTRACE_PRINTLN6
(
"RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)"
,
xgc
,
x
,
y
,
width
,
height
,
pixelArray
);
DTRACE_PRINTLN6
(
"RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)"
,
xgc
,
x
,
y
,
width
,
height
,
pixelArray
);
...
@@ -316,24 +228,14 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
...
@@ -316,24 +228,14 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
adata
=
(
AwtGraphicsConfigDataPtr
)
JNU_GetLongFieldAsPtr
(
env
,
xgc
,
x11GraphicsConfigIDs
.
aData
);
adata
=
(
AwtGraphicsConfigDataPtr
)
JNU_GetLongFieldAsPtr
(
env
,
xgc
,
x11GraphicsConfigIDs
.
aData
);
DASSERT
(
adata
!=
NULL
);
DASSERT
(
adata
!=
NULL
);
window
=
XRootWindow
(
awt_display
,
adata
->
awt_visInfo
.
screen
);
rootWindow
=
XRootWindow
(
awt_display
,
adata
->
awt_visInfo
.
screen
);
image
=
getWindowImage
(
awt_display
,
rootWindow
,
x
,
y
,
width
,
height
);
if
(
IsXCompositeAvailable
())
{
// Use 'composite overlay window' instead of the root window.
// See 6903034 for details.
window
=
XCompositeGetOverlayWindow
(
awt_display
,
window
);
}
image
=
getWindowImage
(
awt_display
,
window
,
x
,
y
,
width
,
height
);
/* Array to use to crunch around the pixel values */
/* Array to use to crunch around the pixel values */
ary
=
(
jint
*
)
malloc
(
width
*
height
*
sizeof
(
jint
));
ary
=
(
jint
*
)
malloc
(
width
*
height
*
sizeof
(
jint
));
if
(
ary
==
NULL
)
{
if
(
ary
==
NULL
)
{
JNU_ThrowOutOfMemoryError
(
env
,
"OutOfMemoryError"
);
JNU_ThrowOutOfMemoryError
(
env
,
"OutOfMemoryError"
);
XDestroyImage
(
image
);
XDestroyImage
(
image
);
if
(
IsXCompositeAvailable
())
{
XCompositeReleaseOverlayWindow
(
awt_display
,
window
);
}
AWT_UNLOCK
();
AWT_UNLOCK
();
return
;
return
;
}
}
...
@@ -354,9 +256,6 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
...
@@ -354,9 +256,6 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
free
(
ary
);
free
(
ary
);
XDestroyImage
(
image
);
XDestroyImage
(
image
);
if
(
IsXCompositeAvailable
())
{
XCompositeReleaseOverlayWindow
(
awt_display
,
window
);
}
AWT_UNLOCK
();
AWT_UNLOCK
();
}
}
...
...
src/windows/classes/sun/awt/windows/WFramePeer.java
浏览文件 @
8c50098c
...
@@ -107,8 +107,16 @@ class WFramePeer extends WWindowPeer implements FramePeer {
...
@@ -107,8 +107,16 @@ class WFramePeer extends WWindowPeer implements FramePeer {
Rectangle
currentDevBounds
=
currentDevGC
.
getBounds
();
Rectangle
currentDevBounds
=
currentDevGC
.
getBounds
();
Rectangle
primaryDevBounds
=
primaryDevGC
.
getBounds
();
Rectangle
primaryDevBounds
=
primaryDevGC
.
getBounds
();
b
.
width
-=
(
currentDevBounds
.
width
-
primaryDevBounds
.
width
);
boolean
isCurrentDevLarger
=
b
.
height
-=
(
currentDevBounds
.
height
-
primaryDevBounds
.
height
);
((
currentDevBounds
.
width
-
primaryDevBounds
.
width
>
0
)
||
(
currentDevBounds
.
height
-
primaryDevBounds
.
height
>
0
));
// the window manager doesn't seem to compensate for differences when
// the primary monitor is larger than the monitor that display the window
if
(
isCurrentDevLarger
)
{
b
.
width
-=
(
currentDevBounds
.
width
-
primaryDevBounds
.
width
);
b
.
height
-=
(
currentDevBounds
.
height
-
primaryDevBounds
.
height
);
}
}
}
}
}
...
...
src/windows/classes/sun/java2d/d3d/D3DRenderer.java
浏览文件 @
8c50098c
...
@@ -102,15 +102,20 @@ class D3DRenderer extends BufferedRenderPipe {
...
@@ -102,15 +102,20 @@ class D3DRenderer extends BufferedRenderPipe {
final
ParallelogramPipe
realpipe
=
d3dr
.
getAAParallelogramPipe
();
final
ParallelogramPipe
realpipe
=
d3dr
.
getAAParallelogramPipe
();
return
new
ParallelogramPipe
()
{
return
new
ParallelogramPipe
()
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DFillAAParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"D3DFillAAParallelogram"
);
realpipe
.
fillParallelogram
(
sg2d
,
realpipe
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
...
@@ -118,6 +123,7 @@ class D3DRenderer extends BufferedRenderPipe {
...
@@ -118,6 +123,7 @@ class D3DRenderer extends BufferedRenderPipe {
{
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DDrawAAParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"D3DDrawAAParallelogram"
);
realpipe
.
drawParallelogram
(
sg2d
,
realpipe
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
lw1
,
lw2
);
}
}
...
@@ -167,21 +173,29 @@ class D3DRenderer extends BufferedRenderPipe {
...
@@ -167,21 +173,29 @@ class D3DRenderer extends BufferedRenderPipe {
d3dr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
d3dr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
}
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
double
dx2
,
double
dy2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DFillParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"D3DFillParallelogram"
);
d3dr
.
fillParallelogram
(
sg2d
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
d3dr
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
dx2
,
double
dy2
,
double
lw1
,
double
lw2
)
double
lw1
,
double
lw2
)
{
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DDrawParallelogram"
);
GraphicsPrimitive
.
tracePrimitive
(
"D3DDrawParallelogram"
);
d3dr
.
drawParallelogram
(
sg2d
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
d3dr
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
}
}
public
void
copyArea
(
SunGraphics2D
sg2d
,
public
void
copyArea
(
SunGraphics2D
sg2d
,
int
x
,
int
y
,
int
w
,
int
h
,
int
dx
,
int
dy
)
int
x
,
int
y
,
int
w
,
int
h
,
int
dx
,
int
dy
)
...
...
src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
浏览文件 @
8c50098c
...
@@ -192,6 +192,14 @@ void D3DPipelineManager::NotifyAdapterEventListeners(UINT adapter,
...
@@ -192,6 +192,14 @@ void D3DPipelineManager::NotifyAdapterEventListeners(UINT adapter,
pMgr
=
D3DPipelineManager
::
GetInstance
();
pMgr
=
D3DPipelineManager
::
GetInstance
();
RETURN_IF_NULL
(
pMgr
);
RETURN_IF_NULL
(
pMgr
);
hMon
=
pMgr
->
pd3d9
->
GetAdapterMonitor
(
adapter
);
hMon
=
pMgr
->
pd3d9
->
GetAdapterMonitor
(
adapter
);
/*
* If we don't have devices initialized yet, no sense to clear them.
*/
if
(
!
Devices
::
GetInstance
()){
return
;
}
gdiScreen
=
AwtWin32GraphicsDevice
::
GetScreenFromHMONITOR
(
hMon
);
gdiScreen
=
AwtWin32GraphicsDevice
::
GetScreenFromHMONITOR
(
hMon
);
JNU_CallStaticMethodByName
(
env
,
NULL
,
JNU_CallStaticMethodByName
(
env
,
NULL
,
...
...
src/windows/native/sun/windows/Devices.h
浏览文件 @
8c50098c
...
@@ -36,6 +36,7 @@ class AwtWin32GraphicsDevice;
...
@@ -36,6 +36,7 @@ class AwtWin32GraphicsDevice;
class
Devices
{
class
Devices
{
public:
public:
static
Devices
*
GetInstance
();
static
BOOL
UpdateInstance
(
JNIEnv
*
env
);
static
BOOL
UpdateInstance
(
JNIEnv
*
env
);
int
GetNumDevices
()
{
return
numDevices
;
}
int
GetNumDevices
()
{
return
numDevices
;
}
AwtWin32GraphicsDevice
*
GetDeviceReference
(
int
index
,
BOOL
adjust
=
TRUE
);
AwtWin32GraphicsDevice
*
GetDeviceReference
(
int
index
,
BOOL
adjust
=
TRUE
);
...
@@ -59,7 +60,6 @@ friend class InstanceAccess;
...
@@ -59,7 +60,6 @@ friend class InstanceAccess;
private:
private:
Devices
(
int
numElements
);
Devices
(
int
numElements
);
void
AddReference
();
void
AddReference
();
static
Devices
*
GetInstance
();
AwtWin32GraphicsDevice
**
devices
;
AwtWin32GraphicsDevice
**
devices
;
int
refCount
;
int
refCount
;
...
...
src/windows/native/sun/windows/awt_Choice.cpp
浏览文件 @
8c50098c
...
@@ -396,6 +396,12 @@ LRESULT CALLBACK AwtChoice::ListWindowProc(HWND hwnd, UINT message,
...
@@ -396,6 +396,12 @@ LRESULT CALLBACK AwtChoice::ListWindowProc(HWND hwnd, UINT message,
DASSERT
(
::
IsWindow
(
hwnd
));
DASSERT
(
::
IsWindow
(
hwnd
));
// This branch is required for the proper work of AwtComponent::GetComponent() method
// while hovering drop-down list
if
(
message
==
WmAwtIsComponent
)
{
return
(
LRESULT
)
TRUE
;
}
switch
(
message
)
{
switch
(
message
)
{
case
WM_LBUTTONDOWN
:
{
case
WM_LBUTTONDOWN
:
{
DWORD
curPos
=
::
GetMessagePos
();
DWORD
curPos
=
::
GetMessagePos
();
...
...
src/windows/native/sun/windows/awt_Component.cpp
浏览文件 @
8c50098c
...
@@ -364,7 +364,6 @@ AwtComponent* AwtComponent::GetComponentImpl(HWND hWnd) {
...
@@ -364,7 +364,6 @@ AwtComponent* AwtComponent::GetComponentImpl(HWND hWnd) {
AwtComponent
*
component
=
AwtComponent
*
component
=
(
AwtComponent
*
)
::
GetWindowLongPtr
(
hWnd
,
GWLP_USERDATA
);
(
AwtComponent
*
)
::
GetWindowLongPtr
(
hWnd
,
GWLP_USERDATA
);
DASSERT
(
!
component
||
!
IsBadReadPtr
(
component
,
sizeof
(
AwtComponent
))
);
DASSERT
(
!
component
||
!
IsBadReadPtr
(
component
,
sizeof
(
AwtComponent
))
);
DASSERT
(
!
component
||
component
->
GetHWnd
()
==
hWnd
);
return
component
;
return
component
;
}
}
...
...
src/windows/native/sun/windows/awt_Frame.cpp
浏览文件 @
8c50098c
...
@@ -344,17 +344,6 @@ LRESULT AwtFrame::ProxyWindowProc(UINT message, WPARAM wParam, LPARAM lParam, Ms
...
@@ -344,17 +344,6 @@ LRESULT AwtFrame::ProxyWindowProc(UINT message, WPARAM wParam, LPARAM lParam, Ms
SetImeTargetComponent
(
NULL
);
SetImeTargetComponent
(
NULL
);
}
}
break
;
break
;
// TODO: when a Choice's list is dropped down and we're scrolling in
// the list WM_MOUSEWHEEL messages come to the poxy, not to the list. Why?
case
WM_MOUSEWHEEL
:
focusOwner
=
AwtComponent
::
GetComponent
(
sm_focusOwner
);
if
(
focusOwner
!=
NULL
&&
focusOwner
!=
this
)
// avoid recursive calls
{
retValue
=
focusOwner
->
WindowProc
(
message
,
wParam
,
lParam
);
mr
=
mrConsume
;
}
break
;
case
WM_SETFOCUS
:
case
WM_SETFOCUS
:
if
(
sm_inSynthesizeFocus
)
break
;
// pass it up the WindowProc chain
if
(
sm_inSynthesizeFocus
)
break
;
// pass it up the WindowProc chain
...
...
test/java/awt/Component/Revalidate/Revalidate.java
浏览文件 @
8c50098c
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
@bug 7036669
@bug 7036669
@summary Test Component.revalidate() method
@summary Test Component.revalidate() method
@author anthony.petrov@oracle.com: area=awt.component
@author anthony.petrov@oracle.com: area=awt.component
@run main Revalidate
@run main
/othervm -Djava.awt.smartInvalidate=true
Revalidate
*/
*/
import
java.awt.*
;
import
java.awt.*
;
...
...
test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java
浏览文件 @
8c50098c
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
@bug 6852592
@bug 6852592
@summary invalidate() must stop when it encounters a validate root
@summary invalidate() must stop when it encounters a validate root
@author anthony.petrov@sun.com
@author anthony.petrov@sun.com
@run main InvalidateMustRespectValidateRoots
@run main
/othervm -Djava.awt.smartInvalidate=true
InvalidateMustRespectValidateRoots
*/
*/
import
javax.swing.*
;
import
javax.swing.*
;
...
...
test/java/awt/Paint/PgramUserBoundsTest.java
0 → 100644
浏览文件 @
8c50098c
/*
* 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 7043054
* @summary Verifies that Paint objects receive the appropriate user space
* bounds in their createContext() method
* @run main PgramUserBoundsTest
*/
import
java.awt.Color
;
import
java.awt.Graphics2D
;
import
java.awt.Paint
;
import
java.awt.PaintContext
;
import
java.awt.RenderingHints
;
import
java.awt.Rectangle
;
import
java.awt.geom.AffineTransform
;
import
java.awt.geom.Line2D
;
import
java.awt.geom.Rectangle2D
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.ColorModel
;
public
class
PgramUserBoundsTest
{
static
final
int
MinX
=
10
;
static
final
int
MinY
=
20
;
static
final
int
MaxX
=
30
;
static
final
int
MaxY
=
50
;
static
AffineTransform
identity
=
new
AffineTransform
();
public
static
void
main
(
String
argv
[])
{
BufferedImage
bimg
=
new
BufferedImage
(
100
,
100
,
BufferedImage
.
TYPE_INT_RGB
);
Graphics2D
g2d
=
bimg
.
createGraphics
();
g2d
.
setPaint
(
new
BoundsCheckerPaint
(
MinX
,
MinY
,
MaxX
,
MaxY
));
testAll
(
g2d
);
g2d
.
setRenderingHint
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
testAll
(
g2d
);
}
static
void
testAll
(
Graphics2D
g2d
)
{
g2d
.
setTransform
(
identity
);
g2d
.
translate
(
100
,
100
);
testPrimitives
(
g2d
);
g2d
.
setTransform
(
identity
);
g2d
.
scale
(
10
,
10
);
testPrimitives
(
g2d
);
g2d
.
setTransform
(
identity
);
g2d
.
rotate
(
Math
.
PI
/
6
);
testPrimitives
(
g2d
);
}
static
void
testPrimitives
(
Graphics2D
g2d
)
{
testLine
(
g2d
);
testRect
(
g2d
);
}
static
void
testLine
(
Graphics2D
g2d
)
{
testLine
(
g2d
,
MinX
,
MinY
,
MaxX
,
MaxY
);
testLine
(
g2d
,
MaxX
,
MinY
,
MinX
,
MaxY
);
testLine
(
g2d
,
MinX
,
MaxY
,
MaxX
,
MinY
);
testLine
(
g2d
,
MaxX
,
MaxY
,
MinX
,
MinY
);
}
static
void
testRect
(
Graphics2D
g2d
)
{
g2d
.
fillRect
(
MinX
,
MinY
,
MaxX
-
MinX
,
MaxY
-
MinY
);
g2d
.
fill
(
new
Rectangle
(
MinX
,
MinY
,
MaxX
-
MinX
,
MaxY
-
MinY
));
}
static
void
testLine
(
Graphics2D
g2d
,
int
x1
,
int
y1
,
int
x2
,
int
y2
)
{
g2d
.
drawLine
(
x1
,
y1
,
x2
,
y2
);
g2d
.
draw
(
new
Line2D
.
Double
(
x1
,
y1
,
x2
,
y2
));
}
static
class
BoundsCheckerPaint
implements
Paint
{
private
Color
c
=
Color
.
WHITE
;
private
Rectangle2D
expectedBounds
;
public
BoundsCheckerPaint
(
double
x1
,
double
y1
,
double
x2
,
double
y2
)
{
expectedBounds
=
new
Rectangle2D
.
Double
();
expectedBounds
.
setFrameFromDiagonal
(
x1
,
y1
,
x2
,
y2
);
}
public
int
getTransparency
()
{
return
c
.
getTransparency
();
}
public
PaintContext
createContext
(
ColorModel
cm
,
Rectangle
deviceBounds
,
Rectangle2D
userBounds
,
AffineTransform
xform
,
RenderingHints
hints
)
{
System
.
out
.
println
(
"user bounds = "
+
userBounds
);
if
(!
userBounds
.
equals
(
expectedBounds
))
{
throw
new
RuntimeException
(
"bounds fail to match"
);
}
return
c
.
createContext
(
cm
,
deviceBounds
,
userBounds
,
xform
,
hints
);
}
}
}
test/java/awt/Toolkit/Headless/ExceptionContract/ExceptionContract.java
0 → 100644
浏览文件 @
8c50098c
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
@test
@bug 7040577
@library ../../../regtesthelpers
@build Sysout
@summary Default implementation of Toolkit.loadSystemColors(int[]) and many others doesn't throw HE in hl env
@author andrei dmitriev: area=awt.headless
@run main/othervm -Djava.awt.headless=true ExceptionContract
*/
import
java.awt.*
;
import
java.util.Properties
;
import
test.java.awt.regtesthelpers.Sysout
;
import
java.awt.datatransfer.Clipboard
;
import
java.awt.dnd.*
;
import
java.awt.dnd.peer.DragSourceContextPeer
;
import
java.awt.font.TextAttribute
;
import
java.awt.im.InputMethodHighlight
;
import
java.awt.image.*
;
import
java.awt.peer.*
;
import
java.net.URL
;
import
java.util.Map
;
import
java.util.Properties
;
public
class
ExceptionContract
{
private
static
boolean
passed
=
false
;
public
static
void
main
(
String
[]
args
)
{
//Case1
try
{
new
_Toolkit
().
getLockingKeyState
(
1
);
}
catch
(
HeadlessException
he
){
passed
=
true
;
}
if
(!
passed
){
throw
new
RuntimeException
(
"Tk.getLockingKeyState() didn't throw HeadlessException while in the headless mode."
);
}
passed
=
false
;
//Case2
try
{
new
_Toolkit
().
setLockingKeyState
(
1
,
true
);
}
catch
(
HeadlessException
he
){
passed
=
true
;
}
if
(!
passed
){
throw
new
RuntimeException
(
"Tk.setLockingKeyState() didn't throw HeadlessException while in the headless mode."
);
}
passed
=
false
;
//Case3
try
{
new
_Toolkit
().
createCustomCursor
(
new
BufferedImage
(
16
,
16
,
BufferedImage
.
TYPE_INT_RGB
),
new
Point
(
0
,
0
),
"Custom cursor"
);
}
catch
(
HeadlessException
he
){
he
.
printStackTrace
();
passed
=
true
;
}
if
(!
passed
){
throw
new
RuntimeException
(
"Tk.createCustomCursor(args) didn't throw HeadlessException while in the headless mode."
);
}
}
static
class
_Toolkit
extends
Toolkit
{
@Override
public
Cursor
createCustomCursor
(
Image
cursor
,
Point
hotSpot
,
String
name
)
throws
IndexOutOfBoundsException
,
HeadlessException
{
return
super
.
createCustomCursor
(
cursor
,
hotSpot
,
name
);
}
@Override
public
void
setLockingKeyState
(
int
keyCode
,
boolean
on
)
throws
UnsupportedOperationException
{
super
.
setLockingKeyState
(
keyCode
,
on
);
}
@Override
public
boolean
getLockingKeyState
(
int
keyCode
)
throws
UnsupportedOperationException
{
return
super
.
getLockingKeyState
(
keyCode
);
}
@Override
public
void
loadSystemColors
(
int
[]
systemColors
)
throws
HeadlessException
{
return
;
}
@Override
protected
DesktopPeer
createDesktopPeer
(
Desktop
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
ButtonPeer
createButton
(
Button
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
TextFieldPeer
createTextField
(
TextField
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
LabelPeer
createLabel
(
Label
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
ListPeer
createList
(
List
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
CheckboxPeer
createCheckbox
(
Checkbox
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
ScrollbarPeer
createScrollbar
(
Scrollbar
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
ScrollPanePeer
createScrollPane
(
ScrollPane
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
TextAreaPeer
createTextArea
(
TextArea
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
ChoicePeer
createChoice
(
Choice
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
FramePeer
createFrame
(
Frame
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
CanvasPeer
createCanvas
(
Canvas
target
)
{
return
null
;
}
@Override
protected
PanelPeer
createPanel
(
Panel
target
)
{
return
null
;
}
@Override
protected
WindowPeer
createWindow
(
Window
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
DialogPeer
createDialog
(
Dialog
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
MenuBarPeer
createMenuBar
(
MenuBar
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
MenuPeer
createMenu
(
Menu
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
PopupMenuPeer
createPopupMenu
(
PopupMenu
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
MenuItemPeer
createMenuItem
(
MenuItem
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
FileDialogPeer
createFileDialog
(
FileDialog
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
CheckboxMenuItemPeer
createCheckboxMenuItem
(
CheckboxMenuItem
target
)
throws
HeadlessException
{
return
null
;
}
@Override
protected
FontPeer
getFontPeer
(
String
name
,
int
style
)
{
return
null
;
}
@Override
public
Dimension
getScreenSize
()
throws
HeadlessException
{
return
null
;
}
@Override
public
int
getScreenResolution
()
throws
HeadlessException
{
return
0
;
}
@Override
public
ColorModel
getColorModel
()
throws
HeadlessException
{
return
null
;
}
@Override
public
String
[]
getFontList
()
{
return
new
String
[
0
];
}
@Override
public
FontMetrics
getFontMetrics
(
Font
font
)
{
return
null
;
}
@Override
public
void
sync
()
{
}
@Override
public
Image
getImage
(
String
filename
)
{
return
null
;
}
@Override
public
Image
getImage
(
URL
url
)
{
return
null
;
}
@Override
public
Image
createImage
(
String
filename
)
{
return
null
;
}
@Override
public
Image
createImage
(
URL
url
)
{
return
null
;
}
@Override
public
boolean
prepareImage
(
Image
image
,
int
width
,
int
height
,
ImageObserver
observer
)
{
return
false
;
}
@Override
public
int
checkImage
(
Image
image
,
int
width
,
int
height
,
ImageObserver
observer
)
{
return
0
;
}
@Override
public
Image
createImage
(
ImageProducer
producer
)
{
return
null
;
}
@Override
public
Image
createImage
(
byte
[]
imagedata
,
int
imageoffset
,
int
imagelength
)
{
return
null
;
}
@Override
public
PrintJob
getPrintJob
(
Frame
frame
,
String
jobtitle
,
Properties
props
)
{
return
null
;
}
@Override
public
void
beep
()
{
}
@Override
public
Clipboard
getSystemClipboard
()
throws
HeadlessException
{
return
null
;
}
@Override
protected
EventQueue
getSystemEventQueueImpl
()
{
return
null
;
}
@Override
public
DragSourceContextPeer
createDragSourceContextPeer
(
DragGestureEvent
dge
)
throws
InvalidDnDOperationException
{
return
null
;
}
@Override
public
boolean
isModalityTypeSupported
(
Dialog
.
ModalityType
modalityType
)
{
return
false
;
}
@Override
public
boolean
isModalExclusionTypeSupported
(
Dialog
.
ModalExclusionType
modalExclusionType
)
{
return
false
;
}
@Override
public
Map
<
TextAttribute
,
?>
mapInputMethodHighlight
(
InputMethodHighlight
highlight
)
throws
HeadlessException
{
return
null
;
}
}
}
test/java/awt/geom/Arc2D/SerializationTest.java
0 → 100644
浏览文件 @
8c50098c
/*
* 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 7040717 6522514
* @summary Verifies that subclasses of Arc2D can be serialized.
* @run main SerializationTest
*/
import
java.awt.geom.Rectangle2D
;
import
java.awt.geom.Arc2D
;
import
java.io.Serializable
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.ObjectInputStream
;
import
java.io.ObjectOutputStream
;
public
class
SerializationTest
{
static
boolean
failed
;
public
static
void
main
(
String
args
[])
{
test
(
new
Arc
());
test
(
new
ArcF
());
test
(
new
ArcD
());
if
(
failed
)
throw
new
RuntimeException
(
"some tests failed"
);
}
public
static
void
test
(
Object
a
)
{
try
{
File
objectbin
=
new
File
(
"object.bin"
);
FileOutputStream
fos
=
new
FileOutputStream
(
objectbin
);
ObjectOutputStream
out
=
new
ObjectOutputStream
(
fos
);
out
.
writeObject
(
a
);
fos
.
close
();
FileInputStream
fis
=
new
FileInputStream
(
objectbin
);
ObjectInputStream
in
=
new
ObjectInputStream
(
fis
);
Object
o
=
in
.
readObject
();
fis
.
close
();
System
.
err
.
println
(
o
);
}
catch
(
Throwable
ex
)
{
ex
.
printStackTrace
();
failed
=
true
;
}
}
static
class
Arc
extends
Arc2D
implements
Serializable
{
public
Arc
()
{
super
(
Arc2D
.
OPEN
);
}
public
Rectangle2D
makeBounds
(
double
x
,
double
y
,
double
w
,
double
h
)
{
return
new
Rectangle2D
.
Double
(
x
,
y
,
w
,
h
);
}
public
double
getX
()
{
return
0
;
}
public
double
getY
()
{
return
0
;
}
public
double
getWidth
()
{
return
0
;
}
public
double
getHeight
()
{
return
0
;
}
public
double
getAngleExtent
()
{
return
0
;
}
public
double
getAngleStart
()
{
return
0
;
}
public
void
setAngleExtent
(
double
angExt
)
{
}
public
void
setAngleStart
(
double
angExt
)
{
}
public
void
setFrame
(
double
x
,
double
y
,
double
w
,
double
h
)
{}
public
void
setArc
(
double
x
,
double
y
,
double
w
,
double
h
,
double
s
,
double
e
,
int
c
)
{
}
public
boolean
isEmpty
()
{
return
false
;
};
}
static
class
ArcF
extends
Arc2D
.
Float
implements
Serializable
{
public
ArcF
()
{
}
}
static
class
ArcD
extends
Arc2D
.
Double
implements
Serializable
{
public
ArcD
()
{
}
}
}
test/java/lang/invoke/6998541/Test6998541.java
0 → 100644
浏览文件 @
8c50098c
/*
* 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 6998541
* @summary JSR 292 implement missing return-type conversion for OP_RETYPE_RAW
*
* @run main/othervm -Xbatch
* -XX:+UnlockDiagnosticVMOptions -XX:ScavengeRootsInCode=2
* -DTest6998541.N=100000 -DTest6998541.KIND=cast Test6998541
* @run main/othervm -Xbatch
* -XX:+UnlockDiagnosticVMOptions -XX:ScavengeRootsInCode=2
* -DTest6998541.N=100000 -DTest6998541.KIND=normal Test6998541
*/
import
java.util.*
;
import
java.lang.invoke.*
;
import
static
java
.
lang
.
invoke
.
MethodHandles
.*;
public
class
Test6998541
{
private
static
final
Class
CLASS
=
Test6998541
.
class
;
private
static
final
String
NAME
=
"identity"
;
private
static
final
int
N
=
Math
.
max
(
2
,
Integer
.
getInteger
(
CLASS
.
getSimpleName
()+
".N"
,
10000
));
private
static
final
String
KIND
=
System
.
getProperty
(
CLASS
.
getSimpleName
()+
".KIND"
,
"cast"
);
private
static
final
int
BITS
=
0x00000201
;
private
static
final
boolean
DO_CASTS
=
!
KIND
.
equals
(
"normal"
);
public
static
void
main
(
String
[]
args
)
throws
Throwable
{
System
.
out
.
println
(
"KIND="
+
KIND
+
" DO_CASTS="
+
DO_CASTS
+
" N="
+
N
);
doboolean
();
dobyte
();
dochar
();
doshort
();
doint
();
dolong
();
dofloat
();
dodouble
();
dovoid
();
}
private
static
void
doboolean
()
throws
Throwable
{
for
(
int
i
=
0
;
i
<
N
;
i
++)
{
boolean2prim
(
false
);
boolean2prim
(
true
);
}
boolean2prim_invalid
(
true
);
}
private
static
void
dobyte
()
throws
Throwable
{
byte
x
=
Byte
.
MIN_VALUE
;
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
++)
byte2prim
(
x
);
byte2prim_invalid
(
x
);
}
private
static
void
dochar
()
throws
Throwable
{
char
x
=
Character
.
MIN_VALUE
;
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
++)
char2prim
(
x
);
char2prim_invalid
(
x
);
}
private
static
void
doshort
()
throws
Throwable
{
short
x
=
Short
.
MIN_VALUE
;
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
++)
short2prim
(
x
);
short2prim_invalid
(
x
);
}
private
static
void
doint
()
throws
Throwable
{
int
x
=
Integer
.
MIN_VALUE
;
int
D
=
Integer
.
MAX_VALUE
/
(
N
/
2
)
|
BITS
;
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
+=
D
)
{
int2prim
(
x
);
}
int2prim_invalid
(
x
);
}
private
static
void
dolong
()
throws
Throwable
{
long
x
=
Long
.
MIN_VALUE
;
long
D
=
Long
.
MAX_VALUE
/
((
long
)
(
N
/
2
))
|
BITS
;
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
+=
D
)
long2prim
(
x
);
long2prim_invalid
(
x
);
}
private
static
void
dofloat
()
throws
Throwable
{
float
x
=
Float
.
MIN_VALUE
;
float
D
=
Float
.
MAX_VALUE
/
((
float
)
(
N
/
2
));
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
+=
D
)
float2prim
(
x
);
float2prim_invalid
(
x
);
}
private
static
void
dodouble
()
throws
Throwable
{
double
x
=
Double
.
MIN_VALUE
;
double
D
=
Double
.
MAX_VALUE
/
((
double
)
(
N
/
2
));
for
(
int
i
=
0
;
i
<
N
;
i
++,
x
+=
D
)
double2prim
(
x
);
double2prim_invalid
(
x
);
}
private
static
void
dovoid
()
throws
Throwable
{
for
(
int
i
=
0
;
i
<
N
;
i
++)
{
void2prim
(
i
);
}
void2prim_invalid
(
0
);
// do the other direction here also:
for
(
int
i
=
0
;
i
<
N
;
i
++)
{
prim2void
(
i
);
}
prim2void_invalid
(
0
);
}
private
static
void
assertEquals
(
Object
o
,
Object
o2
)
{
if
(!
o
.
equals
(
o2
))
throw
new
AssertionError
(
"expected: "
+
o
+
", found: "
+
o2
);
}
private
static
void
fail
()
{
throw
new
AssertionError
();
}
private
final
static
MethodHandles
.
Lookup
lookup
=
MethodHandles
.
lookup
();
private
static
MethodHandle
mh
(
Class
ret
,
Class
...
args
)
{
try
{
MethodType
mt
=
MethodType
.
methodType
(
ret
,
args
);
Class
lookupRet
=
(
args
.
length
==
0
?
void
.
class
:
args
[
0
]);
MethodHandle
mh
=
lookup
.
findStatic
(
CLASS
,
NAME
,
mt
.
changeReturnType
(
lookupRet
));
if
(
DO_CASTS
)
return
MethodHandles
.
explicitCastArguments
(
mh
,
mt
);
if
(
canDoAsType
(
mh
.
type
(),
mt
))
return
mh
.
asType
(
mt
);
try
{
mh
.
asType
(
mt
);
throw
new
AssertionError
(
"asType should not succeed: "
+
mh
+
" => "
+
mt
);
}
catch
(
WrongMethodTypeException
ex
)
{
// this was a required WMTE
return
mh
.
asType
(
mt
.
generic
()).
asType
(
mt
);
}
}
catch
(
ReflectiveOperationException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
private
static
final
Class
<?>[]
NUMERIC_TYPE_WIDENING_ORDER
=
{
byte
.
class
,
short
.
class
,
int
.
class
,
long
.
class
,
float
.
class
,
double
.
class
};
private
static
boolean
canDoAsType
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
)
return
true
;
if
(
dst
==
void
.
class
)
return
true
;
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
;
if
(
dst
==
char
.
class
)
return
false
;
if
(
src
==
char
.
class
)
src
=
int
.
class
;
// can widen char to int
for
(
Class
<?>
ntype
:
NUMERIC_TYPE_WIDENING_ORDER
)
{
if
(
src
==
ntype
)
return
true
;
if
(
dst
==
ntype
)
return
false
;
}
throw
new
AssertionError
(
"should not reach here: "
+
src
+
", "
+
dst
);
}
private
static
boolean
canDoAsType
(
MethodType
mt0
,
MethodType
mt1
)
{
Class
<?>
rt0
=
mt0
.
returnType
();
Class
<?>
rt1
=
mt1
.
returnType
();
if
(!
canDoAsType
(
rt0
,
rt1
))
return
false
;
int
argc
=
mt0
.
parameterCount
();
if
(
argc
!=
mt1
.
parameterCount
())
return
false
;
for
(
int
i
=
0
;
i
<
argc
;
i
++)
{
if
(!
canDoAsType
(
mt1
.
parameterType
(
i
),
mt0
.
parameterType
(
i
)))
return
false
;
}
return
true
;
}
private
static
MethodHandle
mh_z
(
Class
ret
)
{
return
mh
(
ret
,
boolean
.
class
);
}
private
final
static
MethodHandle
mh_zz
=
mh_z
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bz
=
mh_z
(
byte
.
class
);
private
final
static
MethodHandle
mh_cz
=
mh_z
(
char
.
class
);
private
final
static
MethodHandle
mh_sz
=
mh_z
(
short
.
class
);
private
final
static
MethodHandle
mh_iz
=
mh_z
(
int
.
class
);
private
final
static
MethodHandle
mh_jz
=
mh_z
(
long
.
class
);
private
final
static
MethodHandle
mh_fz
=
mh_z
(
float
.
class
);
private
final
static
MethodHandle
mh_dz
=
mh_z
(
double
.
class
);
private
static
void
boolean2prim
(
boolean
x
)
throws
Throwable
{
int
i
=
x
?
1
:
0
;
assertEquals
(
x
,
(
boolean
)
mh_zz
.
invokeExact
(
x
));
// boolean -> boolean
if
(!
DO_CASTS
)
return
;
assertEquals
((
byte
)
i
,
(
byte
)
mh_bz
.
invokeExact
(
x
));
// boolean -> byte
assertEquals
((
char
)
i
,
(
char
)
mh_cz
.
invokeExact
(
x
));
// boolean -> char
assertEquals
((
short
)
i
,
(
short
)
mh_sz
.
invokeExact
(
x
));
// boolean -> short
assertEquals
((
int
)
i
,
(
int
)
mh_iz
.
invokeExact
(
x
));
// boolean -> int
assertEquals
((
long
)
i
,
(
long
)
mh_jz
.
invokeExact
(
x
));
// boolean -> long
assertEquals
((
float
)
i
,
(
float
)
mh_fz
.
invokeExact
(
x
));
// boolean -> float
assertEquals
((
double
)
i
,
(
double
)
mh_dz
.
invokeExact
(
x
));
// boolean -> double
}
private
static
void
boolean2prim_invalid
(
boolean
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
byte
y
=
(
byte
)
mh_bz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> byte
try
{
char
y
=
(
char
)
mh_cz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> char
try
{
short
y
=
(
short
)
mh_sz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> short
try
{
int
y
=
(
int
)
mh_iz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> int
try
{
long
y
=
(
long
)
mh_jz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> long
try
{
float
y
=
(
float
)
mh_fz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> float
try
{
double
y
=
(
double
)
mh_dz
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// boolean -> double
}
private
static
MethodHandle
mh_b
(
Class
ret
)
{
return
mh
(
ret
,
byte
.
class
);
}
private
final
static
MethodHandle
mh_zb
=
mh_b
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bb
=
mh_b
(
byte
.
class
);
private
final
static
MethodHandle
mh_cb
=
mh_b
(
char
.
class
);
private
final
static
MethodHandle
mh_sb
=
mh_b
(
short
.
class
);
private
final
static
MethodHandle
mh_ib
=
mh_b
(
int
.
class
);
private
final
static
MethodHandle
mh_jb
=
mh_b
(
long
.
class
);
private
final
static
MethodHandle
mh_fb
=
mh_b
(
float
.
class
);
private
final
static
MethodHandle
mh_db
=
mh_b
(
double
.
class
);
private
static
void
byte2prim
(
byte
x
)
throws
Throwable
{
assertEquals
((
byte
)
x
,
(
byte
)
mh_bb
.
invokeExact
(
x
));
// byte -> byte
assertEquals
((
short
)
x
,
(
short
)
mh_sb
.
invokeExact
(
x
));
// byte -> short
assertEquals
((
int
)
x
,
(
int
)
mh_ib
.
invokeExact
(
x
));
// byte -> int
assertEquals
((
long
)
x
,
(
long
)
mh_jb
.
invokeExact
(
x
));
// byte -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fb
.
invokeExact
(
x
));
// byte -> float
assertEquals
((
double
)
x
,
(
double
)
mh_db
.
invokeExact
(
x
));
// byte -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
((
x
&
1
)
!=
0
);
assertEquals
((
char
)
x
,
(
char
)
mh_cb
.
invokeExact
(
x
));
// byte -> char
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zb
.
invokeExact
(
x
));
// byte -> boolean
}
private
static
void
byte2prim_invalid
(
byte
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
char
y
=
(
char
)
mh_cb
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// byte -> char
try
{
boolean
y
=
(
boolean
)
mh_zb
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// byte -> boolean
}
private
static
MethodHandle
mh_c
(
Class
ret
)
{
return
mh
(
ret
,
char
.
class
);
}
private
final
static
MethodHandle
mh_zc
=
mh_c
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bc
=
mh_c
(
byte
.
class
);
private
final
static
MethodHandle
mh_cc
=
mh_c
(
char
.
class
);
private
final
static
MethodHandle
mh_sc
=
mh_c
(
short
.
class
);
private
final
static
MethodHandle
mh_ic
=
mh_c
(
int
.
class
);
private
final
static
MethodHandle
mh_jc
=
mh_c
(
long
.
class
);
private
final
static
MethodHandle
mh_fc
=
mh_c
(
float
.
class
);
private
final
static
MethodHandle
mh_dc
=
mh_c
(
double
.
class
);
private
static
void
char2prim
(
char
x
)
throws
Throwable
{
assertEquals
((
char
)
x
,
(
char
)
mh_cc
.
invokeExact
(
x
));
// char -> char
assertEquals
((
int
)
x
,
(
int
)
mh_ic
.
invokeExact
(
x
));
// char -> int
assertEquals
((
long
)
x
,
(
long
)
mh_jc
.
invokeExact
(
x
));
// char -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fc
.
invokeExact
(
x
));
// char -> float
assertEquals
((
double
)
x
,
(
double
)
mh_dc
.
invokeExact
(
x
));
// char -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
((
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zc
.
invokeExact
(
x
));
// char -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bc
.
invokeExact
(
x
));
// char -> byte
assertEquals
((
short
)
x
,
(
short
)
mh_sc
.
invokeExact
(
x
));
// char -> short
}
private
static
void
char2prim_invalid
(
char
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zc
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// char -> boolean
try
{
byte
y
=
(
byte
)
mh_bc
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// char -> byte
try
{
short
y
=
(
short
)
mh_sc
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// char -> short
}
private
static
MethodHandle
mh_s
(
Class
ret
)
{
return
mh
(
ret
,
short
.
class
);
}
private
final
static
MethodHandle
mh_zs
=
mh_s
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bs
=
mh_s
(
byte
.
class
);
private
final
static
MethodHandle
mh_cs
=
mh_s
(
char
.
class
);
private
final
static
MethodHandle
mh_ss
=
mh_s
(
short
.
class
);
private
final
static
MethodHandle
mh_is
=
mh_s
(
int
.
class
);
private
final
static
MethodHandle
mh_js
=
mh_s
(
long
.
class
);
private
final
static
MethodHandle
mh_fs
=
mh_s
(
float
.
class
);
private
final
static
MethodHandle
mh_ds
=
mh_s
(
double
.
class
);
private
static
void
short2prim
(
short
x
)
throws
Throwable
{
assertEquals
((
short
)
x
,
(
short
)
mh_ss
.
invokeExact
(
x
));
// short -> short
assertEquals
((
int
)
x
,
(
int
)
mh_is
.
invokeExact
(
x
));
// short -> int
assertEquals
((
long
)
x
,
(
long
)
mh_js
.
invokeExact
(
x
));
// short -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fs
.
invokeExact
(
x
));
// short -> float
assertEquals
((
double
)
x
,
(
double
)
mh_ds
.
invokeExact
(
x
));
// short -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
((
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zs
.
invokeExact
(
x
));
// short -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bs
.
invokeExact
(
x
));
// short -> byte
assertEquals
((
char
)
x
,
(
char
)
mh_cs
.
invokeExact
(
x
));
// short -> char
}
private
static
void
short2prim_invalid
(
short
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zs
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// short -> boolean
try
{
byte
y
=
(
byte
)
mh_bs
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// short -> byte
try
{
char
y
=
(
char
)
mh_cs
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// short -> char
}
private
static
MethodHandle
mh_i
(
Class
ret
)
{
return
mh
(
ret
,
int
.
class
);
}
private
final
static
MethodHandle
mh_zi
=
mh_i
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bi
=
mh_i
(
byte
.
class
);
private
final
static
MethodHandle
mh_ci
=
mh_i
(
char
.
class
);
private
final
static
MethodHandle
mh_si
=
mh_i
(
short
.
class
);
private
final
static
MethodHandle
mh_ii
=
mh_i
(
int
.
class
);
private
final
static
MethodHandle
mh_ji
=
mh_i
(
long
.
class
);
private
final
static
MethodHandle
mh_fi
=
mh_i
(
float
.
class
);
private
final
static
MethodHandle
mh_di
=
mh_i
(
double
.
class
);
private
static
void
int2prim
(
int
x
)
throws
Throwable
{
assertEquals
((
int
)
x
,
(
int
)
mh_ii
.
invokeExact
(
x
));
// int -> int
assertEquals
((
long
)
x
,
(
long
)
mh_ji
.
invokeExact
(
x
));
// int -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fi
.
invokeExact
(
x
));
// int -> float
assertEquals
((
double
)
x
,
(
double
)
mh_di
.
invokeExact
(
x
));
// int -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
((
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zi
.
invokeExact
(
x
));
// int -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bi
.
invokeExact
(
x
));
// int -> byte
assertEquals
((
char
)
x
,
(
char
)
mh_ci
.
invokeExact
(
x
));
// int -> char
assertEquals
((
short
)
x
,
(
short
)
mh_si
.
invokeExact
(
x
));
// int -> short
}
private
static
void
int2prim_invalid
(
int
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zi
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// int -> boolean
try
{
byte
y
=
(
byte
)
mh_bi
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// int -> byte
try
{
char
y
=
(
char
)
mh_ci
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// int -> char
try
{
short
y
=
(
short
)
mh_si
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// int -> short
}
private
static
MethodHandle
mh_j
(
Class
ret
)
{
return
mh
(
ret
,
long
.
class
);
}
private
final
static
MethodHandle
mh_zj
=
mh_j
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bj
=
mh_j
(
byte
.
class
);
private
final
static
MethodHandle
mh_cj
=
mh_j
(
char
.
class
);
private
final
static
MethodHandle
mh_sj
=
mh_j
(
short
.
class
);
private
final
static
MethodHandle
mh_ij
=
mh_j
(
int
.
class
);
private
final
static
MethodHandle
mh_jj
=
mh_j
(
long
.
class
);
private
final
static
MethodHandle
mh_fj
=
mh_j
(
float
.
class
);
private
final
static
MethodHandle
mh_dj
=
mh_j
(
double
.
class
);
private
static
void
long2prim
(
long
x
)
throws
Throwable
{
assertEquals
((
long
)
x
,
(
long
)
mh_jj
.
invokeExact
(
x
));
// long -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fj
.
invokeExact
(
x
));
// long -> float
assertEquals
((
double
)
x
,
(
double
)
mh_dj
.
invokeExact
(
x
));
// long -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
((
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zj
.
invokeExact
(
x
));
// long -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bj
.
invokeExact
(
x
));
// long -> byte
assertEquals
((
char
)
x
,
(
char
)
mh_cj
.
invokeExact
(
x
));
// long -> char
assertEquals
((
short
)
x
,
(
short
)
mh_sj
.
invokeExact
(
x
));
// long -> short
assertEquals
((
int
)
x
,
(
int
)
mh_ij
.
invokeExact
(
x
));
// long -> int
}
private
static
void
long2prim_invalid
(
long
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zj
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// long -> boolean
try
{
byte
y
=
(
byte
)
mh_bj
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// long -> byte
try
{
char
y
=
(
char
)
mh_cj
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// long -> char
try
{
short
y
=
(
short
)
mh_sj
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// long -> short
try
{
int
y
=
(
int
)
mh_ij
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// long -> int
}
private
static
MethodHandle
mh_f
(
Class
ret
)
{
return
mh
(
ret
,
float
.
class
);
}
private
final
static
MethodHandle
mh_zf
=
mh_f
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bf
=
mh_f
(
byte
.
class
);
private
final
static
MethodHandle
mh_cf
=
mh_f
(
char
.
class
);
private
final
static
MethodHandle
mh_sf
=
mh_f
(
short
.
class
);
private
final
static
MethodHandle
mh_if
=
mh_f
(
int
.
class
);
private
final
static
MethodHandle
mh_jf
=
mh_f
(
long
.
class
);
private
final
static
MethodHandle
mh_ff
=
mh_f
(
float
.
class
);
private
final
static
MethodHandle
mh_df
=
mh_f
(
double
.
class
);
private
static
void
float2prim
(
float
x
)
throws
Throwable
{
assertEquals
((
float
)
x
,
(
float
)
mh_ff
.
invokeExact
(
x
));
// float -> float
assertEquals
((
double
)
x
,
(
double
)
mh_df
.
invokeExact
(
x
));
// float -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
(((
byte
)
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zf
.
invokeExact
(
x
));
// float -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bf
.
invokeExact
(
x
));
// float -> byte
assertEquals
((
char
)
x
,
(
char
)
mh_cf
.
invokeExact
(
x
));
// float -> char
assertEquals
((
short
)
x
,
(
short
)
mh_sf
.
invokeExact
(
x
));
// float -> short
assertEquals
((
int
)
x
,
(
int
)
mh_if
.
invokeExact
(
x
));
// float -> int
assertEquals
((
long
)
x
,
(
long
)
mh_jf
.
invokeExact
(
x
));
// float -> long
}
private
static
void
float2prim_invalid
(
float
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zf
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> boolean
try
{
byte
y
=
(
byte
)
mh_bf
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> byte
try
{
char
y
=
(
char
)
mh_cf
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> char
try
{
short
y
=
(
short
)
mh_sf
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> short
try
{
int
y
=
(
int
)
mh_if
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> int
try
{
long
y
=
(
long
)
mh_jf
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// float -> long
}
private
static
MethodHandle
mh_d
(
Class
ret
)
{
return
mh
(
ret
,
double
.
class
);
}
private
final
static
MethodHandle
mh_zd
=
mh_d
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bd
=
mh_d
(
byte
.
class
);
private
final
static
MethodHandle
mh_cd
=
mh_d
(
char
.
class
);
private
final
static
MethodHandle
mh_sd
=
mh_d
(
short
.
class
);
private
final
static
MethodHandle
mh_id
=
mh_d
(
int
.
class
);
private
final
static
MethodHandle
mh_jd
=
mh_d
(
long
.
class
);
private
final
static
MethodHandle
mh_fd
=
mh_d
(
float
.
class
);
private
final
static
MethodHandle
mh_dd
=
mh_d
(
double
.
class
);
private
static
void
double2prim
(
double
x
)
throws
Throwable
{
assertEquals
((
double
)
x
,
(
double
)
mh_dd
.
invokeExact
(
x
));
// double -> double
if
(!
DO_CASTS
)
return
;
boolean
z
=
(((
byte
)
x
&
1
)
!=
0
);
assertEquals
((
boolean
)
z
,
(
boolean
)
mh_zd
.
invokeExact
(
x
));
// double -> boolean
assertEquals
((
byte
)
x
,
(
byte
)
mh_bd
.
invokeExact
(
x
));
// double -> byte
assertEquals
((
char
)
x
,
(
char
)
mh_cd
.
invokeExact
(
x
));
// double -> char
assertEquals
((
short
)
x
,
(
short
)
mh_sd
.
invokeExact
(
x
));
// double -> short
assertEquals
((
int
)
x
,
(
int
)
mh_id
.
invokeExact
(
x
));
// double -> int
assertEquals
((
long
)
x
,
(
long
)
mh_jd
.
invokeExact
(
x
));
// double -> long
assertEquals
((
float
)
x
,
(
float
)
mh_fd
.
invokeExact
(
x
));
// double -> float
}
private
static
void
double2prim_invalid
(
double
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
boolean
y
=
(
boolean
)
mh_zd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> boolean
try
{
byte
y
=
(
byte
)
mh_bd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> byte
try
{
char
y
=
(
char
)
mh_cd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> char
try
{
short
y
=
(
short
)
mh_sd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> short
try
{
int
y
=
(
int
)
mh_id
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> int
try
{
long
y
=
(
long
)
mh_jd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> long
try
{
float
y
=
(
float
)
mh_fd
.
invokeExact
(
x
);
fail
();
}
catch
(
ClassCastException
_
)
{}
// double -> float
}
private
final
static
MethodHandle
mh_zv
=
mh
(
boolean
.
class
);
private
final
static
MethodHandle
mh_bv
=
mh
(
byte
.
class
);
private
final
static
MethodHandle
mh_cv
=
mh
(
char
.
class
);
private
final
static
MethodHandle
mh_sv
=
mh
(
short
.
class
);
private
final
static
MethodHandle
mh_iv
=
mh
(
int
.
class
);
private
final
static
MethodHandle
mh_jv
=
mh
(
long
.
class
);
private
final
static
MethodHandle
mh_fv
=
mh
(
float
.
class
);
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
assertEquals
((
short
)
0
,
(
short
)
mh_sv
.
invokeExact
());
// void -> short
assertEquals
(
0
,
(
int
)
mh_iv
.
invokeExact
());
// void -> int
assertEquals
(
0L
,
(
long
)
mh_jv
.
invokeExact
());
// void -> long
assertEquals
(
0.0f
,
(
float
)
mh_fv
.
invokeExact
());
// void -> float
assertEquals
(
0.0d
,
(
double
)
mh_dv
.
invokeExact
());
// void -> double
}
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
}
private
static
MethodHandle
mh_v
(
Class
arg
)
{
return
mh
(
void
.
class
,
arg
);
}
private
final
static
MethodHandle
mh_vz
=
mh_v
(
boolean
.
class
);
private
final
static
MethodHandle
mh_vb
=
mh_v
(
byte
.
class
);
private
final
static
MethodHandle
mh_vc
=
mh_v
(
char
.
class
);
private
final
static
MethodHandle
mh_vs
=
mh_v
(
short
.
class
);
private
final
static
MethodHandle
mh_vi
=
mh_v
(
int
.
class
);
private
final
static
MethodHandle
mh_vj
=
mh_v
(
long
.
class
);
private
final
static
MethodHandle
mh_vf
=
mh_v
(
float
.
class
);
private
final
static
MethodHandle
mh_vd
=
mh_v
(
double
.
class
);
private
static
void
prim2void
(
int
x
)
throws
Throwable
{
boolean
z
=
((
x
&
1
)
!=
0
);
mh_vz
.
invokeExact
(
z
);
// boolean -> void
mh_vb
.
invokeExact
((
byte
)
x
);
// byte -> void
mh_vc
.
invokeExact
((
char
)
x
);
// char -> void
mh_vs
.
invokeExact
((
short
)
x
);
// short -> void
mh_vi
.
invokeExact
((
int
)
x
);
// int -> void
mh_vj
.
invokeExact
((
long
)
x
);
// long -> void
mh_vf
.
invokeExact
((
float
)
x
);
// float -> void
mh_vd
.
invokeExact
((
double
)
x
);
// double -> void
}
private
static
void
prim2void_invalid
(
int
x
)
throws
Throwable
{
// no cases
}
private
static
boolean
identity
(
boolean
v
)
{
return
v
;
}
private
static
byte
identity
(
byte
v
)
{
return
v
;
}
private
static
char
identity
(
char
v
)
{
return
v
;
}
private
static
short
identity
(
short
v
)
{
return
v
;
}
private
static
int
identity
(
int
v
)
{
return
v
;
}
private
static
long
identity
(
long
v
)
{
return
v
;
}
private
static
float
identity
(
float
v
)
{
return
v
;
}
private
static
double
identity
(
double
v
)
{
return
v
;
}
private
static
void
identity
()
{}
}
test/java/lang/invoke/InvokeGenericTest.java
浏览文件 @
8c50098c
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
*/
*/
/* @test
/* @test
* @summary unit tests for java.lang.invoke.MethodHandle.invoke
Generic
* @summary unit tests for java.lang.invoke.MethodHandle.invoke
* @compile -target 7 InvokeGenericTest.java
* @compile -target 7 InvokeGenericTest.java
* @run junit/othervm test.java.lang.invoke.InvokeGenericTest
* @run junit/othervm test.java.lang.invoke.InvokeGenericTest
*/
*/
...
@@ -53,6 +53,10 @@ public class InvokeGenericTest {
...
@@ -53,6 +53,10 @@ public class InvokeGenericTest {
if
(
vstr
!=
null
)
verbosity
=
Integer
.
parseInt
(
vstr
);
if
(
vstr
!=
null
)
verbosity
=
Integer
.
parseInt
(
vstr
);
}
}
public
static
void
main
(
String
...
av
)
throws
Throwable
{
new
InvokeGenericTest
().
testFirst
();
}
@Test
@Test
public
void
testFirst
()
throws
Throwable
{
public
void
testFirst
()
throws
Throwable
{
verbosity
+=
9
;
try
{
verbosity
+=
9
;
try
{
...
@@ -103,7 +107,7 @@ public class InvokeGenericTest {
...
@@ -103,7 +107,7 @@ public class InvokeGenericTest {
void
startTest
(
String
name
)
{
void
startTest
(
String
name
)
{
if
(
testName
!=
null
)
printCounts
();
if
(
testName
!=
null
)
printCounts
();
if
(
verbosity
>=
1
)
if
(
verbosity
>=
1
)
System
.
out
.
println
(
name
);
System
.
out
.
println
(
"["
+
name
+
"]"
);
posTests
=
negTests
=
0
;
posTests
=
negTests
=
0
;
testName
=
name
;
testName
=
name
;
}
}
...
@@ -350,6 +354,30 @@ public class InvokeGenericTest {
...
@@ -350,6 +354,30 @@ public class InvokeGenericTest {
String
[]
args
=
{
"one"
,
"two"
};
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
@Test
public
void
testSimplePrims
()
throws
Throwable
{
startTest
(
"testSimplePrims"
);
countTest
();
int
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
Object
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
(
args
[
0
],
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
toString
(
args
),
res
.
toString
());
}
@Test
public
void
testAlternateName
()
throws
Throwable
{
startTest
(
"testAlternateName"
);
countTest
();
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invokeGeneric
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
res
=
resl
=
(
List
)
mh
.
invokeGeneric
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
...
@@ -388,24 +416,24 @@ public class InvokeGenericTest {
...
@@ -388,24 +416,24 @@ public class InvokeGenericTest {
try
{
try
{
switch
(
args
.
length
)
{
switch
(
args
.
length
)
{
case
0
:
case
0
:
junk
=
target
.
invoke
Generic
();
break
;
junk
=
target
.
invoke
();
break
;
case
1
:
case
1
:
junk
=
target
.
invoke
Generic
(
args
[
0
]);
break
;
junk
=
target
.
invoke
(
args
[
0
]);
break
;
case
2
:
case
2
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
]);
break
;
case
3
:
case
3
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
case
4
:
case
4
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
default
:
default
:
junk
=
target
.
invokeWithArguments
(
args
);
break
;
junk
=
target
.
invokeWithArguments
(
args
);
break
;
}
}
}
catch
(
WrongMethodTypeException
ex
)
{
}
catch
(
WrongMethodTypeException
ex
)
{
return
;
return
;
}
catch
(
Exception
ex
)
{
}
catch
(
Exception
ex
)
{
throw
new
RuntimeException
(
"wrong exception calling "
+
target
+
target
.
type
()+
" on "
+
Arrays
.
asList
(
args
)+
" : "
+
ex
);
throw
new
RuntimeException
(
"wrong exception calling "
+
target
+
" on "
+
Arrays
.
asList
(
args
),
ex
);
}
}
throw
new
RuntimeException
(
"bad success calling "
+
target
+
target
.
type
()+
" on "
+
Arrays
.
asList
(
args
));
throw
new
RuntimeException
(
"bad success calling "
+
target
+
" on "
+
Arrays
.
asList
(
args
));
}
}
/** Make a list of all combinations of the given types, with the given arities.
/** Make a list of all combinations of the given types, with the given arities.
...
@@ -451,7 +479,7 @@ public class InvokeGenericTest {
...
@@ -451,7 +479,7 @@ public class InvokeGenericTest {
startTest
(
"testReferenceConversions"
);
startTest
(
"testReferenceConversions"
);
toString_MH
=
LOOKUP
.
toString_MH
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"toString"
,
MethodType
.
methodType
(
String
.
class
));
findVirtual
(
Object
.
class
,
"toString"
,
MethodType
.
methodType
(
String
.
class
));
String
[]
args
=
{
"one"
,
"two"
};
Object
[]
args
=
{
"one"
,
"two"
};
for
(
MethodType
type
:
allMethodTypes
(
2
,
Object
.
class
,
String
.
class
,
RandomInterface
.
class
))
{
for
(
MethodType
type
:
allMethodTypes
(
2
,
Object
.
class
,
String
.
class
,
RandomInterface
.
class
))
{
testReferenceConversions
(
type
,
args
);
testReferenceConversions
(
type
,
args
);
}
}
...
@@ -463,7 +491,7 @@ public class InvokeGenericTest {
...
@@ -463,7 +491,7 @@ public class InvokeGenericTest {
MethodHandle
tsdrop
=
MethodHandles
.
dropArguments
(
toString_MH
,
1
,
type
.
parameterList
());
MethodHandle
tsdrop
=
MethodHandles
.
dropArguments
(
toString_MH
,
1
,
type
.
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
tsdrop
,
mh
);
mh
=
MethodHandles
.
foldArguments
(
tsdrop
,
mh
);
mh
=
mh
.
asType
(
type
);
mh
=
mh
.
asType
(
type
);
Object
res
=
mh
.
invoke
Generic
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
Object
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
).
toString
(),
res
);
assertEquals
(
Arrays
.
asList
(
args
).
toString
(),
res
);
}
}
...
@@ -473,10 +501,10 @@ public class InvokeGenericTest {
...
@@ -473,10 +501,10 @@ public class InvokeGenericTest {
public
void
testBoxConversions
()
throws
Throwable
{
public
void
testBoxConversions
()
throws
Throwable
{
startTest
(
"testBoxConversions"
);
startTest
(
"testBoxConversions"
);
countTest
();
countTest
();
Integer
[]
args
=
{
1
,
2
};
Object
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
int
.
class
);
MethodHandle
mh
=
callable
(
Object
.
class
,
int
.
class
);
Object
res
;
List
resl
;
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
Generic
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
res
=
resl
=
(
List
)
mh
.
invoke
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
}
...
...
test/java/lang/invoke/JavaDocExamplesTest.java
浏览文件 @
8c50098c
...
@@ -170,8 +170,8 @@ assert(s.equals("savvy"));
...
@@ -170,8 +170,8 @@ assert(s.equals("savvy"));
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
assert
(
mh
.
isVarargsCollector
());
assert
(
mh
.
isVarargsCollector
());
x
=
mh
.
invoke
Generic
(
"one"
,
"two"
);
x
=
mh
.
invoke
(
"one"
,
"two"
);
// invoke
Generic
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)));
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)));
// mt is (Object,Object,Object)Object
// mt is (Object,Object,Object)Object
mt
=
MethodType
.
genericMethodType
(
3
);
mt
=
MethodType
.
genericMethodType
(
3
);
...
@@ -199,12 +199,12 @@ mh.invokeExact(System.out, "Hello, world.");
...
@@ -199,12 +199,12 @@ mh.invokeExact(System.out, "Hello, world.");
MethodHandle
asList
=
publicLookup
()
MethodHandle
asList
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
.
asVarargsCollector
(
Object
[].
class
);
assertEquals
(
"[]"
,
asList
.
invoke
Generic
().
toString
());
assertEquals
(
"[]"
,
asList
.
invoke
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
Generic
(
1
).
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
Generic
(
"two"
,
"too"
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
(
"two"
,
"too"
).
toString
());
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
Generic
(
argv
).
toString
());
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
(
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
Generic
((
Object
)
argv
);
List
ls
=
(
List
)
asList
.
invoke
((
Object
)
argv
);
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
}}
}}
...
@@ -218,9 +218,9 @@ MethodHandle vamh = publicLookup()
...
@@ -218,9 +218,9 @@ MethodHandle vamh = publicLookup()
.
asVarargsCollector
(
Object
[].
class
);
.
asVarargsCollector
(
Object
[].
class
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
assert
(
vamh
.
type
().
equals
(
mh
.
type
()));
assert
(
vamh
.
type
().
equals
(
mh
.
type
()));
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
Generic
(
1
,
2
,
3
).
toString
());
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
(
1
,
2
,
3
).
toString
());
boolean
failed
=
false
;
boolean
failed
=
false
;
try
{
mh
.
invoke
Generic
(
1
,
2
,
3
);
}
try
{
mh
.
invoke
(
1
,
2
,
3
);
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
assert
(
failed
);
assert
(
failed
);
{}
{}
...
...
test/java/lang/invoke/MethodHandlesTest.java
浏览文件 @
8c50098c
...
@@ -105,24 +105,6 @@ public class MethodHandlesTest {
...
@@ -105,24 +105,6 @@ public class MethodHandlesTest {
public
MethodHandlesTest
()
{
public
MethodHandlesTest
()
{
}
}
@Before
public
void
checkImplementedPlatform
()
{
boolean
platformOK
=
false
;
Properties
properties
=
System
.
getProperties
();
String
vers
=
properties
.
getProperty
(
"java.vm.version"
);
String
name
=
properties
.
getProperty
(
"java.vm.name"
);
String
arch
=
properties
.
getProperty
(
"os.arch"
);
if
((
arch
.
equals
(
"amd64"
)
||
arch
.
equals
(
"i386"
)
||
arch
.
equals
(
"x86"
)
||
arch
.
equals
(
"sparc"
)
||
arch
.
equals
(
"sparcv9"
))
&&
(
name
.
contains
(
"Client"
)
||
name
.
contains
(
"Server"
))
)
{
platformOK
=
true
;
}
else
{
System
.
err
.
println
(
"Skipping tests for unsupported platform: "
+
Arrays
.
asList
(
vers
,
name
,
arch
));
}
assumeTrue
(
platformOK
);
}
String
testName
;
String
testName
;
static
int
allPosTests
,
allNegTests
;
static
int
allPosTests
,
allNegTests
;
int
posTests
,
negTests
;
int
posTests
,
negTests
;
...
@@ -331,6 +313,9 @@ public class MethodHandlesTest {
...
@@ -331,6 +313,9 @@ public class MethodHandlesTest {
static
MethodHandle
varargsArray
(
int
arity
)
{
static
MethodHandle
varargsArray
(
int
arity
)
{
return
ValueConversions
.
varargsArray
(
arity
);
return
ValueConversions
.
varargsArray
(
arity
);
}
}
static
MethodHandle
varargsArray
(
Class
<?>
arrayType
,
int
arity
)
{
return
ValueConversions
.
varargsArray
(
arrayType
,
arity
);
}
/** Variation of varargsList, but with the given rtype. */
/** Variation of varargsList, but with the given rtype. */
static
MethodHandle
varargsList
(
int
arity
,
Class
<?>
rtype
)
{
static
MethodHandle
varargsList
(
int
arity
,
Class
<?>
rtype
)
{
MethodHandle
list
=
varargsList
(
arity
);
MethodHandle
list
=
varargsList
(
arity
);
...
@@ -865,7 +850,7 @@ public class MethodHandlesTest {
...
@@ -865,7 +850,7 @@ public class MethodHandlesTest {
Class
<?>
type
=
(
Class
<?>)
t
[
1
];
Class
<?>
type
=
(
Class
<?>)
t
[
1
];
Object
value
;
Object
value
;
Field
field
;
Field
field
;
try
{
try
{
field
=
HasFields
.
class
.
getDeclaredField
(
name
);
field
=
HasFields
.
class
.
getDeclaredField
(
name
);
}
catch
(
Exception
ex
)
{
}
catch
(
Exception
ex
)
{
throw
new
InternalError
(
"no field HasFields."
+
name
);
throw
new
InternalError
(
"no field HasFields."
+
name
);
...
@@ -1144,16 +1129,9 @@ public class MethodHandlesTest {
...
@@ -1144,16 +1129,9 @@ public class MethodHandlesTest {
:
MethodHandles
.
arrayElementSetter
(
arrayType
);
:
MethodHandles
.
arrayElementSetter
(
arrayType
);
assertSame
(
mh
.
type
(),
expType
);
assertSame
(
mh
.
type
(),
expType
);
if
(
elemType
!=
int
.
class
&&
elemType
!=
boolean
.
class
)
{
if
(
elemType
!=
int
.
class
&&
elemType
!=
boolean
.
class
)
{
MethodType
gtype
;
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
if
(
true
)
{
// FIXME: remove this path (and remove <void> below in the mh.invokes)
MethodType
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
Integer
.
class
);
gtype
=
mh
.
type
().
changeParameterType
(
0
,
Object
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeReturnType
(
void
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeParameterType
(
2
,
Object
.
class
);
else
gtype
=
gtype
.
changeReturnType
(
Object
.
class
);
}
else
// FIXME: This simpler path hits a bug in convertArguments => ToGeneric
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
int
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
}
}
Object
sawValue
,
expValue
;
Object
sawValue
,
expValue
;
...
@@ -1169,7 +1147,7 @@ public class MethodHandlesTest {
...
@@ -1169,7 +1147,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
else
if
(
elemType
==
boolean
.
class
)
mh
.
invokeExact
((
boolean
[])
array
,
i
,
(
boolean
)
random
);
mh
.
invokeExact
((
boolean
[])
array
,
i
,
(
boolean
)
random
);
else
else
mh
.
invokeExact
(
array
,
i
,
random
);
mh
.
invokeExact
(
array
,
(
Integer
)
i
,
random
);
assertEquals
(
model
,
array2list
(
array
));
assertEquals
(
model
,
array2list
(
array
));
}
else
{
}
else
{
Array
.
set
(
array
,
i
,
random
);
Array
.
set
(
array
,
i
,
random
);
...
@@ -1189,7 +1167,7 @@ public class MethodHandlesTest {
...
@@ -1189,7 +1167,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
else
if
(
elemType
==
boolean
.
class
)
sawValue
=
(
boolean
)
mh
.
invokeExact
((
boolean
[])
array
,
i
);
sawValue
=
(
boolean
)
mh
.
invokeExact
((
boolean
[])
array
,
i
);
else
else
sawValue
=
mh
.
invokeExact
(
array
,
i
);
sawValue
=
mh
.
invokeExact
(
array
,
(
Integer
)
i
);
assertEquals
(
sawValue
,
expValue
);
assertEquals
(
sawValue
,
expValue
);
assertEquals
(
model
,
array2list
(
array
));
assertEquals
(
model
,
array2list
(
array
));
}
}
...
@@ -1341,21 +1319,15 @@ public class MethodHandlesTest {
...
@@ -1341,21 +1319,15 @@ public class MethodHandlesTest {
int
numcases
=
1
;
int
numcases
=
1
;
for
(
int
outargs
=
0
;
outargs
<=
max
;
outargs
++)
{
for
(
int
outargs
=
0
;
outargs
<=
max
;
outargs
++)
{
if
(
outargs
-
inargs
>=
MAX_ARG_INCREASE
)
continue
;
if
(
outargs
-
inargs
>=
MAX_ARG_INCREASE
)
continue
;
int
[]
reorder
=
new
int
[
outargs
];
int
casStep
=
dilution
+
1
;
int
casStep
=
dilution
+
1
;
// Avoid some common factors:
// Avoid some common factors:
while
((
casStep
>
2
&&
casStep
%
2
==
0
&&
inargs
%
2
==
0
)
||
while
((
casStep
>
2
&&
casStep
%
2
==
0
&&
inargs
%
2
==
0
)
||
(
casStep
>
3
&&
casStep
%
3
==
0
&&
inargs
%
3
==
0
))
(
casStep
>
3
&&
casStep
%
3
==
0
&&
inargs
%
3
==
0
))
casStep
++;
casStep
++;
for
(
int
cas
=
0
;
cas
<
numcases
;
cas
+=
casStep
)
{
testPermuteArguments
(
args
,
types
,
outargs
,
numcases
,
casStep
);
for
(
int
i
=
0
,
c
=
cas
;
i
<
outargs
;
i
++)
{
reorder
[
i
]
=
c
%
inargs
;
c
/=
inargs
;
}
testPermuteArguments
(
args
,
types
,
reorder
);
}
numcases
*=
inargs
;
numcases
*=
inargs
;
if
(
dilution
>
10
&&
outargs
>=
4
)
{
if
(
dilution
>
10
&&
outargs
>=
4
)
{
int
[]
reorder
=
new
int
[
outargs
];
// Do some special patterns, which we probably missed.
// Do some special patterns, which we probably missed.
// Replication of a single argument or argument pair.
// Replication of a single argument or argument pair.
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
...
@@ -1383,6 +1355,19 @@ public class MethodHandlesTest {
...
@@ -1383,6 +1355,19 @@ public class MethodHandlesTest {
}
}
}
}
public
void
testPermuteArguments
(
Object
[]
args
,
Class
<?>[]
types
,
int
outargs
,
int
numcases
,
int
casStep
)
throws
Throwable
{
int
inargs
=
args
.
length
;
int
[]
reorder
=
new
int
[
outargs
];
for
(
int
cas
=
0
;
cas
<
numcases
;
cas
+=
casStep
)
{
for
(
int
i
=
0
,
c
=
cas
;
i
<
outargs
;
i
++)
{
reorder
[
i
]
=
c
%
inargs
;
c
/=
inargs
;
}
testPermuteArguments
(
args
,
types
,
reorder
);
}
}
static
int
[]
reverse
(
int
[]
reorder
)
{
static
int
[]
reverse
(
int
[]
reorder
)
{
reorder
=
reorder
.
clone
();
reorder
=
reorder
.
clone
();
for
(
int
i
=
0
,
imax
=
reorder
.
length
/
2
;
i
<
imax
;
i
++)
{
for
(
int
i
=
0
,
imax
=
reorder
.
length
/
2
;
i
<
imax
;
i
++)
{
...
@@ -1433,6 +1418,12 @@ public class MethodHandlesTest {
...
@@ -1433,6 +1418,12 @@ public class MethodHandlesTest {
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
if
(!
expected
.
equals
(
result
))
{
System
.
out
.
println
(
"*** failed permuteArguments "
+
Arrays
.
toString
(
reorder
)+
" types="
+
Arrays
.
asList
(
types
));
System
.
out
.
println
(
"in args: "
+
Arrays
.
asList
(
args
));
System
.
out
.
println
(
"out args: "
+
expected
);
System
.
out
.
println
(
"bad args: "
+
result
);
}
assertEquals
(
expected
,
result
);
assertEquals
(
expected
,
result
);
}
}
...
@@ -1456,26 +1447,27 @@ public class MethodHandlesTest {
...
@@ -1456,26 +1447,27 @@ public class MethodHandlesTest {
}
}
public
void
testSpreadArguments
(
Class
<?>
argType
,
int
pos
,
int
nargs
)
throws
Throwable
{
public
void
testSpreadArguments
(
Class
<?>
argType
,
int
pos
,
int
nargs
)
throws
Throwable
{
countTest
();
countTest
();
MethodHandle
target
=
varargsArray
(
nargs
);
Class
<?>
arrayType
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
argType
,
0
).
getClass
();
MethodHandle
target2
=
changeArgTypes
(
target
,
argType
);
MethodHandle
target2
=
varargsArray
(
arrayType
,
nargs
);
MethodHandle
target
=
target2
.
asType
(
target2
.
type
().
generic
());
if
(
verbosity
>=
3
)
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"spread into "
+
target2
+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
System
.
out
.
println
(
"spread into "
+
target2
+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
// make sure the target does what we think it does:
// make sure the target does what we think it does:
if
(
pos
==
0
&&
nargs
<
5
)
{
if
(
pos
==
0
&&
nargs
<
5
&&
!
argType
.
isPrimitive
()
)
{
Object
[]
check
=
(
Object
[])
target
.
invokeWithArguments
(
args
);
Object
[]
check
=
(
Object
[])
(
Object
)
target
.
invokeWithArguments
(
args
);
assertArrayEquals
(
args
,
check
);
assertArrayEquals
(
args
,
check
);
switch
(
nargs
)
{
switch
(
nargs
)
{
case
0
:
case
0
:
check
=
(
Object
[])
target
.
invokeExact
();
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
();
assertArrayEquals
(
args
,
check
);
assertArrayEquals
(
args
,
check
);
break
;
break
;
case
1
:
case
1
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
]);
assertArrayEquals
(
args
,
check
);
assertArrayEquals
(
args
,
check
);
break
;
break
;
case
2
:
case
2
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
assertArrayEquals
(
args
,
check
);
assertArrayEquals
(
args
,
check
);
break
;
break
;
}
}
...
@@ -1483,23 +1475,50 @@ public class MethodHandlesTest {
...
@@ -1483,23 +1475,50 @@ public class MethodHandlesTest {
List
<
Class
<?>>
newParams
=
new
ArrayList
<
Class
<?>>(
target2
.
type
().
parameterList
());
List
<
Class
<?>>
newParams
=
new
ArrayList
<
Class
<?>>(
target2
.
type
().
parameterList
());
{
// modify newParams in place
{
// modify newParams in place
List
<
Class
<?>>
spreadParams
=
newParams
.
subList
(
pos
,
nargs
);
List
<
Class
<?>>
spreadParams
=
newParams
.
subList
(
pos
,
nargs
);
spreadParams
.
clear
();
spreadParams
.
add
(
Object
[].
class
);
spreadParams
.
clear
();
spreadParams
.
add
(
arrayType
);
}
}
MethodType
newType
=
MethodType
.
methodType
(
Object
.
class
,
newParams
);
MethodType
newType
=
MethodType
.
methodType
(
arrayType
,
newParams
);
MethodHandle
result
=
target2
.
asSpreader
(
Object
[].
class
,
nargs
-
pos
).
asType
(
newType
);
MethodHandle
result
=
target2
.
asSpreader
(
arrayType
,
nargs
-
pos
);
Object
[]
returnValue
;
assert
(
result
.
type
()
==
newType
)
:
Arrays
.
asList
(
result
,
newType
);
result
=
result
.
asType
(
newType
.
generic
());
Object
returnValue
;
if
(
pos
==
0
)
{
if
(
pos
==
0
)
{
// In the following line, the first cast implies
Object
args2
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
// normal Object return value for the MH call (Object[])->Object,
returnValue
=
result
.
invokeExact
(
args2
);
// while the second cast dynamically converts to an Object array.
// Such a double cast is typical of MH.invokeExact.
returnValue
=
(
Object
[])
(
Object
)
result
.
invokeExact
(
args
);
}
else
{
}
else
{
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
args1
[
pos
]
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
returnValue
=
(
Object
[])
result
.
invokeWithArguments
(
args1
);
returnValue
=
result
.
invokeWithArguments
(
args1
);
}
String
argstr
=
Arrays
.
toString
(
args
);
if
(!
argType
.
isPrimitive
())
{
Object
[]
rv
=
(
Object
[])
returnValue
;
String
rvs
=
Arrays
.
toString
(
rv
);
if
(!
Arrays
.
equals
(
args
,
rv
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertArrayEquals
(
args
,
rv
);
}
}
else
if
(
argType
==
int
.
class
)
{
String
rvs
=
Arrays
.
toString
((
int
[])
returnValue
);
if
(!
argstr
.
equals
(
rvs
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertEquals
(
argstr
,
rvs
);
}
}
else
if
(
argType
==
long
.
class
)
{
String
rvs
=
Arrays
.
toString
((
long
[])
returnValue
);
if
(!
argstr
.
equals
(
rvs
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertEquals
(
argstr
,
rvs
);
}
}
else
{
// cannot test...
}
}
assertArrayEquals
(
args
,
returnValue
);
}
}
@Test
@Test
...
@@ -1780,7 +1799,7 @@ public class MethodHandlesTest {
...
@@ -1780,7 +1799,7 @@ public class MethodHandlesTest {
assertCalled
(
"invokee"
,
args
);
assertCalled
(
"invokee"
,
args
);
// generic invoker
// generic invoker
countTest
();
countTest
();
inv
=
MethodHandles
.
genericI
nvoker
(
type
);
inv
=
MethodHandles
.
i
nvoker
(
type
);
if
(
nargs
<=
3
)
{
if
(
nargs
<=
3
)
{
calledLog
.
clear
();
calledLog
.
clear
();
switch
(
nargs
)
{
switch
(
nargs
)
{
...
@@ -2130,15 +2149,12 @@ public class MethodHandlesTest {
...
@@ -2130,15 +2149,12 @@ public class MethodHandlesTest {
Object
z
=
surprise
.
invokeExact
(
x
);
Object
z
=
surprise
.
invokeExact
(
x
);
System
.
out
.
println
(
"Failed to throw; got z="
+
z
);
System
.
out
.
println
(
"Failed to throw; got z="
+
z
);
assertTrue
(
false
);
assertTrue
(
false
);
}
catch
(
Exception
ex
)
{
}
catch
(
ClassCast
Exception
ex
)
{
if
(
verbosity
>
2
)
if
(
verbosity
>
2
)
System
.
out
.
println
(
"caught "
+
ex
);
System
.
out
.
println
(
"caught "
+
ex
);
if
(
verbosity
>
3
)
if
(
verbosity
>
3
)
ex
.
printStackTrace
();
ex
.
printStackTrace
();
assertTrue
(
ex
instanceof
ClassCastException
assertTrue
(
true
);
// all is well
// FIXME: accept only one of the two for any given unit test
||
ex
instanceof
WrongMethodTypeException
);
}
}
}
}
...
@@ -2328,6 +2344,34 @@ class ValueConversions {
...
@@ -2328,6 +2344,34 @@ class ValueConversions {
// else need to spin bytecode or do something else fancy
// else need to spin bytecode or do something else fancy
throw
new
UnsupportedOperationException
(
"NYI: cannot form a varargs array of length "
+
nargs
);
throw
new
UnsupportedOperationException
(
"NYI: cannot form a varargs array of length "
+
nargs
);
}
}
public
static
MethodHandle
varargsArray
(
Class
<?>
arrayType
,
int
nargs
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
MethodType
vaType
=
MethodType
.
methodType
(
arrayType
,
Collections
.<
Class
<?>>
nCopies
(
nargs
,
elemType
));
MethodHandle
mh
=
varargsArray
(
nargs
);
if
(
arrayType
!=
Object
[].
class
)
mh
=
MethodHandles
.
filterReturnValue
(
mh
,
CHANGE_ARRAY_TYPE
.
bindTo
(
arrayType
));
return
mh
.
asType
(
vaType
);
}
static
Object
changeArrayType
(
Class
<?>
arrayType
,
Object
[]
a
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
if
(!
elemType
.
isPrimitive
())
return
Arrays
.
copyOf
(
a
,
a
.
length
,
arrayType
.
asSubclass
(
Object
[].
class
));
Object
b
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
elemType
,
a
.
length
);
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++)
java
.
lang
.
reflect
.
Array
.
set
(
b
,
i
,
a
[
i
]);
return
b
;
}
private
static
final
MethodHandle
CHANGE_ARRAY_TYPE
;
static
{
try
{
CHANGE_ARRAY_TYPE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"changeArrayType"
,
MethodType
.
methodType
(
Object
.
class
,
Class
.
class
,
Object
[].
class
));
}
catch
(
NoSuchMethodException
|
IllegalAccessException
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
throw
err
;
}
}
private
static
final
List
<
Object
>
NO_ARGS_LIST
=
Arrays
.
asList
(
NO_ARGS_ARRAY
);
private
static
final
List
<
Object
>
NO_ARGS_LIST
=
Arrays
.
asList
(
NO_ARGS_ARRAY
);
private
static
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
private
static
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
...
...
test/java/lang/invoke/RicochetTest.java
0 → 100644
浏览文件 @
8c50098c
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary unit tests for recursive method handles
* @run junit/othervm -DRicochetTest.MAX_ARITY=255 test.java.lang.invoke.RicochetTest
*/
package
test.java.lang.invoke
;
import
java.lang.invoke.*
;
import
java.util.*
;
import
org.junit.*
;
import
static
java
.
lang
.
invoke
.
MethodType
.*;
import
static
java
.
lang
.
invoke
.
MethodHandles
.*;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assume
.*;
/**
*
* @author jrose
*/
public
class
RicochetTest
{
private
static
final
Class
CLASS
=
RicochetTest
.
class
;
private
static
final
int
MAX_ARITY
=
Integer
.
getInteger
(
CLASS
.
getSimpleName
()+
".MAX_ARITY"
,
40
);
public
static
void
main
(
String
...
av
)
throws
Throwable
{
RicochetTest
test
=
new
RicochetTest
();
if
(
av
.
length
>
0
)
test
.
testOnly
=
Arrays
.
asList
(
av
).
toString
();
if
(
REPEAT
==
1
||
test
.
testOnly
!=
null
)
{
test
.
testAll
();
if
(
test
.
testOnlyTests
==
null
)
throw
new
RuntimeException
(
"no matching test: "
+
test
.
testOnly
);
}
else
if
(
REPEAT
==
0
)
{
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
RicochetTest
.
class
);
}
else
{
verbose
(
1
,
"REPEAT="
+
REPEAT
);
for
(
int
i
=
0
;
i
<
REPEAT
;
i
++)
{
test
.
testRepetition
=
(
i
+
1
);
verbose
(
0
,
"[#"
+
test
.
testRepetition
+
"]"
);
test
.
testAll
();
}
}
}
int
testRepetition
;
public
void
testAll
()
throws
Throwable
{
testNull
();
testBoxInteger
();
testFilterReturnValue
();
testFilterObject
();
testBoxLong
();
testFilterInteger
();
testIntSpreads
();
testByteSpreads
();
testLongSpreads
();
testIntCollects
();
testReturns
();
}
@Test
public
void
testNull
()
throws
Throwable
{
if
(
testRepetition
>
(
1
+
REPEAT
/
100
))
return
;
// trivial test
if
(!
startTest
(
"testNull"
))
return
;
assertEquals
(
opI
(
37
),
opI
.
invokeWithArguments
(
37
));
assertEqualFunction
(
opI
,
opI
);
}
@Test
public
void
testBoxInteger
()
throws
Throwable
{
if
(!
startTest
(
"testBoxInteger"
))
return
;
assertEqualFunction
(
opI
,
opI
.
asType
(
opL_I
.
type
()).
asType
(
opI
.
type
()));
}
@Test
public
void
testFilterReturnValue
()
throws
Throwable
{
if
(!
startTest
(
"testFilterReturnValue"
))
return
;
int
[]
ints
=
{
12
,
23
,
34
,
45
,
56
,
67
,
78
,
89
};
Object
res
=
list8ints
.
invokeExact
(
ints
[
0
],
ints
[
1
],
ints
[
2
],
ints
[
3
],
ints
[
4
],
ints
[
5
],
ints
[
6
],
ints
[
7
]);
assertEquals
(
Arrays
.
toString
(
ints
),
res
.
toString
());
MethodHandle
idreturn
=
filterReturnValue
(
list8ints
,
identity
(
Object
.
class
));
res
=
idreturn
.
invokeExact
(
ints
[
0
],
ints
[
1
],
ints
[
2
],
ints
[
3
],
ints
[
4
],
ints
[
5
],
ints
[
6
],
ints
[
7
]);
assertEquals
(
Arrays
.
toString
(
ints
),
res
.
toString
());
MethodHandle
add0
=
addL
.
bindTo
(
0
);
assertEqualFunction
(
filterReturnValue
(
opL2
,
add0
),
opL2
);
}
@Test
public
void
testFilterObject
()
throws
Throwable
{
if
(!
startTest
(
"testFilterObject"
))
return
;
MethodHandle
add0
=
addL
.
bindTo
(
0
);
assertEqualFunction
(
sequence
(
opL2
,
add0
),
opL2
);
int
bump13
=
-
13
;
// value near 20 works as long as test values are near [-80..80]
MethodHandle
add13
=
addL
.
bindTo
(
bump13
);
MethodHandle
add13_0
=
addL
.
bindTo
(
opI2
(
bump13
,
0
));
MethodHandle
add13_1
=
addL
.
bindTo
(
opI2
(
0
,
bump13
));
assertEqualFunction
(
sequence
(
opL2
,
add13_0
),
filterArguments
(
opL2
,
0
,
add13
));
assertEqualFunction
(
sequence
(
opL2
,
add13_1
),
filterArguments
(
opL2
,
1
,
add13
));
System
.
out
.
println
(
"[testFilterObject done]"
);
}
@Test
public
void
testBoxLong
()
throws
Throwable
{
if
(!
startTest
(
"testBoxLong"
))
return
;
assertEqualFunction
(
opJ
,
opJ
.
asType
(
opL_J
.
type
()).
asType
(
opJ
.
type
()));
}
@Test
public
void
testFilterInteger
()
throws
Throwable
{
if
(!
startTest
(
"testFilterInteger"
))
return
;
assertEqualFunction
(
opI
,
sequence
(
convI_L
,
opL_I
));
}
@Test
public
void
testIntSpreads
()
throws
Throwable
{
if
(!
startTest
(
"testIntSpreads"
))
return
;
MethodHandle
id
=
identity
(
int
[].
class
);
final
int
MAX
=
MAX_ARITY
-
2
;
// 253+1 would cause parameter overflow with 'this' added
for
(
int
nargs
=
0
;
nargs
<=
MAX
;
nargs
++)
{
if
(
nargs
>
30
&&
nargs
<
MAX
-
20
)
nargs
+=
10
;
int
[]
args
=
new
int
[
nargs
];
for
(
int
j
=
0
;
j
<
args
.
length
;
j
++)
args
[
j
]
=
(
int
)(
j
+
11
);
//System.out.println("testIntSpreads "+Arrays.toString(args));
int
[]
args1
=
(
int
[])
id
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args1
);
MethodHandle
coll
=
id
.
asCollector
(
int
[].
class
,
nargs
);
int
[]
args2
=
args
;
switch
(
nargs
)
{
case
0
:
args2
=
(
int
[])
coll
.
invokeExact
();
break
;
case
1
:
args2
=
(
int
[])
coll
.
invokeExact
(
args
[
0
]);
break
;
case
2
:
args2
=
(
int
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
]);
break
;
case
3
:
args2
=
(
int
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
case
4
:
args2
=
(
int
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
case
5
:
args2
=
(
int
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
]);
break
;
}
assertArrayEquals
(
args
,
args2
);
MethodHandle
mh
=
coll
.
asSpreader
(
int
[].
class
,
nargs
);
int
[]
args3
=
(
int
[])
mh
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args3
);
}
}
@Test
public
void
testByteSpreads
()
throws
Throwable
{
if
(!
startTest
(
"testByteSpreads"
))
return
;
MethodHandle
id
=
identity
(
byte
[].
class
);
final
int
MAX
=
MAX_ARITY
-
2
;
// 253+1 would cause parameter overflow with 'this' added
for
(
int
nargs
=
0
;
nargs
<=
MAX
;
nargs
++)
{
if
(
nargs
>
30
&&
nargs
<
MAX
-
20
)
nargs
+=
10
;
byte
[]
args
=
new
byte
[
nargs
];
for
(
int
j
=
0
;
j
<
args
.
length
;
j
++)
args
[
j
]
=
(
byte
)(
j
+
11
);
//System.out.println("testByteSpreads "+Arrays.toString(args));
byte
[]
args1
=
(
byte
[])
id
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args1
);
MethodHandle
coll
=
id
.
asCollector
(
byte
[].
class
,
nargs
);
byte
[]
args2
=
args
;
switch
(
nargs
)
{
case
0
:
args2
=
(
byte
[])
coll
.
invokeExact
();
break
;
case
1
:
args2
=
(
byte
[])
coll
.
invokeExact
(
args
[
0
]);
break
;
case
2
:
args2
=
(
byte
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
]);
break
;
case
3
:
args2
=
(
byte
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
case
4
:
args2
=
(
byte
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
case
5
:
args2
=
(
byte
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
]);
break
;
}
assertArrayEquals
(
args
,
args2
);
MethodHandle
mh
=
coll
.
asSpreader
(
byte
[].
class
,
nargs
);
byte
[]
args3
=
(
byte
[])
mh
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args3
);
}
}
@Test
public
void
testLongSpreads
()
throws
Throwable
{
if
(!
startTest
(
"testLongSpreads"
))
return
;
MethodHandle
id
=
identity
(
long
[].
class
);
final
int
MAX
=
(
MAX_ARITY
-
2
)
/
2
;
// 253/2+1 would cause parameter overflow with 'this' added
for
(
int
nargs
=
0
;
nargs
<=
MAX
;
nargs
++)
{
if
(
nargs
>
30
&&
nargs
<
MAX
-
20
)
nargs
+=
10
;
long
[]
args
=
new
long
[
nargs
];
for
(
int
j
=
0
;
j
<
args
.
length
;
j
++)
args
[
j
]
=
(
long
)(
j
+
11
);
//System.out.println("testLongSpreads "+Arrays.toString(args));
long
[]
args1
=
(
long
[])
id
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args1
);
MethodHandle
coll
=
id
.
asCollector
(
long
[].
class
,
nargs
);
long
[]
args2
=
args
;
switch
(
nargs
)
{
case
0
:
args2
=
(
long
[])
coll
.
invokeExact
();
break
;
case
1
:
args2
=
(
long
[])
coll
.
invokeExact
(
args
[
0
]);
break
;
case
2
:
args2
=
(
long
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
]);
break
;
case
3
:
args2
=
(
long
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
case
4
:
args2
=
(
long
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
case
5
:
args2
=
(
long
[])
coll
.
invokeExact
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
]);
break
;
}
assertArrayEquals
(
args
,
args2
);
MethodHandle
mh
=
coll
.
asSpreader
(
long
[].
class
,
nargs
);
long
[]
args3
=
(
long
[])
mh
.
invokeExact
(
args
);
assertArrayEquals
(
args
,
args3
);
}
}
@Test
public
void
testIntCollects
()
throws
Throwable
{
if
(!
startTest
(
"testIntCollects"
))
return
;
for
(
MethodHandle
lister
:
INT_LISTERS
)
{
int
outputs
=
lister
.
type
().
parameterCount
();
for
(
int
collects
=
0
;
collects
<=
Math
.
min
(
outputs
,
INT_COLLECTORS
.
length
-
1
);
collects
++)
{
int
inputs
=
outputs
-
1
+
collects
;
if
(
inputs
<
0
)
continue
;
for
(
int
pos
=
0
;
pos
+
collects
<=
inputs
;
pos
++)
{
MethodHandle
collector
=
INT_COLLECTORS
[
collects
];
int
[]
args
=
new
int
[
inputs
];
int
ap
=
0
,
arg
=
31
;
for
(
int
i
=
0
;
i
<
pos
;
i
++)
args
[
ap
++]
=
arg
++
+
0
;
for
(
int
i
=
0
;
i
<
collects
;
i
++)
args
[
ap
++]
=
arg
++
+
10
;
while
(
ap
<
args
.
length
)
args
[
ap
++]
=
arg
++
+
20
;
// calculate piecemeal:
//System.out.println("testIntCollects "+Arrays.asList(lister, pos, collector)+" on "+Arrays.toString(args));
int
[]
collargs
=
Arrays
.
copyOfRange
(
args
,
pos
,
pos
+
collects
);
int
coll
=
(
int
)
collector
.
asSpreader
(
int
[].
class
,
collargs
.
length
).
invokeExact
(
collargs
);
int
[]
listargs
=
Arrays
.
copyOfRange
(
args
,
0
,
outputs
);
System
.
arraycopy
(
args
,
pos
+
collects
,
listargs
,
pos
+
1
,
outputs
-
(
pos
+
1
));
listargs
[
pos
]
=
coll
;
//System.out.println(" coll="+coll+" listargs="+Arrays.toString(listargs));
Object
expect
=
lister
.
asSpreader
(
int
[].
class
,
listargs
.
length
).
invokeExact
(
listargs
);
//System.out.println(" expect="+expect);
// now use the combined MH, and test the output:
MethodHandle
mh
=
collectArguments
(
lister
,
pos
,
INT_COLLECTORS
[
collects
]);
if
(
mh
==
null
)
continue
;
// no infix collection, yet
assert
(
mh
.
type
().
parameterCount
()
==
inputs
);
Object
observe
=
mh
.
asSpreader
(
int
[].
class
,
args
.
length
).
invokeExact
(
args
);
assertEquals
(
expect
,
observe
);
}
}
}
}
private
static
MethodHandle
collectArguments
(
MethodHandle
lister
,
int
pos
,
MethodHandle
collector
)
{
int
collects
=
collector
.
type
().
parameterCount
();
int
outputs
=
lister
.
type
().
parameterCount
();
if
(
pos
==
outputs
-
1
)
return
MethodHandles
.
filterArguments
(
lister
,
pos
,
collector
.
asSpreader
(
int
[].
class
,
collects
))
.
asCollector
(
int
[].
class
,
collects
);
//return MethodHandles.collectArguments(lister, pos, collector); //no such animal
return
null
;
}
private
static
final
Class
<?>[]
RETURN_TYPES
=
{
Object
.
class
,
String
.
class
,
Integer
.
class
,
int
.
class
,
long
.
class
,
boolean
.
class
,
byte
.
class
,
char
.
class
,
short
.
class
,
float
.
class
,
double
.
class
,
void
.
class
,
};
@Test
public
void
testReturns
()
throws
Throwable
{
if
(!
startTest
(
"testReturns"
))
return
;
// fault injection:
int
faultCount
=
0
;
// total of 1296 tests
faultCount
=
Integer
.
getInteger
(
"testReturns.faultCount"
,
0
);
for
(
Class
<?>
ret
:
RETURN_TYPES
)
{
// make a complicated identity function and pass something through it
System
.
out
.
println
(
ret
.
getSimpleName
());
Class
<?>
vret
=
(
ret
==
void
.
class
)
?
Void
.
class
:
ret
;
MethodHandle
id
=
// (vret)->ret
identity
(
vret
).
asType
(
methodType
(
ret
,
vret
));
final
int
LENGTH
=
4
;
int
[]
index
=
{
0
};
Object
vals
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
vret
,
LENGTH
);
MethodHandle
indexGetter
=
//()->int
insertArguments
(
arrayElementGetter
(
index
.
getClass
()),
0
,
index
,
0
);
MethodHandle
valSelector
=
// (int)->vret
arrayElementGetter
(
vals
.
getClass
()).
bindTo
(
vals
);
MethodHandle
valGetter
=
// ()->vret
foldArguments
(
valSelector
,
indexGetter
);
if
(
ret
!=
void
.
class
)
{
for
(
int
i
=
0
;
i
<
LENGTH
;
i
++)
{
Object
val
=
(
i
+
50
);
if
(
ret
==
boolean
.
class
)
val
=
(
i
%
3
==
0
);
if
(
ret
==
String
.
class
)
val
=
"#"
+
i
;
if
(
ret
==
char
.
class
)
val
=
(
char
)(
'a'
+
i
);
if
(
ret
==
byte
.
class
)
val
=
(
byte
)~
i
;
if
(
ret
==
short
.
class
)
val
=
(
short
)(
1
<<
i
);
java
.
lang
.
reflect
.
Array
.
set
(
vals
,
i
,
val
);
}
}
for
(
int
i
=
0
;
i
<
LENGTH
;
i
++)
{
Object
val
=
java
.
lang
.
reflect
.
Array
.
get
(
vals
,
i
);
System
.
out
.
println
(
i
+
" => "
+
val
);
index
[
0
]
=
i
;
if
(--
faultCount
==
0
)
index
[
0
]
^=
1
;
Object
x
=
valGetter
.
invokeWithArguments
();
assertEquals
(
val
,
x
);
// make a return-filter call: x = id(valGetter())
if
(--
faultCount
==
0
)
index
[
0
]
^=
1
;
x
=
filterReturnValue
(
valGetter
,
id
).
invokeWithArguments
();
assertEquals
(
val
,
x
);
// make a filter call: x = id(*,valGetter(),*)
for
(
int
len
=
1
;
len
<=
4
;
len
++)
{
for
(
int
pos
=
0
;
pos
<
len
;
pos
++)
{
MethodHandle
proj
=
id
;
// lambda(..., vret x,...){x}
for
(
int
j
=
0
;
j
<
len
;
j
++)
{
if
(
j
==
pos
)
continue
;
proj
=
dropArguments
(
proj
,
j
,
Object
.
class
);
}
assert
(
proj
.
type
().
parameterCount
()
==
len
);
// proj: (Object*, pos: vret, Object*)->ret
assertEquals
(
vret
,
proj
.
type
().
parameterType
(
pos
));
MethodHandle
vgFilter
=
dropArguments
(
valGetter
,
0
,
Object
.
class
);
if
(--
faultCount
==
0
)
index
[
0
]
^=
1
;
x
=
filterArguments
(
proj
,
pos
,
vgFilter
).
invokeWithArguments
(
new
Object
[
len
]);
assertEquals
(
val
,
x
);
}
}
// make a fold call:
for
(
int
len
=
0
;
len
<=
4
;
len
++)
{
for
(
int
fold
=
0
;
fold
<=
len
;
fold
++)
{
MethodHandle
proj
=
id
;
// lambda(ret x, ...){x}
if
(
ret
==
void
.
class
)
proj
=
constant
(
Object
.
class
,
null
);
int
arg0
=
(
ret
==
void
.
class
?
0
:
1
);
for
(
int
j
=
0
;
j
<
len
;
j
++)
{
proj
=
dropArguments
(
proj
,
arg0
,
Object
.
class
);
}
assert
(
proj
.
type
().
parameterCount
()
==
arg0
+
len
);
// proj: (Object*, pos: vret, Object*)->ret
if
(
arg0
!=
0
)
assertEquals
(
vret
,
proj
.
type
().
parameterType
(
0
));
MethodHandle
vgFilter
=
valGetter
.
asType
(
methodType
(
ret
));
for
(
int
j
=
0
;
j
<
fold
;
j
++)
{
vgFilter
=
dropArguments
(
vgFilter
,
j
,
Object
.
class
);
}
x
=
foldArguments
(
proj
,
vgFilter
).
invokeWithArguments
(
new
Object
[
len
]);
if
(--
faultCount
==
0
)
index
[
0
]
^=
1
;
assertEquals
(
val
,
x
);
}
}
}
}
//System.out.println("faultCount="+faultCount);
}
private
static
MethodHandle
sequence
(
MethodHandle
mh1
,
MethodHandle
...
mhs
)
{
MethodHandle
res
=
mh1
;
for
(
MethodHandle
mh2
:
mhs
)
res
=
filterReturnValue
(
res
,
mh2
);
return
res
;
}
private
static
void
assertEqualFunction
(
MethodHandle
x
,
MethodHandle
y
)
throws
Throwable
{
assertEquals
(
x
.
type
(),
y
.
type
());
//??
MethodType
t
=
x
.
type
();
if
(
t
.
parameterCount
()
==
0
)
{
assertEqualFunctionAt
(
null
,
x
,
y
);
return
;
}
Class
<?>
ptype
=
t
.
parameterType
(
0
);
if
(
ptype
==
long
.
class
||
ptype
==
Long
.
class
)
{
for
(
long
i
=
-
10
;
i
<=
10
;
i
++)
{
assertEqualFunctionAt
(
i
,
x
,
y
);
}
}
else
{
for
(
int
i
=
-
10
;
i
<=
10
;
i
++)
{
assertEqualFunctionAt
(
i
,
x
,
y
);
}
}
}
private
static
void
assertEqualFunctionAt
(
Object
v
,
MethodHandle
x
,
MethodHandle
y
)
throws
Throwable
{
Object
[]
args
=
new
Object
[
x
.
type
().
parameterCount
()];
Arrays
.
fill
(
args
,
v
);
Object
xval
=
invokeWithCatch
(
x
,
args
);
Object
yval
=
invokeWithCatch
(
y
,
args
);
String
msg
=
"ok"
;
if
(!
Objects
.
equals
(
xval
,
yval
))
{
msg
=
(
"applying "
+
x
+
" & "
+
y
+
" to "
+
v
);
}
assertEquals
(
msg
,
xval
,
yval
);
}
private
static
Object
invokeWithCatch
(
MethodHandle
mh
,
Object
...
args
)
throws
Throwable
{
try
{
return
mh
.
invokeWithArguments
(
args
);
}
catch
(
Throwable
ex
)
{
System
.
out
.
println
(
"threw: "
+
mh
+
Arrays
.
asList
(
args
));
ex
.
printStackTrace
();
return
ex
;
}
}
private
static
final
Lookup
LOOKUP
=
lookup
();
private
static
MethodHandle
findStatic
(
String
name
,
Class
<?>
rtype
,
Class
<?>...
ptypes
)
{
try
{
return
LOOKUP
.
findStatic
(
LOOKUP
.
lookupClass
(),
name
,
methodType
(
rtype
,
ptypes
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
private
static
MethodHandle
findStatic
(
String
name
,
Class
<?>
rtype
,
List
<?>
ptypes
)
{
return
findStatic
(
name
,
rtype
,
ptypes
.
toArray
(
new
Class
<?>[
ptypes
.
size
()]));
}
static
int
getProperty
(
String
name
,
int
dflt
)
{
String
qual
=
LOOKUP
.
lookupClass
().
getName
();
String
prop
=
System
.
getProperty
(
qual
+
"."
+
name
);
if
(
prop
==
null
)
prop
=
System
.
getProperty
(
name
);
if
(
prop
==
null
)
return
dflt
;
return
Integer
.
parseInt
(
prop
);
}
private
static
int
opI
(
int
...
xs
)
{
stress
();
int
base
=
100
;
int
z
=
0
;
for
(
int
x
:
xs
)
{
z
=
(
z
*
base
)
+
(
x
%
base
);
}
verbose
(
"opI"
,
xs
.
length
,
xs
,
z
);
return
z
;
}
private
static
int
opI2
(
int
x
,
int
y
)
{
return
opI
(
x
,
y
);
}
// x*100 + y%100
private
static
int
opI3
(
int
x
,
int
y
,
int
z
)
{
return
opI
(
x
,
y
,
z
);
}
private
static
int
opI4
(
int
w
,
int
x
,
int
y
,
int
z
)
{
return
opI
(
w
,
x
,
y
,
z
);
}
private
static
int
opI
(
int
x
)
{
return
opI2
(
x
,
37
);
}
private
static
Object
opI_L
(
int
x
)
{
return
(
Object
)
opI
(
x
);
}
private
static
long
opJ3
(
long
x
,
long
y
,
long
z
)
{
return
(
long
)
opI3
((
int
)
x
,
(
int
)
y
,
(
int
)
z
);
}
private
static
long
opJ2
(
long
x
,
long
y
)
{
return
(
long
)
opI2
((
int
)
x
,
(
int
)
y
);
}
private
static
long
opJ
(
long
x
)
{
return
(
long
)
opI
((
int
)
x
);
}
private
static
Object
opL2
(
Object
x
,
Object
y
)
{
return
(
Object
)
opI2
((
int
)
x
,
(
int
)
y
);
}
private
static
Object
opL
(
Object
x
)
{
return
(
Object
)
opI
((
int
)
x
);
}
private
static
int
opL2_I
(
Object
x
,
Object
y
)
{
return
(
int
)
opI2
((
int
)
x
,
(
int
)
y
);
}
private
static
int
opL_I
(
Object
x
)
{
return
(
int
)
opI
((
int
)
x
);
}
private
static
long
opL_J
(
Object
x
)
{
return
(
long
)
opI
((
int
)
x
);
}
private
static
final
MethodHandle
opI
,
opI2
,
opI3
,
opI4
,
opI_L
,
opJ
,
opJ2
,
opJ3
,
opL2
,
opL
,
opL2_I
,
opL_I
,
opL_J
;
static
{
opI4
=
findStatic
(
"opI4"
,
int
.
class
,
int
.
class
,
int
.
class
,
int
.
class
,
int
.
class
);
opI3
=
findStatic
(
"opI3"
,
int
.
class
,
int
.
class
,
int
.
class
,
int
.
class
);
opI2
=
findStatic
(
"opI2"
,
int
.
class
,
int
.
class
,
int
.
class
);
opI
=
findStatic
(
"opI"
,
int
.
class
,
int
.
class
);
opI_L
=
findStatic
(
"opI_L"
,
Object
.
class
,
int
.
class
);
opJ
=
findStatic
(
"opJ"
,
long
.
class
,
long
.
class
);
opJ2
=
findStatic
(
"opJ2"
,
long
.
class
,
long
.
class
,
long
.
class
);
opJ3
=
findStatic
(
"opJ3"
,
long
.
class
,
long
.
class
,
long
.
class
,
long
.
class
);
opL2
=
findStatic
(
"opL2"
,
Object
.
class
,
Object
.
class
,
Object
.
class
);
opL
=
findStatic
(
"opL"
,
Object
.
class
,
Object
.
class
);
opL2_I
=
findStatic
(
"opL2_I"
,
int
.
class
,
Object
.
class
,
Object
.
class
);
opL_I
=
findStatic
(
"opL_I"
,
int
.
class
,
Object
.
class
);
opL_J
=
findStatic
(
"opL_J"
,
long
.
class
,
Object
.
class
);
}
private
static
final
MethodHandle
[]
INT_COLLECTORS
=
{
constant
(
int
.
class
,
42
),
opI
,
opI2
,
opI3
,
opI4
};
private
static
final
MethodHandle
[]
LONG_COLLECTORS
=
{
constant
(
long
.
class
,
42
),
opJ
,
opJ2
,
opJ3
};
private
static
int
addI
(
int
x
,
int
y
)
{
stress
();
return
x
+
y
;
}
private
static
Object
addL
(
Object
x
,
Object
y
)
{
return
addI
((
int
)
x
,
(
int
)
y
);
}
private
static
final
MethodHandle
addI
,
addL
;
static
{
addI
=
findStatic
(
"addI"
,
int
.
class
,
int
.
class
,
int
.
class
);
addL
=
findStatic
(
"addL"
,
Object
.
class
,
Object
.
class
,
Object
.
class
);
}
private
static
Object
list8ints
(
int
a
,
int
b
,
int
c
,
int
d
,
int
e
,
int
f
,
int
g
,
int
h
)
{
return
Arrays
.
asList
(
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
);
}
private
static
Object
list8longs
(
long
a
,
long
b
,
long
c
,
long
d
,
long
e
,
long
f
,
long
g
,
long
h
)
{
return
Arrays
.
asList
(
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
);
}
private
static
final
MethodHandle
list8ints
=
findStatic
(
"list8ints"
,
Object
.
class
,
Collections
.
nCopies
(
8
,
int
.
class
));
private
static
final
MethodHandle
list8longs
=
findStatic
(
"list8longs"
,
Object
.
class
,
Collections
.
nCopies
(
8
,
long
.
class
));
private
static
final
MethodHandle
[]
INT_LISTERS
,
LONG_LISTERS
;
static
{
int
listerCount
=
list8ints
.
type
().
parameterCount
()
+
1
;
INT_LISTERS
=
new
MethodHandle
[
listerCount
];
LONG_LISTERS
=
new
MethodHandle
[
listerCount
];
MethodHandle
lister
=
list8ints
;
MethodHandle
llister
=
list8longs
;
for
(
int
i
=
listerCount
-
1
;
;
i
--)
{
INT_LISTERS
[
i
]
=
lister
;
LONG_LISTERS
[
i
]
=
llister
;
if
(
i
==
0
)
break
;
lister
=
insertArguments
(
lister
,
i
-
1
,
(
int
)
0
);
llister
=
insertArguments
(
llister
,
i
-
1
,
(
long
)
0
);
}
}
private
static
Object
convI_L
(
int
x
)
{
stress
();
return
(
Object
)
x
;
}
private
static
int
convL_I
(
Object
x
)
{
stress
();
return
(
int
)
x
;
}
private
static
Object
convJ_L
(
long
x
)
{
stress
();
return
(
Object
)
x
;
}
private
static
long
convL_J
(
Object
x
)
{
stress
();
return
(
long
)
x
;
}
private
static
int
convJ_I
(
long
x
)
{
stress
();
return
(
int
)
x
;
}
private
static
long
convI_J
(
int
x
)
{
stress
();
return
(
long
)
x
;
}
private
static
final
MethodHandle
convI_L
,
convL_I
,
convJ_L
,
convL_J
,
convJ_I
,
convI_J
;
static
{
convI_L
=
findStatic
(
"convI_L"
,
Object
.
class
,
int
.
class
);
convL_I
=
findStatic
(
"convL_I"
,
int
.
class
,
Object
.
class
);
convJ_L
=
findStatic
(
"convJ_L"
,
Object
.
class
,
long
.
class
);
convL_J
=
findStatic
(
"convL_J"
,
long
.
class
,
Object
.
class
);
convJ_I
=
findStatic
(
"convJ_I"
,
int
.
class
,
long
.
class
);
convI_J
=
findStatic
(
"convI_J"
,
long
.
class
,
int
.
class
);
}
// stress modes:
private
static
final
int
REPEAT
=
getProperty
(
"REPEAT"
,
0
);
private
static
final
int
STRESS
=
getProperty
(
"STRESS"
,
0
);
private
static
/*v*/
int
STRESS_COUNT
;
private
static
final
Object
[]
SINK
=
new
Object
[
4
];
private
static
void
stress
()
{
if
(
STRESS
<=
0
)
return
;
int
count
=
STRESS
+
(
STRESS_COUNT
++
&
0x1
);
// non-constant value
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
SINK
[
i
%
SINK
.
length
]
=
new
Object
[
STRESS
+
i
%
(
SINK
.
length
+
1
)];
}
}
// verbosity:
private
static
final
int
VERBOSITY
=
getProperty
(
"VERBOSITY"
,
0
)
+
(
REPEAT
==
0
?
0
:
-
1
);
private
static
void
verbose
(
Object
a
,
Object
b
,
Object
c
,
Object
d
)
{
if
(
VERBOSITY
<=
0
)
return
;
verbose
(
1
,
a
,
b
,
c
,
d
);
}
private
static
void
verbose
(
Object
a
,
Object
b
,
Object
c
)
{
if
(
VERBOSITY
<=
0
)
return
;
verbose
(
1
,
a
,
b
,
c
);
}
private
static
void
verbose
(
int
level
,
Object
a
,
Object
...
bcd
)
{
if
(
level
>
VERBOSITY
)
return
;
String
m
=
a
.
toString
();
if
(
bcd
!=
null
&&
bcd
.
length
>
0
)
{
List
<
Object
>
l
=
new
ArrayList
<>(
bcd
.
length
);
for
(
Object
x
:
bcd
)
{
if
(
x
instanceof
Object
[])
x
=
Arrays
.
asList
((
Object
[])
x
);
if
(
x
instanceof
int
[])
x
=
Arrays
.
toString
((
int
[])
x
);
if
(
x
instanceof
long
[])
x
=
Arrays
.
toString
((
long
[])
x
);
l
.
add
(
x
);
}
m
=
m
+
Arrays
.
asList
(
bcd
);
}
System
.
out
.
println
(
m
);
}
String
testOnly
;
String
testOnlyTests
;
private
boolean
startTest
(
String
name
)
{
if
(
testOnly
!=
null
&&
!
testOnly
.
contains
(
name
))
return
false
;
verbose
(
0
,
"["
+
name
+
"]"
);
testOnlyTests
=
(
testOnlyTests
==
null
)
?
name
:
testOnlyTests
+
" "
+
name
;
return
true
;
}
}
test/java/text/Bidi/Bug7041232.java
0 → 100644
浏览文件 @
8c50098c
/*
* 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 7041232
* @summary verify that an unexpected exception isn't thrown for unnatural data to keep backward compatibility with JDK 6.
*/
import
java.text.*
;
public
class
Bug7041232
{
public
static
void
main
(
String
[]
args
)
{
String
UnicodeChars
;
StringBuffer
sb
=
new
StringBuffer
();
// Generates String which includes U+2028(line separator) and
// U+2029(paragraph separator)
for
(
int
i
=
0x2000
;
i
<
0x2100
;
i
++)
{
sb
.
append
((
char
)
i
);
}
UnicodeChars
=
sb
.
toString
();
Bidi
bidi
=
new
Bidi
(
UnicodeChars
,
Bidi
.
DIRECTION_DEFAULT_LEFT_TO_RIGHT
);
bidi
.
createLineBidi
(
0
,
UnicodeChars
.
length
());
}
}
test/javax/swing/JComboBox/7031551/bug7031551.java
0 → 100644
浏览文件 @
8c50098c
/*
* 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 7031551
* @summary Generics: JComboBox
* @author Pavel Porvatov
*/
import
javax.swing.*
;
import
java.util.Vector
;
public
class
bug7031551
{
private
static
final
String
TEST_ELEMENT1
=
"Test1"
;
private
static
final
String
TEST_ELEMENT2
=
"Test2"
;
private
static
final
String
TEST_ELEMENT3
=
"Test3"
;
/**
* @param args the command line arguments
*/
@SuppressWarnings
(
"unchecked"
)
public
static
void
main
(
String
[]
args
)
{
testRawSignatures
();
testGenericSignatures
();
}
@SuppressWarnings
(
"unchecked"
)
private
static
void
testRawSignatures
()
{
// Test JComboBox
ComboBoxModel
rawTestModel
=
new
DefaultComboBoxModel
();
JComboBox
rawTestComboBox
=
new
JComboBox
();
rawTestComboBox
=
new
JComboBox
(
rawTestModel
);
rawTestComboBox
=
new
JComboBox
(
new
Object
[]{
TEST_ELEMENT1
});
rawTestComboBox
=
new
JComboBox
(
new
Vector
());
Object
unused1
=
rawTestComboBox
.
getPrototypeDisplayValue
();
rawTestComboBox
.
setPrototypeDisplayValue
(
TEST_ELEMENT1
);
ListCellRenderer
unused2
=
rawTestComboBox
.
getRenderer
();
rawTestComboBox
.
setRenderer
(
new
DefaultListCellRenderer
());
ComboBoxModel
unused3
=
rawTestComboBox
.
getModel
();
rawTestComboBox
.
setModel
(
rawTestModel
);
rawTestComboBox
.
addItem
(
TEST_ELEMENT2
);
rawTestComboBox
.
insertItemAt
(
TEST_ELEMENT3
,
1
);
rawTestComboBox
.
removeItem
(
TEST_ELEMENT2
);
assertEquals
(
rawTestComboBox
.
getItemAt
(
0
),
TEST_ELEMENT3
);
rawTestComboBox
.
removeAllItems
();
// Test DefaultComboBoxModel
DefaultComboBoxModel
testModel
=
new
DefaultComboBoxModel
();
testModel
=
new
DefaultComboBoxModel
(
new
Vector
());
testModel
=
new
DefaultComboBoxModel
(
new
Object
[]{
TEST_ELEMENT1
});
testModel
.
addElement
(
TEST_ELEMENT2
);
testModel
.
insertElementAt
(
TEST_ELEMENT3
,
1
);
assertEquals
(
testModel
.
getElementAt
(
2
),
TEST_ELEMENT2
);
}
private
static
void
testGenericSignatures
()
{
// Test JComboBox
ComboBoxModel
<
String
>
stringTestModel
=
new
DefaultComboBoxModel
<
String
>();
JComboBox
<
String
>
stringTestComboBox
=
new
JComboBox
<
String
>();
stringTestComboBox
=
new
JComboBox
<
String
>(
stringTestModel
);
stringTestComboBox
=
new
JComboBox
<
String
>(
new
String
[]{
TEST_ELEMENT1
});
stringTestComboBox
=
new
JComboBox
<
String
>(
new
Vector
<
String
>());
String
unused1
=
stringTestComboBox
.
getPrototypeDisplayValue
();
stringTestComboBox
.
setPrototypeDisplayValue
(
TEST_ELEMENT1
);
ListCellRenderer
<?
super
String
>
unused2
=
stringTestComboBox
.
getRenderer
();
stringTestComboBox
.
setRenderer
(
new
DefaultListCellRenderer
());
ComboBoxModel
unused3
=
stringTestComboBox
.
getModel
();
stringTestComboBox
.
setModel
(
stringTestModel
);
stringTestComboBox
.
addItem
(
TEST_ELEMENT2
);
stringTestComboBox
.
insertItemAt
(
TEST_ELEMENT3
,
1
);
stringTestComboBox
.
removeItem
(
TEST_ELEMENT2
);
assertEquals
(
stringTestComboBox
.
getItemAt
(
0
),
TEST_ELEMENT3
);
stringTestComboBox
.
removeAllItems
();
// Test DefaultComboBoxModel
DefaultComboBoxModel
<
String
>
testModel
=
new
DefaultComboBoxModel
<
String
>();
testModel
=
new
DefaultComboBoxModel
<
String
>(
new
Vector
<
String
>());
testModel
=
new
DefaultComboBoxModel
<
String
>(
new
String
[]{
TEST_ELEMENT1
});
testModel
.
addElement
(
TEST_ELEMENT2
);
testModel
.
insertElementAt
(
TEST_ELEMENT3
,
1
);
assertEquals
(
testModel
.
getElementAt
(
2
),
TEST_ELEMENT2
);
}
private
static
void
assertEquals
(
Object
expectedObject
,
Object
actualObject
)
{
if
(!
expectedObject
.
equals
(
actualObject
))
{
throw
new
RuntimeException
(
"Expected: "
+
expectedObject
+
" but was: "
+
actualObject
);
}
}
}
test/javax/swing/JTable/6788484/bug6788484.java
浏览文件 @
8c50098c
/*
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010,
2011
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -24,9 +24,17 @@
...
@@ -24,9 +24,17 @@
/* @test
/* @test
@bug 6788484
@bug 6788484
@summary NPE in DefaultTableCellHeaderRenderer.getColumnSortOrder() with null table
@summary NPE in DefaultTableCellHeaderRenderer.getColumnSortOrder() with null table
@compile -XDignore.symbol.file=true bug6788484.java
@author Alexander Potochkin
@author Alexander Potochkin
@run main bug6788484
@run main bug6788484
*/
*/
/*
* Compile with -XDignore.symbol.file=true option as a workaround for
* specific behaviour described in 6380059 which restricts proprietary
* package loading
*/
import
sun.swing.table.DefaultTableCellHeaderRenderer
;
import
sun.swing.table.DefaultTableCellHeaderRenderer
;
import
javax.swing.*
;
import
javax.swing.*
;
...
...
test/sun/invoke/util/ValueConversionsTest.java
0 → 100644
浏览文件 @
8c50098c
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along 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
test.sun.invoke.util
;
import
sun.invoke.util.ValueConversions
;
import
sun.invoke.util.Wrapper
;
import
java.lang.invoke.MethodType
;
import
java.lang.invoke.MethodHandle
;
import
java.lang.invoke.MethodHandles
;
import
java.io.Serializable
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
org.junit.Ignore
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
/* @test
* @summary unit tests for value-type conversion utilities
* @ignore This test requires a special compilation environment to access sun.inovke.util. Run by hand.
* @run junit/othervm test.sun.invoke.util.ValueConversionsTest
* @run junit/othervm
* -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.START_ARITY=250
* test.sun.invoke.util.ValueConversionsTest
*/
// This might take a while and burn lots of metadata:
// @run junit/othervm -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.EXHAUSTIVE=true test.sun.invoke.util.ValueConversionsTest
/**
*
* @author jrose
*/
public
class
ValueConversionsTest
{
private
static
final
Class
CLASS
=
ValueConversionsTest
.
class
;
private
static
final
int
MAX_ARITY
=
Integer
.
getInteger
(
CLASS
.
getSimpleName
()+
".MAX_ARITY"
,
40
);
private
static
final
int
START_ARITY
=
Integer
.
getInteger
(
CLASS
.
getSimpleName
()+
".START_ARITY"
,
0
);
private
static
final
boolean
EXHAUSTIVE
=
Boolean
.
getBoolean
(
CLASS
.
getSimpleName
()+
".EXHAUSTIVE"
);
@Test
public
void
testUnbox
()
throws
Throwable
{
testUnbox
(
false
);
}
@Test
public
void
testUnboxCast
()
throws
Throwable
{
testUnbox
(
true
);
}
private
void
testUnbox
(
boolean
doCast
)
throws
Throwable
{
//System.out.println("unbox");
for
(
Wrapper
dst
:
Wrapper
.
values
())
{
//System.out.println(dst);
for
(
Wrapper
src
:
Wrapper
.
values
())
{
testUnbox
(
doCast
,
dst
,
src
);
}
}
}
private
void
testUnbox
(
boolean
doCast
,
Wrapper
dst
,
Wrapper
src
)
throws
Throwable
{
boolean
expectThrow
=
!
doCast
&&
!
dst
.
isConvertibleFrom
(
src
);
if
(
dst
==
Wrapper
.
OBJECT
||
src
==
Wrapper
.
OBJECT
)
return
;
// must have prims
if
(
dst
==
Wrapper
.
OBJECT
)
expectThrow
=
false
;
// everything (even VOID==null here) converts to OBJECT
try
{
for
(
int
n
=
-
5
;
n
<
10
;
n
++)
{
Object
box
=
src
.
wrap
(
n
);
switch
(
src
)
{
case
VOID:
assertEquals
(
box
,
null
);
break
;
case
OBJECT:
box
=
box
.
toString
();
break
;
case
SHORT:
assertEquals
(
box
.
getClass
(),
Short
.
class
);
break
;
default
:
assertEquals
(
box
.
getClass
(),
src
.
wrapperType
());
break
;
}
MethodHandle
unboxer
;
if
(
doCast
)
unboxer
=
ValueConversions
.
unboxCast
(
dst
.
primitiveType
());
else
unboxer
=
ValueConversions
.
unbox
(
dst
.
primitiveType
());
Object
expResult
=
(
box
==
null
)
?
dst
.
zero
()
:
dst
.
wrap
(
box
);
Object
result
=
null
;
switch
(
dst
)
{
case
INT:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
LONG:
result
=
(
long
)
unboxer
.
invokeExact
(
box
);
break
;
case
FLOAT:
result
=
(
float
)
unboxer
.
invokeExact
(
box
);
break
;
case
DOUBLE:
result
=
(
double
)
unboxer
.
invokeExact
(
box
);
break
;
case
CHAR:
result
=
(
char
)
unboxer
.
invokeExact
(
box
);
break
;
case
BYTE:
result
=
(
byte
)
unboxer
.
invokeExact
(
box
);
break
;
case
SHORT:
result
=
(
short
)
unboxer
.
invokeExact
(
box
);
break
;
case
OBJECT:
result
=
(
Object
)
unboxer
.
invokeExact
(
box
);
break
;
case
BOOLEAN:
result
=
(
boolean
)
unboxer
.
invokeExact
(
box
);
break
;
case
VOID:
result
=
null
;
unboxer
.
invokeExact
(
box
);
break
;
}
if
(
expectThrow
)
{
expResult
=
"(need an exception)"
;
}
assertEquals
(
"(doCast,expectThrow,dst,src,n,box)="
+
Arrays
.
asList
(
doCast
,
expectThrow
,
dst
,
src
,
n
,
box
),
expResult
,
result
);
}
}
catch
(
RuntimeException
ex
)
{
if
(
expectThrow
)
return
;
System
.
out
.
println
(
"Unexpected throw for (doCast,expectThrow,dst,src)="
+
Arrays
.
asList
(
doCast
,
expectThrow
,
dst
,
src
));
throw
ex
;
}
}
@Test
public
void
testUnboxRaw
()
throws
Throwable
{
//System.out.println("unboxRaw");
for
(
Wrapper
w
:
Wrapper
.
values
())
{
if
(
w
==
Wrapper
.
OBJECT
)
continue
;
// skip this; no raw form
//System.out.println(w);
for
(
int
n
=
-
5
;
n
<
10
;
n
++)
{
Object
box
=
w
.
wrap
(
n
);
long
expResult
=
w
.
unwrapRaw
(
box
);
Object
box2
=
w
.
wrapRaw
(
expResult
);
assertEquals
(
box
,
box2
);
MethodHandle
unboxer
=
ValueConversions
.
unboxRaw
(
w
.
primitiveType
());
long
result
=
-
1
;
switch
(
w
)
{
case
INT:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
LONG:
result
=
(
long
)
unboxer
.
invokeExact
(
box
);
break
;
case
FLOAT:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
DOUBLE:
result
=
(
long
)
unboxer
.
invokeExact
(
box
);
break
;
case
CHAR:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
BYTE:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
SHORT:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
BOOLEAN:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
case
VOID:
result
=
(
int
)
unboxer
.
invokeExact
(
box
);
break
;
}
assertEquals
(
"(w,n,box)="
+
Arrays
.
asList
(
w
,
n
,
box
),
expResult
,
result
);
}
}
}
@Test
public
void
testBox
()
throws
Throwable
{
//System.out.println("box");
for
(
Wrapper
w
:
Wrapper
.
values
())
{
if
(
w
==
Wrapper
.
VOID
)
continue
;
// skip this; no unboxed form
//System.out.println(w);
for
(
int
n
=
-
5
;
n
<
10
;
n
++)
{
Object
box
=
w
.
wrap
(
n
);
MethodHandle
boxer
=
ValueConversions
.
box
(
w
.
primitiveType
());
Object
expResult
=
box
;
Object
result
=
null
;
switch
(
w
)
{
case
INT:
result
=
boxer
.
invokeExact
((
int
)
n
);
break
;
case
LONG:
result
=
boxer
.
invokeExact
((
long
)
n
);
break
;
case
FLOAT:
result
=
boxer
.
invokeExact
((
float
)
n
);
break
;
case
DOUBLE:
result
=
boxer
.
invokeExact
((
double
)
n
);
break
;
case
CHAR:
result
=
boxer
.
invokeExact
((
char
)
n
);
break
;
case
BYTE:
result
=
boxer
.
invokeExact
((
byte
)
n
);
break
;
case
SHORT:
result
=
boxer
.
invokeExact
((
short
)
n
);
break
;
case
OBJECT:
result
=
boxer
.
invokeExact
((
Object
)
n
);
break
;
case
BOOLEAN:
result
=
boxer
.
invokeExact
((
n
&
1
)
!=
0
);
break
;
}
assertEquals
(
"(dst,src,n,box)="
+
Arrays
.
asList
(
w
,
w
,
n
,
box
),
expResult
,
result
);
}
}
}
@Test
public
void
testBoxRaw
()
throws
Throwable
{
//System.out.println("boxRaw");
for
(
Wrapper
w
:
Wrapper
.
values
())
{
if
(
w
==
Wrapper
.
VOID
)
continue
;
// skip this; no unboxed form
if
(
w
==
Wrapper
.
OBJECT
)
continue
;
// skip this; no raw form
//System.out.println(w);
for
(
int
n
=
-
5
;
n
<
10
;
n
++)
{
Object
box
=
w
.
wrap
(
n
);
long
raw
=
w
.
unwrapRaw
(
box
);
Object
expResult
=
box
;
MethodHandle
boxer
=
ValueConversions
.
boxRaw
(
w
.
primitiveType
());
Object
result
=
null
;
switch
(
w
)
{
case
INT:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
case
LONG:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
FLOAT:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
case
DOUBLE:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
CHAR:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
case
BYTE:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
case
SHORT:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
case
BOOLEAN:
result
=
boxer
.
invokeExact
((
int
)
raw
);
break
;
}
assertEquals
(
"(dst,src,n,box)="
+
Arrays
.
asList
(
w
,
w
,
n
,
box
),
expResult
,
result
);
}
}
}
@Test
public
void
testReboxRaw
()
throws
Throwable
{
//System.out.println("reboxRaw");
for
(
Wrapper
w
:
Wrapper
.
values
())
{
Wrapper
pw
=
Wrapper
.
forPrimitiveType
(
w
.
rawPrimitiveType
());
if
(
w
==
Wrapper
.
VOID
)
continue
;
// skip this; no unboxed form
if
(
w
==
Wrapper
.
OBJECT
)
continue
;
// skip this; no raw form
//System.out.println(w);
for
(
int
n
=
-
5
;
n
<
10
;
n
++)
{
Object
box
=
w
.
wrap
(
n
);
Object
raw
=
pw
.
wrap
(
w
.
unwrapRaw
(
box
));
Object
expResult
=
box
;
MethodHandle
boxer
=
ValueConversions
.
rebox
(
w
.
primitiveType
());
Object
result
=
null
;
switch
(
w
)
{
case
INT:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
LONG:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
FLOAT:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
DOUBLE:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
CHAR:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
BYTE:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
SHORT:
result
=
boxer
.
invokeExact
(
raw
);
break
;
case
BOOLEAN:
result
=
boxer
.
invokeExact
(
raw
);
break
;
}
assertEquals
(
"(dst,src,n,box)="
+
Arrays
.
asList
(
w
,
w
,
n
,
box
),
expResult
,
result
);
}
}
}
@Test
public
void
testCast
()
throws
Throwable
{
//System.out.println("cast");
Class
<?>[]
types
=
{
Object
.
class
,
Serializable
.
class
,
String
.
class
,
Number
.
class
,
Integer
.
class
};
Object
[]
objects
=
{
new
Object
(),
Boolean
.
FALSE
,
"hello"
,
(
Long
)
12L
,
(
Integer
)
6
};
for
(
Class
<?>
dst
:
types
)
{
MethodHandle
caster
=
ValueConversions
.
cast
(
dst
);
assertEquals
(
caster
.
type
(),
ValueConversions
.
identity
().
type
());
for
(
Object
obj
:
objects
)
{
Class
<?>
src
=
obj
.
getClass
();
boolean
canCast
;
if
(
dst
.
isInterface
())
{
canCast
=
true
;
}
else
{
canCast
=
dst
.
isAssignableFrom
(
src
);
assertEquals
(
canCast
,
dst
.
isInstance
(
obj
));
}
//System.out.println("obj="+obj+" <: dst="+dst);
try
{
Object
result
=
caster
.
invokeExact
(
obj
);
if
(
canCast
)
assertEquals
(
obj
,
result
);
else
assertEquals
(
"cast should not have succeeded"
,
dst
,
obj
);
}
catch
(
ClassCastException
ex
)
{
if
(
canCast
)
throw
ex
;
}
}
}
}
@Test
public
void
testIdentity
()
throws
Throwable
{
//System.out.println("identity");
MethodHandle
id
=
ValueConversions
.
identity
();
Object
expResult
=
"foo"
;
Object
result
=
id
.
invokeExact
(
expResult
);
// compiler bug: ValueConversions.identity().invokeExact("bar");
assertEquals
(
expResult
,
result
);
}
@Test
public
void
testVarargsArray
()
throws
Throwable
{
//System.out.println("varargsArray");
final
int
MIN
=
START_ARITY
;
final
int
MAX
=
MAX_ARITY
-
2
;
// 253+1 would cause parameter overflow with 'this' added
for
(
int
nargs
=
MIN
;
nargs
<=
MAX
;
nargs
=
nextArgCount
(
nargs
,
17
,
MAX
))
{
MethodHandle
target
=
ValueConversions
.
varargsArray
(
nargs
);
Object
[]
args
=
new
Object
[
nargs
];
for
(
int
i
=
0
;
i
<
nargs
;
i
++)
args
[
i
]
=
"#"
+
i
;
Object
res
=
target
.
invokeWithArguments
(
args
);
assertArrayEquals
(
args
,
(
Object
[])
res
);
}
}
@Test
public
void
testVarargsReferenceArray
()
throws
Throwable
{
//System.out.println("varargsReferenceArray");
testTypedVarargsArray
(
Object
[].
class
);
testTypedVarargsArray
(
String
[].
class
);
testTypedVarargsArray
(
Number
[].
class
);
}
@Test
public
void
testVarargsPrimitiveArray
()
throws
Throwable
{
//System.out.println("varargsPrimitiveArray");
testTypedVarargsArray
(
int
[].
class
);
testTypedVarargsArray
(
long
[].
class
);
testTypedVarargsArray
(
byte
[].
class
);
testTypedVarargsArray
(
boolean
[].
class
);
testTypedVarargsArray
(
short
[].
class
);
testTypedVarargsArray
(
char
[].
class
);
testTypedVarargsArray
(
float
[].
class
);
testTypedVarargsArray
(
double
[].
class
);
}
private
static
int
nextArgCount
(
int
nargs
,
int
density
,
int
MAX
)
{
if
(
EXHAUSTIVE
)
return
nargs
+
1
;
if
(
nargs
>=
MAX
)
return
Integer
.
MAX_VALUE
;
int
BOT
=
20
,
TOP
=
MAX
-
5
;
if
(
density
<
10
)
{
BOT
=
10
;
MAX
=
TOP
-
2
;
}
if
(
nargs
<=
BOT
||
nargs
>=
TOP
)
{
++
nargs
;
}
else
{
int
bump
=
Math
.
max
(
1
,
100
/
density
);
nargs
+=
bump
;
if
(
nargs
>
TOP
)
nargs
=
TOP
;
}
return
nargs
;
}
private
void
testTypedVarargsArray
(
Class
<?>
arrayType
)
throws
Throwable
{
System
.
out
.
println
(
arrayType
.
getSimpleName
());
Class
<?>
elemType
=
arrayType
.
getComponentType
();
int
MIN
=
START_ARITY
;
int
MAX
=
MAX_ARITY
-
2
;
// 253+1 would cause parameter overflow with 'this' added
int
density
=
3
;
if
(
elemType
==
int
.
class
||
elemType
==
long
.
class
)
density
=
7
;
if
(
elemType
==
long
.
class
||
elemType
==
double
.
class
)
{
MAX
/=
2
;
MIN
/=
2
;
}
for
(
int
nargs
=
MIN
;
nargs
<=
MAX
;
nargs
=
nextArgCount
(
nargs
,
density
,
MAX
))
{
Object
[]
args
=
makeTestArray
(
elemType
,
nargs
);
MethodHandle
varargsArray
=
ValueConversions
.
varargsArray
(
arrayType
,
nargs
);
MethodType
vaType
=
varargsArray
.
type
();
assertEquals
(
arrayType
,
vaType
.
returnType
());
if
(
nargs
!=
0
)
{
assertEquals
(
elemType
,
vaType
.
parameterType
(
0
));
assertEquals
(
elemType
,
vaType
.
parameterType
(
vaType
.
parameterCount
()-
1
));
}
assertEquals
(
MethodType
.
methodType
(
arrayType
,
Collections
.<
Class
<?>>
nCopies
(
nargs
,
elemType
)),
vaType
);
Object
res
=
varargsArray
.
invokeWithArguments
(
args
);
String
resString
=
toArrayString
(
res
);
assertEquals
(
Arrays
.
toString
(
args
),
resString
);
MethodHandle
spreader
=
varargsArray
.
asSpreader
(
arrayType
,
nargs
);
MethodType
stype
=
spreader
.
type
();
assert
(
stype
==
MethodType
.
methodType
(
arrayType
,
arrayType
));
if
(
nargs
<=
5
)
{
// invoke target as a spreader also:
Object
res2
=
spreader
.
invokeWithArguments
((
Object
)
res
);
String
res2String
=
toArrayString
(
res2
);
assertEquals
(
Arrays
.
toString
(
args
),
res2String
);
// invoke the spreader on a generic Object[] array; check for error
try
{
Object
res3
=
spreader
.
invokeWithArguments
((
Object
)
args
);
String
res3String
=
toArrayString
(
res3
);
assertTrue
(
arrayType
.
getName
(),
arrayType
.
isAssignableFrom
(
Object
[].
class
));
assertEquals
(
Arrays
.
toString
(
args
),
res3String
);
}
catch
(
ClassCastException
ex
)
{
assertFalse
(
arrayType
.
getName
(),
arrayType
.
isAssignableFrom
(
Object
[].
class
));
}
}
if
(
nargs
==
0
)
{
// invoke spreader on null arglist
Object
res3
=
spreader
.
invokeWithArguments
((
Object
)
null
);
String
res3String
=
toArrayString
(
res3
);
assertEquals
(
Arrays
.
toString
(
args
),
res3String
);
}
}
}
private
static
Object
[]
makeTestArray
(
Class
<?>
elemType
,
int
len
)
{
Wrapper
elem
=
null
;
if
(
elemType
.
isPrimitive
())
elem
=
Wrapper
.
forPrimitiveType
(
elemType
);
else
if
(
Wrapper
.
isWrapperType
(
elemType
))
elem
=
Wrapper
.
forWrapperType
(
elemType
);
Object
[]
args
=
new
Object
[
len
];
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
Object
arg
=
i
*
100
;
if
(
elem
==
null
)
{
if
(
elemType
==
String
.
class
)
arg
=
"#"
+
arg
;
arg
=
elemType
.
cast
(
arg
);
// just to make sure
}
else
{
switch
(
elem
)
{
case
BOOLEAN:
arg
=
(
i
%
3
==
0
);
break
;
case
CHAR:
arg
=
'a'
+
i
;
break
;
case
LONG:
arg
=
(
long
)
i
*
1000_000_000
;
break
;
case
FLOAT:
arg
=
(
float
)
i
/
100
;
break
;
case
DOUBLE:
arg
=
(
double
)
i
/
1000_000
;
break
;
}
arg
=
elem
.
cast
(
arg
,
elemType
);
}
args
[
i
]
=
arg
;
}
//System.out.println(elemType.getName()+Arrays.toString(args));
return
args
;
}
private
static
String
toArrayString
(
Object
a
)
{
if
(
a
==
null
)
return
"null"
;
Class
<?>
elemType
=
a
.
getClass
().
getComponentType
();
if
(
elemType
==
null
)
return
a
.
toString
();
if
(
elemType
.
isPrimitive
())
{
switch
(
Wrapper
.
forPrimitiveType
(
elemType
))
{
case
INT:
return
Arrays
.
toString
((
int
[])
a
);
case
BYTE:
return
Arrays
.
toString
((
byte
[])
a
);
case
BOOLEAN:
return
Arrays
.
toString
((
boolean
[])
a
);
case
SHORT:
return
Arrays
.
toString
((
short
[])
a
);
case
CHAR:
return
Arrays
.
toString
((
char
[])
a
);
case
FLOAT:
return
Arrays
.
toString
((
float
[])
a
);
case
LONG:
return
Arrays
.
toString
((
long
[])
a
);
case
DOUBLE:
return
Arrays
.
toString
((
double
[])
a
);
}
}
return
Arrays
.
toString
((
Object
[])
a
);
}
@Test
public
void
testVarargsList
()
throws
Throwable
{
//System.out.println("varargsList");
final
int
MIN
=
START_ARITY
;
final
int
MAX
=
MAX_ARITY
-
2
;
// 253+1 would cause parameter overflow with 'this' added
for
(
int
nargs
=
MIN
;
nargs
<=
MAX
;
nargs
=
nextArgCount
(
nargs
,
7
,
MAX
))
{
MethodHandle
target
=
ValueConversions
.
varargsList
(
nargs
);
Object
[]
args
=
new
Object
[
nargs
];
for
(
int
i
=
0
;
i
<
nargs
;
i
++)
args
[
i
]
=
"#"
+
i
;
Object
res
=
target
.
invokeWithArguments
(
args
);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录