Структура файла класса и инструкции по байт-коду

Java задняя часть переводчик API

структура файла класса

Содержимое, хранящееся в файле Class, называется ByteCode и включает в себя набор инструкций JVM и таблицу символов, а также некоторую другую вспомогательную информацию.

Файл класса представляет собой набор бинарных потоков на основе 8-битных байтов.Каждый элемент данных расположен в файле класса строго по порядку и компактно, без добавления какого-либо разделителя посередине.Практически все содержимое, хранящееся во всем файле класса, программа запущена, необходимые данные, пропусков нет.

При обнаружении элемента данных с пространством более 8 байтов он будет разделен на несколько 8-битных байтов для хранения в соответствии с первым старшим порядком.

В файле Class есть два типа данных: числа без знака и таблицы.

беззнаковое число

Числа без знака относятся к базовым типам данных, где u1, u2, u4, u8 представляют числа без знака в один байт, два байта...; числа без знака используются для описания чисел, индексных ссылок, количественных значений или UTF-8. закодированное строковое значение.

поверхность

Таблица — это составной тип данных, состоящий из нескольких чисел без знака или других таблиц в качестве элементов данных, обычно оканчивающихся на «_info», который используется для описания структуры данных файла класса.

Особенности: Экономьте место для хранения и повышайте производительность обработки

ClassFile { 
    u4 magic; 
    u2 minor_version; 
    u2 major_version; 
    u2 constant_pool_count; 
    cp_info constant_pool[constant_pool_count-1]; 
    u2 access_flags; 
    u2 this_class; 
    u2 super_class; 
    u2 interfaces_count; 
    u2 interfaces[interfaces_count]; 
    u2 fields_count; 
    field_info fields[fields_count]; 
    u2 methods_count; 
    method_info methods[methods_count]; 
    u2 attributes_count; 
    attribute_info attributes[attributes_count]; 
}
  • магическое число
  • Версия файла класса
  • постоянный пул
  • знак доступа
  • Индекс класса, индекс родительского класса, коллекция индексов интерфейса
  • Коллекция полевых таблиц
  • Коллекция таблиц методов
  • коллекция листов свойств

u2 означает беззнаковые 2 байта u4 означает беззнаковые 4 байта

Концепция и значение дизайна файла класса

1. Магия магических чисел

Единственная функция магического числа — определить, является ли файл файлом класса, который может быть принят виртуальной машиной. Магическое значение зафиксировано на 0xCAFEBABE и не изменится.

Докажите магический эффект

Создайте файл класса magic.class , содержимое которого является магическим тестом, запустите напрямуюjava magicработать:

84407@FantJ MINGW64 ~/Desktop
$ java magictest
▒▒▒▒: ▒▒▒▒▒▒▒▒ magictest ʱ▒▒▒▒ LinkageError
        java.lang.ClassFormatError: Incompatible magic value 1886741100 in class file magictest

Смысл ошибки таков: магия противоречит, и тогда дается десятичное число магического значения, то какое должно быть распознанное магическое десятичное число.

должно быть3405691582

Что ж, тогда я использую обычный файл Java, скомпилированный javac, для создания файла класса и просмотра его с помощью средства просмотра двоичных файлов:

младшая_версия, основная_версия

Четыре цифры после магического числа: представляют версию байт-кода, которые соответственно представляют вторичную и основную версии файла класса. Наиболее распространенные сегодня версии: jdk1.8:52 jdk1.7:51 jdk1.6:50

Соответствующий номер версии — 52, то есть jdk1.8.

Версия обратно совместима

2. constant_pool_count

Счетчик пула констант, значение равно количеству членов в таблице Constant_pool плюс 1, занимает два байта

3. Constant_pool[] постоянный пул

Инструкции виртуальной машины Java при выполнении полагаются на информацию о символах в таблице пула констант (constant_pool).

Все записи пула констант имеют следующий общий формат:

cp_info {
    u1 tag; 
    u1 info[]; 
}

Тег содержимого элемента info[] определяется типом. Допустимые типы и соответствующие значения тегов перечислены в следующей таблице.

