ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 24.12.2021
Просмотров: 12181
Скачиваний: 10

3 9 8
Глава 5. Уровень архитектуры команд
Таблица 5.9.
Некоторые моделируемые команды UltraSPARC II
Команда Как получить команду
MOV SRC, DST Выполнить команду OR над SRC и GO и сохранить результат в DST
CMP SRC1, SRC2 Вычесть SRC2 из SRC1 (команда SUBCC) и сохранить результат в GO
TST SRC Выполнить команду ORCC над SRC и GO и сохранить результат в GO
NOT DST Выполнить команду XNOR над DST и GO
NEG DST Вычесть SRC2 из SRC1 (команда SUBCC) и сохранить результат в GO
INC DST Прибавить 1 к DST (непосредственный операнд) — команда ADD
DEC DST Отнять 1 от DST (непосредственный операнд) — команда SUB
CLR DST Выполнить команду OR над GO и GO и сохранить результат в DST
NOP SETHI GO на О
RET JMPL%l7+8, %G0
JVM содержит относительно небольшой набор простых команд. Набор всех
команд JVM (за исключением некоторых расширенных, коротких и быстрых ва-
риантов команд) приведен на рис. 5.23.
Команды JVM типизированы. Одну и ту же операцию с разными типами дан-
ных выполняют разные команды. Например, команда ILOAD помещает в стек целое
32-битное число, а команда ALOAD помещает в стек 32-битный указатель. Такое стро-
гое разделение необязательно для правильного выполнения программы, посколь-
ку в обоих случаях 32 бита, которые находятся в определенной ячейке памяти,
передаются в стек независимо от типа этого 32-битного слова. Такое жесткое
разграничение типов требуется для того, чтобы можно было проверить во время
выполнения программы, не нарушены ли какие-нибудь ограничения (например,
не пытается ли программа превратить целое число в указатель, чтобы обратиться
к памяти).
Перейдем к командам JVM. Первая команда в списке — typeLOAD IND8.
На самом деле это не одна команда, а шаблон для порождения команд. Коман-
ды JVM регулярны, поэтому вместо того чтобы приводить все команды по одной,
в некоторых случаях мы будем давать правило для порождения команд. В данном
случае слово type заменяет одну из четырех букв: I, L, F и D, которые соответству-
ют типам integer (целые числа), long, float (32-битные числа с плавающей точкой)
и double (64-битные числа с плавающей точкой) соответственно. Следовательно,
здесь подразумевается 4 команды (ILOAD, LLOAD, FLOAD и DLOAD), каждая из которых
содержит 8-битный индекс IND8 для нахождения локальной переменной и поме-
щает в стек значение соответствующей длины и типа. Мы рассматривали только
одну из этих команд — ILOAD, но остальные действуют точно так же и отличаются
только по числу слов, помещаемых в стек, и по типу значения.
Кроме этих четырех команд существует еще четыре команды загрузки typeALOAD.
Эти команды помещают в стек элементы массива. Во всех четырех случаях снача-
ла в стек должен загружаться указатель на массив и индекс элемента массива.
Затем эти команды выталкивают индекс и указатель, производят вычисление,
чтобы найти элемент массива, и помещают этот элемент в стек. При вычислении
нужно знать размер элементов, который определяется по типу. Эти команды по-
лучают индекс массива из стека, поэтому сама команда не содержит операнда.

Типы команд
399
ж
Команды загрузки
typeLOAD IND8
typeALOAD
BALOAD
SALOAD
CALOAD
AALOAD
Помещает локальную переменную в стек
Помещает элемент массива в стек
Помещает байт из массива в стек
Помещает short integer из массива в стек
Помещает символ из массива в стек
Помещает указатель из массива в стек
Команды сохранения
typeSTORE IND8
typeASTORE
BASTORE
SASTORE
CASTORE
AASTORE
Выталкивает из стека значение и сохраняет его в локальной переменной
Выталкивает из стека значение и сохраняет его в массиве
Выталкивает из стека байт и сохраняет его в массиве
Выталкивает из стека short и сохраняет его в массиве
Выталкивает из стека символ и сохраняет его в массиве
Выталкивает из стека указатель и сохраняет его в массиве
Команды помещения в стек
BIPUSH CON8
SIPUSHCON16
LDC IND8
typeCONST_*
ACONS_NULL
Помещает небольшую константу в стек
Помещает 16-битную константу в стек
Помещает в стек константу из набора констант
Помещает в стек непосредственную константу
Помещает в стек нулевой указатель
Арифметические команды
typeADD
typeSUB
typeMUL
typeDIV
typeREM
typeNEG
Сложение
Вычитание
Умножение
Деление
Остаток
Отрицание
Логические команды/команды сдвига
HAND
NOR
ilXOR
ilSHL
lISHR
ilUSHR
Логическое И
Логическое ИЛИ
Логическое ИСКЛЮЧАЮЩЕЕ ИЛИ
Сдвиг влево
Сдвиг вправо
Сдвиг вправо без знака
Команды преобразования
х2у
i2c
i2b
Преобразует х в у
Преобразует целое число в символ
Преобразует целое число в байт
Команды управления стеком
DUPxx
POP
РОР2
SWAP
Шесть команд дублирования
Выталкивает целое число из стека и отбрасывает его
Выталкивает два целых числа из стека и отбрасывает их
Меняет местами два верхних целых числа в стеке
Рис. 5.23.
Набор к о м а н д а м (начало)

