Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
4b939f2a
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看板
提交
4b939f2a
编写于
5月 18, 2011
作者:
S
schien
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
8bfae86c
4ed3d9c8
变更
27
展开全部
隐藏空白更改
内联
并排
Showing
27 changed file
with
3304 addition
and
737 deletion
+3304
-737
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
+259
-62
src/share/classes/java/lang/invoke/CallSite.java
src/share/classes/java/lang/invoke/CallSite.java
+4
-4
src/share/classes/java/lang/invoke/FilterGeneric.java
src/share/classes/java/lang/invoke/FilterGeneric.java
+4
-0
src/share/classes/java/lang/invoke/FilterOneArgument.java
src/share/classes/java/lang/invoke/FilterOneArgument.java
+4
-0
src/share/classes/java/lang/invoke/FromGeneric.java
src/share/classes/java/lang/invoke/FromGeneric.java
+8
-5
src/share/classes/java/lang/invoke/InvokeGeneric.java
src/share/classes/java/lang/invoke/InvokeGeneric.java
+3
-3
src/share/classes/java/lang/invoke/Invokers.java
src/share/classes/java/lang/invoke/Invokers.java
+11
-11
src/share/classes/java/lang/invoke/MemberName.java
src/share/classes/java/lang/invoke/MemberName.java
+1
-1
src/share/classes/java/lang/invoke/MethodHandle.java
src/share/classes/java/lang/invoke/MethodHandle.java
+84
-64
src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
+316
-237
src/share/classes/java/lang/invoke/MethodHandleNatives.java
src/share/classes/java/lang/invoke/MethodHandleNatives.java
+68
-17
src/share/classes/java/lang/invoke/MethodHandleStatics.java
src/share/classes/java/lang/invoke/MethodHandleStatics.java
+18
-2
src/share/classes/java/lang/invoke/MethodHandles.java
src/share/classes/java/lang/invoke/MethodHandles.java
+85
-54
src/share/classes/java/lang/invoke/MethodType.java
src/share/classes/java/lang/invoke/MethodType.java
+34
-9
src/share/classes/java/lang/invoke/MethodTypeForm.java
src/share/classes/java/lang/invoke/MethodTypeForm.java
+4
-3
src/share/classes/java/lang/invoke/SpreadGeneric.java
src/share/classes/java/lang/invoke/SpreadGeneric.java
+4
-0
src/share/classes/java/lang/invoke/ToGeneric.java
src/share/classes/java/lang/invoke/ToGeneric.java
+11
-7
src/share/classes/java/lang/invoke/package-info.java
src/share/classes/java/lang/invoke/package-info.java
+8
-8
src/share/classes/sun/invoke/util/ValueConversions.java
src/share/classes/sun/invoke/util/ValueConversions.java
+549
-144
src/share/classes/sun/invoke/util/VerifyType.java
src/share/classes/sun/invoke/util/VerifyType.java
+9
-2
src/share/classes/sun/invoke/util/Wrapper.java
src/share/classes/sun/invoke/util/Wrapper.java
+119
-18
test/java/lang/invoke/6998541/Test6998541.java
test/java/lang/invoke/6998541/Test6998541.java
+513
-0
test/java/lang/invoke/InvokeGenericTest.java
test/java/lang/invoke/InvokeGenericTest.java
+41
-13
test/java/lang/invoke/JavaDocExamplesTest.java
test/java/lang/invoke/JavaDocExamplesTest.java
+9
-9
test/java/lang/invoke/MethodHandlesTest.java
test/java/lang/invoke/MethodHandlesTest.java
+108
-64
test/java/lang/invoke/RicochetTest.java
test/java/lang/invoke/RicochetTest.java
+582
-0
test/sun/invoke/util/ValueConversionsTest.java
test/sun/invoke/util/ValueConversionsTest.java
+448
-0
未找到文件。
src/share/classes/java/lang/invoke/AdapterMethodHandle.java
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
src/share/classes/java/lang/invoke/CallSite.java
浏览文件 @
4b939f2a
...
...
@@ -273,9 +273,9 @@ public class CallSite {
Object
binding
;
info
=
maybeReBox
(
info
);
if
(
info
==
null
)
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
);
}
else
if
(!
info
.
getClass
().
isArray
())
{
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
,
info
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
,
info
);
}
else
{
Object
[]
argv
=
(
Object
[])
info
;
maybeReBoxElements
(
argv
);
...
...
@@ -283,10 +283,10 @@ public class CallSite {
throw
new
BootstrapMethodError
(
"too many bootstrap method arguments"
);
MethodType
bsmType
=
bootstrapMethod
.
type
();
if
(
bsmType
.
parameterCount
()
==
4
&&
bsmType
.
parameterType
(
3
)
==
Object
[].
class
)
binding
=
bootstrapMethod
.
invoke
Generic
(
caller
,
name
,
type
,
argv
);
binding
=
bootstrapMethod
.
invoke
(
caller
,
name
,
type
,
argv
);
else
binding
=
MethodHandles
.
spreadInvoker
(
bsmType
,
3
)
.
invoke
Generic
(
bootstrapMethod
,
caller
,
name
,
type
,
argv
);
.
invoke
(
bootstrapMethod
,
caller
,
name
,
type
,
argv
);
}
//System.out.println("BSM for "+name+type+" => "+binding);
if
(
binding
instanceof
CallSite
)
{
...
...
src/share/classes/java/lang/invoke/FilterGeneric.java
浏览文件 @
4b939f2a
...
...
@@ -61,6 +61,10 @@ class FilterGeneric {
return
ad
;
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
Adapter
makeInstance
(
Kind
kind
,
int
pos
,
MethodHandle
filter
,
MethodHandle
target
)
{
Adapter
ad
=
getAdapter
(
kind
,
pos
);
return
ad
.
makeInstance
(
ad
.
prototypeEntryPoint
(),
filter
,
target
);
...
...
src/share/classes/java/lang/invoke/FilterOneArgument.java
浏览文件 @
4b939f2a
...
...
@@ -67,6 +67,10 @@ class FilterOneArgument extends BoundMethodHandle {
this
.
target
=
target
;
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
public
static
MethodHandle
make
(
MethodHandle
filter
,
MethodHandle
target
)
{
if
(
filter
==
null
)
return
target
;
if
(
target
==
null
)
return
filter
;
...
...
src/share/classes/java/lang/invoke/FromGeneric.java
浏览文件 @
4b939f2a
...
...
@@ -98,6 +98,10 @@ class FromGeneric {
this
.
unboxingInvoker
=
computeUnboxingInvoker
(
targetType
,
internalType0
);
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/**
* The typed target will be called according to targetType.
* The adapter code will in fact see the raw result from internalType,
...
...
@@ -112,10 +116,10 @@ class FromGeneric {
assert
(
iret
==
Object
.
class
);
return
ValueConversions
.
identity
();
}
else
if
(
wrap
.
primitiveType
()
==
iret
)
{
return
ValueConversions
.
box
(
wrap
,
false
);
return
ValueConversions
.
box
(
wrap
);
}
else
{
assert
(
tret
==
double
.
class
?
iret
==
long
.
class
:
iret
==
int
.
class
);
return
ValueConversions
.
boxRaw
(
wrap
,
false
);
return
ValueConversions
.
boxRaw
(
wrap
);
}
}
...
...
@@ -135,7 +139,7 @@ class FromGeneric {
MethodType
fixArgsType
=
internalType
.
changeReturnType
(
targetType
.
returnType
());
MethodHandle
fixArgs
=
MethodHandleImpl
.
convertArguments
(
invoker
,
Invokers
.
invokerType
(
fixArgsType
),
invoker
.
type
(),
null
);
invoker
.
type
(),
0
);
if
(
fixArgs
==
null
)
throw
new
InternalError
(
"bad fixArgs"
);
// reinterpret the calling sequence as raw:
...
...
@@ -160,7 +164,6 @@ class FromGeneric {
/** Build an adapter of the given generic type, which invokes typedTarget
* on the incoming arguments, after unboxing as necessary.
* The return value is boxed if necessary.
* @param genericType the required type of the result
* @param typedTarget the target
* @return an adapter method handle
*/
...
...
@@ -231,7 +234,7 @@ class FromGeneric {
}
static
Adapter
buildAdapterFromBytecodes
(
MethodType
internalType
)
{
throw
new
UnsupportedOperationException
(
"NYI
"
);
throw
new
UnsupportedOperationException
(
"NYI
"
+
internalType
);
}
/**
...
...
src/share/classes/java/lang/invoke/InvokeGeneric.java
浏览文件 @
4b939f2a
...
...
@@ -29,12 +29,12 @@ import sun.invoke.util.*;
import
static
java
.
lang
.
invoke
.
MethodHandles
.
Lookup
.
IMPL_LOOKUP
;
/**
* Adapters which manage
MethodHandle.invokeGeneric
calls.
* Adapters which manage
inexact MethodHandle.invoke
calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
class
InvokeGeneric
{
// erased type for the call, which originates from an in
vokeGeneric
site
// erased type for the call, which originates from an in
exact invoke
site
private
final
MethodType
erasedCallerType
;
// an invoker of type (MT, MH; A...) -> R
private
final
MethodHandle
initialInvoker
;
...
...
@@ -56,7 +56,7 @@ class InvokeGeneric {
}
/** Return the adapter information for this type's erasure. */
/*non-public*/
static
MethodHandle
gener
ic
InvokerOf
(
MethodType
erasedCallerType
)
throws
ReflectiveOperationException
{
/*non-public*/
static
MethodHandle
gener
al
InvokerOf
(
MethodType
erasedCallerType
)
throws
ReflectiveOperationException
{
InvokeGeneric
gen
=
new
InvokeGeneric
(
erasedCallerType
);
return
gen
.
initialInvoker
;
}
...
...
src/share/classes/java/lang/invoke/Invokers.java
浏览文件 @
4b939f2a
...
...
@@ -43,10 +43,10 @@ class Invokers {
private
/*lazy*/
MethodHandle
erasedInvoker
;
/*lazy*/
MethodHandle
erasedInvokerWithDrops
;
// for InvokeGeneric
// gener
ic (untyped)
invoker for the outgoing call
private
/*lazy*/
MethodHandle
gener
ic
Invoker
;
// gener
al
invoker for the outgoing call
private
/*lazy*/
MethodHandle
gener
al
Invoker
;
// gener
ic (untyped)
invoker for the outgoing call; accepts a single Object[]
// gener
al
invoker for the outgoing call; accepts a single Object[]
private
final
/*lazy*/
MethodHandle
[]
spreadInvokers
;
// invoker for an unbound callsite
...
...
@@ -77,13 +77,13 @@ class Invokers {
return
invoker
;
}
/*non-public*/
MethodHandle
gener
ic
Invoker
()
{
/*non-public*/
MethodHandle
gener
al
Invoker
()
{
MethodHandle
invoker1
=
exactInvoker
();
MethodHandle
invoker
=
gener
ic
Invoker
;
MethodHandle
invoker
=
gener
al
Invoker
;
if
(
invoker
!=
null
)
return
invoker
;
MethodType
gener
ic
Type
=
targetType
.
generic
();
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
generic
Type
));
gener
ic
Invoker
=
invoker
;
MethodType
gener
al
Type
=
targetType
.
generic
();
invoker
=
invoker1
.
asType
(
invokerType
(
general
Type
));
gener
al
Invoker
=
invoker
;
return
invoker
;
}
...
...
@@ -93,9 +93,9 @@ class Invokers {
if
(
invoker
!=
null
)
return
invoker
;
MethodType
erasedType
=
targetType
.
erase
();
if
(
erasedType
==
targetType
.
generic
())
invoker
=
gener
ic
Invoker
();
invoker
=
gener
al
Invoker
();
else
invoker
=
MethodHandles
.
convertArguments
(
invoker1
,
invokerType
(
erasedType
));
invoker
=
invoker1
.
asType
(
invokerType
(
erasedType
));
erasedInvoker
=
invoker
;
return
invoker
;
}
...
...
@@ -103,7 +103,7 @@ class Invokers {
/*non-public*/
MethodHandle
spreadInvoker
(
int
objectArgCount
)
{
MethodHandle
vaInvoker
=
spreadInvokers
[
objectArgCount
];
if
(
vaInvoker
!=
null
)
return
vaInvoker
;
MethodHandle
gInvoker
=
gener
ic
Invoker
();
MethodHandle
gInvoker
=
gener
al
Invoker
();
vaInvoker
=
gInvoker
.
asSpreader
(
Object
[].
class
,
targetType
.
parameterCount
()
-
objectArgCount
);
spreadInvokers
[
objectArgCount
]
=
vaInvoker
;
return
vaInvoker
;
...
...
src/share/classes/java/lang/invoke/MemberName.java
浏览文件 @
4b939f2a
...
...
@@ -525,7 +525,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
*/
public
static
class
Factory
{
/*non-public*/
static
class
Factory
{
private
Factory
()
{
}
// singleton pattern
static
Factory
INSTANCE
=
new
Factory
();
...
...
src/share/classes/java/lang/invoke/MethodHandle.java
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
src/share/classes/java/lang/invoke/MethodHandleImpl.java
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
src/share/classes/java/lang/invoke/MethodHandleNatives.java
浏览文件 @
4b939f2a
...
...
@@ -115,6 +115,8 @@ class MethodHandleNatives {
/** Which conv-ops are implemented by the JVM? */
static
final
int
CONV_OP_IMPLEMENTED_MASK
;
/** Derived mode flag. Only false on some old JVM implementations. */
static
final
boolean
HAVE_RICOCHET_FRAMES
;
private
static
native
void
registerNatives
();
static
{
...
...
@@ -141,6 +143,7 @@ class MethodHandleNatives {
if
(
CONV_OP_IMPLEMENTED_MASK_
==
0
)
CONV_OP_IMPLEMENTED_MASK_
=
DEFAULT_CONV_OP_IMPLEMENTED_MASK
;
CONV_OP_IMPLEMENTED_MASK
=
CONV_OP_IMPLEMENTED_MASK_
;
HAVE_RICOCHET_FRAMES
=
(
CONV_OP_IMPLEMENTED_MASK
&
(
1
<<
OP_COLLECT_ARGS
))
!=
0
;
}
// All compile-time constants go here.
...
...
@@ -186,25 +189,26 @@ class MethodHandleNatives {
*/
static
final
int
OP_RETYPE_ONLY
=
0x0
,
// no argument changes; straight retype
OP_RETYPE_RAW
=
0x1
,
//
no argument changes; straight retype
OP_RETYPE_RAW
=
0x1
,
//
straight retype, trusted (void->int, Object->T)
OP_CHECK_CAST
=
0x2
,
// ref-to-ref conversion; requires a Class argument
OP_PRIM_TO_PRIM
=
0x3
,
// converts from one primitive to another
OP_REF_TO_PRIM
=
0x4
,
// unboxes a wrapper to produce a primitive
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
(NYI)
OP_PRIM_TO_REF
=
0x5
,
// boxes a primitive into a wrapper
OP_SWAP_ARGS
=
0x6
,
// swap arguments (vminfo is 2nd arg)
OP_ROT_ARGS
=
0x7
,
// rotate arguments (vminfo is displaced arg)
OP_DUP_ARGS
=
0x8
,
// duplicates one or more arguments (at TOS)
OP_DROP_ARGS
=
0x9
,
// remove one or more argument slots
OP_COLLECT_ARGS
=
0xA
,
// combine
one or more arguments into a varargs (NYI)
OP_COLLECT_ARGS
=
0xA
,
// combine
arguments using an auxiliary function
OP_SPREAD_ARGS
=
0xB
,
// expand in place a varargs array (of known size)
OP_F
LYBY
=
0xC
,
// operate first on reified argument list (NYI)
OP_RICOCHET
=
0xD
,
// run an adapter chain on the return value (NYI)
OP_F
OLD_ARGS
=
0xC
,
// combine but do not remove arguments; prepend result
//OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists
CONV_OP_LIMIT
=
0xE
;
// limit of CONV_OP enumeration
/** Shift and mask values for decoding the AMH.conversion field.
* These numbers are shared with the JVM for creating AMHs.
*/
static
final
int
CONV_OP_MASK
=
0xF00
,
// this nybble contains the conversion op field
CONV_TYPE_MASK
=
0x0F
,
// fits T_ADDRESS and below
CONV_VMINFO_MASK
=
0x0FF
,
// LSB is reserved for JVM use
CONV_VMINFO_SHIFT
=
0
,
// position of bits in CONV_VMINFO_MASK
CONV_OP_SHIFT
=
8
,
// position of bits in CONV_OP_MASK
...
...
@@ -244,8 +248,9 @@ class MethodHandleNatives {
T_LONG
=
11
,
T_OBJECT
=
12
,
//T_ARRAY = 13
T_VOID
=
14
;
T_VOID
=
14
,
//T_ADDRESS = 15
T_ILLEGAL
=
99
;
/**
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
...
...
@@ -273,16 +278,29 @@ class MethodHandleNatives {
try
{
Field
con
=
Constants
.
class
.
getDeclaredField
(
name
);
int
jval
=
con
.
getInt
(
null
);
if
(
jval
!=
vmval
)
throw
new
InternalError
(
name
+
": JVM has "
+
vmval
+
" while Java has "
+
jval
);
if
(
jval
==
vmval
)
continue
;
String
err
=
(
name
+
": JVM has "
+
vmval
+
" while Java has "
+
jval
);
if
(
name
.
equals
(
"CONV_OP_LIMIT"
))
{
System
.
err
.
println
(
"warning: "
+
err
);
continue
;
}
throw
new
InternalError
(
err
);
}
catch
(
Exception
ex
)
{
if
(
ex
instanceof
NoSuchFieldException
)
{
String
err
=
(
name
+
": JVM has "
+
vmval
+
" which Java does not define"
);
// ignore exotic ops the JVM cares about; we just wont issue them
if
(
name
.
startsWith
(
"OP_"
)
||
name
.
startsWith
(
"GC_"
))
{
System
.
err
.
println
(
"warning: "
+
err
);
continue
;
}
}
throw
new
InternalError
(
name
+
": access failed, got "
+
ex
);
}
}
return
true
;
}
static
{
verifyConstants
(
);
assert
(
verifyConstants
()
);
}
// Up-calls from the JVM.
...
...
@@ -313,7 +331,7 @@ class MethodHandleNatives {
}
/**
* The JVM wants to use a MethodType with in
vokeGeneric
. Give the runtime fair warning.
* The JVM wants to use a MethodType with in
exact invoke
. Give the runtime fair warning.
*/
static
void
notifyGenericMethodType
(
MethodType
type
)
{
type
.
form
().
notifyGenericMethodType
();
...
...
@@ -323,15 +341,39 @@ class MethodHandleNatives {
* The JVM wants to raise an exception. Here's the path.
*/
static
void
raiseException
(
int
code
,
Object
actual
,
Object
required
)
{
String
message
;
String
message
=
null
;
switch
(
code
)
{
case
190
:
// arraylength
try
{
String
reqLength
=
""
;
if
(
required
instanceof
AdapterMethodHandle
)
{
int
conv
=
((
AdapterMethodHandle
)
required
).
getConversion
();
int
spChange
=
AdapterMethodHandle
.
extractStackMove
(
conv
);
reqLength
=
" of length "
+(
spChange
+
1
);
}
int
actualLength
=
actual
==
null
?
0
:
java
.
lang
.
reflect
.
Array
.
getLength
(
actual
);
message
=
"required array"
+
reqLength
+
", but encountered wrong length "
+
actualLength
;
break
;
}
catch
(
IllegalArgumentException
ex
)
{
}
required
=
Object
[].
class
;
// should have been an array
code
=
192
;
// checkcast
break
;
}
// disregard the identity of the actual object, if it is not a class:
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
actual
=
actual
.
getClass
();
if
(
actual
!=
null
)
message
=
"required "
+
required
+
" but encountered "
+
actual
;
else
message
=
"required "
+
required
;
if
(
message
==
null
)
{
if
(!(
actual
instanceof
Class
)
&&
!(
actual
instanceof
MethodType
))
actual
=
actual
.
getClass
();
if
(
actual
!=
null
)
message
=
"required "
+
required
+
" but encountered "
+
actual
;
else
message
=
"required "
+
required
;
}
switch
(
code
)
{
case
190
:
// arraylength
throw
new
ArrayIndexOutOfBoundsException
(
message
);
case
50
:
//_aaload
throw
new
ClassCastException
(
message
);
case
192
:
// checkcast
throw
new
ClassCastException
(
message
);
default
:
...
...
@@ -365,4 +407,13 @@ class MethodHandleNatives {
throw
err
;
}
}
/**
* This assertion marks code which was written before ricochet frames were implemented.
* Such code will go away when the ports catch up.
*/
static
boolean
workaroundWithoutRicochetFrames
()
{
assert
(!
HAVE_RICOCHET_FRAMES
)
:
"this code should not be executed if `-XX:+UseRicochetFrames is enabled"
;
return
true
;
}
}
src/share/classes/java/lang/invoke/MethodHandleStatics.java
浏览文件 @
4b939f2a
...
...
@@ -63,8 +63,17 @@ package java.lang.invoke;
}
static
void
checkSpreadArgument
(
Object
av
,
int
n
)
{
if
(
av
==
null
?
n
!=
0
:
((
Object
[])
av
).
length
!=
n
)
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
if
(
av
==
null
)
{
if
(
n
==
0
)
return
;
}
else
if
(
av
instanceof
Object
[])
{
int
len
=
((
Object
[])
av
).
length
;
if
(
len
==
n
)
return
;
}
else
{
int
len
=
java
.
lang
.
reflect
.
Array
.
getLength
(
av
);
if
(
len
==
n
)
return
;
}
// fall through to error:
throw
newIllegalArgumentException
(
"Array is not of length "
+
n
);
}
// handy shared exception makers (they simplify the common case code)
...
...
@@ -80,6 +89,9 @@ package java.lang.invoke;
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
obj
)
{
return
new
IllegalArgumentException
(
message
(
message
,
obj
));
}
/*non-public*/
static
RuntimeException
newIllegalArgumentException
(
String
message
,
Object
obj
,
Object
obj2
)
{
return
new
IllegalArgumentException
(
message
(
message
,
obj
,
obj2
));
}
/*non-public*/
static
Error
uncaughtException
(
Exception
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
...
...
@@ -89,4 +101,8 @@ package java.lang.invoke;
if
(
obj
!=
null
)
message
=
message
+
": "
+
obj
;
return
message
;
}
private
static
String
message
(
String
message
,
Object
obj
,
Object
obj2
)
{
if
(
obj
!=
null
||
obj2
!=
null
)
message
=
message
+
": "
+
obj
+
", "
+
obj2
;
return
message
;
}
}
src/share/classes/java/lang/invoke/MethodHandles.java
浏览文件 @
4b939f2a
...
...
@@ -190,7 +190,7 @@ public class MethodHandles {
* is not symbolically accessible from the lookup class's loader,
* the lookup can still succeed.
* For example, lookups for {@code MethodHandle.invokeExact} and
* {@code MethodHandle.invoke
Generic
} will always succeed, regardless of requested type.
* {@code MethodHandle.invoke} will always succeed, regardless of requested type.
* <li>If there is a security manager installed, it can forbid the lookup
* on various grounds (<a href="#secmgr">see below</a>).
* By contrast, the {@code ldc} instruction is not subject to
...
...
@@ -590,10 +590,10 @@ public class MethodHandles {
* Because of the general equivalence between {@code invokevirtual}
* instructions and method handles produced by {@code findVirtual},
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invoke
Generic
}, the resulting
* {@code invokeExact} or {@code invoke}, the resulting
* method handle is equivalent to one produced by
* {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
* {@link java.lang.invoke.MethodHandles#
genericInvoker MethodHandles.genericI
nvoker}
* {@link java.lang.invoke.MethodHandles#
invoker MethodHandles.i
nvoker}
* with the same {@code type} argument.
*
* @param refc the class or interface from which the method is accessed
...
...
@@ -1080,7 +1080,7 @@ return mh1;
MethodType
rawType
=
mh
.
type
();
if
(
rawType
.
parameterType
(
0
)
==
caller
)
return
mh
;
MethodType
narrowType
=
rawType
.
changeParameterType
(
0
,
caller
);
MethodHandle
narrowMH
=
MethodHandleImpl
.
convertArguments
(
mh
,
narrowType
,
rawType
,
null
);
MethodHandle
narrowMH
=
MethodHandleImpl
.
convertArguments
(
mh
,
narrowType
,
rawType
,
0
);
return
fixVarargs
(
narrowMH
,
mh
);
}
...
...
@@ -1148,7 +1148,7 @@ return mh1;
* <li>an {@code Object[]} array containing more arguments
* </ul>
* <p>
* The invoker will behave like a call to {@link MethodHandle#invoke
Generic invokeGeneric
} with
* The invoker will behave like a call to {@link MethodHandle#invoke
invoke
} with
* the indicated {@code type}.
* That is, if the target is exactly of the given {@code type}, it will behave
* like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
...
...
@@ -1166,7 +1166,7 @@ return mh1;
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
MethodHandle invoker = MethodHandles.
genericI
nvoker(type);
MethodHandle invoker = MethodHandles.
i
nvoker(type);
int spreadArgCount = type.parameterCount - objectArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
...
...
@@ -1186,7 +1186,7 @@ return invoker;
/**
* Produces a special <em>invoker method handle</em> which can be used to
* invoke any method handle of the given type, as if by {@
code
invokeExact}.
* invoke any method handle of the given type, as if by {@
link MethodHandle#invokeExact
invokeExact}.
* The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
...
...
@@ -1203,7 +1203,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* For example, to emulate an {@code invokeExact} call to a variable method
* handle {@code M}, extract its type {@code T},
* look up the invoker method {@code X} for {@code T},
* and call the invoker method, as {@code X.invoke
Generic
(T, A...)}.
* and call the invoker method, as {@code X.invoke(T, A...)}.
* (It would not work to call {@code X.invokeExact}, since the type {@code T}
* is unknown.)
* If spreading, collecting, or other argument transformations are required,
...
...
@@ -1212,7 +1212,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* <p>
* <em>(Note: The invoker method is not available via the Core Reflection API.
* An attempt to call {@linkplain java.lang.reflect.Method#invoke Method.invoke}
* on the declared {@code invokeExact} or {@code invoke
Generic
} method will raise an
* on the declared {@code invokeExact} or {@code invoke} method will raise an
* {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
* <p>
* This method throws no reflective or security exceptions.
...
...
@@ -1226,20 +1226,20 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
/**
* Produces a special <em>invoker method handle</em> which can be used to
* invoke any method handle
of the given type, as if by {@code invokeGeneric
}.
* invoke any method handle
compatible with the given type, as if by {@link MethodHandle#invoke invoke
}.
* The resulting invoker will have a type which is
* exactly equal to the desired type, except that it will accept
* an additional leading argument of type {@code MethodHandle}.
* <p>
* Before invoking its target, the invoker will apply reference casts as
* necessary and
unbox and widen primitive arguments, as if by {@link #convertArguments convertArguments
}.
*
The return value of the invoker will be an {@code Object} reference,
*
boxing a primitive value if the original type returns a primitive
,
*
and always null if the original type returns void
.
* necessary and
box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType
}.
*
Similarly, the return value will be converted as necessary.
*
If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle}
,
*
the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}
.
* <p>
* This method is equivalent to the following code (though it may be more efficient):
* <p><blockquote><pre>
publicLookup().findVirtual(MethodHandle.class, "invoke
Generic
", type)
publicLookup().findVirtual(MethodHandle.class, "invoke", type)
* </pre></blockquote>
* <p>
* This method throws no reflective or security exceptions.
...
...
@@ -1247,8 +1247,17 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
* @return a method handle suitable for invoking any method handle convertible to the given type
*/
static
public
MethodHandle
invoker
(
MethodType
type
)
{
return
type
.
invokers
().
generalInvoker
();
}
/**
* <em>Temporary alias</em> for {@link #invoker}, for backward compatibility with some versions of JSR 292.
* @deprecated Will be removed for JSR 292 Proposed Final Draft.
*/
public
static
MethodHandle
genericInvoker
(
MethodType
type
)
{
return
type
.
invokers
().
genericInvoker
(
);
return
invoker
(
type
);
}
/**
...
...
@@ -1368,18 +1377,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
public
static
MethodHandle
convertArguments
(
MethodHandle
target
,
MethodType
newType
)
{
MethodType
oldType
=
target
.
type
();
if
(
oldType
.
equals
(
newType
))
return
target
;
MethodHandle
res
=
null
;
try
{
res
=
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
oldType
,
null
);
}
catch
(
IllegalArgumentException
ex
)
{
}
if
(
res
==
null
)
throw
new
WrongMethodTypeException
(
"cannot convert to "
+
newType
+
": "
+
target
);
return
res
;
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
1
);
}
/**
...
...
@@ -1422,7 +1420,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
public
static
MethodHandle
explicitCastArguments
(
MethodHandle
target
,
MethodType
newType
)
{
return
convertArguments
(
target
,
newType
);
// FIXME!
return
MethodHandleImpl
.
convertArguments
(
target
,
newType
,
2
);
}
/*
...
...
@@ -1517,23 +1515,32 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle
permuteArguments
(
MethodHandle
target
,
MethodType
newType
,
int
...
reorder
)
{
MethodType
oldType
=
target
.
type
();
checkReorder
(
reorder
,
newType
,
oldType
);
return
MethodHandleImpl
.
convert
Arguments
(
target
,
return
MethodHandleImpl
.
permute
Arguments
(
target
,
newType
,
oldType
,
reorder
);
}
private
static
void
checkReorder
(
int
[]
reorder
,
MethodType
newType
,
MethodType
oldType
)
{
if
(
newType
.
returnType
()
!=
oldType
.
returnType
())
throw
newIllegalArgumentException
(
"return types do not match"
,
oldType
,
newType
);
if
(
reorder
.
length
==
oldType
.
parameterCount
())
{
int
limit
=
newType
.
parameterCount
();
boolean
bad
=
false
;
for
(
int
i
:
reorder
)
{
for
(
int
j
=
0
;
j
<
reorder
.
length
;
j
++)
{
int
i
=
reorder
[
j
];
if
(
i
<
0
||
i
>=
limit
)
{
bad
=
true
;
break
;
}
Class
<?>
src
=
newType
.
parameterType
(
i
);
Class
<?>
dst
=
oldType
.
parameterType
(
j
);
if
(
src
!=
dst
)
throw
newIllegalArgumentException
(
"parameter types do not match after reorder"
,
oldType
,
newType
);
}
if
(!
bad
)
return
;
}
throw
newIllegalArgumentException
(
"bad reorder array
"
);
throw
newIllegalArgumentException
(
"bad reorder array
: "
+
Arrays
.
toString
(
reorder
)
);
}
/**
...
...
@@ -1622,7 +1629,7 @@ assert((int)twice.invokeExact(21) == 42);
if
(
type
==
void
.
class
)
throw
newIllegalArgumentException
(
"void type"
);
Wrapper
w
=
Wrapper
.
forPrimitiveType
(
type
);
return
i
dentity
(
type
).
bindTo
(
w
.
convert
(
value
,
type
));
return
i
nsertArguments
(
identity
(
type
),
0
,
w
.
convert
(
value
,
type
));
}
else
{
return
identity
(
type
).
bindTo
(
type
.
cast
(
value
));
}
...
...
@@ -1857,7 +1864,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
MethodHandle
filterArguments
(
MethodHandle
target
,
int
pos
,
MethodHandle
...
filters
)
{
MethodType
targetType
=
target
.
type
();
MethodHandle
adapter
=
target
;
MethodType
adapterType
=
targetType
;
MethodType
adapterType
=
null
;
assert
((
adapterType
=
targetType
)
!=
null
);
int
maxPos
=
targetType
.
parameterCount
();
if
(
pos
+
filters
.
length
>
maxPos
)
throw
newIllegalArgumentException
(
"too many filters"
);
...
...
@@ -1865,19 +1873,23 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
for
(
MethodHandle
filter
:
filters
)
{
curPos
+=
1
;
if
(
filter
==
null
)
continue
;
// ignore null elements of filters
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
curPos
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filterType
.
parameterType
(
0
));
adapter
=
MethodHandleImpl
.
filterArgument
(
adapter
,
curPos
,
filter
);
adapter
=
filterArgument
(
adapter
,
curPos
,
filter
);
assert
((
adapterType
=
adapterType
.
changeParameterType
(
curPos
,
filter
.
type
().
parameterType
(
0
)))
!=
null
);
}
MethodType
midType
=
adapter
.
type
();
if
(
midType
!=
adapterType
)
adapter
=
MethodHandleImpl
.
convertArguments
(
adapter
,
adapterType
,
midType
,
null
);
assert
(
adapterType
.
equals
(
adapter
.
type
()));
return
adapter
;
}
/*non-public*/
static
MethodHandle
filterArgument
(
MethodHandle
target
,
int
pos
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
returnType
()
!=
targetType
.
parameterType
(
pos
))
throw
newIllegalArgumentException
(
"target and filter types do not match"
,
targetType
,
filterType
);
return
MethodHandleImpl
.
filterArgument
(
target
,
pos
,
filter
);
}
/**
* Adapts a target method handle {@code target} by post-processing
* its return value with a unary filter function.
...
...
@@ -1913,14 +1925,26 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
filterReturnValue
(
MethodHandle
target
,
MethodHandle
filter
)
{
MethodType
targetType
=
target
.
type
();
MethodType
filterType
=
filter
.
type
();
if
(
filterType
.
parameterCount
()
!=
1
||
filterType
.
parameterType
(
0
)
!=
targetType
.
returnType
())
throw
newIllegalArgumentException
(
"target and filter types do not match"
);
Class
<?>
rtype
=
targetType
.
returnType
();
int
filterValues
=
filterType
.
parameterCount
();
if
(
filterValues
==
0
?
(
rtype
!=
void
.
class
)
:
(
rtype
!=
filterType
.
parameterType
(
0
)))
throw
newIllegalArgumentException
(
"target and filter types do not match"
,
target
,
filter
);
// result = fold( lambda(retval, arg...) { filter(retval) },
// lambda( arg...) { target(arg...) } )
MethodType
newType
=
targetType
.
changeReturnType
(
filterType
.
returnType
());
MethodHandle
result
=
null
;
if
(
AdapterMethodHandle
.
canCollectArguments
(
filterType
,
targetType
,
0
,
false
))
{
result
=
AdapterMethodHandle
.
makeCollectArguments
(
filter
,
target
,
0
,
false
);
if
(
result
!=
null
)
return
result
;
}
// FIXME: Too many nodes here.
MethodHandle
returner
=
dropArguments
(
filter
,
1
,
targetType
.
parameterList
());
return
foldArguments
(
returner
,
target
);
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
MethodHandle
returner
=
dropArguments
(
filter
,
filterValues
,
targetType
.
parameterList
());
result
=
foldArguments
(
returner
,
target
);
assert
(
result
.
type
().
equals
(
newType
));
return
result
;
}
/**
...
...
@@ -1972,16 +1996,23 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodHandle
foldArguments
(
MethodHandle
target
,
MethodHandle
combiner
)
{
MethodType
targetType
=
target
.
type
();
MethodType
combinerType
=
combiner
.
type
();
int
foldPos
=
0
;
// always at the head, at present
int
foldArgs
=
combinerType
.
parameterCount
();
boolean
ok
=
(
targetType
.
parameterCount
()
>=
1
+
foldArgs
);
if
(
ok
&&
!
combinerType
.
parameterList
().
equals
(
targetType
.
parameterList
().
subList
(
1
,
foldArgs
+
1
)))
int
foldVals
=
combinerType
.
returnType
()
==
void
.
class
?
0
:
1
;
int
afterInsertPos
=
foldPos
+
foldVals
;
boolean
ok
=
(
targetType
.
parameterCount
()
>=
afterInsertPos
+
foldArgs
);
if
(
ok
&&
!(
combinerType
.
parameterList
()
.
equals
(
targetType
.
parameterList
().
subList
(
afterInsertPos
,
afterInsertPos
+
foldArgs
))))
ok
=
false
;
if
(
ok
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
if
(
ok
&&
foldVals
!=
0
&&
!
combinerType
.
returnType
().
equals
(
targetType
.
parameterType
(
0
)))
ok
=
false
;
if
(!
ok
)
throw
misMatchedTypes
(
"target and combiner types"
,
targetType
,
combinerType
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
0
,
1
);
return
MethodHandleImpl
.
foldArguments
(
target
,
newType
,
combiner
);
MethodType
newType
=
targetType
.
dropParameterTypes
(
foldPos
,
afterInsertPos
);
MethodHandle
res
=
MethodHandleImpl
.
foldArguments
(
target
,
newType
,
foldPos
,
combiner
);
if
(
res
==
null
)
throw
newIllegalArgumentException
(
"cannot fold from "
+
newType
+
" to "
+
targetType
);
return
res
;
}
/**
...
...
@@ -2142,7 +2173,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* {@code target.invoke
Generic
}.
* {@code target.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
...
...
src/share/classes/java/lang/invoke/MethodType.java
浏览文件 @
4b939f2a
...
...
@@ -25,6 +25,7 @@
package
java.lang.invoke
;
import
sun.invoke.util.Wrapper
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.HashMap
;
...
...
@@ -39,7 +40,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
* matched between a method handle and all its callers,
* and the JVM's operations enforce this matching at, specifically
* during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
* and {@link MethodHandle#invoke
Generic MethodHandle.invokeGeneric
}, and during execution
* and {@link MethodHandle#invoke
MethodHandle.invoke
}, and during execution
* of {@code invokedynamic} instructions.
* <p>
* The structure is a return type accompanied by any number of parameter types.
...
...
@@ -262,18 +263,18 @@ class MethodType implements java.io.Serializable {
* Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be {@code Object},
* except the final
varargs
parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the
varargs
parameter if any)
* @param
varargs whether there will be a varargs
parameter, of type {@code Object[]}
* @return a
totally generic method type, given only its count of parameters and vararg
s
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* except the final
array
parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the
final array
parameter if any)
* @param
finalArray whether there will be a trailing array
parameter, of type {@code Object[]}
* @return a
generally applicable method type, for all calls of the given fixed argument count and a collected array of further argument
s
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
(or 254, if {@code finalArray})
* @see #genericMethodType(int)
*/
public
static
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
varargs
)
{
MethodType
genericMethodType
(
int
objectArgCount
,
boolean
finalArray
)
{
MethodType
mt
;
checkSlotCount
(
objectArgCount
);
int
ivarargs
=
(!
varargs
?
0
:
1
);
int
ivarargs
=
(!
finalArray
?
0
:
1
);
int
ootIndex
=
objectArgCount
*
2
+
ivarargs
;
if
(
ootIndex
<
objectOnlyTypes
.
length
)
{
mt
=
objectOnlyTypes
[
ootIndex
];
...
...
@@ -294,7 +295,7 @@ class MethodType implements java.io.Serializable {
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All parameters and the return type will be Object.
* @param objectArgCount number of parameters
* @return a
totally generic method type, given only its count of parameters
* @return a
generally applicable method type, for all calls of the given argument count
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
* @see #genericMethodType(int, boolean)
*/
...
...
@@ -626,6 +627,30 @@ class MethodType implements java.io.Serializable {
return
sb
.
toString
();
}
/*non-public*/
boolean
isConvertibleTo
(
MethodType
newType
)
{
if
(!
canConvert
(
returnType
(),
newType
.
returnType
()))
return
false
;
int
argc
=
parameterCount
();
if
(
argc
!=
newType
.
parameterCount
())
return
false
;
for
(
int
i
=
0
;
i
<
argc
;
i
++)
{
if
(!
canConvert
(
newType
.
parameterType
(
i
),
parameterType
(
i
)))
return
false
;
}
return
true
;
}
private
static
boolean
canConvert
(
Class
<?>
src
,
Class
<?>
dst
)
{
if
(
src
==
dst
||
dst
==
void
.
class
)
return
true
;
if
(
src
.
isPrimitive
()
&&
dst
.
isPrimitive
())
{
if
(!
Wrapper
.
forPrimitiveType
(
dst
)
.
isConvertibleFrom
(
Wrapper
.
forPrimitiveType
(
src
)))
return
false
;
}
return
true
;
}
/// Queries which have to do with the bytecode architecture
/** Reports the number of JVM stack slots required to invoke a method
...
...
src/share/classes/java/lang/invoke/MethodTypeForm.java
浏览文件 @
4b939f2a
...
...
@@ -46,6 +46,7 @@ class MethodTypeForm {
final
long
argCounts
;
// packed slot & value counts
final
long
primCounts
;
// packed prim & double counts
final
int
vmslots
;
// total number of parameter slots
private
Object
vmlayout
;
// vm-specific information for calls
final
MethodType
erasedType
;
// the canonical erasure
/*lazy*/
MethodType
primsAsBoxes
;
// replace prims by wrappers
...
...
@@ -59,7 +60,7 @@ class MethodTypeForm {
/*lazy*/
FromGeneric
fromGeneric
;
// convert cs. w/o prims to with
/*lazy*/
SpreadGeneric
[]
spreadGeneric
;
// expand one argument to many
/*lazy*/
FilterGeneric
filterGeneric
;
// convert argument(s) on the fly
/*lazy*/
MethodHandle
genericInvoker
;
// hook for in
vokeGeneric
/*lazy*/
MethodHandle
genericInvoker
;
// hook for in
exact invoke
public
MethodType
erasedType
()
{
return
erasedType
;
...
...
@@ -460,9 +461,9 @@ class MethodTypeForm {
if
(
genericInvoker
!=
null
)
return
;
try
{
// Trigger adapter creation.
genericInvoker
=
InvokeGeneric
.
gener
ic
InvokerOf
(
erasedType
);
genericInvoker
=
InvokeGeneric
.
gener
al
InvokerOf
(
erasedType
);
}
catch
(
Exception
ex
)
{
Error
err
=
new
InternalError
(
"Exception while resolving in
vokeGeneric
"
);
Error
err
=
new
InternalError
(
"Exception while resolving in
exact invoke
"
);
err
.
initCause
(
ex
);
throw
err
;
}
...
...
src/share/classes/java/lang/invoke/SpreadGeneric.java
浏览文件 @
4b939f2a
...
...
@@ -66,6 +66,10 @@ class SpreadGeneric {
this
.
entryPoint
=
ep
[
0
];
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/** From targetType remove the last spreadCount arguments, and instead
* append a simple Object argument.
*/
...
...
src/share/classes/java/lang/invoke/ToGeneric.java
浏览文件 @
4b939f2a
...
...
@@ -96,7 +96,7 @@ class ToGeneric {
ToGeneric
va2
=
ToGeneric
.
of
(
primsAtEnd
);
this
.
adapter
=
va2
.
adapter
;
if
(
true
)
throw
new
UnsupportedOperationException
(
"NYI: primitive parameters must follow references; entryType = "
+
entryType
);
this
.
entryPoint
=
MethodHandleImpl
.
convert
Arguments
(
this
.
entryPoint
=
MethodHandleImpl
.
permute
Arguments
(
va2
.
entryPoint
,
primsAtEnd
,
entryType
,
primsAtEndOrder
);
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
...
...
@@ -128,7 +128,7 @@ class ToGeneric {
assert
(
eptWithInts
.
parameterType
(
i
)
==
int
.
class
);
MethodType
nextType
=
midType
.
changeParameterType
(
i
,
int
.
class
);
rawEntryPoint
=
MethodHandleImpl
.
convertArguments
(
rawEntryPoint
,
nextType
,
midType
,
null
);
rawEntryPoint
,
nextType
,
midType
,
0
);
midType
=
nextType
;
}
}
...
...
@@ -152,6 +152,10 @@ class ToGeneric {
this
.
invoker
=
makeRawArgumentFilter
(
invoker0
,
rawEntryTypeInit
,
entryType
);
}
static
{
assert
(
MethodHandleNatives
.
workaroundWithoutRicochetFrames
());
// this class is deprecated
}
/** A generic argument list will be created by a call of type 'raw'.
* The values need to be reboxed for to match 'cooked'.
* Do this on the fly.
...
...
@@ -171,7 +175,7 @@ class ToGeneric {
invoker
.
type
().
generic
(),
invoker
,
0
,
MethodHandle
.
class
);
if
(
filteredInvoker
==
null
)
throw
new
UnsupportedOperationException
(
"NYI"
);
}
MethodHandle
reboxer
=
ValueConversions
.
rebox
(
dst
,
false
);
MethodHandle
reboxer
=
ValueConversions
.
rebox
(
dst
);
filteredInvoker
=
FilterGeneric
.
makeArgumentFilter
(
1
+
i
,
reboxer
,
filteredInvoker
);
if
(
filteredInvoker
==
null
)
throw
new
InternalError
();
}
...
...
@@ -199,13 +203,13 @@ class ToGeneric {
assert
(!
rret
.
isPrimitive
());
if
(
rret
==
Object
.
class
&&
!
mustCast
)
return
null
;
return
ValueConversions
.
cast
(
tret
,
false
);
return
ValueConversions
.
cast
(
tret
);
}
else
if
(
tret
==
rret
)
{
return
ValueConversions
.
unbox
(
tret
,
false
);
return
ValueConversions
.
unbox
(
tret
);
}
else
{
assert
(
rret
.
isPrimitive
());
assert
(
tret
==
double
.
class
?
rret
==
long
.
class
:
rret
==
int
.
class
);
return
ValueConversions
.
unboxRaw
(
tret
,
false
);
return
ValueConversions
.
unboxRaw
(
tret
);
}
}
...
...
@@ -311,7 +315,7 @@ class ToGeneric {
}
static
Adapter
buildAdapterFromBytecodes
(
MethodType
entryPointType
)
{
throw
new
UnsupportedOperationException
(
"NYI
"
);
throw
new
UnsupportedOperationException
(
"NYI
: "
+
entryPointType
);
}
/**
...
...
src/share/classes/java/lang/invoke/package-info.java
浏览文件 @
4b939f2a
...
...
@@ -185,7 +185,7 @@
* The method handle constant produced for such a method behaves as if
* it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code
invokeGeneric
}.
* when invoked via {@code
MethodHandle.invoke
}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
* as if the {@code varargs} bit were not set.
* <p>
...
...
@@ -243,7 +243,7 @@
* <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* The method handle is then applied to the other values as if by
* {@link java.lang.invoke.MethodHandle#invoke
Generic invokeGeneric
}.
* {@link java.lang.invoke.MethodHandle#invoke
MethodHandle.invoke
}.
* The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
* The type of the call site's target must be exactly equal to the type
* derived from the dynamic call site's type descriptor and passed to
...
...
@@ -251,7 +251,7 @@
* The call site then becomes permanently linked to the dynamic call site.
* <p>
* As long as each bootstrap method can be correctly invoked
* by <code>
invokeGeneric
</code>, its detailed type is arbitrary.
* by <code>
MethodHandle.invoke
</code>, its detailed type is arbitrary.
* For example, the first argument could be {@code Object}
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
...
...
@@ -272,7 +272,7 @@
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
* <li>the bootstrap method has the wrong arity,
* causing {@code
invokeGeneric
} to throw {@code WrongMethodTypeException} </li>
* causing {@code
MethodHandle.invoke
} to throw {@code WrongMethodTypeException} </li>
* <li>the bootstrap method has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
...
...
@@ -381,10 +381,10 @@
* those values will be passed as additional arguments to the method handle.
* (Note that because there is a limit of 255 arguments to any method,
* at most 252 extra arguments can be supplied.)
* The bootstrap method will be invoked as if by either {@code
invokeGeneric
}
* The bootstrap method will be invoked as if by either {@code
MethodHandle.invoke
}
* or {@code invokeWithArguments}. (There is no way to tell the difference.)
* <p>
* The normal argument conversion rules for {@code
invokeGeneric
} apply to all stacked arguments.
* The normal argument conversion rules for {@code
MethodHandle.invoke
} apply to all stacked arguments.
* For example, if a pushed value is a primitive type, it may be converted to a reference by boxing conversion.
* If the bootstrap method is a variable arity method (its modifier bit {@code 0x0080} is set),
* then some or all of the arguments specified here may be collected into a trailing array parameter.
...
...
@@ -419,8 +419,8 @@
* For example, the fourth argument could be {@code MethodHandle},
* if that is the type of the corresponding constant in
* the {@code CONSTANT_InvokeDynamic} entry.
* In that case, the {@code
invokeGeneric
} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code
invokeGeneric
}
* In that case, the {@code
MethodHandle.invoke
} call will pass the extra method handle
* constant as an {@code Object}, but the type matching machinery of {@code
MethodHandle.invoke
}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail,
* resulting in a {@code BootstrapMethodError}.)
...
...
src/share/classes/sun/invoke/util/ValueConversions.java
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
src/share/classes/sun/invoke/util/VerifyType.java
浏览文件 @
4b939f2a
...
...
@@ -54,9 +54,15 @@ public class VerifyType {
if
(
dst
==
void
.
class
)
return
true
;
// drop any return value
if
(
isNullType
(
src
))
return
!
dst
.
isPrimitive
();
if
(!
src
.
isPrimitive
())
return
dst
.
isAssignableFrom
(
src
);
if
(!
dst
.
isPrimitive
())
return
false
;
// Verifier allows an int to carry byte, short, char, or even boolean:
if
(
dst
==
int
.
class
)
return
Wrapper
.
forPrimitiveType
(
src
).
isSubwordOrInt
();
return
false
;
Wrapper
sw
=
Wrapper
.
forPrimitiveType
(
src
);
if
(
dst
==
int
.
class
)
return
sw
.
isSubwordOrInt
();
Wrapper
dw
=
Wrapper
.
forPrimitiveType
(
dst
);
if
(!
sw
.
isSubwordOrInt
())
return
false
;
if
(!
dw
.
isSubwordOrInt
())
return
false
;
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
return
false
;
return
dw
.
bitWidth
()
>
sw
.
bitWidth
();
}
/**
...
...
@@ -155,6 +161,7 @@ public class VerifyType {
return
-
1
;
// truncation may be required
if
(!
dw
.
isSigned
()
&&
sw
.
isSigned
())
return
-
1
;
// sign elimination may be required
return
1
;
}
if
(
src
==
float
.
class
||
dst
==
float
.
class
)
{
if
(
src
==
double
.
class
||
dst
==
double
.
class
)
...
...
src/share/classes/sun/invoke/util/Wrapper.java
浏览文件 @
4b939f2a
...
...
@@ -26,37 +26,47 @@
package
sun.invoke.util
;
public
enum
Wrapper
{
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
Format
.
unsigned
(
1
)),
BOOLEAN
(
Boolean
.
class
,
boolean
.
class
,
'Z'
,
(
Boolean
)
false
,
new
boolean
[
0
],
Format
.
unsigned
(
1
)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
Format
.
signed
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
Format
.
unsigned
(
16
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
Format
.
floating
(
64
)),
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
Format
.
other
(
1
)),
BYTE
(
Byte
.
class
,
byte
.
class
,
'B'
,
(
Byte
)(
byte
)
0
,
new
byte
[
0
],
Format
.
signed
(
8
)),
SHORT
(
Short
.
class
,
short
.
class
,
'S'
,
(
Short
)(
short
)
0
,
new
short
[
0
],
Format
.
signed
(
16
)),
CHAR
(
Character
.
class
,
char
.
class
,
'C'
,
(
Character
)(
char
)
0
,
new
char
[
0
],
Format
.
unsigned
(
16
)),
INT
(
Integer
.
class
,
int
.
class
,
'I'
,
(
Integer
)(
int
)
0
,
new
int
[
0
],
Format
.
signed
(
32
)),
LONG
(
Long
.
class
,
long
.
class
,
'J'
,
(
Long
)(
long
)
0
,
new
long
[
0
],
Format
.
signed
(
64
)),
FLOAT
(
Float
.
class
,
float
.
class
,
'F'
,
(
Float
)(
float
)
0
,
new
float
[
0
],
Format
.
floating
(
32
)),
DOUBLE
(
Double
.
class
,
double
.
class
,
'D'
,
(
Double
)(
double
)
0
,
new
double
[
0
],
Format
.
floating
(
64
)),
//NULL(Null.class, null.class, 'N', null,
null,
Format.other(1)),
OBJECT
(
Object
.
class
,
Object
.
class
,
'L'
,
null
,
new
Object
[
0
],
Format
.
other
(
1
)),
// VOID must be the last type, since it is "assignable" from any other type:
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
Format
.
other
(
0
)),
VOID
(
Void
.
class
,
void
.
class
,
'V'
,
null
,
null
,
Format
.
other
(
0
)),
;
private
final
Class
<?>
wrapperType
;
private
final
Class
<?>
primitiveType
;
private
final
char
basicTypeChar
;
private
final
Object
zero
;
private
final
Object
emptyArray
;
private
final
int
format
;
private
final
String
simpleName
;
private
Wrapper
(
Class
<?>
wtype
,
Class
<?>
ptype
,
char
tchar
,
Object
zero
,
int
format
)
{
private
Wrapper
(
Class
<?>
wtype
,
Class
<?>
ptype
,
char
tchar
,
Object
zero
,
Object
emptyArray
,
int
format
)
{
this
.
wrapperType
=
wtype
;
this
.
primitiveType
=
ptype
;
this
.
basicTypeChar
=
tchar
;
this
.
zero
=
zero
;
this
.
emptyArray
=
emptyArray
;
this
.
format
=
format
;
this
.
simpleName
=
wtype
.
getSimpleName
();
}
/** For debugging, give the details of this wrapper. */
public
String
detailString
()
{
return
simpleName
+
java
.
util
.
Arrays
.
asList
(
wrapperType
,
primitiveType
,
basicTypeChar
,
zero
,
"0x"
+
Integer
.
toHexString
(
format
));
}
private
static
abstract
class
Format
{
static
final
int
SLOT_SHIFT
=
0
,
SIZE_SHIFT
=
2
,
KIND_SHIFT
=
12
;
static
final
int
...
...
@@ -114,16 +124,18 @@ public enum Wrapper {
public
boolean
isUnsigned
()
{
return
format
>=
Format
.
BOOLEAN
&&
format
<
Format
.
FLOAT
;
}
/** Is the wrapped type either float or double? */
public
boolean
isFloating
()
{
return
format
>=
Format
.
FLOAT
;
}
/** Is the wrapped type either void or a reference? */
public
boolean
isOther
()
{
return
(
format
&
~
Format
.
SLOT_MASK
)
==
0
;
}
/** Does the J
VM verifier
allow a variable of this wrapper's
/** Does the J
LS 5.1.2
allow a variable of this wrapper's
* primitive type to be assigned from a value of the given wrapper's primitive type?
* Cases:
* <ul>
* <li>unboxing followed by widening primitive conversion
* <li>any type converted to {@code void}
* <li>any type converted to {@code void}
(i.e., dropping a method call's value)
* <li>boxing conversion followed by widening reference conversion to {@code Object}
* <li>conversion of {@code boolean} to any type
* </ul>
* These are the cases allowed by MethodHandle.asType and convertArguments.
*/
public
boolean
isConvertibleFrom
(
Wrapper
source
)
{
if
(
this
==
source
)
return
true
;
...
...
@@ -131,13 +143,75 @@ public enum Wrapper {
// At best, this is a narrowing conversion.
return
false
;
}
if
((
this
.
format
^
source
.
format
)
==
(
Format
.
SHORT
^
Format
.
CHAR
))
{
assert
(
this
==
SHORT
&&
source
==
CHAR
)
||
(
this
==
CHAR
&&
source
==
SHORT
);
// All conversions are allowed in the enum order between floats and signed ints.
// First detect non-signed non-float types (boolean, char, Object, void).
boolean
floatOrSigned
=
(((
this
.
format
&
source
.
format
)
&
Format
.
SIGNED
)
!=
0
);
if
(!
floatOrSigned
)
{
if
(
this
.
isOther
())
return
true
;
// can convert char to int or wider, but nothing else
if
(
source
.
format
==
Format
.
CHAR
)
return
true
;
// no other conversions are classified as widening
return
false
;
}
// All signed and float conversions in the enum order are widening.
assert
(
this
.
isFloating
()
||
this
.
isSigned
());
assert
(
source
.
isFloating
()
||
source
.
isSigned
());
return
true
;
}
static
{
assert
(
checkConvertibleFrom
());
}
private
static
boolean
checkConvertibleFrom
()
{
// Check the matrix for correct classification of widening conversions.
for
(
Wrapper
w
:
values
())
{
assert
(
w
.
isConvertibleFrom
(
w
));
assert
(
VOID
.
isConvertibleFrom
(
w
));
if
(
w
!=
VOID
)
{
assert
(
OBJECT
.
isConvertibleFrom
(
w
));
assert
(!
w
.
isConvertibleFrom
(
VOID
));
}
// check relations with unsigned integral types:
if
(
w
!=
CHAR
)
{
assert
(!
CHAR
.
isConvertibleFrom
(
w
));
if
(!
w
.
isConvertibleFrom
(
INT
))
assert
(!
w
.
isConvertibleFrom
(
CHAR
));
}
if
(
w
!=
BOOLEAN
)
{
assert
(!
BOOLEAN
.
isConvertibleFrom
(
w
));
if
(
w
!=
VOID
&&
w
!=
OBJECT
)
assert
(!
w
.
isConvertibleFrom
(
BOOLEAN
));
}
// check relations with signed integral types:
if
(
w
.
isSigned
())
{
for
(
Wrapper
x
:
values
())
{
if
(
w
==
x
)
continue
;
if
(
x
.
isFloating
())
assert
(!
w
.
isConvertibleFrom
(
x
));
else
if
(
x
.
isSigned
())
{
if
(
w
.
compareTo
(
x
)
<
0
)
assert
(!
w
.
isConvertibleFrom
(
x
));
else
assert
(
w
.
isConvertibleFrom
(
x
));
}
}
}
// check relations with floating types:
if
(
w
.
isFloating
())
{
for
(
Wrapper
x
:
values
())
{
if
(
w
==
x
)
continue
;
if
(
x
.
isSigned
())
assert
(
w
.
isConvertibleFrom
(
x
));
else
if
(
x
.
isFloating
())
{
if
(
w
.
compareTo
(
x
)
<
0
)
assert
(!
w
.
isConvertibleFrom
(
x
));
else
assert
(
w
.
isConvertibleFrom
(
x
));
}
}
}
}
return
true
;
// i.e., assert(true)
}
/** Produce a zero value for the given wrapper type.
* This will be a numeric zero for a number or character,
* false for a boolean, and null for a reference or void.
...
...
@@ -549,7 +623,7 @@ public enum Wrapper {
}
private
static
boolean
boolValue
(
long
bits
)
{
//
bits &= 1; // simple 31-bit zero extension
bits
&=
1
;
// simple 31-bit zero extension
return
(
bits
!=
0
);
}
...
...
@@ -559,4 +633,31 @@ public enum Wrapper {
private
static
RuntimeException
newIllegalArgumentException
(
String
message
)
{
return
new
IllegalArgumentException
(
message
);
}
// primitive array support
public
Object
makeArray
(
int
len
)
{
return
java
.
lang
.
reflect
.
Array
.
newInstance
(
primitiveType
,
len
);
}
public
Class
<?>
arrayType
()
{
return
emptyArray
.
getClass
();
}
public
void
copyArrayUnboxing
(
Object
[]
values
,
int
vpos
,
Object
a
,
int
apos
,
int
length
)
{
if
(
a
.
getClass
()
!=
arrayType
())
arrayType
().
cast
(
a
);
// throw NPE or CCE if bad type
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
Object
value
=
values
[
i
+
vpos
];
value
=
convert
(
value
,
primitiveType
);
java
.
lang
.
reflect
.
Array
.
set
(
a
,
i
+
apos
,
value
);
}
}
public
void
copyArrayBoxing
(
Object
a
,
int
apos
,
Object
[]
values
,
int
vpos
,
int
length
)
{
if
(
a
.
getClass
()
!=
arrayType
())
arrayType
().
cast
(
a
);
// throw NPE or CCE if bad type
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
Object
value
=
java
.
lang
.
reflect
.
Array
.
get
(
a
,
i
+
apos
);
//Already done: value = convert(value, primitiveType);
assert
(
value
.
getClass
()
==
wrapperType
);
values
[
i
+
vpos
]
=
value
;
}
}
}
test/java/lang/invoke/6998541/Test6998541.java
0 → 100644
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
test/java/lang/invoke/InvokeGenericTest.java
浏览文件 @
4b939f2a
...
...
@@ -24,7 +24,7 @@
*/
/* @test
* @summary unit tests for java.lang.invoke.MethodHandle.invoke
Generic
* @summary unit tests for java.lang.invoke.MethodHandle.invoke
* @compile -target 7 InvokeGenericTest.java
* @run junit/othervm test.java.lang.invoke.InvokeGenericTest
*/
...
...
@@ -53,6 +53,10 @@ public class InvokeGenericTest {
if
(
vstr
!=
null
)
verbosity
=
Integer
.
parseInt
(
vstr
);
}
public
static
void
main
(
String
...
av
)
throws
Throwable
{
new
InvokeGenericTest
().
testFirst
();
}
@Test
public
void
testFirst
()
throws
Throwable
{
verbosity
+=
9
;
try
{
...
...
@@ -103,7 +107,7 @@ public class InvokeGenericTest {
void
startTest
(
String
name
)
{
if
(
testName
!=
null
)
printCounts
();
if
(
verbosity
>=
1
)
System
.
out
.
println
(
name
);
System
.
out
.
println
(
"["
+
name
+
"]"
);
posTests
=
negTests
=
0
;
testName
=
name
;
}
...
...
@@ -350,6 +354,30 @@ public class InvokeGenericTest {
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
@Test
public
void
testSimplePrims
()
throws
Throwable
{
startTest
(
"testSimplePrims"
);
countTest
();
int
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
Object
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
(
args
[
0
],
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
toString
(
args
),
res
.
toString
());
}
@Test
public
void
testAlternateName
()
throws
Throwable
{
startTest
(
"testAlternateName"
);
countTest
();
String
[]
args
=
{
"one"
,
"two"
};
MethodHandle
mh
=
callable
(
Object
.
class
,
String
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invokeGeneric
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
...
...
@@ -388,24 +416,24 @@ public class InvokeGenericTest {
try
{
switch
(
args
.
length
)
{
case
0
:
junk
=
target
.
invoke
Generic
();
break
;
junk
=
target
.
invoke
();
break
;
case
1
:
junk
=
target
.
invoke
Generic
(
args
[
0
]);
break
;
junk
=
target
.
invoke
(
args
[
0
]);
break
;
case
2
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
]);
break
;
case
3
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
],
args
[
2
]);
break
;
case
4
:
junk
=
target
.
invoke
Generic
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
junk
=
target
.
invoke
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
]);
break
;
default
:
junk
=
target
.
invokeWithArguments
(
args
);
break
;
}
}
catch
(
WrongMethodTypeException
ex
)
{
return
;
}
catch
(
Exception
ex
)
{
throw
new
RuntimeException
(
"wrong exception calling "
+
target
+
target
.
type
()+
" on "
+
Arrays
.
asList
(
args
)+
" : "
+
ex
);
throw
new
RuntimeException
(
"wrong exception calling "
+
target
+
" on "
+
Arrays
.
asList
(
args
),
ex
);
}
throw
new
RuntimeException
(
"bad success calling "
+
target
+
target
.
type
()+
" on "
+
Arrays
.
asList
(
args
));
throw
new
RuntimeException
(
"bad success calling "
+
target
+
" on "
+
Arrays
.
asList
(
args
));
}
/** Make a list of all combinations of the given types, with the given arities.
...
...
@@ -451,7 +479,7 @@ public class InvokeGenericTest {
startTest
(
"testReferenceConversions"
);
toString_MH
=
LOOKUP
.
findVirtual
(
Object
.
class
,
"toString"
,
MethodType
.
methodType
(
String
.
class
));
String
[]
args
=
{
"one"
,
"two"
};
Object
[]
args
=
{
"one"
,
"two"
};
for
(
MethodType
type
:
allMethodTypes
(
2
,
Object
.
class
,
String
.
class
,
RandomInterface
.
class
))
{
testReferenceConversions
(
type
,
args
);
}
...
...
@@ -463,7 +491,7 @@ public class InvokeGenericTest {
MethodHandle
tsdrop
=
MethodHandles
.
dropArguments
(
toString_MH
,
1
,
type
.
parameterList
());
mh
=
MethodHandles
.
foldArguments
(
tsdrop
,
mh
);
mh
=
mh
.
asType
(
type
);
Object
res
=
mh
.
invoke
Generic
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
Object
res
=
mh
.
invoke
((
String
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
).
toString
(),
res
);
}
...
...
@@ -473,10 +501,10 @@ public class InvokeGenericTest {
public
void
testBoxConversions
()
throws
Throwable
{
startTest
(
"testBoxConversions"
);
countTest
();
Integer
[]
args
=
{
1
,
2
};
Object
[]
args
=
{
1
,
2
};
MethodHandle
mh
=
callable
(
Object
.
class
,
int
.
class
);
Object
res
;
List
resl
;
res
=
resl
=
(
List
)
mh
.
invoke
Generic
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
res
=
resl
=
(
List
)
mh
.
invoke
((
int
)
args
[
0
],
(
Object
)
args
[
1
]);
//System.out.println(res);
assertEquals
(
Arrays
.
asList
(
args
),
res
);
}
...
...
test/java/lang/invoke/JavaDocExamplesTest.java
浏览文件 @
4b939f2a
...
...
@@ -170,8 +170,8 @@ assert(s.equals("savvy"));
mt
=
MethodType
.
methodType
(
java
.
util
.
List
.
class
,
Object
[].
class
);
mh
=
lookup
.
findStatic
(
java
.
util
.
Arrays
.
class
,
"asList"
,
mt
);
assert
(
mh
.
isVarargsCollector
());
x
=
mh
.
invoke
Generic
(
"one"
,
"two"
);
// invoke
Generic
(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
x
=
mh
.
invoke
(
"one"
,
"two"
);
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assert
(
x
.
equals
(
java
.
util
.
Arrays
.
asList
(
"one"
,
"two"
)));
// mt is (Object,Object,Object)Object
mt
=
MethodType
.
genericMethodType
(
3
);
...
...
@@ -199,12 +199,12 @@ mh.invokeExact(System.out, "Hello, world.");
MethodHandle
asList
=
publicLookup
()
.
findStatic
(
Arrays
.
class
,
"asList"
,
methodType
(
List
.
class
,
Object
[].
class
))
.
asVarargsCollector
(
Object
[].
class
);
assertEquals
(
"[]"
,
asList
.
invoke
Generic
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
Generic
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
Generic
(
"two"
,
"too"
).
toString
());
assertEquals
(
"[]"
,
asList
.
invoke
().
toString
());
assertEquals
(
"[1]"
,
asList
.
invoke
(
1
).
toString
());
assertEquals
(
"[two, too]"
,
asList
.
invoke
(
"two"
,
"too"
).
toString
());
Object
[]
argv
=
{
"three"
,
"thee"
,
"tee"
};
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
Generic
(
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
Generic
((
Object
)
argv
);
assertEquals
(
"[three, thee, tee]"
,
asList
.
invoke
(
argv
).
toString
());
List
ls
=
(
List
)
asList
.
invoke
((
Object
)
argv
);
assertEquals
(
1
,
ls
.
size
());
assertEquals
(
"[three, thee, tee]"
,
Arrays
.
toString
((
Object
[])
ls
.
get
(
0
)));
}}
...
...
@@ -218,9 +218,9 @@ MethodHandle vamh = publicLookup()
.
asVarargsCollector
(
Object
[].
class
);
MethodHandle
mh
=
MethodHandles
.
exactInvoker
(
vamh
.
type
()).
bindTo
(
vamh
);
assert
(
vamh
.
type
().
equals
(
mh
.
type
()));
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
Generic
(
1
,
2
,
3
).
toString
());
assertEquals
(
"[1, 2, 3]"
,
vamh
.
invoke
(
1
,
2
,
3
).
toString
());
boolean
failed
=
false
;
try
{
mh
.
invoke
Generic
(
1
,
2
,
3
);
}
try
{
mh
.
invoke
(
1
,
2
,
3
);
}
catch
(
WrongMethodTypeException
ex
)
{
failed
=
true
;
}
assert
(
failed
);
{}
...
...
test/java/lang/invoke/MethodHandlesTest.java
浏览文件 @
4b939f2a
...
...
@@ -105,24 +105,6 @@ public class MethodHandlesTest {
public
MethodHandlesTest
()
{
}
@Before
public
void
checkImplementedPlatform
()
{
boolean
platformOK
=
false
;
Properties
properties
=
System
.
getProperties
();
String
vers
=
properties
.
getProperty
(
"java.vm.version"
);
String
name
=
properties
.
getProperty
(
"java.vm.name"
);
String
arch
=
properties
.
getProperty
(
"os.arch"
);
if
((
arch
.
equals
(
"amd64"
)
||
arch
.
equals
(
"i386"
)
||
arch
.
equals
(
"x86"
)
||
arch
.
equals
(
"sparc"
)
||
arch
.
equals
(
"sparcv9"
))
&&
(
name
.
contains
(
"Client"
)
||
name
.
contains
(
"Server"
))
)
{
platformOK
=
true
;
}
else
{
System
.
err
.
println
(
"Skipping tests for unsupported platform: "
+
Arrays
.
asList
(
vers
,
name
,
arch
));
}
assumeTrue
(
platformOK
);
}
String
testName
;
static
int
allPosTests
,
allNegTests
;
int
posTests
,
negTests
;
...
...
@@ -331,6 +313,9 @@ public class MethodHandlesTest {
static
MethodHandle
varargsArray
(
int
arity
)
{
return
ValueConversions
.
varargsArray
(
arity
);
}
static
MethodHandle
varargsArray
(
Class
<?>
arrayType
,
int
arity
)
{
return
ValueConversions
.
varargsArray
(
arrayType
,
arity
);
}
/** Variation of varargsList, but with the given rtype. */
static
MethodHandle
varargsList
(
int
arity
,
Class
<?>
rtype
)
{
MethodHandle
list
=
varargsList
(
arity
);
...
...
@@ -865,7 +850,7 @@ public class MethodHandlesTest {
Class
<?>
type
=
(
Class
<?>)
t
[
1
];
Object
value
;
Field
field
;
try
{
try
{
field
=
HasFields
.
class
.
getDeclaredField
(
name
);
}
catch
(
Exception
ex
)
{
throw
new
InternalError
(
"no field HasFields."
+
name
);
...
...
@@ -1144,16 +1129,9 @@ public class MethodHandlesTest {
:
MethodHandles
.
arrayElementSetter
(
arrayType
);
assertSame
(
mh
.
type
(),
expType
);
if
(
elemType
!=
int
.
class
&&
elemType
!=
boolean
.
class
)
{
MethodType
gtype
;
if
(
true
)
{
// FIXME: remove this path (and remove <void> below in the mh.invokes)
gtype
=
mh
.
type
().
changeParameterType
(
0
,
Object
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeParameterType
(
2
,
Object
.
class
);
else
gtype
=
gtype
.
changeReturnType
(
Object
.
class
);
}
else
// FIXME: This simpler path hits a bug in convertArguments => ToGeneric
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
int
.
class
);
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
MethodType
gtype
=
mh
.
type
().
generic
().
changeParameterType
(
1
,
Integer
.
class
);
if
(
testSetter
)
gtype
=
gtype
.
changeReturnType
(
void
.
class
);
mh
=
MethodHandles
.
convertArguments
(
mh
,
gtype
);
}
Object
sawValue
,
expValue
;
...
...
@@ -1169,7 +1147,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
mh
.
invokeExact
((
boolean
[])
array
,
i
,
(
boolean
)
random
);
else
mh
.
invokeExact
(
array
,
i
,
random
);
mh
.
invokeExact
(
array
,
(
Integer
)
i
,
random
);
assertEquals
(
model
,
array2list
(
array
));
}
else
{
Array
.
set
(
array
,
i
,
random
);
...
...
@@ -1189,7 +1167,7 @@ public class MethodHandlesTest {
else
if
(
elemType
==
boolean
.
class
)
sawValue
=
(
boolean
)
mh
.
invokeExact
((
boolean
[])
array
,
i
);
else
sawValue
=
mh
.
invokeExact
(
array
,
i
);
sawValue
=
mh
.
invokeExact
(
array
,
(
Integer
)
i
);
assertEquals
(
sawValue
,
expValue
);
assertEquals
(
model
,
array2list
(
array
));
}
...
...
@@ -1341,21 +1319,15 @@ public class MethodHandlesTest {
int
numcases
=
1
;
for
(
int
outargs
=
0
;
outargs
<=
max
;
outargs
++)
{
if
(
outargs
-
inargs
>=
MAX_ARG_INCREASE
)
continue
;
int
[]
reorder
=
new
int
[
outargs
];
int
casStep
=
dilution
+
1
;
// Avoid some common factors:
while
((
casStep
>
2
&&
casStep
%
2
==
0
&&
inargs
%
2
==
0
)
||
(
casStep
>
3
&&
casStep
%
3
==
0
&&
inargs
%
3
==
0
))
casStep
++;
for
(
int
cas
=
0
;
cas
<
numcases
;
cas
+=
casStep
)
{
for
(
int
i
=
0
,
c
=
cas
;
i
<
outargs
;
i
++)
{
reorder
[
i
]
=
c
%
inargs
;
c
/=
inargs
;
}
testPermuteArguments
(
args
,
types
,
reorder
);
}
testPermuteArguments
(
args
,
types
,
outargs
,
numcases
,
casStep
);
numcases
*=
inargs
;
if
(
dilution
>
10
&&
outargs
>=
4
)
{
int
[]
reorder
=
new
int
[
outargs
];
// Do some special patterns, which we probably missed.
// Replication of a single argument or argument pair.
for
(
int
i
=
0
;
i
<
inargs
;
i
++)
{
...
...
@@ -1383,6 +1355,19 @@ public class MethodHandlesTest {
}
}
public
void
testPermuteArguments
(
Object
[]
args
,
Class
<?>[]
types
,
int
outargs
,
int
numcases
,
int
casStep
)
throws
Throwable
{
int
inargs
=
args
.
length
;
int
[]
reorder
=
new
int
[
outargs
];
for
(
int
cas
=
0
;
cas
<
numcases
;
cas
+=
casStep
)
{
for
(
int
i
=
0
,
c
=
cas
;
i
<
outargs
;
i
++)
{
reorder
[
i
]
=
c
%
inargs
;
c
/=
inargs
;
}
testPermuteArguments
(
args
,
types
,
reorder
);
}
}
static
int
[]
reverse
(
int
[]
reorder
)
{
reorder
=
reorder
.
clone
();
for
(
int
i
=
0
,
imax
=
reorder
.
length
/
2
;
i
<
imax
;
i
++)
{
...
...
@@ -1433,6 +1418,12 @@ public class MethodHandlesTest {
MethodHandle
newTarget
=
MethodHandles
.
permuteArguments
(
target
,
inType
,
reorder
);
Object
result
=
newTarget
.
invokeWithArguments
(
args
);
Object
expected
=
Arrays
.
asList
(
permArgs
);
if
(!
expected
.
equals
(
result
))
{
System
.
out
.
println
(
"*** failed permuteArguments "
+
Arrays
.
toString
(
reorder
)+
" types="
+
Arrays
.
asList
(
types
));
System
.
out
.
println
(
"in args: "
+
Arrays
.
asList
(
args
));
System
.
out
.
println
(
"out args: "
+
expected
);
System
.
out
.
println
(
"bad args: "
+
result
);
}
assertEquals
(
expected
,
result
);
}
...
...
@@ -1456,26 +1447,27 @@ public class MethodHandlesTest {
}
public
void
testSpreadArguments
(
Class
<?>
argType
,
int
pos
,
int
nargs
)
throws
Throwable
{
countTest
();
MethodHandle
target
=
varargsArray
(
nargs
);
MethodHandle
target2
=
changeArgTypes
(
target
,
argType
);
Class
<?>
arrayType
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
argType
,
0
).
getClass
();
MethodHandle
target2
=
varargsArray
(
arrayType
,
nargs
);
MethodHandle
target
=
target2
.
asType
(
target2
.
type
().
generic
());
if
(
verbosity
>=
3
)
System
.
out
.
println
(
"spread into "
+
target2
+
" ["
+
pos
+
".."
+
nargs
+
"]"
);
Object
[]
args
=
randomArgs
(
target2
.
type
().
parameterArray
());
// make sure the target does what we think it does:
if
(
pos
==
0
&&
nargs
<
5
)
{
Object
[]
check
=
(
Object
[])
target
.
invokeWithArguments
(
args
);
if
(
pos
==
0
&&
nargs
<
5
&&
!
argType
.
isPrimitive
()
)
{
Object
[]
check
=
(
Object
[])
(
Object
)
target
.
invokeWithArguments
(
args
);
assertArrayEquals
(
args
,
check
);
switch
(
nargs
)
{
case
0
:
check
=
(
Object
[])
target
.
invokeExact
();
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
();
assertArrayEquals
(
args
,
check
);
break
;
case
1
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
]);
assertArrayEquals
(
args
,
check
);
break
;
case
2
:
check
=
(
Object
[])
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
check
=
(
Object
[])
(
Object
)
target
.
invokeExact
(
args
[
0
],
args
[
1
]);
assertArrayEquals
(
args
,
check
);
break
;
}
...
...
@@ -1483,23 +1475,50 @@ public class MethodHandlesTest {
List
<
Class
<?>>
newParams
=
new
ArrayList
<
Class
<?>>(
target2
.
type
().
parameterList
());
{
// modify newParams in place
List
<
Class
<?>>
spreadParams
=
newParams
.
subList
(
pos
,
nargs
);
spreadParams
.
clear
();
spreadParams
.
add
(
Object
[].
class
);
spreadParams
.
clear
();
spreadParams
.
add
(
arrayType
);
}
MethodType
newType
=
MethodType
.
methodType
(
Object
.
class
,
newParams
);
MethodHandle
result
=
target2
.
asSpreader
(
Object
[].
class
,
nargs
-
pos
).
asType
(
newType
);
Object
[]
returnValue
;
MethodType
newType
=
MethodType
.
methodType
(
arrayType
,
newParams
);
MethodHandle
result
=
target2
.
asSpreader
(
arrayType
,
nargs
-
pos
);
assert
(
result
.
type
()
==
newType
)
:
Arrays
.
asList
(
result
,
newType
);
result
=
result
.
asType
(
newType
.
generic
());
Object
returnValue
;
if
(
pos
==
0
)
{
// In the following line, the first cast implies
// normal Object return value for the MH call (Object[])->Object,
// while the second cast dynamically converts to an Object array.
// Such a double cast is typical of MH.invokeExact.
returnValue
=
(
Object
[])
(
Object
)
result
.
invokeExact
(
args
);
Object
args2
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
returnValue
=
result
.
invokeExact
(
args2
);
}
else
{
Object
[]
args1
=
Arrays
.
copyOfRange
(
args
,
0
,
pos
+
1
);
args1
[
pos
]
=
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
);
returnValue
=
(
Object
[])
result
.
invokeWithArguments
(
args1
);
args1
[
pos
]
=
ValueConversions
.
changeArrayType
(
arrayType
,
Arrays
.
copyOfRange
(
args
,
pos
,
args
.
length
));
returnValue
=
result
.
invokeWithArguments
(
args1
);
}
String
argstr
=
Arrays
.
toString
(
args
);
if
(!
argType
.
isPrimitive
())
{
Object
[]
rv
=
(
Object
[])
returnValue
;
String
rvs
=
Arrays
.
toString
(
rv
);
if
(!
Arrays
.
equals
(
args
,
rv
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertArrayEquals
(
args
,
rv
);
}
}
else
if
(
argType
==
int
.
class
)
{
String
rvs
=
Arrays
.
toString
((
int
[])
returnValue
);
if
(!
argstr
.
equals
(
rvs
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertEquals
(
argstr
,
rvs
);
}
}
else
if
(
argType
==
long
.
class
)
{
String
rvs
=
Arrays
.
toString
((
long
[])
returnValue
);
if
(!
argstr
.
equals
(
rvs
))
{
System
.
out
.
println
(
"method: "
+
result
);
System
.
out
.
println
(
"expected: "
+
argstr
);
System
.
out
.
println
(
"returned: "
+
rvs
);
assertEquals
(
argstr
,
rvs
);
}
}
else
{
// cannot test...
}
assertArrayEquals
(
args
,
returnValue
);
}
@Test
...
...
@@ -1780,7 +1799,7 @@ public class MethodHandlesTest {
assertCalled
(
"invokee"
,
args
);
// generic invoker
countTest
();
inv
=
MethodHandles
.
genericI
nvoker
(
type
);
inv
=
MethodHandles
.
i
nvoker
(
type
);
if
(
nargs
<=
3
)
{
calledLog
.
clear
();
switch
(
nargs
)
{
...
...
@@ -2130,15 +2149,12 @@ public class MethodHandlesTest {
Object
z
=
surprise
.
invokeExact
(
x
);
System
.
out
.
println
(
"Failed to throw; got z="
+
z
);
assertTrue
(
false
);
}
catch
(
Exception
ex
)
{
}
catch
(
ClassCast
Exception
ex
)
{
if
(
verbosity
>
2
)
System
.
out
.
println
(
"caught "
+
ex
);
if
(
verbosity
>
3
)
ex
.
printStackTrace
();
assertTrue
(
ex
instanceof
ClassCastException
// FIXME: accept only one of the two for any given unit test
||
ex
instanceof
WrongMethodTypeException
);
assertTrue
(
true
);
// all is well
}
}
...
...
@@ -2328,6 +2344,34 @@ class ValueConversions {
// else need to spin bytecode or do something else fancy
throw
new
UnsupportedOperationException
(
"NYI: cannot form a varargs array of length "
+
nargs
);
}
public
static
MethodHandle
varargsArray
(
Class
<?>
arrayType
,
int
nargs
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
MethodType
vaType
=
MethodType
.
methodType
(
arrayType
,
Collections
.<
Class
<?>>
nCopies
(
nargs
,
elemType
));
MethodHandle
mh
=
varargsArray
(
nargs
);
if
(
arrayType
!=
Object
[].
class
)
mh
=
MethodHandles
.
filterReturnValue
(
mh
,
CHANGE_ARRAY_TYPE
.
bindTo
(
arrayType
));
return
mh
.
asType
(
vaType
);
}
static
Object
changeArrayType
(
Class
<?>
arrayType
,
Object
[]
a
)
{
Class
<?>
elemType
=
arrayType
.
getComponentType
();
if
(!
elemType
.
isPrimitive
())
return
Arrays
.
copyOf
(
a
,
a
.
length
,
arrayType
.
asSubclass
(
Object
[].
class
));
Object
b
=
java
.
lang
.
reflect
.
Array
.
newInstance
(
elemType
,
a
.
length
);
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++)
java
.
lang
.
reflect
.
Array
.
set
(
b
,
i
,
a
[
i
]);
return
b
;
}
private
static
final
MethodHandle
CHANGE_ARRAY_TYPE
;
static
{
try
{
CHANGE_ARRAY_TYPE
=
IMPL_LOOKUP
.
findStatic
(
ValueConversions
.
class
,
"changeArrayType"
,
MethodType
.
methodType
(
Object
.
class
,
Class
.
class
,
Object
[].
class
));
}
catch
(
NoSuchMethodException
|
IllegalAccessException
ex
)
{
Error
err
=
new
InternalError
(
"uncaught exception"
);
err
.
initCause
(
ex
);
throw
err
;
}
}
private
static
final
List
<
Object
>
NO_ARGS_LIST
=
Arrays
.
asList
(
NO_ARGS_ARRAY
);
private
static
List
<
Object
>
makeList
(
Object
...
args
)
{
return
Arrays
.
asList
(
args
);
}
...
...
test/java/lang/invoke/RicochetTest.java
0 → 100644
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
test/sun/invoke/util/ValueConversionsTest.java
0 → 100644
浏览文件 @
4b939f2a
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录