ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 24.12.2021
Просмотров: 6737
Скачиваний: 8
248
Глава 4. Микроархитектурный уровень
Набор
констант
СРР
Текущий стек
операндов 3
Текущий
фрейм
локальных
переменных 3
Фрейм
локальных
переменных 2
Фрейм
локальных
переменных 1
SP
LV
Область
процедур
PC
Рис.
4.9. Области памяти IJVM
Регистр PC, напротив, содержит адреса байтов, и изменение этого значения
означает увеличение на определенное количество байтов, а не слов. Обращение к
памяти регистром PC отличается от обращений других регистров, поэтому в ма-
шине Mic-1 и предусмотрен специальный порт памяти для PC. Запомните, что его
размер составляет всего один байт. Если увеличить PC на единицу и начать про-
цесс чтения, то это приведет к вызову следующего
байта.
Если увеличить SP на
единицу и начать процесс чтения, то это приведет к вызову следующего
слова.
Набор команд IJVM
Набор команд IJVM приведен в табл. 4.2. Каждая команда состоит из кода опера-
ции и иногда из операнда (например, смещения адреса или константы). В первом
столбце приводится шестнадцатеричный код команды. Во втором столбце дается
мнемоника языка ассемблера. В третьем столбце описывается предназначение
команды.
Команды нужны для того, чтобы помещать слова из различных источников в
стек. Источники — это набор констант (LDC_W), фрейм локальных переменных (ILOAD)
и сама команда (BIPUSH). Переменную можно также вытолкнуть из стека и сохра-
нить ее во фрейме локальных переменных (ISTORE). Над двумя верхними словами
стека можно совершать две арифметические (IADD и ISUB) и две логические опера-
ции (IAND и I0R). При выполнении любой арифметической или логической опера-
ции два слова выталкиваются из стека, а результат помещается обратно в стек.
Существует 4 команды перехода: одна для безусловного перехода (GOTO), а три дру-
гие для условных переходов (IFEQ, IFLT и IF_ICMPEQ). Все эти команды изменяют
значение PC на размер их смещения, который следует за кодом операции в коман-
де. Операнд смещения состоит из 16 битов. Он прибавляется к адресу кода опера-
ции. Существуют также команды для перестановки двух верхних слов стека (SWAP),
дублирования верхнего слова (DUP) и удаления верхнего слова (POP).
Пример архитектуры команд: IJVM
249
Таблица 4.2.
Набор команд IJVM. Размер операндов byte, const и varnum — 1 байт.
Размер операндов disp, index и offset — 2 байта
Число Мнемоника
Примечание
0x10
0x59
0хА7
0x60
0x7 Е
BIPUSHbyfe
DUP
GOTO
offset
IADD
IAND
0x99 IFEQoffsef
0x9B IFLT
offset
0x9F IFJCMPEQ
offset
0x84 IINC
varnum const
0x15
\LOAD varnum
0xB6 INVOKEVIRTUAL
disp
0x80 IOR
OxAC
0x36
0x64
0x13
0x00
0x57
0x5 F
0xC4
IRETURN
ISTORE
varnum
ISUB
LDCJN index
NOP
POP
SWAP
WIDE
Помещает байт в стек
Копирует верхнее слова стека и помещает его в стек
Безусловный переход
Выталкивает два слова из стека; помещает в стек их сумму
Выталкивает два слова из стека; помещает в стек результат
логического умножения (операция И)
Выталкивает слово из стека и совершает переход, если оно
равно нулю
Выталкивает слово из стека и совершает переход, если оно
меньше нуля
Выталкивает два слова из стека; совершает переход, если
они равны
Прибавляет константу к локальной переменной
Помещает локальную переменную в стек
Вызывает процедуру
Выталкивает два слова из стека; помещает в стек результат
логического сложения {операция ИЛИ)
Выдает результат выполнения процедуры (целое число)
Выталкивает слово из стека и запоминает его во фрейме
локальных переменных
Выталкивает два слова из стека; помещает в стек их разность
Берет константу из набора констант и помещает ее в стек
Не производит никаких действий
Удаляет верхнее слово стека
Переставляет два верхних слова стека
Префиксная команда; следующая команда содержит
16-битный индекс
Некоторые команды имеют сложный формат, допускающий краткую форму для
часто используемых версий. Из всех механизмов, которые JVM применяет для
этого, в IJVM мы включили два. В одном случае мы пропустили краткую форму
в пользу более традиционной. В другом случае мы показываем, как префиксная
команда WIDE может использоваться для изменения следующей команды.
Наконец, существует команда для вызова другой процедуры (INVOKEVIRTUAL) и
команда для выхода из текущей процедуры и возвращения к процедуре, из кото-
рой она была вызвана. Из-за сложности механизма мы немного упростили опреде-
ление. Ограничение состоит в том, что, в отличие от языка Java, в нашем примере
процедура может вызывать только такую процедуру, которая находится внутри
нее. Это ограничение сильно искажает язык Java, но зато позволяет представить
более простой механизм, избегая требования размещать процедуру динамически.
(Если вы не знакомы с объектно-ориентированным программированием, вы мо-
жете пропустить это предложение. Мы просто превратили язык Java из объектно-
250
Глава 4. Микроархитектурный уровень
ориентированного в обычный, такой как С или Pascal.) На всех компьютерах, кро-
ме JVM, адрес процедуры, которую нужно вызвать, непосредственно определяет-
ся командой CALL, поэтому наш подход скорее правило, чем исключение.
Механизм вызова процедуры состоит в следующем. Сначала вызывающая про-
грамма помещает в стек указатель на объект, который нужно вызвать. На рис. 4.10,
а
этот указатель обозначен буквами OBJREF. Затем вызывающая программа по-
мещает в стек параметры процедуры (в данном примере
Параметр 1, Параметр 2
и
Параметр 3).
После этого выполняется команда INVOKEVIRTUAL.
Стек после выполнения
команды INVOKEVIRTUAL
Стек до выполнения
команды INVOKEVIRTUAL
Вытолкнутые
из стека
параметры
Фрейм
локальных
переменных
вызывающей
процедуры
Параметр 3
Параметр 2
Параметр 1
OBJREF
Предыдущее
значение LV
Предыдущее
значение PC
Фрейм локальных
переменных
вызывающей
процедуры
Параметр 2
Параметр 1
Связывающий
указатель
Основание стека
SP после выполнения
команды
INVOKEVIRTUAL
Основание стека
до выполнения
команды
INVOKEVIRTUAL
LV
LV вызывающей
процедуры
PC вызывающей
процедуры
Пространство
для локальных
переменных
вызывающей
процедуры
Параметр 3
Параметр 2
Параметр 1
Связующий
указатель
Предыдущее
значение LV
Предыдущее
значение PC
Фрейм локальных
переменных
вызывающей
процедуры
Параметр 2
Параметр 1
Связывающий
указатель
-SP
LV
Рис. 4.10. Память до выполнения команды INVOKEVIRTUAL (а);
память после выполнения этой команды (б)
Команда INVOKEVIRTUAL включает в себя относительный адрес
(disp).
Он указы-
вает на позицию в наборе констант. В этой позиции содержится начальный адрес
вызываемой процедуры, которая хранится в области процедур. Первые 4 байта
в области процедур содержат специальные данные. Первые два байта представляют
собой целое 16-битное число, указывающее на количество параметров данной про-
цедуры (сами параметры были ранее помещены в стек). В данном случае OBJREF
считается параметром: параметром 0. Это 16-битное целое число вместе со значе-
нием SP дает адрес OBJREF. Отметим, что регистр LV указывает на OBJREF, а не
Пример архитектуры команд: IJVM 251
на первый реальный параметр. Выбор, на что указывает LV, в какой-то степени
произволен.
Следующие два байта в области процедур представляют еще одно 16-битное
целое число, указывающее размер области локальных переменных для вызывае-
мой процедуры. Дело в том, что для данной процедуры предоставляется новый
стек, который размещается прямо над фреймом локальных переменных, для этого
и нужно это число. Наконец, пятый байт в области процедур содержит код первой
операции, которую нужно выполнить.
Ниже описывается, что происходит перед вызовом процедуры (см. также
рис. 4.10). Два байта без знака, которые следуют за кодом операции, используются
для индексирования таблицы констант (первый байт — это старший байт). Команда
вычисляет базовый адрес нового фрейма локальных переменных. Для этого из
указателя стека вычитается число параметров, a LV устанавливается на OBJREF.
В OBJREF хранится адрес ячейки, в которой находится старое значение'РС. Этот
адрес вычисляется следующим образом. К размеру фрейма локальных переменных
(параметры + локальные переменные) прибавляется адрес, содержащийся в реги-
стре LV. Сразу над адресом, в котором должно быть сохранено старое значение
PC, находится адрес, в котором должно быть сохранено старое значение LV. Над
этим адресом начинается стек для новой вызванной процедуры. SP указывает на
старое значение LV, адрес которого находится сразу под первой пустой ячейкой
стека. Помните, что SP всегда указывает на верхнее слово в стеке. Если стек пуст,
то SP указывает на адрес, который находится непосредственно под стеком, посколь-
ку стек заполняется снизу вверх.
И наконец, для выполнения команды INVOKEVIRTUAL нужно сделать так, чтобы
PC указывал на пятый байт в кодовом пространстве процедуры.
Команда IRETURN противоположна команде INVOKEVIRTUAL (рис. 4.11). Она осво-
бождает пространство, используемое процедурой. Она также возвращает стек в
предыдущее состояние, за исключением того, что: 1) OBJREF и все параметры
удаляются из стека; 2) возвращенное значение помещается в стек, туда, где рань-
ше находился OBJREF. Чтобы восстановить прежнее состояние, команда IRETURN
должна вернуть прежние значения указателей PC и LV. Для этого она обращается
к связующему указателю (это слово, определяемое текущим значением LV). В этом
месте, где изначально находился параметр OBJREF, команда OBJREF сохранила
адрес, содержащий старое значение PC. Это слово и слово над ним извлекаются,
чтобы восстановить старые значения PC и LV соответственно. Возвращенное
значение, которое хранится на самой вершине стека завершающейся процедуры,
копируется туда, где изначально находился OBJREF, и теперь SP указывает на
этот адрес. И тогда управление переходит к команде, которая следует сразу за
INVOKEVIRTUAL.
До сих пор у нашей м а ш и н ы не было никаких команд ввода-вывода. Мы и не
собираемся их вводить. В нашем примере, как и в виртуальной машине Java, они
не нужны, и в описании J V M никогда не упоминаются процессы ввода-вывода.
Считается, что машина без ввода-вывода более надежна. (Чтение и запись осуще-
ствляются в J V M путем вызова специальных процедур.)
252
Глава 4. Микроархитектурный уровень
Стек до выполнения
команды I RETURN
Локальные
переменные
вызывающей
процедуры
Возвращаемое
значение
Предыдущее
значение LV
Предыдущее
значение PC
локальные
переменные
вызывающей
процедуры
Параметр 3
Параметр 2
Параметр 1
Связующий
указатель
Предыдущее
значение LV
Предыдущее
значение PC
Локальные
переменные
вызывающей
процедуры
Параметр 2
Параметр 1
Связующий
указатель
SP
Основание стека
до выполнения
команды IRETURN
LV
Стек после
выполнения
команды IRETURN
Основание стека
после выполнения
команды IRETURN
Возвращаемое
значение
Предыдущее
значение LV
Предыдущее
значение PC
Локальные
переменные
вызывающей
процедуры
Параметр 2
Параметр 1
Связующий
указатель
SP
LV
Рис. 4 . 1 1 . Память до выполнения команды IRETURN (a);
память после выполнения этой команды (б)
Компиляция Java для IJVM
А теперь рассмотрим, как язык Java связывается с машиной IJVM. В листинге 4.1
представлен небольшой фрагмент программы на языке Java. Компилятор Java дол-
жен был бы переделать эту программу в программу на языке ассемблер IJVM.
Эта программа приведена в листинге 4.2. Цифры с 1 по 15 в левой части листинга,
а также комментарии за значком «//» не являются частью самой программы. Они
даны для наглядности и просто облегчают понимание. Затем ассемблер Java
транслировал бы ее в программу в двоичном коде. Эта программа приведена в ли-
стинге 4.3. (В действительности компилятор Java сразу производит двоичную про-
грамму.) В данном примере i — локальная переменная 1, j — локальная перемен-
ная 2, а к — локальная переменная 3.
Листинг 4 . 1
. Фрагмент программы на языке Java
I—3)
k-0:
else
J-J-l: