Formato de código de bytes Dalvik

Diseño general

  • El modelo de máquina y las convenciones de llamadas están diseñados para imitar de forma aproximada las arquitecturas reales comunes y las convenciones de llamadas de estilo C:
    • La máquina se basa en registros, y los fotogramas tienen un tamaño fijo cuando se crean. Cada marco consta de una cantidad particular de registros (especificados por el método), así como cualquier dato complementario necesario para ejecutar el método, como (sin limitaciones) el contador de programas y una referencia al archivo .dex que contiene el método.
    • Cuando se usan para valores de bits (como números enteros y de punto flotante), los registros se consideran de 32 bits de ancho. Los pares de registros adyacentes se usan para valores de 64 bits. No hay requisitos de alineación para los pares de registros.
    • Cuando se usan para referencias de objetos, los registros se consideran lo suficientemente amplios como para contener exactamente una de esas referencias.
    • En términos de representación por bits, (Object) null == (int) 0.
    • Los argumentos N de un método se ubican en los últimos N registros del marco de invocación del método, en orden. Los argumentos anchos consumen dos registros. A los métodos de instancia se les pasa una referencia this como primer argumento.
  • La unidad de almacenamiento en el flujo de instrucciones es una cantidad de 16 bits sin firmar. Algunos bits de algunas instrucciones se ignoran o deben ser cero.
  • Las instrucciones no se limitan de forma gratuita a un tipo en particular. Por ejemplo, las instrucciones que mueven valores de registro de 32 bits sin interpretación no tienen que especificar si están moviendo números enteros o de punto flotante.
  • Existen grupos de constantes enumerados e indexados por separado para las referencias a cadenas, tipos, campos y métodos.
  • Los datos literales de bits se representan intercalados en el flujo de instrucciones.
  • Debido a que, en la práctica, es poco común que un método necesite más de 16 registros y a que necesitar más de ocho registros es bastante común, muchas instrucciones se limitan a abordar solo los primeros 16 registros. Cuando sea razonablemente posible, las instrucciones permiten referencias a hasta los primeros 256 registros. Además, algunas instrucciones tienen variantes que permiten recuentos de registros mucho más grandes, incluido un par de instrucciones move generales que pueden abordar registros en el rango v0 a v65535. En los casos en que no haya una variante de instrucción disponible para abordar un registro deseado, se espera que el contenido del registro se mueva del registro original a un registro bajo (antes de la operación) o de un registro de resultado bajo a un registro alto (después de la operación).
  • Hay varias “pseudoinstrucciones” que se usan para contener cargas útiles de datos de longitud variable, a las que se hace referencia con instrucciones normales (por ejemplo, fill-array-data). Nunca se deben encontrar tales instrucciones durante el flujo normal de ejecución. Además, las instrucciones deben ubicarse en offsets de código de bytes con números pares (es decir, alineados con 4 bytes). Para cumplir con este requisito, las herramientas de generación de dex deben emitir una instrucción nop adicional como espaciador si, de otro modo, esa instrucción no estaría alineada. Por último, aunque no es obligatorio, se espera que la mayoría de las herramientas elijan emitir estas instrucciones al final de los métodos, ya que, de lo contrario, es probable que se necesiten instrucciones adicionales para ramificarse alrededor de ellas.
  • Cuando se instalan en un sistema en ejecución, es posible que se alteren algunas instrucciones y cambie su formato, como una optimización de vinculación estática en el tiempo de instalación. Esto permite una ejecución más rápida una vez que se conoce la vinculación. Consulta el documento de formatos de instrucciones asociado para ver las variantes sugeridas. La palabra "sugerido" se usa con cautela, ya que no es obligatorio implementarlos.
  • Sintaxis y mnemotecnias humanas:
    • Orden de destino y, luego, fuente para los argumentos.
    • Algunos opcodes tienen un sufijo de nombre para desambiguar que indica los tipos en los que operan:
      • Los opcodes de 32 bits de tipo general no están marcados.
      • Los opcodes de 64 bits de tipo general tienen el sufijo -wide.
      • Los opcodes específicos de tipo tienen el sufijo de su tipo (o una sigla directa), una de las siguientes: -boolean, -byte, -char, -short, -int, -long, -float, -double, -object, -string, -class o -void.
    • Algunos opcodes tienen un sufijo para desambiguar que distingue operaciones idénticas que tienen diferentes diseños de instrucciones o opciones. Estos sufijos se separan de los nombres principales con una barra diagonal ("/") y, en general, existen para que haya una asignación uno a uno con constantes estáticas en el código que genera e interpreta ejecutables (es decir, para reducir la ambigüedad para las personas).
    • En las descripciones que se incluyen aquí, el ancho de un valor (que indica, p.ej., el rango de una constante o la cantidad de registros a los que se puede dirigir) se enfatiza con el uso de un carácter por cada cuatro bits de ancho.
    • Por ejemplo, en la instrucción “move-wide/from16 vAA, vBBBB”:
      • "move" es el código de operación base, que indica la operación básica (mover el valor de un registro).
      • "wide" es el sufijo del nombre, que indica que opera en datos amplios (64 bits).
      • from16” es el sufijo del código de operación, que indica una variante que tiene una referencia de registro de 16 bits como fuente.
      • "vAA" es el registro de destino (que se implica en la operación; una vez más, la regla es que los argumentos de destino siempre son los primeros), que debe estar en el rango v0 a v255.
      • vBBBB” es el registro de origen, que debe estar en el rango v0 a v65535.
  • Consulta el documento sobre los formatos de instrucción para obtener más detalles sobre los diversos formatos de instrucción (que se enumeran en "Op & Format"), así como detalles sobre la sintaxis del código de operación.
  • Consulta el documento sobre el formato de archivo .dex para obtener más detalles sobre dónde se ajusta el código de bytes en el panorama general.

