Spec-Zone .ru
спецификации, руководства, описания, API
Содержание | Предыдущий | Следующий | ИндексСпецификация Виртуальной машины JavaTM


ГЛАВА 3

Структура виртуальной машины Java


Эта книга определяет абстрактную машину. Это не документирует определенной реализации виртуальной машины Java, включая Sun.

Чтобы реализовать виртуальную машину Java правильно, Вы должны только быть в состоянии считать Java class формат файла и правильно выполняет операции, определенные там. Детали реализации, которые не являются частью спецификации виртуальной машины Java, излишне ограничили бы творческий потенциал конструкторов, и будут только обеспечены, чтобы сделать выставку более четкой. Например, расположение памяти областей данных времени выполнения, алгоритм сборки "мусора", используемый, и любая оптимизация байт-кодов (например, преобразовывая их в машинный код), оставляют усмотрению конструктора.


3.1 Типы данных

Как язык Java, виртуальная машина Java работает на двух видах типов: типы примитивов и ссылочные типы. Есть, соответственно, два вида значений, которые могут быть сохранены в переменных, передали как параметры, возвращенные методами, и работали на: примитивные значения и ссылочные значения.

Виртуальная машина Java ожидает, что почти вся проверка типа делается во время компиляции, не виртуальной машиной Java непосредственно. В частности данные не должны быть тегированы или иначе быть inspectable, чтобы определить типы. Вместо этого набор команд виртуальной машины Java отличает свои инструкции использования типов операнда, предназначенные, чтобы работать на значениях определенных типов. Например, iadd, ladd, fadd, и dadd все инструкции виртуальной машины Java, которые добавляют два числовых значения, но они требуют операндов, типы которых int, long, float, и double, соответственно. Для сводки поддержки типа в наборе команд виртуальной машины Java см. §3.11.1.

Виртуальная машина Java содержит явную поддержку объектов. Объект является или динамически выделенным экземпляром класса или массивом. У ссылки на объект, как полагают, есть тип виртуальной машины Java reference. Значения типа reference может считаться указателями на объекты. Больше чем одна ссылка может существовать к объекту. Хотя виртуальная машина Java выполняет операции на объектах, она никогда не адресует их непосредственно. На объектах всегда управляют, передаются, и тестируются через значения типа reference.


3.2 Типы примитивов и Значения

Примитивные типы данных, поддерживаемые виртуальной машиной Java, являются числовыми типами и returnAddress ввести. Числовые типы состоят из целочисленных типов:

и типы с плавающей точкой:

Значения returnAddress тип является указателями на коды операций инструкций виртуальной машины Java. Только returnAddress тип не является типом языка Java.

3.2.1 Целочисленные типы и Значения

Значения целочисленных типов виртуальной машины Java являются тем же самым как теми для целочисленных типов языка Java (§2.4.1):

3.2.2 Типы с плавающей точкой и Значения

Значения типов с плавающей точкой виртуальной машины Java являются тем же самым как теми для типов с плавающей точкой языка Java (§2.4.1). Типы с плавающей точкой float и double представьте 32-разрядную одинарную точность и значения формата IEEE 754 64-битов двойной точности как определено в Стандарте IEEE для Двоичной Арифметики С плавающей точкой, Станд. ANSI/IEEE 754-1985 (IEEE, Нью-Йорк).

Стандарт IEEE 754 включает не только положительный и числа величины знака минус, но также и положительный, и отрицательный обнуляет, положительные и отрицательные бесконечности, и специальное Не-число (после этого сокращал НЭН), значение, которое используется, чтобы представить результат определенных операций, таких как делящийся нуль нулем. Такие значения существуют для обоих float и double типы.

Конечные ненулевые значения типа float имеют форму s xfa м. xfa 2e, где s +1 или-1, м. является положительным целым числом меньше чем 224, и e является целым числом между-149 и 104, включительно. Самый большой положительный конечный литерал с плавающей точкой типа float 3.40282347e+38F. Самый маленький положительный ненулевой литерал с плавающей точкой типа float 1.40239846e-45F.

Конечные ненулевые значения типа double имеют форму s xfa м. xfa 2e, где s +1 или-1, м. является положительным целым числом меньше чем 253, и e является целым числом между-1075 и 970, включительно. Самый большой положительный конечный литерал с плавающей точкой типа double 1.79769313486231570e+308. Самый маленький положительный ненулевой литерал с плавающей точкой типа double 4.94065645841246544e-324.

Положительный нуль с плавающей точкой и отрицательный нуль с плавающей точкой сравниваются как равный, но есть другие операции, которые могут отличить их; например, деление 1.0 0.0 производит положительную бесконечность, но деление 1.0 -0.0 производит отрицательную бесконечность.

За исключением НЭН, упорядочиваются значения с плавающей точкой. Когда расположено от самого маленького до самого большого, они - отрицательная бесконечность, отрицательные конечные значения, отрицательный нуль, положительный нуль, положительные конечные значения, и положительная бесконечность.