постоянный тип ценность
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18
3.1 Структура CONSTANT_Class_info

Представляет класс или интерфейс

CONSTANT_Class_info {
    u1 tag; 
    u2 name_index;
}

name_indexДолжен быть действительным индексом в постоянном пуле

3.2 Структуры CONSTANT_Fieldref_info, CONSTANT_Methodref_info и CONSTANT_InterfaceMethodref_info

Поле:

CONSTANT_Fieldref_info {
    u1 tag; 
    u2 class_index; 
    u2 name_and_type_index; 
}

метод:

CONSTANT_Methodref_info { 
    u1 tag; 
    u2 class_index; 
    u2 name_and_type_index; 
}

Метод интерфейса:

CONSTANT_InterfaceMethodref_info {
    u1 tag; 
    u2 class_index; 
    u2 name_and_type_index; 
}

class_indexДолжен быть допустимым индексом для пула констант. Запись пула констант в этом индексе должна быть структурой CONSTANT_Class_info, представляющей класс или интерфейс, а текущее поле или метод является членом этого класса или интерфейса.

CONSTANT_Methodref_infoструктурныйclass_indexТип элемента должен быть классом (не интерфейсом).CONSTANT_InterfaceMethodref_infoструктурныйclass_indexТип элемента должен быть интерфейсом (не классом).CONSTANT_Fieldref_infoструктурныйclass_indexТип элемента может быть либо классом, либо интерфейсом.

name_and_type_indexДолжен быть допустимым индексом в пуле констант, представляющим имя и дескриптор текущего поля или метода. вCONSTANT_Fieldref_infoструктура, данный дескриптор должен быть字段Дескриптор. иCONSTANT_Methodref_infoиCONSTANT_InterfaceMethodref_infoУказанный дескриптор должен быть方法Дескриптор.

3.3 Структура CONSTANT_String_info

Структура, используемая для представления строки

CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}

string_indexДолжен быть допустимым индексом в пуле констант, в котором запись пула констант должна быть CONSTANT_Utf8_info Структура, представляющая набор последовательностей кодовых точек Unicode, которые в конечном итоге будут инициализированы как объект String.

3.4 Структуры CONSTANT_Integer_info и CONSTANT_Float_info

Числовые константы, представляющие 4 байта (int и float):

CONSTANT_Integer_info {
    u1 tag; 
    u4 bytes; 
} 
CONSTANT_Float_info { 
    u1 tag; 
    u4 bytes;
}
3.5 Структуры CONSTANT_Long_info и CONSTANT_Double_info

Числовая константа, представляющая 8 байтов (long и double)

CONSTANT_Long_info {
    u1 tag; 
    u4 high_bytes; 
    u4 low_bytes; 
} 

CONSTANT_Double_info { 
    u1 tag; 
    u4 high_bytes; 
    u4 low_bytes; 
}
3.6 Структура CONSTANT_NameAndType_info

Представляет поле или метод, но в отличие от трех структур, описанных выше, структура CONSTANT_NameAndType_info не идентифицирует класс или интерфейс, к которому она принадлежит.

CONSTANT_NameAndType_info { 
    u1 tag; 
    u2 name_index; 
    u2 descriptor_index;
}

name_indexЗначение записи должно быть допустимым индексом в пуле констант, а запись пула констант в этом индексе должна быть структурой CONSTANT_Utf8_info, которая либо представляет имя специального метода, либо допустимое поле или метод. Неполное имя (Unqualified Name) .

descriptor_indexЗначение записи должно быть допустимым индексом в пуле констант, а запись пула констант в этом индексе должна быть структурой CONSTANT_Utf8_info, представляющей допустимое поле или дескриптор метода.

3.7 Структура CONSTANT_Utf8_info

значение, используемое для представления строковых констант

CONSTANT_Utf8_info {
    u1 tag; 
    u2 length; 
    u1 bytes[length]; 
}

Содержимое структуры CONSTANT_Utf8_info:lengthатрибут определяет длину

3.8 Структура CONSTANT_MethodHandle_info

Представляет дескриптор метода