Resumen del conjunto de código de bytes

Op y formato Mnemónico o sintaxis Argumentos Descripción
00 10 veces nop   Ciclos de residuos

Nota: Las pseudoinstrucciones con datos se etiquetan con este código de operación, en cuyo caso el byte de orden superior de la unidad de código de operación indica la naturaleza de los datos. Consulta "Formato packed-switch-payload", "Formato sparse-switch-payload" y "Formato fill-array-data-payload" a continuación.

01 12x move vA, vB Registro de destino A: (4 bits)
Registro de origen B: (4 bits)
Mueve el contenido de un registro que no es de objeto a otro.
02 22x move/from16 vAA, vBBBB A: registro de destino (8 bits)
B: registro de origen (16 bits)
Mueve el contenido de un registro que no es de objeto a otro.
03 32x move/16 vAAAA, vBBBB Registro de destino A: (16 bits)
Registro de origen B: (16 bits)
Mueve el contenido de un registro que no es de objeto a otro.
04 12x vA y vB de movimiento amplio A: par de registros de destino (4 bits)
B: par de registros de origen (4 bits)
Mueve el contenido de un par de registros a otro.

Nota: Es legal pasar de vN a vN-1 o vN+1, por lo que las implementaciones deben organizarse para que se lean ambas mitades de un par de registros antes de escribir algo.

05 22x move-wide/from16 vAA, vBBBB A: par de registros de destino (8 bits)
B: par de registros de origen (16 bits)
Mueve el contenido de un par de registros a otro.

Nota: Las consideraciones de implementación son las mismas que las de move-wide, más arriba.

06 32x move-wide/16 vAAAA, vBBBB Par de registros de destino A: (16 bits)
Par de registros de origen B: (16 bits)
Mueve el contenido de un par de registros a otro.

Nota: Las consideraciones de implementación son las mismas que las de move-wide, más arriba.