4 0 0
Глава 5. Уровень архитектуры команд
Команды сравнения
IF ICMPrel 0FFSET16
IF ACMPEQ 0FFSET16
IF ACMPNE0FFSET16
IFrel 0FFSET16
IFNULLOFFSET16
IFNONNULLOFFSET16
LCMP
FCMPL
FCMPG
DCMPL
DCMPG
Условный переход
Переход в случае равенства двух значений
Переход в случае неравенства двух значений
Проверяет одно значение и совершает переход
Совершает переход, если значение равно 0
Совершает переход, если значение не равно 0
Сравнивает два числа long
Сравнивает два числа с плавающей точкой на <
Сравнивает два числа с плавающей точкой на >
Сравнивает два числа типа double на <
Сравнивает два числа типа double на >
Команды передачи управления
и
INVOKEVIRTUAL IND16
INVOKESTATIC IND16
INVOKEINTRFACE
INVOKESPECIAL IND16
JSROFFSET16
tipeRETURN
ARETURN
RETURN
RET IND8
G0T0 0FFSET16
Вызов процедуры
Вызов процедуры
Вызов процедуры
Вызов процедуры
Вызов процедуры
Возвращает значение
Возвращает указатель
Возвращает пустой тип
Выход из процедуры
Безусловный переход
Операции с массивами
ANEWARRAYIND16
NEWARRAY ATYPE
MULTINEWARRAY 1N16, D
ARRAYLENGTH
Создает массив переменных
Создает массив из массивов
Создает многомерный массив
Выдает длину массива
Прочие команды
л
IINCIND8, CON16
WIDE
NOP
GETFIELDIND16
PUTFIELD IND16
GETSTATIC IND16
NEWIND16
INSTANCEOF 0FFSET16
CHECKCASTIND16
ATHROW
LOOKUPSWITCH...
TABLESWITCH...
MONITORENTER
MONITOREXIT
Увеличивает локальную переменную на 1
Префикс
Пустая операция
Считывает поле из объекта
Записывает слово в объект
Получает статическое поле из класса
Создает новый объект
Определяет тип объекта
Проверяет тип объекта
Обработка исключения
Разбросанные многоуровневые переходы
Компактные многоуровневые переходы
Входит в управляющую прграмму
Выходит из управляющей прграммы
IND
8/16 = индекс
локальной переменной;
CON 8/16, D, ATYPE = константа;
type, х, у = I, L, F, D;
OFFSET 16 для команд перехода
Рис. 5.23.
Набор команд JVM (окончание)

Типы команд 401
Последние четыре команды этой группы также предназначены для работы с эле-
ментами массива, но только других типов. Они поддерживают byte (байт — 8 би-
тов), short (16 битов), char (символ — 16 битов) и pointer (указатель — 32 бита).
Таким образом, всего существует 12 команд LOAD.
Команды typeSTORE обратны командам typeLOAD. Каждая команда выталкивает
элемент из стека и сохраняет его в локальной переменной. Одну из этих команд
(ISTORE) мы уже рассматривали, когда изучали машину IJVM. Здесь также имеют-
ся команды для сохранения элементов массива. В вершине стека находится значе-
ние нужного типа. Под ним находится индекс, а еще ниже — указатель на массив.
Все три элемента удаляются из стека этой командой.
Команды PUSH помещают значение в стек. Команду ВI PUSH мы уже рассматрива-
ли. Команда SIPUSH выполняет ту же операцию, но только с 16-битным числом.
Команда LDC помещает в стек значение из набора констант. Следующая команда
представляет целую группу команд всех четырех основных типов (integer, long,
float и double). Каждая команда содержит только код операции, и каждый код опе-
рации помещает определенное значение в стек. Например, команда ICONST0 (код
операции 0x03) помещает в стек 32-битное слово 0. То же самое действие можно
произвести с помощью команды BIPUSH, но это займет два байта. Благодаря опти-
мизации самых распространенных команд программы JVM получаются неболь-
шими по размеру. Поддерживаются следующие значения: Integers (целые чис-
ла) - 1 , 0, 1, 2, 3, 4, 5; longs 0 и 1; floats (числа с плавающей точкой) 0,0, 1,0 и 2,0 и
doubles 0,0 и 1,0. Команда CONST_NULL помещает в стек нулевой указатель. Сочета-
ние кодов операций и самых распространенных адресов в одной 1 -байтной коман-
де сильно сокращает размер команды, что экономит память и время на передачу
бинарных программ на языке Java по Интернету.
Арифметические операции абсолютно регулярны. Для каждого из основных
четырех типов имеется 4 команды. Три логические операции и три операции сдви-
га применяются только для целых чисел и чисел типа long. Наличие команды AND
для чисел с плавающей точкой противоречило бы строгим правилам типизирова-
ния JVM. Строка х2у в таблице представляет 4x4 команд преобразования. Значе-
ния каждого типа могут переделываться в любой другой тип (но только не в тот же
самый), поэтому здесь имеется 12 команд. Самой типичной из них является ко-
манда I2F, которая превращает целое число в число с плавающей точкой.
Группа команд управления стеком содержит команды, которые дублируют верх-
нее значение или два значения стека и помещают их в различные части стека (не
обязательно в вершину). Остальные команды выталкивают значения из стека и
меняют местами два верхних значения.
Команды группы сравнения выталкивают одно или два значения из стека и
проверяют их. Если из стека выталкивается два значения, то одно из них вычита-
ется из другого, а результат проверяется. Если выталкивается одно значение, то
оно и проверяется. Суффикс rel замещает реляционные операторы: LT, LE, EQ,
NE, GE и GT. Команды со смещением совершают переход, если определенное усло-
вие подтверждено. Остальные команды помещают результат обратно в стек.
Следующая группа предназначена для вызова процедур и возвращения зна-
чений. При изучении машины IJVM мы рассматривали очень простые версии ко-
манд INVOKEVIRTUAL и IRETURN. Полные версии содержат гораздо больше параметров,

