Spec-Zone.ru › OpenJDK 21

Пакет java.lang.invoke

package java.lang.invoke
Пакет java.lang.invoke предоставляет низкоуровневые примитивы для взаимодействия с виртуальной машиной Java.

Как описано в Спецификации виртуальной машины Java, некоторым типам в этом пакете предоставляется специальное обращение виртуальной машиной:

  • Классы MethodHandle и VarHandle содержат полиморфные по сигнатуре методы, которые могут быть связаны независимо от их описателя типа. Обычно, связывание метода требует точного совпадения описателей типов.
  • Формат байткода JVM поддерживает непосредственные константы классов MethodHandle и MethodType.
  • Инструкция invokedynamic использует константы загрузки MethodHandle для динамического разрешения объектов CallSite для пользовательского поведения вызова методов.
  • Инструкция ldc использует константы загрузки MethodHandle для динамического разрешения пользовательских значений констант.

Динамическое разрешение точек вызова и констант

Следующая низкоуровневая информация обобщает соответствующие части спецификации виртуальной машины Java. Для получения полной информации, пожалуйста, обратитесь к текущей версии этой спецификации.

Динамически вычисляемые точки вызова

Инструкция invokedynamic первоначально находится в несвязанном состоянии. В этом состоянии нет целевого метода для вызова инструкцией.

Прежде чем JVM сможет выполнить инструкцию invokedynamic, инструкция должна быть сначала связана. Связывание выполняется путем вызова метода инициализации, которому предоставляется статическая информация о вызове, и который должен произвести CallSite, задающий поведение вызова.

Каждая инструкция invokedynamic статически определяет свой собственный метод инициализации как ссылку на пул констант. Ссылка на пул констант также определяет имя вызова и описатель типа метода, подобно invokestatic и другим инструкциям вызова.

Динамически вычисляемые константы

Пул констант может содержать константы, помеченные CONSTANT_Dynamic, оснащенные методами инициализации, которые выполняют их разрешение. Такая динамическая константа первоначально находится в состоянии ожидания разрешения. Перед тем, как JVM может использовать динамически вычисляемую константу, она должна быть сначала разрешена. Разрешение динамически вычисляемых констант выполняется путем вызова метода инициализации, которому предоставляется статическая информация о константе, и который должен произвести значение типа константы, объявленного статически.

Каждая динамически вычисляемая константа статически определяет свой собственный метод инициализации как ссылку на пул констант. Ссылка на пул констант также определяет имя константы и описатель типа поля, подобно getstatic и другим инструкциям ссылки на поле. (Грубо говоря, динамически вычисляемая константа относится к динамически вычисляемой точке вызова, как CONSTANT_Fieldref к CONSTANT_Methodref. )

Выполнение методов инициализации

Разрешение динамически вычисляемой точки вызова или константы начинается с разрешения констант из пула констант для следующих элементов:
  • метод инициализации, являющийся CONSTANT_MethodHandle
  • Class или MethodType, полученные из компонента типа описателя CONSTANT_NameAndType
  • статические аргументы, если таковые имеются (обратите внимание, что статические аргументы сами могут быть динамически вычисляемыми константами)

Затем вызывается метод инициализации, как если бы это был вызов MethodHandle.invoke, со следующими аргументами:

  • MethodHandles.Lookup, представляющий собой объект поиска в классе вызывающего объекта, в котором происходит динамически вычисляемая константа или точка вызова
  • String, имя, упомянутое в CONSTANT_NameAndType
  • MethodType или Class, разрешенный описатель типа CONSTANT_NameAndType
  • Class, разрешенный описатель типа константы, если это динамическая константа
  • дополнительные разрешенные статические аргументы, если таковые имеются

Для динамически вычисляемой точки вызова возвращаемое значение должно быть ссылкой на объект CallSite. Тип целевого объекта точки вызова должен точно совпадать с типом, полученным из описателя типа вызова и переданного методу инициализации. Если эти условия не выполнены, выбрасывается BootstrapMethodError. При успехе точка вызова затем становится постоянно связанной с инструкцией invokedynamic.

Для динамически вычисляемой константы первый параметр метода инициализации должен быть приводим к типу MethodHandles.Lookup. Если это условие не выполнено, выбрасывается BootstrapMethodError. При успехе результат метода инициализации кэшируется в качестве разрешенного значения константы.

Если во время выполнения метода инициализации произойдет исключение, скажем, E, то разрешение завершится с ошибкой. E перебрасывается, если тип E равен Error или подклассу, в противном случае выбрасывается BootstrapMethodError, который оборачивает E. Если это произойдет, то та же ошибка будет выброшена при всех последующих попытках выполнить инструкцию invokedynamic или загрузить динамически вычисляемую константу.

