Format du 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 frames est fixe lors de leur création. Chaque frame se compose d'un nombre particulier de registres (spécifiés par la méthode) ainsi que de toutes les données supplémentaires nécessaires à l'exécution de la méthode, telles que (mais sans s'y limiter) le compteur de programme et une référence au fichier .dex contenant la méthode.
    • Lorsqu'ils sont utilisés pour des valeurs de bits (telles que des 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 de 64 bits. Aucune exigence d'alignement n'est requise pour les paires de registres.
    • Lorsqu'ils sont utilisés pour les références d'objets, les registres sont considérés comme suffisamment larges pour contenir exactement une seule référence de ce type.
    • En termes de représentation par bits, (Object) null == (int) 0.
    • Les N arguments d'une méthode se trouvent dans les derniers N registres du frame d'appel 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 du flux d'instructions est une quantité de 16 bits non signée. Certains bits de certaines instructions sont ignorés ou doivent être nuls.
  • Les instructions ne sont pas limitées à 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 nombres à virgule flottante.
  • Il existe des pools de constantes énumérés et indexés séparément pour les références aux chaînes, types, champs et méthodes.
  • Les données littérales binaires sont représentées en ligne dans le flux d'instructions.
  • En pratique, il est rare qu'une méthode ait besoin de plus de 16 registres, et il est assez courant d'en avoir besoin de plus de huit. Par conséquent, de nombreuses instructions ne s'adressent qu'aux 16 premiers registres. Lorsque cela est raisonnablement possible, les instructions autorisent des références jusqu'aux 256 premiers registres. De plus, certaines instructions comportent des variantes qui permettent de compter un nombre de registres beaucoup plus important, y compris une paire d'instructions move génériques pouvant adresser des registres dans la plage v0 à v65535. Dans les cas où une variante d'instruction n'est pas disponible pour adresser un registre souhaité, le contenu du registre doit être déplacé du registre d'origine vers un registre bas (avant l'opération) et/ou d'un registre de résultat bas vers un registre haut (après l'opération).
  • Plusieurs "pseudo-instructions" sont utilisées pour contenir des charges utiles de données à 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 lors du flux d'exécution normal. De plus, les instructions doivent se trouver sur des décalages de code octet pairs (c'est-à-dire alignés sur quatre octets). Pour 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 ne serait pas alignée. Enfin, bien que cela ne soit pas obligatoire, la plupart des outils devraient choisir d'émettre ces instructions à la fin des méthodes, car il serait autrement 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, ce qui modifie leur format, en tant qu'optimisation de la liaison statique au moment de l'installation. Cela permet d'accélérer l'exécution une fois la liaison connue. Consultez le document sur les formats d'instructions associé pour connaître les variantes suggérées. Le mot "suggérées" est utilisé à dessein. Il n'est pas obligatoire de les implémenter.
  • Syntaxe et mnémoniques adaptées aux humains :
    • Ordre de destination, puis de source pour les arguments.
    • Certains opcodes comportent un suffixe de nom permettant de les distinguer 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 suivis du suffixe -wide.
      • Les opcodes spécifiques au type sont suivis d'un suffixe correspondant à leur type (ou à une abréviation simple), parmi les suivants: -boolean, -byte, -char, -short, -int, -long, -float, -double, -object, -string, -class et -void.
    • Certains opcodes comportent un suffixe permettant de distinguer des opérations identiques qui présentent des mises en page ou des options d'instruction différentes. Ces suffixes sont séparés des noms principaux par une barre oblique ("/") et existent principalement pour établir une mise en correspondance individuelle 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 ci-dessous, la largeur d'une valeur (indiquant, par exemple, la plage d'une constante ou le nombre de registres pouvant être adressés) est mise en évidence 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, qui indique l'opération de base (déplacer la valeur d'un registre).
      • "wide" est le suffixe de nom, qui indique qu'il fonctionne sur des données larges (64 bits).
      • "from16" est le suffixe d'instruction, qui indique une variante dont la source est une référence de registre 16 bits.
      • "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 se trouver dans la plage v0 à v255.
      • "vBBBB" est le registre source, qui doit se trouver dans la plage v0 à v65535.
  • Pour en savoir plus sur les différents formats d'instructions (listés sous "Op & Format"), ainsi que sur la syntaxe de l'opcode, consultez le document sur les formats d'instructions.
  • Pour en savoir plus sur l'emplacement du bytecode dans l'ensemble, consultez la documentation sur le format de fichier .dex.

Résumé de l'ensemble de bytecode

Opération et format Mnémonique / Syntaxe Arguments Description
00 10x nop   Cycles des déchets.

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

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

Remarque:Il est légal de passer de vN à vN-1 ou vN+1. Par conséquent, les implémentations doivent prévoir que les deux moitiés d'une paire de registres soient lues avant toute écriture.

05 22x move-wide/from16 vAA, vBBBB A: Paire de registres de destination (8 bits)
B: Paire de registres de 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 move-wide/16 vAAAA, vBBBB Paire de registres de destination A: (16 bits)
Paire de registres de source B: (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 move-object vA, vB Registre de destination A: (4 bits)
Registre de source B: (4 bits)
Déplacer le contenu d'un registre contenant des objets vers un autre
08 22x move-object/from16 vAA, vBBBB Registre de destination A: (8 bits)
Registre source B: (16 bits)
Déplacer le contenu d'un registre contenant des objets vers un autre
09 32x move-object/16 vAAAA, vBBBB Registre de destination A: (16 bits)
Registre source B: (16 bits)
Déplacer le contenu d'un registre contenant des objets vers un autre
0a 11x vAA move-result Registre de destination A: (8 bits) Déplacez le résultat non objet à un seul mot de la invoke-kind la plus récente dans le registre indiqué. Cela doit être fait en tant qu'instruction immédiatement après un invoke-kind dont le résultat (mot unique, non objet) ne doit pas être ignoré. Tout autre emplacement est non valide.
0b 11x vAA move-result-wide Paire de registres de destination A: (8 bits) Déplacez le résultat en double-mot de la invoke-kind la plus récente dans la paire de registres indiquée. Cela doit être fait en tant qu'instruction immédiatement après un invoke-kind dont le résultat (double-mot) ne doit pas être ignoré. Tout autre emplacement est non valide.
0c 11x move-result-object vAA Registre de destination A: (8 bits) Déplacez le résultat de l'objet de l'invoke-kind la plus récente dans le registre indiqué. Cela doit être fait en tant qu'instruction immédiatement après un invoke-kind ou un filled-new-array dont le résultat (objet) ne doit pas être ignoré. Tout autre emplacement est non valide.
0 j 11x move-exception vAA Registre de destination A: (8 bits) Enregistre une exception vient d'être détectée dans le registre donné. Il doit s'agir de la première instruction de tout gestionnaire d'exception dont l'exception détectée ne doit pas être ignorée. Cette instruction ne doit jamais se produire en tant que première instruction d'un gestionnaire d'exception. Tout autre emplacement est non valide.
0e 10x return-void   Retour à partir d'une méthode void.
0f 11x return vAA Registre de valeur renvoyée A: (8 bits) Retour à partir d'une méthode renvoyant une valeur non objet à largeur unique (32 bits).
10 11x vAA de retour Paire de registres de valeur renvoyée A: (8 bits) Retour à partir d'une méthode renvoyant une valeur à double largeur (64 bits).
11 11x vAA de l'objet de retour Registre de valeur renvoyée A: (8 bits) Retour d'une méthode renvoyant un objet.
12 11n const/4 vA, #+B Registre de destination A: (4 bits)
Entier signé B: (4 bits)
Déplace la valeur littérale donnée (étendue à 32 bits) dans le registre spécifié.
13 21 s const/16 vAA, #+BBBB Registre de destination A: (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (étendue à 32 bits) dans le registre spécifié.
14 31i const vAA, #+BBBBBBBB Registre de destination A: (8 bits)
B: constante arbitraire de 32 bits
Déplace la valeur littérale donnée dans le registre spécifié.
15 21h const/high16 vAA, #+BBBB0000 Registre de destination A: (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (étendue à 32 bits à droite) dans le registre spécifié.
16 21 const-wide/16 vAA, #+BBBB Registre de destination A: (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (étendue à 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éplace la valeur littérale donnée (étendue à 64 bits) dans la paire de registres spécifiée.
18 51 l vAA de portée globale, #+BBBBBBBBBBBBBBBB A:Registre de destination (8 bits)
B:Constante arbitraire à double largeur (64 bits)
Déplace la valeur littérale donnée dans la paire de registres spécifiée.
19 21h const-wide/high16 vAA, #+BBBB000000000000 Registre de destination A: (8 bits)
B: entier signé (16 bits)
Déplace la valeur littérale donnée (étendue à 64 bits à droite) dans la paire de registres spécifiée.
1a 21c const-string vAA, string@BBBB Registre de destination A: (8 bits)
Index de chaîne B:
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, string@BBBBBBBB Registre de destination A: (8 bits)
Index de chaîne B:
Déplace une référence à la chaîne spécifiée par l'index donné dans le registre spécifié.
1c 21c const-class vAA, type@BBBB Registre de destination A: (8 bits)
Index de type B:
Déplacez une référence à la classe spécifiée par l'index donné dans le registre spécifié. Si le type indiqué est primitif, une référence à la classe dégénérée du type primitif est stockée.
1d 11x monitor-enter vAA Registre de référence A: (8 bits) Acquérir le moniteur pour l'objet indiqué.
1e 11x monitor-exit vAA Registre de référence A: (8 bits) Libérez le moniteur pour l'objet indiqué.

Remarque:Si cette instruction doit générer une exception, elle doit le faire comme si le processeur avait déjà avancé au-delà de l'instruction. Il peut être utile de considérer que l'instruction s'exécute correctement (dans un sens) et que l'exception est générée après l'instruction, mais avant que la suivante ait la possibilité de s'exécuter. Cette définition permet à une méthode d'utiliser un nettoyeur de moniteur générique (par exemple, finally) comme le nettoyage du moniteur pour ce bloc lui-même, afin de gérer les exceptions arbitraires pouvant être générées en raison de l'implémentation historique de Thread.stop(), tout en veillant à une hygiène de surveillance appropriée.

1f 21c check-cast vAA, type@BBBB A: registre avec référence (8 bits)
B: indice de type (16 bits)
Génère une exception ClassCastException si la référence du registre donné ne peut pas être convertie au type indiqué.

Remarque:Étant donné que A doit toujours être une référence (et non une valeur primitive), cette opération échouera nécessairement au moment de l'exécution (c'est-à-dire qu'une exception sera générée) si B fait référence à un type primitif.

20 22c instance-of vA, vB, type@CCCC Registre de destination A: (4 bits)
Registre contenant une référence B: (4 bits)
Index de type C: (16 bits)
Stockez dans le registre de destination donné 1 si la référence indiquée est une instance du type donné, ou 0 si ce n'est pas le cas.

Remarque:Étant donné que B doit toujours être une référence (et non une valeur primitive), 0 sera toujours stocké si C fait référence à un type primitif.

21 12x vA, vB (longueur de tableau) Registre de destination A: (4 bits)
Registre de référence de tableau B: (4 bits)
Stockez dans le registre de destination donné la longueur du tableau indiqué, en entrées.
22 21c new-instance vAA, type@BBBB Registre de destination A: (8 bits)
Index de type B:
Créez une instance du type indiqué, en stockant une référence à celle-ci dans la destination. Le type doit faire référence à une classe autre qu'un tableau.
23 22c new-array vA, vB, type@CCCC Registre de destination A: (4 bits)
Registre de taille B:
Index de type C:
Créez un tableau du type et de la taille indiqués. Le type doit être un type de tableau.
24 35c filled-new-array {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)
Construit un tableau du type et de la taille donnés, en le remplissant avec le contenu fourni. Le type doit être un type de tableau. Le contenu du tableau doit être constitué d'un seul mot (c'est-à-dire qu'il ne doit pas y avoir de tableaux de long ou de double, mais les types de référence sont acceptés). L'instance créée est stockée en tant que "résultat" de la même manière que les instructions d'appel de méthode stockent leurs résultats. L'instance créée doit donc être déplacée vers un registre avec une instruction move-result-object immédiatement suivante (si elle doit être utilisée).
25 3rc filled-new-array/range {vCCCC .. vNNNN}, type@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
Construit un tableau du type et de la taille donnés, en le remplissant avec le contenu fourni. Les clarifications et les restrictions sont identiques à celles de filled-new-array, décrites ci-dessus.
26 31t fill-array-data vAA, +BBBBBBBB (avec les données supplémentaires spécifiées ci-dessous dans "fill-array-data-payload Format") Référence de tableau A: (8 bits)
Décalage signé de la "branche" vers la pseudo-instruction de données de table B: (32 bits)
Remplissez le tableau donné avec les données indiquées. La référence doit être un tableau de primitives, et le tableau de données doit lui correspondre en type et ne pas contenir plus d'éléments que ceux qui peuvent tenir dans le tableau. Autrement dit, le tableau peut être plus volumineux que la table. Dans ce cas, seuls les éléments initiaux du tableau sont définis, laissant le reste intact.
27 11x générer vAA Registre A: contenant des exceptions (8 bits)
Générez l'exception indiquée.
28 10t goto +AA Décalage de branche signé A: (8 bits) Saute sans condition à l'instruction indiquée.

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

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

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

2a 30t goto/32 +AAAAAAAA Décalage de branche signé A: (32 bits)
Saute sans condition à l'instruction indiquée.
2b 31t packed-switch vAA, +BBBBBBBB (avec les données supplémentaires spécifiées ci-dessous dans "packed-switch-payload Format") Registre A: pour le test
Décalage de "branchement" signé B: vers la pseudo-instruction de données de table (32 bits)
Saute vers une nouvelle instruction en fonction de la valeur du registre donné, à l'aide d'un tableau de décalages correspondant à chaque valeur d'une plage d'entiers particulière, ou passe à l'instruction suivante en cas de non-correspondance.
2c 31t sparse-switch vAA, +BBBBBBBB (avec les données supplémentaires spécifiées ci-dessous dans "sparse-switch-payload Format") Registre A: pour le test
Décalage de "branchement" signé B: vers la pseudo-instruction de données de table (32 bits)
Accédez à une nouvelle instruction en fonction de la valeur du registre donné, à l'aide d'un tableau ordonné de paires valeur-décalage, ou passez à l'instruction suivante en cas de non-correspondance.
2d..31 23x cmpkind vAA, vBB, vCC
2d: cmpl-float (biais inférieur)
2e: cmpg-float (biais supérieur)
2f: cmpl-double (biais inférieur)
30: cmpg-double (biais supérieur)
31: cmp-long
A: Registre de destination (8 bits)
B: Premier registre ou paire de source
C: Deuxième registre ou paire de 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" indiqué pour les opérations à virgule flottante indique comment les comparaisons NaN sont traitées : les instructions "biais gt" renvoient 1 pour les comparaisons NaN, et les instructions "biais lt" renvoient -1.

Par exemple, pour vérifier si un nombre à virgule flottante est 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 if-test vA, vB, +CCCC
32: if-eq
33: if-ne
34: if-lt
35: if-ge
36: if-gt
37: if-le
A: premier registre à tester (4 bits)
B: deuxième registre à tester (4 bits)
C: décalage de branche signé (16 bits)
Branchement vers la destination donnée si les valeurs des deux registres donnés sont comparées comme spécifié.

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

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
Registre A: à tester (8 bits)
Décalage de branche signé B: (16 bits)
Branchement vers la destination donnée si la valeur du registre donné est comparée à 0, comme spécifié.

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

3e..43 10x (inutilisé)   (inutilisé)
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
Registre ou paire de valeurs A: (peut être source ou destination) (8 bits)
Registre de tableau B: (8 bits)
Registre d'index C: (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 valeurs.
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
Registre ou paire de valeurs A: ; peut être source ou destination (4 bits)
Registre d'objet B: (4 bits)
Index de référence de champ d'instance C: (16 bits)
Effectuez l'opération de champ d'instance d'objet identifiée avec le champ identifié, en le chargeant ou en le stockant dans le registre de valeurs.

Remarque:Ces opcodes sont des candidats raisonnables pour le lien statique, en modifiant l'argument de champ pour qu'il soit un décalage plus direct.

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
Registre ou paire de valeurs A:. Peut être source ou destination (8 bits)
Index de référence de champ statique B: (16 bits)
Effectuez l'opération de champ statique de l'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 le lien statique, en modifiant l'argument de champ pour qu'il soit un décalage plus direct.

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
Nombre de mots d'argument A: (4 bits)
Index de référence de méthode B: (16 bits)
Registres d'argument C..G: (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 permet d'appeler une méthode virtuelle normale, qui n'est pas static, private ou un constructeur.

Lorsque method_id fait référence à une méthode d'une classe non interface, invoke-super est utilisé pour appeler 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 qu'avec 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 appeler la version la plus spécifique et non écrasée de cette méthode définie sur cette interface. Les mêmes restrictions de méthode s'appliquent qu'avec invoke-virtual. Dans les fichiers Dex antérieurs à la version 037, la présence d'une interface method_id est illégale et non définie.

invoke-direct permet d'appeler une méthode directe autre que static (c'est-à-dire une méthode d'instance qui, par nature, ne peut pas être remplacée, à savoir une méthode d'instance private ou un constructeur).

invoke-static permet d'appeler une méthode static (qui est toujours considérée comme une méthode directe).

invoke-interface permet d'appeler une méthode interface, c'est-à-dire sur un objet dont la classe concrète n'est pas connue, à l'aide d'un method_id qui fait référence à un interface.

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

73 10x (inutilisé)   (inutilisé)
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: Nombre de mots d'argument (8 bits)
B: Indice 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. Pour en savoir plus, consulter la première description de invoke-kind ci-dessus.
79..7a 10x (inutilisé)   (inutilisé)
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: registre ou paire de destination (4 bits)
B: registre ou paire de source (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: 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: Paire ou registre de destination (8 bits)
B: Paire ou registre de première source (8 bits)
C: Paire ou registre de deuxième source (8 bits)
Effectuez l'opération binaire identifiée sur les deux registres sources, 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: 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: Destination et premier registre ou paire source (4 bits)
B: Deuxième registre ou paire source (4 bits)
Effectuez l'opération binaire identifiée sur les deux registres sources, 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 une paire de registres 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: add-int/lit16
d1: rsub-int (soustraction inverse)
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: registre de destination (4 bits)
B: registre source (4 bits)
C: constante int signée (16 bits)
Effectue 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, car cette version est l'opcode principal de sa famille. Consultez également la section ci-dessous pour en savoir plus 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
Registre de destination A: (8 bits)
Registre source B: (8 bits)
Constante int signée C: (8 bits)
Effectue 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:Pour en savoir plus sur la sémantique de rsub-int, consultez les informations ci-dessous.

e3..f9 10x (inutilisé)   (inutilisé)
fa 45 cm³ invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: Nombre de mots d'argument (4 bits)
B: Indice de référence de la méthode (16 bits)
C: Récepteur (4 bits)
D..G: Enregistreurs d'arguments (4 bits chacun)
H: Indice de référence du prototype (16 bits)
Appelez 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 faire référence à 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 compatible avec la méthode polymorphe de signature appelée.

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

Le bytecode invoke-polymorphic peut générer 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 appelée.

Présent dans les fichiers DEX à partir de la version 038.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: Nombre de mots d'argument (8 bits)
B: Indice de référence de la méthode (16 bits)
C: Récepteur (16 bits)
H: Indice de référence du prototype (16 bits)
N = A + C - 1
Appelez le gestionnaire de méthode indiqué. Pour en savoir plus, consultez la description de invoke-polymorphic ci-dessus.

Présent dans les fichiers DEX à partir de la version 038.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB Nombre de mots d'argument A: (4 bits)
Index de référence du site d'appel B: (16 bits)
Registres d'argument C..G: (4 bits chacun)
Résout et appelle le site d'appel indiqué. Le résultat de l'appel (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 appel 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. Dans le cas contraire, la méthode de l'éditeur de liens de démarrage pour le site d'appel indiqué est appelée à l'aide des arguments présents dans le fichier DEX (voir call_site_item). La méthode de l'éditeur de liens de démarrage renvoie une instance java.lang.invoke.CallSite qui sera ensuite associée au site d'appel indiqué si aucune association n'existe. Il est possible qu'un autre thread ait déjà effectué l'association en premier. Dans ce cas, l'exécution de l'instruction se poursuit avec la première instance java.lang.invoke.CallSite associée.

L'appel du site est effectué 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) à l'aide du gestionnaire de méthode et des arguments de l'instruction invoke-custom comme arguments d'une invocation de gestionnaire de méthode exacte.

Les exceptions générées par la méthode de l'éditeur de liens de démarrage sont encapsulées dans un java.lang.BootstrapMethodError. Une BootstrapMethodError est également générée dans les cas suivants :
  • La méthode du linker de démarrage ne parvient pas à renvoyer une instance java.lang.invoke.CallSite.
  • Le java.lang.invoke.CallSite renvoyé comporte une cible de poignée de méthode null.
  • La cible du gestionnaire de méthode n'est pas du type demandé.
Présent dans les fichiers DEX à partir de la version 038.
fd 3rc invoke-custom/range {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ésolvez et appelez un site d'appel. Pour en savoir plus, consultez la description de invoke-custom ci-dessus.

Présent dans les fichiers DEX à partir de la version 038.
fe 21c const-method-handle vAA, method_handle@BBBB Registre de destination A: (8 bits)
Index de poignée de méthode B: (16 bits)
Déplacez une référence au gestionnaire 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 Registre de destination A: (8 bits)
Référence du prototype de méthode B: (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 packed-switch-payload

Nom Format Description
ident ushort = 0x0100 identification du pseudo-opcode
taille ushort nombre d'entrées dans le tableau ;
first_key int première (et plus basse) valeur de l'instruction switch
cibles int[] liste des cibles de branche relatives size. Les cibles sont relatives à l'adresse de l'opcode de commutateur, et non à celle de ce tableau.

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

Format sparse-switch-payload

Nom Format Description
ident ushort = 0x0200 identification du pseudo-opcode
taille ushort nombre d'entrées dans le tableau ;
clés int[] liste des valeurs de clé size, triées de la valeur la plus basse à la plus élevée
cibles int[] Liste des cibles de branche relatives size, chacune correspondant à la valeur de clé au même indice. Les cibles sont relatives à l'adresse de l'opcode de commutateur, et non à celle de ce tableau.

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

Format de la charge utile de données de remplissage d'un tableau

Nom Format Description
ident ushort = 0x0300 identification du pseudo-opcode
element_width ushort Nombre d'octets dans chaque élément
taille uint nombre d'éléments dans la table ;
de données ubyte[] valeurs des données

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

Détails de l'opération mathématique

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

Code opération Sémantique C Notes
neg-int int32 a;
int32 result = -a;
Complément à deux unaire.
not-int int32 a;
int32 result = ~a;
Complément à unaire
neg-long int64 a;
int64 result = -a;
Complément à deux unaire.
not-long int64 a;
int64 result = ~a;
Complément à un.
neg-float float a;
float result = -a;
Négation à virgule flottante.
neg-double double a;
double résultat = -a;
Négation à virgule flottante.
int-to-long int32 a;
int64 result = (int64) a;
Signature de l'extension de int32 dans int64.
int-to-float int32 a;
float result = (float) a;
Conversion de int32 en float, avec arrondi à la valeur la plus proche. Cela entraîne une perte de précision pour certaines valeurs.
int-to-double int32 a;
double résultat = (double) a;
Conversion de int32 en double.
long-to-int int64 a;
int32 result = (int32) a;
Troncature de int64 en int32.
long-to-float int64 a;
float result = (float) a;
Conversion de int64 en float, avec arrondi à la valeur la plus proche. Cela entraîne une perte de précision pour certaines valeurs.
long-to-double int64 a;
double résultat = (double) a;
Conversion de int64 en double, avec arrondi à la valeur la plus proche. Cela entraîne une perte de précision pour certaines valeurs.
float-to-int float a;
int32 result = (int32) a;
Conversion de float en int32, à l'aide de la méthode d'arrondi à zéro. NaN et -0.0 (zéro négatif) sont convertis en entier 0. Les valeurs infinies et celles dont la magnitude est trop élevée pour être représentées sont converties en 0x7fffffff ou -0x80000000, selon le signe.
float-to-long float a;
int64 result = (int64) a;
Conversion de float en int64, à l'aide de la méthode d'arrondi à zéro. Les mêmes règles de cas particulier que pour float-to-int s'appliquent ici, sauf que les valeurs hors plage sont converties en 0x7fffffffffffffff ou -0x8000000000000000 en fonction du signe.
float-to-double float a;
double result = (double) a;
Conversion de float en double, en conservant exactement la valeur.
double-to-int double a;
int32 result = (int32) a;
Conversion de double en int32, à l'aide de la méthode d'arrondi à zéro. Les mêmes règles de cas particulier que pour float-to-int s'appliquent ici.
double-to-long double a;
int64 result = (int64) a;
Conversion de double en int64, à l'aide de la méthode d'arrondi à zéro. Les mêmes règles de cas particulier que pour float-to-long s'appliquent ici.
double-to-float double a;
float result = (float) a;
Conversion de double en float, avec arrondi à la valeur la plus proche. Cela entraîne une perte de précision pour certaines valeurs.
int-to-byte int32 a;
int32 résultat = (a << 24) >> 24;
Troncature de int32 à int8, signe prolongeant le résultat.
int-to-char int32 a;
int32 résultat = a & 0xffff;
Troncature de int32 à uint16, sans extension du signe.
int-to-short int32 a;
int32 résultat = (a << 16) >> 16;
Troncature de int32 à int16, signe prolongeant le résultat.
add-int int32 a, b;
int32 résultat = a + b;
Addition en complément à deux.
sous-entier int32 a, b;
int32 résultat = a - b;
Soustraction en complément à deux
rsub-int int32 a, b;
int32 result = b - a;
Soustraction inverse en complément à deux
mul-int int32 a, b;
int32 résultat = a * b;
Multiplication en complément à deux
div-int int32 a, b;
int32 résultat = a / b;
Division en complément à deux, arrondie vers zéro (c'est-à-dire tronquée pour afficher un entier). Cela génère une exception ArithmeticException si b == 0.
rem-int int32 a, b;
int32 résultat = a % b;
Reste en complément à deux après division. Le signe du résultat est le même que celui de a et est défini plus précisément comme result == a - (a / b) * b. Cette opération génère une exception ArithmeticException si b == 0.
and-int int32 a, b;
int32 result = a & b;
Opérateur AND (ET) au niveau du bit.
or-int int32 a, b;
int32 result = a | b;
Opérateur OR au niveau du bit.
xor-int int32 a, b;
int32 result = a ^ b;
Opérateur XOR (OU exclusif) bit à bit.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Décalage à gauche bit à bit (avec argument masqué).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Décalage à droite signé bit à bit (avec argument masqué).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Décalage à droite non signé bit à bit (avec argument masqué).
add-long int64 a, b;
int64 result = a + b;
Addition en complément à deux.
sous-longueur int64 a, b;
int64 result = a - b;
Soustraction en complément à deux
mul-long int64 a, b;
int64 result = a * b;
Multiplication en complément à deux
div-long int64 a, b;
int64 result = a / b;
Division en complément à deux, arrondie vers zéro (c'est-à-dire tronquée pour afficher un entier). Cela génère une exception ArithmeticException si b == 0.
rem-long int64 a, b;
int64 result = a % b;
Reste en complément à deux après division. Le signe du résultat est le même que celui de a et est défini plus précisément comme result == a - (a / b) * b. Cette opération génère une exception ArithmeticException si b == 0.
and-long int64 a, b;
int64 result = a & b;
Opérateur AND (ET) au niveau du bit.
or-long int64 a, b;
int64 result = a | b;
Opérateur OR au niveau du bit.
xor-long int64 a, b;
int64 result = a ^ b;
Opérateur XOR (OU exclusif) au niveau du bit.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Décalage à gauche bit à bit (avec argument masqué).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Décalage à droite signé bit à bit (avec argument masqué).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Décalage à droite non signé bit à bit (avec argument masqué).
add-float float a, b;
float result = a + b;
Addition à virgule flottante.
sous-flottaison float a, b;
float result = a - b;
Soustraction à virgule flottante.
mul-float float a, b;
float result = a * b;
Multiplication à virgule flottante.
div-float float a, b;
float result = a / b;
Division à virgule flottante.
rem-float float a, b;
float result = a % b;
Reste à virgule flottante après division. Cette fonction est différente du reste IEEE 754 et est définie comme result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double résultat = a + b;
Addition à virgule flottante.
sous-double double a, b;
double résultat = a - b;
Soustraction à virgule flottante.
mul-double double a, b;
double résultat = a * b;
Multiplication à virgule flottante.
div-double double a, b;
double résultat = a / b;
Division à virgule flottante.
rem-double double a, b;
double résultat = a % b;
Reste à virgule flottante après division. Cette fonction est différente du reste IEEE 754 et est définie comme result == a - roundTowardZero(a / b) * b.