НЭН неупорядочивают, таким образом, у числовых сравнений есть ложь значения, если или или оба из их операндов НЭН. У теста для числового равенства есть ложь значения, если любым операндом является НЭН, и у теста для количественного неравенства есть истина значения, если любым операндом является НЭН. В частности у теста для числового равенства значения против себя есть ложь значения, если и только если значением является НЭН.

IEEE 754 определяет большое количество отличных значений НЭН, но не в состоянии определить, какие значения НЭН производятся в различных ситуациях. Чтобы избежать проблем мобильности, виртуальная машина Java объединяет эти значения НЭН вместе в единственное концептуальное значение НЭН.

3.2.3 returnAddress Введите и Оценивает

returnAddress тип используется jsr виртуальной машины Java, мочите, и jsr_w инструкции. Значения returnAddress тип является указателями на коды операций инструкций виртуальной машины Java. В отличие от числовых типов примитивов, returnAddress тип не соответствует никакому типу данных Java.

3.2.4 Есть Нет boolean Ввести

Хотя Java определяет a boolean введите, виртуальной машине Java не выделяли инструкции операциям на boolean значения. Вместо этого выражение Java, которое работает на boolean значения компилируются в использование int тип данных, чтобы представить boolean переменные.

Хотя у виртуальной машины Java есть поддержка создания массивов типа boolean (см. описание newarray инструкции), у этого нет выделенной поддержки доступа и изменения элементов boolean массивы. Массивы типа boolean получаются доступ и изменил использование byte инструкции 1 массива

Для получения дополнительной информации по обработке boolean значения в виртуальной машине Java, см. Главу 7, "Компилирующую для виртуальной машины Java."


3.3 Ссылочные типы и Значения

Есть три вида reference типы: типы классов, интерфейсные типы, и типы массива, значения которых являются ссылками на динамически создаваемые экземпляры класса, массивы, или экземпляры класса или массивы та реализация интерфейсы. A reference значение может также быть специальной нулевой ссылкой, ссылкой ни на какой объект, который будет обозначен здесь null. null ссылка первоначально не имеет никакого типа времени выполнения, но может быть брошена к любому типу (§2.4).


3.4 Слова

Никакое упоминание не было сделано из требований хранения для значений различных типов виртуальной машины Java, только диапазоны, которые могут взять те значения. Виртуальная машина Java не передает под мандат размер своих типов данных. Вместо этого виртуальная машина Java определяет абстрактное понятие слова, у которого есть специфичный для платформы размер. Слово является достаточно большим, чтобы содержать значение типа byte, char, short, int, float, reference, или returnAddress, или содержать собственный указатель. Два слова являются достаточно большими, чтобы содержать значения больших типов, long и double. Области данных времени выполнения Java все определяются с точки зрения этих абстрактных слов.

Слово обычно является размером указателя на платформе узла. На 32-разрядной платформе слово составляет 32 бита, указатели составляют 32 бита, и longs и doubles естественно приводят два слова в рабочее состояние. Наивная 64-разрядная реализация виртуальной машины Java может потратить впустую половину слова, используемого, чтобы сохранить 32-разрядную данную величину, но может также быть в состоянии сохранить все a long или a double в одном из этих двух слов, выделенных к этому.

Выбор определенного размера слова, хотя специфичный для платформы, делается на уровне реализации, не как часть проекта виртуальной машины Java. Это не видимо вне реализации или кодировать скомпилированный для виртуальной машины Java.

Всюду по этой книге все ссылки на данную величину слова к этому абстрактному понятию слова.


3.5 Области Данных времени выполнения

3.5.1 pc Регистр

Виртуальная машина Java может поддерживать много потоков выполнения сразу (§2.17). У каждого потока виртуальной машины Java есть свое собственное pc (счетчик программы) регистр. В любой точке каждый поток виртуальной машины Java выполняет код единственного метода, текущий метод (§3.6) для того потока. Если тот метод не native, pc регистр содержит адрес инструкции виртуальной машины Java, в настоящий момент выполняемой. Если метод, в настоящий момент выполняемый потоком, native, значение виртуальной машины Java pc регистр неопределен. Виртуальная машина Java pc регистр является одним широким словом, ширина, которая, как гарантируют, будет содержать a returnAddress или собственный указатель на определенной платформе.

3.5.2 Стек Java

У каждого потока виртуальной машины Java (§2.17) есть частный стек Java, создаваемый одновременно как поток. Стек Java хранит фреймы виртуальной машины Java (§3.6). Стек Java эквивалентен стеку стандартного языка, такого как C: это содержит локальные переменные и частичные результаты, и играет роль в вызове метода и возврате. Поскольку стеком никогда не управляют непосредственно кроме продвинуть и вытолкать фреймы, он может фактически быть реализован как "куча", и фреймы Java могут быть выделенной "кучей". Память для стека Java не должна быть непрерывной.

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

Следующие исключительные условия связываются со стеками Java:

