Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
10995d86
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看板
体验新版 GitCode,发现更多精彩内容 >>
提交
10995d86
编写于
5月 27, 2011
作者:
J
jcoomes
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
cb4b28cf
32e3c0fa
变更
26
展开全部
隐藏空白更改
内联
并排
Showing
26 changed file
with
1637 addition
and
1172 deletion
+1637
-1172
src/share/classes/java/lang/BootstrapMethodError.java
src/share/classes/java/lang/BootstrapMethodError.java
+2
-2
src/share/classes/java/lang/ClassValue.java
src/share/classes/java/lang/ClassValue.java
+9
-1
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
+51
-13
src/share/classes/java/lang/invoke/BoundMethodHandle.java
src/share/classes/java/lang/invoke/BoundMethodHandle.java
+1
-1
src/share/classes/java/lang/invoke/CallSite.java
src/share/classes/java/lang/invoke/CallSite.java
+23
-3
src/share/classes/java/lang/invoke/ConstantCallSite.java
src/share/classes/java/lang/invoke/ConstantCallSite.java
+45
-2
src/share/classes/java/lang/invoke/Invokers.java
src/share/classes/java/lang/invoke/Invokers.java
+33
-19
src/share/classes/java/lang/invoke/MemberName.java
src/share/classes/java/lang/invoke/MemberName.java
+13
-3
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+285
-180
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+23
-12
src/share/classes/java/lang/invoke/MethodHandleNatives.java
src/share/classes/java/lang/invoke/MethodHandleNatives.java
+1
-1
src/share/classes/java/lang/invoke/MethodHandleProxies.java
src/share/classes/java/lang/invoke/MethodHandleProxies.java
+257
-0
src/share/classes/java/lang/invoke/MethodHandles.java
src/share/classes/java/lang/invoke/MethodHandles.java
+324
-531
src/share/classes/java/lang/invoke/MethodType.java
src/share/classes/java/lang/invoke/MethodType.java
+51
-7
src/share/classes/java/lang/invoke/MutableCallSite.java
src/share/classes/java/lang/invoke/MutableCallSite.java
+7
-4
src/share/classes/java/lang/invoke/SwitchPoint.java
src/share/classes/java/lang/invoke/SwitchPoint.java
+19
-4
src/share/classes/java/lang/invoke/package-info.java
src/share/classes/java/lang/invoke/package-info.java
+30
-292
src/share/classes/sun/invoke/util/ValueConversions.java
src/share/classes/sun/invoke/util/ValueConversions.java
+7
-4
src/share/classes/sun/invoke/util/VerifyAccess.java
src/share/classes/sun/invoke/util/VerifyAccess.java
+33
-7
src/share/classes/sun/invoke/util/Wrapper.java
src/share/classes/sun/invoke/util/Wrapper.java
+1
-1
test/java/lang/invoke/6998541/Test6998541.java
test/java/lang/invoke/6998541/Test6998541.java
+2
-10
test/java/lang/invoke/InvokeDynamicPrintArgs.java
test/java/lang/invoke/InvokeDynamicPrintArgs.java
+49
-10
test/java/lang/invoke/InvokeGenericTest.java
test/java/lang/invoke/InvokeGenericTest.java
+2
-2
test/java/lang/invoke/JavaDocExamplesTest.java
test/java/lang/invoke/JavaDocExamplesTest.java
+296
-24
test/java/lang/invoke/MethodHandlesTest.java
test/java/lang/invoke/MethodHandlesTest.java
+71
-39
test/java/lang/invoke/indify/Indify.java
test/java/lang/invoke/indify/Indify.java
+2
-0
未找到文件。
src/share/classes/java/lang/BootstrapMethodError.java
浏览文件 @
10995d86
...
...
@@ -39,14 +39,14 @@ public class BootstrapMethodError extends LinkageError {
private
static
final
long
serialVersionUID
=
292L
;
/**
* Constructs a
n
{@code BootstrapMethodError} with no detail message.
* Constructs a {@code BootstrapMethodError} with no detail message.
*/
public
BootstrapMethodError
()
{
super
();
}
/**
* Constructs a
n
{@code BootstrapMethodError} with the specified
* Constructs a {@code BootstrapMethodError} with the specified
* detail message.
*
* @param s the detail message.
...
...
src/share/classes/java/lang/ClassValue.java
浏览文件 @
10995d86
...
...
@@ -38,6 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* @since 1.7
*/
public
abstract
class
ClassValue
<
T
>
{
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected
ClassValue
()
{
}
/**
* Computes the given class's derived value for this {@code ClassValue}.
* <p>
...
...
@@ -100,7 +107,7 @@ public abstract class ClassValue<T> {
* If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
* This may result in an additional invocation of the
* {@code computeValue
computeValue
} method for the given class.
* {@code computeValue} method for the given class.
* <p>
* In order to explain the interaction between {@code get} and {@code remove} calls,
* we must model the state transitions of a class value to take into account
...
...
@@ -193,6 +200,7 @@ public abstract class ClassValue<T> {
=
new
WeakHashMap
<
Class
<?>,
ClassValueMap
>();
private
static
ClassValueMap
getMap
(
Class
<?>
type
)
{
type
.
getClass
();
// test for null
return
ROOT
.
get
(
type
);
}
...
...
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
浏览文件 @
10995d86
...
...
@@ -29,6 +29,8 @@ import sun.invoke.util.VerifyType;
import
sun.invoke.util.Wrapper
;
import
sun.invoke.util.ValueConversions
;
import
java.util.Arrays
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
static
java
.
lang
.
invoke
.
MethodHandleNatives
.
Constants
.*;
import
static
java
.
lang
.
invoke
.
MethodHandleStatics
.*;
...
...
@@ -62,7 +64,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by
MethodHandles.convertArguments
?
* argument conversions, as if by
fixed-arity MethodHandle.asType
?
*/
static
boolean
canPairwiseConvert
(
MethodType
newType
,
MethodType
oldType
,
int
level
)
{
// same number of args, of course
...
...
@@ -92,7 +94,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by
MethodHandles.convertArguments
?
* argument conversion, as if by
fixed-arity MethodHandle.asType
?
*/
static
boolean
canConvertArgument
(
Class
<?>
src
,
Class
<?>
dst
,
int
level
)
{
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
...
...
@@ -550,6 +552,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int
last
=
type
.
parameterCount
()
-
1
;
if
(
type
.
parameterType
(
last
)
!=
arrayType
)
target
=
target
.
asType
(
type
.
changeParameterType
(
last
,
arrayType
));
target
=
target
.
asFixedArity
();
// make sure this attribute is turned off
return
new
AsVarargsCollector
(
target
,
arrayType
);
}
...
...
@@ -570,6 +573,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
return
true
;
}
@Override
public
MethodHandle
asFixedArity
()
{
return
target
;
}
@Override
public
MethodHandle
asType
(
MethodType
newType
)
{
MethodType
type
=
this
.
type
();
...
...
@@ -594,14 +602,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
cache
=
collector
;
return
collector
.
asType
(
newType
);
}
@Override
public
MethodHandle
asVarargsCollector
(
Class
<?>
arrayType
)
{
MethodType
type
=
this
.
type
();
if
(
type
.
parameterType
(
type
.
parameterCount
()-
1
)
==
arrayType
)
return
this
;
return
super
.
asVarargsCollector
(
arrayType
);
}
}
/** Can a checkcast adapter validly convert the target to newType?
...
...
@@ -747,8 +747,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(!
canUnboxArgument
(
newType
,
oldType
,
arg
,
convType
,
level
))
return
null
;
MethodType
castDone
=
newType
;
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
if
(!
VerifyType
.
isNullConversion
(
src
,
boxType
))
{
// Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
if
(
level
!=
0
)
{
// must include additional conversions
if
(
src
==
Object
.
class
||
!
Wrapper
.
isWrapperType
(
src
))
{
// src must be examined at runtime, to detect Byte, Character, etc.
MethodHandle
unboxMethod
=
(
level
==
1
?
ValueConversions
.
unbox
(
dst
)
:
ValueConversions
.
unboxCast
(
dst
));
long
conv
=
makeConv
(
OP_COLLECT_ARGS
,
arg
,
basicType
(
src
),
basicType
(
dst
));
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
,
unboxMethod
);
}
// Example: Byte->int
// Do this by reformulating the problem to Byte->byte.
Class
<?>
srcPrim
=
Wrapper
.
forWrapperType
(
src
).
primitiveType
();
MethodType
midType
=
newType
.
changeParameterType
(
arg
,
srcPrim
);
MethodHandle
fixPrim
;
// makePairwiseConvert(midType, target, 0);
if
(
canPrimCast
(
midType
,
oldType
,
arg
,
dst
))
fixPrim
=
makePrimCast
(
midType
,
target
,
arg
,
dst
);
else
fixPrim
=
target
;
return
makeUnboxArgument
(
newType
,
fixPrim
,
arg
,
srcPrim
,
0
);
}
castDone
=
newType
.
changeParameterType
(
arg
,
boxType
);
}
long
conv
=
makeConv
(
OP_REF_TO_PRIM
,
arg
,
T_OBJECT
,
basicType
(
primType
));
MethodHandle
adapter
=
new
AdapterMethodHandle
(
target
,
castDone
,
conv
,
boxType
);
if
(
castDone
==
newType
)
...
...
@@ -917,6 +940,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
if
(
swapArg1
==
swapArg2
)
return
target
;
if
(
swapArg1
>
swapArg2
)
{
int
t
=
swapArg1
;
swapArg1
=
swapArg2
;
swapArg2
=
t
;
}
if
(
type2size
(
newType
.
parameterType
(
swapArg1
))
!=
type2size
(
newType
.
parameterType
(
swapArg2
)))
{
// turn a swap into a pair of rotates:
// [x a b c y] => [a b c y x] => [y a b c x]
int
argc
=
swapArg2
-
swapArg1
+
1
;
final
int
ROT
=
1
;
ArrayList
<
Class
<?>>
rot1Params
=
new
ArrayList
<
Class
<?>>(
target
.
type
().
parameterList
());
Collections
.
rotate
(
rot1Params
.
subList
(
swapArg1
,
swapArg1
+
argc
),
-
ROT
);
MethodType
rot1Type
=
MethodType
.
methodType
(
target
.
type
().
returnType
(),
rot1Params
);
MethodHandle
rot1
=
makeRotateArguments
(
rot1Type
,
target
,
swapArg1
,
argc
,
+
ROT
);
if
(
argc
==
2
)
return
rot1
;
MethodHandle
rot2
=
makeRotateArguments
(
newType
,
rot1
,
swapArg1
,
argc
-
1
,
-
ROT
);
return
rot2
;
}
if
(!
canSwapArguments
(
newType
,
target
.
type
(),
swapArg1
,
swapArg2
))
return
null
;
Class
<?>
swapType
=
newType
.
parameterType
(
swapArg1
);
...
...
@@ -946,7 +983,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
static
boolean
canRotateArguments
(
MethodType
newType
,
MethodType
targetType
,
int
firstArg
,
int
argCount
,
int
rotateBy
)
{
if
(!
convOpSupported
(
OP_ROT_ARGS
))
return
false
;
if
(
argCount
<=
2
)
return
false
;
// must be a swap, not a rotate
rotateBy
=
positiveRotation
(
argCount
,
rotateBy
);
if
(
rotateBy
==
0
)
return
false
;
// no rotation
if
(
rotateBy
>
MAX_ARG_ROTATION
&&
rotateBy
<
argCount
-
MAX_ARG_ROTATION
)
...
...
@@ -992,6 +1028,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// From here on out, it assumes a single-argument shift.
assert
(
MAX_ARG_ROTATION
==
1
);
int
srcArg
,
dstArg
;
int
dstSlot
;
byte
basicType
;
if
(
chunk2Slots
<=
chunk1Slots
)
{
// Rotate right/down N (rotateBy = +N, N small, c2 small):
...
...
@@ -999,6 +1036,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
srcArg
=
limit
-
1
;
dstArg
=
firstArg
;
dstSlot
=
depth0
-
chunk2Slots
;
basicType
=
basicType
(
newType
.
parameterType
(
srcArg
));
assert
(
chunk2Slots
==
type2size
(
basicType
));
}
else
{
...
...
@@ -1007,10 +1045,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
srcArg
=
firstArg
;
dstArg
=
limit
-
1
;
dstSlot
=
depth2
;
basicType
=
basicType
(
newType
.
parameterType
(
srcArg
));
assert
(
chunk1Slots
==
type2size
(
basicType
));
}
int
dstSlot
=
newType
.
parameterSlotDepth
(
dstArg
+
1
);
long
conv
=
makeSwapConv
(
OP_ROT_ARGS
,
srcArg
,
basicType
,
dstSlot
);
return
new
AdapterMethodHandle
(
target
,
newType
,
conv
);
}
...
...
src/share/classes/java/lang/invoke/BoundMethodHandle.java
浏览文件 @
10995d86
...
...
@@ -151,7 +151,7 @@ class BoundMethodHandle extends MethodHandle {
final
static
RuntimeException
badBoundArgumentException
(
Object
argument
,
MethodHandle
mh
,
int
argnum
)
{
String
atype
=
(
argument
==
null
)
?
"null"
:
argument
.
getClass
().
toString
();
return
new
WrongMethodType
Exception
(
"cannot bind "
+
atype
+
" argument to parameter #"
+
argnum
+
" of "
+
mh
.
type
());
return
new
ClassCast
Exception
(
"cannot bind "
+
atype
+
" argument to parameter #"
+
argnum
+
" of "
+
mh
.
type
());
}
@Override
...
...
src/share/classes/java/lang/invoke/CallSite.java
浏览文件 @
10995d86
...
...
@@ -111,7 +111,7 @@ public class CallSite {
}
/**
* Make a
blank call site object, possibly
equipped with an initial target method handle.
* Make a
call site object
equipped with an initial target method handle.
* @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null
*/
...
...
@@ -121,6 +121,25 @@ public class CallSite {
this
.
target
=
target
;
}
/**
* Make a call site object equipped with an initial target method handle.
* @param targetType the desired type of the call site
* @param createTargetHook a hook which will bind the call site to the target method handle
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
/*package-private*/
CallSite
(
MethodType
targetType
,
MethodHandle
createTargetHook
)
throws
Throwable
{
this
(
targetType
);
ConstantCallSite
selfCCS
=
(
ConstantCallSite
)
this
;
MethodHandle
boundTarget
=
(
MethodHandle
)
createTargetHook
.
invokeWithArguments
(
selfCCS
);
checkTargetChange
(
this
.
target
,
boundTarget
);
this
.
target
=
boundTarget
;
}
/**
* Returns the type of this call site's target.
* Although targets may change, any call site's type is permanent, and can never change to an unequal type.
...
...
@@ -129,6 +148,7 @@ public class CallSite {
* @return the type of the current target, which is also the type of any future target
*/
public
MethodType
type
()
{
// warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
return
target
.
type
();
}
...
...
@@ -294,8 +314,8 @@ public class CallSite {
}
else
{
throw
new
ClassCastException
(
"bootstrap method failed to produce a CallSite"
);
}
assert
(
site
.
getTarget
()
!=
null
);
assert
(
site
.
getTarget
().
type
().
equals
(
type
));
if
(!
site
.
getTarget
().
type
().
equals
(
type
))
throw
new
WrongMethodTypeException
(
"wrong type: "
+
site
.
getTarget
(
));
}
catch
(
Throwable
ex
)
{
BootstrapMethodError
bex
;
if
(
ex
instanceof
BootstrapMethodError
)
...
...
src/share/classes/java/lang/invoke/ConstantCallSite.java
浏览文件 @
10995d86
...
...
@@ -32,6 +32,8 @@ package java.lang.invoke;
* @author John Rose, JSR 292 EG
*/
public
class
ConstantCallSite
extends
CallSite
{
private
final
boolean
isFrozen
;
/**
* Creates a call site with a permanent target.
* @param target the target to be permanently associated with this call site
...
...
@@ -39,6 +41,45 @@ public class ConstantCallSite extends CallSite {
*/
public
ConstantCallSite
(
MethodHandle
target
)
{
super
(
target
);
isFrozen
=
true
;
}
/**
* Creates a call site with a permanent target, possibly bound to the call site itself.
* <p>
* During construction of the call site, the {@code createTargetHook} is invoked to
* produce the actual target, as if by a call of the form
* {@code (MethodHandle) createTargetHook.invoke(this)}.
* <p>
* Note that user code cannot perform such an action directly in a subclass constructor,
* since the target must be fixed before the {@code ConstantCallSite} constructor returns.
* <p>
* The hook is said to bind the call site to a target method handle,
* and a typical action would be {@code someTarget.bindTo(this)}.
* However, the hook is free to take any action whatever,
* including ignoring the call site and returning a constant target.
* <p>
* The result returned by the hook must be a method handle of exactly
* the same type as the call site.
* <p>
* While the hook is being called, the new {@code ConstantCallSite}
* object is in a partially constructed state.
* In this state,
* a call to {@code getTarget}, or any other attempt to use the target,
* will result in an {@code IllegalStateException}.
* It is legal at all times to obtain the call site's type using the {@code type} method.
*
* @param targetType the type of the method handle to be permanently associated with this call site
* @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
protected
ConstantCallSite
(
MethodType
targetType
,
MethodHandle
createTargetHook
)
throws
Throwable
{
super
(
targetType
,
createTargetHook
);
isFrozen
=
true
;
}
/**
...
...
@@ -48,9 +89,10 @@ public class ConstantCallSite extends CallSite {
* to the constructor call which created this instance.
*
* @return the immutable linkage state of this call site, a constant method handle
* @throws
UnsupportedOperationException because this kind of call site cannot change its target
* @throws
IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/
@Override
public
final
MethodHandle
getTarget
()
{
if
(!
isFrozen
)
throw
new
IllegalStateException
();
return
target
;
}
...
...
@@ -61,7 +103,7 @@ public class ConstantCallSite extends CallSite {
* @throws UnsupportedOperationException because this kind of call site cannot change its target
*/
@Override
public
final
void
setTarget
(
MethodHandle
ignore
)
{
throw
new
UnsupportedOperationException
(
"ConstantCallSite"
);
throw
new
UnsupportedOperationException
();
}
/**
...
...
@@ -69,6 +111,7 @@ public class ConstantCallSite extends CallSite {
* Since that target will never change, this is a correct implementation
* of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
* @return the immutable linkage state of this call site, a constant method handle
* @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/
@Override
public
final
MethodHandle
dynamicInvoker
()
{
...
...
src/share/classes/java/lang/invoke/Invokers.java
浏览文件 @
10995d86
...
...
@@ -46,7 +46,10 @@ class Invokers {
// general invoker for the outgoing call
private
/*lazy*/
MethodHandle
generalInvoker
;
// general invoker for the outgoing call; accepts a single Object[]
// general invoker for the outgoing call, uses varargs
private
/*lazy*/
MethodHandle
varargsInvoker
;
// general invoker for the outgoing call; accepts a trailing Object[]
private
final
/*lazy*/
MethodHandle
[]
spreadInvokers
;
// invoker for an unbound callsite
...
...
@@ -67,45 +70,56 @@ class Invokers {
/*non-public*/
MethodHandle
exactInvoker
()
{
MethodHandle
invoker
=
exactInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
try
{
invoker
=
IMPL_LOOKUP
.
findVirtual
(
MethodHandle
.
class
,
"invokeExact"
,
targetType
);
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
InternalError
(
"JVM cannot find invoker for "
+
targetType
);
}
assert
(
invokerType
(
targetType
)
==
invoker
.
type
());
invoker
=
lookupInvoker
(
"invokeExact"
);
exactInvoker
=
invoker
;
return
invoker
;
}
/*non-public*/
MethodHandle
generalInvoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker
=
generalInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
generalType
=
targetType
.
generic
();
invoker
=
invoker1
.
asType
(
invokerType
(
generalType
));
invoker
=
lookupInvoker
(
"invoke"
);
generalInvoker
=
invoker
;
return
invoker
;
}
private
MethodHandle
lookupInvoker
(
String
name
)
{
MethodHandle
invoker
;
try
{
invoker
=
IMPL_LOOKUP
.
findVirtual
(
MethodHandle
.
class
,
name
,
targetType
);
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
InternalError
(
"JVM cannot find invoker for "
+
targetType
);
}
assert
(
invokerType
(
targetType
)
==
invoker
.
type
());
assert
(!
invoker
.
isVarargsCollector
());
return
invoker
;
}
/*non-public*/
MethodHandle
erasedInvoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
xinvoker
=
exactInvoker
();
MethodHandle
invoker
=
erasedInvoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
erasedType
=
targetType
.
erase
();
if
(
erasedType
==
targetType
.
generic
())
invoker
=
generalInvoker
();
else
invoker
=
invoker1
.
asType
(
invokerType
(
erasedType
));
invoker
=
xinvoker
.
asType
(
invokerType
(
erasedType
));
erasedInvoker
=
invoker
;
return
invoker
;
}
/*non-public*/
MethodHandle
spreadInvoker
(
int
object
ArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
object
ArgCount
];
/*non-public*/
MethodHandle
spreadInvoker
(
int
leading
ArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
leading
ArgCount
];
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
MethodHandle
gInvoker
=
generalInvoker
();
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
int
spreadArgCount
=
targetType
.
parameterCount
()
-
leadingArgCount
;
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
spreadArgCount
);
spreadInvokers
[
leadingArgCount
]
=
vaInvoker
;
return
vaInvoker
;
}
/*non-public*/
MethodHandle
varargsInvoker
()
{
MethodHandle
vaInvoker
=
varargsInvoker
;
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
vaInvoker
=
spreadInvoker
(
0
).
asType
(
invokerType
(
MethodType
.
genericMethodType
(
0
,
true
)));
varargsInvoker
=
vaInvoker
;
return
vaInvoker
;
}
...
...
src/share/classes/java/lang/invoke/MemberName.java
浏览文件 @
10995d86
...
...
@@ -506,8 +506,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
if
(
from
!=
null
)
message
+=
", from "
+
from
;
return
new
IllegalAccessException
(
message
);
}
public
ReflectiveOperationException
makeAccessException
(
String
message
)
{
message
=
message
+
": "
+
toString
();
private
String
message
()
{
if
(
isResolved
())
return
"no access"
;
else
if
(
isConstructor
())
return
"no such constructor"
;
else
if
(
isMethod
())
return
"no such method"
;
else
return
"no such field"
;
}
public
ReflectiveOperationException
makeAccessException
()
{
String
message
=
message
()
+
": "
+
toString
();
if
(
isResolved
())
return
new
IllegalAccessException
(
message
);
else
if
(
isConstructor
())
...
...
@@ -641,7 +651,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
MemberName
result
=
resolveOrNull
(
m
,
searchSupers
,
lookupClass
);
if
(
result
!=
null
)
return
result
;
ReflectiveOperationException
ex
=
m
.
makeAccessException
(
"no access"
);
ReflectiveOperationException
ex
=
m
.
makeAccessException
();
if
(
ex
instanceof
IllegalAccessException
)
throw
(
IllegalAccessException
)
ex
;
throw
nsmClass
.
cast
(
ex
);
}
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
10995d86
此差异已折叠。
点击以展开。
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
10995d86
...
...
@@ -82,12 +82,17 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
DirectMethodHandle
mh
=
new
DirectMethodHandle
(
mtype
,
method
,
doDispatch
,
lookupClass
);
if
(!
mh
.
isValid
())
throw
method
.
makeAccessException
(
"no
access
"
,
lookupClass
);
throw
method
.
makeAccessException
(
"no
direct method handle
"
,
lookupClass
);
assert
(
mh
.
type
()
==
mtype
);
if
(!
method
.
isVarargs
())
return
mh
;
else
return
mh
.
asVarargsCollector
(
mtype
.
parameterType
(
mtype
.
parameterCount
()-
1
));
int
argc
=
mtype
.
parameterCount
();
if
(
argc
!=
0
)
{
Class
<?>
arrayType
=
mtype
.
parameterType
(
argc
-
1
);
if
(
arrayType
.
isArray
())
return
AdapterMethodHandle
.
makeVarargsCollector
(
mh
,
arrayType
);
}
throw
method
.
makeAccessException
(
"cannot make variable arity"
,
null
);
}
static
...
...
@@ -485,14 +490,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
*/
static
MethodHandle
bindReceiver
(
MethodHandle
target
,
Object
receiver
)
{
if
(
receiver
==
null
)
return
null
;
if
(
target
instanceof
AdapterMethodHandle
&&
((
AdapterMethodHandle
)
target
).
conversionOp
()
==
MethodHandleNatives
.
Constants
.
OP_RETYPE_ONLY
)
{
Object
info
=
MethodHandleNatives
.
getTargetInfo
(
target
);
if
(
info
instanceof
DirectMethodHandle
)
{
DirectMethodHandle
dmh
=
(
DirectMethodHandle
)
info
;
if
(
receiver
==
null
||
dmh
.
type
().
parameterType
(
0
).
isAssignableFrom
(
receiver
.
getClass
()))
{
if
(
dmh
.
type
().
parameterType
(
0
).
isAssignableFrom
(
receiver
.
getClass
()))
{
MethodHandle
bmh
=
new
BoundMethodHandle
(
dmh
,
receiver
,
0
);
MethodType
newType
=
target
.
type
().
dropParameterTypes
(
0
,
1
);
return
convertArguments
(
bmh
,
newType
,
bmh
.
type
(),
0
);
...
...
@@ -698,7 +703,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if
(
target
==
null
)
throw
newIllegalArgumentException
(
"cannot drop"
);
oldType
=
target
.
type
();
}
return
convertArguments
(
target
,
newType
,
oldType
,
0
);
target
=
convertArguments
(
target
,
newType
,
oldType
,
0
);
assert
(
target
!=
null
);
return
target
;
}
/*non-public*/
static
...
...
@@ -907,14 +914,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this
.
test
=
test
;
this
.
target
=
target
;
this
.
fallback
=
fallback
;
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
}
// FIXME: Build the control flow out of foldArguments.
static
boolean
preferRicochetFrame
(
MethodType
type
)
{
return
(
type
.
parameterCount
()
>=
INVOKES
.
length
||
type
.
hasPrimitives
());
}
static
MethodHandle
make
(
MethodHandle
test
,
MethodHandle
target
,
MethodHandle
fallback
)
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodType
type
=
target
.
type
();
int
nargs
=
type
.
parameterCount
();
if
(
nargs
<
INVOKES
.
length
)
{
if
(
preferRicochetFrame
(
type
))
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
invoke
=
INVOKES
[
nargs
];
MethodType
gtype
=
type
.
generic
();
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
...
...
@@ -925,6 +934,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
gguard
=
new
GuardWithTest
(
invoke
,
gtest
,
gtarget
,
gfallback
);
return
convertArguments
(
gguard
,
type
,
gtype
,
0
);
}
else
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
MethodHandle
invoke
=
VARARGS_INVOKE
;
MethodType
gtype
=
MethodType
.
genericMethodType
(
1
);
assert
(
invoke
.
type
().
dropParameterTypes
(
0
,
1
)
==
gtype
);
...
...
@@ -1048,8 +1058,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
// [tailcall]=> tf(arg...)
assert
(
test
.
type
().
returnType
()
==
boolean
.
class
);
MethodType
foldTargetType
=
target
.
type
().
insertParameterTypes
(
0
,
boolean
.
class
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
foldTargetType
,
test
.
type
(),
0
,
true
))
{
MethodType
targetType
=
target
.
type
();
MethodType
foldTargetType
=
targetType
.
insertParameterTypes
(
0
,
boolean
.
class
);
if
(
AdapterMethodHandle
.
canCollectArguments
(
foldTargetType
,
test
.
type
(),
0
,
true
)
&&
GuardWithTest
.
preferRicochetFrame
(
targetType
))
{
// working backwards, as usual:
assert
(
target
.
type
().
equals
(
fallback
.
type
()));
MethodHandle
tailcall
=
MethodHandles
.
exactInvoker
(
target
.
type
());
...
...
@@ -1062,7 +1074,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle
fold
=
foldArguments
(
filter
,
filter
.
type
().
dropParameterTypes
(
0
,
1
),
0
,
test
);
return
fold
;
}
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this code is deprecated
return
GuardWithTest
.
make
(
test
,
target
,
fallback
);
}
...
...
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
10995d86
...
...
@@ -400,7 +400,7 @@ class MethodHandleNatives {
case
REF_newInvokeSpecial:
return
lookup
.
findConstructor
(
defc
,
(
MethodType
)
type
);
case
REF_invokeInterface:
return
lookup
.
findVirtual
(
defc
,
name
,
(
MethodType
)
type
);
}
throw
new
I
llegalArgumentException
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
throw
new
I
nternalError
(
"bad MethodHandle constant "
+
name
+
" : "
+
type
);
}
catch
(
ReflectiveOperationException
ex
)
{
Error
err
=
new
IncompatibleClassChangeError
();
err
.
initCause
(
ex
);
...
...
src/share/classes/java/lang/invoke/MethodHandleProxies.java
0 → 100644
浏览文件 @
10995d86
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
java.lang.invoke
;
import
java.lang.reflect.*
;
import
sun.invoke.WrapperInstance
;
/**
* This class consists exclusively of static methods that help adapt
* method handles to other JVM types, such as interfaces.
*/
public
class
MethodHandleProxies
{
private
MethodHandleProxies
()
{
}
// do not instantiate
/**
* Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
* <p>
* A single-method interface is an interface which declares a uniquely named method.
* When determining the uniquely named method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
* are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
* <p>
* The interface must be public. No additional access checks are performed.
* <p>
* The resulting instance of the required type will respond to
* invocation of the type's uniquely named method by calling
* the given target on the incoming arguments,
* and returning or throwing whatever the target
* returns or throws. The invocation will be as if by
* {@code target.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* <p>
* The uniquely named method is allowed to be multiply declared,
* with distinct type descriptors. (E.g., it can be overloaded,
* or can possess bridge methods.) All such declarations are
* connected directly to the target method handle.
* Argument and return types are adjusted by {@code asType}
* for each individual declaration.
* <p>
* The wrapper instance will implement the requested interface
* and its super-types, but no other single-method interfaces.
* This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
* multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the requested type's single abstract method.
* If this happens, the throwable will be wrapped in an instance of
* {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
* and thrown in that wrapped form.
* <p>
* Like {@link java.lang.Integer#valueOf Integer.valueOf},
* {@code asInterfaceInstance} is a factory method whose results are defined
* by their behavior.
* It is not guaranteed to return a new instance for every call.
* <p>
* Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
* and other corner cases, the interface may also have several abstract methods
* with the same name but having distinct descriptors (types of returns and parameters).
* In this case, all the methods are bound in common to the one given target.
* The type check and effective {@code asType} conversion is applied to each
* method type descriptor, and all abstract methods are bound to the target in common.
* Beyond this type check, no further checks are made to determine that the
* abstract methods are related in any way.
* <p>
* Future versions of this API may accept additional types,
* such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces.
*
* @param target the method handle to invoke from the wrapper
* @param intfc the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given target
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the {@code intfc} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the target cannot
* be converted to the type required by the requested interface
*/
// Other notes to implementors:
// <p>
// No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
// classes might be used for the same type.
// <p>
// If the implementation is able
// to prove that a wrapper of the required type
// has already been created for a given
// method handle, or for another method handle with the
// same behavior, the implementation may return that wrapper in place of
// a new wrapper.
// <p>
// This method is designed to apply to common use cases
// where a single method handle must interoperate with
// an interface that implements a function-like
// API. Additional variations, such as single-abstract-method classes with
// private constructors, or interfaces with multiple but related
// entry points, must be covered by hand-written or automatically
// generated adapter classes.
//
public
static
<
T
>
T
asInterfaceInstance
(
final
Class
<
T
>
intfc
,
final
MethodHandle
target
)
{
// POC implementation only; violates the above contract several ways
final
Method
sm
=
getSingleMethod
(
intfc
);
if
(
sm
==
null
)
throw
new
IllegalArgumentException
(
"not a single-method interface: "
+
intfc
.
getName
());
MethodType
smMT
=
MethodType
.
methodType
(
sm
.
getReturnType
(),
sm
.
getParameterTypes
());
MethodHandle
checkTarget
=
target
.
asType
(
smMT
);
// make throw WMT
checkTarget
=
checkTarget
.
asType
(
checkTarget
.
type
().
changeReturnType
(
Object
.
class
));
final
MethodHandle
vaTarget
=
checkTarget
.
asSpreader
(
Object
[].
class
,
smMT
.
parameterCount
());
return
intfc
.
cast
(
Proxy
.
newProxyInstance
(
intfc
.
getClassLoader
(),
new
Class
[]{
intfc
,
WrapperInstance
.
class
},
new
InvocationHandler
()
{
private
Object
getArg
(
String
name
)
{
if
((
Object
)
name
==
"getWrapperInstanceTarget"
)
return
target
;
if
((
Object
)
name
==
"getWrapperInstanceType"
)
return
intfc
;
throw
new
AssertionError
();
}
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
if
(
method
.
getDeclaringClass
()
==
WrapperInstance
.
class
)
return
getArg
(
method
.
getName
());
if
(
method
.
equals
(
sm
))
return
vaTarget
.
invokeExact
(
args
);
if
(
isObjectMethod
(
method
))
return
callObjectMethod
(
this
,
method
,
args
);
throw
new
InternalError
();
}
}));
}
/**
* Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* @param x any reference
* @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
*/
public
static
boolean
isWrapperInstance
(
Object
x
)
{
return
x
instanceof
WrapperInstance
;
}
private
static
WrapperInstance
asWrapperInstance
(
Object
x
)
{
try
{
if
(
x
!=
null
)
return
(
WrapperInstance
)
x
;
}
catch
(
ClassCastException
ex
)
{
}
throw
new
IllegalArgumentException
(
"not a wrapper instance"
);
}
/**
* Produces or recovers a target method handle which is behaviorally
* equivalent to the unique method of this wrapper instance.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return a method handle implementing the unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public
static
MethodHandle
wrapperInstanceTarget
(
Object
x
)
{
return
asWrapperInstance
(
x
).
getWrapperInstanceTarget
();
}
/**
* Recovers the unique single-method interface type for which this wrapper instance was created.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return the single-method interface type for which the wrapper was created
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public
static
Class
<?>
wrapperInstanceType
(
Object
x
)
{
return
asWrapperInstance
(
x
).
getWrapperInstanceType
();
}
private
static
boolean
isObjectMethod
(
Method
m
)
{
switch
(
m
.
getName
())
{
case
"toString"
:
return
(
m
.
getReturnType
()
==
String
.
class
&&
m
.
getParameterTypes
().
length
==
0
);
case
"hashCode"
:
return
(
m
.
getReturnType
()
==
int
.
class
&&
m
.
getParameterTypes
().
length
==
0
);
case
"equals"
:
return
(
m
.
getReturnType
()
==
boolean
.
class
&&
m
.
getParameterTypes
().
length
==
1
&&
m
.
getParameterTypes
()[
0
]
==
Object
.
class
);
}
return
false
;
}
private
static
Object
callObjectMethod
(
Object
self
,
Method
m
,
Object
[]
args
)
{
assert
(
isObjectMethod
(
m
))
:
m
;
switch
(
m
.
getName
())
{
case
"toString"
:
return
self
.
getClass
().
getName
()
+
"@"
+
Integer
.
toHexString
(
self
.
hashCode
());
case
"hashCode"
:
return
System
.
identityHashCode
(
self
);
case
"equals"
:
return
(
self
==
args
[
0
]);
}
return
null
;
}
private
static
Method
getSingleMethod
(
Class
<?>
intfc
)
{
if
(!
intfc
.
isInterface
())
return
null
;
Method
sm
=
null
;
for
(
Method
m
:
intfc
.
getMethods
())
{
int
mod
=
m
.
getModifiers
();
if
(
Modifier
.
isAbstract
(
mod
))
{
if
(
sm
!=
null
&&
!
isObjectMethod
(
sm
))
return
null
;
// too many abstract methods
sm
=
m
;
}
}
return
sm
;
}
}
src/share/classes/java/lang/invoke/MethodHandles.java
浏览文件 @
10995d86
此差异已折叠。
点击以展开。
src/share/classes/java/lang/invoke/MethodType.java
浏览文件 @
10995d86
...
...
@@ -273,7 +273,7 @@ class MethodType implements java.io.Serializable {
* @param objectArgCount number of parameters (excluding the final array parameter if any)
* @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
* @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray})
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray}
is true
)
* @see #genericMethodType(int)
*/
public
static
...
...
@@ -455,7 +455,8 @@ class MethodType implements java.io.Serializable {
/**
* Reports if this type contains a wrapper argument or return value.
* Wrappers are types which box primitive values, such as {@link Integer}.
* The reference type {@code java.lang.Void} counts as a wrapper.
* The reference type {@code java.lang.Void} counts as a wrapper,
* if it occurs as a return type.
* @return true if any of the types are wrappers
*/
public
boolean
hasWrappers
()
{
...
...
@@ -649,13 +650,55 @@ class MethodType implements java.io.Serializable {
}
/*non-public*/
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
)))
// short-circuit a few cases:
if
(
src
==
dst
||
dst
==
Object
.
class
)
return
true
;
// the remainder of this logic is documented in MethodHandle.asType
if
(
src
.
isPrimitive
())
{
// can force void to an explicit null, a la reflect.Method.invoke
// can also force void to a primitive zero, by analogy
if
(
src
==
void
.
class
)
return
true
;
//or !dst.isPrimitive()?
Wrapper
sw
=
Wrapper
.
forPrimitiveType
(
src
);
if
(
dst
.
isPrimitive
())
{
// P->P must widen
return
Wrapper
.
forPrimitiveType
(
dst
).
isConvertibleFrom
(
sw
);
}
else
{
// P->R must box and widen
return
dst
.
isAssignableFrom
(
sw
.
wrapperType
());
}
}
else
if
(
dst
.
isPrimitive
())
{
// any value can be dropped
if
(
dst
==
void
.
class
)
return
true
;
Wrapper
dw
=
Wrapper
.
forPrimitiveType
(
dst
);
// R->P must be able to unbox (from a dynamically chosen type) and widen
// For example:
// Byte/Number/Comparable/Object -> dw:Byte -> byte.
// Character/Comparable/Object -> dw:Character -> char
// Boolean/Comparable/Object -> dw:Boolean -> boolean
// This means that dw must be cast-compatible with src.
if
(
src
.
isAssignableFrom
(
dw
.
wrapperType
()))
{
return
true
;
}
// The above does not work if the source reference is strongly typed
// to a wrapper whose primitive must be widened. For example:
// Byte -> unbox:byte -> short/int/long/float/double
// Character -> unbox:char -> int/long/float/double
if
(
Wrapper
.
isWrapperType
(
src
)
&&
dw
.
isConvertibleFrom
(
Wrapper
.
forWrapperType
(
src
)))
{
// can unbox from src and then widen to dst
return
true
;
}
// We have already covered cases which arise due to runtime unboxing
// of a reference type which covers several wrapper types:
// Object -> cast:Integer -> unbox:int -> long/float/double
// Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
// An marginal case is Number -> dw:Character -> char, which would be OK if there were a
// subclass of Number which wraps a value that can convert to char.
// Since there is none, we don't need an extra check here to cover char or boolean.
return
false
;
}
else
{
// R->R always works, since null is always valid dynamically
return
true
;
}
return
true
;
}
/// Queries which have to do with the bytecode architecture
...
...
@@ -740,6 +783,7 @@ class MethodType implements java.io.Serializable {
* @param descriptor a bytecode-level type descriptor string "(T...)T"
* @param loader the class loader in which to look up the types
* @return a method type matching the bytecode-level type descriptor
* @throws NullPointerException if the string is null
* @throws IllegalArgumentException if the string is not well-formed
* @throws TypeNotPresentException if a named type cannot be found
*/
...
...
src/share/classes/java/lang/invoke/MutableCallSite.java
浏览文件 @
10995d86
...
...
@@ -37,12 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <!-- JavaDocExamplesTest.testMutableCallSite -->
* <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str
2 = MethodType.methodType(String.class,
String.class);
MethodType MT_str
1 = MethodType.methodType(
String.class);
MethodHandle MH_upcase = MethodHandles.lookup()
.findVirtual(String.class, "toUpperCase", MT_str
2
);
.findVirtual(String.class, "toUpperCase", MT_str
1
);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
...
...
@@ -53,8 +54,10 @@ assertEquals("FRED", (String) worker1.invokeExact());
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
...
...
src/share/classes/java/lang/invoke/SwitchPoint.java
浏览文件 @
10995d86
...
...
@@ -56,16 +56,17 @@ package java.lang.invoke;
* <p>
* Here is an example of a switch point in action:
* <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", M
T_str2
);
.findVirtual(String.class, "concat", M
ethodType.methodType(String.class, String.class)
);
SwitchPoint spt = new SwitchPoint();
assert(spt.isValid());
// the following steps may be repeated to re-use the same switch point:
MethodHandle worker1 = strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(
strcat, MT_str2
, 1, 0);
MethodHandle worker1 =
MH_
strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(
MH_strcat, MH_strcat.type()
, 1, 0);
MethodHandle worker = spt.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(!spt.isValid());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* <p style="font-size:smaller;">
...
...
@@ -124,6 +125,19 @@ public class SwitchPoint {
this
.
mcsInvoker
=
mcs
.
dynamicInvoker
();
}
/**
* Determines if this switch point is still valid.
* <p>
* Since invalidation is a global and immediate operation,
* this query must be sequenced with any
* other threads that could invalidate this switch point.
* It may therefore be expensive.
* @return true if this switch point has never been invalidated
*/
public
boolean
isValid
()
{
return
(
mcs
.
getTarget
()
==
K_true
);
}
/**
* Returns a method handle which always delegates either to the target or the fallback.
* The method handle will delegate to the target exactly as long as the switch point is valid.
...
...
@@ -136,6 +150,7 @@ public class SwitchPoint {
* @param fallback the method handle selected by the switch point after it is invalidated
* @return a combined method handle which always calls either the target or fallback
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the two method types do not match
* @see MethodHandles#guardWithTest
*/
public
MethodHandle
guardWithTest
(
MethodHandle
target
,
MethodHandle
fallback
)
{
...
...
src/share/classes/java/lang/invoke/package-info.java
浏览文件 @
10995d86
此差异已折叠。
点击以展开。
src/share/classes/sun/invoke/util/ValueConversions.java
浏览文件 @
10995d86
...
...
@@ -198,27 +198,30 @@ public class ValueConversions {
return
unbox
(
Wrapper
.
forPrimitiveType
(
type
),
true
,
false
);
}
static
private
final
Integer
ZERO_INT
=
0
,
ONE_INT
=
1
;
/// Primitive conversions
public
static
Number
primitiveConversion
(
Wrapper
wrap
,
Object
x
,
boolean
cast
)
{
// Maybe merge this code with Wrapper.convert/cast.
Number
res
=
null
;
if
(
x
==
null
)
{
if
(!
cast
)
return
null
;
x
=
wrap
.
zero
()
;
return
ZERO_INT
;
}
if
(
x
instanceof
Number
)
{
res
=
(
Number
)
x
;
}
else
if
(
x
instanceof
Boolean
)
{
res
=
((
boolean
)
x
?
1
:
0
);
res
=
((
boolean
)
x
?
ONE_INT
:
ZERO_INT
);
}
else
if
(
x
instanceof
Character
)
{
res
=
(
int
)(
char
)
x
;
}
else
{
// this will fail with the required ClassCastException:
res
=
(
Number
)
x
;
}
if
(!
cast
&&
!
wrap
.
isConvertibleFrom
(
Wrapper
.
forWrapperType
(
x
.
getClass
())))
Wrapper
xwrap
=
Wrapper
.
findWrapperType
(
x
.
getClass
());
if
(
xwrap
==
null
||
!
cast
&&
!
wrap
.
isConvertibleFrom
(
xwrap
))
// this will fail with the required ClassCastException:
re
s
=
(
Number
)
wrap
.
wrapperType
().
cast
(
x
);
re
turn
(
Number
)
wrap
.
wrapperType
().
cast
(
x
);
return
res
;
}
...
...
src/share/classes/sun/invoke/util/VerifyAccess.java
浏览文件 @
10995d86
...
...
@@ -154,9 +154,10 @@ public class VerifyAccess {
* @return whether they are in the same package
*/
public
static
boolean
isSamePackage
(
Class
<?>
class1
,
Class
<?>
class2
)
{
assert
(!
class1
.
isArray
()
&&
!
class2
.
isArray
());
if
(
class1
==
class2
)
return
true
;
if
(!
loadersAreRelated
(
class1
.
getClassLoader
(),
class2
.
getClassLoader
()))
if
(!
loadersAreRelated
(
class1
.
getClassLoader
(),
class2
.
getClassLoader
()
,
false
))
return
false
;
String
name1
=
class1
.
getName
(),
name2
=
class2
.
getName
();
int
dot
=
name1
.
lastIndexOf
(
'.'
);
...
...
@@ -169,6 +170,16 @@ public class VerifyAccess {
return
true
;
}
/** Return the package name for this class.
*/
public
static
String
getPackageName
(
Class
<?>
cls
)
{
assert
(!
cls
.
isArray
());
String
name
=
cls
.
getName
();
int
dot
=
name
.
lastIndexOf
(
'.'
);
if
(
dot
<
0
)
return
""
;
return
name
.
substring
(
0
,
dot
);
}
/**
* Test if two classes are defined as part of the same package member (top-level class).
* If this is true, they can share private access with each other.
...
...
@@ -193,18 +204,33 @@ public class VerifyAccess {
return
pkgmem
;
}
private
static
boolean
loadersAreRelated
(
ClassLoader
loader1
,
ClassLoader
loader2
)
{
if
(
loader1
==
loader2
||
loader1
==
null
||
loader2
==
null
)
{
private
static
boolean
loadersAreRelated
(
ClassLoader
loader1
,
ClassLoader
loader2
,
boolean
loader1MustBeParent
)
{
if
(
loader1
==
loader2
||
loader1
==
null
||
(
loader2
==
null
&&
!
loader1MustBeParent
))
{
return
true
;
}
for
(
ClassLoader
scan1
=
loader1
;
scan1
!=
null
;
scan1
=
scan1
.
getParent
())
{
if
(
scan1
==
loader2
)
return
true
;
}
for
(
ClassLoader
scan2
=
loader2
;
scan2
!=
null
;
scan2
=
scan2
.
getParent
())
{
if
(
scan2
==
loader1
)
return
true
;
}
if
(
loader1MustBeParent
)
return
false
;
// see if loader2 is a parent of loader1:
for
(
ClassLoader
scan1
=
loader1
;
scan1
!=
null
;
scan1
=
scan1
.
getParent
())
{
if
(
scan1
==
loader2
)
return
true
;
}
return
false
;
}
/**
* Is the class loader of parentClass identical to, or an ancestor of,
* the class loader of childClass?
* @param parentClass
* @param childClass
* @return whether parentClass precedes or equals childClass in class loader order
*/
public
static
boolean
classLoaderIsAncestor
(
Class
<?>
parentClass
,
Class
<?>
childClass
)
{
return
loadersAreRelated
(
parentClass
.
getClassLoader
(),
childClass
.
getClassLoader
(),
true
);
}
}
src/share/classes/sun/invoke/util/Wrapper.java
浏览文件 @
10995d86
...
...
@@ -135,7 +135,7 @@ public enum Wrapper {
* <li>any type converted to {@code void} (i.e., dropping a method call's value)
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* </ul>
* These are the cases allowed by MethodHandle.asType
and convertArguments
.
* These are the cases allowed by MethodHandle.asType.
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
...
...
test/java/lang/invoke/6998541/Test6998541.java
浏览文件 @
10995d86
...
...
@@ -164,6 +164,7 @@ public class Test6998541 {
private
static
boolean
canDoAsType
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
)
return
true
;
if
(
dst
==
void
.
class
)
return
true
;
if
(
src
==
void
.
class
)
return
true
;
// allow void->zero
if
(!
src
.
isPrimitive
()
||
!
dst
.
isPrimitive
())
return
true
;
// primitive conversion works for asType only when it's widening
if
(
src
==
boolean
.
class
||
dst
==
boolean
.
class
)
return
false
;
...
...
@@ -451,7 +452,6 @@ public class Test6998541 {
private
final
static
MethodHandle
mh_dv
=
mh
(
double
.
class
);
private
static
void
void2prim
(
int
i
)
throws
Throwable
{
if
(!
DO_CASTS
)
return
;
assertEquals
(
false
,
(
boolean
)
mh_zv
.
invokeExact
());
// void -> boolean
assertEquals
((
byte
)
0
,
(
byte
)
mh_bv
.
invokeExact
());
// void -> byte
assertEquals
((
char
)
0
,
(
char
)
mh_cv
.
invokeExact
());
// void -> char
...
...
@@ -463,15 +463,7 @@ public class Test6998541 {
}
private
static
void
void2prim_invalid
(
double
x
)
throws
Throwable
{
if
(
DO_CASTS
)
return
;
try
{
assertEquals
(
false
,
(
boolean
)
mh_zv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> boolean
try
{
assertEquals
((
byte
)
0
,
(
byte
)
mh_bv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> byte
try
{
assertEquals
((
char
)
0
,
(
char
)
mh_cv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> char
try
{
assertEquals
((
short
)
0
,
(
short
)
mh_sv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> short
try
{
assertEquals
(
0
,
(
int
)
mh_iv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> int
try
{
assertEquals
(
0L
,
(
long
)
mh_jv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> long
try
{
assertEquals
(
0.0f
,
(
float
)
mh_fv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> float
try
{
assertEquals
(
0.0d
,
(
double
)
mh_dv
.
invokeExact
());
fail
();
}
catch
(
NullPointerException
_
)
{}
// void -> double
// no cases
}
private
static
MethodHandle
mh_v
(
Class
arg
)
{
return
mh
(
void
.
class
,
arg
);
}
...
...
test/java/lang/invoke/InvokeDynamicPrintArgs.java
浏览文件 @
10995d86
...
...
@@ -106,8 +106,10 @@ public class InvokeDynamicPrintArgs {
"Done printing argument lists."
};
private
static
boolean
doPrint
=
true
;
private
static
void
printArgs
(
Object
bsmInfo
,
Object
...
args
)
{
System
.
out
.
println
(
bsmInfo
+
Arrays
.
deepToString
(
args
));
String
message
=
bsmInfo
+
Arrays
.
deepToString
(
args
);
if
(
doPrint
)
System
.
out
.
println
(
message
);
}
private
static
MethodHandle
MH_printArgs
()
throws
ReflectiveOperationException
{
shouldNotCallThis
();
...
...
@@ -129,11 +131,48 @@ public class InvokeDynamicPrintArgs {
return
lookup
().
findStatic
(
lookup
().
lookupClass
(),
"bsm"
,
MT_bsm
());
}
private
static
CallSite
bsm2
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
arg
)
throws
ReflectiveOperationException
{
/* Example of a constant call site with user-data.
* In this case, the user data is exactly the BSM data.
* Note that a CCS with user data must use the "hooked" constructor
* to bind the CCS itself into the resulting target.
* A normal constructor would not allow a circular relation
* between the CCS and its target.
*/
public
static
class
PrintingCallSite
extends
ConstantCallSite
{
final
Lookup
caller
;
final
String
name
;
final
Object
[]
staticArgs
;
PrintingCallSite
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
staticArgs
)
throws
Throwable
{
super
(
type
,
MH_createTarget
());
this
.
caller
=
caller
;
this
.
name
=
name
;
this
.
staticArgs
=
staticArgs
;
}
public
MethodHandle
createTarget
()
{
try
{
return
lookup
().
bind
(
this
,
"runTarget"
,
genericMethodType
(
0
,
true
)).
asType
(
type
());
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
public
Object
runTarget
(
Object
...
dynamicArgs
)
{
List
<
Object
>
bsmInfo
=
new
ArrayList
<>(
Arrays
.
asList
(
caller
,
name
,
type
()));
bsmInfo
.
addAll
(
Arrays
.
asList
(
staticArgs
));
printArgs
(
bsmInfo
,
dynamicArgs
);
return
null
;
}
private
static
MethodHandle
MH_createTarget
()
throws
ReflectiveOperationException
{
shouldNotCallThis
();
return
lookup
().
findVirtual
(
lookup
().
lookupClass
(),
"createTarget"
,
methodType
(
MethodHandle
.
class
));
}
}
private
static
CallSite
bsm2
(
Lookup
caller
,
String
name
,
MethodType
type
,
Object
...
arg
)
throws
Throwable
{
// ignore caller and name, but match the type:
List
<
Object
>
bsmInfo
=
new
ArrayList
<>(
Arrays
.
asList
(
caller
,
name
,
type
));
bsmInfo
.
addAll
(
Arrays
.
asList
((
Object
[])
arg
));
return
new
ConstantCallSite
(
MH_printArgs
().
bindTo
(
bsmInfo
).
asCollector
(
Object
[].
class
,
type
.
parameterCount
()).
asType
(
type
));
return
new
PrintingCallSite
(
caller
,
name
,
type
,
arg
);
}
private
static
MethodType
MT_bsm2
()
{
shouldNotCallThis
();
...
...
@@ -146,33 +185,33 @@ public class InvokeDynamicPrintArgs {
private
static
MethodHandle
INDY_nothing
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm
().
invoke
(
lookup
(),
"nothing"
,
methodType
(
void
.
class
)
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_foo
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm
().
invoke
(
lookup
(),
"foo"
,
methodType
(
void
.
class
,
String
.
class
)
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_bar
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"bar"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
)
,
Void
.
class
,
"void type!"
,
1
,
234.5
F
,
67.5
,
(
long
)
89
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_bar2
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"bar2"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
)
,
Void
.
class
,
"void type!"
,
1
,
234.5
F
,
67.5
,
(
long
)
89
)).
dynamicInvoker
();
}
private
static
MethodHandle
INDY_baz
()
throws
Throwable
{
shouldNotCallThis
();
return
((
CallSite
)
MH_bsm2
().
invoke
Generic
(
lookup
(),
return
((
CallSite
)
MH_bsm2
().
invoke
(
lookup
(),
"baz"
,
methodType
(
void
.
class
,
String
.
class
,
int
.
class
,
double
.
class
)
,
1234.5
)).
dynamicInvoker
();
...
...
test/java/lang/invoke/InvokeGenericTest.java
浏览文件 @
10995d86
...
...
@@ -314,7 +314,7 @@ public class InvokeGenericTest {
ArrayList
<
Class
<?>>
argTypes
=
new
ArrayList
<
Class
<?>>(
targetType
.
parameterList
());
Collections
.
fill
(
argTypes
.
subList
(
beg
,
end
),
argType
);
MethodType
ttype2
=
MethodType
.
methodType
(
targetType
.
returnType
(),
argTypes
);
return
MethodHandles
.
convertArguments
(
target
,
ttype2
);
return
target
.
asType
(
ttype2
);
}
// This lookup is good for all members in and under InvokeGenericTest.
...
...
@@ -378,7 +378,7 @@ public class InvokeGenericTest {
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
Generic
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
res
=
resl
=
(
List
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
...
...
test/java/lang/invoke/JavaDocExamplesTest.java
浏览文件 @
10995d86
...
...
@@ -34,7 +34,7 @@
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-D
test.java.lang.invoke.
JavaDocExamplesTest.verbosity=1 \
-DJavaDocExamplesTest.verbosity=1 \
test.java.lang.invoke.JavaDocExamplesTest
----
*/
...
...
@@ -45,12 +45,10 @@ import java.lang.invoke.*;
import
static
java
.
lang
.
invoke
.
MethodHandles
.*;
import
static
java
.
lang
.
invoke
.
MethodType
.*;
import
java.lang.reflect.*
;
import
java.util.*
;
import
org.junit.*
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assume
.*;
/**
...
...
@@ -60,11 +58,29 @@ public class JavaDocExamplesTest {
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
*/
public
static
void
main
(
String
...
ignore
)
{
org
.
junit
.
runner
.
JUnitCore
.
runClasses
(
JavaDocExamplesTest
.
class
);
public
static
void
main
(
String
...
ignore
)
throws
Throwable
{
System
.
out
.
println
(
"can run this as:"
);
System
.
out
.
println
(
"$ java org.junit.runner.JUnitCore "
+
JavaDocExamplesTest
.
class
.
getName
());
new
JavaDocExamplesTest
().
run
();
}
public
void
run
()
throws
Throwable
{
testFindVirtual
();
testPermuteArguments
();
testDropArguments
();
testFilterArguments
();
testFoldArguments
();
testMethodHandlesSummary
();
testAsSpreader
();
testAsCollector
();
testAsVarargsCollector
();
testAsFixedArity
();
testAsTypeCornerCases
();
testMutableCallSite
();
}
// How much output?
static
int
verbosity
=
Integer
.
getInteger
(
"test.java.lang.invoke.JavaDocExamplesTest.verbosity"
,
0
);
static
final
Class
<?>
THIS_CLASS
=
JavaDocExamplesTest
.
class
;
static
int
verbosity
=
Integer
.
getInteger
(
THIS_CLASS
.
getSimpleName
()+
".verbosity"
,
0
);
{}
static
final
private
Lookup
LOOKUP
=
lookup
();
...
...
@@ -74,17 +90,23 @@ static final private Lookup LOOKUP = lookup();
// "hashCode", methodType(int.class));
// form required if ReflectiveOperationException is intercepted:
static
final
private
MethodHandle
CONCAT_2
,
HASHCODE
_2
;
static
final
private
MethodHandle
CONCAT_2
,
HASHCODE_2
,
ADD_2
,
SUB
_2
;
static
{
try
{
Class
<?>
THIS_CLASS
=
LOOKUP
.
lookupClass
();
CONCAT_2
=
LOOKUP
.
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
HASHCODE_2
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"hashCode"
,
methodType
(
int
.
class
));
ADD_2
=
LOOKUP
.
findStatic
(
THIS_CLASS
,
"add"
,
methodType
(
int
.
class
,
int
.
class
,
int
.
class
));
SUB_2
=
LOOKUP
.
findStatic
(
THIS_CLASS
,
"sub"
,
methodType
(
int
.
class
,
int
.
class
,
int
.
class
));
}
catch
(
ReflectiveOperationException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
static
int
add
(
int
x
,
int
y
)
{
return
x
+
y
;
}
static
int
sub
(
int
x
,
int
y
)
{
return
x
-
y
;
}
{}
@Test
public
void
testFindVirtual
()
throws
Throwable
{
...
...
@@ -101,6 +123,39 @@ assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy"));
assertEquals
(
"xy"
.
hashCode
(),
(
int
)
HASHCODE_3
.
invokeExact
((
Object
)
"xy"
));
{}
}
@Test
public
void
testPermuteArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodType
intfn1
=
methodType
(
int
.
class
,
int
.
class
);
MethodType
intfn2
=
methodType
(
int
.
class
,
int
.
class
,
int
.
class
);
MethodHandle
sub
=
SUB_2
;
// ... {int x, int y => x-y} ...;
assert
(
sub
.
type
().
equals
(
intfn2
));
MethodHandle
sub1
=
permuteArguments
(
sub
,
intfn2
,
0
,
1
);
MethodHandle
rsub
=
permuteArguments
(
sub
,
intfn2
,
1
,
0
);
assert
((
int
)
rsub
.
invokeExact
(
1
,
100
)
==
99
);
MethodHandle
add
=
ADD_2
;
// ... {int x, int y => x+y} ...;
assert
(
add
.
type
().
equals
(
intfn2
));
MethodHandle
twice
=
permuteArguments
(
add
,
intfn1
,
0
,
0
);
assert
(
twice
.
type
().
equals
(
intfn1
));
assert
((
int
)
twice
.
invokeExact
(
21
)
==
42
);
}}
{{
{}
/// JAVADOC
MethodHandle
cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
assertEquals
(
"xy"
,
(
String
)
cat
.
invokeExact
(
"x"
,
"y"
));
MethodHandle
d0
=
dropArguments
(
cat
,
0
,
String
.
class
);
assertEquals
(
"yz"
,
(
String
)
d0
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d1
=
dropArguments
(
cat
,
1
,
String
.
class
);
assertEquals
(
"xz"
,
(
String
)
d1
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d2
=
dropArguments
(
cat
,
2
,
String
.
class
);
assertEquals
(
"xy"
,
(
String
)
d2
.
invokeExact
(
"x"
,
"y"
,
"z"
));
MethodHandle
d12
=
dropArguments
(
cat
,
1
,
int
.
class
,
boolean
.
class
);
assertEquals
(
"xz"
,
(
String
)
d12
.
invokeExact
(
"x"
,
12
,
true
,
"z"
));
}}
}
@Test
public
void
testDropArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
...
...
@@ -145,6 +200,21 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
}}
}
@Test
public
void
testFoldArguments
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
trace
=
publicLookup
().
findVirtual
(
java
.
io
.
PrintStream
.
class
,
"println"
,
methodType
(
void
.
class
,
String
.
class
))
.
bindTo
(
System
.
out
);
MethodHandle
cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
assertEquals
(
"boojum"
,
(
String
)
cat
.
invokeExact
(
"boo"
,
"jum"
));
MethodHandle
catTrace
=
foldArguments
(
cat
,
trace
);
// also prints "boo":
assertEquals
(
"boojum"
,
(
String
)
catTrace
.
invokeExact
(
"boo"
,
"jum"
));
}}
}
static
void
assertEquals
(
Object
exp
,
Object
act
)
{
if
(
verbosity
>
0
)
System
.
out
.
println
(
"result: "
+
act
);
...
...
@@ -162,24 +232,24 @@ mt = MethodType.methodType(String.class, char.class, char.class);
mh
=
lookup
.
findVirtual
(
String
.
class
,
"replace"
,
mt
);
s
=
(
String
)
mh
.
invokeExact
(
"daddy"
,
'd'
,
'n'
);
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assert
(
s
.
equals
(
"nanny"
)
);
assert
Equals
(
s
,
"nanny"
);
// weakly typed invocation (using MHs.invoke)
s
=
(
String
)
mh
.
invokeWithArguments
(
"sappy"
,
'p'
,
'v'
);
assert
(
s
.
equals
(
"savvy"
)
);
assert
Equals
(
s
,
"savvy"
);
// mt is (Object[])List
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
assert
(
mh
.
isVarargsCollector
());
x
=
mh
.
invoke
(
"one"
,
"two"
);
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)
));
assert
Equals
(
x
,
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
));
// mt is (Object,Object,Object)Object
mt
=
MethodType
.
genericMethodType
(
3
);
mh
=
mh
.
asType
(
mt
);
x
=
mh
.
invokeExact
((
Object
)
1
,
(
Object
)
2
,
(
Object
)
3
);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
)
));
// mt is
{ => int}
assert
Equals
(
x
,
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
));
// mt is
()int
mt
=
MethodType
.
methodType
(
int
.
class
);
mh
=
lookup
.
findVirtual
(
java
.
util
.
List
.
class
,
"size"
,
mt
);
i
=
(
int
)
mh
.
invokeExact
(
java
.
util
.
Arrays
.
asList
(
1
,
2
,
3
));
...
...
@@ -193,37 +263,239 @@ mh.invokeExact(System.out, "Hello, world.");
}}
}
@Test
public
void
testAsSpreader
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
equals
=
publicLookup
()
.
findVirtual
(
String
.
class
,
"equals"
,
methodType
(
boolean
.
class
,
Object
.
class
));
assert
(
(
boolean
)
equals
.
invokeExact
(
"me"
,
(
Object
)
"me"
));
assert
(!(
boolean
)
equals
.
invokeExact
(
"me"
,
(
Object
)
"thee"
));
// spread both arguments from a 2-array:
MethodHandle
eq2
=
equals
.
asSpreader
(
Object
[].
class
,
2
);
assert
(
(
boolean
)
eq2
.
invokeExact
(
new
Object
[]{
"me"
,
"me"
}));
assert
(!(
boolean
)
eq2
.
invokeExact
(
new
Object
[]{
"me"
,
"thee"
}));
// spread both arguments from a String array:
MethodHandle
eq2s
=
equals
.
asSpreader
(
String
[].
class
,
2
);
assert
(
(
boolean
)
eq2s
.
invokeExact
(
new
String
[]{
"me"
,
"me"
}));
assert
(!(
boolean
)
eq2s
.
invokeExact
(
new
String
[]{
"me"
,
"thee"
}));
// spread second arguments from a 1-array:
MethodHandle
eq1
=
equals
.
asSpreader
(
Object
[].
class
,
1
);
assert
(
(
boolean
)
eq1
.
invokeExact
(
"me"
,
new
Object
[]{
"me"
}));
assert
(!(
boolean
)
eq1
.
invokeExact
(
"me"
,
new
Object
[]{
"thee"
}));
// spread no arguments from a 0-array or null:
MethodHandle
eq0
=
equals
.
asSpreader
(
Object
[].
class
,
0
);
assert
(
(
boolean
)
eq0
.
invokeExact
(
"me"
,
(
Object
)
"me"
,
new
Object
[
0
]));
assert
(!(
boolean
)
eq0
.
invokeExact
(
"me"
,
(
Object
)
"thee"
,
(
Object
[])
null
));
// asSpreader and asCollector are approximate inverses:
for
(
int
n
=
0
;
n
<=
2
;
n
++)
{
for
(
Class
<?>
a
:
new
Class
<?>[]{
Object
[].
class
,
String
[].
class
,
CharSequence
[].
class
})
{
MethodHandle
equals2
=
equals
.
asSpreader
(
a
,
n
).
asCollector
(
a
,
n
);
assert
(
(
boolean
)
equals2
.
invokeWithArguments
(
"me"
,
"me"
));
assert
(!(
boolean
)
equals2
.
invokeWithArguments
(
"me"
,
"thee"
));
}
}
MethodHandle
caToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
char
[].
class
));
assertEquals
(
"[A, B, C]"
,
(
String
)
caToString
.
invokeExact
(
"ABC"
.
toCharArray
()));
MethodHandle
caString3
=
caToString
.
asCollector
(
char
[].
class
,
3
);
assertEquals
(
"[A, B, C]"
,
(
String
)
caString3
.
invokeExact
(
'A'
,
'B'
,
'C'
));
MethodHandle
caToString2
=
caString3
.
asSpreader
(
char
[].
class
,
2
);
assertEquals
(
"[A, B, C]"
,
(
String
)
caToString2
.
invokeExact
(
'A'
,
"BC"
.
toCharArray
()));
}}
}
@Test
public
void
testAsCollector
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
deepToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"deepToString"
,
methodType
(
String
.
class
,
Object
[].
class
));
assertEquals
(
"[won]"
,
(
String
)
deepToString
.
invokeExact
(
new
Object
[]{
"won"
}));
MethodHandle
ts1
=
deepToString
.
asCollector
(
Object
[].
class
,
1
);
assertEquals
(
methodType
(
String
.
class
,
Object
.
class
),
ts1
.
type
());
//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
assertEquals
(
"[[won]]"
,
(
String
)
ts1
.
invokeExact
((
Object
)
new
Object
[]{
"won"
}));
// arrayType can be a subtype of Object[]
MethodHandle
ts2
=
deepToString
.
asCollector
(
String
[].
class
,
2
);
assertEquals
(
methodType
(
String
.
class
,
String
.
class
,
String
.
class
),
ts2
.
type
());
assertEquals
(
"[two, too]"
,
(
String
)
ts2
.
invokeExact
(
"two"
,
"too"
));
MethodHandle
ts0
=
deepToString
.
asCollector
(
Object
[].
class
,
0
);
assertEquals
(
"[]"
,
(
String
)
ts0
.
invokeExact
());
// collectors can be nested, Lisp-style
MethodHandle
ts22
=
deepToString
.
asCollector
(
Object
[].
class
,
3
).
asCollector
(
String
[].
class
,
2
);
assertEquals
(
"[A, B, [C, D]]"
,
((
String
)
ts22
.
invokeExact
((
Object
)
'A'
,
(
Object
)
"B"
,
"C"
,
"D"
)));
// arrayType can be any primitive array type
MethodHandle
bytesToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
byte
[].
class
))
.
asCollector
(
byte
[].
class
,
3
);
assertEquals
(
"[1, 2, 3]"
,
(
String
)
bytesToString
.
invokeExact
((
byte
)
1
,
(
byte
)
2
,
(
byte
)
3
));
MethodHandle
longsToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"toString"
,
methodType
(
String
.
class
,
long
[].
class
))
.
asCollector
(
long
[].
class
,
1
);
assertEquals
(
"[123]"
,
(
String
)
longsToString
.
invokeExact
((
long
)
123
));
}}
}
@Test
public
void
testAsVarargsCollector
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
deepToString
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"deepToString"
,
methodType
(
String
.
class
,
Object
[].
class
));
MethodHandle
ts1
=
deepToString
.
asVarargsCollector
(
Object
[].
class
);
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invokeExact
(
new
Object
[]{
"won"
}));
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invoke
(
new
Object
[]{
"won"
}));
assertEquals
(
"[won]"
,
(
String
)
ts1
.
invoke
(
"won"
));
assertEquals
(
"[[won]]"
,
(
String
)
ts1
.
invoke
((
Object
)
new
Object
[]{
"won"
}));
// findStatic of Arrays.asList(...) produces a variable arity method handle:
MethodHandle
asList
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
));
assertEquals
(
methodType
(
List
.
class
,
Object
[].
class
),
asList
.
type
());
assert
(
asList
.
isVarargsCollector
());
assertEquals
(
"[]"
,
asList
.
invoke
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
(
"two"
,
"too"
).
toString
());
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
String
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
(
argv
).
toString
());
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
((
Object
[])
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
((
Object
)
argv
);
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
}}
}
@Test
public
void
test
VarargsCollectorSuppression
()
throws
Throwable
{
@Test
public
void
test
AsFixedArity
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
vamh
=
publicLookup
()
MethodHandle
asListVar
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
assert
(
vamh
.
type
().
equals
(
mh
.
type
()));
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
(
1
,
2
,
3
).
toString
());
boolean
failed
=
false
;
try
{
mh
.
invoke
(
1
,
2
,
3
);
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
assert
(
failed
);
MethodHandle
asListFix
=
asListVar
.
asFixedArity
();
assertEquals
(
"[1]"
,
asListVar
.
invoke
(
1
).
toString
());
Exception
caught
=
null
;
try
{
asListFix
.
invoke
((
Object
)
1
);
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
assertEquals
(
"[two, too]"
,
asListVar
.
invoke
(
"two"
,
"too"
).
toString
());
try
{
asListFix
.
invoke
(
"two"
,
"too"
);
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asListVar
.
invoke
(
argv
).
toString
());
assertEquals
(
"[three, thee, tee]"
,
asListFix
.
invoke
(
argv
).
toString
());
assertEquals
(
1
,
((
List
)
asListVar
.
invoke
((
Object
)
argv
)).
size
());
assertEquals
(
"[three, thee, tee]"
,
asListFix
.
invoke
((
Object
)
argv
).
toString
());
}}
}
@Test
public
void
testAsTypeCornerCases
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
i2s
=
publicLookup
()
.
findVirtual
(
Integer
.
class
,
"toString"
,
methodType
(
String
.
class
));
i2s
=
i2s
.
asType
(
i2s
.
type
().
unwrap
());
MethodHandle
l2s
=
publicLookup
()
.
findVirtual
(
Long
.
class
,
"toString"
,
methodType
(
String
.
class
));
l2s
=
l2s
.
asType
(
l2s
.
type
().
unwrap
());
Exception
caught
=
null
;
try
{
i2s
.
asType
(
methodType
(
String
.
class
,
String
.
class
));
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
i2s
.
asType
(
methodType
(
String
.
class
,
byte
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Byte
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Character
.
class
));
i2s
.
asType
(
methodType
(
String
.
class
,
Integer
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
byte
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Byte
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Character
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Integer
.
class
));
l2s
.
asType
(
methodType
(
String
.
class
,
Long
.
class
));
caught
=
null
;
try
{
i2s
.
asType
(
methodType
(
String
.
class
,
Long
.
class
));
}
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
WrongMethodTypeException
);
MethodHandle
i2sGen
=
i2s
.
asType
(
methodType
(
String
.
class
,
Object
.
class
));
MethodHandle
l2sGen
=
l2s
.
asType
(
methodType
(
String
.
class
,
Object
.
class
));
i2sGen
.
invoke
(
42
);
// int -> Integer -> Object -> Integer -> int
i2sGen
.
invoke
((
byte
)
4
);
// byte -> Byte -> Object -> Byte -> byte -> int
l2sGen
.
invoke
(
42
);
// int -> Integer -> Object -> Integer -> int
l2sGen
.
invoke
((
byte
)
4
);
// byte -> Byte -> Object -> Byte -> byte -> int
l2sGen
.
invoke
(
0x420000000
L
);
caught
=
null
;
try
{
i2sGen
.
invoke
(
0x420000000
L
);
}
// long -> Long -> Object -> Integer CCE
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
caught
=
null
;
try
{
i2sGen
.
invoke
(
"asdf"
);
}
// String -> Object -> Integer CCE
catch
(
Exception
ex
)
{
caught
=
ex
;
}
assert
(
caught
instanceof
ClassCastException
);
{}
}}
}
@Test
public
void
testMutableCallSite
()
throws
Throwable
{
{{
{}
/// JAVADOC
MutableCallSite
name
=
new
MutableCallSite
(
MethodType
.
methodType
(
String
.
class
));
MethodHandle
MH_name
=
name
.
dynamicInvoker
();
MethodType
MT_str1
=
MethodType
.
methodType
(
String
.
class
);
MethodHandle
MH_upcase
=
MethodHandles
.
lookup
()
.
findVirtual
(
String
.
class
,
"toUpperCase"
,
MT_str1
);
MethodHandle
worker1
=
MethodHandles
.
filterReturnValue
(
MH_name
,
MH_upcase
);
name
.
setTarget
(
MethodHandles
.
constant
(
String
.
class
,
"Rocky"
));
assertEquals
(
"ROCKY"
,
(
String
)
worker1
.
invokeExact
());
name
.
setTarget
(
MethodHandles
.
constant
(
String
.
class
,
"Fred"
));
assertEquals
(
"FRED"
,
(
String
)
worker1
.
invokeExact
());
// (mutation can be continued indefinitely)
/*
* </pre></blockquote>
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
*/
MethodType
MT_str2
=
MethodType
.
methodType
(
String
.
class
,
String
.
class
);
MethodHandle
MH_cat
=
lookup
().
findVirtual
(
String
.
class
,
"concat"
,
methodType
(
String
.
class
,
String
.
class
));
MethodHandle
MH_dear
=
MethodHandles
.
insertArguments
(
MH_cat
,
1
,
", dear?"
);
MethodHandle
worker2
=
MethodHandles
.
filterReturnValue
(
MH_name
,
MH_dear
);
assertEquals
(
"Fred, dear?"
,
(
String
)
worker2
.
invokeExact
());
name
.
setTarget
(
MethodHandles
.
constant
(
String
.
class
,
"Wilma"
));
assertEquals
(
"WILMA"
,
(
String
)
worker1
.
invokeExact
());
assertEquals
(
"Wilma, dear?"
,
(
String
)
worker2
.
invokeExact
());
{}
}}
}
@Test
public
void
testSwitchPoint
()
throws
Throwable
{
{{
{}
/// JAVADOC
MethodHandle
MH_strcat
=
MethodHandles
.
lookup
()
.
findVirtual
(
String
.
class
,
"concat"
,
MethodType
.
methodType
(
String
.
class
,
String
.
class
));
SwitchPoint
spt
=
new
SwitchPoint
();
assert
(
spt
.
isValid
());
// the following steps may be repeated to re-use the same switch point:
MethodHandle
worker1
=
MH_strcat
;
MethodHandle
worker2
=
MethodHandles
.
permuteArguments
(
MH_strcat
,
MH_strcat
.
type
(),
1
,
0
);
MethodHandle
worker
=
spt
.
guardWithTest
(
worker1
,
worker2
);
assertEquals
(
"method"
,
(
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
SwitchPoint
.
invalidateAll
(
new
SwitchPoint
[]{
spt
});
assert
(!
spt
.
isValid
());
assertEquals
(
"hodmet"
,
(
String
)
worker
.
invokeExact
(
"met"
,
"hod"
));
{}
}}
}
/* ---- TEMPLATE ----
@Test public void testFoo() throws Throwable {
{{
{} /// JAVADOC
{}
}}
}
*/
}
test/java/lang/invoke/MethodHandlesTest.java
浏览文件 @
10995d86
...
...
@@ -100,6 +100,31 @@ public class MethodHandlesTest {
// ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
testInsertArguments
(
0
,
0
,
MAX_ARG_INCREASE
+
10
);
}
@Test
@Ignore
(
"permuteArguments has trouble with double slots"
)
public
void
testFail_7
()
throws
Throwable
{
testPermuteArguments
(
new
Object
[]{
10
,
200L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
},
new
int
[]{
1
,
0
});
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
0
,
1
});
//rot
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
1
,
2
,
0
});
//rot
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
1
,
0
});
//swap
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
0
,
1
,
2
,
2
});
//dup
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
0
,
1
,
2
});
testPermuteArguments
(
new
Object
[]{
10
,
200L
,
5000L
},
new
Class
<?>[]{
Integer
.
class
,
long
.
class
,
long
.
class
},
new
int
[]{
2
,
2
,
0
,
1
});
testPermuteArguments
(
4
,
Integer
.
class
,
2
,
long
.
class
,
6
);
}
static
final
int
MAX_ARG_INCREASE
=
3
;
public
MethodHandlesTest
()
{
...
...
@@ -356,7 +381,7 @@ public class MethodHandlesTest {
ArrayList
<
Class
<?>>
argTypes
=
new
ArrayList
<
Class
<?>>(
targetType
.
parameterList
());
Collections
.
fill
(
argTypes
.
subList
(
beg
,
end
),
argType
);
MethodType
ttype2
=
MethodType
.
methodType
(
targetType
.
returnType
(),
argTypes
);
return
MethodHandles
.
convertArguments
(
target
,
ttype2
);
return
target
.
asType
(
ttype2
);
}
// This lookup is good for all members in and under MethodHandlesTest.
...
...
@@ -1005,13 +1030,13 @@ public class MethodHandlesTest {
Class
<?>
vtype
=
ftype
;
if
(
ftype
!=
int
.
class
)
vtype
=
Object
.
class
;
if
(
isGetter
)
{
mh
=
MethodHandles
.
convertArguments
(
mh
,
mh
.
type
().
generic
()
.
changeReturnType
(
vtype
));
mh
=
mh
.
asType
(
mh
.
type
().
generic
()
.
changeReturnType
(
vtype
));
}
else
{
int
last
=
mh
.
type
().
parameterCount
()
-
1
;
mh
=
MethodHandles
.
convertArguments
(
mh
,
mh
.
type
().
generic
()
.
changeReturnType
(
void
.
class
)
.
changeParameterType
(
last
,
vtype
));
mh
=
mh
.
asType
(
mh
.
type
().
generic
()
.
changeReturnType
(
void
.
class
)
.
changeParameterType
(
last
,
vtype
));
}
if
(
f
!=
null
&&
f
.
getDeclaringClass
()
==
HasFields
.
class
)
{
assertEquals
(
f
.
get
(
fields
),
value
);
// clean to start with
...
...
@@ -1139,7 +1164,7 @@ public class MethodHandlesTest {
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
MethodType
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
Integer
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeReturnType
(
void
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
mh
=
mh
.
asType
(
gtype
);
}
Object
sawValue
,
expValue
;
List
<
Object
>
model
=
array2list
(
array
);
...
...
@@ -1233,11 +1258,10 @@ public class MethodHandlesTest {
}
void
testConvert
(
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
testConvert
(
true
,
false
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
true
,
id
,
rtype
,
name
,
params
);
testConvert
(
true
,
id
,
rtype
,
name
,
params
);
}
void
testConvert
(
boolean
positive
,
boolean
useAsType
,
void
testConvert
(
boolean
positive
,
MethodHandle
id
,
Class
<?>
rtype
,
String
name
,
Class
<?>...
params
)
throws
Throwable
{
countTest
(
positive
);
MethodType
idType
=
id
.
type
();
...
...
@@ -1265,10 +1289,7 @@ public class MethodHandlesTest {
MethodHandle
target
=
null
;
RuntimeException
error
=
null
;
try
{
if
(
useAsType
)
target
=
id
.
asType
(
newType
);
else
target
=
MethodHandles
.
convertArguments
(
id
,
newType
);
target
=
id
.
asType
(
newType
);
}
catch
(
RuntimeException
ex
)
{
error
=
ex
;
}
...
...
@@ -1293,11 +1314,11 @@ public class MethodHandlesTest {
MethodType
.
methodType
(
Object
.
class
,
String
.
class
,
Object
[].
class
));
vac0
=
vac0
.
bindTo
(
"vac"
);
MethodHandle
vac
=
vac0
.
asVarargsCollector
(
Object
[].
class
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
0
)),
null
,
"vac"
);
for
(
Class
<?>
at
:
new
Class
[]
{
Object
.
class
,
String
.
class
,
Integer
.
class
})
{
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
1
)),
null
,
"vac"
,
at
);
testConvert
(
true
,
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
2
)),
null
,
"vac"
,
at
,
at
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
1
)),
null
,
"vac"
,
at
);
testConvert
(
true
,
vac
.
asType
(
MethodType
.
genericMethodType
(
2
)),
null
,
"vac"
,
at
,
at
);
}
}
...
...
@@ -1306,8 +1327,8 @@ public class MethodHandlesTest {
if
(
CAN_SKIP_WORKING
)
return
;
startTest
(
"permuteArguments"
);
testPermuteArguments
(
4
,
Integer
.
class
,
2
,
String
.
class
,
0
);
//
testPermuteArguments(6, Integer.class, 0, null, 30);
//testPermuteArguments(4, Integer.class,
1, int.class, 6);
testPermuteArguments
(
6
,
Integer
.
class
,
0
,
null
,
30
);
//testPermuteArguments(4, Integer.class,
2, long.class, 6); // FIXME Fail_7
}
public
void
testPermuteArguments
(
int
max
,
Class
<?>
type1
,
int
t2c
,
Class
<?>
type2
,
int
dilution
)
throws
Throwable
{
if
(
verbosity
>=
2
)
...
...
@@ -1421,8 +1442,9 @@ public class MethodHandlesTest {
}
MethodType
inType
=
MethodType
.
methodType
(
Object
.
class
,
types
);
MethodType
outType
=
MethodType
.
methodType
(
Object
.
class
,
permTypes
);
MethodHandle
target
=
MethodHandles
.
convertArguments
(
varargsList
(
outargs
),
outType
);
MethodHandle
target
=
varargsList
(
outargs
).
asType
(
outType
);
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
if
(
verbosity
>=
5
)
System
.
out
.
println
(
"newTarget = "
+
newTarget
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
if
(!
expected
.
equals
(
result
))
{
...
...
@@ -1666,7 +1688,7 @@ public class MethodHandlesTest {
countTest
();
MethodHandle
target
=
varargsList
(
nargs
);
MethodHandle
filter
=
varargsList
(
1
);
filter
=
MethodHandles
.
convertArguments
(
filter
,
filter
.
type
().
generic
());
filter
=
filter
.
asType
(
filter
.
type
().
generic
());
Object
[]
argsToPass
=
randomArgs
(
nargs
,
Object
.
class
);
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"filter "
+
target
+
" at "
+
pos
+
" with "
+
filter
);
...
...
@@ -1807,7 +1829,7 @@ public class MethodHandlesTest {
// generic invoker
countTest
();
inv
=
MethodHandles
.
invoker
(
type
);
if
(
nargs
<=
3
)
{
if
(
nargs
<=
3
&&
type
==
type
.
generic
()
)
{
calledLog
.
clear
();
switch
(
nargs
)
{
case
0
:
...
...
@@ -1833,10 +1855,16 @@ public class MethodHandlesTest {
// varargs invoker #0
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
0
);
result
=
inv
.
invokeExact
(
target
,
args
);
if
(
type
.
returnType
()
==
Object
.
class
)
{
result
=
inv
.
invokeExact
(
target
,
args
);
}
else
if
(
type
.
returnType
()
==
void
.
class
)
{
result
=
null
;
inv
.
invokeExact
(
target
,
args
);
}
else
{
result
=
inv
.
invokeWithArguments
(
target
,
(
Object
)
args
);
}
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
if
(
nargs
>=
1
)
{
if
(
nargs
>=
1
&&
type
==
type
.
generic
()
)
{
// varargs invoker #1
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
1
);
...
...
@@ -1844,7 +1872,7 @@ public class MethodHandlesTest {
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
}
if
(
nargs
>=
2
)
{
if
(
nargs
>=
2
&&
type
==
type
.
generic
()
)
{
// varargs invoker #2
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
2
);
...
...
@@ -1852,7 +1880,7 @@ public class MethodHandlesTest {
if
(
testRetCode
)
assertEquals
(
code
,
result
);
assertCalled
(
"invokee"
,
args
);
}
if
(
nargs
>=
3
)
{
if
(
nargs
>=
3
&&
type
==
type
.
generic
()
)
{
// varargs invoker #3
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
3
);
...
...
@@ -1865,6 +1893,10 @@ public class MethodHandlesTest {
countTest
();
calledLog
.
clear
();
inv
=
MethodHandles
.
spreadInvoker
(
type
,
k
);
MethodType
expType
=
(
type
.
dropParameterTypes
(
k
,
nargs
)
.
appendParameterTypes
(
Object
[].
class
)
.
insertParameterTypes
(
0
,
MethodHandle
.
class
));
assertEquals
(
expType
,
inv
.
type
());
List
<
Object
>
targetPlusVarArgs
=
new
ArrayList
<
Object
>(
targetPlusArgs
);
List
<
Object
>
tailList
=
targetPlusVarArgs
.
subList
(
1
+
k
,
1
+
nargs
);
Object
[]
tail
=
tailList
.
toArray
();
...
...
@@ -2045,7 +2077,7 @@ public class MethodHandlesTest {
//System.out.println("throwing with "+target+" : "+thrown);
MethodType
expectedType
=
MethodType
.
methodType
(
returnType
,
exType
);
assertEquals
(
expectedType
,
target
.
type
());
target
=
MethodHandles
.
convertArguments
(
target
,
target
.
type
().
generic
());
target
=
target
.
asType
(
target
.
type
().
generic
());
Throwable
caught
=
null
;
try
{
Object
res
=
target
.
invokeExact
((
Object
)
thrown
);
...
...
@@ -2117,12 +2149,12 @@ public class MethodHandlesTest {
if
(
mode
.
endsWith
(
"/return"
))
{
if
(
mode
.
equals
(
"unbox/return"
))
{
// fail on return to ((Integer)surprise).intValue
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
surprise
=
surprise
.
asType
(
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
identity
=
identity
.
asType
(
MethodType
.
methodType
(
int
.
class
,
Object
.
class
));
}
else
if
(
mode
.
equals
(
"cast/return"
))
{
// fail on return to (Integer)surprise
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
surprise
=
surprise
.
asType
(
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
identity
=
identity
.
asType
(
MethodType
.
methodType
(
Integer
.
class
,
Object
.
class
));
}
}
else
if
(
mode
.
endsWith
(
"/argument"
))
{
MethodHandle
callee
=
null
;
...
...
@@ -2134,14 +2166,14 @@ public class MethodHandlesTest {
callee
=
Surprise
.
BOX_IDENTITY
;
}
if
(
callee
!=
null
)
{
callee
=
MethodHandles
.
convertArguments
(
callee
,
MethodType
.
genericMethodType
(
1
));
callee
=
callee
.
asType
(
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
filterArguments
(
callee
,
0
,
surprise
);
identity
=
MethodHandles
.
filterArguments
(
callee
,
0
,
identity
);
}
}
assertNotSame
(
mode
,
surprise
,
surprise0
);
identity
=
MethodHandles
.
convertArguments
(
identity
,
MethodType
.
genericMethodType
(
1
));
surprise
=
MethodHandles
.
convertArguments
(
surprise
,
MethodType
.
genericMethodType
(
1
));
identity
=
identity
.
asType
(
MethodType
.
genericMethodType
(
1
));
surprise
=
surprise
.
asType
(
MethodType
.
genericMethodType
(
1
));
Object
x
=
42
;
for
(
int
i
=
0
;
i
<
okCount
;
i
++)
{
Object
y
=
identity
.
invokeExact
(
x
);
...
...
@@ -2230,14 +2262,14 @@ public class MethodHandlesTest {
{
MethodType
mt
=
MethodType
.
methodType
(
void
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"runForRunnable"
,
mt
);
Runnable
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
Runnable
.
class
);
Runnable
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
Runnable
.
class
,
mh
);
proxy
.
run
();
assertCalled
(
"runForRunnable"
);
}
{
MethodType
mt
=
MethodType
.
methodType
(
Object
.
class
,
Fooable
.
class
,
Object
.
class
);
MethodHandle
mh
=
lookup
.
findStatic
(
MethodHandlesTest
.
class
,
"fooForFooable"
,
mt
);
Fooable
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
Fooable
.
class
);
Fooable
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
Fooable
.
class
,
mh
);
Object
[]
args
=
randomArgs
(
mt
.
parameterArray
());
Object
result
=
proxy
.
foo
((
Fooable
)
args
[
0
],
args
[
1
]);
assertCalled
(
"fooForFooable"
,
args
);
...
...
@@ -2251,7 +2283,7 @@ public class MethodHandlesTest {
})
{
MethodHandle
mh
=
MethodHandles
.
throwException
(
void
.
class
,
Throwable
.
class
);
mh
=
MethodHandles
.
insertArguments
(
mh
,
0
,
ex
);
WillThrow
proxy
=
MethodHandle
s
.
asInstance
(
mh
,
WillThrow
.
class
);
WillThrow
proxy
=
MethodHandle
Proxies
.
asInterfaceInstance
(
WillThrow
.
class
,
mh
);
try
{
proxy
.
willThrow
();
System
.
out
.
println
(
"Failed to throw: "
+
ex
);
...
...
@@ -2279,7 +2311,7 @@ public class MethodHandlesTest {
CharSequence
.
class
,
Example
.
class
})
{
try
{
MethodHandle
s
.
asInstance
(
varargsArray
(
0
),
nonSAM
);
MethodHandle
Proxies
.
asInterfaceInstance
(
nonSAM
,
varargsArray
(
0
)
);
System
.
out
.
println
(
"Failed to throw"
);
assertTrue
(
false
);
}
catch
(
IllegalArgumentException
ex
)
{
...
...
test/java/lang/invoke/indify/Indify.java
浏览文件 @
10995d86
...
...
@@ -524,6 +524,8 @@ public class Indify {
if
(
verifySpecifierCount
>=
0
)
{
List
<
Object
[]>
specs
=
bootstrapMethodSpecifiers
(
false
);
int
specsLen
=
(
specs
==
null
?
0
:
specs
.
size
());
// Pass by specsLen == 0, to help with associated (inner) classes.
if
(
specsLen
==
0
)
specsLen
=
verifySpecifierCount
;
if
(
specsLen
!=
verifySpecifierCount
)
{
throw
new
IllegalArgumentException
(
"BootstrapMethods length is "
+
specsLen
+
" but should be "
+
verifySpecifierCount
);
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录