07 12x move-object vA, vB Registro de destino A: (4 bits)
Registro de origen B: (4 bits)
Mover el contenido de un registro con objetos a otro
08 22x move-object/from16 vAA, vBBBB A: registro de destino (8 bits)
B: registro de origen (16 bits)
Mover el contenido de un registro con objetos a otro
09 32x move-object/16 vAAAA, vBBBB Registro de destino A: (16 bits)
Registro de origen B: (16 bits)
Mover el contenido de un registro con objetos a otro
0a 11x vAA de resultado de movimiento Registro de destino A: (8 bits) Mueve el resultado no de objeto de una sola palabra del invoke-kind más reciente al registro indicado. Esto se debe hacer como la instrucción inmediatamente después de un invoke-kind cuyo resultado (de una sola palabra, no de objeto) no se debe ignorar; en cualquier otro lugar no es válido.
0b 11x vAA de move-result-wide Par de registros de destino A: (8 bits) Mueve el resultado de doble palabra del invoke-kind más reciente al par de registros indicado. Esto se debe hacer como la instrucción inmediatamente después de un invoke-kind cuyo resultado (de doble palabra) no se debe ignorar; en cualquier otro lugar no es válido.
0c 11x objeto de resultado de movimiento vAA Registro de destino A: (8 bits) Mueve el resultado del objeto del invoke-kind más reciente al registro indicado. Esto se debe hacer como la instrucción inmediatamente después de un invoke-kind o filled-new-array cuyo resultado (objeto) no se debe ignorar; en cualquier otro lugar no es válido.
0d 11x vAA de move-exception Registro de destino A: (8 bits) Guarda una excepción detectada recientemente en el registro determinado. Esta debe ser la primera instrucción de cualquier controlador de excepciones cuya excepción detectada no se deba ignorar, y esta instrucción solo debe ocurrir como la primera instrucción de un controlador de excepciones; en cualquier otro lugar no es válida.
0e 10x return-void   Muestra desde un método void.
0f 11x return vAA Registro de valor que se muestra A: (8 bits) Devuelve desde un método que muestra un valor no de objeto de un solo ancho (32 bits).
10 11 veces vAA de todo el retorno Par de registros del valor que se muestra A: (8 bits) Devuelve un método que muestra un valor de doble ancho (64 bits).
11 11x return-object vAA Registro del valor que se muestra A: (8 bits) Devuelve desde un método que muestra un objeto.
12 11n const/4 vA, #+B Registro de destino A: (4 bits)
Int firmado B: (4 bits)
Mueve el valor literal determinado (con signo extendido a 32 bits) al registro especificado.
13 21s const/16 vAA, #+BBBB Registro de destino A: (8 bits)
Int firmado B: (16 bits)
Mueve el valor literal determinado (con signo extendido a 32 bits) al registro especificado.
14 31i const vAA, #+BBBBBBBB A: registro de destino (8 bits)
B: constante arbitraria de 32 bits
Mueve el valor literal determinado al registro especificado.
15 21h const/high16 vAA, #+BBBB0000 Registro de destino A: (8 bits)
Int firmado B: (16 bits)
Mueve el valor literal determinado (extendido a la derecha a 32 bits) al registro especificado.
16 x 21 s const-wide/16 vAA, #+BBBB Registro de destino A: (8 bits)
Int firmado B: (16 bits)
Mueve el valor literal determinado (con signo extendido a 64 bits) al par de registros especificado.
17 31i const-wide/32 vAA, #+BBBBBBBB Registro de destino A: (8 bits)
Int firmado B: (32 bits)
Mueve el valor literal determinado (con signo extendido a 64 bits) al par de registros especificado.
18 51 l vAA de ancho constante, #+BBBBBBBBBBBBBBBB Registro de destino A: (8 bits)
B: constante arbitraria de doble ancho (64 bits)
Mueve el valor literal determinado al par de registros especificado.
19 21h const-wide/high16 vAA, #+BBBB000000000000 Registro de destino A: (8 bits)
Int firmado B: (16 bits)
Mueve el valor literal determinado (extendido a 64 bits a la derecha) al par de registros especificado.
1a 21c const-string vAA, string@BBBB Registro de destino A: (8 bits)
Índice de cadena B:
Mueve una referencia a la cadena especificada por el índice determinado al registro especificado.
1b 31c const-string/jumbo vAA, string@BBBBBBBB Registro de destino A: (8 bits)
Índice de cadena B:
Mueve una referencia a la cadena especificada por el índice determinado al registro especificado.
1c 21c const-class vAA, type@BBBB Registro de destino A: (8 bits)
Índice de tipo B:
Mueve una referencia a la clase especificada por el índice determinado al registro especificado. En el caso de que el tipo indicado sea primitivo, se almacenará una referencia a la clase degenerada del tipo primitivo.
1d 11x monitor-enter vAA Registro con referencia A: (8 bits) Adquiere el monitor para el objeto indicado.
1e 11x monitor-exit vAA Registro con referencia A: (8 bits) Libera el monitor del objeto indicado.

Nota: Si esta instrucción necesita generar una excepción, debe hacerlo como si la PC ya hubiera avanzado más allá de la instrucción. Puede ser útil pensar en esto como la instrucción que se ejecuta correctamente (en cierto sentido) y la excepción que se arroja después de la instrucción, pero antes de que la siguiente tenga la oportunidad de ejecutarse. Esta definición permite que un método use un filtro de limpieza de monitores (p.ej., finally) como la limpieza del monitor para ese bloque, como una forma de controlar las excepciones arbitrarias que podrían arrojarse debido a la implementación histórica de Thread.stop(), a la vez que se logra tener una higiene del monitor adecuada.

1f 21c check-cast vAA, type@BBBB A: registro con referencia (8 bits)
Índice de tipo B: (16 bits)
Lanza un ClassCastException si la referencia en el registro determinado no se puede transmitir al tipo indicado.

Nota: Dado que A siempre debe ser una referencia (y no un valor primitivo), esto fallará necesariamente en el tiempo de ejecución (es decir, arrojará una excepción) si B hace referencia a un tipo primitivo.

20 22c instance-of vA, vB, type@CCCC Registro de destino A: (4 bits)
Registro de referencia B: (4 bits)
Índice de tipo C: (16 bits)
Almacena en el registro de destino determinado 1 si la referencia indicada es una instancia del tipo determinado o 0 si no es así.

