Формат байт-кода Dalvik

Общий дизайн

  • Модель машины и соглашения о вызовах призваны приблизительно имитировать распространенные реальные архитектуры и соглашения о вызовах в стиле C:
    • Машина работает на основе регистров, а размер кадров фиксируется при создании. Каждый фрейм состоит из определенного количества регистров (указывается методом), а также любых дополнительных данных, необходимых для выполнения метода, таких как (но не ограничиваясь) счетчик команд и ссылка на файл .dex, содержащий метод.
    • При использовании для битовых значений (например, целых чисел и чисел с плавающей запятой) регистры считаются 32-битными. Для 64-битных значений используются смежные пары регистров. Требования к выравниванию для пар регистров отсутствуют.
    • При использовании для ссылок на объекты регистры считаются достаточно широкими, чтобы вместить ровно одну такую ссылку.
    • В битовом представлении (Object) null == (int) 0.
    • Аргументы N метода попадают в последние N регистров фрейма вызова метода в порядке их объявления. Широкие аргументы занимают два регистра. Методам экземпляра в качестве первого аргумента передается ссылка this.
  • Единица хранения в потоке инструкций – это 16-битное беззнаковое значение. Некоторые биты в некоторых инструкциях игнорируются или должны быть равны нулю.
  • Инструкции не ограничены определенным типом. Например, инструкции, которые перемещают 32-битные значения регистров без интерпретации, не должны указывать, перемещают ли они целые числа или числа с плавающей запятой.
  • Для ссылок на строки, типы, поля и методы существуют отдельные пронумерованные и индексированные пулы констант.
  • Побитовые литеральные данные представлены в потоке инструкций.
  • На практике методу редко требуется более 16 регистров, а более восьми регистров требуются довольно часто, поэтому многие инструкции ограничены адресацией только первых 16 регистров. По возможности инструкции позволяют ссылаться на первые 256 регистров. Кроме того, некоторые инструкции имеют варианты, которые позволяют использовать гораздо большее количество регистров, включая пару универсальных инструкций move, которые могут обращаться к регистрам в диапазоне v0–v65535. Если вариант инструкции не позволяет обратиться к нужному регистру, содержимое регистра должно быть перемещено из исходного регистра в регистр с низким номером (до операции) и/или из регистра с низким номером в регистр с высоким номером (после операции).
  • Существует несколько псевдоинструкций, которые используются для хранения полезных данных переменной длины, на которые ссылаются обычные инструкции (например, fill-array-data). Такие инструкции никогда не должны встречаться в обычном потоке выполнения. Кроме того, инструкции должны располагаться по четным смещениям байткода (то есть быть выровнены по 4 байтам). Чтобы выполнить это требование, инструменты генерации dex-файлов должны добавлять дополнительную инструкцию nop в качестве разделителя, если в противном случае инструкция будет невыровненной. Наконец, хотя это и не обязательно, ожидается, что большинство инструментов будут добавлять эти инструкции в конце методов, поскольку в противном случае, скорее всего, потребуются дополнительные инструкции для перехода к ним.
  • При установке в работающую систему некоторые инструкции могут быть изменены, в том числе их формат, в рамках статической оптимизации связывания во время установки. Это позволяет быстрее выполнять запросы, когда связь уже известна. Рекомендуемые варианты приведены в документе с форматами инструкций. Обратите внимание, что это лишь рекомендации, а не обязательные требования.
  • Синтаксис и мнемоника:
    • Порядок аргументов: сначала целевой, затем исходный.
    • Некоторые операционные коды имеют суффикс, указывающий на тип данных, с которыми они работают:
      • 32-битные коды операций общего типа не помечаются.
      • 64-разрядные коды операций общего типа имеют суффикс -wide.
      • Опкоды, относящиеся к определенному типу, имеют суффикс, обозначающий тип (или его сокращение): -boolean, -byte, -char, -short, -int, -long, -float, -double, -object, -string, -class, -void.
    • Некоторые коды операций имеют уточняющий суффикс, чтобы различать идентичные операции с разными макетами инструкций или параметрами. Эти суффиксы отделяются от основных названий косой чертой (/) и в основном существуют для того, чтобы обеспечить однозначное сопоставление со статическими константами в коде, который генерирует и интерпретирует исполняемые файлы (то есть чтобы уменьшить двусмысленность для людей).
    • В описаниях ниже ширина значения (например, диапазон константы или количество регистров, к которым можно обратиться) выделяется с помощью символа на каждые четыре бита ширины.
    • Например, в инструкции "move-wide/from16 vAA, vBBBB":
      • "move" – это базовый код операции, указывающий на базовую операцию (перемещение значения регистра).
      • "wide" – это суффикс названия, указывающий на то, что операция выполняется с 64-битными данными.
      • "from16" – суффикс кода операции, указывающий на вариант, в котором в качестве источника используется ссылка на 16-битный регистр.
      • vAA – целевой регистр (подразумевается операцией; правило гласит, что целевые аргументы всегда указываются первыми), который должен находиться в диапазоне v0–v255.
      • "vBBBB" – исходный регистр, который должен находиться в диапазоне v0–v65535.
  • Подробную информацию о различных форматах инструкций (перечисленных в разделе Op & Format), а также о синтаксисе кодов операций можно найти в документе о форматах инструкций.
  • Подробную информацию о том, как байт-код вписывается в общую картину, можно найти в документе о формате файла .dex.

