Format kodu bajtowego Dalvik

Ogólny projekt

  • Model maszyny i konwencje wywoływania mają w przybliżeniu naśladować typowe rzeczywiste architektury i konwencje wywoływania w stylu C:
    • Maszyna jest oparta na rejestrach, a rozmiar ramek jest stały podczas tworzenia. Każda ramka składa się z określonej liczby rejestrów (określonej przez metodę) oraz wszelkich danych dodatkowych potrzebnych do wykonania metody, takich jak (ale nie wyłącznie) licznik programu i odniesienie do pliku .dex zawierającego metodę .
    • W przypadku stosowania do wartości bitowych (takich jak liczby całkowite i liczby zmiennoprzecinkowe) rejestry są uznawane za szerokie na 32 bity. Dla wartości 64-bitowych używane są sąsiednie pary rejestrów. Nie ma wymogu wyrównania dla par rejestrów.
    • Rejestry używane do odniesień do obiektów są uważane za wystarczająco szerokie, aby pomieścić dokładnie jedno takie odniesienie.
    • Jeśli chodzi o reprezentację bitową, (Object) null == (int) 0 .
    • N argumentów metody ląduje w kolejności w ostatnich N rejestrach ramki wywołania metody. Szerokie argumenty zużywają dwa rejestry. Do metod instancji przekazywane jest odwołanie this jako pierwszy argument.
  • Jednostką pamięci w strumieniu instrukcji jest 16-bitowa wielkość bez znaku. Niektóre bity w niektórych instrukcjach są ignorowane / muszą wynosić zero.
  • Instrukcje nie są bezpodstawnie ograniczone do określonego typu. Na przykład instrukcje, które przesuwają wartości rejestrów 32-bitowych bez interpretacji, nie muszą określać, czy przesuwają liczby całkowite, czy zmiennoprzecinkowe.
  • Istnieją oddzielnie wyliczane i indeksowane pule stałe zawierające odniesienia do ciągów, typów, pól i metod.
  • Dane literału bitowego są reprezentowane w strumieniu instrukcji.
  • Ponieważ w praktyce rzadko zdarza się, aby metoda wymagała więcej niż 16 rejestrów, a potrzeba więcej niż ośmiu rejestrów jest dość powszechna, wiele instrukcji ogranicza się tylko do adresowania pierwszych 16 rejestrów. Jeśli jest to racjonalnie możliwe, instrukcje umożliwiają odwoływanie się do maksymalnie pierwszych 256 rejestrów. Ponadto niektóre instrukcje mają warianty, które pozwalają na znacznie większą liczbę rejestrów, w tym parę instrukcji move catch-all, które mogą adresować rejestry z zakresu v0v65535 . W przypadkach, gdy nie jest dostępny wariant instrukcji adresowania żądanego rejestru, oczekuje się, że zawartość rejestru zostanie przeniesiona z rejestru pierwotnego do rejestru dolnego (przed operacją) i/lub przeniesiona z rejestru dolnego wyniku do rejestru wysokiego zarejestruj się (po operacji).
  • Istnieje kilka „pseudoinstrukcji”, które służą do przechowywania ładunków danych o zmiennej długości, do których odwołują się zwykłe instrukcje (na przykład fill-array-data ). Z takimi instrukcjami nie można nigdy spotkać się w trakcie normalnego wykonywania. Ponadto instrukcje muszą być umieszczone w parzystych przesunięciach kodu bajtowego (tj. wyrównane 4-bajtowo). Aby spełnić ten wymóg, narzędzia generujące dex muszą emitować dodatkową instrukcję nop jako odstępnik, jeśli w przeciwnym razie taka instrukcja byłaby niewyrównana. Wreszcie, chociaż nie jest to wymagane, oczekuje się, że większość narzędzi zdecyduje się na emisję tych instrukcji na końcach metod, ponieważ w przeciwnym razie prawdopodobnie potrzebne byłyby dodatkowe instrukcje do ich rozgałęzienia.
  • Po zainstalowaniu w działającym systemie niektóre instrukcje mogą zostać zmienione, zmieniając ich format, w ramach optymalizacji statycznego łączenia w czasie instalacji. Ma to na celu umożliwienie szybszego wykonania, gdy znane jest powiązanie. Sugerowane warianty można znaleźć w powiązanym dokumencie dotyczącym formatów instrukcji . Słowo „sugerowane” zostało użyte rozsądnie; ich wdrożenie nie jest obowiązkowe.
  • Składnia człowieka i mnemonika:
    • Porządkowanie argumentów według źródła i źródła.
    • Niektóre kody operacji mają jednoznaczny przyrostek nazwy wskazujący typ (y), na których działają:
      • Ogólne 32-bitowe kody operacji są nieoznaczone.
      • Ogólne 64-bitowe kody operacji mają przyrostek -wide .
      • Do kodów operacji specyficznych dla typu dodawany jest przyrostek określający ich typ (lub prosty skrót), jeden z następujących: -boolean -byte -char -short -int -long -float -double -object -string -class -void .
    • Niektóre kody operacji mają ujednoznaczniający przyrostek umożliwiający rozróżnienie w przeciwnym razie identycznych operacji, które mają różne układy instrukcji lub opcje. Te przyrostki są oddzielone od głównych nazw ukośnikiem („ / ”) i istnieją głównie po to, aby zapewnić mapowanie jeden do jednego ze stałymi statycznymi w kodzie, który generuje i interpretuje pliki wykonywalne (to znaczy w celu zmniejszenia niejednoznaczności dla ludzi).
    • W niniejszych opisach szerokość wartości (wskazująca np. zakres stałej lub liczbę możliwych do adresowania rejestrów) jest podkreślana poprzez użycie znaku przypadającego na cztery bity szerokości.
    • Przykładowo w instrukcji „ move-wide/from16 vAA, vBBBB ”:
      • move ” to podstawowy kod operacji, wskazujący podstawową operację (przesunięcie wartości rejestru).
      • wide ” to przyrostek nazwy wskazujący, że operuje na szerokich (64-bitowych) danych.
      • from16 ” to przyrostek kodu operacji, wskazujący wariant, który jako źródło ma odniesienie do rejestru 16-bitowego.
      • vAA ” to rejestr docelowy (co wynika z operacji; ponownie obowiązuje zasada, że ​​argumenty docelowe są zawsze podawane jako pierwsze), który musi należeć do zakresu v0v255 .
      • vBBBB ” to rejestr źródłowy, który musi należeć do zakresu v0v65535 .
  • Zobacz dokument dotyczący formatów instrukcji, aby uzyskać więcej szczegółów na temat różnych formatów instrukcji (wymienionych w sekcji „Opcje i format”), a także szczegółów na temat składni kodu operacji.
  • Zobacz dokument formatu pliku .dex , aby uzyskać więcej szczegółów na temat tego, gdzie kod bajtowy pasuje do szerszego obrazu.

