ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 24.12.2021

Просмотров: 6737

Скачиваний: 8

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

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).


background image

Пример архитектуры команд: 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 из объектно-


background image

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, а не


background image

Пример архитектуры команд: 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 путем вызова специальных процедур.)


background image

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: