Глухих Михаил Игоревич mailto: [email protected] › media ›...
TRANSCRIPT
Глухих Михаил Игоревичmailto: [email protected]
The Java Virtual Machine Specification
Action “Show Bytecode” in IDEA
2
Регистры, как минимум◦ Указатель программы◦ Указатель стека◦ Регистры для хранения данных
Арифметико-логическое устройство◦ Непосредственное выполнение операций
Конвейер чтения и дешифрации команд◦ Читает команды и определяет, что они значат◦ Команды в двоичном коде
Устройство управления◦ Руководит всем
3
Язык программирования, непосредственно понятный процессору
Команды в двоичном коде◦ Как правило имеют также символьное представление
(human-friendly)
Как правило не включает сложных конструкций и структур данных
Типичный набор инструкций◦ Арифметико-логические операции◦ Чтение / запись из / в памяти◦ Переходы (goto) по условию и без него◦ Вызов процедур ◦ …
4
JVM = “виртуальный компьютер”, имеющий, как минимум, процессор и память
JVM имеет собственный машинный язык (это НЕ Java, хотя язык сделан так, чтобы было удобно компилировать Java в этот язык)
JVM имеет стековую архитектуру (в отличие от регистровой архитектуры большинства настоящих процессоров)
◦ Стековая = операнды хранятся на стеке, количество регистров минимизировано, многие операции вроде ADD не имеют аргументов
◦ Регистровая = операнды хранятся в регистрах, операции имеют аргументы, например ADD AX, BX
5
Программа для JVM состоит из class-файлов, их формат строго специфицирован, каждый class-файл описывает ровно один класс
◦ Отметим, что машинный язык «знает», что такое классы
◦ Примеры с разными классами: см. в IDE
◦ С точки зрения JVM, все классы работают как top-level
6
Header (magic number)
Version (bound to JDK in use)
Constant pool◦ Все константы и идентификаторы сохраняются
как индекс для constant pool
This & super-class names
Super-interface names
Fields
Methods
Other attributes
7
Обычные (top-level, regular)◦ public / package private
Вложенные (nested)◦ Статически вложенные (static nested)
◦ Внутренние (inner, member inner)
Локальные (local, method local)
Анонимные (anonymous)
8
Kind Scope Access Notes
Regular Top-level Everywhere
Static nested Class Everywhere
Member inner Class Everywhere Bound to outer class
Method local Method Method Captures local variables
Anonymous Method Method Captures local variables
9
Regular class – напрямую
Static nested class – напрямую с именем вроде OuterName$NestedName
Member inner class – также содержит неявную ссылку на объект внешнего класса, через которую может обращаться к его полям и методам
Local & anonymous classes – при создании получают ссылки на captured local variables
10
Поддерживаемые типы данных◦ Примитивные: byte, short, int, long, char, float,
double, boolean, returnAddress returnAddress ~ адрес инструкции в байт-коде,
используется для вызова так называемых процедур (subroutine)
Subroutines раньше использовались для try / finally, начиная с JDK 6 вроде бы не используются
◦ Ссылочные: class, interface, array, all are nullable
11
Поддерживаемые типы данных◦ Примитивные: byte, short, int, long, char, float,
double, boolean, returnAddress
◦ Ссылочные: class, interface, array, all are nullable Используется class или interface в зависимости от
compile-time типа
Array является специальным вариантом
12
Регистр PC
JVM stack = привязан к каждой JVM-нити, служит для хранения локальных переменных,параметров методов и операций, состоит из фреймов◦ JVM frame = создаётся для каждого вызванного метода
на стеке, состоит из массива локальных переменных, стека операндов (Operand stack, не путать с JVM stack!), ссылки на пул констант для класса, к которому относится метод
13
Регистр PC
JVM stack = привязан к каждой JVM-нити, служит для хранения локальных переменных,параметров методов и операций, состоит из фреймов
JVM heap = общий для всех нитей
JVM method area = хранит машинные коды
JVM constant pool = хранилище констант, своё для каждого класса
14
Любая инструкция содержит код выполняемой операции размером один байт (поэтому – байт-код)
Также может содержать дополнительные операнды
Для вычислений используются типы: int, long, float, double, reference, return address
Группы инструкций
◦ LOAD (local variable → operand stack)
◦ STORE (local variable operand stack
◦ Константы: CONST / LDC
◦ ADD / SUB / MUL / DIV / REM / NEG / SHR / SHL / USHR / AND / OR / XOR / INC / CMP
◦ Преобразования типов вроде I2L
◦ Стековые: POP / DUP / SWAP
15
См. в IDE
16
Группы инструкций
◦ Передача управления: GOTO / IFEQ / IFNE / IF<other> / TABLESWITCH / LOOKUPSWITCH
◦ Процедуры subroutine (не путать с методами): JSR / RET –устаревшие
17
На конкретную метку в коде
По условию или без него
SWITCH◦ TABLESWITCH – имеется массив, который по
(целому) значению ключа выдаёт конкретную метку
◦ LOOKUPSWITCH – выполняет последовательное сравнение ключа с заданными значениями и переход в случае совпадения
◦ Выбор зависит от степени «компактности» исходного switch
18
Группы инструкций
◦ Передача управления: GOTO / IFEQ / IFNE / IF<other> / TABLESWITCH / LOOKUPSWITCH
◦ Процедуры subroutine (не путать с методами): JSR / RET –устаревшие
◦ Массивы: NEWARRAY / ALOAD / ASTORE / ARRAYLENGTH
19
В JVM – специфический вид объектов
Тип элемента массива сохраняется в runtime (reified)
Ковариантны (covariant) с точки зрения типов элементов◦ То есть мы можем присвоить массиву объектов
массив строк:
◦ Object[] someArr = new String[1];
20
Когда SomeType<A> является подтипом SomeType<B>?◦ Invariant – значение типового аргумента должно
быть строго таким же, A = B (generics)
◦ Covariant – A должно быть подтипом B
◦ Contravariant – B должно быть подтипом A
21
Группы инструкций
◦ Передача управления: GOTO / IFEQ / IFNE / IF<other> / TABLESWITCH / LOOKUPSWITCH
◦ Процедуры subroutine (не путать с методами): JSR / RET –устаревшие
◦ Массивы: NEWARRAY / ALOAD / ASTORE / ARRAYLENGTH
◦ Объекты: NEW / GETFIELD / PUTFIELD / GETSTATIC / PUTSTATIC / INSTANCEOF / CHECKCAST
◦ Методы: INVOKEVIRTUAL / INVOKESTATIC / INVOKESPECIAL / INVOKEINTERFACE / RETURN
22
«Знают» свой runtime type◦ Compile-time type VS runtime type
Операции с типами: ◦ INSTANCEOF: даёт 0 или 1 в зависимости от
правильности типа
◦ CHECKCAST: бросает или нет ClassCastException в зависимости от правильности типа
Обращение идёт через ссылку (reference)◦ Поля
◦ Методы
23
Делается сравнительно просто
Операнды: ◦ Ссылка на объект в стеке
(только для GETFIELD / PUTFIELD)
◦ Индекс поля в команде
Результат – извлечённое поле
24
Нужный метод всегда указывается через пул констант, там содержится его имя в виде BaseClass.doSomething
Ссылка на константу – аргумент invoke
INVOKEVIRTUAL #index
◦ Берёт с вершины стека операндов будущий this, так называемый receiver (получатель)
◦ Оттуда же берёт аргументы
◦ Ищет нужный метод вначале внутри класса получателя (в соответствии с его реальным типом времени выполнения), потом его базовых классов, вызывает первый найденный
По факту это делается через таблицу виртуальных методов
25
Содержит в качестве ключа индекс метода и в качестве значения ссылку на реализацию метода (она может находиться как в текущем классе, так и в одном из базовых)
26
INVOKEINTERFACE #index
◦ Работает примерно как INVOKEVIRTUAL
◦ Основная разница в том, что базовый метод определён в интерфейсе, а не в классе
◦ Тоже работает через таблицу виртуальных методов, но чуть более сложным образом
27
INVOKESTATIC #index
◦ Не имеет получателя
◦ Берёт аргументы с вершины стека
◦ Вызывает именно тот метод, название которого было взято из пула констант
28
Вначале NEW
А уже потом INVOKESPECIAL <init>
29
INVOKESPECIAL #index
◦ К специальным методам относятся конструктор, вызов метода базового класса из метода производного класса, вызов закрытого метода (из метода того же класса)
◦ Конструктор в байт-коде имеет название вида MyClass.<init>
◦ В большинстве случаев INVOKESPECIAL вызывает тот метод, который указан непосредственно в ней (исключение составляют защищённые методы базового класса)
30
Типовые параметры стираются (erased)
Вместо их типа обычно подставляется Object (или граница для типового параметра T extends Something –см. пример)
Следствие: преобразование из Type<A> в Type<B> на самом деле не делает ничего (unchecked cast)
31
Многопоточные приложения…
32