Podsumowanie zestawu kodów bajtowych

Operacje i formatowanie Mnemonika / składnia Argumenty Opis
00 10x nie Cykle odpadów.

Uwaga: pseudoinstrukcje przenoszące dane są oznaczone tym kodem operacji, w którym to przypadku starszy bajt jednostki kodu operacji wskazuje naturę danych. Zobacz „Format packed-switch-payload ”, „Format sparse-switch-payload ” i „Format fill-array-data-payload ” poniżej.

01 12x przesuń vA, vB A: rejestr docelowy (4 bity)
B: rejestr źródłowy (4 bity)
Przenieś zawartość jednego rejestru nieobiektowego do innego.
02 22x przesuń/z 16 vAA, vBBBB A: rejestr docelowy (8 bitów)
B: rejestr źródłowy (16 bitów)
Przenieś zawartość jednego rejestru nieobiektowego do innego.
03 32x ruch/16 vAAAA, vBBBB A: rejestr docelowy (16 bitów)
B: rejestr źródłowy (16 bitów)
Przenieś zawartość jednego rejestru nieobiektowego do innego.
04 12x poruszaj się szeroko vA, vB A: para rejestrów docelowych (4 bity)
B: para rejestrów źródłowych (4 bity)
Przenieś zawartość jednej pary rejestrów do drugiej.

Uwaga: Przejście z v N na v N-1 lub v N+1 jest legalne, więc implementacje muszą zapewnić odczytanie obu połówek pary rejestrów, zanim cokolwiek zostanie zapisane.

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

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

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

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

07 12x przesuń obiekt vA, vB A: rejestr docelowy (4 bity)
B: rejestr źródłowy (4 bity)
Przenieś zawartość 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)
Przenieś zawartość 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)
Przenieś zawartość jednego rejestru zawierającego obiekty do innego.
0a 11x wynik ruchu vAA A: rejestr docelowy (8 bitów) Przenieś jednowyrazowy, nieobiektowy wynik ostatniego invoke- kind do wskazanego rejestru. Należy to zrobić jako instrukcję bezpośrednio po invoke- kind którego wynik (jednowyrazowy, nieobiektowy) nie powinien być ignorowany; gdziekolwiek indziej jest nieważne.
0b 11x vAA w całym wyniku ruchu A: para rejestrów docelowych (8 bitów) Przenieś wynik podwójnego słowa ostatniego invoke- kind do wskazanej pary rejestrów. Należy to zrobić jako instrukcję bezpośrednio po invoke- kind którego wynik (podwójne słowo) nie powinien być ignorowany; gdziekolwiek indziej jest nieważne.
0c 11x przesuń obiekt-wynikowy vAA A: rejestr docelowy (8 bitów) Przenieś wynik obiektu ostatniego invoke- kind do wskazanego rejestru. Należy to wykonać jako instrukcję bezpośrednio po invoke- kind lub filled-new-array której wynik (obiektu) nie powinien być ignorowany; gdziekolwiek indziej jest nieważne.
0d 11x wyjątek ruchu vAA A: rejestr docelowy (8 bitów) Zapisz właśnie przechwycony wyjątek w podanym rejestrze. Musi to być pierwsza instrukcja dowolnej procedury obsługi wyjątku, której przechwycony wyjątek nie ma być ignorowany, a instrukcja ta może zawsze występować tylko jako pierwsza instrukcja obsługi wyjątku; gdziekolwiek indziej jest nieważne.
0e 10x zwrot-nieważny Powrót z metody void .
0f 11x zwrócić vAA A: rejestr wartości zwracanej (8 bitów) Powrót z metody nie zwracającej wartości obiektowej o pojedynczej szerokości (32-bitowej).
10 11x vAA o szerokim zakresie zwrotu A: zwracana para rejestrów wartości (8 bitów) Powrót z metody zwracającej wartość o podwójnej szerokości (64-bitowej).
11 11x obiekt zwracany vAA A: rejestr wartości zwracanej (8 bitów) Powrót z metody zwracającej obiekt.
12 11n stała/4 vA, #+B A: rejestr docelowy (4 bity)
B: podpisany int (4 bity)
Przenieś podaną wartość literału (ze znakiem rozszerzonym do 32 bitów) do określonego rejestru.
13 21s stała/16 vAA, #+BBBB A: rejestr docelowy (8 bitów)
B: podpisany int (16 bitów)
Przenieś podaną wartość literału (ze znakiem rozszerzonym do 32 bitów) do określonego rejestru.
14 31i stała vAA, #+BBBBBBBB A: rejestr docelowy (8 bitów)
B: dowolna stała 32-bitowa
Przenieś podaną wartość literału do określonego rejestru.
15 21h stała/wysoka16 vAA, #+BBBB0000 A: rejestr docelowy (8 bitów)
B: podpisany int (16 bitów)
Przenieś podaną wartość literału (z prawej strony zera rozszerzonego do 32 bitów) do określonego rejestru.
16 21s const-wide/16 vAA, #+BBBB A: rejestr docelowy (8 bitów)
B: podpisany int (16 bitów)
Przenieś podaną wartość literału (ze znakiem rozszerzonym do 64 bitów) do określonej pary rejestrów.
17 31i const-wide/32 vAA, #+BBBBBBBB A: rejestr docelowy (8 bitów)
B: podpisany int (32 bity)
Przenieś podaną wartość literału (ze znakiem rozszerzonym do 64 bitów) do określonej pary rejestrów.
18 51l const-wide vAA, #+BBBBBBBBBBBBBB A: rejestr docelowy (8 bitów)
B: dowolna stała podwójnej szerokości (64-bitowa).
Przenieś podaną wartość literału do określonej pary rejestrów.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: rejestr docelowy (8 bitów)
B: podpisany int (16 bitów)
Przenieś podaną wartość literału (z prawej strony zera rozszerzoną do 64 bitów) do określonej pary rejestrów.
1a 21c const-string vAA, string@BBBB A: rejestr docelowy (8 bitów)
B: indeks ciągu
Przenieś odwołanie do ciągu określonego przez dany indeks do określonego rejestru.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: rejestr docelowy (8 bitów)
B: indeks ciągu
Przenieś odwołanie do ciągu określonego przez dany indeks do określonego rejestru.
1c 21c const-klasa vAA, typ@BBBB A: rejestr docelowy (8 bitów)
B: wpisz indeks
Przenieś odwołanie do klasy określonej przez dany indeks do określonego rejestru. W przypadku, gdy wskazany typ jest pierwotny, zostanie zapisane odwołanie do zdegenerowanej klasy typu pierwotnego.
1d 11x monitor-wprowadź vAA A: rejestr nośny odniesienia (8 bitów) Zdobądź monitor dla wskazanego obiektu.
1e 11x wyjście monitora vAA A: rejestr nośny odniesienia (8 bitów) Zwolnij monitor dla wskazanego obiektu.