Nota: Dado que B siempre debe ser una referencia (y no un valor primitivo), esto siempre hará que se almacene 0 si C hace referencia a un tipo primitivo.

21 12x vA, vB de longitud de array Registro de destino A: (4 bits)
Registro de referencia del array B: (4 bits)
Almacena en el registro de destino determinado la longitud del array indicado, en entradas
22 21c new-instance vAA, type@BBBB Registro de destino A: (8 bits)
Índice de tipo B:
Crea una instancia nueva del tipo indicado y almacena una referencia a ella en el destino. El tipo debe hacer referencia a una clase que no sea de array.
23 22c new-array vA, vB, type@CCCC Registro de destino A: (4 bits)
Registro de tamaño B:
Índice de tipo C:
Crea un nuevo array del tipo y tamaño indicados. El tipo debe ser un tipo de array.
24 35c array-nuevo-completo {vC, vD, vE, vF, vG}, type@BBBB A: Tamaño del array y recuento de palabras de argumentos (4 bits)
Índice de tipo B: (16 bits)
Registros de argumentos C..G: (4 bits cada uno)
Construye un array del tipo y tamaño determinado y complétalo con el contenido proporcionado. El tipo debe ser un tipo de array. El contenido del array debe ser de una sola palabra (es decir, no hay arrays de long o double, pero se aceptan tipos de referencia). La instancia creada se almacena como un "resultado" de la misma manera que las instrucciones de invocación de métodos almacenan sus resultados, por lo que la instancia creada se debe mover a un registro con una instrucción move-result-object inmediatamente posterior (si se va a usar).
25 3rc filled-new-array/range {vCCCC .. vNNNN}, type@BBBB A: Tamaño del array y recuento de palabras de argumentos (8 bits)
Índice de tipo B: (16 bits)
Registro del primer argumento C: (16 bits)
N = A + C - 1
Construye un array del tipo y tamaño determinado y complétalo con el contenido proporcionado. Las aclaraciones y restricciones son las mismas que las de filled-new-array, que se describieron anteriormente.
26 31 t fill-array-data vAA, +BBBBBBBB (con datos complementarios como se especifica a continuación en “Formato fill-array-data-payload”) Referencia de array A: (8 bits)
Desplazamiento de “rama” firmado B: a la pseudoinstrucción de datos de la tabla (32 bits)
Completa el array determinado con los datos indicados. La referencia debe ser a un array de primitivas, y la tabla de datos debe coincidir con ella en el tipo y no debe contener más elementos que los que caben en el array. Es decir, el array puede ser más grande que la tabla y, de ser así, solo se establecen los elementos iniciales del array, dejando el resto solo.
27 11x arroja vAA Registro con excepción A: (8 bits)
Lanza la excepción indicada.
28 10t goto +AA Desplazamiento de rama firmado A: (8 bits) Salta de forma incondicional a la instrucción indicada.

Nota: El desplazamiento de la rama no debe ser 0. (Un bucle de giro se puede construir legalmente con goto/32 o si se incluye un nop como objetivo antes de la rama).

29 20 t goto/16 +AAAA Desplazamiento de rama firmado A: (16 bits)
Salta de forma incondicional a la instrucción indicada.

Nota: El desplazamiento de la rama no debe ser 0. (Un bucle de giro se puede construir legalmente con goto/32 o si se incluye un nop como objetivo antes de la rama).

2a 30t goto/32 +AAAAAAAA Desplazamiento de rama firmado A: (32 bits)
Salta de forma incondicional a la instrucción indicada.
2b 31t conmutador empaquetado vAA, +BBBBBBBB (con datos complementarios como se especifica a continuación en “Formato packed-switch-payload”) Registro A: para probar
Offset de “rama” firmado B: a la pseudoinstrucción de datos de la tabla (32 bits)
Saltar a una instrucción nueva según el valor del registro determinado, con una tabla de desplazamientos correspondientes a cada valor en un rango integral en particular, o bien pasar a la siguiente instrucción si no hay coincidencias
2c 31t sparse-switch vAA, +BBBBBBBB (con datos complementarios como se especifica a continuación en “Formato sparse-switch-payload”) Registro A: para probar
Offset de “rama” firmado B: a la pseudoinstrucción de datos de la tabla (32 bits)
Saltar a una instrucción nueva según el valor del registro determinado, con una tabla ordenada de pares de valores y desplazamientos, o bien pasar a la siguiente instrucción si no hay coincidencias
2d..31 23x cmpkind vAA, vBB, vCC
2d: cmpl-float (lt bias)
2e: cmpg-float (gt bias)
2f: cmpl-double (lt bias)
30: cmpg-double (gt bias)
31: cmp-long
A: registro de destino (8 bits)
B: primer registro o par de origen
C: segundo registro o par de origen
Realiza la comparación indicada de punto flotante o long, y establece a en 0 si es b == c, 1 si es b > c o -1 si es b < c. El "sesgo" que se indica para las operaciones de punto flotante indica cómo se tratan las comparaciones de NaN: las instrucciones de "sesgo superior" muestran 1 para las comparaciones de NaN, y las instrucciones de "sesgo inferior" muestran -1.

