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
9315c733fb17ddfb9fb44be7e0ffea37bf3c727d jdk7-b140
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143
make/sun/rmi/rmi/Makefile
浏览文件 @
8c50098c
...
...
@@ -85,16 +85,21 @@ REMOTE_impls = \
sun.rmi.registry.RegistryImpl
\
sun.rmi.transport.DGCImpl
ifeq
($(PLATFORM), windows)
build
:
stubs
else
# PLATFORM
ifneq
($(ARCH_DATA_MODEL), 32)
build
:
stubs
else
# ARCH_DATA_MODEL
build
:
stubs bin
#
# The java-rmi.cgi script in bin/ only gets delivered in certain situations
#
BUILD_TARGETS
=
stubs
ifeq
($(PLATFORM), linux)
BUILD_TARGETS
+=
bin
endif
ifeq
($(PLATFORM), solaris)
ifeq
($(ARCH_DATA_MODEL), 32)
BUILD_TARGETS
+=
bin
endif
endif
build
:
$(BUILD_TARGETS)
clean clobber
::
bin.clean
...
...
make/sun/xawt/mapfile-vers
浏览文件 @
8c50098c
...
...
@@ -158,7 +158,6 @@ SUNWprivate_1.1 {
Java_sun_awt_X11_XRobotPeer_mouseReleaseImpl;
Java_sun_awt_X11_XRobotPeer_mouseWheelImpl;
Java_sun_awt_X11_XRobotPeer_setup;
Java_sun_awt_X11_XRobotPeer__1dispose;
Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl;
Java_java_awt_Component_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,
/**
* Invalidates this component and its ancestors.
* <p>
* All the ancestors of this component up to the nearest validate root are
* marked invalid also. If there is no a validate root container for this
* component, all of its ancestors up to the root of the hierarchy are
* marked invalid as well. Marking a container <i>invalid</i> indicates
* that the container needs to be laid out.
* By default, all the ancestors of the component up to the top-most
* container of the hierarchy are marked invalid. If the {@code
* java.awt.smartInvalidate} system property is set to {@code true},
* invalidation stops on the nearest validate root of this component.
* Marking a container <i>invalid</i> indicates that the container needs to
* be laid out.
* <p>
* This method is called automatically when any layout-related information
* 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;
import
java.io.PrintStream
;
import
java.io.PrintWriter
;
import
java.security.AccessController
;
import
java.util.Arrays
;
import
java.util.EventListener
;
import
java.util.HashSet
;
...
...
@@ -60,6 +62,8 @@ import sun.awt.dnd.SunDropTargetEvent;
import
sun.java2d.pipe.Region
;
import
sun.security.action.GetBooleanAction
;
/**
* A generic Abstract Window Toolkit(AWT) container object is a component
* that can contain other AWT components.
...
...
@@ -1506,12 +1510,18 @@ public class Container extends Component {
* Layout-related changes, such as bounds of the validate root descendants,
* do not affect the layout of the validate root parent. This peculiarity
* 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>
* If a component hierarchy contains validate roots, the {@code validate()}
* method must be invoked on the validate root of a previously invalidated
* component, rather than on the top-level container (such as a {@code
* Frame} object) to restore the validity of the hierarchy later.
* If a component hierarchy contains validate roots and the new optimized
* {@code invalidate()} behavior is enabled, the {@code validate()} method
* must be invoked on the validate root of a previously invalidated
* 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>
* The {@code Window} class and the {@code Applet} class are the validate
* roots in AWT. Swing introduces more validate roots.
...
...
@@ -1527,13 +1537,20 @@ public class Container extends Component {
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
* is a validate root.
*/
@Override
void
invalidateParent
()
{
if
(!
isValidateRoot
())
{
if
(!
is
JavaAwtSmartInvalidate
||
!
is
ValidateRoot
())
{
super
.
invalidateParent
();
}
}
...
...
@@ -1572,9 +1589,8 @@ public class Container extends Component {
* automatically. Note that the ancestors of the container may be
* invalidated also (see {@link Component#invalidate} for details.)
* Therefore, to restore the validity of the hierarchy, the {@code
* validate()} method should be invoked on a validate root of an
* invalidated component, or on the top-most container if the hierarchy
* does not contain validate roots.
* validate()} method should be invoked on the top-most invalid
* container of the hierarchy.
* <p>
* Validating the container may be a quite time-consuming operation. For
* 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 {
*/
protected
void
loadSystemColors
(
int
[]
systemColors
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
}
/**
...
...
@@ -504,10 +501,7 @@ public abstract class Toolkit {
*/
public
void
setDynamicLayout
(
boolean
dynamic
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
}
/**
...
...
@@ -531,9 +525,8 @@ public abstract class Toolkit {
*/
protected
boolean
isDynamicLayoutSet
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutSet
();
}
else
{
...
...
@@ -569,9 +562,8 @@ public abstract class Toolkit {
*/
public
boolean
isDynamicLayoutActive
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
isDynamicLayoutActive
();
}
else
{
...
...
@@ -615,9 +607,7 @@ public abstract class Toolkit {
*/
public
Insets
getScreenInsets
(
GraphicsConfiguration
gc
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getScreenInsets
(
gc
);
}
else
{
...
...
@@ -1200,10 +1190,7 @@ public abstract class Toolkit {
* security manager's <code>checkPermission</code> method with a <code>
* RuntimePermission("queuePrintJob")</code> permission.
*
* @param frame the parent of the print dialog. May be null if and only
* if jobAttributes is not null and jobAttributes.getDialog()
* returns JobAttributes.DialogType.NONE or
* JobAttributes.DialogType.COMMON.
* @param frame the parent of the print dialog. May not be null.
* @param jobtitle the title of the PrintJob. A null title is equivalent
* to "".
* @param jobAttributes a set of job attributes which will control the
...
...
@@ -1359,9 +1346,8 @@ public abstract class Toolkit {
* @since 1.4
*/
public
Clipboard
getSystemSelection
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getSystemSelection
();
}
else
{
...
...
@@ -1391,9 +1377,7 @@ public abstract class Toolkit {
* @since JDK1.1
*/
public
int
getMenuShortcutKeyMask
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
return
Event
.
CTRL_MASK
;
}
...
...
@@ -1418,7 +1402,10 @@ public abstract class Toolkit {
* @since 1.3
*/
public
boolean
getLockingKeyState
(
int
keyCode
)
throws
UnsupportedOperationException
{
throws
UnsupportedOperationException
{
GraphicsEnvironment
.
checkHeadless
();
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.getLockingKeyState"
);
...
...
@@ -1449,7 +1436,10 @@ public abstract class Toolkit {
* @since 1.3
*/
public
void
setLockingKeyState
(
int
keyCode
,
boolean
on
)
throws
UnsupportedOperationException
{
throws
UnsupportedOperationException
{
GraphicsEnvironment
.
checkHeadless
();
if
(!
(
keyCode
==
KeyEvent
.
VK_CAPS_LOCK
||
keyCode
==
KeyEvent
.
VK_NUM_LOCK
||
keyCode
==
KeyEvent
.
VK_SCROLL_LOCK
||
keyCode
==
KeyEvent
.
VK_KANA_LOCK
))
{
throw
new
IllegalArgumentException
(
"invalid key for Toolkit.setLockingKeyState"
);
...
...
@@ -1523,9 +1513,8 @@ public abstract class Toolkit {
*/
public
Dimension
getBestCursorSize
(
int
preferredWidth
,
int
preferredHeight
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
// Override to implement custom cursor support.
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
...
...
@@ -1553,9 +1542,8 @@ public abstract class Toolkit {
* @since 1.2
*/
public
int
getMaximumCursorColors
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
// Override to implement custom cursor support.
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
getMaximumCursorColors
();
...
...
@@ -1605,9 +1593,8 @@ public abstract class Toolkit {
public
boolean
isFrameStateSupported
(
int
state
)
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
if
(
this
!=
Toolkit
.
getDefaultToolkit
())
{
return
Toolkit
.
getDefaultToolkit
().
isFrameStateSupported
(
state
);
...
...
@@ -2614,9 +2601,8 @@ public abstract class Toolkit {
* @since 1.7
*/
public
boolean
areExtraMouseButtonsEnabled
()
throws
HeadlessException
{
if
(
GraphicsEnvironment
.
isHeadless
()){
throw
new
HeadlessException
();
}
GraphicsEnvironment
.
checkHeadless
();
return
Toolkit
.
getDefaultToolkit
().
areExtraMouseButtonsEnabled
();
}
}
src/share/classes/java/lang/Throwable.java
浏览文件 @
8c50098c
...
...
@@ -777,7 +777,8 @@ public class Throwable implements Serializable {
* @see java.lang.Throwable#printStackTrace()
*/
public
synchronized
Throwable
fillInStackTrace
()
{
if
(
stackTrace
!=
null
)
{
if
(
stackTrace
!=
null
||
backtrace
!=
null
/* Out of protocol state */
)
{
fillInStackTrace
(
0
);
stackTrace
=
UNASSIGNED_STACK
;
}
...
...
@@ -817,7 +818,8 @@ public class Throwable implements Serializable {
private
synchronized
StackTraceElement
[]
getOurStackTrace
()
{
// Initialize stack trace field with information from
// 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
();
stackTrace
=
new
StackTraceElement
[
depth
];
for
(
int
i
=
0
;
i
<
depth
;
i
++)
...
...
@@ -865,7 +867,8 @@ public class Throwable implements Serializable {
}
synchronized
(
this
)
{
if
(
this
.
stackTrace
==
null
)
// Immutable stack
if
(
this
.
stackTrace
==
null
&&
// Immutable stack
backtrace
==
null
)
// Test for out of protocol state
return
;
this
.
stackTrace
=
defensiveCopy
;
}
...
...
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
浏览文件 @
8c50098c
...
...
@@ -27,6 +27,7 @@ package java.lang.invoke;
import
sun.invoke.util.VerifyType
;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.ValueConversions
;
import
java.util.Arrays
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
...
...
@@ -55,29 +56,35 @@ class AdapterMethodHandle extends BoundMethodHandle {
this
(
target
,
newType
,
conv
,
null
);
}
int
getConversion
()
{
return
conversion
;
}
// TO DO: When adapting another MH with a null conversion, clone
// the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by MethodHandles.convertArguments?
*/
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
)
{
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
,
int
level
)
{
// same number of args, of course
int
len
=
newType
.
parameterCount
();
if
(
len
!=
oldType
.
parameterCount
())
return
false
;
// Check return type.
(Not much can be done with it.)
// Check return type.
Class
<?>
exp
=
newType
.
returnType
();
Class
<?>
ret
=
oldType
.
returnType
();
if
(!
VerifyType
.
isNullConversion
(
ret
,
exp
))
return
false
;
if
(!
VerifyType
.
isNullConversion
(
ret
,
exp
))
{
if
(!
convOpSupported
(
OP_COLLECT_ARGS
))
return
false
;
if
(!
canConvertArgument
(
ret
,
exp
,
level
))
return
false
;
}
// Check args pairwise.
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
dst
=
oldType
.
parameterType
(
i
);
// destination type
if
(!
canConvertArgument
(
src
,
dst
))
if
(!
canConvertArgument
(
src
,
dst
,
level
))
return
false
;
}
...
...
@@ -87,11 +94,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
/** Can a JVM-level adapter directly implement the proposed
* 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,
// so we don't need to repeat so much decision making.
if
(
VerifyType
.
isNullConversion
(
src
,
dst
))
{
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
())
{
if
(
dst
.
isPrimitive
())
return
canPrimCast
(
src
,
dst
);
...
...
@@ -99,7 +109,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
canBoxArgument
(
src
,
dst
);
}
else
{
if
(
dst
.
isPrimitive
())
return
canUnboxArgument
(
src
,
dst
);
return
canUnboxArgument
(
src
,
dst
,
level
);
else
return
true
;
// any two refs can be interconverted
}
...
...
@@ -109,21 +119,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
* Create a JVM-level adapter method handle to conform the given method
* handle to the similar newType, using only pairwise argument conversions.
* For each argument, convert incoming argument to the exact type needed.
* Only null conversions are allowed on the return value (until
* the JVM supports ricochet adapters).
* The argument conversions allowed are casting, unboxing,
* The argument conversions allowed are casting, boxing and unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
* @param newType required call type
* @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,
* or the original target if the types are already identical
* or null if the adaptation cannot be made
*/
static
MethodHandle
makePairwiseConvert
(
MethodType
newType
,
MethodHandle
target
)
{
static
MethodHandle
makePairwiseConvert
(
MethodType
newType
,
MethodHandle
target
,
int
level
)
{
MethodType
oldType
=
target
.
type
();
if
(
newType
==
oldType
)
return
target
;
if
(!
canPairwiseConvert
(
newType
,
oldType
))
if
(!
canPairwiseConvert
(
newType
,
oldType
,
level
))
return
null
;
// (after this point, it is an assertion error to fail to convert)
...
...
@@ -138,9 +147,14 @@ class AdapterMethodHandle extends BoundMethodHandle {
break
;
}
}
Class
<?>
needReturn
=
newType
.
returnType
();
Class
<?>
haveReturn
=
oldType
.
returnType
();
boolean
retConv
=
!
VerifyType
.
isNullConversion
(
haveReturn
,
needReturn
);
// Now build a chain of one or more adapters.
MethodHandle
adapter
=
target
;
MethodType
midType
=
oldType
.
changeReturnType
(
newType
.
returnType
())
;
MethodHandle
adapter
=
target
,
adapter2
;
MethodType
midType
=
oldType
;
for
(
int
i
=
0
;
i
<=
lastConv
;
i
++)
{
Class
<?>
src
=
newType
.
parameterType
(
i
);
// source type
Class
<?>
dst
=
midType
.
parameterType
(
i
);
// destination type
...
...
@@ -149,22 +163,23 @@ class AdapterMethodHandle extends BoundMethodHandle {
continue
;
}
// Work the current type backward toward the desired caller type:
if
(
i
!=
lastConv
)
{
midType
=
midType
.
changeParameterType
(
i
,
src
);
}
else
{
midType
=
midType
.
changeParameterType
(
i
,
src
);
if
(
i
==
lastConv
)
{
// When doing the last (or only) real conversion,
// force all remaining null conversions to happen also.
assert
(
VerifyType
.
isNullConversion
(
newType
,
midType
.
changeParameterType
(
i
,
src
)));
midType
=
newType
;
MethodType
lastMidType
=
newType
;
if
(
retConv
)
lastMidType
=
lastMidType
.
changeReturnType
(
haveReturn
);
assert
(
VerifyType
.
isNullConversion
(
lastMidType
,
midType
));
midType
=
lastMidType
;
}
// Tricky case analysis follows.
// It parallels canConvertArgument() above.
if
(
src
.
isPrimitive
())
{
if
(
dst
.
isPrimitive
())
{
adapter
=
makePrimCast
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makePrimCast
(
midType
,
adapter
,
i
,
dst
);
}
else
{
adapter
=
makeBoxArgument
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeBoxArgument
(
midType
,
adapter
,
i
,
src
);
}
}
else
{
if
(
dst
.
isPrimitive
())
{
...
...
@@ -174,29 +189,53 @@ class AdapterMethodHandle extends BoundMethodHandle {
// conversions supported by reflect.Method.invoke.
// Those conversions require a big nest of if/then/else logic,
// which we prefer to make a user responsibility.
adapter
=
makeUnboxArgument
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeUnboxArgument
(
midType
,
adapter
,
i
,
dst
,
level
);
}
else
{
// Simple reference conversion.
// Note: Do not check for a class hierarchy relation
// between src and dst. In all cases a 'null' argument
// will pass the cast conversion.
adapter
=
makeCheckCast
(
midType
,
adapter
,
i
,
dst
);
adapter
2
=
makeCheckCast
(
midType
,
adapter
,
i
,
dst
);
}
}
assert
(
adapter
!=
null
);
assert
(
adapter
.
type
()
==
midType
);
assert
(
adapter2
!=
null
)
:
Arrays
.
asList
(
src
,
dst
,
midType
,
adapter
,
i
,
target
,
newType
);
assert
(
adapter2
.
type
()
==
midType
);
adapter
=
adapter2
;
}
if
(
retConv
)
{
adapter2
=
makeReturnConversion
(
adapter
,
haveReturn
,
needReturn
);
assert
(
adapter2
!=
null
);
adapter
=
adapter2
;
}
if
(
adapter
.
type
()
!=
newType
)
{
// Only trivial conversions remain.
adapter
=
makeRetypeOnly
(
newType
,
adapter
);
assert
(
adapter
!=
null
);
adapter2
=
makeRetypeOnly
(
newType
,
adapter
);
assert
(
adapter2
!=
null
);
adapter
=
adapter2
;
// Actually, that's because there were no non-trivial ones:
assert
(
lastConv
==
-
1
);
assert
(
lastConv
==
-
1
||
retConv
);
}
assert
(
adapter
.
type
()
==
newType
);
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
* of the given method.
...
...
@@ -224,7 +263,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(
argumentMap
.
length
!=
oldType
.
parameterCount
())
throw
newIllegalArgumentException
(
"bad permutation: "
+
Arrays
.
toString
(
argumentMap
));
if
(
nullPermutation
)
{
MethodHandle
res
=
makePairwiseConvert
(
newType
,
target
);
MethodHandle
res
=
makePairwiseConvert
(
newType
,
target
,
0
);
// well, that was easy
if
(
res
==
null
)
throw
newIllegalArgumentException
(
"cannot convert pairwise: "
+
newType
);
...
...
@@ -310,11 +349,25 @@ class AdapterMethodHandle extends BoundMethodHandle {
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. */
private
static
long
makeConv
(
int
convOp
,
int
argnum
,
int
src
,
int
dest
)
{
assert
(
src
==
(
src
&
0xF
));
assert
(
dest
==
(
dest
&
0xF
));
assert
(
convOp
>=
OP_CHECK_CAST
&&
convOp
<=
OP_PRIM_TO_REF
);
assert
(
src
==
(
src
&
CONV_TYPE_MASK
));
assert
(
dest
==
(
dest
&
CONV_TYPE_MASK
));
assert
(
convOp
>=
OP_CHECK_CAST
&&
convOp
<=
OP_PRIM_TO_REF
||
convOp
==
OP_COLLECT_ARGS
);
int
stackMove
=
type2size
(
dest
)
-
type2size
(
src
);
return
((
long
)
argnum
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
...
...
@@ -323,11 +376,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
insertStackMove
(
stackMove
)
);
}
private
static
long
makeConv
(
int
convOp
,
int
argnum
,
int
stackMove
)
{
assert
(
convOp
>=
OP_DUP_ARGS
&&
convOp
<=
OP_SPREAD_ARGS
);
private
static
long
makeDupConv
(
int
convOp
,
int
argnum
,
int
stackMove
)
{
// simple argument motion, requiring one slot to specify
assert
(
convOp
==
OP_DUP_ARGS
||
convOp
==
OP_DROP_ARGS
);
byte
src
=
0
,
dest
=
0
;
if
(
convOp
>=
OP_COLLECT_ARGS
&&
convOp
<=
OP_SPREAD_ARGS
)
src
=
dest
=
T_OBJECT
;
return
((
long
)
argnum
<<
32
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
int
)
src
<<
CONV_SRC_TYPE_SHIFT
|
...
...
@@ -336,7 +388,8 @@ class AdapterMethodHandle extends BoundMethodHandle {
);
}
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
|
(
long
)
convOp
<<
CONV_OP_SHIFT
|
(
int
)
type
<<
CONV_SRC_TYPE_SHIFT
|
...
...
@@ -344,6 +397,18 @@ class AdapterMethodHandle extends BoundMethodHandle {
(
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
)
{
assert
(
convOp
==
OP_RETYPE_ONLY
||
convOp
==
OP_RETYPE_RAW
);
return
((
long
)-
1
<<
32
)
|
(
convOp
<<
CONV_OP_SHIFT
);
// stackMove, src, dst all zero
...
...
@@ -570,14 +635,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
static
boolean
canPrimCast
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
||
!
src
.
isPrimitive
()
||
!
dst
.
isPrimitive
())
{
return
false
;
}
else
if
(
Wrapper
.
forPrimitiveType
(
dst
).
isFloating
())
{
// both must be floating types
return
Wrapper
.
forPrimitiveType
(
src
).
isFloating
();
}
else
{
// both are integral, and all combinations work fine
assert
(
Wrapper
.
forPrimitiveType
(
src
).
isIntegral
()
&&
Wrapper
.
forPrimitiveType
(
dst
).
isIntegral
());
return
true
;
boolean
sflt
=
Wrapper
.
forPrimitiveType
(
src
).
isFloating
();
boolean
dflt
=
Wrapper
.
forPrimitiveType
(
dst
).
isFloating
();
return
!(
sflt
|
dflt
);
// no float support at present
}
}
...
...
@@ -589,6 +650,29 @@ class AdapterMethodHandle extends BoundMethodHandle {
*/
static
MethodHandle
makePrimCast
(
MethodType
newType
,
MethodHandle
target
,
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
();
if
(!
canPrimCast
(
newType
,
oldType
,
arg
,
convType
))
return
null
;
...
...
@@ -602,7 +686,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
* The convType is the unboxed type; it can be either a primitive or wrapper.
*/
static
boolean
canUnboxArgument
(
MethodType
newType
,
MethodType
targetType
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
,
int
level
)
{
if
(!
convOpSupported
(
OP_REF_TO_PRIM
))
return
false
;
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
targetType
.
parameterType
(
arg
);
...
...
@@ -616,21 +700,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
(
diff
==
arg
+
1
);
// arg is sole non-trivial diff
}
/** Can an primitive unboxing adapter validly convert src to dst? */
static
boolean
canUnboxArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
return
(!
src
.
isPrimitive
()
&&
Wrapper
.
asPrimitiveType
(
dst
).
isPrimitive
());
static
boolean
canUnboxArgument
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
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.
* Return null if this cannot be done.
*/
static
MethodHandle
makeUnboxArgument
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
int
arg
,
Class
<?>
convType
,
int
level
)
{
MethodType
oldType
=
target
.
type
();
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
oldType
.
parameterType
(
arg
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
Class
<?>
primType
=
Wrapper
.
asPrimitiveType
(
convType
);
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
))
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
,
level
))
return
null
;
MethodType
castDone
=
newType
;
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
...
...
@@ -642,19 +736,46 @@ class AdapterMethodHandle extends BoundMethodHandle {
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? */
static
boolean
canBoxArgument
(
Class
<?>
src
,
Class
<?>
dst
)
{
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.
*/
static
MethodHandle
makeBoxArgument
(
MethodType
newType
,
MethodHandle
target
,
int
arg
,
Class
<?>
convType
)
{
// this is difficult to do in the JVM because it must GC
return
null
;
MethodType
oldType
=
target
.
type
();
Class
<?>
src
=
newType
.
parameterType
(
arg
);
Class
<?>
dst
=
oldType
.
parameterType
(
arg
);
Class
<?>
boxType
=
Wrapper
.
asWrapperType
(
convType
);
Class
<?>
primType
=
Wrapper
.
asPrimitiveType
(
convType
);
if
(!
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? */
...
...
@@ -699,7 +820,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int
slotCount
=
keep1InSlot
-
dropSlot
;
assert
(
slotCount
>=
dropArgCount
);
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
);
}
...
...
@@ -739,7 +860,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int
keep1InSlot
=
newType
.
parameterSlotDepth
(
dupArgPos
);
int
slotCount
=
keep1InSlot
-
dupSlot
;
assert
(
target
.
type
().
parameterSlotCount
()
-
slotCount
==
newType
.
parameterSlotCount
());
long
conv
=
makeConv
(
OP_DUP_ARGS
,
dupArgPos
+
dupArgCount
-
1
,
slotCount
);
long
conv
=
make
Dup
Conv
(
OP_DUP_ARGS
,
dupArgPos
+
dupArgCount
-
1
,
slotCount
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
}
...
...
@@ -900,7 +1021,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
for
(
int
i
=
0
;
i
<
spreadArgCount
;
i
++)
{
Class
<?>
src
=
VerifyType
.
spreadArgElementType
(
spreadArgType
,
i
);
Class
<?>
dst
=
targetType
.
parameterType
(
spreadArgPos
+
i
);
if
(
src
==
null
||
!
VerifyType
.
isNullConversion
(
src
,
dst
))
if
(
src
==
null
||
!
canConvertArgument
(
src
,
dst
,
1
))
return
false
;
}
return
true
;
...
...
@@ -910,24 +1031,100 @@ class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Spread selected argument. */
static
MethodHandle
makeSpreadArguments
(
MethodType
newType
,
MethodHandle
target
,
Class
<?>
spreadArgType
,
int
spreadArgPos
,
int
spreadArgCount
)
{
// FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
MethodType
targetType
=
target
.
type
();
if
(!
canSpreadArguments
(
newType
,
targetType
,
spreadArgType
,
spreadArgPos
,
spreadArgCount
))
return
null
;
// 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... ]
// out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
int
keep2OutPos
=
spreadArgPos
+
spreadArgCount
;
int
spreadSlot
=
targetType
.
parameterSlotDepth
(
keep2OutPos
);
int
keep1OutSlot
=
targetType
.
parameterSlotDepth
(
spreadArgPos
);
int
slotCount
=
keep1OutSlot
-
spreadSlot
;
assert
(
spreadSlot
==
newType
.
parameterSlotDepth
(
spreadArgPos
+
1
));
int
keep1OutSlot
=
targetType
.
parameterSlotDepth
(
spreadArgPos
);
// leading edge of |spread...|
int
spreadSlot
=
targetType
.
parameterSlotDepth
(
keep2OutPos
);
// trailing edge of |spread...|
assert
(
spreadSlot
==
newType
.
parameterSlotDepth
(
spreadArgPos
+
arrayArgSize
))
;
int
slotCount
=
keep1OutSlot
-
spreadSlot
;
// slots in |spread...|
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
);
assert
(
res
.
type
().
parameterType
(
spreadArgPos
)
==
spreadArgType
);
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
public
String
toString
()
{
...
...
src/share/classes/java/lang/invoke/CallSite.java
浏览文件 @
8c50098c
...
...
@@ -273,9 +273,9 @@ public class CallSite {
Object
binding
;
info
=
maybeReBox
(
info
);
if
(
info
==
null
)
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
);
}
else
if
(!
info
.
getClass
().
isArray
())
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
,
info
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
,
info
);
}
else
{
Object
[]
argv
=
(
Object
[])
info
;
maybeReBoxElements
(
argv
);
...
...
@@ -283,10 +283,10 @@ public class CallSite {
throw
new
BootstrapMethodError
(
"too many bootstrap method arguments"
);
MethodType
bsmType
=
bootstrapMethod
.
type
();
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
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);
if
(
binding
instanceof
CallSite
)
{
...
...
src/share/classes/java/lang/invoke/FilterGeneric.java
浏览文件 @
8c50098c
...
...
@@ -61,6 +61,10 @@ class FilterGeneric {
return
ad
;
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
Adapter
makeInstance
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
Adapter
ad
=
getAdapter
(
kind
,
pos
);
return
ad
.
makeInstance
(
ad
.
prototypeEntryPoint
(),
filter
,
target
);
...
...
src/share/classes/java/lang/invoke/FilterOneArgument.java
浏览文件 @
8c50098c
...
...
@@ -67,6 +67,10 @@ class FilterOneArgument extends BoundMethodHandle {
this
.
target
=
target
;
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
public
static
MethodHandle
make
(
MethodHandle
filter
,
MethodHandle
target
)
{
if
(
filter
==
null
)
return
target
;
if
(
target
==
null
)
return
filter
;
...
...
src/share/classes/java/lang/invoke/FromGeneric.java
浏览文件 @
8c50098c
...
...
@@ -98,6 +98,10 @@ class FromGeneric {
this
.
unboxingInvoker
=
computeUnboxingInvoker
(
targetType
,
internalType0
);
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/**
* The typed target will be called according to targetType.
* The adapter code will in fact see the raw result from internalType,
...
...
@@ -112,10 +116,10 @@ class FromGeneric {
assert
(
iret
==
Object
.
class
);
return
ValueConversions
.
identity
();
}
else
if
(
wrap
.
primitiveType
()
==
iret
)
{
return
ValueConversions
.
box
(
wrap
,
false
);
return
ValueConversions
.
box
(
wrap
);
}
else
{
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 {
MethodType
fixArgsType
=
internalType
.
changeReturnType
(
targetType
.
returnType
());
MethodHandle
fixArgs
=
MethodHandleImpl
.
convertArguments
(
invoker
,
Invokers
.
invokerType
(
fixArgsType
),
invoker
.
type
(),
null
);
invoker
.
type
(),
0
);
if
(
fixArgs
==
null
)
throw
new
InternalError
(
"bad fixArgs"
);
// reinterpret the calling sequence as raw:
...
...
@@ -160,7 +164,6 @@ class FromGeneric {
/** Build an adapter of the given generic type, which invokes typedTarget
* on the incoming arguments, after unboxing as necessary.
* The return value is boxed if necessary.
* @param genericType the required type of the result
* @param typedTarget the target
* @return an adapter method handle
*/
...
...
@@ -231,7 +234,7 @@ class FromGeneric {
}
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.*;
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.
* @author jrose
*/
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
;
// an invoker of type (MT, MH; A...) -> R
private
final
MethodHandle
initialInvoker
;
...
...
@@ -56,7 +56,7 @@ class InvokeGeneric {
}
/** 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
);
return
gen
.
initialInvoker
;
}
...
...
src/share/classes/java/lang/invoke/Invokers.java
浏览文件 @
8c50098c
...
...
@@ -43,10 +43,10 @@ class Invokers {
private
/*lazy*/
MethodHandle
erasedInvoker
;
/*lazy*/
MethodHandle
erasedInvokerWithDrops
;
// for InvokeGeneric
// gener
ic (untyped)
invoker for the outgoing call
private
/*lazy*/
MethodHandle
gener
ic
Invoker
;
// gener
al
invoker for the outgoing call
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
;
// invoker for an unbound callsite
...
...
@@ -77,13 +77,13 @@ class Invokers {
return
invoker
;
}
/*non-public*/
MethodHandle
gener
ic
Invoker
()
{
/*non-public*/
MethodHandle
gener
al
Invoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker
=
gener
ic
Invoker
;
MethodHandle
invoker
=
gener
al
Invoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
gener
ic
Type
=
targetType
.
generic
();
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
generic
Type
));
gener
ic
Invoker
=
invoker
;
MethodType
gener
al
Type
=
targetType
.
generic
();
invoker
=
invoker1
.
asType
(
invokerType
(
general
Type
));
gener
al
Invoker
=
invoker
;
return
invoker
;
}
...
...
@@ -93,9 +93,9 @@ class Invokers {
if
(
invoker
!=
null
)
return
invoker
;
MethodType
erasedType
=
targetType
.
erase
();
if
(
erasedType
==
targetType
.
generic
())
invoker
=
gener
ic
Invoker
();
invoker
=
gener
al
Invoker
();
else
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
erasedType
));
invoker
=
invoker1
.
asType
(
invokerType
(
erasedType
));
erasedInvoker
=
invoker
;
return
invoker
;
}
...
...
@@ -103,7 +103,7 @@ class Invokers {
/*non-public*/
MethodHandle
spreadInvoker
(
int
objectArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
objectArgCount
];
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
MethodHandle
gInvoker
=
gener
ic
Invoker
();
MethodHandle
gInvoker
=
gener
al
Invoker
();
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
return
vaInvoker
;
...
...
src/share/classes/java/lang/invoke/MemberName.java
浏览文件 @
8c50098c
...
...
@@ -525,7 +525,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
*/
public
static
class
Factory
{
/*non-public*/
static
class
Factory
{
private
Factory
()
{
}
// singleton pattern
static
Factory
INSTANCE
=
new
Factory
();
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
8c50098c
...
...
@@ -26,6 +26,7 @@
package
java.lang.invoke
;
import
sun.invoke.util.ValueConversions
;
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.
* <p>
* 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
* underlying method, constructor, field, or other operation,
* as modified by transformations of arguments and return values.
* Both invokers accept calls which exactly match the method handle's own type.
* The
{@code invokeGeneric}
invoker also accepts a range of other call types.
* The
plain, inexact
invoker also accepts a range of other call types.
* <p>
* Method handles are immutable and have no visible 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.*;
* may change from time to time or across implementations from different vendors.
*
* <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.
* From the viewpoint of source code, these methods can take any arguments
* and their result can be cast to any return type.
...
...
@@ -86,7 +87,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* which connects this freedom of invocation directly to the JVM execution stack.
* <p>
* 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,
* and may not perform method invocation conversions on the arguments.
* Instead, it must push them on the stack according to their own unconverted types.
...
...
@@ -109,7 +110,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* The first time a {@code invokevirtual} instruction is executed
* it is linked, by symbolically resolving the names in the instruction
* and verifying that the method call is statically legal.
* This is true of calls to {@code invokeExact} and {@code 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
* correct syntax and names it contains are resolved.
* Thus, an {@code invokevirtual} instruction which invokes
...
...
@@ -127,18 +128,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
* In the case of {@code invokeExact}, the type descriptor of the invocation
* (after resolving symbolic type names) must exactly match the method type
* of the receiving method handle.
* In the case of
{@code invokeGeneric
}, the resolved type descriptor
* 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.
* Thus,
{@code invokeGeneric
} is more permissive than {@code invokeExact}.
* Thus,
plain {@code invoke
} is more permissive than {@code invokeExact}.
* <p>
* After type matching, a call to {@code invokeExact} directly
* and immediately invoke the method handle's underlying method
* (or other behavior, as the case may be).
* <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
* 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,
* as if by a call to {@link #asType asType},
* to obtain an exactly invokable method handle {@code M2}.
...
...
@@ -152,7 +153,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* In typical programs, method handle type matching will usually succeed.
* But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
* either directly (in the case of {@code invokeExact}) or indirectly as if
* by a failed call to {@code asType} (in the case of {@code invoke
Generic
}).
* by a failed call to {@code asType} (in the case of {@code invoke}).
* <p>
* Thus, a method type mismatch which might show up as a linkage error
* in a statically typed program can show up as
...
...
@@ -249,8 +250,8 @@ assert(s.equals("savvy"));
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke
Generic
("one", "two");
// invoke
Generic
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert(x.equals(java.util.Arrays.asList("one","two")));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
...
...
@@ -269,12 +270,12 @@ mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
* </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
* the type descriptor indicated in the following comment.
*
* <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},
* 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
...
...
@@ -288,7 +289,7 @@ mh.invokeExact(System.out, "Hello, world.");
*
* <h3><a name="sigpoly"></a>Signature polymorphism</h3>
* 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>.
* A signature polymorphic method is one which can operate with
* any of a wide range of call signatures and return types.
...
...
@@ -322,7 +323,7 @@ mh.invokeExact(System.out, "Hello, world.");
* The following methods (and no others) are signature polymorphic:
* <ul>
* <li>{@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.lang.invoke.MethodHandle#invoke
Generic MethodHandle.invokeGeneric
}
* <li>{@link java.lang.invoke.MethodHandle#invoke
MethodHandle.invoke
}
* </ul>
* <p>
* A signature polymorphic method will be declared with the following properties:
...
...
@@ -374,24 +375,34 @@ mh.invokeExact(System.out, "Hello, world.");
* <p>
* As a special case,
* when the Core Reflection API is used to view the signature polymorphic
* methods {@code invokeExact} or {@code invokeGeneric} in this class,
* they appear as single, non-polymorphic native methods.
* Calls to these native methods do not result in method handle invocations.
* methods {@code invokeExact} or plain {@code invoke} in this class,
* they appear as ordinary non-polymorphic methods.
* 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
* invoke method handles under any type descriptor, this reflective view conflicts
* with the normal presentation via bytecodes.
* Thus, these two native methods, as viewed by
* {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
* are placeholders only.
* If invoked via {@link java.lang.reflect.Method#invoke Method.invoke},
* they will throw {@code UnsupportedOperationException}.
* with the normal presentation of these methods via bytecodes.
* Thus, these two native methods, when reflectively viewed by
* {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
* <p>
* In order to obtain an invoker method for a particular type descriptor,
* use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
* or {@link java.lang.invoke.MethodHandles#
genericInvoker MethodHandles.genericI
nvoker}.
* or {@link java.lang.invoke.MethodHandles#
invoker MethodHandles.i
nvoker}.
* The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* API is also able to return a method handle
* to call {@code invokeExact} or
{@code invokeGeneric
},
* to call {@code invokeExact} or
plain {@code invoke
},
* for any specified type descriptor .
*
* <h3>Interoperation between method handles and Java generics</h3>
...
...
@@ -523,7 +534,7 @@ public abstract class MethodHandle {
* adaptations directly on the caller's arguments,
* and call the target method handle according to its own exact type.
* <p>
* The type descriptor at the call site of {@code invoke
Generic
} must
* The type descriptor at the call site of {@code invoke} must
* be a valid argument to the receivers {@code asType} method.
* In particular, the caller must specify the same argument arity
* as the callee's type,
...
...
@@ -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 Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
public
final
native
@PolymorphicSignature
Object
invoke
(
Object
...
args
)
throws
Throwable
;
/**
* <em>Temporary alias</em> for {@link #invoke}, for backward compatibility with some versions of JSR 292.
* On some JVMs, support can be excluded by the flags {@code -XX:+UnlockExperimentalVMOptions -XX:-AllowInvokeGeneric}.
* @deprecated Will be removed for JSR 292 Proposed Final Draft.
*/
public
final
native
@PolymorphicSignature
Object
invokeGeneric
(
Object
...
args
)
throws
Throwable
;
/**
* Performs a varargs invocation, passing the arguments in the given array
* 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
* of the argument array.
* <p>
...
...
@@ -553,7 +571,7 @@ public abstract class MethodHandle {
* <ul>
* <li>Determine the length of the argument array as {@code N}.
* 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>
* <li>Force the original target method handle {@code MH0} to the
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
...
...
@@ -580,7 +598,7 @@ public abstract class MethodHandle {
* Object result = invoker.invokeExact(this, arguments);
* </pre></blockquote>
* <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.
* It can therefore be used as a bridge between native or reflective code and method handles.
*
...
...
@@ -595,11 +613,11 @@ public abstract class MethodHandle {
int
argc
=
arguments
==
null
?
0
:
arguments
.
length
;
MethodType
type
=
type
();
if
(
type
.
parameterCount
()
!=
argc
)
{
// simulate invoke
Generic
// simulate invoke
return
asType
(
MethodType
.
genericMethodType
(
argc
)).
invokeWithArguments
(
arguments
);
}
if
(
argc
<=
10
)
{
MethodHandle
invoker
=
type
.
invokers
().
gener
ic
Invoker
();
MethodHandle
invoker
=
type
.
invokers
().
gener
al
Invoker
();
switch
(
argc
)
{
case
0
:
return
invoker
.
invokeExact
(
this
);
case
1
:
return
invoker
.
invokeExact
(
this
,
...
...
@@ -644,7 +662,7 @@ public abstract class MethodHandle {
/**
* 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
* of the argument array.
* <p>
...
...
@@ -672,9 +690,9 @@ public abstract class MethodHandle {
* If the original type and new type are equal, returns {@code this}.
* <p>
* 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
* 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
* to match up the caller's and callee's types.
* <p>
...
...
@@ -689,6 +707,9 @@ public abstract class MethodHandle {
* @see MethodHandles#convertArguments
*/
public
MethodHandle
asType
(
MethodType
newType
)
{
if
(!
type
.
isConvertibleTo
(
newType
))
{
throw
new
WrongMethodTypeException
(
"cannot convert "
+
type
+
" to "
+
newType
);
}
return
MethodHandles
.
convertArguments
(
this
,
newType
);
}
...
...
@@ -731,13 +752,9 @@ public abstract class MethodHandle {
public
MethodHandle
asSpreader
(
Class
<?>
arrayType
,
int
arrayLength
)
{
Class
<?>
arrayElement
=
arrayType
.
getComponentType
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
MethodType
oldType
=
type
();
int
nargs
=
oldType
.
parameterCount
();
int
nargs
=
type
().
parameterCount
();
if
(
nargs
<
arrayLength
)
throw
newIllegalArgumentException
(
"bad spread array length"
);
int
keepPosArgs
=
nargs
-
arrayLength
;
MethodType
newType
=
oldType
.
dropParameterTypes
(
keepPosArgs
,
nargs
);
newType
=
newType
.
insertParameterTypes
(
keepPosArgs
,
arrayType
);
return
MethodHandles
.
spreadArguments
(
this
,
newType
);
return
MethodHandleImpl
.
spreadArguments
(
this
,
arrayType
,
arrayLength
);
}
/**
...
...
@@ -780,15 +797,18 @@ public abstract class MethodHandle {
* @see #asVarargsCollector
*/
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
();
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
);
MethodType
oldType
=
type
();
int
nargs
=
oldType
.
parameterCount
();
if
(
nargs
==
0
)
throw
newIllegalArgumentException
(
"no trailing argument"
);
MethodType
newType
=
oldType
.
dropParameterTypes
(
nargs
-
1
,
nargs
);
newType
=
newType
.
insertParameterTypes
(
nargs
-
1
,
java
.
util
.
Collections
.<
Class
<?>>
nCopies
(
arrayLength
,
arrayElement
));
return
MethodHandles
.
collectArguments
(
this
,
newType
);
if
(
arrayElement
==
null
)
throw
newIllegalArgumentException
(
"not an array type"
,
arrayType
);
int
nargs
=
type
().
parameterCount
();
if
(
nargs
==
0
||
!
type
().
parameterType
(
nargs
-
1
).
isAssignableFrom
(
arrayType
))
throw
newIllegalArgumentException
(
"array type not assignable to trailing argument"
,
this
,
arrayType
);
}
/**
...
...
@@ -798,7 +818,7 @@ public abstract class MethodHandle {
* <p>
* The type and behavior of the adapter will be the same as
* 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 parameter.
* Also, the last parameter type of the adapter will be
...
...
@@ -812,17 +832,17 @@ public abstract class MethodHandle {
* since it accepts a whole array of indeterminate length,
* rather than a fixed number of arguments.)
* <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
* {@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>
* Otherwise, if the caller and adapter arity are the same, and the
* trailing parameter type of the caller is a reference type identical to
* or assignable to the trailing parameter type of the adapter,
* the arguments and return values are converted pairwise,
* as if by {@link MethodHandles#convertArguments convertArguments}.
* (This is also normal behavior for {@code invoke
Generic
} in such a case.)
* (This is also normal behavior for {@code invoke} in such a case.)
* <p>
* Otherwise, the arities differ, or the adapter's trailing parameter
* type is not assignable from the corresponding caller type.
...
...
@@ -838,7 +858,7 @@ public abstract class MethodHandle {
* where {@code N} is the arity of the target.
* Also, there must exist conversions from the incoming arguments
* to the target's arguments.
* As with other uses of
{@code invokeGeneric
}, if these basic
* As with other uses of
plain {@code invoke
}, if these basic
* requirements are not fulfilled, a {@code WrongMethodTypeException}
* may be thrown.
* <p>
...
...
@@ -856,7 +876,7 @@ public abstract class MethodHandle {
* <p>
* The behavior of {@link #asType asType} is also specialized for
* variable arity adapters, to maintain the invariant that
*
{@code invokeGeneric
} is always equivalent to an {@code asType}
*
plain, inexact {@code invoke
} is always equivalent to an {@code asType}
* call to adjust the target type, followed by {@code invokeExact}.
* Therefore, a variable arity adapter responds
* to an {@code asType} request by building a fixed arity collector,
...
...
@@ -893,12 +913,12 @@ public abstract class MethodHandle {
MethodHandle asList = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
assertEquals("[]", asList.invoke
Generic
().toString());
assertEquals("[1]", asList.invoke
Generic
(1).toString());
assertEquals("[two, too]", asList.invoke
Generic
("two", "too").toString());
assertEquals("[]", asList.invoke().toString());
assertEquals("[1]", asList.invoke(1).toString());
assertEquals("[two, too]", asList.invoke("two", "too").toString());
Object[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asList.invoke
Generic
(argv).toString());
List ls = (List) asList.invoke
Generic
((Object)argv);
assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
List ls = (List) asList.invoke((Object)argv);
assertEquals(1, ls.size());
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
* </pre></blockquote>
...
...
@@ -926,9 +946,9 @@ MethodHandle vamh = publicLookup()
.asVarargsCollector(Object[].class);
MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
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;
try { mh.invoke
Generic
(1,2,3); }
try { mh.invoke(1,2,3); }
catch (WrongMethodTypeException ex) { failed = true; }
assert(failed);
* </pre></blockquote>
...
...
@@ -960,7 +980,7 @@ assert(failed);
* <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
* which resolves to a variable arity Java method or constructor
* </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
*/
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;
if
(
nargs
<
INVOKES
.
length
)
{
MethodHandle
invoke
=
INVOKES
[
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
;
MethodHandle
galloc
=
new
AllocateObject
(
invoke
,
allocateClass
,
gcon
);
assert
(
galloc
.
type
()
==
newType
.
generic
());
return
convertArguments
(
galloc
,
newType
,
galloc
.
type
(),
null
);
return
convertArguments
(
galloc
,
newType
,
galloc
.
type
(),
0
);
}
else
{
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
conType
=
CON_TYPES
[
nargs
];
...
...
@@ -256,8 +256,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
FieldAccessor
.
ahandle
(
arrayClass
,
true
)
};
if
(
mhs
[
0
].
type
().
parameterType
(
0
)
==
Class
.
class
)
{
mhs
[
0
]
=
MethodHandles
.
insertArguments
(
mhs
[
0
],
0
,
elemClass
);
mhs
[
1
]
=
MethodHandles
.
insertArguments
(
mhs
[
1
],
0
,
elemClass
);
mhs
[
0
]
=
mhs
[
0
].
bindTo
(
elemClass
);
mhs
[
1
]
=
mhs
[
1
].
bindTo
(
elemClass
);
}
synchronized
(
FieldAccessor
.
ARRAY_CACHE
)
{}
// memory barrier
FieldAccessor
.
ARRAY_CACHE
.
put
(
elemClass
,
mhs
);
...
...
@@ -372,7 +372,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
evclass
!=
vclass
||
(!
isStatic
&&
ecclass
!=
cclass
))
{
MethodType
strongType
=
FieldAccessor
.
ftype
(
cclass
,
vclass
,
isSetter
,
isStatic
);
strongType
=
strongType
.
insertParameterTypes
(
0
,
FieldAccessor
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
strongType
);
mh
=
convertArguments
(
mh
,
strongType
,
0
);
}
return
mh
;
}
...
...
@@ -439,8 +439,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
if
(
caclass
!=
null
)
{
MethodType
strongType
=
FieldAccessor
.
atype
(
caclass
,
isSetter
);
mh
=
MethodHandles
.
insertArguments
(
mh
,
0
,
caclass
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
strongType
);
mh
=
mh
.
bindTo
(
caclass
);
mh
=
convertArguments
(
mh
,
strongType
,
0
);
}
return
mh
;
}
...
...
@@ -465,7 +465,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
dmh
.
type
().
parameterType
(
0
).
isAssignableFrom
(
receiver
.
getClass
()))
{
MethodHandle
bmh
=
new
BoundMethodHandle
(
dmh
,
receiver
,
0
);
MethodType
newType
=
target
.
type
().
dropParameterTypes
(
0
,
1
);
return
convertArguments
(
bmh
,
newType
,
bmh
.
type
(),
null
);
return
convertArguments
(
bmh
,
newType
,
bmh
.
type
(),
0
);
}
}
}
...
...
@@ -486,301 +486,378 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return
new
BoundMethodHandle
(
target
,
receiver
,
argnum
);
}
static
MethodHandle
convert
Arguments
(
MethodHandle
target
,
static
MethodHandle
permute
Arguments
(
MethodHandle
target
,
MethodType
newType
,
MethodType
oldType
,
int
[]
permutationOrNull
)
{
assert
(
oldType
.
parameterCount
()
==
target
.
type
().
parameterCount
());
if
(
permutationOrNull
!=
null
)
{
int
outargs
=
oldType
.
parameterCount
(),
inargs
=
newType
.
parameterCount
();
if
(
permutationOrNull
.
length
!=
outargs
)
throw
newIllegalArgumentException
(
"wrong number of arguments in permutation"
);
// Make the individual outgoing argument types match up first.
Class
<?>[]
callTypeArgs
=
new
Class
<?>[
outargs
];
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
callTypeArgs
[
i
]
=
newType
.
parameterType
(
permutationOrNull
[
i
]);
MethodType
callType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
callTypeArgs
);
target
=
convertArguments
(
target
,
callType
,
oldType
,
null
);
assert
(
target
!=
null
);
oldType
=
target
.
type
();
List
<
Integer
>
goal
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
state
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
drops
=
new
ArrayList
<
Integer
>();
// not tokens
List
<
Integer
>
dups
=
new
ArrayList
<
Integer
>();
// not tokens
final
int
TOKEN
=
10
;
// to mark items which are symbolic only
// state represents the argument values coming into target
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
{
state
.
add
(
permutationOrNull
[
i
]
*
TOKEN
);
int
outargs
=
oldType
.
parameterCount
(),
inargs
=
newType
.
parameterCount
();
if
(
permutationOrNull
.
length
!=
outargs
)
throw
newIllegalArgumentException
(
"wrong number of arguments in permutation"
);
// Make the individual outgoing argument types match up first.
Class
<?>[]
callTypeArgs
=
new
Class
<?>[
outargs
];
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
callTypeArgs
[
i
]
=
newType
.
parameterType
(
permutationOrNull
[
i
]);
MethodType
callType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
callTypeArgs
);
target
=
convertArguments
(
target
,
callType
,
oldType
,
0
);
assert
(
target
!=
null
);
oldType
=
target
.
type
();
List
<
Integer
>
goal
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
state
=
new
ArrayList
<
Integer
>();
// i*TOKEN
List
<
Integer
>
drops
=
new
ArrayList
<
Integer
>();
// not tokens
List
<
Integer
>
dups
=
new
ArrayList
<
Integer
>();
// not tokens
final
int
TOKEN
=
10
;
// to mark items which are symbolic only
// state represents the argument values coming into target
for
(
int
i
=
0
;
i
<
outargs
;
i
++)
{
state
.
add
(
permutationOrNull
[
i
]
*
TOKEN
);
}
// goal represents the desired state
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
if
(
state
.
contains
(
i
*
TOKEN
))
{
goal
.
add
(
i
*
TOKEN
);
}
else
{
// adapter must initially drop all unused arguments
drops
.
add
(
i
);
}
// goal represents the desired state
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
if
(
state
.
contains
(
i
*
TOKEN
))
{
goal
.
add
(
i
*
TOKEN
);
}
else
{
// adapter must initially drop all unused arguments
drops
.
add
(
i
);
}
// detect duplications
while
(
state
.
size
()
>
goal
.
size
())
{
for
(
int
i2
=
0
;
i2
<
state
.
size
();
i2
++)
{
int
arg1
=
state
.
get
(
i2
);
int
i1
=
state
.
indexOf
(
arg1
);
if
(
i1
!=
i2
)
{
// found duplicate occurrence at i2
int
arg2
=
(
inargs
++)
*
TOKEN
;
state
.
set
(
i2
,
arg2
);
dups
.
add
(
goal
.
indexOf
(
arg1
));
goal
.
add
(
arg2
);
}
}
// detect duplications
while
(
state
.
size
()
>
goal
.
size
())
{
for
(
int
i2
=
0
;
i2
<
state
.
size
();
i2
++)
{
int
arg1
=
state
.
get
(
i2
);
int
i1
=
state
.
indexOf
(
arg1
);
if
(
i1
!=
i2
)
{
// found duplicate occurrence at i2
int
arg2
=
(
inargs
++)
*
TOKEN
;
state
.
set
(
i2
,
arg2
);
dups
.
add
(
goal
.
indexOf
(
arg1
));
goal
.
add
(
arg2
);
}
assert
(
state
.
size
()
==
goal
.
size
());
int
size
=
goal
.
size
();
while
(!
state
.
equals
(
goal
))
{
// Look for a maximal sequence of adjacent misplaced arguments,
// and try to rotate them into place.
int
bestRotArg
=
-
10
*
TOKEN
,
bestRotLen
=
0
;
int
thisRotArg
=
-
10
*
TOKEN
,
thisRotLen
=
0
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
int
arg
=
state
.
get
(
i
);
// Does this argument match the current run?
if
(
arg
==
thisRotArg
+
TOKEN
)
{
thisRotArg
=
arg
;
thisRotLen
+=
1
;
if
(
bestRotLen
<
thisRotLen
)
{
bestRotLen
=
thisRotLen
;
bestRotArg
=
thisRotArg
;
}
}
}
assert
(
state
.
size
()
==
goal
.
size
());
int
size
=
goal
.
size
();
while
(!
state
.
equals
(
goal
))
{
// Look for a maximal sequence of adjacent misplaced arguments,
// and try to rotate them into place.
int
bestRotArg
=
-
10
*
TOKEN
,
bestRotLen
=
0
;
int
thisRotArg
=
-
10
*
TOKEN
,
thisRotLen
=
0
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
int
arg
=
state
.
get
(
i
);
// Does this argument match the current run?
if
(
arg
==
thisRotArg
+
TOKEN
)
{
}
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
<
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
;
}
thisRotLen
=
1
;
}
}
if
(
bestRotLen
>=
2
)
{
// Do a rotation if it can improve argument positioning
// by at least 2 arguments. This is not always optimal,
// but it seems to catch common cases.
int
dstEnd
=
state
.
indexOf
(
bestRotArg
);
int
srcEnd
=
goal
.
indexOf
(
bestRotArg
);
int
rotBy
=
dstEnd
-
srcEnd
;
int
dstBeg
=
dstEnd
-
(
bestRotLen
-
1
);
int
srcBeg
=
srcEnd
-
(
bestRotLen
-
1
);
assert
((
dstEnd
|
dstBeg
|
srcEnd
|
srcBeg
)
>=
0
);
// no negs
// Make a span which covers both source and destination.
int
rotBeg
=
Math
.
min
(
dstBeg
,
srcBeg
);
int
rotEnd
=
Math
.
max
(
dstEnd
,
srcEnd
);
int
score
=
0
;
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
score
+=
1
;
}
List
<
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
);
}
if
(
bestRotLen
>=
2
)
{
// Do a rotation if it can improve argument positioning
// by at least 2 arguments. This is not always optimal,
// but it seems to catch common cases.
int
dstEnd
=
state
.
indexOf
(
bestRotArg
);
int
srcEnd
=
goal
.
indexOf
(
bestRotArg
);
int
rotBy
=
dstEnd
-
srcEnd
;
int
dstBeg
=
dstEnd
-
(
bestRotLen
-
1
);
int
srcBeg
=
srcEnd
-
(
bestRotLen
-
1
);
assert
((
dstEnd
|
dstBeg
|
srcEnd
|
srcBeg
)
>=
0
);
// no negs
// Make a span which covers both source and destination.
int
rotBeg
=
Math
.
min
(
dstBeg
,
srcBeg
);
int
rotEnd
=
Math
.
max
(
dstEnd
,
srcEnd
);
int
score
=
0
;
for
(
int
i
=
rotBeg
;
i
<=
rotEnd
;
i
++)
{
if
((
int
)
state
.
get
(
i
)
!=
(
int
)
goal
.
get
(
i
))
score
+=
1
;
}
// Now swap like the wind!
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
// What argument do I want here?
int
arg
=
goal
.
get
(
i
);
if
(
arg
!=
state
.
get
(
i
))
{
// Where is it now?
int
j
=
state
.
indexOf
(
arg
);
Collections
.
swap
(
ptypes
,
i
,
j
);
MethodType
swapType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeSwapArguments
(
swapType
,
target
,
i
,
j
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot swap"
);
assert
(
target
.
type
()
==
swapType
);
oldType
=
swapType
;
Collections
.
swap
(
state
,
i
,
j
);
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
;
}
}
//
One pass of swapping must finish the job
.
assert
(
state
.
equals
(
goal
)
);
//
Else de-rotate, and drop through to the swap-fest
.
Collections
.
rotate
(
rotSpan
,
rotBy
);
}
while
(!
dups
.
isEmpty
())
{
// Grab a contiguous trailing sequence of dups.
int
grab
=
dups
.
size
()
-
1
;
int
dupArgPos
=
dups
.
get
(
grab
),
dupArgCount
=
1
;
while
(
grab
-
1
>=
0
)
{
int
dup0
=
dups
.
get
(
grab
-
1
);
if
(
dup0
!=
dupArgPos
-
1
)
break
;
dupArgPos
-=
1
;
dupArgCount
+=
1
;
grab
-=
1
;
// Now swap like the wind!
List
<
Class
<?>>
ptypes
=
Arrays
.
asList
(
oldType
.
parameterArray
());
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
// What argument do I want here?
int
arg
=
goal
.
get
(
i
);
if
(
arg
!=
state
.
get
(
i
))
{
// Where is it now?
int
j
=
state
.
indexOf
(
arg
);
Collections
.
swap
(
ptypes
,
i
,
j
);
MethodType
swapType
=
MethodType
.
methodType
(
oldType
.
returnType
(),
ptypes
);
target
=
AdapterMethodHandle
.
makeSwapArguments
(
swapType
,
target
,
i
,
j
);
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot swap"
);
assert
(
target
.
type
()
==
swapType
);
oldType
=
swapType
;
Collections
.
swap
(
state
,
i
,
j
);
}
//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
())
{
// 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
();
// One pass of swapping must finish the job.
assert
(
state
.
equals
(
goal
));
}
while
(!
dups
.
isEmpty
())
{
// Grab a contiguous trailing sequence of dups.
int
grab
=
dups
.
size
()
-
1
;
int
dupArgPos
=
dups
.
get
(
grab
),
dupArgCount
=
1
;
while
(
grab
-
1
>=
0
)
{
int
dup0
=
dups
.
get
(
grab
-
1
);
if
(
dup0
!=
dupArgPos
-
1
)
break
;
dupArgPos
-=
1
;
dupArgCount
+=
1
;
grab
-=
1
;
}
//if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
dups
.
subList
(
grab
,
dups
.
size
()).
clear
();
// In the new target type drop that many args from the tail:
List
<
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
)
return
target
;
if
(
oldType
.
parameterCount
()
!=
newType
.
parameterCount
())
throw
newIllegalArgumentException
(
"mismatched parameter count"
);
MethodHandle
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
target
);
throw
newIllegalArgumentException
(
"mismatched parameter count"
,
oldType
,
newType
);
MethodHandle
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
target
,
level
);
if
(
res
!=
null
)
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
();
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
// The JVM can't do it directly, so fill in the gap with a Java adapter.
// TO DO: figure out what to put here from case-by-case experience
// Use a heavier method: Convert all the arguments to Object,
// then back to the desired types. We might have to use Java-based
// method handles to do this.
MethodType
objType
=
MethodType
.
genericMethodType
(
argc
);
MethodHandle
objTarget
=
AdapterMethodHandle
.
makePairwiseConvert
(
objType
,
target
);
MethodHandle
objTarget
=
AdapterMethodHandle
.
makePairwiseConvert
(
objType
,
target
,
level
);
if
(
objTarget
==
null
)
objTarget
=
FromGeneric
.
make
(
target
);
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
objTarget
);
res
=
AdapterMethodHandle
.
makePairwiseConvert
(
newType
,
objTarget
,
level
);
if
(
res
!=
null
)
return
res
;
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
,
MethodType
newType
,
int
spreadArg
)
{
int
spreadArgPos
,
Class
<?>
arrayType
,
int
arrayLength
)
{
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
MethodType
oldType
=
target
.
type
();
// spread the last argument of newType to oldType
int
spreadCount
=
oldType
.
parameterCount
()
-
spreadArg
;
Class
<
Object
[]>
spreadArgType
=
Object
[].
class
;
MethodHandle
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
spreadArgType
,
spreadArg
,
spreadCount
);
if
(
res
!=
null
)
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
);
assert
(
arrayLength
==
oldType
.
parameterCount
()
-
spreadArgPos
);
assert
(
newType
.
parameterType
(
spreadArgPos
)
==
arrayType
);
MethodHandle
res
=
AdapterMethodHandle
.
makeSpreadArguments
(
newType
,
target
,
arrayType
,
spreadArgPos
,
arrayLength
);
if
(
res
==
null
)
throw
new
IllegalArgumentException
(
"spread on "
+
target
+
" with "
+
arrayType
.
getSimpleName
());
return
res
;
}
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
,
MethodType
newType
,
int
collectArg
,
MethodHandle
collector
)
{
MethodType
oldType
=
target
.
type
();
// (a...,c)=>r
if
(
collector
==
null
)
{
int
numCollect
=
newType
.
parameterCount
()
-
oldType
.
parameterCount
()
+
1
;
collector
=
ValueConversions
.
varargsArray
(
numCollect
);
}
// newType // (a..., b...)=>r
MethodType
colType
=
collector
.
type
();
// (b...)=>c
// oldType // (a..., b...)=>r
assert
(
newType
.
parameterCount
()
==
collectArg
+
colType
.
parameterCount
());
assert
(
oldType
.
parameterCount
()
==
collectArg
+
1
);
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
null
);
MethodHandle
gcollector
=
convertArguments
(
collector
,
colType
.
generic
(),
colType
,
null
);
if
(
gtarget
==
null
||
gcollector
==
null
)
return
null
;
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentCollector
(
gcollector
,
gtarget
);
MethodHandle
result
=
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
null
);
MethodHandle
result
=
null
;
if
(
AdapterMethodHandle
.
canCollectArguments
(
oldType
,
colType
,
collectArg
,
false
))
{
result
=
AdapterMethodHandle
.
makeCollectArguments
(
target
,
collector
,
collectArg
,
false
);
}
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
;
}
static
MethodHandle
filterArgument
(
MethodHandle
target
,
int
pos
,
MethodHandle
filter
)
{
MethodType
ttype
=
target
.
type
(),
gttype
=
ttype
.
generic
();
int
pos
,
MethodHandle
filter
)
{
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
)
{
target
=
convertArguments
(
target
,
gttype
,
ttype
,
null
);
target
=
convertArguments
(
target
,
gttype
,
ttype
,
0
);
ttype
=
gttype
;
}
MethodType
ftype
=
filter
.
type
(),
gftype
=
ftype
.
generic
();
if
(
ftype
.
parameterCount
()
!=
1
)
throw
new
InternalError
();
MethodType
gftype
=
ftype
.
generic
();
if
(
ftype
!=
gftype
)
{
filter
=
convertArguments
(
filter
,
gftype
,
ftype
,
null
);
filter
=
convertArguments
(
filter
,
gftype
,
ftype
,
0
);
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
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
,
MethodType
newType
,
MethodHandle
combiner
)
{
MethodType
newType
,
int
foldPos
,
MethodHandle
combiner
)
{
MethodType
oldType
=
target
.
type
();
MethodType
ctype
=
combiner
.
type
();
MethodHandle
gtarget
=
convertArguments
(
target
,
oldType
.
generic
(),
oldType
,
null
);
MethodHandle
gcombiner
=
convertArguments
(
combiner
,
ctype
.
generic
(),
ctype
,
null
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
oldType
,
ctype
,
foldPos
,
true
))
{
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
;
MethodHandle
gresult
=
FilterGeneric
.
makeArgumentFolder
(
gcombiner
,
gtarget
);
MethodHandle
result
=
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
null
);
return
result
;
return
convertArguments
(
gresult
,
newType
,
gresult
.
type
(),
0
);
}
static
...
...
@@ -802,6 +879,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
target
=
target
;
this
.
fallback
=
fallback
;
}
// FIXME: Build the control flow out of foldArguments.
static
MethodHandle
make
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
MethodType
type
=
target
.
type
();
int
nargs
=
type
.
parameterCount
();
...
...
@@ -809,12 +887,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodType
gtype
=
type
.
generic
();
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
MethodHandle
gtest
=
convertArguments
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
test
.
type
(),
null
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
null
);
MethodHandle
gfallback
=
convertArguments
(
fallback
,
gtype
,
type
,
null
);
MethodHandle
gtest
=
convertArguments
(
test
,
gtype
.
changeReturnType
(
boolean
.
class
),
test
.
type
(),
0
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
0
);
MethodHandle
gfallback
=
convertArguments
(
fallback
,
gtype
,
type
,
0
);
if
(
gtest
==
null
||
gtarget
==
null
||
gfallback
==
null
)
return
null
;
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
return
convertArguments
(
gguard
,
type
,
gtype
,
null
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
gtype
=
MethodType
.
genericMethodType
(
1
);
...
...
@@ -925,8 +1003,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
GuardWithCatch
(
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
this
(
INVOKES
[
target
.
type
().
parameterCount
()],
target
,
exType
,
catcher
);
}
GuardWithCatch
(
MethodHandle
invoker
,
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
// FIXME: Build the control flow out of foldArguments.
GuardWithCatch
(
MethodHandle
invoker
,
MethodHandle
target
,
Class
<?
extends
Throwable
>
exType
,
MethodHandle
catcher
)
{
super
(
invoker
);
this
.
target
=
target
;
this
.
exType
=
exType
;
...
...
@@ -1057,11 +1136,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
nargs
<
GuardWithCatch
.
INVOKES
.
length
)
{
MethodType
gtype
=
type
.
generic
();
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
null
);
MethodHandle
gcatcher
=
convertArguments
(
catcher
,
gcatchType
,
ctype
,
null
);
MethodHandle
gtarget
=
convertArguments
(
target
,
gtype
,
type
,
0
);
MethodHandle
gcatcher
=
convertArguments
(
catcher
,
gcatchType
,
ctype
,
0
);
MethodHandle
gguard
=
new
GuardWithCatch
(
gtarget
,
exType
,
gcatcher
);
if
(
gtarget
==
null
||
gcatcher
==
null
||
gguard
==
null
)
return
null
;
return
convertArguments
(
gguard
,
type
,
gtype
,
null
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
MethodType
gtype
=
MethodType
.
genericMethodType
(
0
,
true
);
MethodType
gcatchType
=
gtype
.
insertParameterTypes
(
0
,
Throwable
.
class
);
...
...
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
8c50098c
...
...
@@ -115,6 +115,8 @@ class MethodHandleNatives {
/** Which conv-ops are implemented by the JVM? */
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
();
static
{
...
...
@@ -141,6 +143,7 @@ class MethodHandleNatives {
if
(
CONV_OP_IMPLEMENTED_MASK_
==
0
)
CONV_OP_IMPLEMENTED_MASK_
=
DEFAULT_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.
...
...
@@ -186,25 +189,26 @@ class MethodHandleNatives {
*/
static
final
int
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_PRIM_TO_PRIM
=
0x3
,
// converts from one primitive to another
OP_REF_TO_PRIM
=
0x4
,
// unboxes a wrapper to produce a primitive
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
(NYI)
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
OP_SWAP_ARGS
=
0x6
,
// swap arguments (vminfo is 2nd arg)
OP_ROT_ARGS
=
0x7
,
// rotate arguments (vminfo is displaced arg)
OP_DUP_ARGS
=
0x8
,
// duplicates one or more arguments (at TOS)
OP_DROP_ARGS
=
0x9
,
// remove one or more argument slots
OP_COLLECT_ARGS
=
0xA
,
// combine
one or more arguments into a varargs (NYI)
OP_COLLECT_ARGS
=
0xA
,
// combine
arguments using an auxiliary function
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_RICOCHET
=
0xD
,
// run an adapter chain on the return value (NYI)
OP_F
OLD_ARGS
=
0xC
,
// combine but do not remove arguments; prepend result
//OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists
CONV_OP_LIMIT
=
0xE
;
// limit of CONV_OP enumeration
/** Shift and mask values for decoding the AMH.conversion field.
* These numbers are shared with the JVM for creating AMHs.
*/
static
final
int
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_SHIFT
=
0
,
// position of bits in CONV_VMINFO_MASK
CONV_OP_SHIFT
=
8
,
// position of bits in CONV_OP_MASK
...
...
@@ -244,8 +248,9 @@ class MethodHandleNatives {
T_LONG
=
11
,
T_OBJECT
=
12
,
//T_ARRAY = 13
T_VOID
=
14
;
T_VOID
=
14
,
//T_ADDRESS = 15
T_ILLEGAL
=
99
;
/**
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
...
...
@@ -273,16 +278,29 @@ class MethodHandleNatives {
try
{
Field
con
=
Constants
.
class
.
getDeclaredField
(
name
);
int
jval
=
con
.
getInt
(
null
);
if
(
jval
!=
vmval
)
throw
new
InternalError
(
name
+
": JVM has "
+
vmval
+
" while Java has "
+
jval
);
if
(
jval
==
vmval
)
continue
;
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
)
{
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
);
}
}
return
true
;
}
static
{
verifyConstants
(
);
assert
(
verifyConstants
()
);
}
// Up-calls from the JVM.
...
...
@@ -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
)
{
type
.
form
().
notifyGenericMethodType
();
...
...
@@ -323,15 +341,39 @@ class MethodHandleNatives {
* The JVM wants to raise an exception. Here's the path.
*/
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:
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
actual
=
actual
.
getClass
();
if
(
actual
!=
null
)
message
=
"required "
+
required
+
" but encountered "
+
actual
;
else
message
=
"required "
+
required
;
if
(
message
==
null
)
{
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
actual
=
actual
.
getClass
();
if
(
actual
!=
null
)
message
=
"required "
+
required
+
" but encountered "
+
actual
;
else
message
=
"required "
+
required
;
}
switch
(
code
)
{
case
190
:
// arraylength
throw
new
ArrayIndexOutOfBoundsException
(
message
);
case
50
:
//_aaload
throw
new
ClassCastException
(
message
);
case
192
:
// checkcast
throw
new
ClassCastException
(
message
);
default
:
...
...
@@ -365,4 +407,13 @@ class MethodHandleNatives {
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;
}
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
if
(
av
==
null
?
n
!=
0
:
((
Object
[])
av
).
length
!=
n
)
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
if
(
av
==
null
)
{
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)
...
...
@@ -80,6 +89,9 @@ package java.lang.invoke;
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
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
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
...
...
@@ -89,4 +101,8 @@ package java.lang.invoke;
if
(
obj
!=
null
)
message
=
message
+
": "
+
obj
;
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 {
* is not symbolically accessible from the lookup class's loader,
* the lookup can still succeed.
* For example, lookups for {@code MethodHandle.invokeExact} and
* {@code MethodHandle.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
* on various grounds (<a href="#secmgr">see below</a>).
* By contrast, the {@code ldc} instruction is not subject to
...
...
@@ -590,10 +590,10 @@ public class MethodHandles {
* Because of the general equivalence between {@code invokevirtual}
* instructions and method handles produced by {@code findVirtual},
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invoke
Generic
}, the resulting
* {@code invokeExact} or {@code invoke}, the resulting
* method handle is equivalent to one produced by
* {@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.
*
* @param refc the class or interface from which the method is accessed
...
...
@@ -1080,7 +1080,7 @@ return mh1;
MethodType
rawType
=
mh
.
type
();
if
(
rawType
.
parameterType
(
0
)
==
caller
)
return
mh
;
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
);
}
...
...
@@ -1148,7 +1148,7 @@ return mh1;
* <li>an {@code Object[]} array containing more arguments
* </ul>
* <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}.
* 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}
...
...
@@ -1166,7 +1166,7 @@ return mh1;
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
MethodHandle invoker = MethodHandles.
genericI
nvoker(type);
MethodHandle invoker = MethodHandles.
i
nvoker(type);
int spreadArgCount = type.parameterCount - objectArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
...
...
@@ -1186,7 +1186,7 @@ return invoker;
/**
* 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
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
...
...
@@ -1203,7 +1203,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* For example, to emulate an {@code invokeExact} call to a variable method
* handle {@code M}, extract its type {@code T},
* look up the invoker method {@code X} for {@code T},
* and call the invoker method, as {@code X.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}
* is unknown.)
* If spreading, collecting, or other argument transformations are required,
...
...
@@ -1212,7 +1212,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* <p>
* <em>(Note: The invoker method is not available via the Core Reflection API.
* An attempt to call {@linkplain java.lang.reflect.Method#invoke Method.invoke}
* 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>
* <p>
* This method throws no reflective or security exceptions.
...
...
@@ -1226,20 +1226,20 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
/**
* 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
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
* <p>
* Before invoking its target, the invoker will apply reference casts as
* necessary and
unbox and widen primitive arguments, as if by {@link #convertArguments convertArguments
}.
*
The return value of the invoker will be an {@code Object} reference,
*
boxing a primitive value if the original type returns a primitive
,
*
and always null if the original type returns void
.
* necessary and
box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType
}.
*
Similarly, the return value will be converted as necessary.
*
If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle}
,
*
the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}
.
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
publicLookup().findVirtual(MethodHandle.class, "invoke
Generic
", type)
publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* </pre></blockquote>
* <p>
* This method throws no reflective or security exceptions.
...
...
@@ -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
*/
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
)
{
return
type
.
invokers
().
genericInvoker
(
);
return
invoker
(
type
);
}
/**
...
...
@@ -1368,18 +1377,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
public
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodType
oldType
=
target
.
type
();
if
(
oldType
.
equals
(
newType
))
return
target
;
MethodHandle
res
=
null
;
try
{
res
=
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
oldType
,
null
);
}
catch
(
IllegalArgumentException
ex
)
{
}
if
(
res
==
null
)
throw
new
WrongMethodTypeException
(
"cannot convert to "
+
newType
+
": "
+
target
);
return
res
;
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
1
);
}
/**
...
...
@@ -1422,7 +1420,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
public
static
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);
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
MethodType
oldType
=
target
.
type
();
checkReorder
(
reorder
,
newType
,
oldType
);
return
MethodHandleImpl
.
convert
Arguments
(
target
,
return
MethodHandleImpl
.
permute
Arguments
(
target
,
newType
,
oldType
,
reorder
);
}
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
())
{
int
limit
=
newType
.
parameterCount
();
boolean
bad
=
false
;
for
(
int
i
:
reorder
)
{
for
(
int
j
=
0
;
j
<
reorder
.
length
;
j
++)
{
int
i
=
reorder
[
j
];
if
(
i
<
0
||
i
>=
limit
)
{
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
;
}
throw
newIllegalArgumentException
(
"bad reorder array
"
);
throw
newIllegalArgumentException
(
"bad reorder array
: "
+
Arrays
.
toString
(
reorder
)
);
}
/**
...
...
@@ -1622,7 +1629,7 @@ assert((int)twice.invokeExact(21) == 42);
if
(
type
==
void
.
class
)
throw
newIllegalArgumentException
(
"void 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
{
return
identity
(
type
).
bindTo
(
type
.
cast
(
value
));
}
...
...
@@ -1857,7 +1864,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
MethodHandle
filterArguments
(
MethodHandle
target
,
int
pos
,
MethodHandle
...
filters
)
{
MethodType
targetType
=
target
.
type
();
MethodHandle
adapter
=
target
;
MethodType
adapterType
=
targetType
;
MethodType
adapterType
=
null
;
assert
((
adapterType
=
targetType
)
!=
null
);
int
maxPos
=
targetType
.
parameterCount
();
if
(
pos
+
filters
.
length
>
maxPos
)
throw
newIllegalArgumentException
(
"too many filters"
);
...
...
@@ -1865,19 +1873,23 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
for
(
MethodHandle
filter
:
filters
)
{
curPos
+=
1
;
if
(
filter
==
null
)
continue
;
// ignore null elements of filters
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
curPos
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filterType
.
parameterType
(
0
));
adapter
=
MethodHandleImpl
.
filterArgument
(
adapter
,
curPos
,
filter
);
adapter
=
filterArgument
(
adapter
,
curPos
,
filter
);
assert
((
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filter
.
type
().
parameterType
(
0
)))
!=
null
);
}
MethodType
midType
=
adapter
.
type
();
if
(
midType
!=
adapterType
)
adapter
=
MethodHandleImpl
.
convertArguments
(
adapter
,
adapterType
,
midType
,
null
);
assert
(
adapterType
.
equals
(
adapter
.
type
()));
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
* its return value with a unary filter function.
...
...
@@ -1913,14 +1925,26 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
parameterType
(
0
)
!=
targetType
.
returnType
())
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
Class
<?>
rtype
=
targetType
.
returnType
();
int
filterValues
=
filterType
.
parameterCount
();
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) },
// 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.
MethodHandle
returner
=
dropArguments
(
filter
,
1
,
targetType
.
parameterList
());
return
foldArguments
(
returner
,
target
);
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
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
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodHandle
combiner
)
{
MethodType
targetType
=
target
.
type
();
MethodType
combinerType
=
combiner
.
type
();
int
foldPos
=
0
;
// always at the head, at present
int
foldArgs
=
combinerType
.
parameterCount
();
boolean
ok
=
(
targetType
.
parameterCount
()
>=
1
+
foldArgs
);
if
(
ok
&&
!
combinerType
.
parameterList
().
equals
(
targetType
.
parameterList
().
subList
(
1
,
foldArgs
+
1
)))
int
foldVals
=
combinerType
.
returnType
()
==
void
.
class
?
0
:
1
;
int
afterInsertPos
=
foldPos
+
foldVals
;
boolean
ok
=
(
targetType
.
parameterCount
()
>=
afterInsertPos
+
foldArgs
);
if
(
ok
&&
!(
combinerType
.
parameterList
()
.
equals
(
targetType
.
parameterList
().
subList
(
afterInsertPos
,
afterInsertPos
+
foldArgs
))))
ok
=
false
;
if
(
ok
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
if
(
ok
&&
foldVals
!=
0
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
ok
=
false
;
if
(!
ok
)
throw
misMatchedTypes
(
"target and combiner types"
,
targetType
,
combinerType
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
0
,
1
);
return
MethodHandleImpl
.
foldArguments
(
target
,
newType
,
combiner
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
foldPos
,
afterInsertPos
);
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
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* {@code target.invoke
Generic
}.
* {@code target.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
...
...
src/share/classes/java/lang/invoke/MethodType.java
浏览文件 @
8c50098c
...
...
@@ -25,6 +25,7 @@
package
java.lang.invoke
;
import
sun.invoke.util.Wrapper
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.HashMap
;
...
...
@@ -39,7 +40,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* matched between a method handle and all its callers,
* and the JVM's operations enforce this matching at, specifically
* during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
* and {@link MethodHandle#invoke
Generic MethodHandle.invokeGeneric
}, and during execution
* and {@link MethodHandle#invoke
MethodHandle.invoke
}, and during execution
* of {@code invokedynamic} instructions.
* <p>
* The structure is a return type accompanied by any number of parameter types.
...
...
@@ -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.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be {@code Object},
* except the final
varargs
parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the
varargs
parameter if any)
* @param
varargs whether there will be a varargs
parameter, of type {@code Object[]}
* @return a
totally generic method type, given only its count of parameters and vararg
s
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* except the final
array
parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the
final array
parameter if any)
* @param
finalArray whether there will be a trailing array
parameter, of type {@code Object[]}
* @return a
generally applicable method type, for all calls of the given fixed argument count and a collected array of further argument
s
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
(or 254, if {@code finalArray})
* @see #genericMethodType(int)
*/
public
static
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
varargs
)
{
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
finalArray
)
{
MethodType
mt
;
checkSlotCount
(
objectArgCount
);
int
ivarargs
=
(!
varargs
?
0
:
1
);
int
ivarargs
=
(!
finalArray
?
0
:
1
);
int
ootIndex
=
objectArgCount
*
2
+
ivarargs
;
if
(
ootIndex
<
objectOnlyTypes
.
length
)
{
mt
=
objectOnlyTypes
[
ootIndex
];
...
...
@@ -294,7 +295,7 @@ class MethodType implements java.io.Serializable {
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be Object.
* @param objectArgCount number of parameters
* @return a
totally generic method type, given only its count of parameters
* @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
* @see #genericMethodType(int, boolean)
*/
...
...
@@ -626,6 +627,30 @@ class MethodType implements java.io.Serializable {
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
/** 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 {
final
long
argCounts
;
// packed slot & value counts
final
long
primCounts
;
// packed prim & double counts
final
int
vmslots
;
// total number of parameter slots
private
Object
vmlayout
;
// vm-specific information for calls
final
MethodType
erasedType
;
// the canonical erasure
/*lazy*/
MethodType
primsAsBoxes
;
// replace prims by wrappers
...
...
@@ -59,7 +60,7 @@ class MethodTypeForm {
/*lazy*/
FromGeneric
fromGeneric
;
// convert cs. w/o prims to with
/*lazy*/
SpreadGeneric
[]
spreadGeneric
;
// expand one argument to many
/*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
()
{
return
erasedType
;
...
...
@@ -460,9 +461,9 @@ class MethodTypeForm {
if
(
genericInvoker
!=
null
)
return
;
try
{
// Trigger adapter creation.
genericInvoker
=
InvokeGeneric
.
gener
ic
InvokerOf
(
erasedType
);
genericInvoker
=
InvokeGeneric
.
gener
al
InvokerOf
(
erasedType
);
}
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
);
throw
err
;
}
...
...
src/share/classes/java/lang/invoke/SpreadGeneric.java
浏览文件 @
8c50098c
...
...
@@ -66,6 +66,10 @@ class SpreadGeneric {
this
.
entryPoint
=
ep
[
0
];
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/** From targetType remove the last spreadCount arguments, and instead
* append a simple Object argument.
*/
...
...
src/share/classes/java/lang/invoke/ToGeneric.java
浏览文件 @
8c50098c
...
...
@@ -96,7 +96,7 @@ class ToGeneric {
ToGeneric
va2
=
ToGeneric
.
of
(
primsAtEnd
);
this
.
adapter
=
va2
.
adapter
;
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
);
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
...
...
@@ -128,7 +128,7 @@ class ToGeneric {
assert
(
eptWithInts
.
parameterType
(
i
)
==
int
.
class
);
MethodType
nextType
=
midType
.
changeParameterType
(
i
,
int
.
class
);
rawEntryPoint
=
MethodHandleImpl
.
convertArguments
(
rawEntryPoint
,
nextType
,
midType
,
null
);
rawEntryPoint
,
nextType
,
midType
,
0
);
midType
=
nextType
;
}
}
...
...
@@ -152,6 +152,10 @@ class ToGeneric {
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'.
* The values need to be reboxed for to match 'cooked'.
* Do this on the fly.
...
...
@@ -171,7 +175,7 @@ class ToGeneric {
invoker
.
type
().
generic
(),
invoker
,
0
,
MethodHandle
.
class
);
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
);
if
(
filteredInvoker
==
null
)
throw
new
InternalError
();
}
...
...
@@ -199,13 +203,13 @@ class ToGeneric {
assert
(!
rret
.
isPrimitive
());
if
(
rret
==
Object
.
class
&&
!
mustCast
)
return
null
;
return
ValueConversions
.
cast
(
tret
,
false
);
return
ValueConversions
.
cast
(
tret
);
}
else
if
(
tret
==
rret
)
{
return
ValueConversions
.
unbox
(
tret
,
false
);
return
ValueConversions
.
unbox
(
tret
);
}
else
{
assert
(
rret
.
isPrimitive
());
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 {
}
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 @@
* The method handle constant produced for such a method behaves as if
* it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code
invokeGeneric
}.
* when invoked via {@code
MethodHandle.invoke
}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
* as if the {@code varargs} bit were not set.
* <p>
...
...
@@ -243,7 +243,7 @@
* <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* 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 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
...
...
@@ -251,7 +251,7 @@
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* As long as each bootstrap method can be correctly invoked
* by <code>
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}
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
...
...
@@ -272,7 +272,7 @@
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
* <li>the bootstrap method has the wrong arity,
* causing {@code
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 invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
...
...
@@ -381,10 +381,10 @@
* those values will be passed as additional arguments to the method handle.
* (Note that because there is a limit of 255 arguments to any method,
* at most 252 extra arguments can be supplied.)
* The bootstrap method will be invoked as if by either {@code
invokeGeneric
}
* The bootstrap method will be invoked as if by either {@code
MethodHandle.invoke
}
* or {@code invokeWithArguments}. (There is no way to tell the difference.)
* <p>
* 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.
* 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.
...
...
@@ -419,8 +419,8 @@
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
* the {@code CONSTANT_InvokeDynamic} entry.
* In that case, the {@code
invokeGeneric
} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code
invokeGeneric
}
* 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
MethodHandle.invoke
}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail,
* resulting in a {@code BootstrapMethodError}.)
...
...
src/share/classes/javax/imageio/metadata/doc-files/jpeg_metadata.html
浏览文件 @
8c50098c
...
...
@@ -211,6 +211,20 @@ to any listeners.
<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
JPEG conventions, as follows:
...
...
@@ -241,8 +255,11 @@ JPEG conventions, as follows:
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
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
is assumed to be YCbCrA. If these values are > 4, they are checked
YCbCr. Subject to the availability of the
<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
encode the following colorspaces:
<p>
...
...
@@ -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.
<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
written without any special marker segments. The component ids
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
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
...
...
@@ -433,6 +454,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
<li>
RGBA images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<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
...
...
@@ -456,6 +479,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
<li>
PhotoYCC Images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<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,
...
...
@@ -471,6 +496,8 @@ in the frame header node of the metadata object, regardless of color space.)
</ul>
<li>
PhotoYCCA Images:
Subject to the
<a
href=
#optcolor
>
optional library support
</a>
described above,
<ul>
<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
...
...
src/share/classes/javax/swing/ComboBoxModel.java
浏览文件 @
8c50098c
...
...
@@ -33,9 +33,11 @@ package javax.swing;
* <code>ListModel</code>. This disjoint behavior allows for the temporary
* storage and retrieval of a selected item in the model.
*
* @param <E> the type of the elements of this model
*
* @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
...
...
src/share/classes/javax/swing/DefaultComboBoxModel.java
浏览文件 @
8c50098c
...
...
@@ -24,39 +24,28 @@
*/
package
javax.swing
;
import
java.beans.*
;
import
java.util.*
;
import
java.awt.*
;
import
java.awt.event.*
;
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.
*
* @param <E> the type of the elements of this model
*
* @author Arnaud Weber
* @author Tom Santos
*/
public
class
DefaultComboBoxModel
extends
AbstractListModel
implements
MutableComboBoxModel
,
Serializable
{
Vector
objects
;
public
class
DefaultComboBoxModel
<
E
>
extends
AbstractListModel
<
E
>
implements
MutableComboBoxModel
<
E
>
,
Serializable
{
Vector
<
E
>
objects
;
Object
selectedObject
;
/**
* Constructs an empty DefaultComboBoxModel object.
*/
public
DefaultComboBoxModel
()
{
objects
=
new
Vector
();
objects
=
new
Vector
<
E
>
();
}
/**
...
...
@@ -65,8 +54,8 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
*
* @param items an array of Object objects
*/
public
DefaultComboBoxModel
(
final
Object
items
[])
{
objects
=
new
Vector
();
public
DefaultComboBoxModel
(
final
E
items
[])
{
objects
=
new
Vector
<
E
>
();
objects
.
ensureCapacity
(
items
.
length
);
int
i
,
c
;
...
...
@@ -84,7 +73,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
*
* @param v a Vector object ...
*/
public
DefaultComboBoxModel
(
Vector
<
?
>
v
)
{
public
DefaultComboBoxModel
(
Vector
<
E
>
v
)
{
objects
=
v
;
if
(
getSize
()
>
0
)
{
...
...
@@ -117,7 +106,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
// implements javax.swing.ListModel
public
Object
getElementAt
(
int
index
)
{
public
E
getElementAt
(
int
index
)
{
if
(
index
>=
0
&&
index
<
objects
.
size
()
)
return
objects
.
elementAt
(
index
);
else
...
...
@@ -136,7 +125,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
// implements javax.swing.MutableComboBoxModel
public
void
addElement
(
Object
anObject
)
{
public
void
addElement
(
E
anObject
)
{
objects
.
addElement
(
anObject
);
fireIntervalAdded
(
this
,
objects
.
size
()-
1
,
objects
.
size
()-
1
);
if
(
objects
.
size
()
==
1
&&
selectedObject
==
null
&&
anObject
!=
null
)
{
...
...
@@ -145,7 +134,7 @@ public class DefaultComboBoxModel extends AbstractListModel implements MutableCo
}
// implements javax.swing.MutableComboBoxModel
public
void
insertElementAt
(
Object
anObject
,
int
index
)
{
public
void
insertElementAt
(
E
anObject
,
int
index
)
{
objects
.
insertElementAt
(
anObject
,
index
);
fireIntervalAdded
(
this
,
index
,
index
);
}
...
...
src/share/classes/javax/swing/JComboBox.java
浏览文件 @
8c50098c
...
...
@@ -69,6 +69,8 @@ import javax.accessibility.*;
* @see ComboBoxModel
* @see DefaultComboBoxModel
*
* @param <E> the type of the elements of this combo box
*
* @beaninfo
* attribute: isContainer false
* description: A combination of a text field and a drop-down list.
...
...
@@ -76,7 +78,7 @@ import javax.accessibility.*;
* @author Arnaud Weber
* @author Mark Davidson
*/
public
class
JComboBox
extends
JComponent
public
class
JComboBox
<
E
>
extends
JComponent
implements
ItemSelectable
,
ListDataListener
,
ActionListener
,
Accessible
{
/**
* @see #getUIClassID
...
...
@@ -91,7 +93,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #getModel
* @see #setModel
*/
protected
ComboBoxModel
dataModel
;
protected
ComboBoxModel
<
E
>
dataModel
;
/**
* This protected field is implementation specific. Do not access directly
* or override. Use the accessor methods instead.
...
...
@@ -99,7 +101,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #getRenderer
* @see #setRenderer
*/
protected
ListCellRenderer
renderer
;
protected
ListCellRenderer
<?
super
E
>
renderer
;
/**
* This protected field is implementation specific. Do not access directly
* or override. Use the accessor methods instead.
...
...
@@ -156,7 +158,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
protected
Object
selectedItemReminder
=
null
;
private
Object
prototypeDisplayValue
;
private
E
prototypeDisplayValue
;
// Flag to ensure that infinite loops do not occur with ActionEvents.
private
boolean
firingActionEvent
=
false
;
...
...
@@ -175,7 +177,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* displayed list of items
* @see DefaultComboBoxModel
*/
public
JComboBox
(
ComboBoxModel
aModel
)
{
public
JComboBox
(
ComboBoxModel
<
E
>
aModel
)
{
super
();
setModel
(
aModel
);
init
();
...
...
@@ -189,9 +191,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @param items an array of objects to insert into the combo box
* @see DefaultComboBoxModel
*/
public
JComboBox
(
final
Object
items
[]
)
{
public
JComboBox
(
E
[]
items
)
{
super
();
setModel
(
new
DefaultComboBoxModel
(
items
));
setModel
(
new
DefaultComboBoxModel
<
E
>
(
items
));
init
();
}
...
...
@@ -203,9 +205,9 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @param items an array of vectors to insert into the combo box
* @see DefaultComboBoxModel
*/
public
JComboBox
(
Vector
<
?
>
items
)
{
public
JComboBox
(
Vector
<
E
>
items
)
{
super
();
setModel
(
new
DefaultComboBoxModel
(
items
));
setModel
(
new
DefaultComboBoxModel
<
E
>
(
items
));
init
();
}
...
...
@@ -219,7 +221,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
public
JComboBox
()
{
super
();
setModel
(
new
DefaultComboBoxModel
());
setModel
(
new
DefaultComboBoxModel
<
E
>
());
init
();
}
...
...
@@ -263,7 +265,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
public
void
updateUI
()
{
setUI
((
ComboBoxUI
)
UIManager
.
getUI
(
this
));
ListCellRenderer
renderer
=
getRenderer
();
ListCellRenderer
<?
super
E
>
renderer
=
getRenderer
();
if
(
renderer
instanceof
Component
)
{
SwingUtilities
.
updateComponentTreeUI
((
Component
)
renderer
);
}
...
...
@@ -302,8 +304,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* bound: true
* description: Model that the combo box uses to get data to display.
*/
public
void
setModel
(
ComboBoxModel
aModel
)
{
ComboBoxModel
oldModel
=
dataModel
;
public
void
setModel
(
ComboBoxModel
<
E
>
aModel
)
{
ComboBoxModel
<
E
>
oldModel
=
dataModel
;
if
(
oldModel
!=
null
)
{
oldModel
.
removeListDataListener
(
this
);
}
...
...
@@ -322,7 +324,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @return the <code>ComboBoxModel</code> that provides the displayed
* list of items
*/
public
ComboBoxModel
getModel
()
{
public
ComboBoxModel
<
E
>
getModel
()
{
return
dataModel
;
}
...
...
@@ -461,8 +463,8 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* expert: true
* description: The renderer that paints the item selected in the list.
*/
public
void
setRenderer
(
ListCellRenderer
aRenderer
)
{
ListCellRenderer
oldRenderer
=
renderer
;
public
void
setRenderer
(
ListCellRenderer
<?
super
E
>
aRenderer
)
{
ListCellRenderer
<?
super
E
>
oldRenderer
=
renderer
;
renderer
=
aRenderer
;
firePropertyChange
(
"renderer"
,
oldRenderer
,
renderer
);
invalidate
();
...
...
@@ -475,7 +477,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @return the <code>ListCellRenderer</code> that displays
* the selected item.
*/
public
ListCellRenderer
getRenderer
()
{
public
ListCellRenderer
<?
super
E
>
getRenderer
()
{
return
renderer
;
}
...
...
@@ -558,7 +560,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
// will be rejected.
boolean
found
=
false
;
for
(
int
i
=
0
;
i
<
dataModel
.
getSize
();
i
++)
{
Object
element
=
dataModel
.
getElementAt
(
i
);
E
element
=
dataModel
.
getElementAt
(
i
);
if
(
anObject
.
equals
(
element
))
{
found
=
true
;
objectToSelect
=
element
;
...
...
@@ -640,7 +642,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
public
int
getSelectedIndex
()
{
Object
sObject
=
dataModel
.
getSelectedItem
();
int
i
,
c
;
Object
obj
;
E
obj
;
for
(
i
=
0
,
c
=
dataModel
.
getSize
();
i
<
c
;
i
++
)
{
obj
=
dataModel
.
getElementAt
(
i
);
...
...
@@ -658,7 +660,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* @see #setPrototypeDisplayValue
* @since 1.4
*/
public
Object
getPrototypeDisplayValue
()
{
public
E
getPrototypeDisplayValue
()
{
return
prototypeDisplayValue
;
}
...
...
@@ -683,7 +685,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* attribute: visualUpdate true
* 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
;
this
.
prototypeDisplayValue
=
prototypeDisplayValue
;
firePropertyChange
(
"prototypeDisplayValue"
,
oldValue
,
prototypeDisplayValue
);
...
...
@@ -708,12 +710,12 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* }
* </pre>
*
* @param
anObject the Object
to add to the list
* @param
item the item
to add to the list
* @see MutableComboBoxModel
*/
public
void
addItem
(
Object
anObject
)
{
public
void
addItem
(
E
item
)
{
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
addElement
(
anObject
);
((
MutableComboBoxModel
<
E
>)
dataModel
).
addElement
(
item
);
}
/**
...
...
@@ -721,14 +723,14 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* This method works only if the <code>JComboBox</code> uses a
* 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
* to add the item
* @see MutableComboBoxModel
*/
public
void
insertItemAt
(
Object
anObject
,
int
index
)
{
public
void
insertItemAt
(
E
item
,
int
index
)
{
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
insertElementAt
(
anObject
,
index
);
((
MutableComboBoxModel
<
E
>)
dataModel
).
insertElementAt
(
item
,
index
);
}
/**
...
...
@@ -756,7 +758,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
public
void
removeItemAt
(
int
anIndex
)
{
checkMutableComboBoxModel
();
((
MutableComboBoxModel
)
dataModel
).
removeElementAt
(
anIndex
);
((
MutableComboBoxModel
<
E
>
)
dataModel
).
removeElementAt
(
anIndex
);
}
/**
...
...
@@ -764,7 +766,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*/
public
void
removeAllItems
()
{
checkMutableComboBoxModel
();
MutableComboBoxModel
model
=
(
MutableComboBoxModel
)
dataModel
;
MutableComboBoxModel
<
E
>
model
=
(
MutableComboBoxModel
<
E
>
)
dataModel
;
int
size
=
model
.
getSize
();
if
(
model
instanceof
DefaultComboBoxModel
)
{
...
...
@@ -772,7 +774,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
}
else
{
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
Object
element
=
model
.
getElementAt
(
0
);
E
element
=
model
.
getElementAt
(
0
);
model
.
removeElement
(
element
);
}
}
...
...
@@ -1188,11 +1190,11 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
private
static
class
ComboBoxActionPropertyChangeListener
extends
ActionPropertyChangeListener
<
JComboBox
>
{
ComboBoxActionPropertyChangeListener
(
JComboBox
b
,
Action
a
)
{
extends
ActionPropertyChangeListener
<
JComboBox
<?>
>
{
ComboBoxActionPropertyChangeListener
(
JComboBox
<?>
b
,
Action
a
)
{
super
(
b
,
a
);
}
protected
void
actionPropertyChanged
(
JComboBox
cb
,
protected
void
actionPropertyChanged
(
JComboBox
<?>
cb
,
Action
action
,
PropertyChangeEvent
e
)
{
if
(
AbstractAction
.
shouldReconfigure
(
e
))
{
...
...
@@ -1454,10 +1456,10 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
*
* @param index an integer indicating the list position, where the first
* 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
*/
public
Object
getItemAt
(
int
index
)
{
public
E
getItemAt
(
int
index
)
{
return
dataModel
.
getElementAt
(
index
);
}
...
...
src/share/classes/javax/swing/MutableComboBoxModel.java
浏览文件 @
8c50098c
...
...
@@ -27,19 +27,21 @@ package javax.swing;
/**
* A mutable version of <code>ComboBoxModel</code>.
*
* @param <E> the type of the elements of this model
*
* @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
* should notify all registered <code>ListDataListener</code>s that the
* 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
...
...
@@ -55,17 +57,17 @@ public interface MutableComboBoxModel extends ComboBoxModel {
* should notify all registered <code>ListDataListener</code>s that the
* 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
*/
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
* should notify all registered <code>ListDataListener</code>s that the
* 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
);
}
src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
浏览文件 @
8c50098c
...
...
@@ -40,7 +40,7 @@ import sun.awt.shell.ShellFolder;
*
* @author Jeff Dinkins
*/
public
class
BasicDirectoryModel
extends
AbstractListModel
implements
PropertyChangeListener
{
public
class
BasicDirectoryModel
extends
AbstractListModel
<
Object
>
implements
PropertyChangeListener
{
private
JFileChooser
filechooser
=
null
;
// 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 {
/**
* 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
>();
int
[]
depths
=
null
;
File
selectedDirectory
=
null
;
...
...
@@ -1063,7 +1063,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI {
/**
* 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
FilterComboBoxModel
()
{
super
();
...
...
src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
浏览文件 @
8c50098c
...
...
@@ -488,6 +488,18 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI
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
,
int
tabPlacement
,
int
selectedIndex
,
...
...
src/share/classes/sun/invoke/util/ValueConversions.java
浏览文件 @
8c50098c
...
...
@@ -31,10 +31,15 @@ import java.lang.invoke.MethodHandles.Lookup;
import
java.lang.invoke.MethodType
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.EnumMap
;
import
java.util.List
;
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
EnumMap
<
Wrapper
,
MethodHandle
>[]
newWrapperCaches
(
int
n
)
{
...
...
@@ -42,88 +47,101 @@ public class ValueConversions {
EnumMap
<
Wrapper
,
MethodHandle
>[]
caches
=
(
EnumMap
<
Wrapper
,
MethodHandle
>[])
new
EnumMap
[
n
];
// unchecked warning expected here
for
(
int
i
=
0
;
i
<
n
;
i
++)
caches
[
i
]
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
caches
[
i
]
=
new
EnumMap
<>(
Wrapper
.
class
);
return
caches
;
}
/// Converting references to values.
static
int
unboxInteger
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Integer
)
x
).
intValue
();
// There are several levels of this unboxing conversions:
// no conversions: exactly Integer.valueOf, etc.
// 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
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Byte
)
x
).
byteValue
();
static
byte
unboxByte
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Byte
)
return
((
Byte
)
x
).
byteValue
();
return
primitiveConversion
(
Wrapper
.
BYTE
,
x
,
cast
).
byteValue
();
}
static
short
unboxShort
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Short
)
x
).
shortValue
();
static
short
unboxShort
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Short
)
return
((
Short
)
x
).
shortValue
();
return
primitiveConversion
(
Wrapper
.
SHORT
,
x
,
cast
).
shortValue
();
}
static
boolean
unboxBoolean
(
Object
x
)
{
if
(
x
==
null
)
return
false
;
// never NPE
return
((
Boolean
)
x
).
booleanValue
();
static
boolean
unboxBoolean
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Boolean
)
return
((
Boolean
)
x
).
booleanValue
();
return
(
primitiveConversion
(
Wrapper
.
BOOLEAN
,
x
,
cast
).
intValue
()
&
1
)
!=
0
;
}
static
char
unboxCharacter
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Character
)
x
).
charValue
();
static
char
unboxCharacter
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Character
)
return
((
Character
)
x
).
charValue
();
return
(
char
)
primitiveConversion
(
Wrapper
.
CHAR
,
x
,
cast
).
intValue
();
}
static
long
unboxLong
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Long
)
x
).
longValue
();
static
long
unboxLong
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Long
)
return
((
Long
)
x
).
longValue
();
return
primitiveConversion
(
Wrapper
.
LONG
,
x
,
cast
).
longValue
();
}
static
float
unboxFloat
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Float
)
x
).
floatValue
();
static
float
unboxFloat
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Float
)
return
((
Float
)
x
).
floatValue
();
return
primitiveConversion
(
Wrapper
.
FLOAT
,
x
,
cast
).
floatValue
();
}
static
double
unboxDouble
(
Object
x
)
{
if
(
x
==
null
)
return
0
;
// never NPE
return
((
Double
)
x
).
doubleValue
();
static
double
unboxDouble
(
Object
x
,
boolean
cast
)
{
if
(
x
instanceof
Double
)
return
((
Double
)
x
).
doubleValue
();
return
primitiveConversion
(
Wrapper
.
DOUBLE
,
x
,
cast
).
doubleValue
();
}
/// Converting references to "raw" values.
/// A raw primitive value is always an int or long.
static
int
unboxByteRaw
(
Object
x
)
{
return
unboxByte
(
x
);
static
int
unboxByteRaw
(
Object
x
,
boolean
cast
)
{
return
unboxByte
(
x
,
cast
);
}
static
int
unboxShortRaw
(
Object
x
)
{
return
unboxShort
(
x
);
static
int
unboxShortRaw
(
Object
x
,
boolean
cast
)
{
return
unboxShort
(
x
,
cast
);
}
static
int
unboxBooleanRaw
(
Object
x
)
{
return
unboxBoolean
(
x
)
?
1
:
0
;
static
int
unboxBooleanRaw
(
Object
x
,
boolean
cast
)
{
return
unboxBoolean
(
x
,
cast
)
?
1
:
0
;
}
static
int
unboxCharacterRaw
(
Object
x
)
{
return
unboxCharacter
(
x
);
static
int
unboxCharacterRaw
(
Object
x
,
boolean
cast
)
{
return
unboxCharacter
(
x
,
cast
);
}
static
int
unboxFloatRaw
(
Object
x
)
{
return
Float
.
floatToIntBits
(
unboxFloat
(
x
));
static
int
unboxFloatRaw
(
Object
x
,
boolean
cast
)
{
return
Float
.
floatToIntBits
(
unboxFloat
(
x
,
cast
));
}
static
long
unboxDoubleRaw
(
Object
x
)
{
return
Double
.
doubleToRawLongBits
(
unboxDouble
(
x
));
static
long
unboxDoubleRaw
(
Object
x
,
boolean
cast
)
{
return
Double
.
doubleToRawLongBits
(
unboxDouble
(
x
,
cast
));
}
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
>[]
UNBOX_CONVERSIONS
=
newWrapperCaches
(
4
);
private
static
MethodHandle
unbox
(
Wrapper
wrap
,
boolean
exact
,
boolean
raw
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
UNBOX_CONVERSIONS
[(
exac
t
?
1
:
0
)+(
raw
?
2
:
0
)];
private
static
MethodHandle
unbox
(
Wrapper
wrap
,
boolean
raw
,
boolean
cast
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
UNBOX_CONVERSIONS
[(
cas
t
?
1
:
0
)+(
raw
?
2
:
0
)];
MethodHandle
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
{
return
mh
;
...
...
@@ -136,7 +154,7 @@ public class ValueConversions {
mh
=
raw
?
ALWAYS_ZERO
:
IGNORE
;
break
;
case
INT:
case
LONG:
// these guys don't need separate raw channels
if
(
raw
)
mh
=
unbox
(
wrap
,
exact
,
false
);
if
(
raw
)
mh
=
unbox
(
wrap
,
false
,
cast
);
break
;
}
if
(
mh
!=
null
)
{
...
...
@@ -146,37 +164,62 @@ public class ValueConversions {
// look up the method
String
name
=
"unbox"
+
wrap
.
simpleName
()
+
(
raw
?
"Raw"
:
""
);
MethodType
type
=
unboxType
(
wrap
,
raw
);
if
(!
exact
)
{
try
{
// actually, type is wrong; the Java method takes Object
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
.
erase
());
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
unbox
(
wrap
,
!
exact
,
raw
).
asType
(
type
);
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
if
(
mh
!=
null
)
{
mh
=
MethodHandles
.
insertArguments
(
mh
,
1
,
cast
);
cache
.
put
(
wrap
,
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
)
{
return
unbox
(
type
,
exact
,
fals
e
);
public
static
MethodHandle
unbox
Cast
(
Wrapper
type
)
{
return
unbox
(
type
,
false
,
tru
e
);
}
public
static
MethodHandle
unboxRaw
(
Wrapper
type
,
boolean
exact
)
{
return
unbox
(
type
,
exact
,
tru
e
);
public
static
MethodHandle
unboxRaw
(
Wrapper
type
)
{
return
unbox
(
type
,
true
,
fals
e
);
}
public
static
MethodHandle
unbox
(
Class
<?>
type
,
boolean
exact
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
false
);
public
static
MethodHandle
unbox
(
Class
<?>
type
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
false
,
false
);
}
public
static
MethodHandle
unboxRaw
(
Class
<?>
type
,
boolean
exact
)
{
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
exact
,
true
);
public
static
MethodHandle
unboxCast
(
Class
<?>
type
)
{
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
...
...
@@ -285,7 +328,7 @@ public class ValueConversions {
MethodType
type
=
boxType
(
wrap
,
raw
);
if
(
exact
)
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
...
...
@@ -296,22 +339,31 @@ public class ValueConversions {
cache
.
put
(
wrap
,
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
);
}
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
);
}
public
static
MethodHandle
box
(
Wrapper
type
,
boolean
exact
)
{
public
static
MethodHandle
box
(
Wrapper
type
)
{
boolean
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
);
}
...
...
@@ -319,16 +371,16 @@ public class ValueConversions {
static
int
unboxRawInteger
(
Object
x
)
{
if
(
x
instanceof
Integer
)
return
unboxInteger
(
x
)
;
return
(
int
)
x
;
else
return
(
int
)
unboxLong
(
x
);
return
(
int
)
unboxLong
(
x
,
false
);
}
static
Integer
reboxRawInteger
(
Object
x
)
{
if
(
x
instanceof
Integer
)
return
(
Integer
)
x
;
else
return
(
int
)
unboxLong
(
x
);
return
(
int
)
unboxLong
(
x
,
false
);
}
static
Byte
reboxRawByte
(
Object
x
)
{
...
...
@@ -362,7 +414,7 @@ public class ValueConversions {
static
Double
reboxRawDouble
(
Object
x
)
{
if
(
x
instanceof
Double
)
return
(
Double
)
x
;
return
boxDoubleRaw
(
unboxLong
(
x
));
return
boxDoubleRaw
(
unboxLong
(
x
,
true
));
}
private
static
MethodType
reboxType
(
Wrapper
wrap
)
{
...
...
@@ -371,7 +423,7 @@ public class ValueConversions {
}
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,
...
...
@@ -380,10 +432,10 @@ public class ValueConversions {
* When the erased primitive value is then boxed into an Integer or Long,
* the final boxed primitive is sometimes required. This transformation
* is called a "rebox". It takes an Integer or Long and produces some
* other boxed value
.
* other boxed value
, typed (inexactly) as an Object
*/
public
static
MethodHandle
rebox
(
Wrapper
wrap
,
boolean
exact
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
REBOX_CONVERSIONS
[
exact
?
1
:
0
];
public
static
MethodHandle
rebox
(
Wrapper
wrap
)
{
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
REBOX_CONVERSIONS
[
0
];
MethodHandle
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
{
return
mh
;
...
...
@@ -402,14 +454,11 @@ public class ValueConversions {
// look up the method
String
name
=
"reboxRaw"
+
wrap
.
simpleName
();
MethodType
type
=
reboxType
(
wrap
);
if
(
exact
)
{
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
}
else
{
mh
=
rebox
(
wrap
,
!
exact
).
asType
(
IDENTITY
.
type
());
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
name
,
type
);
mh
=
mh
.
asType
(
IDENTITY
.
type
());
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
if
(
mh
!=
null
)
{
cache
.
put
(
wrap
,
mh
);
...
...
@@ -418,8 +467,8 @@ public class ValueConversions {
throw
new
IllegalArgumentException
(
"cannot find rebox adapter for "
+
wrap
);
}
public
static
MethodHandle
rebox
(
Class
<?>
type
,
boolean
exact
)
{
return
rebox
(
Wrapper
.
forPrimitiveType
(
type
)
,
exact
);
public
static
MethodHandle
rebox
(
Class
<?>
type
)
{
return
rebox
(
Wrapper
.
forPrimitiveType
(
type
));
}
/// Width-changing conversions between int and long.
...
...
@@ -486,9 +535,10 @@ public class ValueConversions {
case
VOID:
mh
=
EMPTY
;
break
;
case
OBJECT:
case
INT:
case
LONG:
case
FLOAT:
case
DOUBLE:
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zero"
+
wrap
.
simpleName
(),
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"zero"
+
wrap
.
simpleName
(),
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
...
...
@@ -592,7 +642,7 @@ public class ValueConversions {
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
{
try
{
MethodType
idType
=
MethodType
.
genericMethodType
(
1
);
...
...
@@ -600,40 +650,56 @@ public class ValueConversions {
MethodType
alwaysZeroType
=
idType
.
changeReturnType
(
int
.
class
);
MethodType
ignoreType
=
idType
.
changeReturnType
(
void
.
class
);
MethodType
zeroObjectType
=
MethodType
.
genericMethodType
(
0
);
IDENTITY
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
idType
);
IDENTITY_I
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
class
));
IDENTITY_J
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
MethodType
.
methodType
(
long
.
class
,
long
.
class
));
IDENTITY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
idType
);
IDENTITY_I
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
MethodType
.
methodType
(
int
.
class
,
int
.
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
.
findStatic
(
ValueConversions
.
class
,
"castReference"
,
castType
);
ALWAYS_NULL
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"alwaysNull"
,
idType
);
ALWAYS_ZERO
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"alwaysZero"
,
alwaysZeroType
);
ZERO_OBJECT
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"zeroObject"
,
zeroObjectType
);
IGNORE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"ignore"
,
ignoreType
);
EMPTY
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"empty"
,
ignoreType
.
dropParameterTypes
(
0
,
1
));
}
catch
(
Exception
ex
)
{
CAST_REFERENCE
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"castReference"
,
castType
);
ALWAYS_NULL
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"alwaysNull"
,
idType
);
ALWAYS_ZERO
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"alwaysZero"
,
alwaysZeroType
);
ZERO_OBJECT
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"zeroObject"
,
zeroObjectType
);
IGNORE
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"ignore"
,
ignoreType
);
EMPTY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"empty"
,
ignoreType
.
dropParameterTypes
(
0
,
1
));
NEW_ARRAY
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"newArray"
,
MethodType
.
methodType
(
Object
[].
class
,
int
.
class
));
}
catch
(
NoSuchMethodException
|
IllegalAccessException
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
throw
err
;
}
}
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>
WRAPPER_CASTS
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
// Varargs methods need to be in a separately initialized class, to bootstrapping problems.
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
=
new
EnumMap
<
Wrapper
,
MethodHandle
>(
Wrapper
.
class
);
private
static
final
EnumMap
<
Wrapper
,
MethodHandle
>
[]
WRAPPER_CASTS
=
new
WrapperCaches
(
2
);
/** 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).
*/
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
);
MethodHandle
mh
=
null
;
Wrapper
wrap
=
null
;
EnumMap
<
Wrapper
,
MethodHandle
>
cache
=
null
;
if
(
Wrapper
.
isWrapperType
(
type
))
{
wrap
=
Wrapper
.
forWrapperType
(
type
);
cache
=
(
exact
?
EXACT_WRAPPER_CASTS
:
WRAPPER_CASTS
)
;
cache
=
WRAPPER_CASTS
[
exact
?
1
:
0
]
;
mh
=
cache
.
get
(
wrap
);
if
(
mh
!=
null
)
return
mh
;
}
...
...
@@ -673,7 +739,7 @@ public class ValueConversions {
if
(
wrap
!=
Wrapper
.
VOID
)
type
=
type
.
appendParameterTypes
(
wrap
.
primitiveType
());
try
{
mh
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"identity"
,
type
);
mh
=
IMPL_LOOKUP
.
findStatic
(
THIS_CLASS
,
"identity"
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
mh
=
null
;
}
...
...
@@ -692,6 +758,210 @@ public class ValueConversions {
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
Object
[]
makeArray
(
Object
...
args
)
{
return
args
;
}
private
static
Object
[]
array
()
{
return
NO_ARGS_ARRAY
;
}
...
...
@@ -723,36 +993,176 @@ public class ValueConversions {
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
,
Object
a9
)
{
return
makeArray
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
static
MethodHandle
[]
makeArrays
()
{
ArrayList
<
MethodHandle
>
arrays
=
new
ArrayList
<
MethodHandle
>();
MethodHandles
.
Lookup
lookup
=
IMPL_LOOKUP
;
private
static
MethodHandle
[]
makeArrays
()
{
ArrayList
<
MethodHandle
>
mhs
=
new
ArrayList
<>();
for
(;;)
{
int
nargs
=
arrays
.
size
();
MethodType
type
=
MethodType
.
genericMethodType
(
nargs
).
changeReturnType
(
Object
[].
class
);
String
name
=
"array"
;
MethodHandle
array
=
null
;
try
{
array
=
lookup
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
if
(
array
==
null
)
break
;
arrays
.
add
(
array
);
MethodHandle
mh
=
findCollector
(
"array"
,
mhs
.
size
(),
Object
[].
class
);
if
(
mh
==
null
)
break
;
mhs
.
add
(
mh
);
}
assert
(
arrays
.
size
()
==
11
);
// current number of methods
return
arrays
.
toArray
(
new
MethodHandle
[
0
]);
assert
(
mhs
.
size
()
==
11
);
// current number of methods
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
* arguments and returns an Object array of them, as if for varargs.
*/
public
static
MethodHandle
varargsArray
(
int
nargs
)
{
if
(
nargs
<
ARRAYS
.
length
)
return
ARRAYS
[
nargs
];
// else need to spin bytecode or do something else fancy
throw
new
UnsupportedOperationException
(
"NYI: cannot form a varargs array of length "
+
nargs
);
MethodHandle
mh
=
ARRAYS
[
nargs
];
if
(
mh
!=
null
)
return
mh
;
mh
=
findCollector
(
"array"
,
nargs
,
Object
[].
class
);
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
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
private
static
List
<
Object
>
list
()
{
return
NO_ARGS_LIST
;
}
...
...
@@ -784,34 +1194,29 @@ public class ValueConversions {
Object
a4
,
Object
a5
,
Object
a6
,
Object
a7
,
Object
a8
,
Object
a9
)
{
return
makeList
(
a0
,
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
);
}
static
MethodHandle
[]
makeLists
()
{
ArrayList
<
MethodHandle
>
arrays
=
new
ArrayList
<
MethodHandle
>();
MethodHandles
.
Lookup
lookup
=
IMPL_LOOKUP
;
private
static
MethodHandle
[]
makeLists
()
{
ArrayList
<
MethodHandle
>
mhs
=
new
ArrayList
<>();
for
(;;)
{
int
nargs
=
arrays
.
size
();
MethodType
type
=
MethodType
.
genericMethodType
(
nargs
).
changeReturnType
(
List
.
class
);
String
name
=
"list"
;
MethodHandle
array
=
null
;
try
{
array
=
lookup
.
findStatic
(
ValueConversions
.
class
,
name
,
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
}
if
(
array
==
null
)
break
;
arrays
.
add
(
array
);
MethodHandle
mh
=
findCollector
(
"list"
,
mhs
.
size
(),
List
.
class
);
if
(
mh
==
null
)
break
;
mhs
.
add
(
mh
);
}
assert
(
array
s
.
size
()
==
11
);
// current number of methods
return
arrays
.
toArray
(
new
MethodHandle
[
0
]);
assert
(
mh
s
.
size
()
==
11
);
// current number of methods
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
* arguments and returns List.
* arguments and returns
a
List.
*/
public
static
MethodHandle
varargsList
(
int
nargs
)
{
if
(
nargs
<
LISTS
.
length
)
return
LISTS
[
nargs
];
// else need to spin bytecode or do something else fancy
throw
new
UnsupportedOperationException
(
"NYI"
);
MethodHandle
mh
=
LISTS
[
nargs
];
if
(
mh
!=
null
)
return
mh
;
mh
=
findCollector
(
"list"
,
nargs
,
List
.
class
);
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 {
if
(
dst
==
void
.
class
)
return
true
;
// drop any return value
if
(
isNullType
(
src
))
return
!
dst
.
isPrimitive
();
if
(!
src
.
isPrimitive
())
return
dst
.
isAssignableFrom
(
src
);
if
(!
dst
.
isPrimitive
())
return
false
;
// Verifier allows an int to carry byte, short, char, or even boolean:
if
(
dst
==
int
.
class
)
return
Wrapper
.
forPrimitiveType
(
src
).
isSubwordOrInt
();
return
false
;
Wrapper
sw
=
Wrapper
.
forPrimitiveType
(
src
);
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 {
return
-
1
;
// truncation may be required
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
return
-
1
;
// sign elimination may be required
return
1
;
}
if
(
src
==
float
.
class
||
dst
==
float
.
class
)
{
if
(
src
==
double
.
class
||
dst
==
double
.
class
)
...
...
src/share/classes/sun/invoke/util/Wrapper.java
浏览文件 @
8c50098c
...
...
@@ -26,37 +26,47 @@
package
sun.invoke.util
;
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
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
Format
.
signed
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
Format
.
unsigned
(
16
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
Format
.
floating
(
64
)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
Format
.
other
(
1
)),
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
new
byte
[
0
],
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
new
short
[
0
],
Format
.
signed
(
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
,
new
int
[
0
],
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
new
long
[
0
],
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
new
float
[
0
],
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
new
double
[
0
],
Format
.
floating
(
64
)),
//NULL(Null.class, null.class, 'N', null,
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
(
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
<?>
primitiveType
;
private
final
char
basicTypeChar
;
private
final
Object
zero
;
private
final
Object
emptyArray
;
private
final
int
format
;
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
.
primitiveType
=
ptype
;
this
.
basicTypeChar
=
tchar
;
this
.
zero
=
zero
;
this
.
emptyArray
=
emptyArray
;
this
.
format
=
format
;
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
{
static
final
int
SLOT_SHIFT
=
0
,
SIZE_SHIFT
=
2
,
KIND_SHIFT
=
12
;
static
final
int
...
...
@@ -114,16 +124,18 @@ public enum Wrapper {
public
boolean
isUnsigned
()
{
return
format
>=
Format
.
BOOLEAN
&&
format
<
Format
.
FLOAT
;
}
/** Is the wrapped type either float or double? */
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?
* Cases:
* <ul>
* <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>conversion of {@code boolean} to any type
* </ul>
* These are the cases allowed by MethodHandle.asType and convertArguments.
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
...
...
@@ -131,13 +143,75 @@ public enum Wrapper {
// At best, this is a narrowing conversion.
return
false
;
}
if
((
this
.
format
^
source
.
format
)
==
(
Format
.
SHORT
^
Format
.
CHAR
))
{
assert
(
this
==
SHORT
&&
source
==
CHAR
)
||
(
this
==
CHAR
&&
source
==
SHORT
);
// All conversions are allowed in the enum order between floats and signed ints.
// 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
;
}
// All signed and float conversions in the enum order are widening.
assert
(
this
.
isFloating
()
||
this
.
isSigned
());
assert
(
source
.
isFloating
()
||
source
.
isSigned
());
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.
* This will be a numeric zero for a number or character,
* false for a boolean, and null for a reference or void.
...
...
@@ -549,7 +623,7 @@ public enum Wrapper {
}
private
static
boolean
boolValue
(
long
bits
)
{
//
bits &= 1; // simple 31-bit zero extension
bits
&=
1
;
// simple 31-bit zero extension
return
(
bits
!=
0
);
}
...
...
@@ -559,4 +633,31 @@ public enum Wrapper {
private
static
RuntimeException
newIllegalArgumentException
(
String
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 {
final
ParallelogramPipe
realpipe
=
oglr
.
getAAParallelogramPipe
();
return
new
ParallelogramPipe
()
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLFillAAParallelogram"
);
realpipe
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
@@ -118,6 +123,7 @@ class OGLRenderer extends BufferedRenderPipe {
{
GraphicsPrimitive
.
tracePrimitive
(
"OGLDrawAAParallelogram"
);
realpipe
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
}
...
...
@@ -166,21 +172,29 @@ class OGLRenderer extends BufferedRenderPipe {
oglr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
{
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
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
lw1
,
double
lw2
)
{
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
,
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
renderPath
(
sg
,
s
,
null
);
}
private
static
Rectangle2D
computeBBox
(
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
private
static
Rectangle2D
computeBBox
(
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
)
{
double
lox
,
loy
,
hix
,
hiy
;
lox
=
hix
=
x
;
loy
=
hiy
=
y
;
if
(
dx1
<
0
)
{
lox
+=
dx1
;
}
else
{
hix
+=
dx1
;
}
if
(
dy1
<
0
)
{
loy
+=
dy1
;
}
else
{
hiy
+=
dy1
;
}
if
(
dx2
<
0
)
{
lox
+=
dx2
;
}
else
{
hix
+=
dx2
;
}
if
(
dy2
<
0
)
{
loy
+=
dy2
;
}
else
{
hiy
+=
dy2
;
}
return
new
Rectangle2D
.
Double
(
lox
,
loy
,
hix
-
lox
,
hiy
-
loy
);
if
((
ux2
-=
ux1
)
<
0
)
{
ux1
+=
ux2
;
ux2
=
-
ux2
;
}
if
((
uy2
-=
uy1
)
<
0
)
{
uy1
+=
uy2
;
uy2
=
-
uy2
;
}
return
new
Rectangle2D
.
Double
(
ux1
,
uy1
,
ux2
,
uy2
);
}
public
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
...
...
@@ -97,10 +99,12 @@ public class AAShapePipe
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
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
@@ -118,7 +122,7 @@ public class AAShapePipe
// Note that bbox is of the original shape, not the wide path.
// 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
;
...
...
src/share/classes/sun/java2d/pipe/AlphaColorPipe.java
浏览文件 @
8c50098c
...
...
@@ -66,6 +66,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
}
public
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
...
...
@@ -75,6 +77,8 @@ public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
}
public
void
drawParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/BufferedRenderPipe.java
浏览文件 @
8c50098c
...
...
@@ -408,6 +408,8 @@ public abstract class BufferedRenderPipe
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
...
...
@@ -429,6 +431,8 @@ public abstract class BufferedRenderPipe
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
@@ -454,6 +458,8 @@ public abstract class BufferedRenderPipe
private
class
AAParallelogramPipe
implements
ParallelogramPipe
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
...
...
@@ -475,6 +481,8 @@ public abstract class BufferedRenderPipe
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/LoopPipe.java
浏览文件 @
8c50098c
...
...
@@ -352,6 +352,8 @@ public class LoopPipe
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
...
...
@@ -362,6 +364,8 @@ public class LoopPipe
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
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.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -40,9 +40,17 @@ import sun.java2d.SunGraphics2D;
* => (x+dx2, y+dy2)
* => origin
* </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
void
fillParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
);
...
...
@@ -59,6 +67,8 @@ public interface ParallelogramPipe {
* difference between the outer and inner parallelograms.
*/
public
void
drawParallelogram
(
SunGraphics2D
sg
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java
浏览文件 @
8c50098c
...
...
@@ -175,8 +175,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
}
public
boolean
drawGeneralLine
(
SunGraphics2D
sg2d
,
double
x1
,
double
y1
,
double
x2
,
double
y2
)
double
ux1
,
double
u
y1
,
double
ux2
,
double
u
y2
)
{
if
(
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_CUSTOM
||
sg2d
.
strokeState
==
SunGraphics2D
.
STROKE_THINDASHED
)
...
...
@@ -194,13 +194,14 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
double
lw
=
bs
.
getLineWidth
();
// Save the original dx, dy in case we need it to transform
// the linewidth as a perpendicular vector below
double
dx
=
x2
-
x1
;
double
dy
=
y2
-
y1
;
double
dx
=
ux2
-
ux1
;
double
dy
=
uy2
-
uy1
;
double
x1
,
y1
,
x2
,
y2
;
switch
(
sg2d
.
transformState
)
{
case
SunGraphics2D
.
TRANSFORM_GENERIC
:
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
);
x1
=
coords
[
0
];
y1
=
coords
[
1
];
...
...
@@ -213,13 +214,17 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
{
double
tx
=
sg2d
.
transform
.
getTranslateX
();
double
ty
=
sg2d
.
transform
.
getTranslateY
();
x1
+=
tx
;
y1
+=
ty
;
x2
+=
tx
;
y2
+=
ty
;
x1
=
ux1
+
tx
;
y1
=
uy1
+
ty
;
x2
=
ux2
+
tx
;
y2
=
uy2
+
ty
;
}
break
;
case
SunGraphics2D
.
TRANSFORM_ISIDENT
:
x1
=
ux1
;
y1
=
uy1
;
x2
=
ux2
;
y2
=
uy2
;
break
;
default
:
throw
new
InternalError
(
"unknown TRANSFORM state..."
);
...
...
@@ -279,7 +284,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
dx
+=
udx
;
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
;
}
...
...
@@ -313,7 +319,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
px
=
newx
;
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
,
...
...
@@ -360,10 +367,12 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
// entire hole in the middle of the parallelogram
// so we can just fill the outer parallelogram.
fillOuterParallelogram
(
sg2d
,
rx
,
ry
,
rx
+
rw
,
ry
+
rh
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
len1
,
len2
,
lw1
,
lw2
);
}
else
{
outrenderer
.
drawParallelogram
(
sg2d
,
rx
,
ry
,
rx
+
rw
,
ry
+
rh
,
px
,
py
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
/
len1
,
lw2
/
len2
);
}
...
...
@@ -377,6 +386,8 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
* and issues a single fillParallelogram request to fill it.
*/
public
void
fillOuterParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
px
,
double
py
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
@@ -412,6 +423,7 @@ public class PixelToParallelogramConverter extends PixelToShapeConverter
dx2
+=
udx2
;
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 {
verifyValidPara
();
verifyRange
(
start
,
0
,
limit
);
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
);
}
...
...
src/solaris/classes/sun/awt/X11/XRobotPeer.java
浏览文件 @
8c50098c
...
...
@@ -48,7 +48,7 @@ class XRobotPeer implements RobotPeer {
}
public
void
dispose
()
{
_dispose
();
// does nothing
}
public
void
mouseMove
(
int
x
,
int
y
)
{
...
...
@@ -88,7 +88,6 @@ class XRobotPeer implements RobotPeer {
}
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
mousePressImpl
(
int
buttons
);
...
...
src/solaris/native/sun/awt/awt_Robot.c
浏览文件 @
8c50098c
...
...
@@ -48,28 +48,12 @@
#ifdef __linux__
#include <sys/socket.h>
#endif
#include <dlfcn.h>
extern
struct
X11GraphicsConfigIDs
x11GraphicsConfigIDs
;
static
jint
*
masks
;
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
()
{
int32_t
major_opcode
,
first_event
,
first_error
;
int32_t
event_basep
,
error_basep
,
majorp
,
minorp
;
...
...
@@ -210,80 +194,8 @@ Java_sun_awt_X11_XRobotPeer_setup (JNIEnv * env, jclass cls, jint numberOfButton
}
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
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
* to parent process.
*/
Window
w
indow
;
Window
rootW
indow
;
AwtGraphicsConfigDataPtr
adata
;
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,
adata
=
(
AwtGraphicsConfigDataPtr
)
JNU_GetLongFieldAsPtr
(
env
,
xgc
,
x11GraphicsConfigIDs
.
aData
);
DASSERT
(
adata
!=
NULL
);
window
=
XRootWindow
(
awt_display
,
adata
->
awt_visInfo
.
screen
);
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
);
rootWindow
=
XRootWindow
(
awt_display
,
adata
->
awt_visInfo
.
screen
);
image
=
getWindowImage
(
awt_display
,
rootWindow
,
x
,
y
,
width
,
height
);
/* Array to use to crunch around the pixel values */
ary
=
(
jint
*
)
malloc
(
width
*
height
*
sizeof
(
jint
));
if
(
ary
==
NULL
)
{
JNU_ThrowOutOfMemoryError
(
env
,
"OutOfMemoryError"
);
XDestroyImage
(
image
);
if
(
IsXCompositeAvailable
())
{
XCompositeReleaseOverlayWindow
(
awt_display
,
window
);
}
AWT_UNLOCK
();
return
;
}
...
...
@@ -354,9 +256,6 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
free
(
ary
);
XDestroyImage
(
image
);
if
(
IsXCompositeAvailable
())
{
XCompositeReleaseOverlayWindow
(
awt_display
,
window
);
}
AWT_UNLOCK
();
}
...
...
src/windows/classes/sun/awt/windows/WFramePeer.java
浏览文件 @
8c50098c
...
...
@@ -107,8 +107,16 @@ class WFramePeer extends WWindowPeer implements FramePeer {
Rectangle
currentDevBounds
=
currentDevGC
.
getBounds
();
Rectangle
primaryDevBounds
=
primaryDevGC
.
getBounds
();
b
.
width
-=
(
currentDevBounds
.
width
-
primaryDevBounds
.
width
);
b
.
height
-=
(
currentDevBounds
.
height
-
primaryDevBounds
.
height
);
boolean
isCurrentDevLarger
=
((
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 {
final
ParallelogramPipe
realpipe
=
d3dr
.
getAAParallelogramPipe
();
return
new
ParallelogramPipe
()
{
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DFillAAParallelogram"
);
realpipe
.
fillParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
);
}
public
void
drawParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
...
...
@@ -118,6 +123,7 @@ class D3DRenderer extends BufferedRenderPipe {
{
GraphicsPrimitive
.
tracePrimitive
(
"D3DDrawAAParallelogram"
);
realpipe
.
drawParallelogram
(
sg2d
,
ux1
,
uy1
,
ux2
,
uy2
,
x
,
y
,
dx1
,
dy1
,
dx2
,
dy2
,
lw1
,
lw2
);
}
...
...
@@ -167,21 +173,29 @@ class D3DRenderer extends BufferedRenderPipe {
d3dr
.
fillSpans
(
sg2d
,
si
,
transx
,
transy
);
}
public
void
fillParallelogram
(
SunGraphics2D
sg2d
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
)
{
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
,
double
ux1
,
double
uy1
,
double
ux2
,
double
uy2
,
double
x
,
double
y
,
double
dx1
,
double
dy1
,
double
dx2
,
double
dy2
,
double
lw1
,
double
lw2
)
{
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
,
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,
pMgr
=
D3DPipelineManager
::
GetInstance
();
RETURN_IF_NULL
(
pMgr
);
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
);
JNU_CallStaticMethodByName
(
env
,
NULL
,
...
...
src/windows/native/sun/windows/Devices.h
浏览文件 @
8c50098c
...
...
@@ -36,6 +36,7 @@ class AwtWin32GraphicsDevice;
class
Devices
{
public:
static
Devices
*
GetInstance
();
static
BOOL
UpdateInstance
(
JNIEnv
*
env
);
int
GetNumDevices
()
{
return
numDevices
;
}
AwtWin32GraphicsDevice
*
GetDeviceReference
(
int
index
,
BOOL
adjust
=
TRUE
);
...
...
@@ -59,7 +60,6 @@ friend class InstanceAccess;
private:
Devices
(
int
numElements
);
void
AddReference
();
static
Devices
*
GetInstance
();
AwtWin32GraphicsDevice
**
devices
;
int
refCount
;
...
...
src/windows/native/sun/windows/awt_Choice.cpp
浏览文件 @
8c50098c
...
...
@@ -396,6 +396,12 @@ LRESULT CALLBACK AwtChoice::ListWindowProc(HWND hwnd, UINT message,
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
)
{
case
WM_LBUTTONDOWN
:
{
DWORD
curPos
=
::
GetMessagePos
();
...
...
src/windows/native/sun/windows/awt_Component.cpp
浏览文件 @
8c50098c
...
...
@@ -364,7 +364,6 @@ AwtComponent* AwtComponent::GetComponentImpl(HWND hWnd) {
AwtComponent
*
component
=
(
AwtComponent
*
)
::
GetWindowLongPtr
(
hWnd
,
GWLP_USERDATA
);
DASSERT
(
!
component
||
!
IsBadReadPtr
(
component
,
sizeof
(
AwtComponent
))
);
DASSERT
(
!
component
||
component
->
GetHWnd
()
==
hWnd
);
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
SetImeTargetComponent
(
NULL
);
}
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
:
if
(
sm_inSynthesizeFocus
)
break
;
// pass it up the WindowProc chain
...
...
test/java/awt/Component/Revalidate/Revalidate.java
浏览文件 @
8c50098c
...
...
@@ -26,7 +26,7 @@
@bug 7036669
@summary Test Component.revalidate() method
@author anthony.petrov@oracle.com: area=awt.component
@run main Revalidate
@run main
/othervm -Djava.awt.smartInvalidate=true
Revalidate
*/
import
java.awt.*
;
...
...
test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java
浏览文件 @
8c50098c
...
...
@@ -26,7 +26,7 @@
@bug 6852592
@summary invalidate() must stop when it encounters a validate root
@author anthony.petrov@sun.com
@run main InvalidateMustRespectValidateRoots
@run main
/othervm -Djava.awt.smartInvalidate=true
InvalidateMustRespectValidateRoots
*/
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 @@
*/
/* @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
* @run junit/othervm test.java.lang.invoke.InvokeGenericTest
*/
...
...
@@ -53,6 +53,10 @@ public class InvokeGenericTest {
if
(
vstr
!=
null
)
verbosity
=
Integer
.
parseInt
(
vstr
);
}
public
static
void
main
(
String
...
av
)
throws
Throwable
{
new
InvokeGenericTest
().
testFirst
();
}
@Test
public
void
testFirst
()
throws
Throwable
{
verbosity
+=
9
;
try
{
...
...
@@ -103,7 +107,7 @@ public class InvokeGenericTest {
void
startTest
(
String
name
)
{
if
(
testName
!=
null
)
printCounts
();
if
(
verbosity
>=
1
)
System
.
out
.
println
(
name
);
System
.
out
.
println
(
"["
+
name
+
"]"
);
posTests
=
negTests
=
0
;
testName
=
name
;
}
...
...
@@ -350,6 +354,30 @@ public class InvokeGenericTest {
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
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
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
...
...
@@ -388,24 +416,24 @@ public class InvokeGenericTest {
try
{
switch
(
args
.
length
)
{
case
0
:
junk
=
target
.
invoke
Generic
();
break
;
junk
=
target
.
invoke
();
break
;
case
1
:
junk
=
target
.
invoke
Generic
(
args
[
0
]);
break
;
junk
=
target
.
invoke
(
args
[
0
]);
break
;
case
2
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
]);
break
;
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
:
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
:
junk
=
target
.
invokeWithArguments
(
args
);
break
;
}
}
catch
(
WrongMethodTypeException
ex
)
{
return
;
}
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.
...
...
@@ -451,7 +479,7 @@ public class InvokeGenericTest {
startTest
(
"testReferenceConversions"
);
toString_MH
=
LOOKUP
.
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
))
{
testReferenceConversions
(
type
,
args
);
}
...
...
@@ -463,7 +491,7 @@ public class InvokeGenericTest {
MethodHandle
tsdrop
=
MethodHandles
.
dropArguments
(
toString_MH
,
1
,
type
.
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
tsdrop
,
mh
);
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);
assertEquals
(
Arrays
.
asList
(
args
).
toString
(),
res
);
}
...
...
@@ -473,10 +501,10 @@ public class InvokeGenericTest {
public
void
testBoxConversions
()
throws
Throwable
{
startTest
(
"testBoxConversions"
);
countTest
();
Integer
[]
args
=
{
1
,
2
};
Object
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
int
.
class
);
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);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
...
...
test/java/lang/invoke/JavaDocExamplesTest.java
浏览文件 @
8c50098c
...
...
@@ -170,8 +170,8 @@ assert(s.equals("savvy"));
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
assert
(
mh
.
isVarargsCollector
());
x
=
mh
.
invoke
Generic
(
"one"
,
"two"
);
// invoke
Generic
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
x
=
mh
.
invoke
(
"one"
,
"two"
);
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)));
// mt is (Object,Object,Object)Object
mt
=
MethodType
.
genericMethodType
(
3
);
...
...
@@ -199,12 +199,12 @@ mh.invokeExact(System.out, "Hello, world.");
MethodHandle
asList
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
assertEquals
(
"[]"
,
asList
.
invoke
Generic
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
Generic
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
Generic
(
"two"
,
"too"
).
toString
());
assertEquals
(
"[]"
,
asList
.
invoke
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
(
"two"
,
"too"
).
toString
());
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
Generic
(
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
Generic
((
Object
)
argv
);
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
(
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
((
Object
)
argv
);
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
}}
...
...
@@ -218,9 +218,9 @@ MethodHandle vamh = publicLookup()
.
asVarargsCollector
(
Object
[].
class
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
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
;
try
{
mh
.
invoke
Generic
(
1
,
2
,
3
);
}
try
{
mh
.
invoke
(
1
,
2
,
3
);
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
assert
(
failed
);
{}
...
...
test/java/lang/invoke/MethodHandlesTest.java
浏览文件 @
8c50098c
...
...
@@ -105,24 +105,6 @@ public class 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
;
static
int
allPosTests
,
allNegTests
;
int
posTests
,
negTests
;
...
...
@@ -331,6 +313,9 @@ public class MethodHandlesTest {
static
MethodHandle
varargsArray
(
int
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. */
static
MethodHandle
varargsList
(
int
arity
,
Class
<?>
rtype
)
{
MethodHandle
list
=
varargsList
(
arity
);
...
...
@@ -865,7 +850,7 @@ public class MethodHandlesTest {
Class
<?>
type
=
(
Class
<?>)
t
[
1
];
Object
value
;
Field
field
;
try
{
try
{
field
=
HasFields
.
class
.
getDeclaredField
(
name
);
}
catch
(
Exception
ex
)
{
throw
new
InternalError
(
"no field HasFields."
+
name
);
...
...
@@ -1144,16 +1129,9 @@ public class MethodHandlesTest {
:
MethodHandles
.
arrayElementSetter
(
arrayType
);
assertSame
(
mh
.
type
(),
expType
);
if
(
elemType
!=
int
.
class
&&
elemType
!=
boolean
.
class
)
{
MethodType
gtype
;
if
(
true
)
{
// FIXME: remove this path (and remove <void> below in the mh.invokes)
gtype
=
mh
.
type
().
changeParameterType
(
0
,
Object
.
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
);
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
MethodType
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
Integer
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeReturnType
(
void
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
}
Object
sawValue
,
expValue
;
...
...
@@ -1169,7 +1147,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
mh
.
invokeExact
((
boolean
[])
array
,
i
,
(
boolean
)
random
);
else
mh
.
invokeExact
(
array
,
i
,
random
);
mh
.
invokeExact
(
array
,
(
Integer
)
i
,
random
);
assertEquals
(
model
,
array2list
(
array
));
}
else
{
Array
.
set
(
array
,
i
,
random
);
...
...
@@ -1189,7 +1167,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
sawValue
=
(
boolean
)
mh
.
invokeExact
((
boolean
[])
array
,
i
);
else
sawValue
=
mh
.
invokeExact
(
array
,
i
);
sawValue
=
mh
.
invokeExact
(
array
,
(
Integer
)
i
);
assertEquals
(
sawValue
,
expValue
);
assertEquals
(
model
,
array2list
(
array
));
}
...
...
@@ -1341,21 +1319,15 @@ public class MethodHandlesTest {
int
numcases
=
1
;
for
(
int
outargs
=
0
;
outargs
<=
max
;
outargs
++)
{
if
(
outargs
-
inargs
>=
MAX_ARG_INCREASE
)
continue
;
int
[]
reorder
=
new
int
[
outargs
];
int
casStep
=
dilution
+
1
;
// Avoid some common factors:
while
((
casStep
>
2
&&
casStep
%
2
==
0
&&
inargs
%
2
==
0
)
||
(
casStep
>
3
&&
casStep
%
3
==
0
&&
inargs
%
3
==
0
))
casStep
++;
for
(
int
cas
=
0
;
cas
<
numcases
;
cas
+=
casStep
)
{
for
(
int
i
=
0
,
c
=
cas
;
i
<
outargs
;
i
++)
{
reorder
[
i
]
=
c
%
inargs
;
c
/=
inargs
;
}
testPermuteArguments
(
args
,
types
,
reorder
);
}
testPermuteArguments
(
args
,
types
,
outargs
,
numcases
,
casStep
);
numcases
*=
inargs
;
if
(
dilution
>
10
&&
outargs
>=
4
)
{
int
[]
reorder
=
new
int
[
outargs
];
// Do some special patterns, which we probably missed.
// Replication of a single argument or argument pair.
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
...
...
@@ -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
)
{
reorder
=
reorder
.
clone
();
for
(
int
i
=
0
,
imax
=
reorder
.
length
/
2
;
i
<
imax
;
i
++)
{
...
...
@@ -1433,6 +1418,12 @@ public class MethodHandlesTest {
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
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
);
}
...
...
@@ -1456,26 +1447,27 @@ public class MethodHandlesTest {
}
public
void
testSpreadArguments
(
Class
<?>
argType
,
int
pos
,
int
nargs
)
throws
Throwable
{
countTest
();
MethodHandle
target
=
varargsArray
(
nargs
);
MethodHandle
target2
=
changeArgTypes
(
target
,
argType
);
Class
<?>
arrayType
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
argType
,
0
).
getClass
();
MethodHandle
target2
=
varargsArray
(
arrayType
,
nargs
);
MethodHandle
target
=
target2
.
asType
(
target2
.
type
().
generic
());
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"spread into "
+
target2
+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
// make sure the target does what we think it does:
if
(
pos
==
0
&&
nargs
<
5
)
{
Object
[]
check
=
(
Object
[])
target
.
invokeWithArguments
(
args
);
if
(
pos
==
0
&&
nargs
<
5
&&
!
argType
.
isPrimitive
()
)
{
Object
[]
check
=
(
Object
[])
(
Object
)
target
.
invokeWithArguments
(
args
);
assertArrayEquals
(
args
,
check
);
switch
(
nargs
)
{
case
0
:
check
=
(
Object
[])
target
.
invokeExact
();
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
();
assertArrayEquals
(
args
,
check
);
break
;
case
1
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
]);
assertArrayEquals
(
args
,
check
);
break
;
case
2
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
assertArrayEquals
(
args
,
check
);
break
;
}
...
...
@@ -1483,23 +1475,50 @@ public class MethodHandlesTest {
List
<
Class
<?>>
newParams
=
new
ArrayList
<
Class
<?>>(
target2
.
type
().
parameterList
());
{
// modify newParams in place
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
);
MethodHandle
result
=
target2
.
asSpreader
(
Object
[].
class
,
nargs
-
pos
).
asType
(
newType
);
Object
[]
returnValue
;
MethodType
newType
=
MethodType
.
methodType
(
arrayType
,
newParams
);
MethodHandle
result
=
target2
.
asSpreader
(
arrayType
,
nargs
-
pos
);
assert
(
result
.
type
()
==
newType
)
:
Arrays
.
asList
(
result
,
newType
);
result
=
result
.
asType
(
newType
.
generic
());
Object
returnValue
;
if
(
pos
==
0
)
{
// In the following line, the first cast implies
// normal Object return value for the MH call (Object[])->Object,
// 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
);
Object
args2
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
returnValue
=
result
.
invokeExact
(
args2
);
}
else
{
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
returnValue
=
(
Object
[])
result
.
invokeWithArguments
(
args1
);
args1
[
pos
]
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
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
...
...
@@ -1780,7 +1799,7 @@ public class MethodHandlesTest {
assertCalled
(
"invokee"
,
args
);
// generic invoker
countTest
();
inv
=
MethodHandles
.
genericI
nvoker
(
type
);
inv
=
MethodHandles
.
i
nvoker
(
type
);
if
(
nargs
<=
3
)
{
calledLog
.
clear
();
switch
(
nargs
)
{
...
...
@@ -2130,15 +2149,12 @@ public class MethodHandlesTest {
Object
z
=
surprise
.
invokeExact
(
x
);
System
.
out
.
println
(
"Failed to throw; got z="
+
z
);
assertTrue
(
false
);
}
catch
(
Exception
ex
)
{
}
catch
(
ClassCast
Exception
ex
)
{
if
(
verbosity
>
2
)
System
.
out
.
println
(
"caught "
+
ex
);
if
(
verbosity
>
3
)
ex
.
printStackTrace
();
assertTrue
(
ex
instanceof
ClassCastException
// FIXME: accept only one of the two for any given unit test
||
ex
instanceof
WrongMethodTypeException
);
assertTrue
(
true
);
// all is well
}
}
...
...
@@ -2328,6 +2344,34 @@ class ValueConversions {
// else need to spin bytecode or do something else fancy
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
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.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -24,9 +24,17 @@
/* @test
@bug 6788484
@summary NPE in DefaultTableCellHeaderRenderer.getColumnSortOrder() with null table
@compile -XDignore.symbol.file=true bug6788484.java
@author Alexander Potochkin
@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
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录