Сводка набора байт-кода

Оператор и формат Мнемоника / синтаксис Аргументы Описание
00 10x nop   Циклы утилизации отходов.

Примечание. Псевдоинструкции, содержащие данные, помечаются этим кодом операции. В этом случае старший байт единицы кода операции указывает на тип данных. См. разделы "Формат packed-switch-payload", "Формат sparse-switch-payload" и "Формат fill-array-data-payload" ниже.

01 12x move vA, vB A: регистр назначения (4 бита)
B: исходный регистр (4 бита)
Перемещать содержимое одного реестра, не относящегося к объектам, в другой.
02 22x move/from16 vAA, vBBBB A: регистр назначения (8 бит)
B: регистр источника (16 бит)
Перемещать содержимое одного реестра, не относящегося к объектам, в другой.
03 32x move/16 vAAAA, vBBBB A: регистр назначения (16 бит)
B: исходный регистр (16 бит)
Перемещать содержимое одного реестра, не относящегося к объектам, в другой.
04 12x move-wide vA, vB A: пара регистров назначения (4 бита)
B: пара исходных регистров (4 бита)
Переместить содержимое одной пары регистров в другую.

Примечание. Переход от vN к vN-1 или vN+1 допустим, поэтому в реализациях необходимо предусмотреть чтение обеих половин пары регистров перед записью.

05 22x move-wide/from16 vAA, vBBBB A: пара регистров назначения (8 бит)
B: пара исходных регистров (16 бит)
Переместить содержимое одной пары регистров в другую.

Примечание. О чем важно помнить, описано в разделе move-wide выше.

06 32x move-wide/16 vAAAA, vBBBB A: пара регистров назначения (16 бит)
B: пара регистров источника (16 бит)
Переместить содержимое одной пары регистров в другую.

Примечание. О чем важно помнить, описано в разделе move-wide выше.

07 12x move-object vA, vB A: регистр назначения (4 бита)
B: исходный регистр (4 бита)
Переместить содержимое одного реестра объектов в другой.
08 22x move-object/from16 vAA, vBBBB A: регистр назначения (8 бит)
B: регистр источника (16 бит)
Переместить содержимое одного регистра, содержащего объект, в другой.
09 32x move-object/16 vAAAA, vBBBB A: регистр назначения (16 бит)
B: исходный регистр (16 бит)
Переместить содержимое одного реестра объектов в другой.
0a 11x move-result vAA Регистр назначения A: (8 бит) Переместить однословный результат, не являющийся объектом, из последнего запроса invoke-kind в указанный регистр. Эта инструкция должна следовать сразу за инструкцией invoke-kind, результат которой (одно слово, не объект) не должен игнорироваться. В любом другом месте она будет недействительна.
0b 11x move-result-wide vAA A: – пара регистров назначения (8 бит); Перемещает результат двойного слова из последнего invoke-kind в указанную пару регистров. Это нужно сделать сразу после инструкции invoke-kind, результат которой (двойное слово) не должен игнорироваться. В любом другом месте это будет недопустимо.
0c 11x move-result-object vAA Регистр назначения A: (8 бит) Переместить объект, полученный в результате последнего действия invoke-kind, в указанный регистр. Это нужно сделать в виде инструкции сразу после invoke-kind или filled-new-array, результат которой не игнорируется. В других местах это недопустимо.
0d 11x move-exception vAA Регистр назначения A: (8 бит) Сохраняет только что пойманное исключение в указанном регистре. Это должна быть первая инструкция любого обработчика исключений, пойманное исключение которого не должно игнорироваться. Эта инструкция должна всегда быть первой инструкцией обработчика исключений. В любом другом месте она недопустима.
0e 10x return-void   Возвращает значение из метода void.
0f 11x return vAA Регистр возвращаемого значения A: (8 бит) Возврат из метода, возвращающего значение, которое не является объектом и имеет одинарную ширину (32 бита).
10 11x return-wide vAA Пара регистров возвращаемого значения A: (8 бит) Возврат из метода, возвращающего значение двойной ширины (64-битное).
11 11x return-object vAA Регистр возвращаемого значения A: (8 бит) Возвращает значение из метода, возвращающего объект.
12 11n const/4 vA, #+B A: регистр назначения (4 бита)
B: знаковое целое число (4 бита)
Перемещает заданное литеральное значение (с расширением знака до 32 бит) в указанный регистр.
13 21 const/16 vAA, #+BBBB A: регистр назначения (8 бит)
B: знаковое целое число (16 бит)
Перемещает заданное литеральное значение (с расширением знака до 32 бит) в указанный регистр.
14 31i const vAA, #+BBBBBBBB A: регистр назначения (8 бит)
B: произвольная 32-битная константа
Перемещает заданное литеральное значение в указанный регистр.
15 21h const/high16 vAA, #+BBBB0000 A: регистр назначения (8 бит)
B: знаковое целое число (16 бит)
Перемещает заданное литеральное значение (дополненное справа нулями до 32 бит) в указанный регистр.
16 21 const-wide/16 vAA, #+BBBB A: регистр назначения (8 бит)
B: знаковое целое число (16 бит)
Перемещает заданное литеральное значение (с расширением знака до 64 бит) в указанную пару регистров.
17 31i const-wide/32 vAA, #+BBBBBBBB A: регистр назначения (8 бит)
B: целое число со знаком (32 бита)
Перемещает заданное литеральное значение (с расширением знака до 64 бит) в указанную пару регистров.
18 51l const-wide vAA, #+BBBBBBBBBBBBBBBB A: регистр назначения (8 бит)
B: произвольная константа двойной ширины (64 бита)
Переместить заданное литеральное значение в указанную пару регистров.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: регистр назначения (8 бит)
B: знаковое целое число (16 бит)
Перемещает заданное литеральное значение (справа дополненное нулями до 64 бит) в указанную пару регистров.
1a 21c const-string vAA, string@BBBB A: регистр назначения (8 бит)
B: индекс строки
Перемещает ссылку на строку, указанную заданным индексом, в указанный регистр.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: регистр назначения (8 бит)
B: индекс строки
Перемещает ссылку на строку, указанную заданным индексом, в указанный регистр.
1c, 21c const-class vAA, type@BBBB A: регистр назначения (8 бит)
B: индекс типа
Перемещает ссылку на класс, указанный заданным индексом, в указанный регистр. Если указанный тип является примитивным, будет сохранена ссылка на вырожденный класс примитивного типа.
1 день, 11 раз monitor-enter vAA A: регистр ссылок (8 бит) Получите монитор для указанного объекта.
1e 11x monitor-exit vAA A: – регистр, содержащий ссылку (8 бит). Освободите монитор для указанного объекта.