Время разрешения

Инструкция invokedynamic связывается непосредственно перед ее первым выполнением. Динамически вычисляемая константа разрешается непосредственно перед первым использованием (путем помещения ее на стек или связывания в качестве параметра метода инициализации). Вызов метода инициализации, реализующий связывание, происходит в потоке, который пытается выполнить первое исполнение или первое использование.

Если таких потоков несколько, метод инициализации может быть вызван в нескольких потоках одновременно. Следовательно, методы инициализации, которые обращаются к глобальным данным приложения, должны принимать обычные меры предосторожности против гонок. В любом случае, каждая инструкция invokedynamic либо несвязана, либо связана с уникальным объектом CallSite.

В приложении, которое требует инструкций invokedynamic с индивидуально изменяемым поведением, их методы инициализации должны генерировать отдельные объекты CallSite, по одному для каждого запроса связывания. В качестве альтернативы приложение может связать один объект CallSite с несколькими инструкциями invokedynamic. В этом случае изменение целевого метода станет видимым в каждой из инструкций.

Если несколько потоков одновременно выполняют метод инициализации для одной динамически вычисляемой точки вызова или константы, JVM должна выбрать один результат метода инициализации и установить его видимым для всех потоков. Любые другие вызовы методов инициализации могут завершиться, но их результаты игнорируются.

Обсуждение: Эти правила не позволяют JVM разделять точки вызова или издавать «беспричинные» вызовы методов инициализации. Каждая инструкция invokedynamic переходит максимум один раз из несвязанного состояния в связанное, непосредственно перед своим первым вызовом. Отменить действие завершенного вызова метода инициализации невозможно.

Типы методов инициализации

Для динамически вычисляемой точки вызова метод инициализации вызывается с параметрами типа MethodHandles.Lookup, String, MethodType, и типов любых статических аргументов; возвращаемый тип — CallSite.

Для динамически вычисляемой константы метод инициализации вызывается с параметрами типа MethodHandles.Lookup, String, Class, и типов любых статических аргументов; возвращаемый тип — тип, представленный Class.

Поскольку MethodHandle.invoke позволяет выполнять адаптации между типом вызываемого метода и типом метода обработчика метода инициализации, в объявлении метода инициализации присутствует гибкость. Для динамически вычисляемой константы первый параметр типа метода инициализации должен быть приводим к типу MethodHandles.Lookup, за исключением этого ограничения, та же степень гибкости распространяется на методы инициализации динамически вычисляемых точек вызова и динамически вычисляемых констант. Примечание: это ограничение допускает в будущем возможность вызова метода инициализации только с параметрами типа статических аргументов, тем самым поддерживая более широкий спектр методов, совместимых со статическими аргументами (например, методы, которые не объявляют или не требуют параметров метаданных поиска, имени и типа).

Например, для динамически вычисляемой точки вызова первым аргументом может быть Object вместо MethodHandles.Lookup, а возвращаемый тип также может быть Object вместо CallSite. (Обратите внимание, что типы и количество аргументов стека ограничивают допустимые типы методов инициализации соответствующими статическими методами и конструкторами.)

Если значение, помещенное на стек, имеет примитивный тип, оно может быть преобразовано в ссылку с помощью преобразования автоупаковки. Если метод инициализации является методом с переменным числом аргументов (его бит модификатора 0x0080 установлен), то некоторые или все указанные здесь аргументы могут быть собраны в заключительный параметр массива. (Это не специальное правило, а скорее полезное следствие взаимодействия между константами CONSTANT_MethodHandle, битом модификатора для методов с переменным числом аргументов и преобразованием asVarargsCollector.)

Учитывая эти правила, вот примеры допустимых объявлений методов инициализации для динамически вычисляемых точек вызова, с различным количеством N дополнительных аргументов. Первая строка (помеченная *) будет работать с любым количеством дополнительных аргументов.

Типы статических аргументов
N Пример метода инициализации
*
  • CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
  • CallSite bootstrap(Object... args)
  • CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)
0
  • CallSite bootstrap(Lookup caller, String name, MethodType type)
  • CallSite bootstrap(Lookup caller, Object... nameAndType)
1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2
  • CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
  • CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
  • CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
END_OF_DOCUMENT_MARKER
Последний пример предполагает, что дополнительные аргументы имеют тип String и Integer (или int) соответственно. Предпоследний пример предполагает, что все дополнительные аргументы имеют тип String. Другие примеры работают со всеми типами дополнительных аргументов. Обратите внимание, что все примеры, кроме второго и третьего, также работают с динамически вычисляемыми константами, если тип возвращаемого значения изменён на совместимый с объявленным типом константы (например, Object, который всегда совместим).

