Format kodu bajtowego Dalvik

Projekt ogólny

  • Model maszyny i konwencje wywoływania mają na celu w przybliżeniu naśladować typowe rzeczywiste architektury i konwencje wywoływania w stylu C:
    • Maszyna działa na podstawie rejestru, a ramki są ustalane w ramach rozmiaru w momencie ich tworzenia. Każdy element składa się z określonej liczby rejestrów (określonych przez metodę) oraz wszelkich danych pomocniczych potrzebnych do wykonania metody, takich jak (ale nie tylko) licznik programu i odwołanie do pliku .dex zawierającego metodę.
    • Gdy są używane do wartości bitowych (takich jak liczby całkowite i liczby zmiennoprzecinkowe), rejestry mają 32 bity szerokości. Pary sąsiednich rejestrów są używane w przypadku wartości 64-bitowych. Nie ma wymagań dotyczących wyrównania par rejestrów.
    • Gdy są używane do odwołań do obiektów, rejestry są wystarczająco szerokie, aby pomieścić dokładnie jedno takie odwołanie.
    • W ujęciu bitowym (Object) null == (int) 0.
    • N argumentów metody trafia w kolejności do ostatnich N rejestrów ramki wywołania metody. Argumenty szerokie zajmują 2 rejestry. Metody instancji otrzymują jako pierwszy argument odniesienie do this.
  • Jednostka pamięci w strumieniu instrukcji to 16-bitowa liczba bez znaku. Niektóre bity w niektórych instrukcjach są ignorowane / muszą być równe 0.
  • Instrukcje nie są bezpodstawnie ograniczone do określonego typu. Na przykład instrukcje, które przenoszą 32-bitowe wartości rejestrów bez interpretacji, nie muszą określać, czy przenoszą wartości całkowite, czy zmiennoprzecinkowe.
  • W przypadku odwołań do ciągów znaków, typów, pól i metod są osobno wyliczane i indeksywane pule stałych.
  • Dane bitowe są reprezentowane w strumieniu instrukcji.
  • W praktyce rzadko zdarza się, aby metoda potrzebowała więcej niż 16 rejestrów, a potrzeba większej liczby niż 8 rejestrów jest dość powszechna, dlatego wiele instrukcji jest ograniczonych do adresowania tylko pierwszych 16 rejestrów. W miarę możliwości instrukcje pozwalają na odwołania do pierwszych 256 rejestrów. Ponadto niektóre instrukcje mają warianty, które umożliwiają znacznie większą liczbę rejestrów, w tym parę instrukcji catch-all move, które mogą adresować rejestry w zakresie v0v65535. W przypadku, gdy wariant instrukcji nie jest dostępny do adresowania żądanego rejestru, zawartość rejestru powinna zostać przeniesiona z pierwotnego rejestru do niskiego rejestru (przed operacją) lub z niskiego rejestru wyników do wysokiego rejestru (po operacji).
  • Istnieje kilka „pseudoinstrukcji”, które służą do przechowywania danych ładunku o zmiennej długości, do których odwołują się zwykłe instrukcje (na przykład fill-array-data). Takie instrukcje nigdy nie mogą być napotkane podczas normalnego przepływu wykonania. Dodatkowo instrukcje muszą znajdować się w parzystych przesunięciach bajtowych kodu bajtowego (czyli wyrównane co 4 bajty). Aby spełnić to wymaganie, narzędzia do generowania dex muszą emitować dodatkową instrukcję nop jako spacer, jeśli w przeciwnym razie instrukcja nie byłaby wyrównana. Na koniec, choć nie jest to wymagane, większość narzędzi emituje te instrukcje na końcu metod, ponieważ w przeciwnym razie konieczne byłyby dodatkowe instrukcje.
  • Podczas instalacji w działającym systemie niektóre instrukcje mogą zostać zmienione, co spowoduje zmianę ich formatu w ramach optymalizacji łączenia statycznego w czasie instalacji. Umożliwi to szybsze wykonanie po ustaleniu powiązania. Sugerowane warianty znajdziesz w dokumentacji formatów instrukcji. Słowo „sugerowane” jest używane z powodu zaleceń; nie jest konieczne wdrażanie tych zaleceń.
  • Składnia i mnemotechnika zrozumiała dla człowieka:
    • kolejność argumentów: najpierw docelowy, a potem źródłowy;
    • Niektóre kody operacji mają sufiks nazwy, który rozstrzyga niejednoznaczność i wskazuje typy, na których działają:
      • Ogólne 32-bitowe opkody nie są oznaczone.
      • 64-bitowe opkody ogólne mają przyrostek -wide.
      • Kody operacji związane z danym typem mają przyrostek z nazwą typu (lub jego prostą skrótową nazwą), np. -boolean, -byte, -char, -short, -int, -long, -float, -double, -object, -string, -class, -void.
    • Niektóre op-kody mają przypisany przyrostek, który pozwala odróżnić operacje identyczne pod względem działania, ale różniące się układem instrukcji lub opcjami. Te przyrostki są oddzielone od nazw głównych za pomocą ukośnika („/”) i istnieją głównie po to, aby zapewnić jednoznaczne mapowanie z stałymi w kodzie, który generuje i interpretuje pliki wykonywalne (czyli aby zmniejszyć niejednoznaczność dla ludzi).
    • W opisach szerokość wartości (np. zakres stałej lub liczba rejestrów, do których można się odwoływać) jest podkreślona przez użycie znaku na 4 bity szerokości.
    • Na przykład w instrukcji „move-wide/from16 vAA, vBBBB”:
      • move” to podstawowy kod operacji wskazujący podstawową operację (przesuń wartość rejestru).
      • wide” to sufiks nazwy wskazujący, że działa ona na danych o szerokości 64 bitów.
      • from16” to sufiks kodu operacji, który wskazuje wariant mający jako źródło 16-bitowe odwołanie do rejestru.
      • vAA” to rejestr docelowy (wynikający z operacji; znowu, zasada jest taka, że argumenty docelowe zawsze występują jako pierwsze), który musi znajdować się w zakresie v0v255.
      • vBBBB” to rejestr źródłowy, który musi znajdować się w zakresie v0v65535.
  • Więcej informacji o różnych formatach instrukcji (wymienionych w sekcji „Operacja i format”) oraz o składni instrukcji znajdziesz w dokumentacji formatów instrukcji.
  • Aby dowiedzieć się więcej o tym, jak kod bajtowy pasuje do szerszego obrazu, zapoznaj się z dokumentem dotyczącym formatu pliku .dex.

