Использование "invokedynamic" - что происходит под капотом?

Фон

В настоящее время я пишу 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 ответ

Решение

Идея 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 конкатенация, которая должна быть проще в реализации.

Другие вопросы по тегам