В JDK Sun 1.0.2 реализации виртуальной машины Java стеки Java являются несмежными и независимо расширяются как требуется вычислением. Стеки Java не сокращаются, но исправляются, когда их связанный поток завершается или уничтожается. Расширение подвергается пределу размера для любого стека Java. Предел размера стека Java может быть установлен для запуска виртуальной машины, используя"-oss"флаг. Предел размера стека Java может использоваться, чтобы ограничить потребление памяти или поймать безудержные рекурсии.

3.5.3 "Куча"

У виртуальной машины Java есть "куча", которая совместно используется среди всех потоков (§2.17). "Куча" является областью данных времени выполнения, от которой выделяется память для всех экземпляров класса и массивов.

"Куча" Java создается на запуске виртуальной машины. Хранение "кучи" для объектов исправляется автоматической системой управления хранения (обычно сборщик "мусора"); объекты явно никогда не освобождаются. Виртуальная машина Java не принимает определенного типа автоматической системы управления хранения, и метод управления хранением может быть выбран согласно системным требованиям конструктора. "Куча" Java может иметь фиксированный размер, или может быть расширена как требуется вычислением и может быть законтрактована, если большая "куча" становится ненужной. Память для "кучи" Java не должна быть непрерывной.

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

Следующее исключительное условие связывается с "кучей" Java:

JDK Sun 1.0.2 реализации виртуальной машины Java динамически разворачивают свою "кучу" Java как требуется вычислением, но никогда не сокращают ее "кучу". Его начальные и максимальные размеры могут быть определены на запуске виртуальной машины, используя"-ms"и"-mx"флаги, соответственно.

3.5.4 Область метода

У виртуальной машины Java есть область метода, которая совместно используется среди всех потоков (§2.17). Область метода походит на область хранения для скомпилированного кода стандартного языка, или к "текстовому" сегменту в процессе UNIX. Это хранит на - структуры класса, такие как постоянный пул, поле и данные метода, и код для методов и конструкторов, включая специальные методы (§3.8) используемый в классе и инициализации экземпляра и интерфейсной инициализации типа.

Область метода создается на запуске виртуальной машины. Хотя областью метода является логически часть собранной "мусор" "кучи", простые реализации могут хотеть ни собирать "мусор", ни уплотнять это. Эта версия спецификации виртуальной машины Java не передает под мандат расположение области метода или политик, используемых, чтобы управлять скомпилированным кодом. Область метода может иметь фиксированный размер, или может быть расширена как требуется вычислением и может быть законтрактована, если большая область метода становится ненужной. Память для области метода не должна быть непрерывной.

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

Следующее исключительное условие связывается с областью метода:

JDK Sun 1.0.2 реализации виртуальной машины Java динамически разворачивают свой метод, как требуется вычислением, но никогда не сокращается. Никакой контроль за работой пользователей свыше максимального или минимального размера области метода не обеспечивается.

3.5.5 Постоянный Пул

Постоянный пул является представлением времени выполнения на интерфейс или на класс constant_pool таблица в Java class файл (§4.4). Это содержит несколько видов констант, в пределах от числовых литералов, известных во время компиляции методу и полевым ссылкам, которые должны быть разрешены во время выполнения. Постоянный пул служит функции, подобной той из таблицы символов для стандартного языка программирования, хотя это содержит более широкий диапазон данных чем типичная таблица символов.

Каждый постоянный пул выделяется от области метода виртуальной машины Java (§3.5.4). Постоянный пул для класса или интерфейса создается когда Java class файл для класса или интерфейса успешно загружается (§2.16.2) виртуальной машиной Java.

Следующее исключительное условие связывается с созданием постоянного пула для класса или интерфейса:

У постоянного разрешения пула, работа времени выполнения, выполняемая на записях в постоянном пуле, есть свой собственный набор связанных исключений. См. Главу 5 для информации об управлении времени выполнения постоянным пулом.

3.5.6 Собственные Стеки Метода

Реализация виртуальной машины Java может использовать стандартные стеки, в разговорной речи вызванные "C стеки," поддерживать native методы, методы, записанные на языках кроме Java. Собственный стек метода может также использоваться, чтобы реализовать эмулятор для набора команд виртуальной машины Java на языке, таком как К. Имплементэйшнс, которые не поддерживают native методы, и которые самостоятельно не полагаются на стандартные стеки, не должны предоставить собственные стеки метода. Если предоставлено, собственные стеки метода обычно выделяются на на основание потока, когда каждый поток создается.

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

Следующие исключительные условия связываются со стеками Java:

JDK Sun 1.0.2 реализации виртуальной машины Java выделяет фиксированный размер собственные стеки метода единственного размера. Размер его собственных стеков метода может быть установлен на запуске виртуальной машины, используя"-ss"флаг. Собственный предел размера стека метода может использоваться, чтобы ограничить потребление памяти или поймать безудержные рекурсии в native методы.

Реализация Sun в настоящий момент не проверяет на собственное переполнение стека метода.


3.6 Фреймы

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