Podsumowanie zestawu kodu bajtowego

Opcje i format Mnemotechnika / składnia Argumenty Opis
00 10x nie   Cykle odpadów.

Uwaga: pseudoinstrukcje zawierające dane są oznaczane tym kodem operacji. W tym przypadku najwyższy bajt jednostki kodu operacji wskazuje charakter danych. Poniżej znajdziesz sekcje „Format packed-switch-payload”, „Format sparse-switch-payload” i „Format fill-array-data-payload”.

01 12x move vA, vB A: rejestr docelowy (4 bity)
B: rejestr źródłowy (4 bity)
Przenoszenie zawartości jednego rejestru nieobiektowego do innego.
02 22x move/from16 vAA, vBBBB A: rejestr docelowy (8 bitów)
B: rejestr źródłowy (16 bitów)
Przenoszenie zawartości jednego rejestru nieobiektowego do innego.
03 32x move/16 vAAAA, vBBBB A: rejestr docelowy (16 bitów)
B: rejestr źródłowy (16 bitów)
Przenoszenie zawartości jednego rejestru nieobiektowego do innego.
04 12x move-wide vA, vB A: para rejestrów docelowych (4 bity)
B: para rejestrów źródłowych (4 bity)
Przenoszenie zawartości jednej pary rejestrów do drugiej.

Uwaga: przejście z vN do vN-1 lub vN+1 jest legalne, więc implementacje muszą zapewnić, aby obie połowy pary rejestrów były odczytywane, zanim cokolwiek zostanie zapisane.

05 22x move-wide/from16 vAA, vBBBB A: para rejestrów docelowych (8 bitów)
B: para rejestrów źródłowych (16 bitów)
Przenoszenie zawartości jednej pary rejestrów do drugiej.

Uwaga: uwagi dotyczące implementacji są takie same jak w sekcji move-wide powyżej.

06 32x move-wide/16 vAAAA, vBBBB A: para rejestrów docelowych (16 bitów)
B: para źródeł rejestrów (16 bitów)
Przenoszenie zawartości jednej pary rejestrów do drugiej.

Uwaga: uwagi dotyczące implementacji są takie same jak w sekcji move-wide powyżej.