Uwaga: Jeśli ta instrukcja ma zgłosić wyjątek, musi to zrobić tak, jakby komputer przekroczył już tę instrukcję. Przydatne może być myślenie o tym jako o pomyślnym wykonaniu instrukcji (w pewnym sensie) i wyjątku zgłoszonym po instrukcji, ale zanim następna będzie miała szansę na wykonanie. Ta definicja umożliwia metodzie użycie bloku catch-all (np. finally ) czyszczenia monitora jako czyszczenia monitora dla samego bloku, jako sposobu na obsługę dowolnych wyjątków, które mogą zostać zgłoszone w wyniku historycznej implementacji Thread.stop() , zachowując jednocześnie odpowiednią higienę monitora.

1f 21c check-cast vAA, typ@BBBB A: rejestr nośny odniesienia (8 bitów)
B: indeks typu (16 bitów)
Zgłoś ClassCastException , jeśli odwołanie w danym rejestrze nie może zostać rzutowane na wskazany typ.

Uwaga: Ponieważ A musi zawsze być referencją (a nie wartością pierwotną), niekoniecznie zakończy się to niepowodzeniem w czasie wykonywania (to znaczy wygeneruje wyjątek), jeśli B odwołuje się do typu pierwotnego.

20 22c instancja vA, vB, typ@CCCC A: rejestr docelowy (4 bity)
B: rejestr odniesienia (4 bity)
C: indeks typu (16 bitów)
Zapisz w danym rejestrze docelowym 1 , jeśli wskazana referencja jest instancją danego typu, lub 0 jeśli nie.

Uwaga: Ponieważ B musi zawsze być odniesieniem (a nie wartością pierwotną), zawsze spowoduje to zapisanie 0 , jeśli C odnosi się do typu pierwotnego.