Примечание. Если эта инструкция должна вызвать исключение, она должна сделать это так, как если бы указатель уже прошел инструкцию. Можно считать, что инструкция успешно выполняется, а исключение генерируется после нее, но до следующей. Это определение позволяет методу использовать универсальный блок очистки монитора (например, finally) в качестве очистки монитора для самого этого блока, чтобы обрабатывать произвольные исключения, которые могут быть вызваны исторической реализацией Thread.stop(), сохраняя при этом надлежащую гигиену монитора.

1f 21c check-cast vAA, type@BBBB A: регистр с ссылкой (8 бит)
B: индекс типа (16 бит)
Выбрасывает исключение ClassCastException, если ссылку в указанном регистре нельзя привести к указанному типу.

Примечание. Поскольку A всегда должен быть ссылкой (а не примитивным значением), во время выполнения обязательно возникнет ошибка (то есть будет сгенерировано исключение), если B относится к примитивному типу.

20 22c instance-of vA, vB, type@CCCC A: регистр назначения (4 бита)
B: регистр со ссылкой (4 бита)
C: индекс типа (16 бит)
Сохраняет в указанном регистре назначения 1, если указанная ссылка является экземпляром заданного типа, или 0, если нет.

Примечание. Поскольку B всегда должен быть ссылкой (а не примитивным значением), примитивный тип C всегда приведет к сохранению 0.

21 12x array-length vA, vB A: регистр назначения (4 бита)
B: регистр, содержащий ссылку на массив (4 бита)
Сохраняет в указанном регистре длину массива, выраженную в записях.
22 21c new-instance vAA, type@BBBB A: регистр назначения (8 бит)
B: индекс типа
Создает новый экземпляр указанного типа и сохраняет ссылку на него в целевом объекте. Тип должен относиться к классу, не являющемуся массивом.
23 22c new-array vA, vB, type@CCCC A: регистр назначения (4 бита)
B: регистр размера
C: индекс типа
Создает новый массив указанного типа и размера. Тип должен быть массивом.
24 35c filled-new-array {vC, vD, vE, vF, vG}, type@BBBB A: размер массива и количество слов в аргументе (4 бита)
B: индекс типа (16 бит)
C..G: регистры аргументов (по 4 бита)
Создает массив заданного типа и размера, заполняя его указанным содержимым. Тип должен быть типом массива. Массив должен содержать только отдельные слова (то есть не массивы long или double, но ссылочные типы допустимы). Созданный экземпляр сохраняется как "результат" так же, как инструкции вызова метода сохраняют свои результаты, поэтому созданный экземпляр должен быть перемещен в регистр с помощью непосредственно следующей инструкции move-result-object (если он должен быть использован).
25 3rc filled-new-array/range {vCCCC .. vNNNN}, type@BBBB A: размер массива и количество слов в аргументе (8 бит)
B: индекс типа (16 бит)
C: регистр первого аргумента (16 бит)
N = A + C - 1
Создает массив заданного типа и размера, заполняя его предоставленным содержимым. Уточнения и ограничения такие же, как и для поля filled-new-array (описано выше).
26 31t fill-array-data vAA, +BBBBBBBB (с дополнительными данными, как указано ниже в разделе fill-array-data-payload Format) A: ссылка на массив (8 бит)
B: знаковое смещение "ветви" к псевдоинструкции данных таблицы (32 бита)
Заполняет указанный массив данными. Ссылка должна указывать на массив примитивов, а таблица данных должна соответствовать ему по типу и содержать не больше элементов, чем может поместиться в массиве. Массив может быть больше таблицы, и в этом случае будут заданы только начальные элементы массива, а остальные останутся без изменений.
27 11x бросить vAA A: регистр исключений (8 бит)
Вызвать указанное исключение.
28 10t goto +AA A: смещение подписанной ветви (8 бит) Безусловный переход к указанной инструкции.