07 12x move-object vA, vB A: rejestr docelowy (4 bity)
B: rejestr źródłowy (4 bity)
Przenoszenie zawartości jednego rejestru zawierającego obiekty do innego.
08 22x move-object/from16 vAA, vBBBB A: rejestr docelowy (8 bitów)
B: rejestr źródłowy (16 bitów)
Przenoszenie zawartości jednego rejestru zawierającego obiekty do innego.
09 32x move-object/16 vAAAA, vBBBB A: rejestr docelowy (16 bitów)
B: rejestr źródłowy (16 bitów)
Przenoszenie zawartości jednego rejestru zawierającego obiekty do innego.
0a 11x move-result vAA A: rejester docelowy (8 bitów) Przesuń jednowyrazowy wynik niebędący obiektem z najnowszego invoke-kind do wskazanego rejestru. Musisz to zrobić jako instrukcję bezpośrednio po elemencie invoke-kind, którego wynik (jednowyrazowy, nieobiektowy) nie powinien być ignorowany. Niedozwolone jest umieszczanie go w innym miejscu.
0b 11x move-result-wide vAA A: para rejestrów docelowych (8 bitów) Przesuń wynik podwójnego słowa z ostatniego invoke-kind do wskazanej pary rejestrów. Należy to zrobić zgodnie z instrukcją bezpośrednio po invoke-kind, której (podwójne słowo) wyniku nie należy ignorować. W żadnym innym miejscu nie jest to dozwolone.
0c 11x move-result-object vAA A: rejester docelowy (8 bitów) Przesuń obiekt z wynikiem ostatniego wywołania funkcji invoke-kind do wskazanego rejestru. Należy to zrobić zgodnie z instrukcją, bezpośrednio po instrukcji invoke-kind lub filled-new-array, której wynik (obiekt) nie ma być ignorowany. W innym miejscu nie jest to dozwolone.
0 d 11x move-exception vAA A: rejester docelowy (8 bitów) Zapisuje właśnie wyjątek do podanego rejestru. Musi to być pierwsza instrukcja dowolnego przetwarzacza wyjątków, którego wychwycony wyjątków nie należy ignorować. Ta instrukcja musi występować tylko jako pierwsza instrukcja przetwarzacza wyjątków. W żadnym innym miejscu nie jest ona prawidłowa.
0e 10x return-void   Powrót z metody void.
0f 11x return vAA A: rejestr zwracanej wartości (8 bitów) Zwracanie wartości z metody o jednolitej szerokości (32 bity), która zwraca wartość niebędącą obiektem.
10 11x vAA na poziomie zwrotu A: zwracana wartość w parze rejestrów (8 bitów) Zwracanie wartości z metody zwracającej wartość o podwójnej szerokości (64-bitowej).
11 11x return-object vAA A: rejestr zwracanej wartości (8 bitów) Zwracanie wartości z metody zwracającej obiekt.
12 11n const/4 vA, #+B A: rejestr docelowy (4 bity)
B: liczba całkowita ze znakiem (4 bity)
Przeniesienie podanej wartości dosłownej (rozszerzonej o 32 bity) do określonego rejestru.
13 21 s const/16 vAA, #+BBBB A: rejestr docelowy (8 bitów)
B: liczba całkowita ze znakiem (16 bitów)
Przeniesienie podanej wartości dosłownej (rozszerzonej o 32 bity) do określonego rejestru.
14 31i const vAA, #+BBBBBBBB A: rejestr docelowy (8 bitów)
B: dowolna stała 32-bitowa
Przesuń podany literał do wskazanego rejestru.
15 21 h const/high16 vAA, #+BBBB0000 A: rejestr docelowy (8 bitów)
B: liczba całkowita ze znakiem (16 bitów)
Przesuń podany dosłowny ciąg znaków (rozszerzony do 32 bitów na prawo) do określonego rejestru.
16 21 const-wide/16 vAA, #+BBBB A: rejestr docelowy (8 bitów)
B: liczba całkowita ze znakiem (16 bitów)
Przeniesienie podanej wartości dosłownej (rozszerzonej o 64 bity) do określonej pary rejestrów.
17 31i const-wide/32 vAA, #+BBBBBBBB A: rejestr docelowy (8 bitów)
B: liczba całkowita ze znakiem (32 bity)
Przeniesienie podanej wartości dosłownej (rozszerzonej o 64 bity) do określonej pary rejestrów.
18 51 l const-wide vAA, #+BBBBBBBBBBBBBBBB A: rejestr docelowy (8 bitów)
B: dowolna stała o podwójnej szerokości (64-bitowa)
Przeniesienie podanej wartości dosłownej do określonej pary rejestrów.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: rejestr docelowy (8 bitów)
B: liczba całkowita ze znakiem (16 bitów)
Przesuń podany dosłowny ciąg znaków (rozszerzony o 64 bity na prawo) do określonej pary rejestrów.
1a 21c const-string vAA, string@BBBB A: rejestrator docelowy (8 bitów)
B: indeks ciągu znaków
Przenoszenie odwołania do ciągu znaków określonego przez dany indeks do podanego rejestru.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: rejestrator docelowy (8 bitów)
B: indeks ciągu znaków
Przenoszenie odwołania do ciągu znaków określonego przez dany indeks do podanego rejestru.
1c 21c const-class vAA, type@BBBB A: rejestr docelowy (8 bitów)
B: indeks typu
Przenoszenie odwołania do klasy określonej przez podany indeks do wskazanego rejestru. W przypadku wskazanego typu prymitywnego przechowywana jest tutaj odwołanie do zdegenerowanej klasy typu prymitywnego.
1d 11x monitor-enter vAA A: rejestr referencyjny (8 bitów) Przejmij monitor wskazanego obiektu.
1e 11x monitor-exit vAA A: rejestr referencyjny (8 bitów) Zwolnij monitorowanie wskazanego obiektu.

Uwaga: jeśli ta instrukcja musi wyjąć wyjątek, musi to zrobić tak, jakby komputer już przeszedł tę instrukcję. Możesz sobie wyobrazić, że instrukcja jest (w pewnym sensie) wykonywana, a wyjątek jest zgłaszany po tej instrukcji, ale zanim kolejna instrukcja zostanie wykonana. Ta definicja umożliwia metodzie użycie uniwersalnego monitora do czyszczenia (np. finally) blokowanie jako czyszczenie monitora dla tego bloku jako sposób na obsługę dowolnych wyjątków, które mogą zostać rzucone z powodu historycznego wdrożenia Thread.stop(), przy jednoczesnym zarządzaniu prawidłową higieną monitora.

1f 21c check-cast vAA, type@BBBB A: rejestr z odniesieniem (8 bitów)
B: indeks typu (16 bitów)
Wywołaj ClassCastException, jeśli odwołania w danym rejestrze nie można rzutować na wskazany typ.

Uwaga: ponieważ A musi zawsze być odwołaniem (a nie wartością prymitywną), podczas wykonywania programu wystąpi błąd (czyli zostanie rzucone wyjątek), jeśli B będzie odnosić się do typu prymitywnego.

20 22 °C instance-of vA, vB, type@CCCC A: rejestr docelowy (4 bity)
B: rejestr z wartością odniesienia (4 bity)
C: indeks typu (16 bitów)
Zapisz w danym rejestrze docelowym 1, jeśli wskazane odwołanie jest wystąpieniem danego typu, lub 0, jeśli nie.