CONSTANT_MethodHandle_info {
    u1 tag;
    u1 reference_kind;
    u2 reference_index;
}

reference_kindЗначение элемента, которое должно быть от 1 до 9 включительно, определяет тип дескриптора метода.

  1. еслиreference_kindстоимость товара1(REF_getField)、2(REF_getStatic)、3(REF_putField)或4(REF_putStatic), то запись пула констант в индексе reference_index должна быть структурой CONSTANT_Fieldref_info, представляющей дескриптор метода, созданный полем.
  2. еслиreference_kindСтоимость предмета5(REF_invokeVirtual)、6(REF_invokeStatic)、7(REF_invokeSpecial)或8(REF_newInvokeSpecial), то постоянный пул находится вreference_indexэлемент в индексе должен бытьCONSTANT_Methodref_infoСтруктура, представляющая дескриптор метода, созданный методом или конструктором класса.
  3. еслиreference_kindСтоимость предмета9(REF_invokeInterface), то запись пула констант в индексе reference_index должна быть структурой CONSTANT_InterfaceMethodref_info, представляющей дескриптор метода, созданный методом интерфейса.
  4. еслиreference_kindСтоимость предмета5(REF_invokeVirtual)、6(REF_invokeStatic)、7(REF_invokeSpecial)或9(REF_invokeInterface), то метод, соответствующий дескриптору метода, не может быть методом инициализации() экземпляра или методом инициализации класса().
  5. еслиreference_kindСтоимость предмета8(REF_newInvokeSpecial), то метод, соответствующий дескриптору метода, должен быть методом инициализации() экземпляра.
3.9 Структура CONSTANT_MethodType_info

Тип метода представления

CONSTANT_MethodType_info { 
    u1 tag; 
    u2 descriptor_index; 
}
3.10 Структура CONSTANT_InvokeDynamic_info

Указывает метод начальной загрузки, используемый инструкцией invokedynamic, имя динамического вызова, используемое методом начальной загрузки, параметры и тип возврата запроса, а также, возможно, дополнительные константы, называемые последовательностью статических аргументов.

CONSTANT_InvokeDynamic_info { 
    u1 tag; 
    u2 bootstrap_method_attr_index; 
    u2 name_and_type_index; 
}

bootstrap_method_attr_indexЗначение элемента должно быть ссылкой на таблицу методов загрузки в текущем файле класса.bootstrap_methods[]Допустимый индекс в массиве.

name_and_type_indexЗначение записи должно быть действительным индексом в текущем пуле констант, в котором запись пула констант должна бытьCONSTANT_NameAndType_infoСтруктура, представляющая имя метода и дескриптор метода.

4. access_flags: флаги доступа

Флаги доступа, access_flags — это флаг маски, используемый для указания прав доступа и основных атрибутов класса или интерфейса. Диапазон значений и соответствующее значение флагов доступа показаны в следующей таблице.

название тэга ценность значение
ACC_PUBLIC 0x0001 Доступ к ним может осуществляться вне класса пакета.
ACC_FINAL 0x0010 Подклассы не допускаются.
ACC_SUPER 0x0020 Методы родительского класса, требующие специальной обработки при использовании invokespecial.
ACC_INTERFACE 0x0200 Идентификаторы определяют интерфейсы, а не классы.
ACC_ABSTRACT 0x0400 не может быть создан.
ACC_SYNTHETIC 0x1000 Идентифицирует код, который не создан из исходного кода Java.
ACC_ANNOTATION 0x2000 Определяет тип аннотации
ACC_ENUM 0x4000 Определяет типы перечисления

5. this_class: индекс класса

Значение this_class должно быть допустимым значением индекса для элемента в таблице Constant_pool.

— допустимое значение индекса для элемента в таблице Constant_pool, указывающее количество позиций, указывающих на пул констант.

6. super_class: индекс родительского класса

Указывает прямой родительский класс класса, определенного в файле классов. Если значение super_class в файле классов равно 0, то файл классов может определять только класс java.lang.Object, и это единственный класс без родительского сорт.

является допустимым значением индекса для элемента в таблице Constant_pool, указывающим количество позиций, указывающих на постоянный пул.