Примечание. Смещение ветви не должно быть равно 0. (Цикл вращения может быть создан законным образом с помощью goto/32 или путем включения nop в качестве цели перед ветвью.)

29 20t goto/16 +AAAA A: смещение перехода со знаком (16 бит)
Безусловный переход к указанной инструкции.

Примечание. Смещение ветви не должно быть равно 0. (Цикл вращения может быть создан законным образом с помощью goto/32 или путем включения nop в качестве цели перед ветвью.)

2a 30t goto/32 +AAAAAAAA A: смещение подписанного перехода (32 бита)
Безусловный переход к указанной инструкции.
2b 31t packed-switch vAA, +BBBBBBBB (дополнительные данные указаны ниже в разделе "packed-switch-payload Формат") A: регистр для тестирования
B: смещение подписанной ветви к псевдоинструкции данных таблицы (32 бита)
Переход к новой инструкции на основе значения в заданном регистре с использованием таблицы смещений, соответствующих каждому значению в определенном целочисленном диапазоне, или переход к следующей инструкции, если совпадений нет.
2c 31t sparse-switch vAA, +BBBBBBBB (с дополнительными данными, как указано ниже в разделе "Формат sparse-switch-payload") A: регистр для тестирования
B: псевдоинструкция со знаком "ветвь" для смещения данных таблицы (32 бита)
Перейти к новой инструкции на основе значения в заданном регистре, используя упорядоченную таблицу пар "значение-смещение", или перейти к следующей инструкции, если совпадений нет.
2д..31 23x cmpkind vAA, vBB, vCC
2d: cmpl-float (lt bias)
2e: cmpg-float (gt bias)
2f: cmpl-double (lt bias)
30: cmpg-double (gt bias)
31: cmp-long
A:регистр назначения (8 бит);
B: первый исходный регистр или пара;
C: второй исходный регистр или пара.
Выполняет указанное сравнение чисел с плавающей запятой или long, задавая для a значение 0, если b == c, 1, если b > c, или -1, если b < c. Параметр "bias", указанный для операций с плавающей запятой, определяет, как обрабатываются сравнения NaN: инструкции "gt bias" возвращают 1 для сравнений NaN, а инструкции "lt bias" возвращают -1.

Например, чтобы проверить, является ли значение с плавающей запятой x < y, рекомендуется использовать cmpg-float. Результат -1 указывает на то, что проверка прошла успешно, а другие значения – на то, что она не удалась из-за допустимого сравнения или из-за того, что одно из значений было NaN.

32..37 22t if-test vA, vB, +CCCC
32: if-eq
33: if-ne
34: if-lt
35: if-ge
36: if-gt
37: if-le
A: первый регистр для тестирования (4 бита)
B: второй регистр для тестирования (4 бита)
C: смещение перехода со знаком (16 бит)
Переход к указанному пункту назначения, если значения двух регистров соответствуют заданным условиям.

Примечание. Смещение ветви не должно быть равно 0. (Цикл ожидания может быть создан либо путем ветвления вокруг обратного goto, либо путем включения nop в качестве цели перед ветвлением.)

38..3d 21t if-testz vAA, +BBBB
38: if-eqz
39: if-nez
3a: if-ltz
3b: if-gez
3c: if-gtz
3d: if-lez
A: регистр для тестирования (8 бит)
B: смещение подписанного перехода (16 бит)
Переход к указанному пункту назначения, если значение указанного регистра сравнивается с нулем в соответствии с заданными условиями.

Примечание. Смещение ветви не должно быть равно 0. (Цикл ожидания может быть создан либо путем ветвления вокруг обратного goto, либо путем включения nop в качестве цели перед ветвлением.)