Uwaga: ponieważ B musi być zawsze odwołaniem (a nie wartością prymitywną), zawsze spowoduje to zapisanie wartości 0, jeśli C odnosi się do typu prymitywnego.

21 12x tablica o długości vA, vB A: rejestr docelowy (4 bity)
B: rejestr z odniesieniem do tablicy (4 bity)
Przechowuj w danym rejestrze docelowym długość wskazanej tablicy w elementach
22 21c new-instance vAA, type@BBBB A: rejestr docelowy (8 bitów)
B: indeks typu
Utwórz nową instancję wskazanego typu, przechowując odwołanie do niej w miejscu docelowym. Typ musi odwoływać się do klasy niebędącej tablicą.
23 22c new-array vA, vB, type@CCCC A: rejestr docelowy (4 bity)
B: rejestr rozmiaru
C: indeks typu
Tworzy nową tablicę o wskazanym typie i rozmiarze. Typ musi być typu tablica.
24 35c wypełniona-nowa-tablica {vC, vD, vE, vF, vG}, typ@BBBB A: rozmiar tablicy i liczba argumentów (4 bity)
B: indeks typu (16 bitów)
C..G: rejestry argumentów (po 4 bity)
Utwórz tablicę o danym typie i rozmiarze, wypełniając ją podanymi treściami. Typ musi być typem tablicy. Treść tablicy musi składać się z jednego słowa (czyli nie można używać tablic long ani double, ale można używać typów referencyjnych). Zbudowana instancja jest przechowywana jako „wynik” w taki sam sposób, w jaki instrukcje wywołania metody przechowują swoje wyniki, więc musi zostać przeniesiona do rejestru za pomocą bezpośrednio następnej instrukcji move-result-object (jeśli ma być użyta).
25 3rc wypełniona nowa tablica/zakres {vCCCC .. vNNNN}, typ@BBBB A: rozmiar tablicy i liczba argumentów (8 bitów)
B: indeks typu (16 bitów)
C: pierwszy rejestr argumentu (16 bitów)
N = A + C - 1
Utwórz tablicę o danym typie i rozmiarze, wypełniając ją dostarczonymi treściami. W przypadku tej opcji obowiązują te same wyjaśnienia i ograniczenia, co w przypadku opcji filled-new-array opisanej powyżej.
26 31t fill-array-data vAA, +BBBBBBBB (z danymi dodatkowymi określonymi poniżej w sekcji „Format fill-array-data-payload”) A: odwołanie do tablicy (8 bitów)
B: przesunięcie „gałęzi” ze znakiem do pseudoinstrukcji danych tabeli (32 bity)
Wypełnij podany tablicę wskazanymi danymi. Odwoływanie się musi dotyczyć tablicy prymitywów, a jej typ musi być zgodny z typem tabeli danych. Tabela danych nie może zawierać więcej elementów niż mieści się w tablicy. Oznacza to, że tablica może być większa niż tablica, a w takim przypadku ustawiane są tylko początkowe elementy tablicy, a pozostałe pozostają bez zmian.
27 11x throw vAA A: rejestr wyjątków (8 bitów)
Wyjątek.
28 10t goto +AA A: podpisany przesunięcie gałęzi (8 bitów) Bezwarunkowe przejście do wskazanej instrukcji.

Uwaga: przesunięcie gałęzi nie może być 0. (pętla może być skonstruowana zgodnie z zasadami za pomocą instrukcji goto/32 lub poprzez uwzględnienie instrukcji nop jako celu przed gałęzią).

29 20 t goto/16 +AAAA A: przesunięcie gałęzi ze znakiem (16 bitów)
Bezwarunkowe przejście do wskazanej instrukcji.

Uwaga: przesunięcie gałęzi nie może być 0. (pętla może być skonstruowana zgodnie z zasadami za pomocą instrukcji goto/32 lub poprzez uwzględnienie instrukcji nop jako celu przed gałęzią).

2a 30t goto/32 +AAAAAAAA A: przesunięcie gałęzi ze znakiem (32 bity)
Bezwarunkowe przejście do wskazanej instrukcji.
2b 31t packed-switch vAA, +BBBBBBBB (z dodatkowymi danymi określonymi poniżej w sekcji „Format packed-switch-payload”) A: rejestr testowy
B: podpisany „odgałęzienie” przesunięcie do pseudoinstrukcji danych tabeli (32 bity)
Przejść do nowej instrukcji na podstawie wartości w danym rejestrze, korzystając z tabeli przesunięć odpowiadających każdej wartości w danym zakresie całkowitym, lub przejść do następnej instrukcji, jeśli nie ma dopasowania.
2c 31t sparse-switch vAA, +BBBBBBBB (z danymi dodatkowymi określonymi poniżej w sekcji „Format”sparse-switch-payload) A: rejestr testowy
B: przesunięcie o znaku „branch” do pseudoinstrukcji danych tabeli (32 bity)
Przejście do nowej instrukcji na podstawie wartości w danym rejestrze za pomocą uporządkowanej tabeli par wartości i przesunięcia lub przejście do następnej instrukcji, jeśli nie ma dopasowania.
2d..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: rejestr docelowy (8 bitów)
B: pierwszy rejestr lub para źródeł
C: drugi rejestr lub para źródeł
Wykonaj wskazane porównanie z liczbą zmiennoprzecinkową lub long, ustawiając a na 0, jeśli b == c, 1, jeśli b > c, lub -1, jeśli b < c. „Bias” podany dla operacji zmiennoprzecinkowych wskazuje, jak traktowane są porównania NaN: instrukcje „gt bias” zwracają 1 w przypadku porównań NaN, a instrukcje „lt bias” zwracają -1.