Новый фрейм создается каждый раз, когда метод Java вызывается. Фрейм уничтожается, когда его метод завершается, является ли то завершение нормальным или аварийным (выдавая исключение). Фреймы выделяются от стека Java (§3.5.2) потока, создающего фрейм. У каждого фрейма есть свой собственный набор локальных переменных (§3.6.1) и его собственный стек операнда (§3.6.2). Место в памяти для этих структур может быть выделено одновременно, так как размеры области локальной переменной и стека операнда известны во время компиляции, и размер структуры данных фрейма зависит только от реализации виртуальной машины Java.

Только один фрейм, фрейм для выполняющегося метода, является активным в любой точке в данном потоке управления. Этот фрейм упоминается как текущий фрейм, и его метод известен как текущий метод. Класс, в котором определяется текущий метод, является текущим классом. Операции на локальных переменных и стеке операнда всегда в отношении текущего фрейма.

Фрейм прекращает быть текущим, если его метод вызывает другой метод или если его метод завершается. Когда метод вызывается, новый фрейм создается и становится текущим, когда управление передает новому методу. По возврату метода текущий фрейм пасует назад результат своего вызова метода, если таковые вообще имеются, к предыдущему фрейму. Текущий фрейм тогда отбрасывается, поскольку предыдущий фрейм становится текущим. Фреймы Виртуальной машины Java могут естественно думаться как выделяемый на стеке с одним стеком на поток Java (§2.17), но они могут также быть выделенной "кучей".

Отметьте, что фрейм, создаваемый потоком, локален для того потока и не может быть непосредственно сослан никаким другим потоком.

3.6.1 Локальные переменные

На каждом вызове метода Java виртуальная машина Java выделяет фрейм Java (§3.6), который содержит массив слов, известных как его локальные переменные. Локальные переменные адресуются, поскольку слово смещает от основы того массива.

Локальные переменные всегда являются одним широким словом. Две локальные переменные резервируются для каждого long или double значение. Эти две локальные переменные адресуются индексом первой из переменных.

Например, локальная переменная с индексом n и содержащий значение типа double фактически занимает эти два слова в индексах n и n+1 локальной переменной. Виртуальная машина Java не требует, чтобы n был даже. (В интуитивных условиях реализации 64-разрядные значения не должны быть 64-разрядные выровненный в массиве локальных переменных.) Конструкторы свободны решить соответствующий способ разделить 64-разрядное значение данных между двумя локальными переменными.

3.6.2 Стеки операнда

На каждом вызове метода Java виртуальная машина Java выделяет фрейм Java (§3.6), который содержит стек операнда. Большинство инструкций виртуальной машины Java принимает значения от стека операнда текущего фрейма, работает на них, и результатах возврата к тому же самому стеку операнда. Стек операнда также используется, чтобы передать параметры методам и получить результаты метода.

Например, iadd инструкция добавляет два int значения вместе. Это требует что int значения, которые будут добавлены быть лучшими двумя словами стека операнда, продвинутого там предыдущими инструкциями. Оба из int значения выталкиваются от стека операнда. Они добавляются, и их сумма пододвигается обратно на стек. Подвычисления могут быть вложены на стеке операнда, приводящем к значениям, которые могут использоваться вычислением затрагивания.

Каждая запись на стеке операнда является одним широким словом. Значения типов long и double продвигаются на стек операнда как два слова. Виртуальная машина Java не требует, чтобы 64-разрядные значения на стеке операнда были 64-разрядное выровненный. Конструкторы свободны решить соответствующий способ разделить 64-разрядное значение данных между двумя словами стека операнда.

На значения от стека операнда нужно управлять способами, соответствующими их типам. Неправильно, например, продвинуть два int значения и затем обрабатывают их как a long, или продвигать два float значения тогда добавляют их с iadd инструкцией. Небольшое количество инструкций виртуальной машины Java (инструкции дубликата и подкачка) работает на областях данных времени выполнения как необработанные значения данной ширины без отношения, чтобы ввести; эти инструкции не должны использоваться, чтобы разбиться или перестроить слова 64-разрядных данных. Эти ограничения на манипулирование стеком операнда осуществляются, в реализации солнца, class верификатор файла (§4.9).

3.6.3 Динамическое подключение

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

Это позднее связывание методов и переменных производит изменения в других классах, которые метод использует менее вероятно, чтобы повредить этот код.

3.6.4 Нормальное Завершение Метода

Вызов метода обычно завершается, если тот вызов не заставляет исключение (§2.15, §3.9) быть брошенным, или непосредственно от виртуальной машины Java или в результате выполнения явного throw оператор. Если вызов текущего метода обычно завершается, то значение может быть возвращено к методу вызова. Это происходит, когда вызванный метод выполняет одну из инструкций возврата (§3.11.8), выбор которого должен быть подходящим для типа возвращаемого значения (если любой).

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

3.6.5 Аварийное Завершение Метода