7. interfaces_count: счетчик интерфейсов

Указывает, что этот класс имеет несколько интерфейсов.

8. interfaces[]: таблица интерфейсов

Порядок интерфейсов, представленных элементами, такой же, как порядок интерфейсов, указанный в соответствующем исходном коде (слева направо), то есть interfaces[0] соответствует самому левому интерфейсу в исходном коде.

является допустимым значением индекса для элемента в таблице Constant_pool, указывающим количество позиций, указывающих на постоянный пул.

Указывает количество прямых родительских интерфейсов текущего класса или интерфейса

9. fields_count: счетчик полей

Указывает количество элементов массива fields[] текущего файла класса.

10. fields[]: таблица полей

Каждый член должен быть элементом данных структуры fields_info, описывающей все поля, объявленные текущим классом или интерфейсом, за исключением унаследованных от родительского класса или родительского интерфейса.

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

field_info {
    u2 access_flags; 
    u2 name_index;      //对常量池的一个有效索引
    u2 descriptor_index;     //对常量池的一个有效索引
    u2 attributes_count;     //当前字段的附加属性的数量
    attribute_info attributes[attributes_count];
}

access_flagsЗначение элемента — это флаг маски, определяющий права доступа и базовые свойства поля. Диапазон значений и соответствующее значение access_flags показаны в следующей таблице:

название тэга ценность инструкция
ACC_PUBLIC 0x0001 public, указывающий, что к полю можно получить доступ из любого пакета.
ACC_PRIVATE 0x0002 private, указывающее, что поле может быть вызвано только самим классом.
ACC_PROTECTED 0x0004 защищенный, указывающий, что поле может быть вызвано подклассами.
ACC_STATIC 0x0008 static, указывающий на статическое поле.
ACC_FINAL 0x0010 final, указывающий, что значение не может быть изменено после определения поля.
ACC_VOLATILE 0x0040 volatile, указывая на то, что поле является изменчивым.
ACC_TRANSIENT 0x0080 переходный, указывающий, что поле не будет сериализовано.
ACC_SYNTHETIC 0x1000 Поле представления автоматически генерируется компилятором.
ACC_ENUM 0x4000 enum, указывающий, что поле является типом перечисления.

attributesЗначение каждого члена таблицы должно бытьattribute结构, поле может иметь любое количество связанных свойств.

11. method_count: счетчик методов

Значение method_count представляет количество членов массива методов [] текущего файла класса, и каждый элемент в массиве методов [] является элементом данных структуры method_info.

12. method[]: таблица методов

Структура method_info может представлять все методы, определенные в классах и интерфейсах, включая методы экземпляра, методы класса, методы инициализации экземпляра и методы инициализации класса или интерфейса. Массив методов [] описывает только методы, объявленные в текущем классе или интерфейсе, за исключением методов, унаследованных от родительского класса или родительского интерфейса.

Каждый член массива методов [] должен быть элементом данных структуры method_info, представляющей полное описание метода в текущем классе или интерфейсе.

method_info { 
    u2 access_flags; 
    u2 name_index; 
    u2 descriptor_index; 
    u2 attributes_count; 
    attribute_info attributes[attributes_count]; 
}

access_flagsЗначением элемента является флаг маски, используемый для определения прав доступа и основных атрибутов текущего метода.Диапазон значений и соответствующее значение access_flags показаны в следующей таблице.

название тэга ценность инструкция
ACC_PUBLIC 0x0001 общедоступный, доступ к методу возможен из-за пределов пакета
ACC_PRIVATE 0x0002 private, доступ к методу возможен только в этом классе
ACC_PROTECTED 0x0004 защищенный, метод может быть доступен сам по себе и подклассам
ACC_STATIC 0x0008 статический, статический метод
ACC_FINAL 0x0010 final, метод не может быть переопределен (переопределен)
ACC_SYNCHRONIZED 0x0020 синхронизированный, метод синхронизируется монитором
ACC_BRIDGE 0x0040 мост, метод генерируется компилятором
ACC_VARARGS 0x0080 Представляет метод с параметром переменной длины.
ACC_NATIVE 0x0100 native, метод ссылается на собственный метод на языке, отличном от Java.
ACC_ABSTRACT 0x0400 абстрактный, метод не имеет конкретной реализации
ACC_STRICT 0x0800 strictfp, метод использует FP-строгий формат с плавающей запятой.
ACC_SYNTHETIC 0x1000 Метод отсутствует в исходном файле, он генерируется компилятором.