Na przykład, aby sprawdzić, czy zmienna typu zmiennoprzecinkowegox < y jest równa 0, zalecamy użycie funkcjicmpg-float. Wynik -1 wskazuje, że test był prawdziwy, a inne wartości wskazują, że był on fałszywy albo z powodu prawidłowego porównania, albo dlatego, że jedna z wartości była równa 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: pierwszy rejestr do przetestowania (4 bity)
B: drugi rejestr do przetestowania (4 bity)
C: przesunięcie gałęzi ze znakiem (16 bitów)
Odgałę do podanego miejsca docelowego, jeśli wartości 2 rejestrów są zgodne z podanymi.

Uwaga: przesunięcie gałęzi nie może być 0. (Spin loop może być zbudowany zgodnie z zasadami, albo przez rozwidlenie w obrocie do tyłu goto, albo przez uwzględnienie nop jako celu przed gałęzią).

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: rejestr do testowania (8 bitów)
B: przesunięcie gałęzi ze znakiem (16 bitów)
Odgałęzienie do podanego miejsca docelowego, jeśli wartość danego rejestru jest porównywana z 0 zgodnie z określeniami.

Uwaga: przesunięcie gałęzi nie może być 0. (Spin loop może być zbudowany zgodnie z zasadami albo przez rozwidlenie w obrocie wstecznym goto, albo przez uwzględnienie nop jako celu przed gałęzią).

3e..43 10x (nieużywany)   (nieużywane)
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: rejestr wartości lub para; może być źródłem lub celem (8 bitów)
B: rejestr tablicy (8 bitów)
C: rejestr indeksu (8 bitów)
Wykonywanie operacji na tablicy w wybranym indeksie danej tablicy, wczytując lub zapisując dane do rejestru wartości.
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: rejestr wartości lub para; może być źródłem lub celem (4 bity)
B: rejestr obiektu (4 bity)
C: indeks pola odwołania instancji (16 bitów)
Wykonaj operację na polu instancji zidentyfikowanego obiektu z wykorzystaniem zidentyfikowanego pola, wczytując lub zapisując je w rejestrze wartości.

Uwaga: te instrukcje są odpowiednimi kandydatami do łączenia stałego, zmieniając argument pola na bardziej bezpośredni przesunięcie.

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: rejestr wartości lub para; może być źródłem lub celem (8 bitów)
B: indeks odwołania do pola stałego (16 bitów)
Wykonaj operację na statycznym polu wskazanego obiektu za pomocą wskazanego pola stałego, wczytując lub zapisując je w rejestrze wartości.

Uwaga: te instrukcje są odpowiednimi kandydatami do łączenia stałego, zmieniając argument pola na bardziej bezpośredni przesunięcie.

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: liczba argumentów (4 bity)
B: indeks odwołania do metody (16 bitów)
C..G: rejestry argumentów (po 4 bity każdy)
Wywołaj wskazaną metodę. Wynik (jeśli występuje) może być przechowywany przy użyciu odpowiedniego wariantu move-result* jako instrukcji bezpośrednio po nim.

invoke-virtual służy do wywołania zwykłej wirtualnej metody, która nie jest metodą static, private ani konstruktorem.

Gdy method_id odwołuje się do metody klasy innej niż interfejs, invoke-super służy do wywołania wirtualnej metody najbliższej superklasy (a nie tej o tej samej nazwie method_id w klasie wywołującej). Obowiązują te same ograniczenia metody co w przypadku metody invoke-virtual.

W pliku Dex w wersji 037 lub nowszej, jeśli method_id odnosi się do metody interfejsu, invoke-super jest używane do wywołania najbardziej szczegółowej, niezastąpionej wersji tej metody zdefiniowanej w tym interfejsie. Obowiązują te same ograniczenia metody co w przypadku invoke-virtual. W plikach Dex w wersji wcześniejszej niż 037 interfejs method_id jest nielegalny i niezdefiniowany.

invoke-direct służy do wywołania metody bezpośredniej, która nie jest metodą invoke-direct (czyli metodą instancji, która z natury nie może być zastąpiona, czyli metodą instancji private lub konstruktorem).static

invoke-static służy do wywołania metody static (która zawsze jest uważana za metodę bezpośrednią).

invoke-interface służy do wywołania metody interface, czyli na obiekcie, którego konkretna klasa nie jest znana, przy użyciu method_id, który odnosi się do interface.

Uwaga: te kody operacji są odpowiednimi kandydatami do łączenia statycznie. Zmień argument metody na bardziej bezpośredni przesunięcie (lub parę takich przesunięć).

73 10x (nieużywany)   (nieużywany)
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: liczba argumentów (8 bitów)
B: indeks odwołania do metody (16 bitów)
C: rejestr pierwszego argumentu (16 bitów)
N = A + C - 1
Wywołaj wskazaną metodę. Szczegółowe informacje, ostrzeżenia i sugestie znajdziesz w pierwszym invoke-kindopisie powyżej.
79..7a 10x (nieużywany)   (nieużywany)
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: rejestr docelowy lub para (4 bity)
B: rejestr źródłowy lub para (4 bity)
Wykonaj zidentyfikowaną operację jednoargumentową na rejestrze źródłowym, przechowując wynik w rejestrze docelowym.
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: rejestr docelowy lub para (8 bitów)
B: pierwszy rejestr źródłowy lub para (8 bitów)
C: drugi rejestr źródłowy lub para (8 bitów)
Wykonaj zidentyfikowaną operację binarną na dwóch rejestrach źródłowych, przechowując wynik w rejestrze docelowym.