Вызов метода завершается неправильно, если выполнение инструкции виртуальной машины Java в пределах метода заставляет виртуальную машину Java выдавать исключение (§2.15, §3.9), и то исключение не обрабатывается в пределах метода. Оценка явного throw оператор также заставляет исключение быть брошенным и, если исключение не поймано текущим методом, результатами в аварийном завершении метода. Вызов метода, который не завершает неправильно никогда возвраты значение к его invoker.

3.6.6 Дополнительная информация

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


3.7 Представление Объектов

Виртуальная машина Java не требует никакой определенной внутренней структуры для объектов. В текущей реализации Sun виртуальной машины Java ссылка на экземпляр класса является указателем на дескриптор, который является самостоятельно парой указателей: один к таблице, содержащей методы объекта и указателя на Class объект, который представляет тип объекта, и другой к памяти, выделенной от "кучи" Java для объектных данных.

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


3.8 Специальные Методы Инициализации

На уровне виртуальной машины Java каждый конструктор (§2.12) появляется как метод инициализации экземпляра, у которого есть специальное имя <init>. Это имя предоставляется компилятором Java. Поскольку имя <init> не допустимый идентификатор, он не может использоваться непосредственно программистом Java. Методы инициализации экземпляра могут только быть вызваны в пределах виртуальной машины Java invokespecial инструкцией, и они могут только быть вызваны на неинициализированные экземпляры класса. Метод инициализации экземпляра берет права доступа (§2.7.8) конструктора, из которого он был получен.

На уровне виртуальной машины Java, класса или интерфейса инициализируется (§2.16.4), вызывая его класс или интерфейсный метод инициализации без параметров. У метода инициализации класса или интерфейса есть специальное имя <clinit>. Это имя предоставляется компилятором Java. Поскольку имя <clinit> не допустимый идентификатор, он не может использоваться непосредственно программистом Java. Класс и интерфейсные методы инициализации вызываются неявно виртуальной машиной Java; они никогда не вызываются непосредственно от кода Java или непосредственно ни от какой инструкции виртуальной машины Java, но только вызываются косвенно как часть процесса инициализации класса.


3.9 Исключения

Вообще, бросок исключения приводит к непосредственной динамической передаче управления, которое может выйти из многократных операторов Java и многократных вызовов конструктора, статичных и полевые оценки инициализатора, и вызовы метода до a catch пункт (§2.15.2) находится, который ловит брошенное значение.

Если не такой catch пункт находится в текущем методе, тогда текущий вызов метода завершается неправильно (§3.6.5). Его стек операнда и локальные переменные отбрасываются, и его фрейм выталкивается, восстанавливая фрейм метода вызова. Исключение тогда повторно бросается в контекст фрейма invoker, и так далее продолжая цепочку вызова метода. Если не подходящий catch пункт находится прежде, чем вершина цепочки вызова метода достигается, выполнение потока, который выдавал исключение, завершается.

На уровне виртуальной машины Java, каждого catch пункт описывает диапазон инструкции виртуальной машины Java, для которого это активно, описывает типы исключений, которые это должно обработать, и дает адрес кода, чтобы обработать это. Исключение соответствует a catch пункт, если инструкция, которая вызвала исключение, находится в соответствующем диапазоне инструкции, и типе исключения, является тем же самым типом как или подкласс класса исключения что catch дескрипторы пункта. Если соответствие catch пункт находится, системные ответвления к указанному обработчику. Если никакой обработчик не находится, процесс повторяется до всего вложенного catch пункты текущего метода были исчерпаны.

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

Если нет никакого соответствия catch пункт, у текущего метода, как говорят, есть непойманное исключение. Режим выполнения invoker, метод, который вызвал этот метод, восстанавливается. Распространение исключения продолжается, как если бы исключение произошло в invoker в инструкции, которая вызвала метод, фактически повышающий исключение.

Java поддерживает более сложные формы обработки исключений через try-finally и try-catch-finally операторы. В таких формах, finally оператор выполняется даже если никакое соответствие catch пункт находится. Путем виртуальная машина Java поддерживает реализацию этих форм, обсуждается в Главе 7, "Компилируя для виртуальной машины Java."


3.10 class Формат файла

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

Глава 4, "Формат файла класса," покрывает class формат файла подробно.


3.11 Сводки Набора команд

Инструкция виртуальной машины Java состоит из однобайтового кода операции, определяющего работу, которая будет выполняться, следоваться нулем или большим количеством операндов, предоставляющих параметры или данные, которые используются работой. Много инструкций не имеют никаких операндов и состоят только из кода операции.

Игнорируя исключения, внутренний цикл выполнения виртуальной машины Java эффективно


    do {
    	fetch an opcode;
    	if (operands) fetch operands;
    	execute the action for the opcode;
    } while (there is more to do);

Число и размер дополнительных операндов определяются кодом операции. Если дополнительный операнд составляет больше чем один байт в размере, то это сохранено в байте старшего разряда порядка с обратным порядком байтов сначала. Например, 16-разрядный индекс без знака в локальные переменные сохранен как два байта без знака byte1 и byte2 так, что, его значение

    (byte1 << 8) | byte2 
