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
.
- 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
- 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 zakresiev0
–v65535
. 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 zakresiev0
–v255
. - „
vBBBB
” to rejestr źródłowy, który musi znajdować się w zakresiev0
–v65535
.
- „
- 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 |
|
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 |
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 |
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 |
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. |
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ż |
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ż |
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 rozmiaruC: 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ć |
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ć |
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 testowyB: 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 testowyB: 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 zmiennoprzecinkowego |
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ć |
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ć |
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.
Gdy W pliku Dex w wersji
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-kind opisie 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 |
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 |
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:
|
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 |
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:
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 i -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 .
|