Uwaga: w przeciwieństwie do innych operacji matematycznych -long (które przyjmują pary rejestrów zarówno dla pierwszego, jak i drugiego źródła), funkcje shl-long, shr-longushr-long przyjmują parę rejestrów dla pierwszego źródła (wartość do przesunięcia), ale tylko pojedynczy rejestr dla drugiego źródła (odległość przesunięcia).

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: rejestr docelowy i pierwszy rejestr źródłowy lub para rejestrów (4 bity)
B: drugi rejestr źródłowy lub para rejestrów (4 bity)
Wykonaj zidentyfikowaną operację binarną na 2 rejestrach źródłowych, przechowując wynik w pierwszym rejestrze źródłowym.

Uwaga: w przeciwieństwie do innych operacji matematycznych -long/2addr (które przyjmują pary rejestrów zarówno dla miejsca docelowego/pierwotnego źródła, jak i drugiego źródła), funkcje shl-long/2addr, shr-long/2addrushr-long/2addr przyjmują parę rejestrów dla miejsca docelowego/pierwotnego źródła (wartość do przesunięcia), ale pojedynczy rejestr dla drugiego źródła (odległość przesunięcia).

d0..d7 22s binop/lit16 vA, vB, #+CCCC
d0: add-int/lit16
d1: rsub-int (reverse subtract)
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: rejestr docelowy (4 bity)
B: rejestr źródłowy (4 bity)
C: stała int ze znakiem (16 bitów)
Wykonaj wskazaną operację binarną na wskazanym rejestrze (pierwszy argument) i wartości dosłownej (drugi argument), przechowując wynik w rejestrze docelowym.

Uwaga: rsub-int nie ma sufiksu, ponieważ ta wersja jest głównym kodem operacyjnym w swojej rodzinie. Szczegółowe informacje o jego semantyce znajdziesz poniżej.

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: rejestr docelowy (8 bitów)
B: rejestr źródłowy (8 bitów)
C: stała int ze znakiem (8 bitów)
Wykonaj wskazaną operację binarną na wskazanym rejestrze (pierwszy argument) i wartości dosłownej (drugi argument), przechowując wynik w rejestrze docelowym.

Uwaga: informacje o semantyce funkcji rsub-int znajdziesz poniżej.

e3..f9 10x (nieużywany)   (nieużywany)
fa 45 cc invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: liczba argumentów (4 bity)
B: indeks odwołania do metody (16 bitów)
C: odbiorca (4 bity)
D..G: rejestry argumentów (po 4 bity)
H: indeks odwołania do prototypu (16 bitów)
Wykonywanie wskazanej metody polimorficznej podpisu. Wynik (jeśli występuje) może być przechowywany przy użyciu odpowiedniego wariantu move-result* jako instrukcji bezpośrednio po nim.

Odwoływanie się do metody musi dotyczyć metody polimorficznej z podpisem, takiej jak java.lang.invoke.MethodHandle.invoke lub java.lang.invoke.MethodHandle.invokeExact.

Odbiorca musi być obiektem obsługującym wywoływaną metodę polimorficzną podpisu.

Przywołanie prototypu opisuje typy argumentów i oczekiwany typ zwracanej wartości.

Kod bajtowy invoke-polymorphic może wywoływać wyjątki podczas wykonywania. Wyjątki są opisane w dokumentacji interfejsu API dla wywoływanej metody polimorficznej z podpisem.

Bezpieczeństwo: obecne w plikach Dex od wersji 038.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: liczba słów argumentu (8 bitów)
B: indeks odwołania do metody (16 bitów)
C: odbiorca (16 bitów)
H: indeks odwołania do prototypu (16 bitów)
N = A + C - 1
Wywołaj wskazany identyfikator metody. Szczegółowe informacje znajdziesz w opisie invoke-polymorphic.

Widoczne w plikach Dex od wersji 038.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB A: liczba argumentów (4 bity)
B: indeks odwołania do miejsca wywołania (16 bitów)
C..G: rejestry argumentów (po 4 bity każdy)
Rozwiązuje i wywołuje wskazane miejsce połączenia. Wynik wywołania (jeśli występuje) może zostać zapisany z odpowiednim wariantem move-result* jako następną instrukcją.

Instrukcja jest wykonywana w 2 fazach: rozdzielczość wywołania witryny i wywołanie witryny.

Rozdzielczość witryny wywołania sprawdza, czy wskazana witryna wywołania ma powiązany obiekt java.lang.invoke.CallSite. W przeciwnym razie metoda bootstrap linkera dla wskazanego miejsca wywołania jest wywoływana za pomocą argumentów obecnych w pliku DEX (patrz call_site_item). Metoda bootstrap linker zwraca instancję java.lang.invoke.CallSite, która zostanie następnie powiązana z wspomnianym miejscem wywołania, jeśli nie istnieje żadne powiązanie. Inny wątek mógł już utworzyć powiązanie, a jeśli tak się stało, instrukcja będzie wykonywana z pierwszym powiązanym wystąpieniem java.lang.invoke.CallSite.