3e..43 10x (не используется)   (unused)
44..51 23x arrayop vAA, vBB, vCC
44: aget
45: aget-wide
46: aget-object
47: aget-boolean
48: aget-byte
49: aget-char
4a: aget-short
4b: aput
4c: aput-wide
4d: aput-object
4e: aput-boolean
4f: aput-byte
50: aput-char
51: aput-short
A: регистр или пара значений; может быть источником или назначением (8 бит)
B: регистр массива (8 бит)
C: индексный регистр (8 бит)
Выполняет указанную операцию с массивом по указанному индексу заданного массива, загружая или сохраняя значение в регистре значений.
52..5f 22c iinstanceop vA, vB, field@CCCC
52: iget
53: iget-wide
54: iget-object
55: iget-boolean
56: iget-byte
57: iget-char
58: iget-short
59: iput
5a: iput-wide
5b: iput-object
5c: iput-boolean
5d: iput-byte
5e: iput-char
5f: iput-short
регистр или пара значений A:; может быть источником или получателем (4 бита)
регистр объекта B: (4 бита)
индекс ссылки на поле экземпляра C: (16 бит)
Выполните операцию с полем экземпляра объекта, используя определенное поле, загружая или сохраняя значение в регистре значений.

Примечание. Эти операционные коды подходят для статического связывания, при котором аргумент поля заменяется на более прямое смещение.

60..6d 21c sstaticop vAA, field@BBBB
60: sget
61: sget-wide
62: sget-object
63: sget-boolean
64: sget-byte
65: sget-char
66: sget-short
67: sput
68: sput-wide
69: sput-object
6a: sput-boolean
6b: sput-byte
6c: sput-char
6d: sput-short
A:регистр или пара значений; может быть источником или получателем (8 бит)
B: индекс статического поля (16 бит)
Выполните операцию со статическим полем идентифицированного объекта, используя идентифицированное статическое поле, загружая или сохраняя значение в регистре значений.

Примечание. Эти коды операций можно использовать для статической компоновки, изменив аргумент поля на более прямое смещение.

6e..72 35c invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB
6e: invoke-virtual
6f: invoke-super
70: invoke-direct
71: invoke-static
72: invoke-interface
A: количество слов в аргументе (4 бита)
B: индекс ссылки на метод (16 бит)
C..G: регистры аргументов (по 4 бита)
Вызовите указанный метод. Результат (если он есть) может быть сохранен с помощью соответствующего варианта move-result* в качестве следующей инструкции.

invoke-virtual используется для вызова обычного виртуального метода, который не является методом static, private или конструктором.

Если method_id ссылается на метод класса, не являющегося интерфейсом, invoke-super используется для вызова виртуального метода ближайшего суперкласса (а не метода с тем же именем method_id в вызывающем классе). Действуют те же ограничения, что и для метода invoke-virtual.

В файлах Dex версии 037 или более поздней, если method_id относится к методу интерфейса, invoke-super используется для вызова наиболее конкретной версии этого метода, определенной в интерфейсе и не переопределенной. Действуют те же ограничения, что и для метода invoke-virtual. В файлах Dex версий ниже 037 наличие интерфейса method_id недопустимо и не определено.

invoke-direct используется для вызова прямого метода, отличного от static (то есть метода экземпляра, который по своей природе нельзя переопределить, а именно метода экземпляра private или конструктора).

invoke-static используется для вызова метода static (который всегда считается прямым методом).

invoke-interface используется для вызова метода interface, то есть для объекта, конкретный класс которого неизвестен, с помощью method_id, ссылающегося на interface.

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

73 10x (не используется)   (unused)
74..78 3rc invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB
74: invoke-virtual/range
75: invoke-super/range
76: invoke-direct/range
77: invoke-static/range
78: invoke-interface/range
A: Количество слов в аргументе (8 бит).
B: Индекс ссылки на метод (16 бит).
C: Регистр первого аргумента (16 бит).
N = A + C - 1
Вызовите указанный метод. Подробную информацию, предостережения и рекомендации можно найти в первом описании выше.invoke-kind
79..7a 10x (не используется)   (не используется)
7b..8f 12x unop vA, vB
7b: neg-int
7c: not-int
7d: neg-long
7e: not-long
7f: neg-float
80: neg-double
81: int-to-long
82: int-to-float
83: int-to-double
84: long-to-int
85: long-to-float
86: long-to-double
87: float-to-int
88: float-to-long
89: float-to-double
8a: double-to-int
8b: double-to-long
8c: double-to-float
8d: int-to-byte
8e: int-to-char
8f: int-to-short
A: регистр или пара регистров назначения (4 бита)
B: регистр или пара регистров источника (4 бита)
Выполните указанную унарную операцию с исходным регистром, сохранив результат в целевом регистре.
90..af 23x binop vAA, vBB, vCC
90: add-int
91: sub-int
92: mul-int
93: div-int
94: rem-int
95: and-int
96: or-int
97: xor-int
98: shl-int
99: shr-int
9a: ushr-int
9b: add-long
9c: sub-long
9d: mul-long
9e: div-long
9f: rem-long
a0: and-long
a1: or-long
a2: xor-long
a3: shl-long
a4: shr-long
a5: ushr-long
a6: add-float
a7: sub-float
a8: mul-float
a9: div-float
aa: rem-float
ab: add-double
ac: sub-double
ad: mul-double
ae: div-double
af: rem-double
A: регистр или пара регистров назначения (8 бит)
B: первый регистр или пара регистров источника (8 бит)
C: второй регистр или пара регистров источника (8 бит)
Выполнить указанную двоичную операцию с двумя исходными регистрами и сохранить результат в целевом регистре.

