Bytecode Dalvik

Conception générale

  • Le modèle de machine et les conventions d'appel sont censés imiter approximativement les architectures réelles courantes et les conventions d'appel de style C :
    • La machine est basée sur les registres et les cadres sont de taille fixe lors de la création. Chaque trame se compose d'un nombre particulier de registres (spécifié par la méthode) ainsi que de toutes les données complémentaires nécessaires pour exécuter la méthode, telles que (mais sans s'y limiter) le compteur de programme et une référence au fichier .dex qui contient la méthode .
    • Lorsqu'ils sont utilisés pour des valeurs binaires (telles que des nombres entiers et des nombres à virgule flottante), les registres sont considérés comme ayant une largeur de 32 bits. Des paires de registres adjacentes sont utilisées pour les valeurs 64 bits. Il n'y a aucune exigence d'alignement pour les paires de registres.
    • Lorsqu'ils sont utilisés pour des références d'objets, les registres sont considérés comme suffisamment larges pour contenir exactement une telle référence.
    • En termes de représentation au niveau du bit, (Object) null == (int) 0 .
    • Les N arguments d'une méthode atterrissent dans les N derniers registres de la trame d'invocation de la méthode, dans l'ordre. Les arguments larges consomment deux registres. Les méthodes d'instance reçoivent une référence this comme premier argument.
  • L'unité de stockage dans le flux d'instructions est une quantité non signée de 16 bits. Certains bits de certaines instructions sont ignorés / doivent être nuls.
  • Les instructions ne sont pas gratuitement limitées à un type particulier. Par exemple, les instructions qui déplacent des valeurs de registre 32 bits sans interprétation n'ont pas à spécifier si elles déplacent des entiers ou des flottants.
  • Il existe des pools de constantes énumérées et indexées séparément pour les références aux chaînes, types, champs et méthodes.
  • Les données littérales au niveau du bit sont représentées en ligne dans le flux d'instructions.
  • Parce qu'en pratique, il est rare qu'une méthode ait besoin de plus de 16 registres, et parce qu'il est raisonnablement courant d'avoir besoin de plus de huit registres, de nombreuses instructions se limitent à adresser uniquement les 16 premiers registres. Lorsque cela est raisonnablement possible, les instructions autorisent les références jusqu'aux 256 premiers registres. De plus, certaines instructions ont des variantes qui permettent un nombre de registres beaucoup plus important, y compris une paire d'instructions de move fourre-tout qui peuvent adresser des registres dans la plage v0v65535 . Dans les cas où une variante d'instruction n'est pas disponible pour adresser un registre souhaité, il est prévu que le contenu du registre soit déplacé du registre d'origine vers un registre bas (avant l'opération) et/ou déplacé d'un registre de résultat bas vers un registre haut. enregistrer (après l'opération).
  • Il existe plusieurs "pseudo-instructions" qui sont utilisées pour contenir des charges utiles de données de longueur variable, qui sont référencées par des instructions régulières (par exemple, fill-array-data ). De telles instructions ne doivent jamais être rencontrées pendant le déroulement normal de l'exécution. De plus, les instructions doivent être situées sur des décalages de code octet pairs (c'est-à-dire alignés sur 4 octets). Afin de répondre à cette exigence, les outils de génération de dex doivent émettre une instruction nop supplémentaire en tant qu'espaceur si une telle instruction serait autrement non alignée. Enfin, bien que ce ne soit pas obligatoire, on s'attend à ce que la plupart des outils choisissent d'émettre ces instructions à la fin des méthodes, car sinon, il serait probable que des instructions supplémentaires soient nécessaires pour les contourner.
  • Lorsqu'elles sont installées sur un système en cours d'exécution, certaines instructions peuvent être modifiées, en modifiant leur format, en tant qu'optimisation de liaison statique au moment de l'installation. Cela permet une exécution plus rapide une fois que la liaison est connue. Voir le document des formats d'instructions associés pour les variantes suggérées. Le mot "suggéré" est utilisé à bon escient; il n'est pas obligatoire de les mettre en œuvre.
  • Syntaxe humaine et mnémoniques :
    • Classement destination-puis-source pour les arguments.
    • Certains opcodes ont un suffixe de nom désambiguïsant pour indiquer le ou les types sur lesquels ils opèrent :
      • Les opcodes 32 bits de type général ne sont pas marqués.
      • Les opcodes 64 bits de type général sont suffixés par -wide .
      • Les opcodes spécifiques au type sont suffixés avec leur type (ou une abréviation directe), l'un des suivants : -boolean -byte -char -short -int -long -float -double -object -string -class -void .
    • Certains opcodes ont un suffixe de désambiguïsation pour distinguer des opérations par ailleurs identiques qui ont des dispositions ou des options d'instructions différentes. Ces suffixes sont séparés des noms principaux par une barre oblique (" / ") et existent principalement pour faire en sorte qu'il y ait un mappage un à un avec des constantes statiques dans le code qui génère et interprète les exécutables (c'est-à-dire pour réduire l'ambiguïté pour les humains).
    • Dans les descriptions ici, la largeur d'une valeur (indiquant par exemple la plage d'une constante ou le nombre de registres éventuellement adressés) est accentuée par l'utilisation d'un caractère par quatre bits de largeur.
    • Par exemple, dans l'instruction " move-wide/from16 vAA, vBBBB " :
      • " move " est l'opcode de base, indiquant l'opération de base (déplacer la valeur d'un registre).
      • " wide " est le suffixe du nom, indiquant qu'il fonctionne sur des données larges (64 bits).
      • " from16 " est le suffixe d'opcode, indiquant une variante qui a une référence de registre 16 bits comme source.
      • " vAA " est le registre de destination (implicite par l'opération ; encore une fois, la règle est que les arguments de destination viennent toujours en premier), qui doit être dans la plage v0v255 .
      • " vBBBB " est le registre source, qui doit être dans la plage v0v65535 .
  • Voir le document sur les formats d'instructions pour plus de détails sur les différents formats d'instructions (répertoriés sous "Op & Format") ainsi que des détails sur la syntaxe de l'opcode.
  • Voir le document sur le format de fichier .dex pour plus de détails sur la place du bytecode dans l'image plus grande.

Résumé du jeu de bytecodes

Opération & Format Mnémonique / Syntaxe Arguments La description
00 10x non Cycles de déchets.

Remarque : Les pseudo-instructions portant des données sont étiquetées avec cet opcode, auquel cas l'octet de poids fort de l'unité d'opcode indique la nature des données. Voir "Format packed-switch-payload ", "Format de charge utile sparse-switch-payload " et "Format fill-array-data-payload " ci-dessous.

01 12x déplacer vA, vB A: registre de destination (4 bits)
B: registre source (4 bits)
Déplacer le contenu d'un registre non objet vers un autre.
02 22x déplacer/depuis16 vAA, vBBBB A: registre de destination (8 bits)
B: registre source (16 bits)
Déplacer le contenu d'un registre non objet vers un autre.
03 32x mouvement/16 vAAAA, vBBBB A: registre de destination (16 bits)
B: registre source (16 bits)
Déplacer le contenu d'un registre non objet vers un autre.
04 12x déplacer à l'échelle vA, vB A: paire de registres de destination (4 bits)
B: paire de registres source (4 bits)
Déplacer le contenu d'une paire de registres vers une autre.

Remarque : Il est légal de passer de v N à v N-1 ou v N+1 , donc les implémentations doivent s'arranger pour que les deux moitiés d'une paire de registres soient lues avant que quoi que ce soit ne soit écrit.

05 22x déplacer à l'échelle/à partir de16 vAA, vBBBB A: paire de registres de destination (8 bits)
B: paire de registres source (16 bits)
Déplacer le contenu d'une paire de registres vers une autre.

Remarque : les considérations d'implémentation sont les mêmes que pour move-wide , ci-dessus.

06 32x déplacer à l'échelle / 16 vAAAA, vBBBB A: paire de registres de destination (16 bits)
B: paire de registres source (16 bits)
Déplacer le contenu d'une paire de registres vers une autre.

Remarque : les considérations d'implémentation sont les mêmes que pour move-wide , ci-dessus.

07 12x déplacer-objet vA, vB A: registre de destination (4 bits)
B: registre source (4 bits)
Déplacer le contenu d'un registre porteur d'objets vers un autre.
08 22x déplacer-objet/depuis16 vAA, vBBBB A: registre de destination (8 bits)
B: registre source (16 bits)
Déplacer le contenu d'un registre porteur d'objets vers un autre.
09 32x déplacer-objet/16 vAAAA, vBBBB A: registre de destination (16 bits)
B: registre source (16 bits)
Déplacer le contenu d'un registre porteur d'objets vers un autre.
0a 11x mouvement-résultat vAA A: registre de destination (8 bits) Déplacez le résultat non objet à mot unique du invoke- kind le plus récent dans le registre indiqué. Cela doit être fait comme l'instruction immédiatement après un invoke- kind dont le résultat (mot unique, non objet) ne doit pas être ignoré ; n'importe où ailleurs est invalide.
0b 11x vAA à l'échelle du résultat de déplacement A: paire de registres de destination (8 bits) Déplacez le résultat du mot double du invoke- kind le plus récent dans la paire de registres indiquée. Cela doit être fait comme l'instruction immédiatement après un invoke- kind dont le résultat (mot double) ne doit pas être ignoré ; n'importe où ailleurs est invalide.
0c 11x move-result-object vAA A: registre de destination (8 bits) Déplacez le résultat d'objet du invoke- kind le plus récent dans le registre indiqué. Cela doit être fait comme l'instruction immédiatement après un invoke- kind d'appel ou filled-new-array dont le résultat (objet) ne doit pas être ignoré ; n'importe où ailleurs est invalide.
0d 11x move-exception vAA A: registre de destination (8 bits) Enregistrer une exception qui vient d'être interceptée dans le registre donné. Il doit s'agir de la première instruction de tout gestionnaire d'exceptions dont l'exception interceptée ne doit pas être ignorée, et cette instruction ne doit apparaître que comme première instruction d'un gestionnaire d'exceptions ; n'importe où ailleurs est invalide.
0e 10x retour-vide Retour d'une méthode void .
0f 11x retour vAA A: registre de valeur de retour (8 bits) Retour à partir d'une méthode de retour de valeur non objet à largeur unique (32 bits).
10 11x vAA à l'échelle du retour A: paire de registres de valeur de retour (8 bits) Retour d'une méthode de retour de valeur double largeur (64 bits).
11 11x objet de retour vAA A: registre de valeur de retour (8 bits) Retour d'une méthode de retour d'objet.
12 11n const/4 vA, #+B A: registre de destination (4 bits)
B: entier signé (4 bits)
Déplace la valeur littérale donnée (signe étendu à 32 bits) dans le registre spécifié.
13 21s const/16 vAA, #+BBBB A: registre de destination (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (signe étendu à 32 bits) dans le registre spécifié.
14 31i const vAA, #+BBBBBBBB A: registre de destination (8 bits)
B: constante arbitraire de 32 bits
Déplace la valeur littérale donnée dans le registre spécifié.
15 21h const/élevé16 vAA, #+BBBB0000 A: registre de destination (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (zéro droit étendu à 32 bits) dans le registre spécifié.
16 21s const-wide/16 vAA, #+BBBB A: registre de destination (8 bits)
B: entier signé (16 bits)
Déplacez la valeur littérale donnée (signe étendu à 64 bits) dans la paire de registres spécifiée.
17 31i const-wide/32 vAA, #+BBBBBBBB A: registre de destination (8 bits)
B: entier signé (32 bits)
Déplacez la valeur littérale donnée (signe étendu à 64 bits) dans la paire de registres spécifiée.
18 51l const-wide vAA, #+BBBBBBBBBBBBBBBB A: registre de destination (8 bits)
B: constante arbitraire à double largeur (64 bits)
Déplacez la valeur littérale donnée dans la paire de registres spécifiée.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: registre de destination (8 bits)
B: entier signé (16 bits)
Déplacez la valeur littérale donnée (zéro droit étendu à 64 bits) dans la paire de registres spécifiée.
1a 21c chaîne const vAA, chaîne@BBBB A: registre de destination (8 bits)
B: indice de chaîne
Déplace une référence à la chaîne spécifiée par l'index donné dans le registre spécifié.
1b 31c chaîne const/jumbo vAA, chaîne@BBBBBBBB A: registre de destination (8 bits)
B: indice de chaîne
Déplace une référence à la chaîne spécifiée par l'index donné dans le registre spécifié.
1c 21c const-classe vAA, type@BBBB A: registre de destination (8 bits)
B: indice des types
Déplace une référence à la classe spécifiée par l'index donné dans le registre spécifié. Dans le cas où le type indiqué est primitif, cela stockera une référence à la classe dégénérée du type primitif.
1j 11x moniteur-entrer vAA A: registre de référence (8 bits) Acquérir le moniteur pour l'objet indiqué.
1e 11x moniteur-sortie vAA A: registre de référence (8 bits) Relâchez le moniteur pour l'objet indiqué.

Remarque : Si cette instruction doit lever une exception, elle doit le faire comme si le pc avait déjà dépassé l'instruction. Il peut être utile de considérer cela comme l'instruction s'exécutant avec succès (dans un sens) et l'exception levée après l'instruction mais avant que la suivante n'ait la chance de s'exécuter. Cette définition permet à une méthode d'utiliser un bloc fourre-tout de nettoyage de moniteur (par exemple, finally ) comme nettoyage de moniteur pour ce bloc lui-même, comme moyen de gérer les exceptions arbitraires qui pourraient être levées en raison de l'implémentation historique de Thread.stop() , tout en réussissant à avoir une bonne hygiène du moniteur.

1f 21c check-cast vAA, type@BBBB A: registre de référence (8 bits)
B: indice de type (16 bits)
Levez une ClassCastException si la référence dans le registre donné ne peut pas être convertie en type indiqué.

Remarque : puisque A doit toujours être une référence (et non une valeur primitive), cela échouera nécessairement à l'exécution (c'est-à-dire qu'il lèvera une exception) si B fait référence à un type primitif.

20 22c instance de vA, vB, type@CCCC A: registre de destination (4 bits)
B: registre de référence (4 bits)
C: indice de type (16 bits)
Stocke dans le registre de destination donné 1 si la référence indiquée est une instance du type donné, ou 0 sinon.

Remarque : puisque B doit toujours être une référence (et non une valeur primitive), cela entraînera toujours le stockage de 0 si C fait référence à un type primitif.

21 12x longueur de tableau vA, vB A: registre de destination (4 bits)
B: registre porte-référence tableau (4 bits)
Stocke dans le registre de destination donné la longueur du tableau indiqué, en entrées
22 21c nouvelle instance vAA, type@BBBB A: registre de destination (8 bits)
B: indice des types
Construire une nouvelle instance du type indiqué, en stockant une référence à celle-ci dans la destination. Le type doit faire référence à une classe non tableau.
23 22c nouvelle matrice vA, vB, type@CCCC A: registre de destination (4 bits)
B: registre de taille
C: indice des types
Construisez un nouveau tableau du type et de la taille indiqués. Le type doit être un type tableau.
24 35c rempli-nouveau-tableau {vC, vD, vE, vF, vG}, type@BBBB A: taille du tableau et nombre de mots d'argument (4 bits)
B: indice de type (16 bits)
C..G: registres d'arguments (4 bits chacun)
Construire un tableau du type et de la taille donnés, en le remplissant avec le contenu fourni. Le type doit être un type tableau. Le contenu du tableau doit être composé d'un seul mot (c'est-à-dire qu'il n'y a pas de tableaux long ou double , mais les types de référence sont acceptables). L'instance construite est stockée en tant que "résultat" de la même manière que les instructions d'invocation de méthode stockent leurs résultats, de sorte que l'instance construite doit être déplacée vers un registre avec une instruction move-result-object immédiatement suivante (si elle doit être utilisée ).
25 3rc rempli-nouveau-tableau/plage {vCCCC .. vNNNN}, type@BBBB A: taille du tableau et nombre de mots d'argument (8 bits)
B: indice de type (16 bits)
C: premier registre d'argument (16 bits)
N = A + C - 1
Construire un tableau du type et de la taille donnés, en le remplissant avec le contenu fourni. Les clarifications et les restrictions sont les mêmes que pour filled-new-array , décrit ci-dessus.
26 31t fill-array-data vAA, +BBBBBBBB (avec des données supplémentaires comme spécifié ci-dessous dans " fill-array-data-payload Format") A: référence de tableau (8 bits)
B: décalage de "branche" signé vers la pseudo-instruction de données de table (32 bits)
Remplissez le tableau donné avec les données indiquées. La référence doit être à un tableau de primitives, et la table de données doit lui correspondre en type et ne doit pas contenir plus d'éléments que ne peut en contenir le tableau. Autrement dit, le tableau peut être plus grand que la table, et si c'est le cas, seuls les éléments initiaux du tableau sont définis, laissant le reste seul.
27 11x jeter vAA A: registre porteur d'exceptions (8 bits)
Lancez l'exception indiquée.
28 10t aller à +AA A: décalage de branche signé (8 bits) Sauter sans condition à l'instruction indiquée.

Remarque : Le décalage de branche ne doit pas être 0 . (Une boucle de rotation peut être légalement construite soit avec goto/32 soit en incluant un nop comme cible avant la branche.)

29 20t goto/16 + AAAA A: décalage de branche signé (16 bits)
Sauter sans condition à l'instruction indiquée.

Remarque : Le décalage de branche ne doit pas être 0 . (Une boucle de rotation peut être légalement construite soit avec goto/32 soit en incluant un nop comme cible avant la branche.)

2a 30t goto/32 +AAAAAAAA A: décalage de branche signé (32 bits)
Sauter sans condition à l'instruction indiquée.
2b 31t packed-switch vAA, +BBBBBBBB (avec des données supplémentaires comme spécifié ci-dessous dans " packed-switch-payload Format") A: inscrivez-vous pour tester
B: décalage de "branche" signé vers la pseudo-instruction de données de table (32 bits)
Sauter à une nouvelle instruction basée sur la valeur dans le registre donné, en utilisant une table de décalages correspondant à chaque valeur dans une plage intégrale particulière, ou passer à l'instruction suivante s'il n'y a pas de correspondance.
2c 31t sparse-switch vAA, +BBBBBBBB (avec des données supplémentaires comme spécifié ci-dessous dans le " sparse-switch-payload Format") A: inscrivez-vous pour tester
B: décalage de "branche" signé vers la pseudo-instruction de données de table (32 bits)
Sauter à une nouvelle instruction basée sur la valeur dans le registre donné, en utilisant un tableau ordonné de paires valeur-décalage, ou passer à l'instruction suivante s'il n'y a pas de correspondance.
2j..31 23x cmp type vAA, vBB, vCC
2d : cmpl-float (biais lt)
2e : cmpg-float (biais gt)
2f : cmpl-double (lt bias)
30 : cmpg-double (biais gt)
31 : cmp de long
A: registre de destination (8 bits)
B: premier registre ou paire source
C: deuxième registre source ou paire
Effectuez la comparaison à virgule flottante ou long indiquée, en définissant a sur 0 si b == c , 1 si b > c , ou -1 si b < c . Le "biais" répertorié pour les opérations en virgule flottante indique comment les comparaisons NaN sont traitées : les instructions "gt bias" renvoient 1 pour les comparaisons NaN , et les instructions "lt bias" renvoient -1 .

Par exemple, pour vérifier si virgule flottante x < y , il est conseillé d'utiliser cmpg-float ; un résultat de -1 indique que le test était vrai, et les autres valeurs indiquent qu'il était faux soit en raison d'une comparaison valide, soit parce que l'une des valeurs était NaN .

32..37 22t si- test vA, vB, +CCCC
32: si-eq
33 : si-ne
34 : si-lt
35 : si-ge
36: si-gt
37: si-le
A: premier registre à tester (4 bits)
B: deuxième registre à tester (4 bits)
C: décalage de branche signé (16 bits)
Branchez-vous à la destination donnée si les valeurs des deux registres donnés se comparent comme spécifié.

Remarque : Le décalage de branche ne doit pas être 0 . (Une boucle de rotation peut être légalement construite soit en se ramifiant autour d'un goto arrière, soit en incluant un nop comme cible avant la branche.)

38..3d 21t si- test z vAA, +BBBB
38 : si-eqz
39: si-nez
3a : si-ltz
3b : si-gez
3c : si-gtz
3d : si-lez
A: registre à tester (8 bits)
B: décalage de branche signé (16 bits)
Branchez-vous à la destination donnée si la valeur du registre donné est comparable à 0 comme spécifié.

Remarque : Le décalage de branche ne doit pas être 0 . (Une boucle de rotation peut être légalement construite soit en se ramifiant autour d'un goto arrière, soit en incluant un nop comme cible avant la branche.)

3e..43 10x (inutilisé) (inutilisé)
44..51 23x arrayop vAA, vBB, vCC
44 :                        ...
45 ans : à l'échelle de l'âge
46 : objet-aget
47 : aget-booléen
48 : age-octet
49: age-char
4a : age-court
4b : mettre
4c : aput à l'échelle
4d : aput-object
4e : aput-booléen
4f : un octet de saisie
50 : aput-char
51 : un put-court
A: registre ou paire de valeurs ; peut être source ou destination (8 bits)
B: registre de tableau (8 bits)
C: registre d'index (8 bits)
Effectuez l'opération de tableau identifiée à l'index identifié du tableau donné, en chargeant ou en stockant dans le registre de valeur.
52..5f 22c i instanceop vA, vB, champ@CCCC
52 : 1
53 : iget à l'échelle
54 : iget-objet
55 : iget-booléen
56 : iget-octet
57: iget-char
58 : iget-court
59 : entrée
5a : à l'échelle de l'entrée
5b : objet d'entrée
5c : entrée-booléen
5d : octet d'entrée
5e : caractère d'entrée
5f : entrée courte
A: registre ou paire de valeurs ; peut être source ou destination (4 bits)
B: registre d'objet (4 bits)
C: index de référence du champ d'instance (16 bits)
Effectuez l'opération de champ d'instance d'objet identifié avec le champ identifié, en chargeant ou en stockant dans le registre de valeurs.

Remarque : Ces opcodes sont des candidats raisonnables pour la liaison statique, modifiant l'argument du champ pour qu'il soit un décalage plus direct.

60..6d 21c s statiqueop vAA , champ@BBBB
60: sget
61 : à l'échelle du sget
62 : objet sget
63 : sget-booléen
64 : sget-octet
65 : sget-char
66 : sget-court
67: cracher
68 : à l'échelle de la source
69: objet-sput
6a : sput-booléen
6b : octet de sortie
6c : sput-char
6d : craché court
A: registre ou paire de valeurs ; peut être source ou destination (8 bits)
B: indice de référence de champ statique (16 bits)
Effectuez l'opération de champ statique de l'objet identifié avec le champ statique identifié, en chargeant ou en stockant dans le registre de valeurs.

Remarque : Ces opcodes sont des candidats raisonnables pour la liaison statique, modifiant l'argument du champ pour qu'il soit un décalage plus direct.

6e..72 35c invoquer- kind {vC, vD, vE, vF, vG}, meth@BBBB
6e : appel virtuel
6f : invoquer-super
70 : invoquer-direct
71 : appel-statique
72 : invoquer l'interface
A: nombre de mots d'argument (4 bits)
B: indice de référence de méthode (16 bits)
C..G: registres d'arguments (4 bits chacun)
Appelez la méthode indiquée. Le résultat (le cas échéant) peut être stocké avec une variante move-result* appropriée comme instruction immédiatement suivante.

invoke-virtual est utilisé pour invoquer une méthode virtuelle normale (une méthode qui n'est pas private , static ou final , et qui n'est pas non plus un constructeur).

Lorsque le method_id référence à une méthode d'une classe non-interface, invoke-super est utilisé pour invoquer la méthode virtuelle de la superclasse la plus proche (par opposition à celle avec le même method_id dans la classe appelante). Les mêmes restrictions de méthode s'appliquent que pour invoke-virtual .

Dans les fichiers Dex version 037 ou ultérieure, si le method_id fait référence à une méthode d'interface, invoke-super est utilisé pour invoquer la version la plus spécifique et non remplacée de cette méthode définie sur cette interface. Les mêmes restrictions de méthode s'appliquent que pour invoke-virtual . Dans les fichiers Dex antérieurs à la version 037 , avoir une interface method_id est illégal et indéfini.

invoke-direct est utilisé pour invoquer une méthode directe non static (c'est-à-dire une méthode d'instance qui est par nature non remplaçable, à savoir une méthode d'instance private ou un constructeur).

invoke-static est utilisé pour invoquer une méthode static (qui est toujours considérée comme une méthode directe).

invoke-interface est utilisé pour invoquer une méthode d' interface , c'est-à-dire sur un objet dont la classe concrète n'est pas connue, en utilisant un method_id qui fait référence à une interface .

Remarque : Ces opcodes sont des candidats raisonnables pour la liaison statique, modifiant l'argument de la méthode pour qu'il soit un décalage plus direct (ou une paire de ceux-ci).

73 10x (inutilisé) (inutilisé)
74..78 3rc invoquer- kind /range {vCCCC .. vNNNN}, meth@BBBB
74 : invoquer-virtuel/plage
75 : invoquer-super/gamme
76 : invoquer-direct/plage
77 : invoquer-statique/plage
78 : invoquer-interface/plage
A: nombre de mots d'argument (8 bits)
B: indice de référence de méthode (16 bits)
C: premier registre d'argument (16 bits)
N = A + C - 1
Appelez la méthode indiquée. Voir la description du premier invoke- kind ci-dessus pour plus de détails, des mises en garde et des suggestions.
79..7a 10x (inutilisé) (inutilisé)
7b..8f 12x unop vA, vB
7b : neg-int
7c : non-entier
7d : négatif long
7e : pas-long
7f : flottant négatif
80 : double négatif
81 : int-à-long
82 : int-à-flottant
83 : int-to-double
84 : long-entier
85 : long à flotter
86 : long pour doubler
87 : flottant vers int
88 : flottant à long
89 : flotter pour doubler
8a : double-int
8b : double à long
8c : double flottant
8d : entier vers octet
8e : int-to-char
8f : int-à-court
A: registre ou paire de destination (4 bits)
B: registre source ou paire (4 bits)
Effectuez l'opération unaire identifiée sur le registre source, en stockant le résultat dans le registre de destination.
90..af 23x binop vAA, vBB, vCC
90 : complément
91 : sous-int
92 : multiint
93 : div-int
94: rem-int
95 : et-int
96 : ou-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 : et-long
a1 : or-long
a2 : xor-long
a3 : shl-long
a4 : shr-long
a5 : ushr-long
a6 : ajouter-flottant
a7 : sous-flottant
a8 : flottant multiple
a9 : div-flotteur
aa : rem-flotteur
ab : addition-double
ac : sous-double
annonce : mul-double
ae : div-double
af : rem-double
A: registre ou paire de destination (8 bits)
B: premier registre source ou paire (8 bits)
C: deuxième registre source ou paire (8 bits)
Effectuez l'opération binaire identifiée sur les deux registres source, en stockant le résultat dans le registre de destination.

Remarque : Contrairement aux autres opérations mathématiques -long (qui prennent des paires de registres pour leur première et leur deuxième source), shl-long , shr-long et ushr-long prennent une paire de registres pour leur première source (la valeur à décaler ), mais un seul registre pour leur deuxième source (la distance de décalage).

b0..cf 12x binop /2addr vA, vB
b0 : add-int/2addr
b1 : sous-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 : ajouter-flottant/2addr
c7 : sous-flottant/2addr
c8 : mul-flottant/2addr
c9 : div-float/2addr
ca: rem-float/2addr
cb : ajouter-double/2addr
cc : sous-double/2addr
cd : mul-double/2addr
ce : div-double/2addr
cf: rem-double/2addr
A: registre ou paire de destination et de première source (4 bits)
B: deuxième registre source ou paire (4 bits)
Effectuez l'opération binaire identifiée sur les deux registres source, en stockant le résultat dans le premier registre source.

Remarque : Contrairement aux autres opérations mathématiques -long/2addr (qui prennent des paires de registres pour leur destination/première source et leur deuxième source), shl-long/2addr , shr-long/2addr et ushr-long/2addr prennent un registre paire pour leur destination/première source (la valeur à décaler), mais un seul registre pour leur seconde source (la distance de décalage).

d0..d7 22s binop /lit16 vA, vB, #+CCCC
d0 : add-int/lit16
d1 : rsub-int (soustraction inverse)
d2 : multiint/lit16
d3 : div-int/lit16
d4 : rem-int/lit16
d5 : et-int/lit16
d6 : or-int/lit16
d7 : xor-int/lit16
A: registre de destination (4 bits)
B: registre source (4 bits)
C: constante entière signée (16 bits)
Effectuez l'opération binaire indiquée sur le registre indiqué (premier argument) et la valeur littérale (deuxième argument), en stockant le résultat dans le registre de destination.

Remarque : rsub-int n'a pas de suffixe puisque cette version est l'opcode principal de sa famille. Voir également ci-dessous pour plus de détails sur sa sémantique.

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: registre de destination (8 bits)
B: registre source (8 bits)
C: constante entière signée (8 bits)
Effectuez l'opération binaire indiquée sur le registre indiqué (premier argument) et la valeur littérale (deuxième argument), en stockant le résultat dans le registre de destination.

Remarque : Voir ci-dessous pour plus de détails sur la sémantique de rsub-int .

e3..f9 10x (inutilisé) (inutilisé)
fa 45cc invoquer polymorphe {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: nombre de mots d'argument (4 bits)
B: indice de référence de méthode (16 bits)
C: récepteur (4 bits)
D..G: registres d'arguments (4 bits chacun)
H: indice de référence prototype (16 bits)
Invoquez la méthode polymorphe de signature indiquée. Le résultat (le cas échéant) peut être stocké avec une variante move-result* appropriée comme instruction immédiatement suivante.

La référence de méthode doit être une méthode polymorphe de signature, telle que java.lang.invoke.MethodHandle.invoke ou java.lang.invoke.MethodHandle.invokeExact .

Le récepteur doit être un objet prenant en charge la méthode polymorphe de signature invoquée.

La référence du prototype décrit les types d'arguments fournis et le type de retour attendu.

Le bytecode d'appel invoke-polymorphic peut déclencher des exceptions lorsqu'il s'exécute. Les exceptions sont décrites dans la documentation de l'API pour la méthode polymorphe de signature invoquée.

Présent dans les fichiers Dex à partir de la version 038 .
fb 4rcc invoquer-polymorphique/plage {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: nombre de mots d'argument (8 bits)
B: indice de référence de méthode (16 bits)
C: récepteur (16 bits)
H: indice de référence prototype (16 bits)
N = A + C - 1
Appelez le handle de méthode indiqué. Voir la description d' invoke-polymorphic ci-dessus pour plus de détails.

Présent dans les fichiers Dex à partir de la version 038 .
fc 35c invoquer-personnalisé {vC, vD, vE, vF, vG}, call_site@BBBB A: nombre de mots d'argument (4 bits)
B: indice de référence du site d'appel (16 bits)
C..G: registres d'arguments (4 bits chacun)
Résout et invoque le site d'appel indiqué. Le résultat de l'invocation (le cas échéant) peut être stocké avec une variante move-result* appropriée comme instruction immédiatement suivante.

Cette instruction s'exécute en deux phases : résolution du site d'appel et invocation du site d'appel.

La résolution du site d'appel vérifie si le site d'appel indiqué a une instance java.lang.invoke.CallSite associée. Si ce n'est pas le cas, la méthode de l'éditeur de liens d'amorçage pour le site d'appel indiqué est invoquée à l'aide des arguments présents dans le fichier DEX (voir call_site_item ). La méthode bootstrap linker renvoie une instance java.lang.invoke.CallSite qui sera ensuite associée au site d'appel indiqué si aucune association n'existe. Un autre thread peut avoir déjà effectué l'association en premier, et si c'est le cas, l'exécution de l'instruction se poursuit avec la première instance java.lang.invoke.CallSite associée.

L'invocation du site d'appel est effectuée sur la cible java.lang.invoke.MethodHandle de l'instance java.lang.invoke.CallSite résolue. La cible est appelée comme si elle exécutait invoke-polymorphic (décrit ci-dessus) en utilisant le handle de méthode et les arguments de l'instruction invoke-custom comme arguments d'un appel de handle de méthode exact.

Les exceptions déclenchées par la méthode de l'éditeur de liens bootstrap sont encapsulées dans une java.lang.BootstrapMethodError . Une BootstrapMethodError est également déclenchée si :
  • la méthode de l'éditeur de liens bootstrap ne parvient pas à renvoyer une instance java.lang.invoke.CallSite .
  • le java.lang.invoke.CallSite retourné a une cible de handle de méthode null .
  • la cible du handle de méthode n'est pas du type demandé.
Présent dans les fichiers Dex à partir de la version 038 .
fd 3rc invoquer-personnalisé/plage {vCCCC .. vNNNN}, call_site@BBBB A: nombre de mots d'argument (8 bits)
B: indice de référence du site d'appel (16 bits)
C: registre du premier argument (16 bits)
N = A + C - 1
Résoudre et invoquer un site d'appel. Voir la description d' invoke-custom ci-dessus pour plus de détails.

Présent dans les fichiers Dex à partir de la version 038 .
fe 21c const-method-handle vAA, method_handle@BBBB A: registre de destination (8 bits)
B: indice de poignée de méthode (16 bits)
Déplace une référence au handle de méthode spécifié par l'index donné dans le registre spécifié.

Présent dans les fichiers Dex à partir de la version 039 .
ff 21c const-method-type vAA, proto@BBBB A: registre de destination (8 bits)
B: référence du prototype de méthode (16 bits)
Déplace une référence au prototype de méthode spécifié par l'index donné dans le registre spécifié.

Présent dans les fichiers Dex à partir de la version 039 .

format de charge utile de commutateur compressé

Nom Format La description
identifier ushort = 0x0100 identifier le pseudo-opcode
Taille bref nombre d'entrées dans le tableau
first_key entier première (et la plus basse) valeur de cas de commutation
cibles int[] liste des cibles de branche relatives à la size . Les cibles sont relatives à l'adresse de l'opcode du commutateur, pas à cette table.

Remarque : Le nombre total d'unités de code pour une instance de cette table est de (size * 2) + 4 .

format de charge utile de commutateur clairsemé

Nom Format La description
identifier ushort = 0x0200 identifier le pseudo-opcode
Taille bref nombre d'entrées dans le tableau
clés int[] liste des valeurs de clé de size , triées de bas en haut
cibles int[] liste des cibles de branche relatives de size , chacune correspondant à la valeur de clé au même index. Les cibles sont relatives à l'adresse de l'opcode du commutateur, pas à cette table.

Remarque : Le nombre total d'unités de code pour une instance de cette table est de (size * 4) + 2 .

format de charge utile de données de tableau de remplissage

Nom Format La description
identifier ushort = 0x0300 identifier le pseudo-opcode
largeur_élément bref nombre d'octets dans chaque élément
Taille uint nombre d'éléments dans le tableau
Les données ubyte[] valeurs de données

Remarque : Le nombre total d'unités de code pour une instance de cette table est (size * element_width + 1) / 2 + 4 .

Détails des opérations mathématiques

Remarque : Les opérations en virgule flottante doivent suivre les règles IEEE 754, en utilisant l'arrondi au plus proche et le sous-dépassement progressif, sauf indication contraire.

Code d'opération C Sémantique Remarques
neg-int int32a;
int32 résultat = -a ;
Complément à deux unaire.
non-entier int32a;
int32 result = ~a;
Complément à un unaire.
négatif long int64a;
int64 résultat = -a ;
Complément à deux unaire.
pas longtemps int64a;
int64 result = ~a;
Complément à un unaire.
flotteur négatif flotter un ;
float result = -a;
Floating point negation.
neg-double double a;
double result = -a;
Floating point negation.
int-to-long int32 a;
int64 result = (int64) a;
Sign extension of int32 into int64 .
int-to-float int32 a;
float result = (float) a;
Conversion of int32 to float , using round-to-nearest. This loses precision for some values.
int-to-double int32 a;
double result = (double) a;
Conversion of int32 to double .
long-to-int int64 a;
int32 result = (int32) a;
Truncation of int64 into int32 .
long-to-float int64 a;
float result = (float) a;
Conversion of int64 to float , using round-to-nearest. This loses precision for some values.
long-to-double int64 a;
double result = (double) a;
Conversion of int64 to double , using round-to-nearest. This loses precision for some values.
float-to-int float a;
int32 result = (int32) a;
Conversion of float to int32 , using round-toward-zero. NaN and -0.0 (negative zero) convert to the integer 0 . Infinities and values with too large a magnitude to be represented get converted to either 0x7fffffff or -0x80000000 depending on sign.
float-to-long float a;
int64 result = (int64) a;
Conversion of float to int64 , using round-toward-zero. The same special case rules as for float-to-int apply here, except that out-of-range values get converted to either 0x7fffffffffffffff or -0x8000000000000000 depending on sign.
float-to-double float a;
double result = (double) a;
Conversion of float to double , preserving the value exactly.
double-to-int double a;
int32 result = (int32) a;
Conversion of double to int32 , using round-toward-zero. The same special case rules as for float-to-int apply here.
double-to-long double a;
int64 result = (int64) a;
Conversion of double to int64 , using round-toward-zero. The same special case rules as for float-to-long apply here.
double-to-float double a;
float result = (float) a;
Conversion of double to float , using round-to-nearest. This loses precision for some values.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
Truncation of int32 to int8 , sign extending the result.
int-to-char int32 a;
int32 result = a & 0xffff;
Truncation of int32 to uint16 , without sign extension.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
Truncation of int32 to int16 , sign extending the result.
add-int int32 a, b;
int32 result = a + b;
Twos-complement addition.
sub-int int32 a, b;
int32 result = a - b;
Twos-complement subtraction.
rsub-int int32 a, b;
int32 result = b - a;
Twos-complement reverse subtraction.
mul-int int32 a, b;
int32 result = a * b;
Twos-complement multiplication.
div-int int32 a, b;
int32 result = a / b;
Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 .
rem-int int32 a, b;
int32 result = a % b;
Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 .
and-int int32 a, b;
int32 result = a & b;
Bitwise AND.
or-int int32 a, b;
int32 result = a | b;
Bitwise OR.
xor-int int32 a, b;
int32 result = a ^ b;
Bitwise XOR.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Bitwise shift left (with masked argument).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Bitwise signed shift right (with masked argument).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Bitwise unsigned shift right (with masked argument).
add-long int64 a, b;
int64 result = a + b;
Twos-complement addition.
sub-long int64 a, b;
int64 result = a - b;
Twos-complement subtraction.
mul-long int64 a, b;
int64 result = a * b;
Twos-complement multiplication.
div-long int64 a, b;
int64 result = a / b;
Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 .
rem-long int64 a, b;
int64 result = a % b;
Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 .
and-long int64 a, b;
int64 result = a & b;
Bitwise AND.
or-long int64 a, b;
int64 result = a | b;
Bitwise OR.
xor-long int64 a, b;
int64 result = a ^ b;
Bitwise XOR.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Bitwise shift left (with masked argument).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Bitwise signed shift right (with masked argument).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Bitwise unsigned shift right (with masked argument).
add-float float a, b;
float result = a + b;
Floating point addition.
sub-float float a, b;
float result = a - b;
Floating point subtraction.
mul-float float a, b;
float result = a * b;
Floating point multiplication.
div-float float a, b;
float result = a / b;
Floating point division.
rem-float float a, b;
float result = a % b;
Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b .
add-double double a, b;
double result = a + b;
Floating point addition.
sub-double double a, b;
double result = a - b;
Floating point subtraction.
mul-double double a, b;
double result = a * b;
Floating point multiplication.
div-double double a, b;
double result = a / b;
Floating point division.
rem-double double a, b;
double result = a % b;
Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b .