Поскольку динамически вычисляемые константы могут быть предоставлены как статические аргументы методам инициализации, нет ограничений на типы аргументов инициализации. Однако аргументы типа boolean, byte, short, или char не могут быть непосредственно предоставлены записями пула констант CONSTANT_Integer, поскольку преобразования asType не выполняют необходимые сужающие преобразования примитивных типов.

В приведенных выше примерах тип возвращаемого значения всегда CallSite, но это не является обязательным свойством методов инициализации. В случае динамически вычисляемого вызова сайта единственное требование состоит в том, что тип возвращаемого значения метода инициализации должен быть преобразуем (с использованием преобразований asType) в CallSite, что означает, что тип возвращаемого значения метода инициализации может быть Object или ConstantCallSite. В случае динамически разрешенной константы тип возвращаемого значения метода инициализации должен быть преобразуем к типу константы, как представлено в её описателе типа поля. Например, если описатель типа поля динамической константы "C" (char), то тип возвращаемого значения метода инициализации может быть Object, Character, или char, но не int или Integer.

С момента:
1.7
Пакет Описание
java.lang
Предоставляет классы, фундаментальные для разработки языка программирования Java.
Класс Описание
CallSite
CallSite — это держатель переменной MethodHandle, которая называется его target.
ConstantBootstraps
Методы инициализации для динамически вычисляемых констант.
ConstantCallSite
ConstantCallSite — это CallSite с постоянным объектом-мишенью, который никогда нельзя изменить.
LambdaConversionException
LambdaConversionException
LambdaMetafactory
Методы для упрощения создания простых "функциональных объектов", которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, возможно, после адаптации типов и частичного вычисления аргументов.
MethodHandle
Обработчик метода — это типизированная, непосредственно исполняемая ссылка на основную функцию, конструктор, поле или аналогичную низкоуровневую операцию с опциональными преобразованиями аргументов или возвращаемых значений.
MethodHandleInfo
Символьная ссылка, полученная путём разбора непосредственного обработчика методов на составные символические части.
MethodHandleProxies
Этот класс состоит исключительно из статических методов, которые помогают адаптировать обработчики методов к другим типам JVM, таким как интерфейсы.
MethodHandles
Этот класс состоит исключительно из статических методов, которые работают с обработчиками методов или возвращают их.
MethodHandles.Lookup
Объект поиска — это фабрика для создания обработчиков методов, когда создание требует проверки доступа.
MethodHandles.Lookup.ClassOption
Набор опций класса, определяющих, добавляется ли скрытый класс, созданный методом Lookup::defineHiddenClass, динамически в качестве нового члена к набору класса поиска, и/или имеет ли скрытый класс сильную связь с загрузчиком класса, помеченным как определяющий загрузчик.
MethodType
Тип метода представляет аргументы и тип возвращаемого значения, принимаемые и возвращаемые обработчиком метода, или аргументы и тип возвращаемого значения, передаваемые и ожидаемые вызывающим обработчиком метода.
MutableCallSite
MutableCallSite — это CallSite, переменная-цель которого ведет себя как обычное поле.
SerializedLambda
Сериализованная форма лямбда-выражения.
StringConcatException
StringConcatException выбрасывается StringConcatFactory, когда нарушены инварианты связывания.
StringConcatFactory
Методы для упрощения создания методов конкатенации строк, которые могут быть использованы для эффективной конкатенации известного количества аргументов известных типов, возможно, после адаптации типов и частичного вычисления аргументов.
SwitchPoint
SwitchPoint — это объект, который может публиковать переходы состояния в другие потоки.
TypeDescriptor
Сущность с описателем типа.
TypeDescriptor.OfField<F extends TypeDescriptor.OfField<F>>
Сущность с описателем типа поля.
TypeDescriptor.OfMethod<F extends TypeDescriptor.OfField<F>,M extends TypeDescriptor.OfMethod<F,M>>
Сущность с описателем типа метода. Описатели методов, соответствующие JVMS 4.3.3, могут быть описаны номинально через MethodType::describeConstable; в противном случае они не могут быть описаны номинально.
VarHandle
VarHandle — это динамически сильно типизированная ссылка на переменную или параметрически определённую совокупность переменных, включая статические поля, нестатические поля, элементы массивов или компоненты вне-кучевой структуры данных.
VarHandle.AccessMode
Набор режимов доступа, определяющих, как осуществляется доступ к переменной, на которую ссылается VarHandle.
VarHandle.VarHandleDesc
Номинальный описатель для константы VarHandle.
VolatileCallSite
VolatileCallSite — это CallSite, чья мишень ведет себя как переменная volatile.
WrongMethodTypeException
Выбрасывается для указания на попытку вызова обработчика методов с неправильным типом метода.

© 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/java.base/java/lang/invoke/package-summary.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API