Примечание. В отличие от других математических операций -long (которые принимают пары регистров в качестве первого и второго источника), shl-long, shr-long и ushr-long принимают пару регистров в качестве первого источника (значение, которое нужно сдвинуть), но один регистр в качестве второго источника (расстояние сдвига).

b0..cf 12x binop/2addr vA, vB
b0: add-int/2addr
b1: sub-int/2addr
b2: mul-int/2addr
b3: div-int/2addr
b4: rem-int/2addr
b5: and-int/2addr
b6: or-int/2addr
b7: xor-int/2addr
b8: shl-int/2addr
b9: shr-int/2addr
ba: ushr-int/2addr
bb: add-long/2addr
bc: sub-long/2addr
bd: mul-long/2addr
be: div-long/2addr
bf: rem-long/2addr
c0: and-long/2addr
c1: or-long/2addr
c2: xor-long/2addr
c3: shl-long/2addr
c4: shr-long/2addr
c5: ushr-long/2addr
c6: add-float/2addr
c7: sub-float/2addr
c8: mul-float/2addr
c9: div-float/2addr
ca: rem-float/2addr
cb: add-double/2addr
cc: sub-double/2addr
cd: mul-double/2addr
ce: div-double/2addr
cf: rem-double/2addr
A:Целевой адрес и первый регистр источника или пара регистров (4 бита)
B:Второй регистр источника или пара регистров (4 бита)
Выполните указанную бинарную операцию с двумя исходными регистрами и сохраните результат в первом из них.

Примечание. В отличие от других математических операций -long/2addr, которые используют пары регистров как для первого, так и для второго источника, команды shl-long/2addr, shr-long/2addr и ushr-long/2addr используют пару регистров для первого источника (значение, которое нужно сдвинуть), но один регистр для второго источника (расстояние сдвига).

d0..d7 22s binop/lit16 vA, vB, #+CCCC
d0: add-int/lit16
d1: rsub-int (обратное вычитание)
d2: mul-int/lit16
d3: div-int/lit16
d4: rem-int/lit16
d5: and-int/lit16
d6: or-int/lit16
d7: xor-int/lit16
A: регистр назначения (4 бита)
B: исходный регистр (4 бита)
C: константа типа signed int (16 бит)
Выполняет указанную бинарную операцию над указанным регистром (первый аргумент) и литеральным значением (второй аргумент), сохраняя результат в целевом регистре.

Примечание. У rsub-int нет суффикса, поскольку эта версия является основным кодом операции в своем семействе. Подробную информацию о семантике этого поля вы найдете ниже.

d8..e2 22b binop/lit8 vAA, vBB, #+CC
d8: add-int/lit8
d9: rsub-int/lit8
da: mul-int/lit8
db: div-int/lit8
dc: rem-int/lit8
dd: and-int/lit8
de: or-int/lit8
df: xor-int/lit8
e0: shl-int/lit8
e1: shr-int/lit8
e2: ushr-int/lit8
A: целевой регистр (8 бит)
B: исходный регистр (8 бит)
C: константа со знаком (8 бит)
Выполняет указанную бинарную операцию над указанным регистром (первый аргумент) и литеральным значением (второй аргумент), сохраняя результат в целевом регистре.

Примечание. Подробные сведения о семантике rsub-int приведены ниже.

e3..f9 10x (unused)   (unused)
fa 45cc invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: количество слов в аргументе (4 бита)
B: индекс ссылки на метод (16 бит)
C: получатель (4 бита)
D..G: регистры аргументов (по 4 бита)
H: индекс ссылки на прототип (16 бит)
Вызов полиморфного метода с указанной сигнатурой. Результат (если он есть) может быть сохранен с подходящим вариантом move-result* в качестве следующей инструкции.

Ссылка на метод должна указывать на полиморфный метод, например java.lang.invoke.MethodHandle.invoke или java.lang.invoke.MethodHandle.invokeExact.

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

В описании прототипа указаны типы аргументов и ожидаемый тип возвращаемого значения.

При выполнении байт-кода invoke-polymorphic могут возникать исключения. Исключения описаны в документации API для вызываемого полиморфного метода подписи.

Присутствует в файлах DEX начиная с версии 038.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: количество слов в аргументе (8 бит)
B: индекс ссылки на метод (16 бит)
C: получатель (16 бит)
H: индекс ссылки на прототип (16 бит)
N = A + C - 1
Вызовите указанный дескриптор метода. Подробную информацию вы найдете в описании invoke-polymorphic выше.

Присутствует в файлах Dex начиная с версии 038.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB A: количество слов в аргументе (4 бита)
B: индекс ссылки на место вызова (16 бит)
C..G: регистры аргументов (по 4 бита)
Разрешает и вызывает указанный сайт звонка. Результат вызова (если он есть) может быть сохранен с помощью соответствующего варианта move-result* в качестве следующей инструкции.

Эта инструкция выполняется в два этапа: разрешение и вызов сайта вызова.