Поток команд байт-кода только однобайтовый выровненный. Эти два исключения являются tableswitch и lookupswitch инструкциями, которые дополняются, чтобы вызвать внутреннее выравнивание некоторых из их операндов на 4-байтовых границах.

Решение ограничить код операции виртуальной машины Java байтом и предшествовать выравниванию данных в пределах скомпилированного кода отражает сознательное смещение в пользу компактности, возможно за счет некоторой производительности в наивных реализациях. Однобайтовый код операции устраняет определенные методы реализации, которые могли улучшить производительность эмулятора виртуальной машины Java, и это ограничивает размер набора команд. Не принятие выравнивания данных означает, что непосредственные данные, больше чем байт, должны быть созданы из байтов во время выполнения на многих машинах.

3.11.1 Типы и виртуальная машина Java

Большинство инструкций в наборе команд виртуальной машины Java кодирует информацию о типе об операциях, которые они выполняют. Например, iload инструкция загружает содержание локальной переменной, которая должна быть int, на стек операнда. fload инструкция делает то же самое с a float значение. Эти две инструкции могут иметь идентичные реализации, но иметь отличные коды операций.

Для большинства введенных инструкций тип инструкции представляется явно в мнемосхеме кода операции буквой: я для int работа, l для long, s для short, b для byte, c для char, f для float, d для double, и для reference. У некоторых инструкций, для которых тип однозначен, нет буквы типа в их мнемосхеме. Например, arraylength всегда работает на объекте, который является массивом. Некоторые инструкции, такие как goto, безусловная передача управления, не работают на введенных операндах.

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

Таблица 3.1 суммирует поддержку типа в наборе команд виртуальной машины Java. Только инструкции, которые существуют для многократных типов, перечисляются. Конкретная инструкция, с информацией о типе, создается, заменяя T в шаблоне инструкции в столбце кода операции буквой в столбце типа. Если столбец типа для некоторого шаблона инструкции и типа является пробелом, то никакая инструкция не существует, поддерживая тот тип работы. Например, есть инструкция загрузки для типа int, iload, но нет никакой инструкции загрузки для типа byte.

Отметьте, что у большинства инструкций в Таблице 3.1 нет форм для целочисленных типов byte, char, и short. При записи в ее локальные переменные или стеки операнда, виртуальная машина Java внутренне подписывается - расширяет значения типов byte и short вводить int, и нуль - расширяет значения типа char вводить int. Таким образом, большинство операций на значениях типов byte, char, и short правильно выполняются инструкциями, работающими на значениях типа int. Виртуальная машина Java также обрабатывает значения типа Java boolean особенно, как отмечено в §3.2.4.

код операции byte short int long float double char reference
Tipush bipush sipush
Tconst iconst lconst fconst dconst aconst
Tload iload lload fload dload aload
Tstore istore lstore fstore dstore astore
Tinc iinc
Taload baload saload iaload laload faload daload caload aload
Tastore bastore sastore iastore lastore fastore dastore castore aastore
Tadd iadd ladd fadd dadd
Tsub isub lsub fsub dsub
Tmul imul lmul fmul dmul
Tdiv idiv ldiv fdiv ddiv
Trem irem lrem frem drem
Tneg ineg lneg fneg dneg
Tshl ishl lshl
Tshr ishr lshr
Tushr iushr lushr
Tand iand земля
Скалистая вершина ior lor
Txor ixor lxor
i2T i2b i2s i2l i2f i2d
l2T l2i l2f l2d
f2T f2i f2l f2d
d2T d2i d2l d2f
Tcmp lcmp
Tcmpl fcmpl dcmpl
Tcmpg fcmpg dcmpg
if_TcmpOP if_icmpOP if_acmpOP
Treturn ireturn lreturn freturn dreturn areturn


Отображение между типами хранения Java и виртуальной машиной Java computatational типы получается в итоге Таблицей 3.2.

Java (Хранение) Тип Size in Bits Computational Type
byte 8 int
char 16 int
short 16 int
int 32 int
long 64 long
float 32 float
double 64 double


Исключение к этому отображению в случае массивов. Массивы типа boolean, byte, char, и short может быть непосредственно представлен виртуальной машиной Java. Массивы типа byte, char, и short получаются доступ, используя инструкции, специализированные к тем типам. Массивы типа boolean получаются доступ, используя byte инструкции массива.

Остаток от этой главы суммирует набор команд виртуальной машины Java.

3.11.2 Загрузка и Инструкции Хранилища

Загрузка и инструкции хранилища передают значения между локальными переменными виртуальной машины Java и стеком операнда:

Инструкции, что поля доступа объектов и элементы массивов также передают данные и от стека операнда (§3.6.2).

Мнемоники команд, показанные выше с запаздывающими буквами между угловыми скобками (например, 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).

Эта нотация для семейств инструкции используется всюду по Спецификации виртуальной машины Java.

3.11.3 Арифметические Инструкции

