Использование «invokedynamic» - что происходит под капотом? - PullRequest
0 голосов
/ 04 ноября 2018

Фон

В настоящее время я пишу JVM на C # для чисто академических целей (и, возможно, в будущем создаю смешанное приложение .NET и Java / Scala).

Контекст

Я пишу простой JAVA класс:

public class test
{
    public static String hello_world(int i)
    {
        return "Hello " + i + " World!";
    }
}

И скомпилируйте его в test.class. Когда я декомпилирую его с помощью моего декомпилятора (который я написал как часть JVM), я вижу следующие инструкции для этого метода:

iload_0
invokedynamic 2
areturn

При поиске внутри пула констант для константы с индексом 2 я вижу запись InvokeDynamic-Constant со следующими данными:

makeConcatWithConstants : (I)Ljava/lang/String;

Думаю, это имеет смысл (я скорее пользователь .NET, чем пользователь JAVA).

При выполнении моего метода hello_world с параметром 1 у меня есть следующий стек перед выполнением invokedynamic 2:

----TOP---
0x00000001
--BOTTOM--

Вопрос

Мой вопрос: Как мне использовать invokedynamic?
Я не могу разрешить метод makeConcatWithConstants, так как InvokeDynamic-Constant не дает мне подсказки, где может находиться makeConcatWithConstants ( см. Документацию ).
В стеке также нет ссылки на кучу, указывающей, с каким типом экземпляра может быть связан метод makeConcatWithConstants.

Я прочитал invokedynamic документы , но я не понимаю этого (может быть, я сильно "поврежден" .NET-Framework).

Может кто-нибудь указать мне пример того, что происходит под капотом JVM при выполнении этих трех инструкций? (Что ожидает вызываемый invokedynamic и т. Д.)?

Я уже реализовал invokestatic в моей JVM ... но в настоящее время я не могу понять invokedynamic.

1 Ответ

0 голосов
/ 04 ноября 2018

Идея invokedynamic есть; При первом обнаружении этого байт-кода вызовите метод начальной загрузки, который создает объект Callsite, который ссылается на фактический метод, который необходимо вызвать.

На практике это часто означает, что вы динамически создаете реализацию для вызова.

Если вы посмотрите на вашу программу с javap -v test, вы увидите внизу атрибут BootstrapMethods:

BootstrapMethods:
  0: #15 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #16 Hello \u0001 World!

Где вы можете видеть, что метод начальной загрузки для этого конкретного места вызова находится в StringConcatFactory

Method arguments - набор постоянных аргументов.

Ведущие аргументы Lookup, String и MethodType соответственно; объект поиска с теми же привилегиями, что и у места вызова, с некоторым именем и типом места вызова. Первый из них должен быть предоставлен виртуальной машиной во время выполнения, а последние 2 - в записи пула констант динамических переменных в форме имени и типа:

#2 = InvokeDynamic      #0:#17         // #0:makeConcatWithConstants:(I)Ljava/lang/String;

Таким образом, для реализации этого байт-кода у вас должно быть какое-то оборудование для создания объекта поиска, а затем вы сможете вызвать метод начальной загрузки. После этого вы можете вызвать dynamicInvoker() для возвращенного объекта Callsite, который дает вам MethodHandle, который вы должны затем кэшировать для этого конкретного места вызова и затем (наконец) вызвать .

Если вы хотите посмотреть, как это реализовано в OpenJDK, вы можете найти реализацию здесь: http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp#l2446

Я предполагаю, что это, вероятно, слишком сложно на этом раннем этапе проекта, так что на данный момент может быть проще скомпилировать вашу программу с -XDstringConcat=inline, поскольку она использует устаревшую конкатенацию StringBuilder, которая должна быть проще реализовать.

...