Разбираюсь с сабжем, и непонятно вот что. Везде пишут, что invokedynamic — это изобретение в первую очередь для поддержки динамических вызовов. То есть например мы — разработчики компилятора/рантайма какого-то динамического языка. И у нас есть код навроде
var a = getSomeA(); // Тип переменной a заранее не известен
var b = getSomeB(); // Тип переменной b тоже заранее не известен
a.foo(123); // Дёргаем метод a.foo(int), если таковой имеется у объекта a
a.foo(b); // Дёргаем метод a.foo(type(b)), если таковой имеется
То есть при компиляции мы не знаем типов ни вызывающего объекта, ни аргументов. Как же в таком случае нам поможет инструкция invokedynamic, если первым её параметром в байт-коде является ссылка на константу InvokeDynamic в пуле констант. А константа InvokeDynamic в свою очередь ссылается на bootstrap method и на константу NameAndType.
В случае статически типизированных лямбд всё понятно:
Constant pool:
#5 = InvokeDynamic #0:#41 // #0:apply:()Ljava/util/function/Function;
#41 = NameAndType #59:#60 // apply:()Ljava/util/function/Function;
#59 = Utf8 apply
#60 = Utf8 ()Ljava/util/function/Function;
BootstrapMethods:
0: #37 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:
#38 (Ljava/lang/Object;)Ljava/lang/Object;
#39 invokestatic org/jcoro/Test.lambda$foo$2:(Ljava/lang/Integer;)Ljava/lang/Boolean;
#40 (Ljava/lang/Integer;)Ljava/lang/Boolean;
public static void foo();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=0
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_0
8: aload_0
9: invokeinterface #4, 1 // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
14: invokedynamic #5, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
19: invokeinterface #6, 2 // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
24: invokestatic #7 // Method java/util/stream/Collectors.toList:()Ljava/util/stream/Collector;
27: invokeinterface #8, 2 // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
32: pop
33: return
LineNumberTable:
line 13: 0
line 14: 8
line 16: 24
line 17: 33
LocalVariableTable:
Start Length Slot Name Signature
8 26 0 list Ljava/util/List;
LocalVariableTypeTable:
Start Length Slot Name Signature
8 26 0 list Ljava/util/List<Ljava/lang/Integer;>;
private static java.lang.Boolean lambda$foo$2(java.lang.Integer);
...
А как это поможет в создании рантайма для динамически типизированных языков ? Ведь NameAndType фиксирован даже не как _аргумент_ инструкции (который можно на стек положить в зависимости от типа), а как параметр инструкции в байткоде ! То есть вот написали метод, который делает invokeDynamic для указанного типа+имени метода. А если тип другой ? И в каком месте выполнять свич по типам аргументов, фактически переданных методу ?