public class PolymorphicSignatureTest {
public int calculate(int num) {
return num + 1;
}
public double calculate(double num) {
return num + 1;
}
public double calculate(Integer num) {
return num + 1;
}
public static void main(String[] args) throws Throwable{
MethodType mt = MethodType.methodType(int.class, int.class);
MethodHandle mh = MethodHandles.lookup()
.findVirtual(PolymorphicSignatureTest.class, "calculate", mt)
.bindTo(new PolymorphicSignatureTest());
int result1 = (int)mh.invoke(1);
double resultE = (double)mh.invokeExact(1);
double result2 = (double)mh.invoke(1);
double result3 = (double)mh.invoke(Integer.valueOf(1));
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
}
字节码:
34: invokevirtual #11 // Method java/lang/invoke/MethodHandle.invoke:(I)I
40: invokevirtual #12 // Method java/lang/invoke/MethodHandle.invokeExact:(I)D
47: invokevirtual #13 // Method java/lang/invoke/MethodHandle.invoke:(I)D
57: invokevirtual #15 // Method java/lang/invoke/MethodHandle.invoke:(Ljava/lang/Integer;)D
其中符号类型描述符为:
(I)I
(I)D
(I)D
(Ljava/lang/Integer;)D
1 MethodHandle实现
通过新建异常实例来查看栈轨迹:
public int calculate(int num) {
new Exception().printStackTrace();
return num + 1;
}
启用-XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames虚拟机参数来打印隐藏的栈信息:
-XX:+UnlockDiagnosticVMOptions
-XX:+ShowHiddenFrames
结果:
java.lang.Exception
at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.calculate(PolymorphicSignatureTest.java:16)
at java.lang.invoke.LambdaForm$DMH006/2055281021.invokeVirtual_001_LI_I(LambdaForm$DMH006:1000011)
at java.lang.invoke.LambdaForm$BMH002/1160460865.reinvoke_002(LambdaForm$BMH002:1000021)
at java.lang.invoke.LambdaForm$MH012/1421795058.invoke_000_MT(LambdaForm$MH012:1000017)
at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.main(PolymorphicSignatureTest.java:35)
添加JVM参数导出class文件:
-Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true
LambdaForm$MH012文件反编译如下:
final class LambdaForm$MH012
{
@LambdaForm.Hidden
@LambdaForm.Compiled
@ForceInline
static double invoke_000_MT(Object paramObject1, int paramInt, Object paramObject2)
{
Object localObject = Invokers.checkGenericType(paramObject1, paramObject2);
Invokers.checkCustomized(localObject);
return (localObject = (MethodHandle)localObject).invokeBasic(paramInt);
}
static void dummy()
{
"invoke_000_MT=Lambda(a0:L,a1:I,a2:L)=>{\n t3:L=Invokers.checkGenericType(a0:L,a2:L);\n t4:V=Invokers.checkCustomized(t3:L);\n t5:D=MethodHandle.invokeBasic(t3:L,a1:I);t5:D}";
}
}
该方法的三个步骤:
step1.Invokers.checkGenericType方法类型检查
step2.Invokers.checkCustomized在MethodHandle执行次数超过一个阈值时进行优化(-Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD,默认为127)
step3.调用MethodHandle的invokeBasic。调用至MethodHandle所持有的的适配器中,同样是LambdaForm
/**
* Private method for trusted invocation of a method handle respecting simplified signatures.
* Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
*
* The caller signature is restricted to the following basic types:
* Object, int, long, float, double, and void return.
*
* The caller is responsible for maintaining type correctness by ensuring
* that the each outgoing argument value is a member of the range of the corresponding
* callee argument type.
* (The caller should therefore issue appropriate casts and integer narrowing
* operations on outgoing argument values.)
* The caller can assume that the incoming result value is part of the range
* of the callee's return type.
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
/*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
LambdaForm$BMH002文件:
final class LambdaForm$BMH002
{
@LambdaForm.Hidden
@LambdaForm.Compiled
@ForceInline
static double reinvoke_002(Object paramObject, int paramInt)
{
Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
return ((MethodHandle)localObject3).invokeBasic(i);
}
static void dummy()
{
"BMH.reinvoke_002=Lambda(a0:L/SpeciesData,a1:I)=>{\n t2:L=BoundMethodHandle$Species_L3.argL1(a0:L);\n t3:L=BoundMethodHandle$Species_L3.argL0(a0:L);\n t4:I=MethodHandle.invokeBasic(t3:L,t2:L,a1:I);\n t5:L=BoundMethodHandle$Species_L3.argL2(a0:L);\n t6:D=MethodHandle.invokeBasic(t5:L,t4:I);t6:D}";
}
}
LambdaForm$DMH006文件:
final class LambdaForm$DMH006
{
@LambdaForm.Hidden
@LambdaForm.Compiled
@ForceInline
static int invokeVirtual_001_LI_I(Object paramObject1, Object paramObject2, int paramInt)
{
Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
return MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
}
static void dummy()
{
"DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{\n t3:L=DirectMethodHandle.internalMemberName(a0:L);\n t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}";
}
}
2 Invokers.checkGenericType
2.1 invokeExact进行严格匹配检查
invokeExact会确认该invokevirtual指令对应的方法描述符和该MethodHandle类型是否严格匹配,不匹配会抛出异常。
double resultE = (double)mh.invokeExact(1);
会进入如下方法进行检查:
@ForceInline
void checkExactType(Object mhObj, Object expectedObj) {
MethodHandle mh = (MethodHandle) mhObj;
MethodType expected = (MethodType) expectedObj;
MethodType actual = mh.type();
if (actual != expected)
throw newWrongMethodTypeException(expected, actual);
}
这里的mhObj就是当前的MethodHandle:
这里的expectedObj就是从实际的参数和返回类型派生符号类型描述符,也就是invokevirtual指令对应的方法描述符:
这里会判断mhObj.type()与expectedObj是否相等,如果不等直接抛出异常newWrongMethodTypeException:
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (int)int but found (int)double
at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:298)
at java.lang.invoke.Invokers.checkExactType(Invokers.java:309)
at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.main(PolymorphicSignatureTest.java:33)
1.2.2 invoke自动适配参数类型
(R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
double result2 = (double)mh.invoke(1);
进入如下代码:
/** Static definition of MethodHandle.invokeGeneric checking code.
* Directly returns the type-adjusted MH to invoke, as follows:
* {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
*/
/*non-public*/ static
@ForceInline
Object checkGenericType(Object mhObj, Object expectedObj) {
MethodHandle mh = (MethodHandle) mhObj;
MethodType expected = (MethodType) expectedObj;
return mh.asType(expected);
/* Maybe add more paths here. Possible optimizations:
* for (R)MH.invoke(a*),
* let MT0 = TYPEOF(a*:R), MT1 = MH.type
*
* if MT0==MT1 or MT1 can be safely called by MT0
* => MH.invokeBasic(a*)
* if MT1 can be safely called by MT0[R := Object]
* => MH.invokeBasic(a*) & checkcast(R)
* if MT1 can be safely called by MT0[* := Object]
* => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
* if a big adapter BA can be pulled out of (MT0,MT1)
* => BA.invokeBasic(MT0,MH,a*)
* if a local adapter LA can cached on static CS0 = new GICS(MT0)
* => CS0.LA.invokeBasic(MH,a*)
* else
* => MH.asType(MT0).invokeBasic(A*)
*/
}
public MethodHandle asType(MethodType newType) {
// Fast path alternative to a heavyweight {@code asType} call.
// Return 'this' if the conversion will be a no-op.
if (newType == type) {
return this;
}
// Return 'this.asTypeCache' if the conversion is already memoized.
MethodHandle atc = asTypeCached(newType);
if (atc != null) {
return atc;
}
return asTypeUncached(newType);
}
asType方法可能会抛出NullPointerException(newType是null引用)或者WrongMethodTypeException(如果类型转换没法进行)。
MethodHandle.asType会返回一个适配器MethodHandle将现有的MethodHandle适配成目标类型newType。
新的适配器MethodHandle调用invoke时:
1)将入参列表进行转换以适配老的MethodHandle的参数列表
2)以转换后的参数列表调用老的MethodHandle
3)将老的MethodHandle的返回值转换为新的适配器MethodHandle的返回类型
3 Invokers.checkCustomized
/*non-public*/ static
@ForceInline
void checkCustomized(Object o) {
MethodHandle mh = (MethodHandle)o;
if (mh.form.customized == null) {
maybeCustomize(mh);
}
}
/*non-public*/ static
@DontInline
void maybeCustomize(MethodHandle mh) {
byte count = mh.customizationCount;
if (count >= CUSTOMIZE_THRESHOLD) {
mh.customize();
} else {
mh.customizationCount = (byte)(count+1);
}
}
CUSTOMIZE_THRESHOLD的值为127。当调用次数超过127时,调用MethodHandle.customize()为该MethodHandle定制一个LambdaForm,并将该MH的(final LambdaForm form)设置为新的LambdaForm。
/** Craft a LambdaForm customized for this particular MethodHandle */
/*non-public*/
void customize() {
if (form.customized == null) {
LambdaForm newForm = form.customize(this);
updateForm(newForm);
} else {
assert(form.customized == this);
}
}
4.BoundMethodHandle 适配器
4.1 调用栈
LambdaForm$BMH002文件:
final class LambdaForm$BMH002
{
@LambdaForm.Hidden
@LambdaForm.Compiled
@ForceInline
static double reinvoke_002(Object paramObject, int paramInt)
{
Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
return ((MethodHandle)localObject3).invokeBasic(i);
}
static void dummy()
{
"BMH.reinvoke_002=Lambda(a0:L/SpeciesData,a1:I)=>{\n t2:L=BoundMethodHandle$Species_L3.argL1(a0:L);\n t3:L=BoundMethodHandle$Species_L3.argL0(a0:L);\n t4:I=MethodHandle.invokeBasic(t3:L,t2:L,a1:I);\n t5:L=BoundMethodHandle$Species_L3.argL2(a0:L);\n t6:D=MethodHandle.invokeBasic(t5:L,t4:I);t6:D}";
}
}
4.2 适配器BoundMethodHandle$Species_L3各参数值
BMH的注释:
/**
* The flavor of method handle which emulates an invoke instruction
* on a predetermined argument. The JVM dispatches to the correct method
* when the handle is created, not when it is invoked.
*
* All bound arguments are encapsulated in dedicated species.
*/
/*non-public*/ abstract class BoundMethodHandle extends MethodHandle {
BMH模拟对预先确定参数的调用指令,JVM在创建MH时就已经确定了调度的方法,而不是调用时。所有绑定参数都封装在专用的species中。
如下为BoundMethodHandle$Species_L3文件:
final class BoundMethodHandle$Species_L3
extends BoundMethodHandle
{
@Stable
static BoundMethodHandle.SpeciesData SPECIES_DATA;
final Object argL0;
final Object argL1;
final Object argL2;
private BoundMethodHandle$Species_L3(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject1, Object paramObject2, Object paramObject3)
{
super(paramMethodType, paramLambdaForm);
this.argL0 = paramObject1;
this.argL1 = paramObject2;
this.argL2 = paramObject3;
}
final BoundMethodHandle.SpeciesData speciesData()
{
return SPECIES_DATA;
}
final int fieldCount()
{
return 3;
}
static BoundMethodHandle make(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject1, Object paramObject2, Object paramObject3)
{
return new Species_L3(paramMethodType, paramLambdaForm, paramObject1, paramObject2, paramObject3);
}
final BoundMethodHandle copyWith(MethodType paramMethodType, LambdaForm paramLambdaForm)
{
return new Species_L3(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2);
}
final BoundMethodHandle copyWithExtendL(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject)
throws Throwable
{
return SPECIES_DATA.extendWith((byte)0).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramObject);
}
final BoundMethodHandle copyWithExtendI(MethodType paramMethodType, LambdaForm paramLambdaForm, int paramInt)
throws Throwable
{
return SPECIES_DATA.extendWith((byte)1).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramInt);
}
final BoundMethodHandle copyWithExtendJ(MethodType paramMethodType, LambdaForm paramLambdaForm, long paramLong)
throws Throwable
{
return SPECIES_DATA.extendWith((byte)2).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramLong);
}
final BoundMethodHandle copyWithExtendF(MethodType paramMethodType, LambdaForm paramLambdaForm, float paramFloat)
throws Throwable
{
return SPECIES_DATA.extendWith((byte)3).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramFloat);
}
final BoundMethodHandle copyWithExtendD(MethodType paramMethodType, LambdaForm paramLambdaForm, double paramDouble)
throws Throwable
{
return SPECIES_DATA.extendWith((byte)4).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramDouble);
}
}
调试方法:
在运行到checkGenericType中,在BMH的构造函数处打断点;
/*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
super(type, form);
assert(speciesData() == speciesData(form));
}
然后获得如下调用栈:
分析这五个参数:
param_1是方法描述符为"(I)D"的MethodType,代表根据实际类型生成的方法描述符。
param_2是LambdaFrom
param_3是之前lookup()生成MH,代表原始的MH:
1)其MemberName member代表对指定类PolymorphicSinatureTest的方法calculate:(I)I的引用
2)其MethodType type就是对方法类型的描述(返回类型int;入参(1-PolymorphicSinatureTest,2-int))
3)其LambdaForm form值如下
DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{
t3:L=DirectMethodHandle.internalMemberName(a0:L);
t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}
param_4是之前传入的入参bindTo(new PolymorphicSignatureTest())
param_5是调用完老的MH后,需要调用该方法进行返回值转换
因此可知BMH的各参数值如下:
MethodType type = "(I)D"的MethodType
LambdaForm form = LambdaForm$BMH002.reinvoke_002
argL0 = 代表原始的MH
argL1 = 之前传入的入参bindTo(new PolymorphicSignatureTest())
argL2 = DMH intToDouble (调用完老的MH后,需要调用该方法进行返回值转换)
4.3 理解 LambdaForm$BMH002.reinvoke_002方法
static double reinvoke_002(Object paramObject, int paramInt)
{
Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
return ((MethodHandle)localObject3).invokeBasic(i);
}
两个入参的含义:
1)paramObject 为上面介绍的适配器BMH
2)paramInt 实际传入的参数值:(double)mh.invoke(1)中的1
Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
将入参bindTo(new PolymorphicSignatureTest())赋值给localObject1
Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
将原始MH赋值给localObject2
int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
通过原始MH调用invokeBasic(new PolymorphicSignatureTest(), 1)调用实际的方法,获得int类型的返回值i
Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
将DMH intToDouble赋值给localObject3
((MethodHandle)localObject3).invokeBasic(i)
调用DMH intToDouble,将int类型转为double类型并返回
总结:
适配器MethodHandle调用invoke时:
1)将入参列表进行转换以适配老的MethodHandle的参数列表
2)以转换后的参数列表调用老的MethodHandle
3)将老的MethodHandle的返回值转换为新的适配器MethodHandle的返回类型
5.原始DMH.invokeBasic(new PolymorphicSignatureTest(), 1)
根据栈信息该方法会调用:
java.lang.invoke.LambdaForm$DMH006/2055281021.invokeVirtual_001_LI_I(LambdaForm$DMH006:1000011)
该方法本身就是原始DMH的form,请参考上一节的param_3的LambdaForm form值。
final class LambdaForm$DMH006
{
@LambdaForm.Hidden
@LambdaForm.Compiled
@ForceInline
static int invokeVirtual_001_LI_I(Object paramObject1, Object paramObject2, int paramInt)
{
Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
return MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
}
static void dummy()
{
"DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{\n t3:L=DirectMethodHandle.internalMemberName(a0:L);\n t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}";
}
}
根据该方法的含义,可推知invokeVirtual_001_LI_I三个参数的含义:
paramObject1 —— 原始DMH
paramObject2 —— new PolymorphicSignatureTest()
paramInt —— 1
Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
获取原始DMH的member,也即类PolymorphicSinatureTest的方法calculate:(I)I的引用。
/*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
DirectMethodHandle dmh = (DirectMethodHandle)mh;
dmh.ensureInitialized();
return dmh.member;
}
MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
该方法最后一个参数必须是MemberName类型,也即将参数传入PolymorphicSinatureTest的方法calculate:(I)I,进行调用。
/**
* Private method for trusted invocation of a MemberName of kind {@code REF_invokeVirtual}.
* The caller signature is restricted to basic types as with {@code invokeBasic}.
* The trailing (not leading) argument must be a MemberName.
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
/*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;