name_indexиdescriptor_indexДва свойства являются действительным индексом в пуле констант.attributes_countЗначение элемента представляет количество дополнительных свойств для этого метода.attributesЗначение каждого члена таблицы должно бытьattributeСтруктура, метод может иметь любое количество связанных с ним свойств.

13. attribute_count: счетчик атрибутов

Каждый элемент в таблице атрибутов является элементом данных структуры attribute_info.

Значение attribute_count указывает количество элементов в таблице атрибутов текущего файла класса.

14. attribute[]: таблица атрибутов

Значение каждого элемента в таблице атрибутов должно быть структурой attribute_info.В формате файла Class используются структура ClassFile, структура field_info, структура method_info и структура Code_attribute.Общий формат всех атрибутов следующий:

attribute_info {
    u2 attribute_name_index; 
    u4 attribute_length; 
    u1 info[attribute_length];
}

attribute_name_indexДолжен быть допустимым 16-битным беззнаковым индексом в константном пуле текущего файла класса. Представляет имя текущего свойства.

attribute_lengthЗначение элемента дает длину следующих байтов, не включаяattribute_name_indexиattribute_name_index6 байт для элемента.

14.1 Свойство ConstantValue

Атрибут ConstantValue — это атрибут фиксированной длины, расположенный в таблице атрибутов структуры field_info. Если поле является статическим типом (т. е. в элементе access_flags структуры field_info установлен флаг ACC_STATIC), это означает, что постоянному значению поля, представленному структурой field_info, будет присвоено значение, представленное его атрибутом ConstantValue, который также является константой, объявленной классом или интерфейсом.Часть инициализации поля (константное поле). Этот процесс происходит перед выполнением метода инициализации класса или интерфейса, на который делается ссылка.

ConstantValue_attribute { 
    u2 attribute_name_index; 
    u4 attribute_length; 
    u2 constantvalue_index; 
}

attribute_name_indexЗначение элемента должно быть действительным индексом в пуле констант.attribute_lengthСтоимость предмета зафиксирована на уровне 2.constantvalue_indexЗначение элемента должно быть действительным индексом в пуле констант.

14.2 Свойство кода

Атрибут Code — это атрибут переменной длины, расположенный в таблице атрибутов структуры method_info. Атрибут Code сохраняет инструкции виртуальной машины Java и соответствующую вспомогательную информацию только для одного метода, метода инициализации класса экземпляра или метода инициализации класса. Все реализации виртуальных машин Java должны уметь распознавать свойство Code. Если метод объявлен как родной или абстрактный тип, соответствующая структура method_info не может иметь чистый атрибут Code, в других случаях method_info должен иметь чистый атрибут Code.

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length; 
    u2 max_stack;
    u2 max_locals;
    u4 code_length; 
    u1 code[code_length]; 
    u2 exception_table_length; 
    {   u2 start_pc;
        u2 end_pc; 
        u2 handler_pc; 
        u2 catch_type; 
    } exception_table[exception_table_length]; 
    u2 attributes_count; 
    attribute_info attributes[attributes_count];
}