Wywołanie strony wywołania jest wykonywane na obiekcie java.lang.invoke.MethodHandle w rozwiązanej instancji java.lang.invoke.CallSite. Docelowy obiekt jest wywoływany jako if executing invoke-polymorphic (described above) using the method handle and arguments to the invoke-custom instruction as the arguments to an exact method handle invocation.

Wyjątki zgłaszane przez metodę łączenia bootstrapa są owijane w java.lang.BootstrapMethodError. BootstrapMethodError jest też podniesiony, jeśli:
  • metoda łącznika bootstrap nie zwraca instancji java.lang.invoke.CallSite.
  • zwracany obiekt java.lang.invoke.CallSite ma obiekt null jako wartość atrybutu handle.
  • Uchwyt metody nie jest typu żądanego.
W plikach Dex od wersji 038.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: liczba argumentów (8 bitów)
B: indeks odwołania do miejsca wywołania (16 bitów)
C: pierwszy rejestr argumentu (16-bitowy)
N = A + C - 1
Rozwiązywanie i wywoływanie strony wywołania. Szczegółowe informacje znajdziesz w opisie invoke-custom.

Widoczne w plikach Dex od wersji 038.
fe 21c const-method-handle vAA, method_handle@BBBB A: rejestr docelowy (8 bitów)
B: indeks metody obsługi (16 bitów)
Przenoszenie odwołania do uchwytu metody określonego przez dany indeks do określonego rejestru.

W plikach Dex od wersji 039.
ff 21c const-method-type vAA, proto@BBBB A: rejestr docelowy (8 bitów)
B: odwołanie do prototypu metody (16 bitów)
Przenoszenie odwołania do prototypu metody określonego przez dany indeks do wskazanego rejestru.

Widoczne w plikach Dex od wersji 039.

Format ładunku packed-switch-payload

Nazwa Format Opis
ident ushort = 0x0100 identyfikacja pseudokodu operacji
rozmiar ushort liczba wpisów w tabeli
first_key int pierwsza (i najniższa) wartość instrukcji warunkowej switch
cele int[] lista size względnych celów gałęzi. Docelowe wartości są względne względem adresu kodu operacji przełącznika, a nie tej tabeli.

Uwaga: łączna liczba jednostek kodu w przypadku instancji tej tabeli to (size * 2) + 4.

format sparser-switch-payload

Nazwa Format Opis
ident ushort = 0x0200 identyfikowanie pseudokodu operacji
rozmiar ushort liczba wpisów w tabeli.
klucze int[] lista wartości klucza size posortowana od najmniejszej do największej
cele int[] lista size względnych celów gałęzi, z których każdy odpowiada wartości klucza w tym samym indeksie. Docelowe wartości są względne względem adresu kodu operacji przełącznika, a nie tej tabeli.

Uwaga: łączna liczba jednostek kodu w przypadku instancji tej tabeli to (size * 4) + 2.

format fill-array-data-payload

Nazwa Format Opis
ident ushort = 0x0300 identyfikacja pseudokodu operacji
element_width ushort liczba bajtów w każdym elemencie,
rozmiar uint Liczba elementów w tabeli
dane ubyte[] wartości danych,

Uwaga: łączna liczba jednostek kodu w przypadku instancji tej tabeli to (size * element_width + 1) / 2 + 4.

Szczegóły działania matematycznego

Uwaga: operacje zmiennoprzecinkowe muszą być zgodne z zasadami IEEE 754, używając zaokrąglenia do najbliższego i stopniowego przepełnienia, chyba że określono inaczej.

