Spec-Zone .ru
спецификации, руководства, описания, API
|
Содержание | Предыдущий | Следующий | Индекс | Спецификация Виртуальной машины JavaTM |
ГЛАВА 3
Эта книга определяет абстрактную машину. Это не документирует определенной реализации виртуальной машины Java, включая Sun Microsystems.
Чтобы реализовать виртуальную машину Java правильно, Вы должны только быть в состоянии читать class
формат файла и правильно выполняет операции, определенные там. Детали реализации, которые не являются частью спецификации виртуальной машины Java, излишне ограничили бы творческий потенциал конструкторов. Например, расположение памяти областей данных времени выполнения, алгоритм сборки "мусора", используемый, и любая внутренняя оптимизация инструкций виртуальной машины Java (например, преобразовывая их в машинный код), оставляют усмотрению конструктора.
class
Формат файлаclass
формат файла. class
формат файла точно определяет представление класса или интерфейса, включая детали, такие как порядок байтов, который мог бы считаться само собой разумеющимся в специфичном для платформы формате объектных файлов.
Глава 4," class
Формат файла", покрытия class
формат файла подробно.
Виртуальная машина Java ожидает, что почти вся проверка типа делается до времени выполнения, обычно компилятором, и не должна быть сделана виртуальной машиной Java непосредственно. Значения типов примитивов не должны быть тегированы или иначе быть inspectable, чтобы определить их типы во время выполнения, или быть отличенными от значений ссылочных типов. Вместо этого набор команд виртуальной машины Java отличает свои инструкции использования типов операнда, предназначенные, чтобы работать на значениях определенных типов. Например, iadd, ladd, fadd, и dadd являются всеми инструкциями виртуальной машины Java, которые добавляют два числовых значения и приводят к числовым результатам, но каждый специализируется для ее типа операнда: int
, long
, float
, и double
, соответственно. Для сводки поддержки типа в наборе команд виртуальной машины Java см. §3.11.1.
Виртуальная машина Java содержит явную поддержку объектов. Объект является или динамически выделенным экземпляром класса или массивом. У ссылки на объект, как полагают, есть тип виртуальной машины Java reference
. Значения типа reference
может считаться указателями на объекты. Больше чем одна ссылка на объект может существовать. На объектах всегда управляют, передаются, и тестируются через значения типа reference
.
boolean
введите (§3.3.4), 1 и returnAddress
введите (§3.3.3). Числовые типы состоят из целочисленных типов (§3.3.1) и типы с плавающей точкой (§3.3.2). Целочисленные типы: byte
, чьи значения являются 8-разрядными two's-дополнительными целыми числами со знаком
short
, чьи значения являются 16-разрядными two's-дополнительными целыми числами со знаком
int
, чьи значения являются 32-разрядными two's-дополнительными целыми числами со знаком
long
, чьи значения являются 64-разрядными two's-дополнительными целыми числами со знаком
char
, чьи значения являются 16-разрядными целыми без знака, представляющими символы Unicode (§2.1)
float
, чьи значения являются элементами набора значений плавающего или, где поддерживающийся, набор значений "расширенная экспонента плавающая"
double
, чьи значения являются элементами двойного набора значений или, где поддерживающийся, набор значений "двойная расширенная экспонента" boolean
тип кодирует значения истинности true
и false
.
Значения returnAddress
тип является указателями на коды операций инструкций виртуальной машины Java. Из типов примитивов только returnAddress
тип непосредственно не связывается с типом языка программирования Java.
byte
, от-128 до 127 (-27 к 27-1), включительно
short
, от-32768 до 32767 (-215 к 215-1), включительно
int
, от-2147483648 до 2147483647 (-231 к 231-1), включительно
long
, от-9223372036854775808 до 9223372036854775807 (-263 к 263-1), включительно
char
, от 0 до 65535 включительно float
и double
, которые концептуально связываются с 32-разрядной одинарной точностью и 64-разрядными значениями формата IEEE 754 двойной точности и операциями как определено в Стандарте IEEE для Двоичной Арифметики С плавающей точкой, Станд. ANSI/IEEE 754-1985 (IEEE, Нью-Йорк). Стандарт IEEE 754 включает не только положительный и числа величины знака минус, но также и положительные и отрицательные нули, положительные и отрицательные бесконечности, и специальное значение Не-числа (после этого сокращенный как "НЭН"). Значение НЭН используется, чтобы представить результат определенных недопустимых операций, таких как делящийся нуль нулем.
Каждая реализация виртуальной машины Java обязана поддерживать два стандартных набора значений с плавающей точкой, названных набором значений плавающим и двойным набором значений. Кроме того, реализация виртуальной машины Java может, по своему выбору, поддерживать или или обе из двух расширенных экспонент наборы значений с плавающей точкой, названные набором значений "расширенная экспонента плавающая" и набор значений "двойная расширенная экспонента". Эти наборы значений расширенной экспоненты, при определенных обстоятельствах, могут использоваться вместо стандартных наборов значений, чтобы представить значения плавания типа или двойной.
Конечные ненулевые значения любого набора значений с плавающей точкой могут все быть выражены в форме s · м. · 2 (e-N + 1), где s +1 или-1, м. является положительным целым числом меньше чем 2N, и e является целым числом между Эмином = - (2 K-1-2) и Emax = 2 K-1-1, включительно, и где N и K являются параметрами, которые зависят от набора значений. Некоторые значения могут быть представлены в этой форме больше чем одним способом; например, если значение v в наборе значений могло бы быть представлено в этой форме, используя определенные значения для s, м., и e, затем если бы это произошло, которым м. был даже, и e составляли меньше чем 2 k-1, то можно было разделить на два м. и увеличить e на 1, чтобы произвести второе представление для того же самого значения v. Представление в этой форме вызывают нормализованное если м. 2N-1; иначе представление, как говорят, денормализовывается. Если значение в наборе значений не может быть представлено таким способом, которым м. 2N-1, то значение, как говорят, является денормализованным значением, потому что у этого нет никакого нормализованного представления.
Ограничения на параметры N и K (и на полученные параметры Эмин и Эмэкс) для этих требуемых двух и два дополнительных набора значений с плавающей точкой получаются в итоге в Таблице 3.1.
Параметр | плавание | расширенный до плавания - экспонента | двойной | двойным образом расширенный - экспонента |
---|---|---|---|---|
N | 24 | 24 | 53 | 53 |
K | 8 | 11 | 11 | 15 |
Emax | +127 | +1023 | +1023 | +16383 |
Эмин | -126 | -1022 | -1022 | -16382 |
Где один или оба набора значений расширенной экспоненты поддерживаются реализацией, затем для каждого поддерживаемого набора значений расширенной экспоненты есть определенный зависящий от реализации постоянный K, значение которого ограничивается Таблицей 3.1; это значение K поочередно диктует значения для Эмина и Эмэкса.
Каждый из этих четырех наборов значений включает не только конечные ненулевые значения, которые приписываются ему выше, но также и пять значений положительный нуль, отрицательный нуль, положительная бесконечность, отрицательная бесконечность, и НЭН.
Отметьте, что ограничения в Таблице 3.1 разрабатываются так, чтобы каждый элемент набора значений плавающего был обязательно также элементом набора значений "расширенная экспонента плавающая", двойной набор значений, и набор значений "двойная расширенная экспонента". Аналогично, каждый элемент двойного набора значений является обязательно также элементом набора значений "двойная расширенная экспонента". Каждый набор значений расширенной экспоненты имеет больший диапазон значений экспоненты чем соответствующий стандартный набор значений, но не имеет большей точности.
Элементы набора значений плавающего являются точно значениями, которые могут быть представлены, используя единственный формат с плавающей точкой, определенный в стандарте IEEE 754, за исключением того, что есть только одно значение НЭН (IEEE 754 определяет 224 - 2 отличных значения НЭН). Элементы двойного набора значений являются точно значениями, которые могут быть представлены, используя двойной формат с плавающей точкой, определенный в стандарте IEEE 754, за исключением того, что есть только одно значение НЭН (IEEE 754 определяет 253 - 2 отличных значения НЭН). Отметьте, однако, что элементы "плавания, расширенная экспонента" и наборы значений "двойная расширенная экспонента", определенная здесь, не соответствуют значениям, которые можно быть представлена, используя IEEE 754 единственные расширенные и двойные расширенные форматы, соответственно. Эта спецификация не передает под мандат определенное представление для значений наборов значений с плавающей точкой кроме того, где значения с плавающей точкой должны быть представлены в class
формат файла (§4.4.4, §4.4.5).
Плавание, "расширенная экспонента плавающая", дважды, и наборы значений "двойная расширенная экспонента" не является типами. Это всегда корректно для реализации виртуальной машины Java, чтобы использовать элемент набора значений плавающего, чтобы представить значение плавания типа; однако, может быть допустимо в определенных контекстах для реализации использовать элемент набора значений "расширенная экспонента плавающая" вместо этого. Точно так же это всегда корректно для реализации, чтобы использовать элемент двойного набора значений, чтобы представить значение двойного типа; однако, может быть допустимо в определенных контекстах для реализации использовать элемент набора значений "двойная расширенная экспонента" вместо этого.
За исключением NaNs, упорядочиваются значения наборов значений с плавающей точкой. Когда расположено от самого маленького до самого большого, они - отрицательная бесконечность, отрицательные конечные значения, положительный и отрицательный нуль, положительные конечные значения, и положительная бесконечность.
Положительный нуль с плавающей точкой и отрицательный нуль с плавающей точкой сравниваются как равный, но есть другие операции, которые могут отличить их; например, деление 1.0
0.0
производит положительную бесконечность, но деление 1.0
-0.0
производит отрицательную бесконечность.
NaNs неупорядочивают, таким образом, у числовых сравнений и тестов для числового равенства есть значение false
если или или оба из их операндов НЭН. В частности у теста для числового равенства значения против себя есть значение false
если и только если значением является НЭН. У теста для количественного неравенства есть значение true
если любым операндом является НЭН.
returnAddress
Введите и ОцениваетreturnAddress
тип используется jsr виртуальной машины Java, мочите, и jsr_w инструкции. Значения returnAddress
тип является указателями на коды операций инструкций виртуальной машины Java. В отличие от числовых типов примитивов, returnAddress
тип не соответствует никакому типу языка программирования Java и не может быть изменен рабочей программой. boolean
Ввестиboolean
введите, это только оказывает очень ограниченную поддержку для этого. Нет никаких инструкций виртуальной машины Java, исключительно выделенных операциям на boolean
значения. Вместо этого выражения в языке программирования Java, которые работают на boolean
значения компилируются, чтобы использовать значения виртуальной машины Java int
тип данных. Виртуальная машина Java действительно непосредственно поддерживает boolean
массивы. Его newarray инструкция включает созданию boolean
массивы. Массивы типа boolean
получаются доступ и изменил использование byte
инструкции массива baload и bastore.2
Виртуальная машина Java кодирует boolean
компоненты массива, используя 1, чтобы представить true
и 0, чтобы представить false
. Где язык программирования Java boolean
значения отображаются компиляторами на значения типа виртуальной машины Java int
, компиляторы должны использовать то же самое кодирование.
reference
типы: типы классов, типы массива, и интерфейсные типы. Их значения являются ссылками на динамически создаваемые экземпляры класса, массивы, или экземпляры класса или массивы, которые реализуют интерфейсы, соответственно. A reference
значение может также быть специальной нулевой ссылкой, ссылкой ни на какой объект, который будет обозначен здесь null
. null
ссылка первоначально не имеет никакого типа времени выполнения, но может быть брошена к любому типу (§2.4). Спецификация виртуальной машины Java не передает под мандат конкретное кодирование значения null
.
pc
Регистрpc
(счетчик программы) регистр. В любой точке каждый поток виртуальной машины Java выполняет код единственного метода, текущий метод (§3.6) для того потока. Если тот метод не native
, pc
регистр содержит адрес инструкции виртуальной машины Java, в настоящий момент выполняемой. Если метод, в настоящий момент выполняемый потоком, native
, значение виртуальной машины Java pc
регистр неопределен. Виртуальная машина Java pc
регистр достаточно широк, чтобы содержать a returnAddress
или собственный указатель на определенной платформе. Спецификация виртуальной машины Java разрешает, чтобы виртуальная машина Java сложила или чтобы быть фиксированного размера или динамически расшириться и сократиться как требуется вычислением. Если стеки виртуальной машины Java имеют фиксированный размер, размер каждого стека виртуальной машины Java может быть выбран независимо, когда тот стек создается. Реализация виртуальной машины Java может предоставить программисту или контролю за работой пользователей свыше начального размера стеков виртуальной машины Java, так же как, в случае динамичного расширения или заключения контракта стеков виртуальной машины Java, управления максимальными и минимальными размерами 4
Следующие исключительные условия связываются со стеками виртуальной машины Java:
StackOverflowError
.
OutOfMemoryError
. "Куча" создается на запуске виртуальной машины. Хранение "кучи" для объектов исправляется автоматической системой управления хранения (известный как сборщик "мусора"); объекты явно никогда не освобождаются. Виртуальная машина Java не принимает определенного типа автоматической системы управления хранения, и метод управления хранением может быть выбран согласно системным требованиям конструктора. "Куча" может иметь фиксированный размер или может быть расширена как требуется вычислением и может быть законтрактована, если большая "куча" становится ненужной. Память для "кучи" не должна быть непрерывной.
Реализация виртуальной машины Java может предоставить программисту или контролю за работой пользователей свыше начального размера "кучи", так же как, если "куча" может быть динамически расширена или законтрактована, управление максимальным и минимальным размером 5 "кучи"
Следующее исключительное условие связывается с "кучей":
OutOfMemoryError
. Область метода создается на запуске виртуальной машины. Хотя областью метода является логически часть "кучи", простые реализации могут хотеть не или собирать "мусор" или уплотнять это. Эта версия спецификации виртуальной машины Java не передает под мандат расположение области метода или политик, используемых, чтобы управлять скомпилированным кодом. Область метода может иметь фиксированный размер или может быть расширена как требуется вычислением и может быть законтрактована, если большая область метода становится ненужной. Память для области метода не должна быть непрерывной.
Реализация виртуальной машины Java может предоставить программисту или контролю за работой пользователей свыше начального размера области метода, так же как, в случае области метода переменного размера, управления максимальным и минимальным размером 6 области метода
Следующее исключительное условие связывается с областью метода:
OutOfMemoryError.
constant_pool
таблица в a class
файл (§4.4). Это содержит несколько видов констант, в пределах от числовых литералов, известных во время компиляции методу и полевым ссылкам, которые должны быть разрешены во время выполнения. Пул константы этапа выполнения служит функции, подобной той из таблицы символов для стандартного языка программирования, хотя это содержит более широкий диапазон данных чем типичная таблица символов. Каждый пул константы этапа выполнения выделяется от области метода виртуальной машины Java (§3.5.4). Пул константы этапа выполнения для класса или интерфейса создается, когда класс или интерфейс создаются (§5.3) виртуальной машиной Java.
Следующее исключительное условие связывается с конструкцией пула константы этапа выполнения для класса или интерфейса:
OutOfMemoryError
. native
методы, методы, записанные на языке кроме языка программирования Java. Собственные стеки метода могут также использоваться реализацией интерпретатора для набора команд виртуальной машины Java на языке, таком как реализации К. Джейва виртуэл макхайна, которые не могут загрузиться native
методы и которые самостоятельно не полагаются на стандартные стеки, не должны предоставить собственные стеки метода. Если предоставлено, собственные стеки метода обычно выделяются на поток, когда каждый поток создается. Спецификация виртуальной машины Java разрешает, чтобы собственный метод сложил или чтобы быть фиксированного размера или динамически расшириться и сократиться как требуется вычислением. Если собственные стеки метода имеют фиксированный размер, размер каждого собственного стека метода может быть выбран независимо, когда тот стек создается. В любом случае реализация виртуальной машины Java может предоставить программисту или контролю за работой пользователей свыше начального размера собственных стеков метода. В случае переменного размера собственные стеки метода это может также сделать доступный элемент управления свыше максимальных и минимальных размеров 7 стека метода
Следующие исключительные условия связываются с собственными стеками метода:
StackOverflowError
.
OutOfMemoryError
. Новый фрейм создается каждый раз, когда метод вызывается. Фрейм уничтожается, когда его вызов метода завершается, является ли то завершение нормальным или резким (это выдает непойманное исключение). Фреймы выделяются от стека виртуальной машины Java (§3.5.2) потока, создающего фрейм. У каждого фрейма есть свой собственный массив локальных переменных (§3.6.1), его собственный стек операнда (§3.6.2), и ссылка на пул константы этапа выполнения (§3.5.5) класса текущего метода.
Размеры массива локальной переменной и стека операнда определяются во время компиляции и предоставляются наряду с кодом для метода, связанного с фреймом (§4.7.3). Таким образом размер структуры данных фрейма зависит только от реализации виртуальной машины Java, и память для этих структур может быть выделена одновременно на вызове метода.
Только один фрейм, фрейм для выполняющегося метода, является активным в любой точке в данном потоке управления. Этот фрейм упоминается как текущий фрейм, и его метод известен как текущий метод. Класс, в котором определяется текущий метод, является текущим классом. Операции на локальных переменных и стеке операнда обычно в отношении текущего фрейма.
Фрейм прекращает быть текущим, если его метод вызывает другой метод или если его метод завершается. Когда метод вызывается, новый фрейм создается и становится текущим, когда управление передает новому методу. По возврату метода текущий фрейм пасует назад результат своего вызова метода, если таковые вообще имеются, к предыдущему фрейму. Текущий фрейм тогда отбрасывается, поскольку предыдущий фрейм становится текущим.
Отметьте, что фрейм, создаваемый потоком, локален для того потока и не может быть сослан никаким другим потоком.
Единственная локальная переменная может содержать значение типа boolean
, byte
, char
, short
, int
, float
, reference
, или returnAddress
. Пара локальных переменных может содержать значение типа long
или double
.
Локальные переменные адресуются, индексируя. Индекс первой локальной переменной является нулем. Целое число, как полагать, быть индексом в массив локальной переменной, если и только если то целое число между нулем и меньше чем размер массива локальной переменной.
Значение типа long
или введите double
занимает две последовательных локальных переменные. Такое значение может только адресоваться, используя меньший индекс. Например, значение типа double
сохраненный в массиве локальной переменной по индексу n фактически занимает локальные переменные с индексами n и n +1; однако, локальная переменная по индексу n +1 не может быть загружена из. Это может быть сохранено в. Однако, выполнение так лишает законной силы содержание локальной переменной n.
Виртуальная машина Java не требует, чтобы n был даже. В интуитивных сроках, значениях типов double
и long
не должен быть 64-разрядное выровненный в массиве локальных переменных. Конструкторы свободны решить соответствующий способ представить такие значения, используя эти две локальных переменные, зарезервированные для значения.
Виртуальная машина Java использует локальные переменные, чтобы передать параметры вызову метода. На вызове метода класса любые параметры передают в последовательных локальных переменных, запускающихся с локальной переменной 0. На вызове метода экземпляра локальная переменная 0 всегда используется, чтобы передать ссылку на объект, на который вызывается метод экземпляра (this
в языке программирования Java). Любые параметры впоследствии передают в последовательных локальных переменных, запускающихся с локальной переменной 1.
Где это является четким контекстом, мы будем иногда обращаться к стеку операнда текущего фрейма как просто стек операнда.
Стек операнда пуст, когда фрейм, который содержит его, создается. Виртуальная машина Java предоставляет инструкции, чтобы загрузить константы или значения от локальных переменных или полей на стек операнда. Другие инструкции виртуальной машины Java берут операнды от стека операнда, работают на них, и продвигают результат назад на стек операнда. Стек операнда также используется, чтобы подготовить параметры, которые передадут к методам и получат результаты метода.
Например, iadd инструкция добавляет два int
значения вместе. Это требует что int
значения, которые будут добавлены быть лучшими двумя значениями стека операнда, продвинутого там предыдущими инструкциями. Оба из int
значения выталкиваются от стека операнда. Они добавляются, и их сумма пододвигается обратно на стек операнда. Подвычисления могут быть вложены на стеке операнда, приводящем к значениям, которые могут использоваться вычислением затрагивания.
Каждая запись на стеке операнда может содержать значение любого типа виртуальной машины Java, включая значение типа long
или введите double
.
На значения от стека операнда нужно управлять способами, соответствующими их типам. Не возможно, например, продвинуть два int
значения и впоследствии обрабатывают их как a long
или продвигать два float
значения и впоследствии добавляют их с iadd инструкцией. Небольшое количество инструкций виртуальной машины Java (инструкции дубликата и подкачка) работает на областях данных времени выполнения, поскольку сырые данные оценивают без отношения их определенным типам; эти инструкции определяются таким способом, которым они не могут использоваться, чтобы изменить или разбить отдельные значения. Эти ограничения на манипулирование стеком операнда осуществляются через class
проверка файла (§4.9).
В любом моменте времени у стека операнда есть связанная глубина, где значение типа long
или double
вносит два модуля глубине, и значение любого другого типа вносит один модуль.
class
код файла для метода обращается к методам, которые будут вызваны и переменные, которые будут получены доступ через символьные ссылки. Динамическое подключение преобразовывает эти символьные ссылки метода в конкретные ссылки метода, загружая классы по мере необходимости, чтобы разрешить пока еще неопределенные символы, и преобразовывает переменные доступы в соответствующие смещения в структурах хранения, связанных с расположением времени выполнения этих переменных. Это позднее связывание методов и переменных производит изменения в других классах, которые метод использует менее вероятно, чтобы повредить этот код.
throw
оператор. Если вызов текущего метода обычно завершается, то значение может быть возвращено к методу вызова. Это происходит, когда вызванный метод выполняет одну из инструкций возврата (§3.11.8), выбор которого должен быть подходящим для типа возвращаемого значения (если любой). Текущий фрейм (§3.6) используется в этом случае, чтобы восстановить состояние invoker, включая его локальные переменные и стек операнда, со счетчиком программы invoker, соответственно постепенно увеличенного, чтобы пропустить мимо инструкции вызова метода. Выполнение тогда обычно продолжается во фрейме метода вызова с возвращенным значением (если любой), продвигал на стек операнда того фрейма.
ACC_STRICT
бит access_flags
элемент method_info
структура (§4.6) определение метода. Метод, для которого устанавливается этот бит, строг FP; иначе, метод не строг FP. Отметьте что это отображение ACC_STRICT
бит подразумевает, что методы в классах, скомпилированных компилятором, который предшествует Java 2 платформы, v1.2, эффективно не строги FP.
Мы будем именовать стек операнда как наличие данного режима с плавающей точкой, когда метод, у вызова которого, создаваемого фрейм, содержащий стек операнда, есть тот режим с плавающей точкой. Точно так же мы будем именовать инструкцию виртуальной машины Java как наличие данного режима с плавающей точкой, когда у метода, содержащего ту инструкцию, будет тот режим с плавающей точкой.
Если набор значений "расширенная экспонента плавающая" поддерживается (§3.3.2), значения типа float
на стеке операнда, который не строг FP, может передвинуться на тот набор значений кроме где запрещено преобразованием набора значений (§3.8.3). Если набор значений "двойная расширенная экспонента" поддерживается (§3.3.2), значения типа double
на стеке операнда, который не строг FP, может передвинуться на тот набор значений кроме где запрещено преобразованием набора значений.
Во всех других контекстах, ли на стеке операнда или в другом месте, и независимо от режима с плавающей точкой, значений с плавающей точкой типа float
и double
май только передвигается на набор значений плавающий и двойной набор значений, соответственно. В частности класс и поля экземпляра, элементы массива, локальные переменные, и параметры метода могут только содержать значения, оттянутые из стандартных наборов значений.
Где преобразование набора значений обозначается, реализации разрешают выполнить одну из следующих операций на значении:
float
и не элемент набора значений плавающего, это отображает значение на самый близкий элемент набора значений плавающего.
double
и не элемент двойного набора значений, это отображает значение на самый близкий элемент двойного набора значений. Кроме того, где преобразование набора значений обозначается требуются, определенные операции:
float
быть продвинутым на стек операнда, который строг FP, передало в качестве параметра, или сохранило в локальную переменную, поле, или элемент массива. Если значение не является элементом набора значений плавающего, оно отображает значение на самый близкий элемент набора значений плавающего.
double
быть продвинутым на стек операнда, который строг FP, передало в качестве параметра, или сохранило в локальную переменную, поле, или элемент массива. Если значение не является элементом двойного набора значений, оно отображает значение на самый близкий элемент двойного набора значений. native
вызов метода; возврат значения типа с плавающей точкой от метода, который не строг FP к методу, который строг FP; или хранение значения типа с плавающей точкой в локальную переменную, поле, или массив в методе, который не строг FP.Не все значения от набора значений расширенной экспоненты могут быть отображены точно на значение в соответствующем стандартном наборе значений. Если отображаемое значение является слишком большим, чтобы быть представленным точно (его экспонента больше чем разрешенное стандартным набором значений), это преобразовывается в (положительный или отрицательный) бесконечность соответствующего типа. Если отображаемое значение является слишком маленьким, чтобы быть представленным точно (его экспонента меньше чем разрешенное стандартным набором значений), это округляется к самому близкому из представимого денормализованного значения или нулю того же самого знака.
Преобразование набора значений сохраняет бесконечности и NaNs и не может изменить знак преобразовываемого значения. Преобразование набора значений не имеет никакого эффекта на значение, которое не имеет типа с плавающей точкой.
специальное имя <init>
. Это имя предоставляется компилятором. Поскольку имя <init>
не допустимый идентификатор, он не может использоваться непосредственно в программе, записанной в языке программирования Java. Методы инициализации экземпляра могут быть вызваны только в пределах виртуальной машины Java invokespecial инструкцией, и они могут быть вызваны только на неинициализированных экземплярах класса. Метод инициализации экземпляра берет права доступа (§2.7.4) конструктора, из которого он был получен. Класс или интерфейс имеют самое большее один класс или интерфейсный метод инициализации и инициализируются (§2.17.4), вызывая тот метод. Метод инициализации класса или интерфейса статичен и не берет параметров. У этого есть специальное имя <clinit>
. Это имя предоставляется компилятором. Поскольку имя <clinit>
не допустимый идентификатор, он не может использоваться непосредственно в программе, записанной в языке программирования Java. Класс и интерфейсные методы инициализации вызываются неявно виртуальной машиной Java; они никогда не вызываются непосредственно ни от какой инструкции виртуальной машины Java, но вызываются только косвенно как часть процесса инициализации класса.
catch
пункт (§2.16.2) находится, который обрабатывает брошенное значение. Если никакой такой пункт не может быть найден, выходы текущего потока.
В случаях, где a finally
пункт (§2.16.2) используется, finally
пункт выполняется во время распространения исключения, выданного от связанного try
блок и любой связались catch
блок, даже если нет catch
пункт, который обрабатывает выданное исключение, может быть найден.
Как реализовано виртуальной машиной Java, каждым catch
или finally
пункт метода представляется обработчиком исключений. Обработчик исключений определяет диапазон смещений в код виртуальной машины Java, реализовывая метод, для которого обработчик исключений является активным, описывает тип исключения, которое обработчик исключений в состоянии обработать, и определяет расположение кода, который должен обработать то исключение. Исключение соответствует обработчик исключений, если смещение инструкции, которая вызвала исключение, находится в диапазоне смещений обработчика исключений, и тип исключения является тем же самым классом как или подкласс класса исключения, которое обрабатывает обработчик исключений. Когда исключение выдается, виртуальная машина Java ищет соответствующий обработчик исключений в текущем методе. Если соответствующий обработчик исключений находится, системные ответвления к коду обработки исключений, определенному соответствующим обработчиком.
Если никакой такой обработчик исключений не находится в текущем методе, текущий вызов метода завершается резко (§3.6.5). На резком завершении отбрасываются стек операнда и локальные переменные текущего вызова метода, и его фрейм выталкивается, восстанавливая фрейм метода вызова. Исключение тогда повторно бросается в контекст фрейма invoker и так далее, продолжая цепочку вызова метода. Если никакой подходящий обработчик исключений не находится прежде, чем вершина цепочки вызова метода достигается, выполнение потока, в котором было выдано исключение, завершается.
Порядок, в котором обработчики исключений метода ищутся соответствие, важен. В пределах a class
файл обработчики исключений для каждого метода хранится в таблице (§4.7.3). Во время выполнения, когда исключение выдается, виртуальная машина Java ищет обработчики исключений текущего метода в порядке, что они появляются в соответствующей таблице обработчиков исключений в class
файл, запускающийся с начала той таблицы. Поскольку try
операторы структурируются, компилятор для языка программирования Java может всегда упорядочивать записи таблицы обработчиков исключений так, что, для любого выданного исключения и любого значения счетчика программы в том методе, первый обработчик исключений, который соответствует выданное исключение, соответствует самому внутреннему соответствию catch
или finally
пункт.
Отметьте, что виртуальная машина Java не осуществляет вложение или любое упорядочивание записей таблицы исключений метода (§4.9.5). Семантика обработки исключений языка программирования Java реализуется только через сотрудничество с компилятором. Когда class
файлы сгенерированы некоторыми другими средствами, определенная поисковая процедура гарантирует, что все виртуальные машины Java будут последовательно вести себя.
Больше информации о реализации catch
и finally
пункты даются в Главе 7, "Компилируя для виртуальной машины Java."
Игнорируя исключения, внутренний цикл интерпретатора виртуальной машины Java эффективно
Число и размер операндов определяются кодом операции. Если операнд составляет больше чем один байт в размере, то это сохранено в байте старшего разряда порядка с обратным порядком байтов сначала. Например, 16-разрядный индекс без знака в локальные переменные сохранен как два байта без знака, byte1 и byte2, так, что его значениеdo { fetch an opcode; if (operands) fetch operands; execute the action for the opcode; } while (there is more to do);
(byte1 << 8) |
byte2
Поток команд байт-кода только однобайтовый выровненный. Эти два исключения являются tableswitch и lookupswitch инструкциями, которые дополняются, чтобы вызвать внутреннее выравнивание некоторых из их операндов на 4-байтовых границах. Решение ограничить код операции виртуальной машины Java байтом и воздержаться от выравнивания данных в пределах скомпилированного кода отражает сознательное смещение в пользу компактности, возможно за счет некоторой производительности в наивных реализациях. Однобайтовый код операции также ограничивает размер набора команд. Не принятие выравнивания данных означает, что непосредственные данные, больше чем байт, должны быть созданы из байтов во время выполнения на многих машинах.
int
, на стек операнда. fload инструкция делает то же самое с a float
значение. Эти две инструкции могут иметь идентичные реализации, но иметь отличные коды операций. Для большинства введенных инструкций тип инструкции представляется явно в мнемосхеме кода операции буквой: я для int
работа, l для long
, s для short
, b для byte
, c для char
, f для float
, d для double
, и для reference
. У некоторых инструкций, для которых тип однозначен, нет буквы типа в их мнемосхеме. Например, arraylength всегда работает на объекте, который является массивом. Некоторые инструкции, такие как goto, безусловная передача управления, не работают на введенных операндах.
Учитывая однобайтовый размер кода операции виртуальной машины Java, кодирование типов в коды операций оказывает давление на проект его набора команд. Если бы каждая введенная инструкция, поддерживаемая все типы данных времени выполнения виртуальной машины Java, было бы больше инструкций, чем можно было представить в байте. Вместо этого набор команд виртуальной машины Java обеспечивает уменьшенный уровень поддержки типа определенных операций. Другими словами набор команд является преднамеренно не ортогональным. Отдельные инструкции могут использоваться, чтобы преобразовать между неподдерживаемыми и поддерживаемыми типами данных по мере необходимости.
Таблица 3.2 суммирует поддержку типа в наборе команд виртуальной машины Java. Конкретная инструкция, с информацией о типе, создается, заменяя T в шаблоне инструкции в столбце кода операции буквой в столбце типа. Если столбец типа для некоторого шаблона инструкции и типа является пробелом, то никакая инструкция не существует, поддерживая тот тип работы. Например, есть инструкция загрузки для типа int
, iload, но нет никакой инструкции загрузки для типа byte
.
Отметьте, что у большинства инструкций в Таблице 3.2 нет форм для целочисленных типов byte
, char
, и short
. Ни у одного нет форм для boolean
ввести. Компиляторы кодируют загрузки литеральных значений типов byte
и short
использование инструкций виртуальной машины Java, которые подписываются - расширяет те значения до значений типа int
во время компиляции или время выполнения. Загрузки литеральных значений типов boolean
и char
кодируются, используя инструкции, которые обнуляют - расширяют литерал до значения типа int
во время компиляции или время выполнения. Аналогично, загрузки из массивов значений типа boolean
, byte
, short
, и char
кодируются, используя инструкции виртуальной машины Java, которые подписываются - расширяют или обнуляют - расширяют значения до значений типа int
. Таким образом, большинство операций на значениях фактических типов boolean
, byte
, char
, и short
правильно выполняются инструкциями, работающими на значениях вычислительного типа int
.
Отображение между виртуальной машиной Java фактические типы и виртуальной машиной Java вычислительные типы получается в итоге Таблицей 3.3.
Определенные инструкции виртуальной машины Java те, которые появляются и подкачка, работают на стеке операнда без отношения, чтобы ввести; однако, такие инструкции ограничиваются использовать только на значениях определенных категорий вычислительных типов, также данных в Таблице 3.3.
Остаток от этой главы суммирует набор команд виртуальной машины Java.
Мнемоники команд, показанные выше с запаздывающими буквами между угловыми скобками (например, iload _ <n>), обозначают семейства инструкций (с элементами iload_0, iload_1, iload_2, и iload_3 в случае iload _ <n>). Такие семейства инструкций являются специализациями дополнительной универсальной инструкции (iload), который берет один операнд. Для специализированных инструкций операнд неявен и не должен быть сохранен или выбран. Семантика является иначе тем же самым (iload_0, означает ту же самую вещь как iload с операндом 0). Буква между угловыми скобками определяет тип неявного операнда для того семейства инструкций: для <n>, неотрицательного целого числа; для <i>, int
; для <l>, a long
; для <f>, a float
; и для <d>, a double
. Формы для типа int
используются во многих случаях, чтобы выполнить операции на значениях типа byte
, char
, и short
(§3.11.1).
Эта нотация для семейств инструкции используется всюду по Спецификации Виртуальной машины JavaTM.
byte
, short
, и char
типы (§3.11.1), или для значений boolean
введите; те операции обрабатываются инструкциями, работающими на типе int
. Целочисленные и инструкции с плавающей точкой также отличаются по их поведению на переполнении и делятся на нуль. Арифметические инструкции следующие:
Виртуальная машина Java не указывает на переполнение во время операций на целочисленных типах данных. Единственные целочисленные операции, которые могут выдать исключение, являются целочисленными инструкциями дележа (idiv и ldiv) и целочисленными инструкциями остатка (irem и lrem), которые бросают ArithmeticException
если делитель является нулем.
Операции виртуальной машины Java на числах с плавающей точкой ведут себя как определено в IEEE 754. В частности виртуальная машина Java требует полной поддержки IEEE 754 денормализованные числа с плавающей точкой и постепенная потеря значимости, которые облегчают доказывать требуемые свойства определенных числовых алгоритмов.
Виртуальная машина Java требует, чтобы арифметика с плавающей точкой вела себя как будто каждый оператор с плавающей точкой, округленный ее результат с плавающей точкой к точности результата. Неточные результаты должны быть округлены к представимому значению, самому близкому к бесконечно точному результату; если два самых близких представимых значения одинаково рядом, тот, имеющий младший значащий бит нуля, выбирается. Это - значение по умолчанию стандарта IEEE 754 округление режима, известного как вокруг самому близкому режиму.
Виртуальная машина Java использует IEEE 754 вокруг к нулевому режиму, преобразовывая значение с плавающей точкой в целое число. Это приводит к числу, являющемуся усеченным; отбрасываются любые биты мантиссы, которые представляют дробную часть значения операнда. Вокруг к нулевому режиму выбирает как его результат значение типа, самое близкое к, но не больше в величине чем, бесконечно точный результат.
Операторы виртуальной машины Java с плавающей точкой не бросают исключения на этапе выполнения (чтобы не быть перепутанными с IEEE 754 исключения с плавающей точкой). Работа, которая переполнения производят бесконечность со знаком, работа, которая потери значимости производят денормализованное значение или нуль со знаком, и работа, у которой нет никакого математически определенного результата, производит НЭН. Все числовые операции с НЭН как операнд производят НЭН в результате.
Сравнения на значениях типа long
(lcmp) выполняют сравнение со знаком. Сравнения на значениях типов с плавающей точкой (dcmpg, dcmpl, fcmpg, fcmpl) выполняются, используя IEEE 754 несигнальные сравнения.
Виртуальная машина Java непосредственно поддерживает следующие расширяющиеся числовые преобразования:
int
к long
, float
, или double
long
к float
или double
float
к double
int
оцените a double
. Расширяющиеся числовые преобразования не теряют информацию о полной величине числового значения. Действительно, преобразования, расширяющиеся от int
к long
и int
к double
не теряйте информацию вообще; числовое значение сохраняется точно. Преобразования, расширяющиеся от float
к double
это строго FP (§3.8.2), также сохраняют числовое значение точно; однако, такие преобразования, которые не строги FP, могут потерять информацию о полной величине преобразованного значения.
Преобразование int
или a long
значение к float
, или a long
значение к double
, может потерять точность, то есть, может потерять некоторые из младших значащих битов значения; получающееся значение с плавающей точкой является правильно округленной версией целочисленного значения, используя IEEE 754 вокруг для самого близкого режима.
Расширяющееся числовое преобразование int
к a long
просто знак - расширяет two's-дополнительное представление int
значение, чтобы заполнить более широкий формат. Расширяющееся числовое преобразование a char
к нулю целочисленного типа - расширяет представление char
значение, чтобы заполнить более широкий формат.
Несмотря на то, что потеря точности может произойти, расширяя числовые преобразования никогда не заставляет виртуальную машину Java бросать исключение на этапе выполнения (чтобы не быть перепутанной с IEEE 754 исключение с плавающей точкой).
Отметьте, что расширяющиеся числовые преобразования не существуют от целочисленных типов byte
, char
, и short
вводить int
. Как отмечено в §3.11.1, значениях типа byte
, char
, и short
внутренне расширяются до типа int
, создание этих неявных преобразований.
Виртуальная машина Java также непосредственно поддерживает следующие сужающиеся числовые преобразования:
int
к byte
, short
, или char
long
к int
float
к int
или long
double
к int
, long
, или float
Сужающееся числовое преобразование int
или long
к целочисленному типу T просто отбрасывает все кроме битов самых низкоуровневых N, где N является числом битов, используемых, чтобы представить тип T. Это может заставить получающееся значение не иметь тот же самый знак как входное значение.
В сужающемся числовом преобразовании значения с плавающей точкой к целочисленному типу T, где T также int
или long
, значение с плавающей точкой преобразовывается следующим образом:
int
или long
0
.
long
и это целочисленное значение может быть представлено как a long
, тогда результат long
значение V.
int
и это целочисленное значение может быть представлено как int
, тогда результат int
значение V.
int
или long
.
int
или long
. double
к float
ведет себя в соответствии с IEEE 754. Результат правильно округляется, используя IEEE 754 вокруг для самого близкого режима. Значение, слишком маленькое, чтобы быть представленным как a float
преобразовывается в положительный или отрицательный нуль типа float
; значение, слишком большое, чтобы быть представленным как a float
преобразовывается в положительную или отрицательную бесконечность. A double
НЭН всегда преобразовывается в a float
НЭН.Несмотря на то, что переполнение, потеря значимости, или потеря точности могут произойти, сужая преобразования среди числовых типов никогда не заставляет виртуальную машину Java бросать исключение на этапе выполнения (чтобы не быть перепутанной с IEEE 754 исключение с плавающей точкой).
static
поля, известные как переменные класса) и поля экземпляров класса (не -static
поля, известные как переменные экземпляра): getfield, putfield, getstatic, putstatic.
int
и reference
типы. У этого также есть отличные команды условного перехода, которые тестируют на нулевую ссылку, и таким образом не обязан определять конкретное значение для null
(§3.4).
Условные переходы на сравнениях между данными типов boolean
, byte
, char
, и short
выполняются, используя int
инструкции сравнения (§3.11.1). Условный переход на сравнении между данными типов long
, float
, или double
инициируется, используя инструкцию, которая сравнивает данные и производит int
результат сравнения (§3.11.3). Последующее int
инструкция сравнения тестирует этот результат и производит условный переход. Из-за его акцента на int
сравнения, виртуальная машина Java обеспечивает богатое дополнение команд условного перехода для типа int
.
Все int
условные инструкции передачи управления выполняют подписанные сравнения.
private
метод, или метод суперкласса.
static
) метод в именованном классе. boolean
, byte
, char
, short
, или int
), lreturn, freturn, dreturn, и areturn. Кроме того, инструкция возврата используется, чтобы возвратиться из методов, которые, как объявляют, были void
, методы инициализации экземпляра, и класс или интерфейсные методы инициализации. finally
finally
ключевое слово использует jsr, jsr_w, и мочите инструкции. См. Раздел 4.9.6, "Исключения и наконец," и Раздел 7.13, "Компилируя наконец."
Синхронизация на уровне метода обрабатывается как часть вызова метода и возврата (см. Раздел 3.11.8, "Вызов метода и Инструкции Возврата").
Синхронизация последовательностей инструкций обычно используется, чтобы закодировать синхронизируемые блоки языка программирования Java. Виртуальная машина Java предоставляет monitorenter и monitorexit инструкции, чтобы поддерживать такие конструкции.
Надлежащая реализация синхронизируемых блоков требует сотрудничества от предназначения компилятора виртуальная машина Java. Компилятор должен гарантировать, что при любом завершении вызова метода monitorexit инструкция будет выполнена для каждой monitorenter инструкции, выполняемой начиная с вызова метода. Это должно иметь место, завершается ли вызов метода обычно (§3.6.4) или резко (§3.6.5).
Компилятор осуществляет надлежащее соединение monitorenter и monitorexit инструкций по резкому завершению вызова метода, генерируя обработчики исключений (§3.10), который будет соответствовать любое исключение и чей связанный код выполняет необходимые monitorexit инструкции (§7.14).
Классы, которые могли бы потребовать специальной поддержки от виртуальной машины Java, включают тех, которые поддерживают:
java.lang.reflect
и класс Class
.
ClassLoader
.
java.security
и другие классы такой как SecurityManage
r.
Thread
.
java.lang.ref
.9
class
формат файла и набор команд. Эти компоненты жизненно важны для аппаратных средств - операционная система - и независимость реализации виртуальной машины Java. Конструктор может предпочесть думать о них как о средстве надежно передать фрагменты программ между узлами каждая реализация Java или Java 2 платформы, а не как проект, который будет сопровождаться точно.
Важно понять, где строка между общедоступным проектом и частной реализацией находится. Реализация виртуальной машины Java должна быть в состоянии читать class
файлы и должны точно реализовать семантику кода виртуальной машины Java там. Один способ сделать это состоит в том, чтобы взять этот документ в качестве спецификации и реализовывать ту спецификацию буквально. Но это является также совершенно выполнимым и требуемым для конструктора, чтобы изменить или оптимизировать реализацию в пределах ограничений этой спецификации. Пока class
формат файла может быть считан, и семантика его кода сохраняются, конструктор может реализовать их семантика всегда. То, что "под капотом", является бизнесом конструктора, пока корректный внешний интерфейс тщательно сохраняется 10
Конструктор может использовать эту гибкость, чтобы адаптировать реализации виртуальной машины Java для высокой производительности, низкое использование памяти, или мобильность. То, что имеет смысл в данной реализации, зависит от целей той реализации. Диапазон опций реализации включает следующее:
boolean
быть типом виртуальной машины Java. Однако, boolean
у значений действительно есть ограниченная поддержка в виртуальной машине Java. Этот второй выпуск разъясняет проблему, обрабатывая boolean
как тип.
2 В выпусках 1.0 и 1.1 JDK Sun, и Java 2 SDK, Standard Edition, v1.2, boolean
массивы в языке программирования Java кодируются как виртуальная машина Java byte
массивы, используя 8 битов на boolean
элемент.
3 В первом выпуске этой спецификации, стек виртуальной машины Java был известен как стек Java.
4 В реализациях Sun виртуальной машины Java в выпусках 1.0.2 и 1.1 JDK, и Java 2 SDK, Standard Edition, v1.2, стеки виртуальной машины Java являются несмежными и независимо расширяются как требуется вычислением. Те реализации не освобождают память, выделенную для стека виртуальной машины Java, пока связанный поток не завершается. Расширение подвергается пределу размера для любого стека. Предел размера стека виртуальной машины Java может быть установлен для запуска виртуальной машины, используя"-oss
"флаг. Предел размера стека виртуальной машины Java может использоваться, чтобы ограничить потребление памяти или поймать безудержные рекурсии.
Реализации 5 Sun виртуальной машины Java в выпусках 1.0.2 и 1.1 JDK, и Java, 2 SDK, Standard Edition, v1.2, динамически разворачивают "кучу" как требуется вычислением, но никогда не сокращают "кучу". Начальные и максимальные размеры могут быть определены на запуске виртуальной машины, используя"-ms
"и"-mx
"флаги, соответственно.
Реализация 6 Sun виртуальной машины Java в выпуске 1.0.2 JDK динамически разворачивает область метода как требуется вычислением, но никогда не сокращает область метода. Реализации виртуальной машины Java в выпуске 1.1 JDK Sun и Java 2 SDK, Standard Edition, v1.2 собирают "мусор" область метода. Ни в том, ни в другом случае контроль за работой пользователей по начальной букве, минимуму, или максимальному размеру обеспеченной области метода.
Реализации 7 Sun виртуальной машины Java в выпусках 1.0.2 и 1.1 JDK, и Java 2 SDK, Standard Edition, v1.2, выделяют фиксированный размер собственные стеки метода единственного размера. Размер собственных стеков метода может быть установлен на запуске виртуальной машины, используя"-ss
"флаг. Собственный предел размера стека метода может использоваться, чтобы ограничить потребление памяти или поймать безудержные рекурсии в native
методы. Реализации Sun не проверяют на собственное переполнение стека метода.
8 В некоторых из реализаций Sun виртуальной машины Java, ссылка на экземпляр класса является указателем на дескриптор, который является самостоятельно парой указателей: один к таблице, содержащей методы объекта и указателя на Class
объект, который представляет тип объекта, и другой к памяти, выделенной от "кучи" для объектных данных.
9 Слабых ссылок были представлены в Java 2 платформы, v1.2.
10 есть некоторые исключения: отладчики, профилировщики, и своевременные генераторы кода могут каждый потребовать доступа к элементам виртуальной машины Java, которые, как обычно полагают, являются "под капотом." Где необходимо Sun работает с другими конструкторами виртуальной машины Java и поставщиками инструментов, чтобы разработать общие интерфейсы к виртуальной машине Java для использования такими инструментами, и продвинуть те интерфейсы через отрасль. Информация о публично доступных низкоуровневых интерфейсах к виртуальной машине Java будет сделана доступной в http://java.sun.com
.
Содержание | Предыдущий | Следующий | Индекс
Спецификация Виртуальной машины JavaTM
Авторское право © Sun Microsystems, Inc 1999 года. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к jvm@java.sun.com