10 лет назад в java было 4 байткод инструкции для вызова методов. В Java 7 добавили invokedynamic для поддержки динамических языков.
invokedynamic - это лишь небольшая часть Da Vinci Machine Project. У проекта очень красивое описание:
a multi-language renaissance for the Java Virtual Machine architecture
Среди других фич Interface injection, Lightweight bytecode loading, Tail calls and tail recursion и прочие интересные штуки.
Но вернёмся к invokedynamic. Разберём по шагам, как он работает:
1️⃣ JVM встречает в class файле такой байткод
invokedynamic #7, 02️⃣ В пуле констант находим такую запись
#7 = InvokeDynamic #0:#83️⃣ Идём по ссылкам и попадаем в специальную секцию .class файла под названием BootstrapMethods.
Если компилятор использует invokedynamic, то он обязан прописать такой метод.
4️⃣ Там мы находим набор инструкций, который по заданным аргументам укажет на конкретный метод. В итоге всё сводится к получению и вызову MethodHandle.
В чём фишка:
В других invoke* алгоритм связывания жёстко задан внутри JVM, а для invokedynamic логика связывания прописывается в отдельном методе, который может быть любым.
Такая вот общая схема. Дальше идут оптимизации. Например, бутстрап метод возвращает не сам MethodHandle, а более гибкий CallSite. У него три реализации: одна с неизменным MethodHandle и две с переменным
invokedynamic был создан для поддержки динамических языков. Но стало понятно, что с ним можно реализовать много классных фич в самой java.
Так что на следующей неделе соберём всё вместе и погрузимся в детали реализации лямбда-выражений🤓