Онбординг

Взлом кода JVM, часть II (Первый эксперимент)
Взлом кода JVM, часть III (структуры данных времени выполнения JVM)

Подавляющее большинство разработчиков программного обеспечения на языке Java и JVM пишут код, не задумываясь о том, как все работает внутри. Это менее распространено среди разработчиков языков C/C++, потому что им обычно требуется хотя бы базовое понимание моделей памяти и компьютерной архитектуры. Так что насчет Java или Scala — есть ли польза от понимания черного ящика?

Как оказалось, после написания кода и запуска его на рабочих серверах происходит множество интересных вещей: компиляция в байт-код, загрузка в JVM, работа с JIT, оптимизация, сборка мусора во время выполнения и т. д. Давайте углубимся в байт-код, чтобы увидеть, что на самом деле происходит. происходит более глубоко. Байт-код — это полезный инструмент для лучшего понимания того, как работает ваш код, реализации конкретных функций языка (исключения, полиморфизм и т. д.) и концепций высокопроизводительного кодирования JVM.

Я покажу, как появляется класс, а также выделение и инициализацию объекта и вызов метода класса. И самое главное, я предоставлю вам все необходимое для продолжения исследований и экспериментов.

Итак, давайте взглянем на следующий простой статический метод.

Компиляция этого Java-кода приводит нас к байт-коду JVM:

$ javac ByteCodeExamples.java
$ ls ByteCodeExamples.*
ByteCodeExamples.class ByteCodeExamples.java

ByteCodeExamples.classсодержит всю необходимую информацию для JVM для загрузки, инициализации и запуска методов из этого класса.

Чтобы понять, что происходит, прежде чем копнуть глубже, я открыл ByteCodeExamples.class с помощью шестнадцатеричного редактора. Вот полученный байт-код:

В первую очередь — класс знатно мал. Все, что вам нужно, есть на картинке выше! Это связано с тем, что Java был создан как язык для веб-приложений, поэтому классы иногда отправляются по сети. В результате инженеры решили, что каждый опкод (операция) должен иметь размер в один байт (отсюда и название bytecode). Во время выполнения программы JVM просит ClassLoader загрузить наш класс (ByteCodeExamples). Затем это HEX-представление, также называемое поток байт-кода, ищется (в ClassPath), загружается, проверяется и т. д.

Например, давайте посмотрим, что происходит по адресу 0xF4:

0xF4: 1A 1B 60 AC

Самое время начать с документации, которая всегда будет вашим лучшим другом.
Из полного документа Спецификация виртуальной машины Java давайте заглянем в Главу 7. Мнемоника кода операции по коду операции и найдем наш байт. коды:

Теперь, с небольшой интуицией и помощью спецификации, эти числа больше не являются чем-то загадкой. Даже без глубоких знаний байт-кода мы понимаем, что изначально загружаются два числа (iload, i для целого числа), суммируется (iдобавить), а затем возвращается результат (ireturn). Это описывает нашу функцию sum() из приведенного выше примера. Точно так же JVM видит и выполняет этот поток байт-кода. Здесь нет ничего сложного.

Теперь пойдем дальше…

Взлом кода JVM, часть II (Первый эксперимент)

ссылки:
Спецификация виртуальной машины Java®
Глава 7. Мнемоника кода операции по коду операции