Java InvokeDynamic (part 2 CallSite)
Tags: java, invokedynamic, methodhandle
Published: 2020-03-31 14:55:41

---
title: Java InvokeDynamic (part 2 CallSite)
published: true
description: เข้าใจ InvokeDynamic ไปจนถึง Lambda
tags: java,invokedynamic,methodhandle
---

ในตอนนี้เราจะ เข้าไปใกล้ 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 ตัว ตามตัวอย่างนี้ 
```java
CallSite bootstrap(Lookup caller, String name, MethodType type)
```

การทำงานของ `invokedynamic` จะทำงานหลักๆอยู่ 3 step [สรุปโดยย่อจาก 6.5.invokedynamic](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic)
1. prepare parameter `Lookup,name,MethodType` (name,MethodType จะ resove reference จาก constant pool แต่ Lookup ผมไม่ทราบ ไม่ได้มีอธิบายไว้ ถ้าดูจากโคีด มันจะใช้ Reflection.getCallerClass() ซึ่งเป็น native method)
2. link คือขั้นตอนการเรียก `bootstrap method`
3. invoke

 เด๋วจะขอยกตัวอย่างการจำลองการ invokedynamic โดย java api เลยละกันครับ
```java
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](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4)
[invokedynamic](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic)
[JSR-292](https://jcp.org/en/jsr/detail?id=292)