4 0 2 Глава 5. Уровень архитектуры команд
и существует множество команд, которые покрывают самые различные случаи.
В этой книге мы не будем описывать эти команды. Подробнее см. [85].
Еще одну группу образуют 4 команды для создания одномерных и многомер-
ных массивов и проверки их длины. В машине JVM массивы хранятся в «куче» и
периодически очищаются (процесс «сборки мусора»), когда они уже больше не
нужны.
Последняя группа включает в себя оставшиеся команды. Каждая из этих ко-
манд имеет специальное назначение, связанное с какой-нибудь особенностью языка
Java. Описание этих команд не входит в задачи этой книги.
А теперь нужно сказать пару слов о самом уровне команд picojava II. Это ма-
шина с обратным порядком байтов (хотя существует несколько команд, которые
можно переделать в формат с прямым порядком байтов). Слова состоят из 32 би-
тов, хотя существуют команды для работы с единицами по 8,16 и
64
бита. Стек
в памяти располагается от верхних адресов к нижним в отличие от IJVM (специ-
фикация JVM допускает оба варианта).
Машина picojava II была разработана для программ на Java, С и C++. Но чтобы
запустить программы на С и C++, нужен компилятор, который превращает С и
C++ в команды picojava И. После того как программа на С или C++ была скомпи-
лирована на JVM, все способы оптимизации аппаратного обеспечения, которые
мы описывали в главе 4, становятся применимы для С и C++.
Чтобы программы на С и C++ могли работать на машине picojava II, к уровню
архитектуры команд было добавлено 115 дополнительных команд. Большинство
из них составляют два или более байтов в длину и начинаются с одного из двух
зарезервированных кодов JVM (OxFE и OxFF), которые показывают, что дальше
следует расширенная команда. Ниже мы дадим краткий обзор особенностей
picojava II, не характерных для JVM.
В машине picojava II содержится 25 32-битных регистров. Четыре из них по
функциям эквивалентны регистрам PC, LV, SP и СРР машины IJVM. Регистр
OPLIM помещает определенное предельное значение в SP. Ести значение SP вы-
ходит за пределы OPLIM, то происходит прерывание. Эта особенность позволяет
представлять стек в виде связного списка участков стека, а не как один непрерыв-
ный блок памяти. Регистр FRAME отмечает конец фрейма локальных переменных
и указывает на слово, которое содержит счетчик команд вызывающей процедуры.
Среди других регистров можно назвать слово состояния программы — это ре-
гистр, который следит, насколько заполнен 64-регистровый стековый кэш, и четы-
ре регистра, которые используются для управления потоком. Кроме того, суще-
ствует 4 регистра для ловушек и прерываний и 4 регистра для вызова процедур и
возвращения значений в командах на языках С и C++. Поскольку picojava II не
имеет виртуальной памяти, для ограничения определенной части памяти, к которой
может иметь доступ текущая программа на С или C++, используются два специаль-
ных регистра. Расширенные команды можно разделить на 5 категорий. К первой
категории относятся команды для чтения и записи верхних регистров. Ко второй
категории относятся команды для работы с указателями. Они позволяют считы-
вать из памяти и записывать в память произвольные слова. Большинство из этих
команд выталкивают машинный адрес из стека, а затем помещают в стек содержи-