Por ejemplo, para comprobar si un número de punto flotante es x < y, se recomienda usar cmpg-float. Un resultado de -1 indica que la prueba fue verdadera, y los otros valores indican que fue falsa, ya sea debido a una comparación válida o porque uno de los valores era 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: primer registro para probar (4 bits)
B: segundo registro para probar (4 bits)
C: desplazamiento de rama firmado (16 bits)
Realiza una bifurcación al destino determinado si los valores de los dos registros determinados se comparan como se especifica.

Nota: El desplazamiento de la rama no debe ser 0. (Un bucle de giro se puede construir legalmente mediante una bifurcación alrededor de un goto hacia atrás o mediante la inclusión de un nop como objetivo antes de la bifurcación).

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
Registro A: para probar (8 bits)
Desplazamiento de rama firmado B: (16 bits)
Realiza una bifurcación al destino determinado si el valor del registro determinado se compara con 0 como se especifica.

Nota: El desplazamiento de la rama no debe ser 0. (Un bucle de giro se puede construir legalmente mediante una ramificación alrededor de un goto hacia atrás o mediante la inclusión de un nop como objetivo antes de la rama).

3e..43 10x (sin usar)   (sin usar)
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
Registro o par de valores A: (puede ser fuente o destino) (8 bits)
Registro de array B: (8 bits)
Registro de índice C: (8 bits)
Realiza la operación de array identificada en el índice identificado del array determinado y carga o almacena en el registro de valores.
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
Registro o par de valores A:; puede ser fuente o destino (4 bits)
Registro de objetos B: (4 bits)
Índice de referencia de campo de instancia C: (16 bits)
Realiza la operación de campo de instancia de objeto identificado con el campo identificado, cargándolo o almacenándolo en el registro de valores.

Nota: Estos códigos de operación son candidatos razonables para la vinculación estática, ya que modifican el argumento del campo para que sea un desplazamiento más directo.

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
Registro o par de valores A:; puede ser fuente o destino (8 bits)
Índice de referencia de campo estático B: (16 bits)
Realiza la operación de campo estático del objeto identificado con el campo estático identificado, cargándolo o almacenándolo en el registro de valores.

Nota: Estos códigos de operación son candidatos razonables para la vinculación estática, ya que modifican el argumento de campo para que sea un desplazamiento más directo.

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
Recuento de palabras del argumento A: (4 bits)
Índice de referencia del método B: (16 bits)
Registros de argumentos C..G: (4 bits cada uno)
Llama al método indicado. El resultado (si corresponde) se puede almacenar con una variante move-result* adecuada como la instrucción inmediatamente posterior.

invoke-virtual se usa para invocar un método virtual normal, que es un método que no es static, private ni un constructor.

Cuando method_id hace referencia a un método de una clase que no es de interfaz, se usa invoke-super para invocar el método virtual de la superclase más cercana (en oposición al que tiene el mismo method_id en la clase de llamada). Se aplican las mismas restricciones de método que para invoke-virtual.

En los archivos DEX de la versión 037 o posterior, si method_id hace referencia a un método de interfaz, se usa invoke-super para invocar la versión más específica y no anulada de ese método definido en esa interfaz. Se aplican las mismas restricciones de método que para invoke-virtual. En los archivos Dex anteriores a la versión 037, tener una interfaz method_id es ilegal y no está definido.

invoke-direct se usa para invocar un método directo que no sea static (es decir, un método de instancia que, por su naturaleza, no se puede anular, es decir, un método de instancia private o un constructor).

invoke-static se usa para invocar un método static (que siempre se considera un método directo).

invoke-interface se usa para invocar un método interface, es decir, en un objeto cuya clase concreta no se conoce, con un method_id que hace referencia a un interface.

Nota: Estos opcodes son candidatos razonables para la vinculación estática, ya que alteran el argumento del método para que sea un desplazamiento más directo (o un par de ellos).

73 10x (sin usar)   (sin usar)
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
Cantidad de palabras del argumento A: (8 bits)
Índice de referencia del método B: (16 bits)
Registro del primer argumento C: (16 bits)
N = A + C - 1
Llama al método indicado. Consulta la primera descripción de invoke-kind que aparece más arriba para obtener detalles, advertencias y sugerencias.
79..7a 10x (sin usar)   (sin usar)
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: registro o par de destino (4 bits)
B: registro o par de origen (4 bits)
Realiza la operación unaria identificada en el registro de origen y almacena el resultado en el registro de destino.
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: registro o par de destino (8 bits)
B: primer registro o par de origen (8 bits)
C: segundo registro o par de origen (8 bits)
Realiza la operación binaria identificada en los dos registros de origen y almacena el resultado en el registro de destino.