Арифметические инструкции вычисляют результат, который обычно является функцией двух значений на стеке операнда, продвигая результат назад на стеке операнда. Есть два основных вида арифметических инструкций, те, которые работают на целочисленных значениях и тех, которые работают на значениях с плавающей точкой. В пределах каждого из этих видов арифметические инструкции специализируются к виртуальной машине Java числовые типы. Нет никакой прямой поддержки целочисленной арифметики на byte, short, и char типы (§3.11.1); те операции обрабатываются инструкциями, работающими на типе int. Целочисленные и инструкции с плавающей точкой также отличаются по их поведению на переполнении, потере значимости, и делятся на нуль. Арифметические инструкции следующие:

Семантика операторов Java на целом числе и значениях с плавающей точкой (§2.4.2, §2.4.3) непосредственно поддерживается семантикой набора команд виртуальной машины Java.

Виртуальная машина Java не указывает на переполнение или потерю значимости во время операций на целочисленных типах данных. Единственные целочисленные операции, которые могут выдать исключение, являются целочисленными инструкциями дележа (idiv и ldiv) и целочисленными инструкциями остатка (irem и lrem), которые бросают ArithmeticException если делитель является нулем.

Операции Виртуальной машины Java на числах с плавающей точкой ведут себя точно как определено в IEEE 754. В частности виртуальная машина Java требует полной поддержки IEEE 754 денормализованные числа с плавающей точкой и постепенная потеря значимости, которые облегчают доказывать требуемые свойства определенных числовых алгоритмов.

Виртуальная машина Java требует, чтобы арифметика с плавающей точкой вела себя как будто каждый оператор с плавающей точкой, округленный ее результат с плавающей точкой к точности результата. Неточные результаты должны быть округлены к представимому значению, самому близкому к бесконечно точному результату; если два самых близких представимых значения одинаково рядом, тот с его младшим значащим разрядным нулем выбирается. Это - значение по умолчанию стандарта IEEE 754 округление режима, известного как раунд-к-самому-близкому.

Виртуальная машина Java использует раунд к нулю, преобразовывая значение с плавающей точкой в целое число. Это приводит к числу, являющемуся усеченным; отбрасываются любые биты мантиссы, которые представляют дробную часть значения операнда. Раунд к нулю выбирает как его результат значение типа, самое близкое к, но не больше в величине чем, бесконечно точный результат.

Операторы виртуальной машины Java с плавающей точкой не производят исключений. Работа, которая переполнения производят бесконечность со знаком, работа, которая потери значимости производят нуль со знаком, и работа, у которой нет никакого математически определенного результата, производит НЭН. Все числовые операции с НЭН как операнд производят НЭН в результате.

3.11.4 Инструкции Преобразования типов

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

Виртуальная машина Java непосредственно поддерживает следующие расширяющиеся числовые преобразования, подмножество расширения Java примитивные преобразования (§2.6.2):

Расширяющиеся числовые инструкции преобразования являются i2l, i2f, i2d, l2f, l2d, и f2d. Мнемоника для этих кодов операций прямая данный соглашения о присвоении имен для введенных инструкций и каламбурящего использования 2, чтобы значить "для". Например, i2d инструкция преобразовывает int оцените a double. Расширяющиеся числовые преобразования не теряют информацию о полной величине числового значения. Действительно, преобразования, расширяющиеся от int введите к long введите и от float к double не теряйте информацию вообще; числовое значение сохраняется точно. Преобразование int или a long значение к float, или a long значение к double, может потерять точность, то есть, может потерять некоторые из младших значащих битов значения; получающееся значение с плавающей точкой является правильно округленной версией целочисленного значения, используя режим раунда-к-самому-близкому IEEE 754.

Согласно этому правилу, расширяющемуся числовому преобразованию int к a long просто знак - расширяет two's-дополнительное представление int значение, чтобы заполнить более широкий формат. Расширяющееся числовое преобразование a char к нулю целочисленного типа - расширяет представление char значение, чтобы заполнить более широкий формат.

Несмотря на то, что потеря точности может произойти, расширяя числовые преобразования никогда не приводит к исключению на этапе выполнения.

Отметьте, что расширяющиеся числовые преобразования не существуют от целочисленных типов byte, char, и short вводить int. Как отмечено в §3.11.1, значениях типа byte, char, и short внутренне расширяются до типа int, создание этих неявных преобразований.

Виртуальная машина Java также непосредственно поддерживает следующие сужающиеся числовые преобразования, подмножество сужения Java примитивные преобразования (§2.6.3):

Сужающиеся числовые инструкции преобразования являются i2b, i2c, i2s, l2i, f2i, f2l, d2i, d2l, и d2f. Сужающееся числовое преобразование может привести к значению различного знака, или различного порядка величины, или обоих; они могут, таким образом, потерять точность.

Сужающееся числовое преобразование int или long к целочисленному типу T просто отбрасывает все кроме битов самых низкоуровневых N, где N является числом битов, используемых, чтобы представить тип T. Это может заставить получающееся значение не иметь тот же самый знак как входное значение.