Проверка разрешения сайта звонка определяет, связан ли указанный сайт звонка с экземпляром java.lang.invoke.CallSite. В противном случае метод загрузчика для указанного сайта вызова вызывается с использованием аргументов, присутствующих в файле DEX (см. call_site_item). Метод связывания при загрузке возвращает экземпляр java.lang.invoke.CallSite, который затем будет связан с указанным местом вызова, если связь отсутствует. Если связь уже установлена другим потоком, выполнение инструкции продолжится с первым связанным экземпляром java.lang.invoke.CallSite.

Вызов сайта для звонка выполняется в целевом объекте java.lang.invoke.MethodHandle разрешенного экземпляра java.lang.invoke.CallSite. Целевой метод вызывается при выполнении инструкции invoke-polymorphic (описанной выше) с использованием дескриптора метода и аргументов инструкции invoke-custom в качестве аргументов для точного вызова дескриптора метода.

Исключения, вызванные методом загрузчика, оборачиваются в java.lang.BootstrapMethodError. BootstrapMethodError также возникает, если:
  • метод загрузчика не возвращает экземпляр java.lang.invoke.CallSite.
  • Возвращаемый объект java.lang.invoke.CallSite имеет целевой дескриптор метода null.
  • целевой объект дескриптора метода не относится к запрошенному типу.
Присутствует в файлах Dex начиная с версии 038.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: Количество слов в аргументе (8 бит)
B: Индекс ссылки на место вызова (16 бит)
C: Регистр первого аргумента (16 бит)
N = A + C - 1
Разрешение и вызов сайта вызова. Подробную информацию вы найдете в описании invoke-custom выше.

Присутствует в файлах DEX начиная с версии 038.
fe 21c const-method-handle vAA, method_handle@BBBB A: Регистр назначения (8 бит)
B: Индекс дескриптора метода (16 бит)
Перемещает ссылку на дескриптор метода, указанный заданным индексом, в указанный регистр.

Присутствует в файлах DEX начиная с версии 039.
ff 21c const-method-type vAA, proto@BBBB A: регистр назначения (8 бит)
B: ссылка на прототип метода (16 бит)
Перемещает ссылку на прототип метода, указанный заданным индексом, в указанный регистр.

Присутствует в файлах DEX начиная с версии 039.

Формат полезной нагрузки с коммутацией пакетов

Название Формат Описание
ident ushort = 0x0100 идентификация псевдооперационного кода;
размер ushort количество записей в таблице;
first_key ПРХВ первое (и наименьшее) значение оператора switch;
целевые объекты int[] список из size относительных целевых ветвей. Целевые адреса относятся к адресу кода операции переключения, а не к адресу этой таблицы.

Примечание. Общее количество единиц кода для экземпляра этой таблицы – (size * 2) + 4.

Формат полезной нагрузки sparse-switch

Название Формат Описание
ident ushort = 0x0200 идентификация псевдооперационного кода;
размер ushort количество записей в таблице;
ключи int[] список значений ключей size, отсортированный по возрастанию;
целевые объекты int[] список относительных целевых ветвей size, каждая из которых соответствует значению ключа с тем же индексом. Целевые адреса относятся к адресу кода операции переключения, а не к адресу этой таблицы.

Примечание. Общее количество единиц кода для экземпляра этой таблицы – (size * 4) + 2.

Формат полезной нагрузки fill-array-data-payload

Название Формат Описание
ident ushort = 0x0300 идентификация псевдооперационного кода;
element_width ushort количество байтов в каждом элементе;
размер uint количество элементов в таблице
данные ubyte[] значения данных

Примечание. Общее количество единиц кода для экземпляра этой таблицы – (size * element_width + 1) / 2 + 4.

Сведения о математической операции

Примечание. Операции с плавающей запятой должны выполняться в соответствии с правилами IEEE 754 с использованием округления до ближайшего и постепенного переполнения, если не указано иное.