Nota: Contrario a otras operaciones matemáticas de -long (que toman pares de registros para su primera y segunda fuente), shl-long, shr-long y ushr-long toman un par de registros para su primera fuente (el valor que se desplazará), pero un solo registro para su segunda fuente (la distancia de desplazamiento).

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: registro o par de destino y primer registro o par de origen (4 bits)
B: registro o par de segundo origen (4 bits)
Realiza la operación binaria identificada en los dos registros de origen y almacena el resultado en el primer registro de origen.

Nota: Al contrario de otras operaciones matemáticas de -long/2addr (que toman pares de registros para su destino o primera fuente y su segunda fuente), shl-long/2addr, shr-long/2addr y ushr-long/2addr toman un par de registros para su destino o primera fuente (el valor que se desplazará), pero un solo registro para su segunda fuente (la distancia de desplazamiento).

d0..d7 22s binop/lit16 vA, vB, #+CCCC
d0: add-int/lit16
d1: rsub-int (reverse subtract)
d2: mul-int/lit16
d3: div-int/lit16
d4: rem-int/lit16
d5: and-int/lit16
d6: or-int/lit16
d7: xor-int/lit16
Registro de destino A: (4 bits)
Registro de origen B: (4 bits)
Constante de int firmada C: (16 bits)
Realiza la operación binaria indicada en el registro indicado (primer argumento) y el valor literal (segundo argumento), y almacena el resultado en el registro de destino.

Nota: rsub-int no tiene un sufijo, ya que esta versión es el código de operación principal de su familia. Además, consulta la siguiente información para obtener detalles sobre su semántica.

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
Registro de destino A: (8 bits)
Registro de origen B: (8 bits)
Constante int firmada C: (8 bits)
Realiza la operación binaria indicada en el registro indicado (primer argumento) y el valor literal (segundo argumento), y almacena el resultado en el registro de destino.

Nota: Consulta a continuación para obtener detalles sobre la semántica de rsub-int.

e3..f9 10x (sin usar)   (sin usar)
fa 45 cc invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH Cantidad de palabras de argumentos A: (4 bits)
Índice de referencia del método B: (16 bits)
Receptor C: (4 bits)
Registros de argumentos D..G: (4 bits cada uno)
Índice de referencia del prototipo H: (16 bits)
Invoca el método polimórfico de firma indicado. El resultado (si corresponde) se puede almacenar con una variante move-result* adecuada como la instrucción inmediatamente posterior.

La referencia del método debe ser a un método polimórfico de firma, como java.lang.invoke.MethodHandle.invoke o java.lang.invoke.MethodHandle.invokeExact.

El receptor debe ser un objeto que admita el método polimórfico de firma que se invoca.

La referencia del prototipo describe los tipos de argumentos proporcionados y el tipo de devolución esperado.

El código de bytes invoke-polymorphic puede generar excepciones cuando se ejecuta. Las excepciones se describen en la documentación de la API para el método polimórfico de firma que se invoca.

Presente en los archivos DEX a partir de la versión 038.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH Recuento de palabras de argumentos A: (8 bits)
Índice de referencia del método B: (16 bits)
Receptor C: (16 bits)
Índice de referencia del prototipo H: (16 bits)
N = A + C - 1
Invoca el controlador de método indicado. Consulta la descripción de invoke-polymorphic que aparece más arriba para obtener más detalles.

Presente en los archivos DEX a partir de la versión 038.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB Recuento de palabras de argumentos A: (4 bits)
Índice de referencia del sitio de llamada B: (16 bits)
Registros de argumentos C..G: (4 bits cada uno)
Resuelve e invoca el lugar de la llamada indicado. El resultado de la invocación (si la hay) se puede almacenar con una variante move-result* adecuada como la instrucción inmediatamente posterior.

Esta instrucción se ejecuta en dos fases: resolución del sitio de llamada y su invocación.

La resolución del sitio de llamada verifica si el sitio de llamada indicado tiene una instancia de java.lang.invoke.CallSite asociada. De lo contrario, se invoca el método del vinculador de arranque para el sitio de llamada indicado con argumentos presentes en el archivo DEX (consulta call_site_item). El método del vinculador de inicio muestra una instancia de java.lang.invoke.CallSite que, luego, se asociará con el sitio de llamada indicado si no existe una asociación. Es posible que otro subproceso ya haya establecido la asociación primero y, de ser así, la ejecución de la instrucción continuará con la primera instancia asociada de java.lang.invoke.CallSite.