В сужающемся числовом преобразовании значения с плавающей точкой к целочисленному типу T, где T также int или long, значение с плавающей точкой преобразовывается в тип T следующим образом:

Сужающееся числовое преобразование из double к float ведет себя в соответствии с IEEE 754. Результат правильно округляется, используя режим раунда-к-самому-близкому IEEE 754. Значение, слишком маленькое, чтобы быть представленным как a float преобразовывается в положительный или отрицательный нуль типа float; значение, слишком большое, чтобы быть представленным как a float преобразовывается в положительную или отрицательную бесконечность. A double НЭН всегда преобразовывается в a float НЭН.

Несмотря на то, что переполнение, потеря значимости, или потеря точности могут произойти, сужая преобразования среди числовых типов никогда не приводит к исключению на этапе выполнения.

3.11.5 Объектное Создание и Манипулирование

Хотя и экземпляры класса и массивы являются объектами, виртуальная машина Java создает и управляет экземплярами класса и массивами, использующими отличные наборы инструкций:

3.11.6 Инструкции управления Стеком операнда

Много инструкций обеспечиваются для непосредственного управления стеком операнда: появитесь, pop2, дубликат, dup2, dup_x1, dup2_x1, dup_x2, dup2_x2, подкачка.

3.11.7 Инструкции Передачи управления

Инструкции передачи управления условно или безоговорочно заставляют виртуальную машину Java продолжать выполнение с инструкцией кроме того, следующего инструкциям передачи управления. Они:

У виртуальной машины Java есть отличные наборы инструкций, чтобы условно перейти на сравнении с данными int, long, float, double, и reference типы. Сравнение с данными byte, char, и short типы делаются, используя int инструкция сравнения (§3.11.1). Из-за этого включенного акцента int сравнения, виртуальная машина Java включает большее дополнение команд условного перехода для типа int чем для других типов. У виртуальной машины Java есть отличные команды условного перехода, которые тестируют на нулевую ссылку, и таким образом не обязан определять конкретное значение для null (§3.3).

Все int и long условные инструкции передачи управления выполняют подписанные сравнения. Сравнение с плавающей точкой выполняется в соответствии с IEEE 754.

3.11.8 Вызов метода и Инструкции Возврата

Четыре инструкции вызывают методы:

Инструкции возврата метода, которые отличает тип возврата, являются ireturn (привыкший к возвращаемым значениям типа byte, char, short, или int), lreturn, freturn, dreturn, и areturn. Кроме того, инструкция возврата используется, чтобы возвратиться из методов, которые, как объявляют, были void.

3.11.9 Бросок и Обработка Исключений

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

3.11.10 Реализация finally

Реализация finally ключевое слово использует jsr, jsr_w, и мочите инструкции. См. Раздел 4.9.6, "Исключения и наконец" и Раздел 7.13, "Компилируя наконец."

3.11.11 Синхронизация

Виртуальная машина Java поддерживает метод - и синхронизация брускового уровня, используя единственный механизм (мониторы) по-разному. Синхронизируемые методы обрабатываются как часть вызова метода и возврата (см. Раздел 3.11.8, "Вызов метода и Инструкции Возврата"). У синхронизации блоков кода, однако, есть явная поддержка в наборе команд: monitorenter, monitorexit.


3.12 Общедоступных Проекта, Частная Реализация

К настоящему времени эта книга делала набросок общедоступного представления виртуальной машины Java: class формат файла и набор команд. Эти компоненты жизненно важны для платформы - и независимость реализации виртуальной машины Java. Конструктор может предпочесть думать о них как о средстве надежно передать фрагменты программ между двумя платформами, а не как проект, который будет сопровождаться точно.

Важно понять, где строка между общедоступным проектом и частной реализацией находится. Виртуальная машина Java должна быть в состоянии читать class файлы, и это должно точно реализовать семантику кода виртуальной машины Java там. Один способ сделать это состоит в том, чтобы взять этот документ в качестве спецификации и реализовывать ту спецификацию буквально. Но это является также совершенно выполнимым и требуемым для конструктора, чтобы изменить или оптимизировать реализацию в пределах ограничений этой спецификации. Пока class формат файла может быть считан, и семантика его кода сохраняется, конструктор может реализовать их семантика всегда. То, что "под капотом", является бизнесом конструктора, пока корректный внешний интерфейс тщательно сохраняется 2

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

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


1 В JDK Sun 1.0.2 выпуска, boolean массивы эффективно byte массивы, используя элемент 8 битов за булевскую переменную.

2 есть некоторые исключения: отладчики и генераторы кода JIT могут потребовать доступа к элементам виртуальной машины Java, которые, как обычно полагают, являются "под капотом." Sun работает с другими конструкторами виртуальной машины Java и поставщиками инструментов, чтобы стандартизировать интерфейсы к виртуальной машине Java для использования такими инструментами.


Содержание | Предыдущий | Следующий | Индекс

Спецификация Виртуальной машины Java

Авторское право © 1996, 1997 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к jvm@java.sun.com

free hit counter