Kod operacji C Semantics Uwagi
neg-int int32 a;
int32 result = -a;
Jednobitowy kod uzupełniający.
not-int int32 a;
int32 result = ~a;
Jednobitowy uzupełniający kod binarny.
neg-long int64 a;
int64 result = -a;
Jednobitowy kod uzupełniający.
not-long int64 a;
int64 result = ~a;
Jednobitowy uzupełniający kod binarny.
neg-float float a;
float result = -a;
negacja zmiennoprzecinkowa;
neg-double podwójna a;
podwójna wynik = -a;
negacja zmiennoprzecinkowa;
int-to-long int32 a;
int64 result = (int64) a;
Podpisz rozszerzenie int32 w int64.
int-to-float int32 a;
float result = (float) a;
Przeliczenie wartości int32 na float z zaokrągleniem do najbliższej wartości. W tym przypadku niektóre wartości tracą dokładność.
int-to-double int32 a;
double result = (double) a;
Konwersja int32 na double.
long-to-int int64 a;
int32 result = (int32) a;
Skrócenie int64 do int32.
long-to-float int64 a;
float result = (float) a;
Przeliczenie wartości int64 na float z zaokrągleniem do najbliższej wartości. W tym przypadku niektóre wartości tracą dokładność.
long-to-double int64 a;
double result = (double) a;
Przeliczenie wartości int64 na double z zaokrągleniem do najbliższej wartości. W tym przypadku niektóre wartości tracą dokładność.
float-to-int float a;
int32 result = (int32) a;
Przeliczenie wartości float na int32 z zaokrągleniem do zera. NaN-0.0 (ujemne zero) zamienione na liczbę całkowitą 0. Nieskończoności i wartości o zbyt dużej wartości, aby można je było przedstawić, są konwertowane na 0x7fffffff lub -0x80000000 w zależności od znaku.
float-to-long float a;
int64 result = (int64) a;
Przeliczenie wartości float na int64 z zaokrągleniem do zera. Obowiązują tu te same reguły dotyczące wartości nieprawidłowych co w przypadku funkcji float-to-int, z tą różnicą, że wartości spoza zakresu są konwertowane na 0x7fffffffffffffff lub -0x8000000000000000 w zależności od znaku.
float-to-double float a;
double result = (double) a;
Przeliczenie jednostki float na jednostkę double z zachowaniem dokładnej wartości.
double-to-int podwójna a;
int32 result = (int32) a;
Przeliczenie wartości double na int32 z zaokrągleniem do zera. Obowiązują tu te same zasady dotyczące przypadków specjalnych co w przypadku float-to-int.
double-to-long double a;
int64 result = (int64) a;
Przeliczenie wartości double na int64 z zaokrągleniem do zera. Obowiązują tu te same zasady dotyczące przypadków specjalnych co w przypadku float-to-long.
double-to-float podwójna a;
float wynik = (float) a;
Przeliczenie wartości double na float z zaokrągleniem do najbliższej wartości. W tym przypadku niektóre wartości tracą dokładność.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
Obcięcie wartości int32 do int8, co oznacza rozszerzenie wyniku.
int-to-char int32 a;
int32 result = a & 0xffff;
Skrócenie int32 do uint16 bez rozszerzenia znaków.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
Obcięcie wartości int32 do int16, co oznacza rozszerzenie wyniku.
add-int int32 a, b;
int32 result = a + b;
Dodawanie uzupełniające do 2.
sub-int int32 a, b;
int32 result = a - b;
Odejmowanie w uzupełnieniu dwójkowym.
rsub-int int32 a, b;
int32 result = b - a;
Odwrotne odejmowanie w systemie dwójkowym.
mul-int int32 a, b;
int32 result = a * b;
Mnożenie w systemie dwójkowym.
div-int int32 a, b;
int32 result = a / b;
Dzielenie z uzupełnieniem do 2 oraz zaokrąglanie w dół (czyli obcinanie do liczby całkowitej). Jeśli b == 0, to ArithmeticException.
rem-int int32 a, b;
int32 result = a % b;
Reszta w uzupełnieniu dwójkowym po podziale. Znak wyniku jest taki sam jak w przypadku funkcji a, a dokładniej określa go wyrażenie result == a - (a / b) * b. Wyrzuca to błąd ArithmeticException, jeśli b == 0.
and-int int32 a, b;
int32 result = a & b;
Operacja bitowa I.
or-int int32 a, b;
int32 result = a | b;
Operacja bitowa LUB.
xor-int int32 a, b;
int32 result = a ^ b;
Operacja bitowa XOR.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
przesunięcie bitowe w lewo (z argumentem maskowanym);
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Zmiana znaku przesunięcie w prawo (z argumentem maskowanym).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Bezwzględne przesunięcie bitowe w prawo (z argumentem maski).
add-long int64 a, b;
int64 result = a + b;
Dodawanie uzupełniające do 2.
sub-long int64 a, b;
int64 result = a - b;
Odejmowanie w uzupełnieniu dwójkowym.
mul-long int64 a, b;
int64 result = a * b;
Mnożenie w systemie dwójkowym.
div-long int64 a, b;
int64 result = a / b;
Dzielenie z uzupełnieniem do 2 oraz zaokrąglanie w dół (czyli obcinanie do liczby całkowitej). Jeśli b == 0, to ArithmeticException.
rem-long int64 a, b;
int64 result = a % b;
Reszta z dzielenia w uzupełnieniu do 2 bitów. Znak wyniku jest taki sam jak w przypadku funkcji a, a dokładniej określa go wyrażenie result == a - (a / b) * b. Wyrzuca to błąd ArithmeticException, jeśli b == 0.
and-long int64 a, b;
int64 result = a & b;
Operacja bitowa I.
or-long int64 a, b;
int64 result = a | b;
Operacja bitowa LUB.
xor-long int64 a, b;
int64 result = a ^ b;
Operacja bitowa XOR.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
przesunięcie bitowe w lewo (z argumentem maskowanym);
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Zmiana znaku przesunięcie w prawo (z argumentem maskowanym).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Bezwzględne przesunięcie bitowe w prawo (z argumentem maski).
add-float float a, b;
float result = a + b;
Dodawanie zmiennoprzecinkowe.
podgrupa float a, b;
float result = a - b;
Odejmowanie zmiennoprzecinkowe.
mul-float float a, b;
float result = a * b;
mnożenie zmiennoprzecinkowe.
div-float float a, b;
float result = a / b;
Dzielenie zmiennoprzecinkowe.
rem-float float a, b;
float wynik = a % b;
Reszta zmiennoprzecinkowa po podziale. Ta funkcja różni się od funkcji IEEE 754 i jest zdefiniowana jako result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double result = a + b;
Dodawanie zmiennoprzecinkowe.
podwójny double a, b;
double result = a - b;
Odejmowanie zmiennoprzecinkowe.
mul-double double a, b;
double result = a * b;
mnożenie zmiennoprzecinkowe.
div-double double a, b;
double result = a / b;
Dzielenie zmiennoprzecinkowe.
rem-double podwójna a, b;
double result = a % b;
Reszta zmiennoprzecinkowa po podziale. Ta funkcja różni się od funkcji IEEE 754 i jest zdefiniowana jako result == a - roundTowardZero(a / b) * b.