Код операции Семантика C Примечания
neg-int int32 a;
int32 result = -a;
Унарное дополнение до двух.
not-int int32 a;
int32 result = ~a;
Унарное дополнение до единицы.
neg-long int64 a;
int64 result = -a;
Унарное дополнение до двух.
недолго int64 a;
int64 result = ~a;
Унарное дополнение до единицы.
neg-float float a;
float result = -a;
Отрицание числа с плавающей запятой.
neg-double double a;
double result = -a;
Отрицание числа с плавающей запятой.
int-to-long int32 a;
int64 result = (int64) a;
Подпишите расширение int32 в int64.
int-to-float int32 a;
float result = (float) a;
Конвертация int32 в float с округлением до ближайшего целого числа. Это приводит к потере точности для некоторых значений.
int-to-double int32 a;
double result = (double) a;
Конвертация int32 в double.
long-to-int int64 a;
int32 result = (int32) a;
Усечение текста int64 до int32.
long-to-float int64 a;
float result = (float) a;
Конвертация int64 в float с округлением до ближайшего целого числа. Это приводит к потере точности для некоторых значений.
long-to-double int64 a;
double result = (double) a;
Преобразование int64 в double с округлением к ближайшему. Это приводит к потере точности для некоторых значений.
float-to-int float a;
int32 result = (int32) a;
Конвертация float в int32 с округлением до нуля. NaN и -0.0 (отрицательный ноль) преобразуются в целое число 0. Бесконечности и значения, которые слишком велики, чтобы быть представленными, преобразуются в 0x7fffffff или -0x80000000 в зависимости от знака.
float-to-long float a;
int64 result = (int64) a;
Конвертация float в int64 с округлением до нуля. Здесь действуют те же правила, что и для float-to-int, за исключением того, что значения вне диапазона преобразуются в 0x7fffffffffffffff или -0x8000000000000000 в зависимости от знака.
float-to-double float a;
double result = (double) a;
Преобразование float в double с точным сохранением значения.
double-to-int double a;
int32 result = (int32) a;
Конвертация double в int32 с округлением до нуля. Здесь действуют те же правила, что и для float-to-int.
double-to-long double a;
int64 result = (int64) a;
Преобразование double в int64 с округлением в сторону нуля. Для него действуют те же правила, что и для float-to-long.
double-to-float double a;
float result = (float) a;
Конвертация double в float с округлением до ближайшего целого числа. Это приводит к потере точности для некоторых значений.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
Усечение int32 до int8, знак продлевает результат.
int-to-char int32 a;
int32 result = a & 0xffff;
Усечение int32 до uint16 без расширения знака.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
Усечение int32 до int16, знак продлевает результат.
add-int int32 a, b;
int32 result = a + b;
Сложение в дополнительном коде.
sub-int int32 a, b;
int32 result = a - b;
Вычитание в дополнительном коде.
rsub-int int32 a, b;
int32 result = b - a;
Вычитание с использованием обратного кода.
mul-int int32 a, b;
int32 result = a * b;
Умножение в дополнительном коде.
div-int int32 a, b;
int32 result = a / b;
Деление с дополнением до двух, округление до нуля (то есть усечение до целого числа). Если b == 0, возвращается ArithmeticException.
rem-int int32 a, b;
int32 result = a % b;
Остаток от деления в дополнительном коде. Знак результата совпадает со знаком a и точнее определяется как result == a - (a / b) * b. В этом случае будет сгенерирована ошибка ArithmeticException, если b == 0.
and-int int32 a, b;
int32 result = a & b;
Побитовое И.
or-int int32 a, b;
int32 result = a | b;
Побитовое ИЛИ.
xor-int int32 a, b;
int32 result = a ^ b;
Побитовое исключающее ИЛИ.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Побитовый сдвиг влево (с маскированным аргументом).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Побитовый сдвиг вправо со знаком (с маскированным аргументом).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Побитовый сдвиг вправо без знака (с маскированным аргументом).
add-long int64 a, b;
int64 result = a + b;
Сложение в дополнительном коде.
sub-long int64 a, b;
int64 result = a - b;
Вычитание в дополнительном коде.
mul-long int64 a, b;
int64 result = a * b;
Умножение с дополнением до двух.
div-long int64 a, b;
int64 result = a / b;
Деление с дополнением до двух, округленное до нуля (то есть усеченное до целого числа). В этом случае будет сгенерирована ошибка ArithmeticException, если b == 0.
rem-long int64 a, b;
int64 result = a % b;
Остаток от деления в дополнительном коде. Знак результата совпадает со знаком a и точнее определяется как result == a - (a / b) * b. В этом случае будет сгенерирована ошибка ArithmeticException, если b == 0.
and-long int64 a, b;
int64 result = a & b;
Побитовое И.
или-длинный int64 a, b;
int64 result = a | b;
Побитовое ИЛИ.
xor-long int64 a, b;
int64 result = a ^ b;
Побитовое исключающее ИЛИ.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Побитовый сдвиг влево (с маскированным аргументом).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Побитовый сдвиг вправо со знаком (с маскированным аргументом).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Побитовый сдвиг вправо без знака (с маскированным аргументом).
add-float float a, b;
float result = a + b;
Сложение чисел с плавающей запятой.
sub-float float a, b;
float result = a - b;
Вычитание чисел с плавающей запятой.
mul-float float a, b;
float result = a * b;
Умножение чисел с плавающей запятой.
div-float float a, b;
float result = a / b;
Деление с плавающей запятой.
rem-float float a, b;
float result = a % b;
Остаток от деления с плавающей запятой. Эта функция отличается от остатка от деления по стандарту IEEE 754 и определяется как result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double result = a + b;
Сложение чисел с плавающей запятой.
sub-double double a, b;
double result = a - b;
Вычитание чисел с плавающей запятой.
mul-double double a, b;
double result = a * b;
Умножение чисел с плавающей запятой.
div-double double a, b;
double result = a / b;
Деление с плавающей запятой.
rem-double double a, b;
double result = a % b;
Остаток от деления с плавающей запятой. Эта функция отличается от остатка от деления по стандарту IEEE 754 и определяется как result == a - roundTowardZero(a / b) * b.