attribute_name_indexЗначение элемента должно быть допустимым индексом в пуле констант.attribute_lengthЗначение элемента указывает длину текущего атрибута, исключая первые 6 байтов.max_stackЗначение элемента дает максимальную глубину стека операндов текущего метода в любой момент времени выполнения.max_localsЗначение записи дает количество локальных переменных, выделенных в таблице локальных переменных, на которую ссылается текущий метод, включая локальные переменные, используемые для передачи аргументов при вызове этого метода. Максимальный индекс локальных переменных типа long и double равен max_locals-2, а максимальный индекс локальных переменных других типов — max_locals-1.code_lengthЭлемент дает количество байтов массива code[] текущего метода, а значение code_length должно быть больше 0, то есть массив code[] не может быть пустым.code[]Массив дает байт-код виртуальной машины Java, реализующий текущий метод.exception_table_lengthЗначение термина даетexception_table[]Количество членов массива.exception_table[]Каждый элемент массива представляетcode[]Обработчик исключений в массиве.exception_table[]В массиве порядок обработчиков исключений имеет смысл (его нельзя изменить произвольно).start_pcиend_pcЗначение двух элементов указывает допустимый диапазон обработчика исключений в массиве code[].handler_pcэлемент представляет начальную точку обработчика исключений еслиcatch_typeэлемент имеет значение, отличное от 0, тогда он должен быть допустимым индексом в пуле константattributes_countЗначение элемента дает количество членов таблицы атрибутов в свойстве Code. Значение каждого члена таблицы атрибутов должно быть структурой атрибута. Свойство Code может иметь любое количество связанных с ним необязательных свойств.

14.3 Свойства StackMapTable

Свойство StackMapTable — это свойство переменной длины, расположенное в таблице свойств свойства Code. Это свойство используется на этапе загрузки класса виртуальной машины.

StackMapTable_attribute { 
    u2 attribute_name_index;
    u4 attribute_length; 
    u2 number_of_entries; 
    stack_map_frame entries[number_of_entries];
}

attribute_name_indexЗначение элемента должно быть допустимым индексом в пуле констант.attribute_lengthЗначение элемента указывает длину текущего атрибута, исключая первые 6 байтов.number_of_entriesЗначение термина даетentriesКоличество участников в таблице. Каждый член таблицы Entries являетсяstack_map_frameЭлементы конструкции.entriesВ таблице указаны необходимыеstack_map_frameструктура.

... больше свойств здесь не размещено, их слишком много, просто проверьте официальную документацию, когда вам это нужно: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html #jvms-4.4

инструкции байт-кода

Инструкция виртуальной машины Java состоит из числа длиной в байт, представляющего значение конкретной операции (называемого кодом операции), за которым следуют операнды, представляющие параметры, необходимые для операции.

Длина кода операции составляет 1 байт, поэтому максимум составляет всего 256.

Постоянная инструкция push

Значение локальной переменной передается в стековую инструкцию

Сохранить верхнее значение стека в инструкции локальной переменной

широкая команда

Общие (нетипизированные) инструкции по работе со стеком

инструкция преобразования типа

Целочисленные операции

арифметика с плавающей запятой

Логические операции — операции сдвига

Логические операции — побитовые логические операции

Инструкции потока управления — инструкции условного перехода

Инструкции по управлению потоком — инструкции сравнения

Инструкции потока управления - инструкции безусловного перехода

Инструкции потока управления — Инструкции перехода к таблице

Инструкции потока управления - исключения и, наконец,

Инструкции по работе с объектами

инструкции по работе с массивом

инструкция вызова метода

инструкция возврата метода

инструкция синхронизации потоков

Ссылка на инструкцию: https://blog.csdn.net/web_code/article/details/12164733

Простой демонстрационный анализ

Test.java

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = a+b;
        System.out.println(c);
    }
}

javap -v Test.class

   #2 = Fieldref           #24.#25        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Methodref          #26.#27        // java/io/PrintStream.println:(I)V
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        10    //把10扩展成int入栈
         2: istore_1      //将栈顶int类型值保存到局部变量1中
         3: bipush        20     //把20扩展成int入栈
         5: istore_2     //将栈顶int类型值保存到局部变量2中
         6: iload_1      //从局部变量1中装载int类型值入栈  
         7: iload_2     //从局部变量2中装载int类型值入栈  
         8: iadd       // 将栈顶两int类型数相加,结果入栈。
         9: istore_3     //将栈顶int类型值保存到局部变量3中
        10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;获取静态字段的值。#2表示常量池的索引
        13: iload_3
        14: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V 运行时方法绑定调用方法。
        17: return      //void函数返回。