2. Фреймы
Фрейм используется для хранения данных и промежуточных результатов, а также для
осуществления динамической компоновки, возрата значений методов и обработки
исключений.
Новый фрейм создаётся при вызове каждого метода. Фрейм уничтожается, когда
завершается вызов метода. Память для фрейма выделяется в Java-стеке потока,
создающего фрейм. Каждый фрейм содержит свой собственный массив локальных
переменных, собственный стек операндов и ссылку на набор констант класса текущего
метода.
Размер массива локальных переменных и стека операндов определяется на этапе
компиляции программы.
2.1. Регистры JVM
Рис.4. Фрейм и регистры JVM.
Для управления исполнением байткода JVM использует 4 32-битных регистра:
- pc (program counter) - счётчик команд.
- vars - указывает на массив локальных переменных текущего метода.
frame - указывает на текущую среду выполнения.
Среда выполнения представляет собой структуру, которая может различаться в
зависимости от реализации виртуальной машины. Эта структура содержит информацию,
необходимую для динамической компоновки методов, обработки исключений и др.
- optop - указывает на вершину стека операндов.
2.2. Типы данных JVM
Как и язык программирования Java, виртуальная машина Java работает с двумя
видами типов данных: простыми типами и ссылочными типами. В Java проверка почти
всех типов производится на этапе компиляции. Существуют байткоды, которые работают
с элементарными значениями и указывают типы операндов, например, каждая из
инструкций iadd, ladd, fadd, и dadd складывает два
числа, имеющих int, long, float, и double,
соответственно.
Виртуальная машина не содержит отдельных инструкций для типов boolean.
Вместо этого, выражения в языке Java, которые работают со значениями типами
boolean, компилируются для использования значений JVM типа int.
Виртуальная машина Java напрямую поддерживает массивы значений типа
boolean. Для работы с массивами логических типов используются команды JVM для
работы с массивами байтов baload и bastore. JVM использует значение
1 для представления true и 0 для представления false.
Существуют ещё 2 типа данных, с которыми работает виртуальная машина Java: ссылка
на объект (reference) и адрес возврата(returnAddress). Значения типа
returnAddress представляют собой указатели на инструкции байткода JVM. В
отличие от численных типов, тип returnAddress не соответствует ни одному типу
языка программирования Java и не может быть изменён выполняемой программой.
Таблица 1. Типы данных виртуальной машины Java.
| Тип |
Описание |
| byte |
1-байтовое двоичное целое со знаком в дополнительном коде. |
| short |
2-байтовое двоичное целое со знаком в дополнительном коде. |
| int |
4-байтовое двоичное целое со знаком в дополнительном коде. |
| long |
8-байтовое двоичное целое со знаком в дополнительном коде. |
| char |
Символ Unicode, занимающий 2 байта. |
| float |
Вещественное число одинарной точности стандарта IEEE 754. Размер 4 байта. |
| double |
Вещественное число двойной точности стандарта IEEE 754. Размер 8 байтов. |
| reference |
Ссылка на объект Java. Размер 4 байта. |
| returnAddress |
Адрес возврата. Размер 4 байта. |
2.3. Локальные переменные
Каждый Java-метод использует набор локальных переменных фиксированного размера.
Они адресуются, как смещения слова от регистра vars. Размер локальных переменных -
32 бита.
Рис.5. Локальные переменные.
Длинные целые и вещественные двойной точности рассматриваются, как
располагающиеся в двух локальных переменных, и адресуются индексом первой локальной
переменной. (Например, локальная переменная с индексом n содержащая
вещественное двойной точности фактически занимает место, соответствующее индексам
n и n + 1.)
2.4. Стек операндов
Все инструкции машины берут операнды из стека операндов, работают с ними
и возвращают результат обратно в стек. Стековая организация была выбрана, чтобы было
легко эффективно эмулировать JVM на процессорах с малым количеством регистров или
с нерегулярным набором регистров (например, как у Intel 486).
Размер ячейки стека операндов 32 бита. Он используется для передачи параметров
методам и получения результатов метода, а также и для обеспечения действий с
параметрами и сохранения результатов действий. Промежуточные значения хранятся в
стеке опреандов, что обеспечивает поддержку вложенных вычислений.
Каждый простейший тип данных имеет специализированные инструкции, которые знают
как работать с операндами этого типа. Каждый операнд требует одной ячейки в стеке,
кроме long и double, которым необходимо две ячейки.
Рис.6. Сложение двух величин типа int.
Рис.7. Сложение двух величин типа double.
Операнды должны использоваться операциями, соответствующими их типу. Например,
нельзя помещать в стек два целых и потом использовать их как длинное целое. В
реализации Sun это ограничение контролируется верификатором байткода. Однако,
некоторые операции (коды операции dup и swap) работают с областями
данных как со значениями данного размера, не обращая внимания на тип.
В результате выполнения инструкции, операнд 1 и операнд 2
извлекаются из стека и заменяются на результат, который был вычислен
инструкцией. Остаток стека, представленный многоточием, не затрагивается при
выполнении инструкции.
Наверх | Дальше
|