Format de 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 des registres et la taille des images est 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 à l'exécution de la méthode, telles que (mais sans s'y limiter) le compteur du 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 entiers et des nombres à virgule flottante), les registres sont considérés comme ayant une largeur de 32 bits. Les paires de registres adjacents 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 de ces références.
    • En termes de représentation au niveau du bit, (Object) null == (int) 0 .
    • Les N arguments d’une méthode atterrissent dans l’ordre dans les N derniers registres de la trame d’invocation de la méthode. 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 limitées gratuitement à un type particulier. Par exemple, les instructions qui déplacent des valeurs de registre 32 bits sans interprétation n'ont pas besoin de spécifier si elles déplacent des entiers ou des flottants.
  • Il existe des pools de constantes énumérés et indexés séparément pour les références aux chaînes, aux types, aux champs et aux méthodes.
  • Les données littérales au niveau du bit sont représentées en ligne dans le flux d'instructions.
  • Parce que, dans la 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 des 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 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ésultats bas vers un registre haut. s'inscrire (après l'opération).
  • Il existe plusieurs « pseudo-instructions » utilisées pour contenir des charges utiles de données de longueur variable, auxquelles font référence des instructions régulières (par exemple, fill-array-data ). De telles instructions ne doivent jamais être rencontrées au cours du flux normal d’exécution. De plus, les instructions doivent être situées sur des décalages de bytecode pairs (c'est-à-dire alignés sur 4 octets). Afin de répondre à cette exigence, les outils de génération dex doivent émettre une instruction nop supplémentaire comme espaceur si une telle instruction ne serait autrement pas alignée. Enfin, bien que cela 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 seraient 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 changeant leur format, en guise d'optimisation des liaisons statiques au moment de l'installation. Cela permet une exécution plus rapide une fois que le lien est connu. Voir le document sur les 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 :
    • Ordre de destination puis source des arguments.
    • Certains opcodes ont un suffixe de nom sans ambiguïté pour indiquer le(s) type(s) sur lesquels ils opèrent :
      • Les opcodes 32 bits généraux de type ne sont pas marqués.
      • Les opcodes 64 bits généraux de type sont suffixés par -wide .
      • Les opcodes spécifiques au type sont suffixés par leur type (ou une abréviation simple), l'un des suivants : -boolean -byte -char -short -int -long -float -double -object -string -class -void .
    • Certains opcodes ont un suffixe sans ambiguïté 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 créer 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 pour 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 de l'opcode, indiquant une variante qui a une référence de registre de 16 bits comme source.
      • " vAA " est le registre de destination (impliqué par l'opération ; encore une fois, la règle est que les arguments de destination viennent toujours en premier), qui doit être compris entre v0v255 .
      • " vBBBB " est le registre source, qui doit être compris entre v0v65535 .
  • Consultez 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.
  • Consultez le document sur le format de fichier .dex pour plus de détails sur la place du bytecode dans l'ensemble.

Résumé de l'ensemble de bytecodes

Opération et format Mnémonique / Syntaxe Arguments Description
00 10x non Cycles des 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 « packed-switch-payload Format», « sparse-switch-payload Format» et « fill-array-data-payload Format » ci-dessous.

01 12x déplacer vA, vB A: registre de destination (4 bits)
B: registre source (4 bits)
Déplacez le contenu d'un registre non-objet vers un autre.
02 22x déplacer/de16 vAA, vBBBB A: registre de destination (8 bits)
B: registre source (16 bits)
Déplacez le contenu d'un registre non-objet vers un autre.
03 32x bouger/16 vAAAA, vBBBB A: registre de destination (16 bits)
B: registre source (16 bits)
Déplacez le contenu d'un registre non-objet vers un autre.
04 12x vA, vB à l'échelle du mouvement A: paire de registres de destination (4 bits)
B: paire de registres source (4 bits)
Déplacez 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 , les implémentations doivent donc faire en sorte que les deux moitiés d'une paire de registres soient lues avant que quoi que ce soit ne soit écrit.

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

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

06 32x mouvement large/16 vAAAA, vBBBB A: paire de registres de destination (16 bits)
B: paire de registres source (16 bits)
Déplacez le contenu d’une paire de registres vers une autre.

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

07 12x déplacer l'objet vA, vB A: registre de destination (4 bits)
B: registre source (4 bits)
Déplacez le contenu d’un registre porteur d’objet vers un autre.
08 22x déplacer-objet/from16 vAA, vBBBB A: registre de destination (8 bits)
B: registre source (16 bits)
Déplacez le contenu d’un registre porteur d’objet vers un autre.
09 32x déplacer-objet/16 vAAAA, vBBBB A: registre de destination (16 bits)
B: registre source (16 bits)
Déplacez le contenu d’un registre porteur d’objet vers un autre.
0a 11x résultat du déplacement vAA A: registre de destination (8 bits) Déplacez le résultat non-objet d'un seul mot 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 (un seul mot, non-objet) ne doit pas être ignoré ; ailleurs, c'est invalide.
0b11x vAA à l'échelle du résultat du déplacement A: paire de registres de destination (8 bits) Déplacez le résultat du double mot 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 (double mot) ne doit pas être ignoré ; ailleurs, c'est invalide.
0c 11x objet de résultat de déplacement vAA A: registre de destination (8 bits) Déplacez le résultat de l'objet du invoke- kind le plus récent dans le registre indiqué. Cela doit être fait comme instruction immédiatement après un invoke- kind ou filled-new-array dont le résultat (objet) ne doit pas être ignoré ; ailleurs, c'est invalide.
0j 11x vAA d'exception de déplacement A: registre de destination (8 bits) Enregistrez 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 ; ailleurs, c'est invalide.
0e 10x retour nul Retour d'une méthode void .
0f 11x retourner vAA A: registre de valeur de retour (8 bits) Retour d’une méthode de retour de valeur non-objet de simple largeur (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: signé entier (4 bits)
Déplacez 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: signé entier (16 bits)
Déplacez 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éplacez la valeur littérale donnée dans le registre spécifié.
15 21h const/high16 vAA, #+BBBB0000 A: registre de destination (8 bits)
B: signé entier (16 bits)
Déplacez la valeur littérale donnée (zéro à droite étendue à 32 bits) dans le registre spécifié.
16 21s const-wide/16 vAA, #+BBBB A: registre de destination (8 bits)
B: signé entier (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: signé entier (32 bits)
Déplacez la valeur littérale donnée (signe étendu à 64 bits) dans la paire de registres spécifiée.
18 51l vAA à l'échelle constante, #+BBBBBBBBBBBBBBBB A: registre de destination (8 bits)
B: constante arbitraire de 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: signé entier (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 const-string vAA, string@BBBB A: registre de destination (8 bits)
B: index 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 const-string/jumbo vAA, chaîne@BBBBBBBB A: registre de destination (8 bits)
B: index 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 vAA de classe const, tapez @BBBB A: registre de destination (8 bits)
B: indice de type
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 surveiller-entrer vAA A: registre de référence (8 bits) Acquérir le moniteur pour l’objet indiqué.
1e 11x vAA de sortie de surveillance 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 qui s'exécute avec succès (dans un sens) et l'exception levée après l'instruction mais avant que la suivante ait une 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() . Thread.stop() , tout en parvenant à avoir une bonne hygiène du moniteur.

1f 21c check-cast vAA, tapez@BBBB A: registre de référence (8 bits)
B: indice de type (16 bits)
Lancez 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 au moment de 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)
Stocker 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 du tableau vA, vB A: registre de destination (4 bits)
B: registre de référence du tableau (4 bits)
Stocker dans le registre de destination donné la longueur du tableau indiqué, en entrées
22 21c vAA de nouvelle instance, tapez@BBBB A: registre de destination (8 bits)
B: indice de type
Construisez 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 nouveau tableau vA, vB, type@CCCC A: registre de destination (4 bits)
B: registre des tailles
C: indice de type
Construisez un nouveau tableau du type et de la taille indiqués. Le type doit être un type tableau.
24 35c nouveau tableau rempli {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)
Construisez 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 constitué d'un seul mot (c'est-à-dire aucun tableau de long ou double , mais les types 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}, tapez @BBBB A: taille du tableau et nombre de mots d’argument (8 bits)
B: indice de type (16 bits)
C: registre du premier argument (16 bits)
N = A + C - 1
Construisez un tableau du type et de la taille donnés, en le remplissant avec le contenu fourni. Les clarifications et restrictions sont les mêmes que 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 du 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 correspondre à son type et ne doit pas contenir plus d'éléments que ne peut contenir le tableau. Autrement dit, le tableau peut être plus grand que la table, et si tel est le cas, seuls les éléments initiaux du tableau sont définis, laissant le reste seul.
27 11x lancer 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) Passez sans condition à l’instruction indiquée.

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

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

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

2a 30t aller à/32 +AAAAAAAA A: décalage de branche signé (32 bits)
Passez 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)
Passez à une nouvelle instruction basée sur la valeur dans le registre donné, en utilisant un tableau de décalages correspondant à chaque valeur dans une plage intégrale particulière, ou passez à 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 " 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)
Passez à une nouvelle instruction basée sur la valeur dans le registre donné, en utilisant un tableau ordonné de paires valeur-décalage, ou passez à 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 (biais lt)
30 : cmpg-double (biais gt)
31 : cmp-long
A: registre de destination (8 bits)
B: premier registre ou paire source
C: deuxième registre ou paire source
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 biais" renvoient 1 pour les comparaisons NaN et les instructions "lt biais" renvoient -1 .

Par exemple, pour vérifier si la 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- tester 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 vers la destination donnée si les valeurs des deux registres données se comparent comme spécifié.

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

38..3j 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: s'inscrire pour tester (8 bits)
B: décalage de branche signé (16 bits)
Branchez-vous vers 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 spin peut être légalement construite soit en bifurquant 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 : âge
45 : à l’échelle de la population
46 : objet-aget
47 : aget-booléen
48 : octet-octet
49 : aget-char
4a : âge court
4b : aput
4c : à l'échelle de l'aput
4d : aput-objet
4e : aput-booléen
4f : octet d'aput
50 : aput-char
51 : aput-court
A: registre ou paire de valeurs ; peut être la source ou la destination (8 bits)
B: registre de tableau (8 bits)
C: registre d'index (8 bits)
Effectuez l'opération de tableau identifié à l'index identifié du tableau donné, en chargeant ou en stockant dans le registre de valeurs.
52..5f 22c j'instanceop vA, vB, field@CCCC
52 : j'obtiens
53 : iget-wide
54 : iget-objet
55 : iget-booléen
56 : iget-octet
57 : iget-char
58 : iget-short
59 : entrée
5a : à l'échelle de l'iput
5b : objet iput
5c : iput-booléen
5d : octet d'entrée
5e : iput-char
5f : iput-court
A: registre ou paire de valeurs ; peut être la source ou la destination (4 bits)
B: registre d'objets (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 le chargeant ou en le stockant dans le registre de valeurs.

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

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

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

6e..72 35c invoquer- genre {vC, vD, vE, vF, vG}, meth@BBBB
6e : invoquer-virtuel
6f : invoquer-super
70 : invoquer-direct
71 : invoquer-statique
72 : interface d'invocation
A: nombre de mots d’argument (4 bits)
B: index de référence de la 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 fait 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 à celles de invoke-virtual .

Dans les fichiers Dex version 037 ou ultérieure, si 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 à celles de invoke-virtual . Dans les fichiers Dex antérieurs à la version 037 , avoir une interface method_id est illégal et non dé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 soit une méthode d'instance private , soit 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 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 en faire un décalage plus direct (ou une paire de ceux-ci).

73 10x (inutilisé) (inutilisé)
74..78 3rc invoquer- genre /range {vCCCC .. vNNNN}, meth@BBBB
74 : invoquer-virtuel/plage
75 : invocation-super/range
76 : invocation-direct/range
77 : invocation-statique/plage
78 : invoquer l'interface/la plage
A: nombre de mots d’argument (8 bits)
B: index de référence de la méthode (16 bits)
C: registre du premier argument (16 bits)
N = A + C - 1
Appelez la méthode indiquée. Voir la première description invoke- kind ci-dessus pour plus de détails, de mises en garde et de suggestions.
79..7a 10x (inutilisé) (inutilisé)
7b..8f 12x unop vA, vB
7b : nég-int
7c : non-int
7d : négatif-long
7e : pas longtemps
7f : flotteur négatif
80 : négatif-double
81 : int-à-long
82 : int-à-flotter
83 : entier vers double
84 : long à int
85 : long à flotter
86 : long à doubler
87 : flottant vers int
88 : flotter trop longtemps
89 : flotter pour doubler
8a : double vers entier
8b : double à long
8c : doubler pour flotter
8d : entier vers octet
8e : int-to-char
8f : int-à-short
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-entier
92 : mul-int
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 : ajout de longueur
9c : sous-long
9d : mul-long
9e : div-long
9f : rem-long
a0 : et-long
a1 : ou-long
a2 : xor-long
a3 : shl-long
a4 : shr-long
a5 : ushr-long
a6 : ajouter un flotteur
a7 : sous-flotteur
a8 : mul-flotteur
a9 : div-float
aa : rem-float
ab : ajouter-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 : complément/2addr
b1 : sous-entier/2adresse
b2 : mul-int/2addr
b3 : div-int/2addr
b4 : rem-int/2addr
b5 : et-int/2addr
b6 : ou-int/2adresse
b7 : xor-int/2addr
b8 : shl-int/2addr
b9 : shr-int/2addr
ba : ushr-int/2addr
bb : ajouter-long/2addr
bc : sous-long/2addr
BD : mul-long/2addr
être : div-long/2addr
bf : rem-long/2addr
c0 : et-long/2addr
c1 : ou-long/2adresse
c2 : xor-long/2addr
c3 : shl-long/2addr
c4 : shr-long/2addr
c5 : ushr-long/2addr
c6 : add-float/2addr
c7 : sous-flotteur/2addr
c8 : mul-float/2addr
c9 : div-float/2addr
ca : rem-float/2addr
cb : add-double/2addr
cc : sous-double/2adresse
cd : mul-double/2 adresses
ce : div-double/2addr
cf : rem-double/2addr
A: destination et premier registre ou paire 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 à la fois 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 deuxième source (la distance de décalage).

d0..d7 22s binop /lit16 vA, vB, #+CCCC
d0 : complément/lit16
d1 : rsub-int (soustraction inverse)
d2 : mul-int/lit16
d3 : div-int/lit16
d4 : rem-int/lit16
d5 : et-int/lit16
d6 : ou-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 : complément/lit8
d9 : rsub-int/lit8
par: mul-int/lit8
base de données : div-int/lit8
cc : rem-int/lit8
jj : et-int/lit8
de: ou-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-polymorphique {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: nombre de mots d’argument (4 bits)
B: index de référence de la méthode (16 bits)
C: récepteur (4 bits)
D..G: registres d'arguments (4 bits chacun)
H: index de référence du 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 renvoyer à 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 invoke-polymorphic peut déclencher des exceptions lors de son exécution. 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 .
fb4rcc invoquer-polymorphique/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: nombre de mots d’argument (8 bits)
B: index de référence de la méthode (16 bits)
C: récepteur (16 bits)
H: index de référence du prototype (16 bits)
N = A + C - 1
Appelez le handle de méthode indiqué. Voir la description 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: index de référence du site d'appel (16 bits)
C..G: registres d'arguments (4 bits chacun)
Résout et appelle 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é est associé à une instance java.lang.invoke.CallSite . Sinon, la méthode de l'éditeur de liens bootstrap 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 de l'éditeur de liens bootstrap 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 continue avec la première instance java.lang.invoke.CallSite associée.

L'appel du site d'appel est effectué sur la cible java.lang.invoke.MethodHandle de l'instance java.lang.invoke.CallSite résolue. La cible est invoqué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 enveloppées dans un java.lang.BootstrapMethodError . Une BootstrapMethodError est également levé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 renvoyé 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 .
fd3rc invoquer-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: nombre de mots d’argument (8 bits)
B: index de référence du site d'appel (16 bits)
C: registre du premier argument (16 bits)
N = A + C - 1
Résolvez et invoquez un site d’appel. Voir la description 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, méthode_handle@BBBB A: registre de destination (8 bits)
B: index du handle de méthode (16 bits)
Déplacez 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 vAA de type méthode const, proto@BBBB A: registre de destination (8 bits)
B: référence du prototype de méthode (16 bits)
Déplacez 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 emballé

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

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

format de charge utile de commutateur clairsemé

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

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

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

Nom Format Description
identifier ushort = 0x0300 identifier le pseudo-opcode
largeur_élément ushort nombre d'octets dans chaque élément
taille uint nombre d'éléments dans le tableau
données ubyte[] valeurs des 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 de l'opération mathématique

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

Opcode Sémantique C Remarques
négatif-int int32a;
résultat int32 = -a ;
Complément unaire à deux.
pas-int int32a;
résultat int32 = ~a;
Complément unaire.
négatif-long int64a;
résultat int64 = -a ;
Complément unaire à deux.
pas longtemps int64a;
résultat int64 = ~a;
Complément unaire.
flotteur négatif flotter un;
résultat flottant = -a;
Négation en virgule flottante.
négatif-double Double A;
résultat double = -a ;
Négation en virgule flottante.
int-à-long int32a;
résultat int64 = (int64) a;
Extension de signe de int32 dans int64 .
entre-boue INT32 A;
float result = (float) a;
Conversion de int32 en float , en utilisant le rond à l'agitation. Cela perd la précision de certaines valeurs.
intrus INT32 A;
Double résultat = (double) a;
Conversion de int32 en double .
long-à-int int64 a;
INT32 Result = (int32) a;
Troncature de int64 dans int32 .
de long à éloigner int64 a;
float result = (float) a;
Conversion de int64 en float , en utilisant le rond à l'agitation. Cela perd la précision de certaines valeurs.
de longue date int64 a;
Double résultat = (double) a;
Conversion de int64 pour double , en utilisant le rond à l'agitation. Cela perd la précision de certaines valeurs.
float-to-int flotter a;
INT32 Result = (int32) a;
Conversion de float en int32 , en utilisant Round-Toward-Zero. NaN et -0.0 (zéro négatif) convertissent en entier 0 . Les infinités et les valeurs avec une grande ampleur pour être représentées sont représentées par 0x7fffffff ou -0x80000000 selon le panneau.
flotter flotter a;
INT64 Result = (Int64) a;
Conversion du float en int64 , en utilisant le rond-toward-zéro. Les mêmes règles de cas spéciales que pour float-to-int s'appliquent ici, sauf que les valeurs hors plage sont converties en 0x7fffffffffffffff ou -0x8000000000000000 en fonction du panneau.
flotteur flotter a;
Double résultat = (double) a;
Conversion du float en double , préservant exactement la valeur.
double-à-int Double A;
INT32 Result = (int32) a;
Conversion de double en int32 , en utilisant le rond-toward-zéro. Les mêmes règles de cas spéciales que pour float-to-int s'appliquent ici.
double à long Double A;
INT64 Result = (Int64) a;
Conversion du double en int64 , en utilisant le rond-toward-zéro. Les mêmes règles de cas spéciales que pour float-to-long s'appliquent ici.
double à flotte Double A;
float result = (float) a;
Conversion du double en float , en utilisant le rond à l'agrément. Cela perd la précision de certaines valeurs.
entre-octet INT32 A;
INT32 Result = (A << 24) >> 24;
Troncature de int32 à int8 , signe étendant le résultat.
intra-char INT32 A;
Résultat INT32 = A & 0XFFFF;
Troncature de int32 à uint16 , sans extension de signe.
intrans INT32 A;
INT32 Result = (A << 16) >> 16;
Troncature de int32 à int16 , signe étendant le résultat.
complément INT32 A, B;
Résultat INT32 = A + B;
Ajout de complément à deux.
sous-intrigue INT32 A, B;
Résultat int32 = a - b;
Soustraction de deux compléments.
rsub-int INT32 A, B;
Résultat INT32 = b - a;
Substraction inverse du complément à deux.
Mul-Int INT32 A, B;
Résultat INT32 = a * b;
Multiplication des deux compléments.
div-int INT32 A, B;
Résultat INT32 = A / B;
Division des deux compléments, arrondi vers zéro (c'est-à-dire tronqué à entier). Cela jette ArithmeticException si b == 0 .
rem-int INT32 A, B;
Résultat INT32 = un% b;
Twos-complément reste après la division. Le signe du résultat est le même que celui de a , et il est plus précisément défini comme result == a - (a / b) * b . Cela jette ArithmeticException si b == 0 .
et dans INT32 A, B;
Résultat INT32 = A&B;
Bitwise et.
ou-int INT32 A, B;
Résultat INT32 = A | b;
Bitwise ou.
xor-int INT32 A, B;
Résultat int32 = a ^ b;
Xor bitwise.
shl-int INT32 A, B;
INT32 Result = A << (B & 0x1f);
Bitwise Shift à gauche (avec argument masqué).
shr-int INT32 A, B;
INT32 Result = A >> (B & 0x1f);
Bitwise Signed Shift Right (avec un argument masqué).
ushr-int uint32 a, b;
INT32 Result = A >> (B & 0x1f);
Bitwise non signé à droite (avec argument masqué).
complément INT64 A, B;
Résultat int64 = a + b;
Ajout de complément à deux.
sous-long INT64 A, B;
Résultat int64 = a - b;
Soustraction de deux compléments.
mâle INT64 A, B;
Résultat int64 = a * b;
Multiplication des deux compléments.
divorant INT64 A, B;
Résultat int64 = a / b;
Division des deux compléments, arrondi vers zéro (c'est-à-dire tronqué à entier). Cela jette ArithmeticException si b == 0 .
de longue date INT64 A, B;
Résultat int64 = un% b;
Twos-complément reste après la division. Le signe du résultat est le même que celui de a , et il est plus précisément défini comme result == a - (a / b) * b . Cela jette ArithmeticException si b == 0 .
et long INT64 A, B;
Résultat INT64 = A&B;
Bitwise et.
ou long INT64 A, B;
Résultat INT64 = A | b;
Bitwise ou.
xor INT64 A, B;
Résultat int64 = a ^ b;
Xor bitwise.
chroniqueur int64 a;
INT32 B;
INT64 Result = A << (B & 0x3f);
Bitwise Shift à gauche (avec argument masqué).
shrolon int64 a;
INT32 B;
INT64 Result = A >> (B & 0x3f);
Bitwise Signed Shift Right (avec un argument masqué).
de longue date uint64 a;
INT32 B;
INT64 Result = A >> (B & 0x3f);
Bitwise non signé à droite (avec argument masqué).
ajouter Float A, B;
Résultat float = a + b;
Ajout de points flottants.
sous-plan Float A, B;
Résultat float = a - b;
Soustraction du point flottant.
mâle Float A, B;
Résultat float = a * b;
Multiplication des points flottants.
div-flott Float A, B;
Résultat float = a / b;
Division des points flottants.
remorqueur Float A, B;
Résultat flottant = un% b;
Point flottant reste après la division. Cette fonction est différente de l'IEEE 754 reste et est définie comme result == a - roundTowardZero(a / b) * b .
additionner Double A, B;
Double résultat = a + b;
Ajout de points flottants.
sous-double Double A, B;
Double résultat = a - b;
Soustraction du point flottant.
mUl-double Double A, B;
Double résultat = a * b;
Multiplication des points flottants.
div-doubble Double A, B;
Double résultat = a / b;
Division des points flottants.
remor-doubble Double A, B;
Double résultat = un% b;
Point flottant reste après la division. Cette fonction est différente de l'IEEE 754 reste et est définie comme result == a - roundTowardZero(a / b) * b .