Модуль jdk.dynalink
Dynalink — это библиотека для динамической привязки высокоуровневых операций к объектам. Эти операции включают «чтение свойства», «запись свойства», «вызов функции» и так далее. Dynalink в первую очередь полезен для реализации языков программирования, где по крайней мере некоторые выражения имеют динамические типы (то есть типы, которые нельзя определить статически), а операции с динамическими типами выражаются в виде сайтов вызова. Эти сайты вызова будут привязаны к соответствующим целевым обработчикам методов во время выполнения на основе фактических типов значений, к которым относятся выражения. Они могут меняться между вызовами, что требует многократной перепривязки сайта вызова для адаптации к новым типам; Dynalink обрабатывает всё это и многое другое.
Dynalink поддерживает реализацию языков программирования с моделями объектов, которые отличаются (даже радикально) от модели JVM на основе классов и имеют свои пользовательские преобразования типов.
Dynalink тесно связан с пакетом java.lang.invoke и опирается на него.
В то время как java.lang.invoke предоставляет низкоуровневый API для динамической привязки invokedynamic сайтов вызова, он не предоставляет способа выражения операций более высокого уровня над объектами, ни методов, которые их реализуют. Эти операции являются обычными в объектно-ориентированных средах: доступ к свойствам, доступ к элементам коллекций, вызов методов и конструкторов (возможно, с множественным диспетчером, например, эквиваленты в Java перегрузки методов во время связи и выполнения). Все эти функции обычно необходимы в языке на JVM. Если язык статически типизирован, и его система типов соответствует системе типов JVM, он может достичь этого с помощью обычных инструкций вызова, доступа к полям и т. д. (например, invokevirtual, getfield). Однако, если язык динамический (следовательно, типы некоторых выражений неизвестны до оценки во время выполнения), или его модель объектов или система типов не очень близки к модели JVM, то он должен использовать invokedynamic сайты вызова вместо этого и позволить Dynalink управлять ими.
Пример
Dynalink, вероятно, лучше всего объясняется примером, демонстрирующим его использование. Предположим, у вас есть программа на языке, где вам не нужно объявлять тип объекта, и вы хотите получить доступ к свойству в нём:var color = obj.color;Если вы сгенерировали Java-класс для представления вышеприведенной однострочной программы, его байт-код будет выглядеть примерно так:
aload 2 // load "obj" on stack invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type astore 3 // store the return value into local variable "color"Для привязки инструкции
invokedynamic нам нужен метод загрузки. Минимальный метод загрузки с Dynalink может выглядеть так:
import java.lang.invoke.*;
import jdk.dynalink.*;
import jdk.dynalink.support.*;
class MyLanguageRuntime {
private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
return dynamicLinker.link(
new SimpleRelinkableCallSite(
new CallSiteDescriptor(lookup, parseOperation(name), type)));
}
private static Operation parseOperation(String name) {
...
}
}
В приведенном фрагменте кода есть несколько важных объектов: -
DynamicLinker— это главный объект в Dynalink, он координирует привязку сайтов вызова к обработчикам методов, которые реализуют названные в них операции. Он настраивается и создаётся с помощьюDynamicLinkerFactory. - При вызове метода загрузки ему необходимо создать объект
CallSite. В Dynalink эти сайты вызова должны дополнительно реализовывать интерфейсRelinkableCallSite. "Перепривязываемый" здесь подразумевает тот факт, что если сайт вызова встретит объекты разных типов во время выполнения, его цель будет изменена на обработчик метода, который может выполнить операцию с вновь встреченным типом.SimpleRelinkableCallSiteиChainedCallSite(не используются в приведённом примере) — это две реализации, уже предоставленные библиотекой. - Dynalink использует объекты
CallSiteDescriptorдля сохранения параметров метода загрузки: поиск и тип метода, так как ему понадобятся они всякий раз, когда потребуется перепривязывать сайт вызова. - Dynalink использует объекты
Operationдля выражения динамических операций. Он не предписывает, как закодировать операции в вашем сайте вызова. Вот почему в примере функцияparseOperationоставлена пустой, и вы должны предоставить код для разбора строки"GET:PROPERTY:color"в имени сайта вызова в объект операции получения именованного свойства, какStandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color").
Что вы уже можете сделать с помощью вышеуказанной настройки? DynamicLinkerFactory по умолчанию создаёт DynamicLinker, который может привязывать Java-объекты с обычной семантикой Java. Если у вас есть эти три простых класса:
public class A {
public String color;
public A(String color) { this.color = color; }
}
public class B {
private String color;
public B(String color) { this.color = color; }
public String getColor() { return color; }
}
public class C {
private int color;
public C(int color) { this.color = color; }
public int getColor() { return color; }
}
и вы каким-то образом создаёте их экземпляры и передаёте их на свой сайт вызова на вашем языке программирования:
for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
print(obj.color);
}
то при первом вызове Dynalink привяжет операцию получения .color к получению поля для A.color, при втором вызове перепривяжет его к B.getColor(), возвращающему String, и, наконец, при третьем вызове перепривяжет его к C.getColor(), возвращающему int. SimpleRelinkableCallSite, который мы использовали выше, запоминает привязку только для последнего встреченного типа (он реализует то, что известно как мономорфный кэш встраивания). Другая реализация, уже предоставленная, ChainedCallSite будет запоминать привязки для нескольких разных типов (это полиморфный кэш встраивания) и, вероятно, является лучшим выбором в серьёзных приложениях. Dynalink и создание байт-кода
CallSite объекты обычно создаются в рамках загрузки invokedynamic инструкций в байт-коде. Таким образом, Dynalink обычно используется как часть сред выполнения языка, которые компилируют программы в формат байт-кода Java .class. Dynalink не затрагивает аспекты создания классов байт-кода или их загрузки в JVM. Тем не менее, Dynalink также можно использовать без компиляции байт-кода (например, в интерпретаторах языка), создавая CallSite объекты явно и связывая их с представлениями динамических операций в интерпретируемой программе (например, типичным представлением были бы объекты узлов в дереве синтаксического анализа). Доступные операции
Dynalink определяет несколько стандартных операций в своём классеStandardOperation. Привязка к Java-объектам может связывать все эти операции, и рекомендуется по крайней мере поддерживать и использовать эти операции в вашем языке. Стандартные операции GET и SET должны быть объединены как минимум с одним Namespace для того, чтобы быть полезными, например, для выражения операции получения свойства, вы бы использовали StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY). Dynalink определяет три стандартных пространства имён в классе StandardNamespace. Для связывания фиксированного имени с операцией вы можете использовать NamedOperation, как в предыдущем примере: StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color") выражает операцию получения свойства с именем «цвет». Операции над несколькими пространствами имён
Некоторые языки могут не иметь отдельных пространств имён для свойств, элементов и методов для объектов, и конструктор языка-источника может охватывать сразу несколько из них. Dynalink поддерживает указание несколькихNamespace объектов с помощью NamespaceOperation. Языкоспецифичные привязки
Языки, которые определяют свою собственную модель объектов, отличную от модели JVM на основе классов, и/или используют свои собственные преобразования типов, должны создавать свои собственные языкоспецифичные привязки. Обратитесь к пакетуjdk.dynalink.linker и, в частности, к интерфейсу GuardingDynamicLinker, чтобы начать работу. Dynalink и Java-объекты
DynamicLinker объекты, созданные DynamicLinkerFactory по умолчанию, содержат внутренний экземпляр BeansLinker, который является языкоспецифичной привязкой, реализующей обычные семантики Java для всех вышеперечисленных операций и может привязывать любой Java-объект, который не удалось привязать никакой другой языкоспецифичной привязкой. Таким образом, все среды выполнения языка имеют встроенную межъязыковую совместимость с обычными Java-объектами. См. BeansLinker для подробностей о том, как он связывает различные операции. Межъязыковая совместимость
DynamicLinkerFactory можно настроить с помощью загрузчика классов class loader. Он будет пытаться создать все классы GuardingDynamicLinkerExporter, видимые этому загрузчику классов, и объединит предоставляемые ими привязки в создаваемый DynamicLinker. Это позволяет обеспечить межъязыковую совместимость: если у вас есть две среды выполнения языка A и B, развернутые в вашей JVM, и они экспортируют свои привязки через указанный механизм, среда выполнения языка A будет иметь экземпляр языкоспецифичной привязки из B, и наоборот, внутри их DynamicLinker объектов. Это означает, что если объект из среды выполнения языка B передаётся в код из среды выполнения языка A, привязка из B получит возможность связать сайт вызова в A, когда она встретит объект из B.- Граф модулей:
- С тех пор:
- 9
Пакеты
| Пакет | Описание |
|---|---|
| jdk.dynalink | Содержит интерфейсы и классы, используемые для связывания invokedynamic места вызова. |
| jdk.dynalink.beans | Содержит линкер для обычных Java-объектов. |
| jdk.dynalink.linker | Содержит интерфейсы и классы, необходимые средам выполнения языков для реализации собственных языковых моделей объектов и преобразований типов. |
| jdk.dynalink.linker.support | Содержит классы, которые упрощают реализацию собственных языковых моделей объектов и преобразований типов для сред выполнения языков, предоставляя базовые реализации некоторых классов, а также различные утилиты. |
| jdk.dynalink.support | Содержит классы, которые упрощают использование Dynalink, предоставляя базовые реализации некоторых классов и различные утилиты. |
Сервисы
| Тип | Описание |
|---|---|
| GuardingDynamicLinkerExporter | Класс, выполняющий роль поставщика защищенных динамических линков, которые могут быть автоматически загружены другими средами выполнения языков. |
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/jdk.dynalink/module-summary.html