ในตอนนี้เราจะ เข้าไปใกล้ invokedynamic เพิ่มขึ้นอีกนิด
จาก part 1 เราได้เห็นวิธีการเรียก method ด้วย MethodHandle.invoke*() ไปแล้ว ในตอนนี้เราจะมาอธิบายการทำงานของ invokedynamic ในรูปแบบ java api และบทความถัดไปจะทดลองทำให้ดูในรูปแบบ bytecode โดยใช้ ASM
invokespecial,invokestatic จะ resolve target method โดยตรงจาก class
invokevirtual,invokeinterface จะ resolve target method จาก virtual method table
invoke** ด้านบนทั้งหมดจะมีกฏตายตัวในการ resove target method แต่สำหรับ invokedynamic จะ delegate การ resolve target method ไปให้เป็นหน้าที่ของ bootstrap method เพื่อเปิดโอกาสที่ผู้ที่อิมพรีเมนภาษาต่างๆสามารถ customize logic ในการ resolve method เองได้
bootstrap method จะ associate กับ invokedynamic instruction หรือพูดได้ว่า invokedynamic จะเรียก bootstrap method เพื่อให้มันรีเทิร์น java.lang.invoke.CallSite กลับมาให้ ซึ่งใน CallSite ก็จะมี target (CallSite.getTarget()) ที่เป็น MethodHandle ที่จะเป็น target method ที่เราต้องการให้เรียกอีกที
การเรียก bootstrap method สามารถคืนค่า MethodHandle เดิมเมือ่เรียกครั้งถัดไปหรืออาจจะไม่คืนค่าเดิมก้ได้ โดย CallSite จะมีสองแบบ constant และ mutable และเราสามารถสร้าง bootstrap method สำหรับแต่ละคำสั่ง invokedynamic หรือจะแชร์ bootstrap method กันก็ได้
invokedynamic จะมีรุปแบบดังนี้
invokedynamic boostrap-method-ref:[method-name:method-type]
โดย
-
boostrap-method-refจะอ้างถึง BootstrapMethod attribute ใน constant pool -
[method-name : method-type]จะอ้างถึง NameAndType_info ใน constant pool ซึ่งmethod-nameจะเป็นชื่อ target method และmethod-typeจะเป็น args และ return type
bootstrap method จะมีหลายรูปแบบ (สามารถอ่านเพิ่มเติมจาก JSR-292) การเรียก bootstrap method จะมีการระบุ parameter อย่างน้อย 3 ตัว ตามตัวอย่างนี้
CallSite bootstrap(Lookup caller, String name, MethodType type)
การทำงานของ invokedynamic จะทำงานหลักๆอยู่ 3 step สรุปโดยย่อจาก 6.5.invokedynamic
- prepare parameter
Lookup,name,MethodType(name,MethodType จะ resove reference จาก constant pool แต่ Lookup ผมไม่ทราบ ไม่ได้มีอธิบายไว้ ถ้าดูจากโคีด มันจะใช้ Reflection.getCallerClass() ซึ่งเป็น native method) - link คือขั้นตอนการเรียก
bootstrap method - invoke
เด๋วจะขอยกตัวอย่างการจำลองการ invokedynamic โดย java api เลยละกันครับ
public class MethodHandleTest2 {
public static void main(String[] args) throws Throwable {
// บรรทัดถัดไปคือ bytecode ของ invokedynamic นะครับ #1 #2 #3 จะถูกเก็บไว้ใน constant pool
// invokedynamic #1:[#2:#3]
// step 1 preapre อันนี้ทำโดย JVM
final MethodHandles.Lookup callerLookup = MethodHandles.lookup();
// #2
String targetMethodName = "target";
// #3
MethodType methodType = MethodType.methodType(void.class, String.class);
// step 2 link
CallSite callSite = boostrapMethod(callerLookup, targetMethodName, methodType);
// step 3 invoke
// ในเคสของ ConstantCallSite dynamicInvoker() จะ delegate ไป getTarget()
callSite.dynamicInvoker().invokeWithArguments("world"); // print "Hello world"
}
// #1
private static CallSite boostrapMethod(MethodHandles.Lookup callerContextLookup, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
final MethodHandle methodHandle = callerContextLookup.findStatic(callerContextLookup.lookupClass(), name, methodType);
CallSite callSite = new ConstantCallSite(methodHandle);
return callSite;
}
//target method ของเรา มี type description (Ljava/lang/String;)V
private static void target(String msg) {
System.out.println("Hello " + msg);
}
}
reference:
Constant Pool
invokedynamic
JSR-292
Top comments (0)