La invocación del sitio de llamada se realiza en el objetivo java.lang.invoke.MethodHandle de la instancia java.lang.invoke.CallSite resuelta. El objetivo se invoca como si se ejecutara invoke-polymorphic (descrito anteriormente) con el identificador de método y los argumentos de la instrucción invoke-custom como los argumentos de una invocación exacta del identificador de método.

Las excepciones que genera el método del vinculador de arranque se unen en un java.lang.BootstrapMethodError. También se genera una BootstrapMethodError en los siguientes casos:
  • El método del vinculador de arranque no muestra una instancia de java.lang.invoke.CallSite.
  • el java.lang.invoke.CallSite que se muestra tiene un objetivo de controlador de método null.
  • El destino del identificador de método no es del tipo solicitado.
Presente en los archivos DEX a partir de la versión 038.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: recuento de palabras de argumentos (8 bits)
B: índice de referencia del sitio de llamada (16 bits)
C: registro del primer argumento (16 bits)
N = A + C - 1
Resuelve e invoca un sitio de llamada. Consulta la descripción de invoke-custom que aparece más arriba para obtener más detalles.

Presente en los archivos DEX a partir de la versión 038.
fe 21c const-method-handle vAA, method_handle@BBBB Registro de destino A: (8 bits)
Índice de identificador de método B: (16 bits)
Mueve una referencia al identificador de método especificado por el índice determinado al registro especificado.

Presente en los archivos DEX a partir de la versión 039.
ff 21c const-method-type vAA, proto@BBBB Registro de destino A: (8 bits)
Referencia del prototipo del método B: (16 bits)
Mueve una referencia al prototipo del método especificado por el índice determinado al registro especificado.

Presente en los archivos DEX a partir de la versión 039.

Formato de carga útil de interruptor empaquetado

Name Formato Descripción
identificador ushort = 0x0100 identificación del pseudocódigo
size ushort cantidad de entradas en la tabla
first_key int primer (y más bajo) valor de case
objetivos int[] Es una lista de destinos de ramas relativas size. Los destinos se relacionan con la dirección del código de operación de cambio, no con esta tabla.

Nota: La cantidad total de unidades de código para una instancia de esta tabla es (size * 2) + 4.

Formato de carga útil de interruptores dispersos

Name Formato Descripción
identificador ushort = 0x0200 identificación del pseudocódigo
size ushort cantidad de entradas en la tabla
llaves int[] Es una lista de valores de clave size, ordenados de menor a mayor.
objetivos int[] Es una lista de destinos de rama relativos size, cada uno de los cuales corresponde al valor de clave en el mismo índice. Los destinos se relacionan con la dirección del código de operación de cambio, no con esta tabla.

Nota: La cantidad total de unidades de código para una instancia de esta tabla es (size * 4) + 2.

Formato de carga útil de datos de array de relleno

Name Formato Descripción
identificador ushort = 0x0300 identificación del pseudocódigo
element_width ushort cantidad de bytes en cada elemento
size uint cantidad de elementos en la tabla
datos ubyte[] valores de datos

Nota: La cantidad total de unidades de código para una instancia de esta tabla es (size * element_width + 1) / 2 + 4.

Detalles de la operación matemática

Nota: Las operaciones de punto flotante deben seguir las reglas del estándar IEEE 754, con redondeo al número más cercano y desbordamiento gradual, excepto cuando se indique lo contrario.