21 12x długość tablicy vA, vB A: rejestr docelowy (4 bity)
B: rejestr nośny tablicy referencyjnej (4 bity)
Zapisz w podanym rejestrze docelowym długość wskazanej tablicy, we wpisach
22 21c nowa instancja vAA, typ@BBBB A: rejestr docelowy (8 bitów)
B: wpisz indeks
Skonstruuj nową instancję wskazanego typu, przechowując odwołanie do niej w miejscu docelowym. Typ musi odnosić się do klasy niebędącej tablicą.
23 22c nowa tablica vA, vB, typ@CCCC A: rejestr docelowy (4 bity)
B: rejestr wielkości
C: wpisz indeks
Skonstruuj nową tablicę wskazanego typu i rozmiaru. Typ musi być typem tablicowym.
24 35c wypełniona-nowa-tablica {vC, vD, vE, vF, vG}, typ@BBBB A: rozmiar tablicy i liczba słów argumentu (4 bity)
B: indeks typu (16 bitów)
C..G: rejestry argumentów (po 4 bity)
Skonstruuj tablicę danego typu i rozmiaru, wypełniając ją dostarczoną zawartością. Typ musi być typem tablicowym. Zawartość tablicy musi składać się z jednego słowa (to znaczy nie może zawierać tablic typu long ani double , ale dopuszczalne są typy referencyjne). Skonstruowana instancja jest przechowywana jako „wynik” w taki sam sposób, w jaki instrukcje wywołania metody przechowują swoje wyniki, zatem skonstruowana instancja musi zostać przeniesiona do rejestru z bezpośrednio następującą instrukcją 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 słów argumentu (8 bitów)
B: indeks typu (16 bitów)
C: rejestr pierwszego argumentu (16 bitów)
N = A + C - 1
Skonstruuj tablicę danego typu i rozmiaru, wypełniając ją dostarczoną zawartością. Wyjaśnienia i ograniczenia są takie same jak w filled-new-array opisanej powyżej.
26 31t fill-array-data vAA, +BBBBBBBB (z dodatkowymi danymi określonymi poniżej w „formacie 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 podaną tablicę wskazanymi danymi. Odniesienie musi odnosić się do tablicy prymitywów, a tabela danych musi odpowiadać jej typowi i nie może zawierać więcej elementów, niż zmieści się w tablicy. Oznacza to, że tablica może być większa niż tabela, a jeśli tak, ustawiane są tylko początkowe elementy tablicy, resztę pozostawiając samą.
27 11x rzuć vAA A: rejestr zawierający wyjątki (8 bitów)
Zgłoś wskazany wyjątek.
28 10t mam +AA A: przesunięcie gałęzi ze znakiem (8 bitów) Bezwarunkowy skok do wskazanej instrukcji.

Uwaga: Przesunięcie gałęzi nie może wynosić 0 . (Pętlę wirującą można legalnie zbudować za pomocą goto/32 lub włączając nop jako cel przed rozgałęzieniem.)

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

Uwaga: Przesunięcie gałęzi nie może wynosić 0 . (Pętlę wirującą można legalnie zbudować za pomocą goto/32 lub włączając nop jako cel przed rozgałęzieniem.)

2a 30t goto/32 +AAAAAAAA A: przesunięcie gałęzi ze znakiem (32 bity)
Bezwarunkowy skok do wskazanej instrukcji.
2b 31t pakiet-switch vAA, +BBBBBBBB (z dodatkowymi danymi określonymi poniżej w „formacie packed-switch-payload ”) A: zarejestruj się, aby przetestować
B: przesunięcie „gałęzi” ze znakiem do pseudoinstrukcji danych tabeli (32 bity)
Przejdź do nowej instrukcji w oparciu o wartość w danym rejestrze, korzystając z tabeli przesunięć odpowiadających każdej wartości w określonym zakresie całkowitym, lub przejdź do następnej instrukcji, jeśli nie ma dopasowania.
2c 31t sparse-switch vAA, +BBBBBBBB (z dodatkowymi danymi określonymi poniżej w „formacie sparse-switch-payload ”) A: zarejestruj się, aby przetestować
B: przesunięcie „gałęzi” ze znakiem do pseudoinstrukcji danych tabeli (32 bity)
Przejdź do nowej instrukcji w oparciu o wartość w danym rejestrze, korzystając z uporządkowanej tabeli par wartości-przesunięcie lub przejdź do następnej instrukcji, jeśli nie ma dopasowania.
2d..31 23x cmp rodzaj vAA, vBB, vCC
2d: cmpl-float (odchylenie lt)
2e: cmpg-float (odchylenie gt)
2f: cmpl-double (lt odchylenie)
30: cmpg-double (odchylenie gt)
31: długość cm
A: rejestr docelowy (8 bitów)
B: pierwszy rejestr źródłowy lub para
C: drugi rejestr źródłowy lub para
Wykonaj wskazane porównanie zmiennoprzecinkowe lub long , ustawiając a na 0 , jeśli b == c , 1 jeśli b > c , lub -1 jeśli b < c . „Odchylenie” wymienione dla operacji zmiennoprzecinkowych wskazuje, jak traktowane są porównania NaN : instrukcje „gt odchylenie” zwracają 1 dla porównań NaN , a instrukcje „lt odchylenie” zwracają -1 .

Na przykład, aby sprawdzić, czy zmiennoprzecinkowy x < y zaleca się użycie cmpg-float ; wynik -1 oznacza, że ​​test był prawdziwy, a pozostałe wartości wskazują, że był fałszywy z powodu prawidłowego porównania lub dlatego, że jedną z wartości było NaN .

32..37 22t if- test vA, vB, +CCCC
32: jeśli-równ
33: jeśli-nie
34: jeśli-lt
35: jeśli-ge
36: jeśli-gt
37: jeśli-le
A: pierwszy rejestr do testowania (4 bity)
B: drugi rejestr do testowania (4 bity)
C: przesunięcie gałęzi ze znakiem (16 bitów)
Przejdź do podanego miejsca docelowego, jeśli wartości danych dwóch rejestrów zostaną porównane zgodnie ze specyfikacją.

Uwaga: Przesunięcie gałęzi nie może wynosić 0 . (Pętlę wirującą można zgodnie z prawem zbudować albo poprzez rozgałęzienie wokół wstecznego goto , albo przez dodanie nop jako celu przed rozgałęzieniem.)

38..3d 21t if- test z vAA, +BBBB
38: jeśli-równ
39: jeśli-nez
3a: jeśli-ltz
3b: jeśli-gez
3c: jeśli-gtz
3d: jeśli-lez
A: zarejestruj się, aby przetestować (8 bitów)
B: przesunięcie gałęzi ze znakiem (16 bitów)
Przejdź do podanego miejsca docelowego, jeśli wartość danego rejestru porównuje się z 0, jak określono.

Uwaga: Przesunięcie gałęzi nie może wynosić 0 . (Pętlę wirującą można zgodnie z prawem zbudować albo poprzez rozgałęzienie wokół wstecznego goto , albo przez dodanie nop jako celu przed rozgałęzieniem.)

3e..43 10x (nie używany) (nie używany)
44..51 23x tablica vAA, vBB, vCC
44: wiek
45: w całym wieku
46: obiekt wieku
47: wartość logiczna wieku
48: bajt wieku
49: wiek-char
4a: krótki wiek
4b: aput
4c: szeroki na aput
4d: obiekt-aput
4e: aput-boolean
4f: aput-bajt
50: aput-char
51: aput-krótki
A: rejestr wartości lub para; może być źródłem lub miejscem docelowym (8 bitów)
B: rejestr tablicowy (8 bitów)
C: rejestr indeksowy (8 bitów)
Wykonaj zidentyfikowaną operację na tablicy pod wskazanym indeksem danej tablicy, ładując lub zapisując do rejestru wartości.
52..5f 22c instancjaop vA, vB, pole@CCCC
52: iget
53: szeroki iget
54: obiekt iget
55: iget-boolean
56: bajt iget
57: iget-char
58: iget-short
59: iput
5a: obejmujący całe wejście
5b: obiekt iput
5c: iput-boolean
5d: bajt iput
5e: iput-char
5f: iput-short
A: rejestr wartości lub para; może być źródłem lub miejscem docelowym (4 bity)
B: rejestr obiektowy (4 bity)
C: indeks odniesienia pola instancji (16 bitów)
Wykonaj operację polową instancji zidentyfikowanego obiektu na zidentyfikowanym polu, ładując lub zapisując do rejestru wartości.

Uwaga: Te kody operacji są rozsądnymi kandydatami do łączenia statycznego, zmieniając argument pola tak, aby był bardziej bezpośrednim przesunięciem.

60..6d 21c s staticop vAA, pole@BBBB
60: sget
61: szeroki
62: obiekt-sget
63: sget-boolean
64: sget-bajt
65: sget-char
66: sget-krótki
67: pluć
68: szeroka
69: obiekt plucia
6a: sput-boolean
6b: bajt sput
6c: sput-char
6d: splunięcie krótkie
A: rejestr wartości lub para; może być źródłem lub miejscem docelowym (8 bitów)
B: indeks odniesienia pola statycznego (16 bitów)
Wykonaj operację pola statycznego zidentyfikowanego obiektu ze zidentyfikowanym polem statycznym, ładując lub zapisując do rejestru wartości.

Uwaga: Te kody operacji są rozsądnymi kandydatami do łączenia statycznego, zmieniając argument pola tak, aby był bardziej bezpośrednim przesunięciem.

6e..72 35c invoke- kind {vC, vD, vE, vF, vG}, met@BBBB
6e: wywołanie-wirtualne
6f: wywołaj super
70: wywołanie bezpośrednie
71: wywołanie statyczne
72: interfejs wywołania
A: liczba słów argumentu (4 bity)
B: indeks odniesienia metody (16 bitów)
C..G: rejestry argumentów (po 4 bity)
Wywołaj wskazaną metodę. Wynik (jeśli istnieje) może zostać zapisany z odpowiednim wariantem move-result* jako instrukcja bezpośrednio następująca.

invoke-virtual służy do wywoływania normalnej metody wirtualnej (metody, która nie jest private , static ani final i nie jest również konstruktorem).

Gdy method_id odwołuje się do metody klasy niebędącej interfejsem, invoke-super służy do wywołania metody wirtualnej najbliższej nadklasy (w przeciwieństwie do metody o tym samym method_id w klasie wywołującej). Obowiązują te same ograniczenia metod, co w przypadku invoke-virtual .

W plikach Dex w wersji 037 lub nowszej, jeśli method_id odnosi się do metody interfejsu, invoke-super służy do wywołania najbardziej szczegółowej, niezastąpionej wersji tej metody zdefiniowanej w tym interfejsie. Obowiązują te same ograniczenia metod, co w przypadku invoke-virtual . W plikach Dex wcześniejszych niż wersja 037 posiadanie method_id interfejsu jest nielegalne i niezdefiniowane.

invoke-direct służy do wywoływania static metody bezpośredniej (to znaczy metody instancji, której ze swej natury nie można zastąpić, a mianowicie metody instancji private lub konstruktora).

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

invoke-interface służy do wywoływania metody interface , to znaczy 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ą rozsądnymi kandydatami do łączenia statycznego, zmieniając argument metody na bardziej bezpośrednie przesunięcie (lub jego parę).

73 10x (nie używany) (nie używany)
74..78 3rc invoke- kind /range {vCCCC .. vNNNN}, met@BBBB
74: wywołaj-wirtualny/zakres
75: wywołanie-super/zakres
76: wywołanie bezpośrednie/zakres
77: wywołanie-statyczne/zakres
78: interfejs/zakres wywołania
A: liczba słów argumentu (8 bitów)
B: indeks odniesienia metody (16 bitów)
C: rejestr pierwszego argumentu (16 bitów)
N = A + C - 1
Wywołaj wskazaną metodę. Zobacz opis pierwszego invoke- kind powyżej, aby uzyskać szczegółowe informacje, zastrzeżenia i sugestie.
79..7a 10x (nie używany) (nie używany)
7b..8f 12x unop vA, vB
7b: neg-int
7c: nie-int
7d: neg-długi
7e: niezbyt długo
7f: pływak ujemny
80: neg-podwójny
81: int-to-long
82: od wejścia do pływaka
83: int-to-double
84: długi do int
85: długi do pływania
86: długi do podwójnego
87: float-to-int
88: pływak za długi
89: float do double
8a: podwójnie do int
8b: podwójnie za długi
8c: double-to-float
8d: liczba całkowita do bajtu
8e: int-to-char
8f: od krótkiego do krótkiego
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: dodatek
91: podwł
92: mul-int
93: dzielenie-int
94: rem-int
95: i-int
96: lub-int
97: xor-int
98: shl-int
99: shr-int
9a: ushr-int
9b: dodatek długi
9c: niezbyt długi
9d: mul-długi
9e: długi div
9f: rem-długi
a0: i-długie
a1: lub-długi
a2: xor-long
a3: shl-long
a4: shr-długi
a5: długi ushr
a6: add-float
a7: pływak podwodny
a8: mul-float
a9: div-float
aa: rem-float
ab: dodaj-double
ac: sub-podwójne
reklama: 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, zapisując wynik w rejestrze docelowym.

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

b0..por. 12x binop /2addr vA, vB
b0: dodatek/2adres
b1: pod-int/2addr
b2: mul-int/2addr
b3: div-int/2addr
b4: rem-int/2addr
b5: i-int/2addr
b6: or-int/2addr
b7: xor-int/2addr
b8: shl-int/2addr
b9: shr-int/2addr
ba: ushr-int/2addr
bb: dodaj-długi/2addr
bc: sub-długi/2addr
bd: mul-long/2addr
być: div-long/2addr
bf: rem-long/2addr
c0: i-long/2addr
c1: lub-długi/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-podwójne/2addr
cd: mul-double/2addr
ce: div-double/2addr
por.: rem-double/2addr
A: docelowy i pierwszy rejestr źródłowy lub para (4 bity)
B: drugi rejestr źródłowy lub para (4 bity)
Wykonaj zidentyfikowaną operację binarną na dwóch rejestrach źródłowych, zapisując wynik w pierwszym rejestrze źródłowym.

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

d0..d7 22s binop /lit16 vA, vB, #+CCCC
d0: dodatek/lit16
d1: rsub-int (odwrotne odejmowanie)
d2: mul-int/lit16
d3: div-int/lit16
d4: rem-int/lit16
d5: i-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 literału (drugi argument), zapisując wynik w rejestrze docelowym.

Uwaga: rsub-int nie ma przyrostka, ponieważ ta wersja jest głównym kodem operacji w swojej rodzinie. Poniżej znajdziesz także szczegółowe informacje na temat jego semantyki.

d8..e2 22b binop /lit8 vAA, vBB, #+CC
d8: dodatek/lit8
d9: rsub-int/lit8
da: mul-int/lit8
db: div-int/lit8
dc: rem-int/lit8
dd: i-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 literału (drugi argument), zapisując wynik w rejestrze docelowym.

Uwaga: Poniżej znajdują się szczegółowe informacje na temat semantyki rsub-int .

e3..f9 10x (nie używany) (nie używany)
tak 45cc invoke-polimorficzny {vC, vD, vE, vF, vG}, met@BBBB, proto@HHHH A: liczba słów argumentu (4 bity)
B: indeks odniesienia metody (16 bitów)
C: odbiornik (4 bity)
D..G: rejestry argumentów (po 4 bity)
H: indeks referencyjny prototypu (16 bitów)
Wywołaj wskazaną metodę polimorficzną podpisu. Wynik (jeśli istnieje) może zostać zapisany z odpowiednim wariantem move-result* jako instrukcja bezpośrednio następująca.

Odwołanie do metody musi odnosić się do metody polimorficznej sygnatury, takiej jak java.lang.invoke.MethodHandle.invoke lub java.lang.invoke.MethodHandle.invokeExact .

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

Odwołanie do prototypu opisuje dostarczone typy argumentów i oczekiwany typ zwracany.

invoke-polymorphic może powodować wyjątki podczas wykonywania. Wyjątki opisano w dokumentacji API dla wywoływanej metody polimorficznej podpisu.

Występuje w plikach Dex od wersji 038 i nowszych.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: liczba słów argumentu (8 bitów)
B: indeks odniesienia metody (16 bitów)
C: odbiornik (16 bitów)
H: indeks referencyjny prototypu (16 bitów)
N = A + C - 1
Wywołaj wskazany uchwyt metody. Aby uzyskać szczegółowe informacje, zobacz powyższy opis invoke-polymorphic .

Występuje w plikach Dex od wersji 038 i nowszych.
FC 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB A: liczba słów argumentu (4 bity)
B: indeks odniesienia do witryny wywoławczej (16 bitów)
C..G: rejestry argumentów (po 4 bity)
Rozwiązuje i wywołuje wskazaną stronę wywołania. Wynik wywołania (jeśli istnieje) może zostać zapisany z odpowiednim wariantem move-result* jako następna instrukcja.

Ta instrukcja jest wykonywana w dwóch fazach: rozpoznawanie miejsca wywołania i wywołanie miejsca wywołania.

Rozpoznawanie witryny wywołań sprawdza, czy wskazana witryna wywołań ma powiązaną instancję java.lang.invoke.CallSite . Jeśli nie, wywoływana jest metoda linkera ładowania początkowego dla wskazanej strony wywołania przy użyciu argumentów znajdujących się w pliku DEX (patrz call_site_item ). Metoda linkera bootstrap zwraca instancję java.lang.invoke.CallSite , która zostanie następnie powiązana ze wskazaną witryną wywołań, jeśli nie istnieje żadne powiązanie. Być może inny wątek już jako pierwszy dokonał skojarzenia, a jeśli tak, wykonywanie instrukcji jest kontynuowane z pierwszą powiązaną instancją java.lang.invoke.CallSite .

Wywołanie witryny wywołania jest wykonywane w obiekcie docelowym java.lang.invoke.MethodHandle rozwiązanej instancji java.lang.invoke.CallSite . Cel jest wywoływany tak, jakby wykonywał invoke-polymorphic (opisane powyżej) przy użyciu uchwytu metody i argumentów instrukcji invoke-custom jako argumentów dokładnego wywołania uchwytu metody.

Wyjątki zgłaszane przez metodę linkera ładowania początkowego są opakowane w java.lang.BootstrapMethodError . Błąd BootstrapMethodError jest również zgłaszany, jeśli:
  • metoda linkera ładowania początkowego nie zwraca instancji java.lang.invoke.CallSite .
  • zwrócona java.lang.invoke.CallSite zawiera docelowy uchwyt metody null .
  • cel uchwytu metody nie jest żądanego typu.
Występuje w plikach Dex od wersji 038 i nowszych.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: liczba słów argumentu (8 bitów)
B: indeks odniesienia do witryny wywoławczej (16 bitów)
C: rejestr pierwszego argumentu (16 bitów)
N = A + C - 1
Rozwiąż problem i wywołaj witrynę połączeń. Aby uzyskać szczegółowe informacje, zobacz powyższy opis invoke-custom .

Występuje w plikach Dex od wersji 038 i nowszych.
piątek 21c const-metoda-handle vAA, metoda_handle@BBBB A: rejestr docelowy (8 bitów)
B: indeks uchwytu metody (16 bitów)
Przenieś odwołanie do uchwytu metody określonego przez dany indeks do określonego rejestru.

Występuje w plikach Dex od wersji 039 i nowszych.
ff 21c typ-metody stałej vAA, proto@BBBB A: rejestr docelowy (8 bitów)
B: odniesienie do prototypu metody (16 bitów)
Przenieś referencję do prototypu metody określonego przez podany indeks do określonego rejestru.

Występuje w plikach Dex od wersji 039 i nowszych.

format pakietu danych-przełącznika

Nazwa Format Opis
ident ushort = 0x0100 identyfikowanie pseudokodu operacji
rozmiar skrócić ilość wpisów w tabeli
pierwszy_klucz wew pierwsza (i najniższa) wartość przypadku przełącznika
cele int[] lista celów oddziałów względnych pod względem size . Cele odnoszą się do adresu kodu operacji przełącznika, a nie do tej tabeli.

Uwaga: Całkowita liczba jednostek kodu dla instancji tej tabeli wynosi (size * 2) + 4 .

format ładunku rzadkiego przełącznika

Nazwa Format Opis
ident ushort = 0x0200 identyfikowanie pseudokodu operacji
rozmiar skrócić ilość wpisów w tabeli
Klucze int[] lista wartości kluczy size , posortowana od najniższej do najwyższej
cele int[] lista celów gałęzi względnych size , z których każdy odpowiada wartości klucza w tym samym indeksie. Cele odnoszą się do adresu kodu operacji przełącznika, a nie do tej tabeli.

Uwaga: Całkowita liczba jednostek kodu dla instancji tej tabeli wynosi (size * 4) + 2 .

format wypełnienia-tablicy-danych-ładunek

Nazwa Format Opis
ident ushort = 0x0300 identyfikowanie pseudokodu operacji
szerokość_elementu skrócić liczba bajtów w każdym elemencie
rozmiar uint ilość elementów w tabeli
dane ubajt[] wartości danych

Uwaga: Całkowita liczba jednostek kodu dla instancji tej tabeli wynosi (size * element_width + 1) / 2 + 4 .

Szczegóły operacji matematycznej

Uwaga: Operacje zmiennoprzecinkowe muszą być zgodne z regułami IEEE 754, stosując zaokrąglanie do najbliższego i stopniowe niedopełnienie, chyba że określono inaczej.

Kod operacji Semantyka C Notatki
neg-int int32 a;
int32 wynik = -a;
Jednoargumentowe uzupełnienie do dwójek.
nie-wew int32 a;
wynik int32 = ~a;
Jednoargumentowe uzupełnienie.
neg-długi int64 a;
int64 wynik = -a;
Jednoargumentowe uzupełnienie do dwójek.
nie długo int64 a;
int64 wynik = ~a;
Jednoargumentowe uzupełnienie.
neg-float pływać;
wynik zmiennoprzecinkowy = -a;
Negacja zmiennoprzecinkowa.
neg-podwójne podwójne A;
podwójny wynik = -a;
Negacja zmiennoprzecinkowa.
za długi int32 a;
int64 wynik = (int64) a;
Rozszerzenie znaku int32 na int64 .
Int-to-Float int32 a;
float wynik = (float) a;
Konwersja int32 na float , przy użyciu obrońcy na jeden. Traci to precyzję niektórych wartości.
Int-to-Double int32 a;
podwójny wynik = (podwójny) a;
Konwersja int32 na double .
Długo do instalu int64 a;
int32 wynik = (int32) a;
Obcięcie int64 do int32 .
Długo-płodzący int64 a;
float wynik = (float) a;
Konwersja int64 na float , przy użyciu obrońcy na jeden. Traci to precyzję niektórych wartości.
Długo-podwójny int64 a;
podwójny wynik = (podwójny) a;
Konwersja int64 na double , przy użyciu obrońcy na jeden. Traci to precyzję niektórych wartości.
float-to-int float a;
int32 wynik = (int32) a;
Konwersja float na int32 , używając okrągłego zero. NaN i -0.0 (zero ujemne) konwertują na liczbę całkowitą 0 . Nieskończoności i wartości ze zbyt dużą wielkością, aby można je było przedstawić na 0x7fffffff lub -0x80000000 w zależności od znaku.
pływak do długiego float a;
Int64 wynik = (int64) a;
Konwersja float na int64 , za pomocą Round-Toward-Zero. Te same reguły przypadków szczególnych, co w przypadku float-to-int , z tym, że wartości poza zasięgiem są przekonwertowane na 0x7fffffffffffffff lub -0x8000000000000000 w zależności od znaku.
float to-podwójny float a;
podwójny wynik = (podwójny) a;
Konwersja float na double , zachowując dokładnie wartość.
podwójne na inst podwójne A;
int32 wynik = (int32) a;
Konwersja double na int32 , przy użyciu Round-Toward-Zero. Te same reguły przypadków szczególnych, co w przypadku float-to-int .
podwójnie do długiego podwójne A;
Int64 wynik = (int64) a;
Konwersja double na int64 , przy użyciu Round-Toward-Zero. Obowiązują tutaj te same zasady dotyczące szczególnych przypadków, co w przypadku float-to-long .
podwójne do floszu podwójne A;
float wynik = (float) a;
Konwersja double na float , przy użyciu obrońcy na jeden. Traci to precyzję niektórych wartości.
int-bajte int32 a;
Int32 wynik = (a << 24) >> 24;
Obcięcie int32 do int8 , podpisz rozszerzenie wyniku.
Int-to-Char int32 a;
Int32 wynik = a & 0xffff;
Obcięcie int32 do uint16 , bez przedłużenia znaku.
int-to-short int32 a;
Int32 wynik = (a << 16) >> 16;
Obcięcie int32 do int16 , podpisanie wyniku.
dodatek int32 a, b;
Int32 wynik = a + b;
Dodatek do komplementu dwójki.
Podpis int32 a, b;
Int32 wynik = a - b;
Odejmowanie komplementowania dwójki.
rsub-int int32 a, b;
Int32 wynik = b - a;
Odejmowanie odwrotnego odejmowania dwójki.
Mul-int int32 a, b;
Int32 wynik = a * b;
Mnożenie dwójki komplementu.
Div-int int32 a, b;
Int32 wynik = a / b;
Podział na całość, zaokrąglony w kierunku Zero (to znaczy obcięty na liczbę całkowitą). To rzuca ArithmeticException , jeśli b == 0 .
rem-int int32 a, b;
Int32 wynik = A % B;
Reszta komplementu po podziale. Znak wyniku jest taki sam jak w przypadku a , i jest dokładniej zdefiniowany jako result == a - (a / b) * b . To rzuca ArithmeticException , jeśli b == 0 .
i Inte int32 a, b;
Int32 wynik = a & b;
Bitwise i.
lub int int32 a, b;
Int32 wynik = a | B;
Bitwise lub.
xor-int int32 a, b;
Int32 wynik = a ^ b;
Bitwise Xor.
shl-int int32 a, b;
Int32 wynik = a << (b & 0x1f);
Bitwise Shift w lewo (z zamaskowanym argumentem).
shr-int int32 a, b;
Int32 wynik = a >> (b & 0x1f);
Bitwise podpisane w prawo (z zamaskowanym argumentem).
ushr-int uint32 a, b;
Int32 wynik = a >> (b & 0x1f);
Bitwise Unsigned Shift w prawo (z zamaskowanym argumentem).
Dodaj długie int64 a, b;
Int64 wynik = a + b;
Dodatek do komplementu dwójki.
Sub-długi int64 a, b;
Int64 wynik = a - b;
Odejmowanie komplementowania dwójki.
Mul-Long int64 a, b;
Int64 wynik = a * b;
Mnożenie dwójki komplementu.
Div-Long int64 a, b;
Int64 wynik = A / B;
Podział na całość, zaokrąglony w kierunku Zero (to znaczy obcięty na liczbę całkowitą). To rzuca ArithmeticException , jeśli b == 0 .
REM-Long int64 a, b;
Int64 wynik = A % B;
Reszta komplementu po podziale. Znak wyniku jest taki sam jak w przypadku a , i jest dokładniej zdefiniowany jako result == a - (a / b) * b . To rzuca ArithmeticException , jeśli b == 0 .
i długi int64 a, b;
Int64 wynik = A&B;
Bitwise i.
lub długie int64 a, b;
Int64 wynik = a | B;
Bitwise lub.
Xor-Long int64 a, b;
Int64 wynik = a ^ b;
Bitwise Xor.
SHL-Long int64 a;
int32 b;
Int64 wynik = a << (b & 0x3f);
Bitwise Shift w lewo (z zamaskowanym argumentem).
SHR-Long int64 a;
int32 b;
Int64 wynik = A >> (B & 0x3f);
Bitwise podpisane w prawo (z zamaskowanym argumentem).
USHR-Long uint64 a;
int32 b;
Int64 wynik = A >> (B & 0x3f);
Bitwise Unsigned Shift w prawo (z zamaskowanym argumentem).
Dodaj-float float a, b;
Wynik float = a + b;
Dodatek Punkt zmiennoprzecinkowy.
sub-float float a, b;
Wynik float = a - b;
Odejmowanie punktu zmiennoprzecinkowego.
mul-float float a, b;
Wynik float = a * b;
Mnożenie punktu zmiennoprzecinkowego.
Div-float float a, b;
Wynik float = a / b;
Dywizja zmiennoprzecinkowa.
Rem-Float float a, b;
Wynik float = a % b;
Pozostała reszta po podziale. Ta funkcja jest inna niż IEEE 754 pozostałe i jest zdefiniowana jako result == a - roundTowardZero(a / b) * b
Dodaj-podwójne Double A, B;
Podwójny wynik = a + b;
Dodatek Punkt zmiennoprzecinkowy.
podwójne Double A, B;
Podwójny wynik = a - b;
Odejmowanie punktu zmiennoprzecinkowego.
MUL-podwójne Double A, B;
Wynik podwójny = a * b;
Mnożenie punktu zmiennoprzecinkowego.
Div-Double Double A, B;
Wynik podwójny = A / B;
Dywizja zmiennoprzecinkowa.
REM-podwójny Double A, B;
Podwójny wynik = A % B;
Pozostała reszta po podziale. Ta funkcja jest inna niż IEEE 754 pozostałe i jest zdefiniowana jako result == a - roundTowardZero(a / b) * b