Spec-Zone .ru
спецификации, руководства, описания, API
|
Следующие темы затрагиваются:
Java платформа SE включает разработке приложений со следующими функциями:
Java платформа SE также оказывает устойчивую поддержку относительно следующих областей (и больше):
JVM HotSpot Oracle также предлагает следующие инструменты и функции:
Java SE 7 языков не-Java включений платформы, чтобы использовать инфраструктуру и потенциальную оптимизацию производительности JVM. Ключевой механизм invokedynamic
инструкция, которая упрощает реализацию компиляторов и систем времени выполнения для динамически типизированных языков на JVM.
Язык программирования со статическим контролем типов, если он выполняет тип, проверяющий во время компиляции. Проверка типа является процессом проверки, что программа безопасна с точки зрения типов. Программа безопасна с точки зрения типов, если параметрами всех ее операций является корректный тип.
Java является статически типизированным языком. Вся введенная информация для класса и переменных экземпляра, параметров метода, возвращаемых значений, и других переменных доступна, когда программа компилируется. Компилятор для языка программирования Java использует эту информацию о типе, чтобы произвести байт-код со строгим контролем типов, который может тогда быть эффективно выполнен JVM во время выполнения.
Следующий пример Привет Мировой программы демонстрирует статический контроль типов. Типы показывают полужирным.
import java.util.Date; public class HelloWorld { public static void main(String[] argv) { String hello = "Hello "; Date currDate = new Date(); for (String a : argv) { System.out.println(hello + a); System.out.println("Today's date is: " + currDate); } } }
Язык программирования с динамическим контролем типов, если он выполняет проверку типа во время выполнения. JavaScript и Ruby являются примерами динамически типизированных языков. Эти языки проверяют во время выполнения, а не во время компиляции, который оценивает в приложении, соответствуют ожидаемым типам. Эти языки обычно не имеют информации о типе в наличии во время компиляции. Тип объекта может быть определен только во время выполнения. Следовательно, в прошлом было трудно эффективно реализовать их на JVM.
Следующее является примером Привет Мировой программы, записанной в языке программирования Ruby:
#!/usr/bin/env ruby require 'date' hello = "Hello " currDate = DateTime.now ARGV.each do|a| puts hello + a puts "Date and time: " + currDate.to_s end
Отметьте, что каждое имя представляется без описания типа. Кроме того, основная программа не располагается в типе держателя (класс Java HelloWorld
. Ruby, эквивалентный из Java for
цикл в динамическом типе переменной ARGV
. Тело цикла содержится в блоке, названном закрытием, типичной функцией на динамических языках.
Язык программирования, что строгий контроль типов функций определяет ограничения на типы значений, предоставленных его операциям. Если машинный язык реализует строгий контроль типов, он предотвращает выполнение работы, если у ее параметров есть неправильный тип. Наоборот, язык, который слабый контроль типов функций неявно преобразовал бы (или бросил бы) параметры работы, если у тех параметров есть неправильные или несовместимые типы.
Языки программирования со статическим контролем типов могут использовать строгий контроль типов или слабый контроль типов. Точно так же динамически типизированные языки могут также применить строгий контроль типов или слабый контроль типов. Например, язык программирования Ruby с динамическим контролем типов и со строгим контролем типов. Как только переменная была инициализирована со значением некоторого типа, язык программирования Ruby не будет неявно преобразовывать переменную в другой тип данных. Язык программирования Ruby не позволил бы следующее:
a = "40" b = a + 2
В этом примере язык программирования Ruby не будет неявно бросать номер 2, у которого есть a Fixnum
введите к строке.
Рассмотрите следующий метод с динамическим контролем типов, addtwo
, это добавляет любые два числа (который может иметь любой числовой тип), и возвращает сумму:
def addtwo(a, b) a + b; end
Предположите, что Ваша организация реализует компилятор и систему времени выполнения для языка программирования в который метод addtwo
пишется. На языке со строгим контролем типов, введенный ли статически или динамически, поведение +
(оператор сложения), зависит от типов операндов. Компилятор для статически типизированного языка выбирает который реализация +
соответствующее основанный на статических типах a
и b
. Например, компилятор Java реализует +
с iadd
Инструкция JVM, если типы a
и b
int
. Оператор сложения будет скомпилирован в вызов метода потому что JVM iadd
инструкция требует, чтобы типы операнда были статически известны.
Напротив, компилятор для динамически типизированного языка должен задержать выбор до времени выполнения. Оператор a + b
компилируется как вызов метода +(a, b)
, где +
имя метода. (Отметьте названный метод +
разрешается в JVM, но не в языке программирования Java.) Предполагают тогда, что система времени выполнения для динамически типизированного языка в состоянии идентифицировать это a
и b
переменные целочисленного типа. Система времени выполнения предпочла бы вызывать реализацию +
это специализируется для целочисленных типов, а не произвольных объектных типов.
Проблема компиляции динамически типизированных языков состоит в том, как реализовать систему времени выполнения, которая может выбрать самую соответствующую реализацию метода или функции — после того, как программа была скомпилирована. Обработка всех переменных как объекты Object
тип не работал бы эффективно; Object
класс не содержит названный метод +
.
Java SE 7 представляет invokedynamic
инструкция, которая позволяет системе времени выполнения настроить редактирование между сайтом вызова и реализацией метода. В этом примере, invokedynamic
сайт вызова +
. invokedynamic
сайт вызова соединяется с методом посредством метода начальной загрузки, который является методом, определенным компилятором для динамически типизированного языка, однажды который вызывает JVM, чтобы соединить сайт. Принятие компилятора, испускаемого invokedynamic
инструкция, которая вызывает +
, и предполагая, что система времени выполнения знает о методе adder(Integer,Integer)
, время выполнения может соединиться invokedynamic
вызовите сайт к adder
метод следующим образом:
class IntegerOps { public static Integer adder(Integer x, Integer y) { return x + y; } }
import java.util.*; import java.lang.invoke.*; import static java.lang.invoke.MethodType.*; import static java.lang.invoke.MethodHandles.*; class Example { public static CallSite mybsm( MethodHandles.Lookup callerClass, String dynMethodName, MethodType dynMethodType) throws Throwable { MethodHandle mh = callerClass.findStatic( Example.class, "IntegerOps.adder", MethodType.methodType(Integer.class, Integer.class, Integer.class)); if (!dynMethodType.equals(mh.type())) { mh = mh.asType(dynMethodType); } return new ConstantCallSite(mh); } }
В этом примере, IntegerOps
класс принадлежит библиотеке, которая сопровождает систему времени выполнения динамического языка.
Метод Example.mybsm
метод начальной загрузки, который соединяется invokedynamic
вызовите сайт к adder
метод.
Объект callerClass
объект поиска, который является фабрикой для того, чтобы создать дескрипторы метода.
Метод MethodHandles.Lookup.findStatic
(вызванный от callerClass
объект поиска), создает статический дескриптор метода для метода adder
.
Отметьте: Этот метод начальной загрузки соединяется invokedynamic
вызовите сайт только к коду, определенному в adder
метод, и это предполагает что параметры, данные invokedynamic
сайт вызова будет Integer
объекты. Метод начальной загрузки требует, чтобы дополнительный код должным образом соединился invokedynamic
вызовите сайты к соответствующему коду, чтобы выполниться если параметры метода начальной загрузки (в этом примере, callerClass
, dynMethodName
, и dynMethodType
) измениться.
Классы java.lang.invoke.MethodHandles
и java.lang.invoke.MethodHandle
содержите различные методы, которые создают дескрипторы метода, основанные на существующих дескрипторах метода. Этот пример вызывает метод asType
если тип метода дескриптора метода mh
не соответствует тип метода, определенный параметром dynMethodType
. Это позволяет методу начальной загрузки соединиться invokedynamic
вызовите сайты к методам Java, типы метода которых точно не соответствуют.
ConstantCallSite
экземпляр, возвращенный методом начальной загрузки, представляет сайт вызова, который будет связан с отличным invokedynamic
инструкция. Цель для a ConstantCallSite
экземпляр является постоянным и никогда не может изменяться. В этом случае есть только один метод Java, adder
, который является кандидатом на выполнение сайта вызова. Отметьте, что этот метод не должен быть методом Java. Вместо этого если были несколько таких методов, являющихся доступным системе времени выполнения, каждый обрабатывающий различный параметр типы, метод начальной загрузки mybsm
мог динамически выбрать корректный метод, основанный на dynMethodType
параметр.
invokedynamic
инструкция упрощает и потенциально улучшает реализации компиляторов и систем времени выполнения для динамических языков на JVM. invokedynamic
инструкция делает это, разрешая разработчику языка определить пользовательское поведение редактирования. Это противопоставляет с другими инструкциями JVM такой как invokevirtual
, в котором поведение редактирования, определенное для классов Java и интерфейсов, соединяется проводами JVM.
Каждый экземпляр invokedynamic
инструкцию вызывают динамическим сайтом вызова. Динамический сайт вызова находится первоначально в расцепляемом состоянии, что означает, что нет никакого метода, определенного для сайта вызова, чтобы вызвать. Как ранее упомянуто, динамический сайт вызова соединяется с методом посредством метода начальной загрузки. Динамический метод начальной загрузки сайта вызова является методом, определенным компилятором для динамически типизированного языка, однажды который вызывает JVM, чтобы соединить сайт. Объект, возвращенный из метода начальной загрузки постоянно, определяет поведение сайта вызова.
invokedynamic
инструкция содержит постоянный индекс пула (в том же самом формате что касается другого invoke
инструкции). Этот постоянный пул индексирует ссылки a CONSTANT_InvokeDynamic
запись. Эта запись определяет метод начальной загрузки (a CONSTANT_MethodHandle
запись), имя динамически соединенного метода, и типы параметра и тип возврата звонка в динамически соединенный метод.
Следующее является примером invokedynamic
инструкция. В этом примере система времени выполнения соединяет динамический сайт вызова, определенный этим invokedynamic
инструкция (который является +
, оператор сложения) к IntegerOps.adder
метод при использовании метода начальной загрузки Example.mybsm
. Методы adder
и mybsm
определяются в разделе Проблема Компиляции Динамически типизированных языков (разрывы строки были добавлены для ясности):
invokedynamic InvokeDynamic REF_invokeStatic: Example.mybsm: "(Ljava/lang/invoke/MethodHandles/Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType;) Ljava/lang/invoke/CallSite;": +: "(Ljava/lang/Integer; Ljava/lang/Integer;) Ljava/lang/Integer;";
Отметьте: примеры байт-кода в этих разделах используют синтаксис платформы манипулирования и анализа Байт-кода Java
Вызов динамически соединенного метода с invokedynamic
инструкция включает следующие шаги:
invokedynamic
ИнструкцияВо время выполнения, когда JVM сначала встречается invokedynamic
инструкция, это вызывает метод начальной загрузки. Этот метод соединяет имя, определенное invokedynamic
инструкция с кодом, который должен быть выполнен (целевой метод), на который ссылается дескриптор метода. Если JVM выполняет то же самое invokedynamic
инструкция снова, это не вызывает метод начальной загрузки; это автоматически вызывает соединенный дескриптор метода.
Тип возврата метода начальной загрузки должен быть java.lang.invoke.CallSite
. A CallSite
объект представляет соединенное состояние invokedynamic
инструкция и метод обрабатывают, с которым это соединяется.
Метод начальной загрузки берет три или больше параметра:
MethodHandles.Lookup
объект, который является фабрикой для того, чтобы создать дескрипторы метода в контексте invokedynamic
инструкция.String
объект, имя метода упоминается в динамическом сайте вызова.MethodType
объект, разрешенная подпись типа динамического сайта вызова.invokedynamic
инструкция. Эти параметры, оттянутые из постоянного пула, предназначаются, чтобы помочь разработчикам языка безопасно и сжато закодировать дополнительные метаданные, полезные для метода начальной загрузки. В принципе имя и дополнительные параметры избыточны, так как каждому сайту вызова можно было дать его собственный уникальный метод начальной загрузки. Однако, такая практика, вероятно, произведет большие файлы класса и постоянные пулыСм. раздел Проблема Компиляции Динамически типизированных языков для примера метода начальной загрузки.
Как упомянуто ранее, invokedynamic
инструкция содержит ссылку на запись в постоянном пуле с тегом CONSTANT_InvokeDynamic
. Эта запись содержит ссылки на другие записи в постоянном пуле и ссылки на атрибуты. Этот раздел кратко описывает постоянные записи пула, используемые invokedynamic
инструкция. Для получения дополнительной информации см. java.lang.invoke документацию пакета и Спецификацию виртуальной машины Java.
Следующее является выборкой от постоянного пула для класса Example
, который содержит метод начальной загрузки Example.mybsm
это соединяет метод +
с методом Java adder
:
class #159; // #47 Utf8 "adder"; // #83 Utf8 "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;"; // #84 Utf8 "mybsm"; // #87 Utf8 "(Ljava/lang/invoke/MethodHandles/Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;) java/lang/invoke/CallSite;"; // #88 Utf8 "Example"; // #159 Utf8 "+"; // #166 // ... NameAndType #83 #84; // #228 Method #47 #228; // #229 MethodHandle 6b #229; // #230 NameAndType #87 #88; // #231 Method #47 #231; // #232 MethodHandle 6b #232; // #233 NameAndType #166 #84; // #234 Utf8 "BootstrapMethods"; // #235 InvokeDynamic 0s #234; // #236
Постоянная запись пула для invokedynamic
инструкция в этом примере содержит три значения:
CONSTANT_InvokeDynamic
тег0
#234
.Значение 0
обращается к первому спецификатору метода начальной загрузки в массиве спецификаторов, сохраненных в BootstrapMethods
атрибут. Спецификаторы метода начальной загрузки не находятся в постоянном бильярдном столе для пула; они содержатся в этом отдельном массиве спецификаторов. Каждый спецификатор метода начальной загрузки содержит индекс к a CONSTANT_MethodHandle
постоянная запись пула, которая является методом начальной загрузки непосредственно.
Следующее является выборкой от того же самого постоянного пула, который показывает BootstrapMethods
атрибут, который содержит массив спецификаторов метода начальной загрузки:
[3] { // Attributes // ... Attr(#235, 6) { // BootstrapMethods at 0x0F63 [1] { // bootstrap_methods { // bootstrap_method #233; // bootstrap_method_ref [0] { // bootstrap_arguments } // bootstrap_arguments } // bootstrap_method } } // end BootstrapMethods } // Attributes
Постоянная запись пула для метода начальной загрузки mybsm
дескриптор метода содержит три значения:
CONSTANT_MethodHandle
тег6
#232
.Значение 6
подтег REF_invokeStatic
. См. следующий раздел, 3. Используя invokedynamic Инструкцию, для получения дополнительной информации об этом подтеге.
Следующий байт-код использует invokedynamic
инструкция, чтобы вызвать метод начальной загрузки mybsm
, который соединяет динамический сайт вызова (+
, оператор сложения) к методу adder
. Этот пример использует +
метод, чтобы добавить числа 40
и 2
(разрывы строки были вставлены для ясности):
bipush 40; invokestatic Method java/lang/Integer.valueOf:"(I)Ljava/lang/Integer;"; iconst_2; invokestatic Method java/lang/Integer.valueOf:"(I)Ljava/lang/Integer;"; invokedynamic InvokeDynamic REF_invokeStatic: Example.mybsm: "(Ljava/lang/invoke/MethodHandles/Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType;) Ljava/lang/invoke/CallSite;": +: "(Ljava/lang/Integer; Ljava/lang/Integer;) Ljava/lang/Integer;";
Первые четыре инструкции, помещенные целые числа 40
и 2
на стеке и окружает их java.lang.Integer
тип обертки. Пятая инструкция вызывает динамический метод. Эта инструкция обращается к постоянной записи пула с a CONSTANT_InvokeDynamic
тег:
REF_invokeStatic: Example.mybsm: "(Ljava/lang/invoke/MethodHandles/Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType;) Ljava/lang/invoke/CallSite;": +: "(Ljava/lang/Integer; Ljava/lang/Integer;) Ljava/lang/Integer;";
Четыре байта следуют CONSTANT_InvokeDynamic
тег в этой записи:
Первые два байта формируют ссылку на a CONSTANT_MethodHandle
запись, которая ссылается на спецификатор метода начальной загрузки:
REF_invokeStatic: Example.mybsm: "(Ljava/lang/invoke/MethodHandles/Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType;) Ljava/lang/invoke/CallSite;"
Как упомянуто ранее, эта ссылка на спецификатор метода начальной загрузки не находится в постоянном бильярдном столе для пула; это содержится в отдельном массиве, определенном названным атрибутом файла класса BootstrapMethods
. Спецификатор метода начальной загрузки содержит индекс к a CONSTANT_MethodHandle
постоянная запись пула, которая является методом начальной загрузки непосредственно.
Три байта следуют за этим CONSTANT_MethodHandle
постоянная запись пула:
Первый байт является подтегом REF_invokeStatic
. Это означает, что этот метод начальной загрузки создаст дескриптор метода для статического метода; отметьте, что этот метод начальной загрузки соединяет динамический сайт вызова со статическим методом Java adder
.
Следующая двухбайтовая форма a CONSTANT_Methodref
запись, которая представляет метод, для которого должен быть создан дескриптор метода:
Example.mybsm: "(Ljava/lang/invoke/MethodHandles/Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType;) Ljava/lang/invoke/CallSite;"
В этом примере полностью определенное имя метода начальной загрузки Example.mybsm
; типы параметра MethodHandles.Lookup
, String
, и MethodType
; и тип возврата CallSite
.
Следующие два байта формируют ссылку на a CONSTANT_NameAndType
запись:
+: "(Ljava/lang/Integer; Ljava/lang/Integer;) Ljava/lang/Integer;"
Эта постоянная запись пула определяет имя метода (+
), типы параметра (два Integer
экземпляры), и тип возврата динамического сайта вызова (Integer
).
В этом примере динамическому сайту вызова дарят упакованные целочисленные значения, которые точно соответствуют тип возможной цели, adder
метод. Практически, параметр и типы возврата не должны точно соответствовать. Например, invokedynamic
инструкция могла передать или или оба из ее операндов на стеке JVM как примитивный int
значения. Или или оба операнда могли также быть невведены Object
значения. invokedynamic
инструкция могла также получить свой результат как примитив int
значение, или невведенный Object
значение. В любом случае, dynMethodType
параметр mybsm
точно опишет тип метода, требуемый invokedynamic
инструкция.
Независимо, adder
методу, возможно, также дали примитивные или невведенные параметры или возвращаемые значения. Метод начальной загрузки ответственен за составление любого различия между dynMethodType
и тип adder
метод. Как показано в коде, это легко делается с asType
обратитесь к целевому методу.