Código de operación Semántica de C Notas
neg-int int32 a;
int32 result = -a;
Complemento a dos unario
not-int int32 a;
int32 result = ~a;
Complemento a uno unario
neg-long int64 a;
int64 result = -a;
Complemento a dos unario
not-long int64 a;
int64 result = ~a;
Complemento a uno unario
neg-float float a;
float result = -a;
Negación de punto flotante.
neg-double double a;
double result = -a;
Negación de punto flotante.
int a long int32 a;
int64 result = (int64) a;
Firma la extensión de int32 en int64.
int a float int32 a;
float result = (float) a;
Conversión de int32 a float con redondeo al número más cercano Esto pierde precisión para algunos valores.
int-to-double int32 a;
double result = (double) a;
Conversión de int32 a double.
long-to-int int64 a;
int32 result = (int32) a;
Truncamiento de int64 en int32.
long-to-float int64 a;
float result = (float) a;
Conversión de int64 a float con redondeo al número más cercano Esto pierde precisión para algunos valores.
de largo a doble int64 a;
double result = (double) a;
Conversión de int64 a double con redondeo al número más cercano Esto pierde precisión para algunos valores.
float-to-int float a;
int32 result = (int32) a;
Conversión de float a int32, con redondeo hacia cero NaN y -0.0 (cero negativo) se convierten en el número entero 0. Los infinitos y los valores con una magnitud demasiado grande para representarse se convierten en 0x7fffffff o -0x80000000 según el signo.
de número de punto flotante a número largo float a;
int64 result = (int64) a;
Conversión de float a int64, con redondeo hacia cero Aquí se aplican las mismas reglas de casos especiales que para float-to-int, excepto que los valores fuera de rango se convierten en 0x7fffffffffffffff o -0x8000000000000000 según el signo.
float-to-double float a;
double result = (double) a;
Conversión de float a double, que conserva el valor de forma exacta
double-to-int double a;
int32 result = (int32) a;
Conversión de double a int32, con redondeo hacia cero Aquí se aplican las mismas reglas de casos especiales que para float-to-int.
de doble a largo double a;
int64 result = (int64) a;
Conversión de double a int64, con redondeo hacia cero Aquí se aplican las mismas reglas de casos especiales que para float-to-long.
double-to-float double a;
float result = (float) a;
Conversión de double a float con redondeo al número más cercano Esto pierde precisión para algunos valores.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
Reducción de int32 a int8, firma que extiende el resultado.
int-to-char int32 a;
int32 result = a & 0xffff;
Reducción de int32 a uint16, sin extensión de signo
int-to-short int32 a;
int32 result = (a << 16) >> 16;
Reducción de int32 a int16, firma que extiende el resultado.
add-int int32 a, b;
int32 result = a + b;
Suma de complemento a dos.
sub-int int32 a, b;
int32 result = a - b;
Resta de complemento a dos
rsub-int int32 a, b;
int32 result = b - a;
Resta inversa de complemento a dos
mul-int int32 a, b;
int32 result = a * b;
Multiplicación de complemento a dos.
div-int int32 a, b;
int32 result = a / b;
División de complemento a dos, redondeada hacia cero (es decir, truncada a número entero). Esto arroja ArithmeticException si b == 0.
rem-int int32 a, b;
int32 result = a % b;
Es el resto en complemento a dos después de la división. El signo del resultado es el mismo que el de a y se define con mayor precisión como result == a - (a / b) * b. Esto arroja ArithmeticException si b == 0.
and-int int32 a, b;
int32 result = a & b;
AND a nivel de bits.
or-int int32 a, b;
int32 result = a | b;
OR bit a bit.
xor-int int32 a, b;
int32 result = a ^ b;
XOR a nivel de bits.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Desplazamiento de bits a la izquierda (con argumento enmascarado).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Desplazamiento de bits firmado a la derecha (con argumento enmascarado).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Desplazamiento de bits sin signo a la derecha (con argumento enmascarado).
add-long int64 a, b;
int64 result = a + b;
Suma de complemento a dos.
sublongitudinal int64 a, b;
int64 result = a - b;
Resta de complemento a dos
mul-long int64 a, b;
int64 result = a * b;
Multiplicación de complemento a dos.
div-long int64 a, b;
int64 result = a / b;
División de complemento a dos, redondeada hacia cero (es decir, truncada a número entero). Esto arroja ArithmeticException si b == 0.
rem-long int64 a, b;
int64 result = a % b;
Es el resto en complemento a dos después de la división. El signo del resultado es el mismo que el de a y se define con mayor precisión como result == a - (a / b) * b. Esto arroja ArithmeticException si b == 0.
and-long int64 a, b;
int64 result = a & b;
AND a nivel de bits.
or-long int64 a, b;
int64 result = a | b;
OR bit a bit.
xor-long int64 a, b;
int64 result = a ^ b;
XOR a nivel de bits.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Desplazamiento de bits a la izquierda (con argumento enmascarado).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Desplazamiento de bits firmado a la derecha (con argumento enmascarado).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Desplazamiento de bits sin signo a la derecha (con argumento enmascarado).
add-float float a, b;
float result = a + b;
Suma de números de punto flotante.
subflotante float a, b;
float result = a - b;
Resta de punto flotante.
mul-float float a, b;
float result = a * b;
Multiplicación de números de punto flotante.
div-float float a, b;
float result = a / b;
División de punto flotante.
rem-float float a, b;
float result = a % b;
Es el resto de punto flotante después de la división. Esta función es diferente del resto de IEEE 754 y se define como result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double result = a + b;
Suma de números de punto flotante.
subdoble double a, b;
double result = a - b;
Resta de punto flotante.
mul-double double a, b;
double result = a * b;
Multiplicación de números de punto flotante.
div-double double a, b;
double result = a / b;
División de punto flotante.
rem-double double a, b;
double result = a % b;
Es el resto de punto flotante después de la división. Esta función es diferente del resto de IEEE 754 y se define como result == a - roundTowardZero(a / b) * b.