Invoke Dynamic
Table of Contents
1. Invoke Dynamic
1.1. Overview
invokedynamic 是 java 1.7 添加一个新的 JVM OPCODE, 主要用来支持动态类型语言. 在 java 1.8 中, OpenJDK 使用 invokedynamic 来实现 lambda.
invokedynamic 要解决的主要问题是:
function (x) {
x.foo();
}
应该编译为什么样的 bytecode? x 的类型是未知的, 那么 `x.foo()` 应该编译成 invoke-?
invokedynamic 的思想是:
由于 x 的类型只有在运行时才能知道, 当需要确定 `x.foo` 如何 dispatch 时,把调用时相关的信息 (例如 x 对象, 字符串 "foo", foo 的 method type 或 signature) 作为参数传递给一个用户提供的 bootstrap 函数, 后者会返回一个 CallSite 对象, 包含了具体的对应于当前 callsite 的 target function (MethodHandle), 即由用户去实现具体的 dispatch.
- invokedynamic 调用时是由 bootstrap 函数决定具体的 dispatch
- bootstrap 函数是用户可以提供的, 给各种动态语言基于 JVM 的实现提供了灵活性, 它相当于 linker 中的 dl_resolve 函数
- invokedynamic 相当于 `userspace` 的 dispatch
1.2. invokedynamic 与 lambda
OpenJDK 中 lambda 的实现:
import java.util.function.Consumer; import java.util.ArrayList; public class playground { static void foo(Consumer<String> c) { c.accept("hello"); } public static void main(String[] args) { foo(v -> {int x = v.length();}); } }
对应的 bytecode 为:
public static void main(java.lang.String[]);
0: invokedynamic #4, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;
5: invokestatic #5 // Method foo:(Ljava/util/function/Consumer;)V
8: return
private static void lambda$main$0(java.lang.String);
0: aload_0
1: invokevirtual #6 // Method java/lang/String.length:()I
4: istore_1
5: return
bootstrap method:
0: #28 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#29 (Ljava/lang/Object;)V
#30 invokestatic playground.lambda$main$0:(Ljava/lang/String;)V
#31 (Ljava/lang/String;)V
与 类似, 首先 lambda 被编译为一个 static 函数, 然后由 invokedynamic 在运行时通过 metafactory 这个 bootstrap 函数提供了一个与 LambdaConsumer 类似的 functional interface 的实例 ((通过 ASM 框架)
