Formato de bytecode Dalvik

Design geral

  • O modelo de máquina e as convenções de chamada têm a finalidade de imitar aproximadamente arquiteturas reais comuns e convenções de chamada no estilo C:
    • A máquina é baseada em registro, e os frames são fixados no tamanho após a criação. Cada frame consiste em um número específico de registros (especificado pelo método) e de dados adjuntos necessários para executar o método, como, mas não se limitando a, o contador de programa e uma referência ao arquivo .dex que contém o método.
    • Quando usados para valores de bit (como números inteiros e de ponto flutuante), os registros são considerados de 32 bits. Pares de registro adjacentes são usados para valores de 64 bits. Não há requisito de alinhamento para pares de registro.
    • Quando usados para referências de objeto, os registros são considerados amplos o suficiente para conter exatamente uma referência.
    • Em termos de representação de bits, (Object) null == (int) 0.
    • Os argumentos N de um método são armazenados nos últimos N registros do frame de invocação do método, em ordem. Os argumentos largos consomem dois registros. Os métodos de instância recebem uma referência this como primeiro argumento.
  • A unidade de armazenamento no fluxo de instruções é uma quantidade não assinada de 16 bits. Alguns bits em algumas instruções são ignorados / precisam ser zero.
  • As instruções não são limitadas a um tipo específico. Por exemplo, instruções que movem valores de registro de 32 bits sem interpretação não precisam especificar se estão movendo ints ou floats.
  • Há pools de constantes enumerados e indexados separadamente para referências a strings, tipos, campos e métodos.
  • Os dados literais de bit são representados inline no fluxo de instruções.
  • Na prática, é raro um método precisar de mais de 16 registros, e como a necessidade de mais de oito registros é bastante comum, muitas instruções são limitadas a apenas endereçar os primeiros 16 registros. Quando razoavelmente possível, as instruções permitem referências a até os primeiros 256 registros. Além disso, algumas instruções têm variantes que permitem contagens de registros muito maiores, incluindo um par de instruções move que podem endereçar registros no intervalo v0 a v65535. Nos casos em que uma variante de instrução não está disponível para endereçar um registro desejado, é esperado que o conteúdo do registro seja movido do registro original para um registro baixo (antes da operação) e/ou movido de um registro de resultado baixo para um registro alto (após a operação).
  • Há várias "pseudoinstruções" que são usadas para armazenar payloads de dados de comprimento variável, que são referenciados por instruções normais (por exemplo, fill-array-data). Essas instruções nunca podem ser encontradas durante o fluxo normal de execução. Além disso, as instruções precisam estar localizadas em deslocamentos de bytecode de número par (ou seja, alinhados a 4 bytes). Para atender a esse requisito, as ferramentas de geração dex precisam emitir uma instrução nop extra como um espaço se essa instrução não estiver alinhada. Por fim, embora não seja obrigatório, espera-se que a maioria das ferramentas emita essas instruções no final dos métodos, porque, caso contrário, provavelmente instruções adicionais seriam necessárias para ramificar em torno delas.
  • Quando instaladas em um sistema em execução, algumas instruções podem ser alteradas, mudando o formato delas, como uma otimização de vinculação estática no momento da instalação. Isso permite uma execução mais rápida quando a vinculação é conhecida. Consulte o documento de formatos de instrução associado para conferir as variantes sugeridas. A palavra "sugerida" é usada com cuidado. Não é obrigatório implementar essas sugestões.
  • Sintaxe humana e mnemônicos:
    • Ordenação de destino e origem para argumentos.
    • Alguns opcodes têm um sufixo de nome que elimina a ambiguidade para indicar os tipos em que eles operam:
      • Os opcodes de 32 bits de tipo geral não são marcados.
      • Os opcodes de 64 bits de tipo geral têm o sufixo -wide.
      • Os opcodes específicos de tipo têm o sufixo do tipo (ou uma abreviação simples), um dos seguintes: -boolean -byte -char -short -int -long -float -double -object -string -class -void.
    • Alguns opcodes têm um sufixo de resolução de ambiguidade para distinguir operações idênticas que têm layouts de instrução ou opções diferentes. Esses sufixos são separados dos nomes principais por um caractere de barra ("/") e existem principalmente para que haja um mapeamento um-para-um com constantes estáticas no código que gera e interpreta executáveis, ou seja, para reduzir a ambiguidade para humanos.
    • Nas descrições aqui, a largura de um valor (que indica, por exemplo, o intervalo de uma constante ou o número de registros possivelmente endereçados) é enfatizada pelo uso de um caractere por quatro bits de largura.
    • Por exemplo, na instrução "move-wide/from16 vAA, vBBBB":
      • "move" é o opcode base, indicando a operação base (mover o valor de um registro).
      • "wide" é o sufixo de nome, indicando que ele opera com dados amplos (64 bits).
      • "from16" é o sufixo do opcode, indicando uma variante que tem uma referência de registro de 16 bits como origem.
      • "vAA" é o registro de destino (implícito na operação. Novamente, a regra é que os argumentos de destino sempre vêm primeiro), que precisa estar no intervalo v0v255.
      • "vBBBB" é o registro de origem, que precisa estar no intervalo v0 a v65535.
  • Consulte o documento de formatos de instrução para mais detalhes sobre os vários formatos de instrução (listados em "Op & Format") e detalhes sobre a sintaxe do opcode.
  • Consulte o documento do formato de arquivo .dex para mais detalhes sobre onde o bytecode se encaixa no contexto geral.

Resumo do conjunto de bytecode

Opção e formato Mnemônico / Sintaxe Argumentos Descrição
00 10x não   Ciclos de resíduos.

Observação:as pseudoinstruções que contêm dados são marcadas com esse opcode. Nesse caso, o byte de ordem alta da unidade de opcode indica a natureza dos dados. Consulte "Formato packed-switch-payload", "Formato sparse-switch-payload" e "Formato fill-array-data-payload" abaixo.

01 12x move vA, vB Registro de destino A: (4 bits)
Registro de origem B: (4 bits)
Mova o conteúdo de um registro não de objeto para outro.
02 22x move/from16 vAA, vBBBB A: Registro de destino (8 bits)
B: Registro de origem (16 bits)
Mova o conteúdo de um registro não de objeto para outro.
03 32x move/16 vAAAA, vBBBB A: Registro de destino (16 bits)
B: Registro de origem (16 bits)
Mova o conteúdo de um registro não de objeto para outro.
04 12x vA, vB de movimento amplo A: par de registros de destino (4 bits)
B: par de registros de origem (4 bits)
Move o conteúdo de um par de registros para outro.

Observação:É permitido passar de vN para vN-1 ou vN+1. Portanto, as implementações precisam organizar as duas metades de um par de registros para que sejam lidas antes de qualquer coisa ser gravada.

05 22x move-wide/from16 vAA, vBBBB A: par de registros de destino (8 bits)
B: par de registros de origem (16 bits)
Move o conteúdo de um par de registros para outro.

Observação:as considerações de implementação são as mesmas de move-wide, acima.

06 32x move-wide/16 vAAAA, vBBBB A: par de registros de destino (16 bits)
B: par de registros de origem (16 bits)
Move o conteúdo de um par de registros para outro.

Observação:as considerações de implementação são as mesmas de move-wide, acima.

07 12x move-object vA, vB Registro de destino A: (4 bits)
Registro de origem B: (4 bits)
Mova o conteúdo de um registro de objeto para outro.
08 22x move-object/from16 vAA, vBBBB A: Registro de destino (8 bits)
B: Registro de origem (16 bits)
Mova o conteúdo de um registro de objeto para outro.
09 32x move-object/16 vAAAA, vBBBB A: Registro de destino (16 bits)
B: Registro de origem (16 bits)
Mova o conteúdo de um registro de objeto para outro.
0a 11x move-result vAA Registro de destino A: (8 bits) Move o resultado não-objeto de uma palavra do invoke-kind mais recente para o registro indicado. Isso precisa ser feito como a instrução imediatamente após um invoke-kind cujo resultado (palavra única, não objeto) não seja ignorado. Qualquer outro lugar é inválido.
0b 11x move-result-wide vAA Par de registro de destino A: (8 bits) Mova o resultado de palavra dupla do invoke-kind mais recente para o par de registros indicado. Isso precisa ser feito como a instrução imediatamente após um invoke-kind cujo resultado (palavra dupla) não seja ignorado. Qualquer outro lugar é inválido.
0c 11x move-result-object vAA Registro de destino A: (8 bits) Mova o resultado do objeto do invoke-kind mais recente para o registro indicado. Isso precisa ser feito como a instrução imediatamente após um invoke-kind ou filled-new-array cujo resultado (objeto) não seja ignorado. Qualquer outro lugar é inválido.
0d 11x move-exception vAA Registro de destino A: (8 bits) Salva uma exceção detectada no registro fornecido. Essa precisa ser a primeira instrução de qualquer gerenciador de exceções em que a exceção capturada não seja ignorada. Essa instrução precisa ocorrer como a primeira instrução de um gerenciador de exceções. Qualquer outro local é inválido.
0e 10x return-void   Retorne de um método void.
0f 11x return vAA Registro de valor de retorno A: (8 bits) Retornar de um método que retorna valor de largura única (32 bits) que não é de objeto.
10 11x return-wide vAA Par de registro de valor de retorno A: (8 bits) Retornar de um método que retorna valor de largura dupla (64 bits).
11 11x return-object vAA Registro de valor de retorno A: (8 bits) Retornar de um método que retorna objetos.
12 11n const/4 vA, #+B A: registro de destino (4 bits)
B: int assinado (4 bits)
Move o valor literal fornecido (com sinal estendido para 32 bits) para o registro especificado.
13 21s const/16 vAA, #+BBBB A: Registro de destino (8 bits)
B: int assinado (16 bits)
Move o valor literal fornecido (com sinal estendido para 32 bits) para o registro especificado.
14 31i const vAA, #+BBBBBBBB A: registro de destino (8 bits)
B: constante arbitrária de 32 bits
Move o valor literal fornecido para o registro especificado.
15 21h const/high16 vAA, #+BBBB0000 A: Registro de destino (8 bits)
B: int assinado (16 bits)
Move o valor literal fornecido (direita-zero-estendida para 32 bits) para o registro especificado.
16 21s const-wide/16 vAA, #+BBBB A: registro de destino (8 bits)
B: int assinado (16 bits)
Move o valor literal fornecido (com sinal estendido para 64 bits) para par de registros especificado.
17 31i const-wide/32 vAA, #+BBBBBBBB A: Registro de destino (8 bits)
B: int assinado (32 bits)
Move o valor literal fornecido (com sinal estendido para 64 bits) para par de registros especificado.
18 51l const-wide vAA, #+BBBBBBBBBBBBBBBB A: Registro de destino (8 bits)
B: constante arbitrária de largura dupla (64 bits)
Move o valor literal fornecido para par de registros especificado.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: Registro de destino (8 bits)
B: int assinado (16 bits)
Move o valor literal fornecido (direito-zero-estendido para 64 bits) para o par de registros especificado.
1a 21c const-string vAA, string@BBBB Registro de destino A: (8 bits)
Índice de string B:
Move uma referência à string especificada pelo índice fornecido para o registro especificado.
1b 31c const-string/jumbo vAA, string@BBBBBBBB Registro de destino A: (8 bits)
Índice de string B:
Move uma referência à string especificada pelo índice fornecido para o registro especificado.
1c 21c const-class vAA, type@BBBB Registro de destino A: (8 bits)
Índice de tipo B:
Move uma referência à classe especificada pelo índice fornecido para o registro especificado. No caso em que o tipo indicado é primitivo, ele armazena uma referência à classe degenerada do tipo primitivo.
1d 11x monitor-enter vAA Registro de referência A: (8 bits) Adquire o monitor para o objeto indicado.
1e 11x monitor-exit vAA Registro de referência A: (8 bits) Libere o monitoramento do objeto indicado.

Observação:se essa instrução precisar gerar uma exceção, ela precisa fazer isso como se o PC já tivesse avançado além da instrução. Pode ser útil pensar nisso como a instrução sendo executada corretamente (em um sentido) e a exceção sendo gerada após a instrução, mas antes que a próxima tenha a chance de ser executada. Essa definição permite que um método use um catch-all de limpeza de monitor (por exemplo, O bloco finally) é bloqueado como a limpeza do monitor para esse bloco, como uma maneira de processar as exceções arbitrárias que podem ser geradas devido à implementação histórica de Thread.stop(), enquanto ainda gerencia para ter uma higiene adequada do monitor.

1f 21c check-cast vAA, type@BBBB Registro de referência A: (8 bits)
Índice de tipo B: (16 bits)
Gera uma ClassCastException se a referência no registro fornecido não puder ser transmitida para o tipo indicado.

Observação:como A precisa ser sempre uma referência (e não um valor primitivo), isso vai falhar necessariamente no momento de execução (ou seja, vai gerar uma exceção) se B se referir a um tipo primitivo.

20 22c instance-of vA, vB, type@CCCC Registro de destino A: (4 bits)
Registro de referência B: (4 bits)
Índice de tipo C: (16 bits)
Armazenar no registro de destino 1 especificado se a referência indicada for uma instância do tipo especificado ou 0, caso contrário.

Observação:como B precisa ser sempre uma referência (e não um valor primitivo), isso sempre resultará na 0 sendo armazenada se C se referir a um tipo primitivo.

21 12x array-length vA, vB Registro de destino A: (4 bits)
Registro de referência de matriz B: (4 bits)
Armazenar no registro de destino especificado o comprimento da matriz indicada, em entradas
22 21c new-instance vAA, type@BBBB Registro de destino A: (8 bits)
Índice de tipo B:
Cria uma nova instância do tipo indicado, armazenando uma referência a ele no destino. O tipo precisa se referir a uma classe que não seja de matriz.
23 22c new-array vA, vB, type@CCCC Registro de destino A: (4 bits)
Registro de tamanho B:
Índice de tipo C:
Cria uma nova matriz do tipo e tamanho indicados. O tipo precisa ser um tipo de matriz.
24 35c filled-new-array {vC, vD, vE, vF, vG}, type@BBBB A: tamanho da matriz e contagem de palavras de argumento (4 bits)
B: índice de tipo (16 bits)
C..G: registros de argumento (4 bits cada)
Cria uma matriz do tipo e tamanho especificados, preenchendo-a com o conteúdo fornecido. O tipo precisa ser um tipo de matriz. O conteúdo da matriz precisa ser uma única palavra, ou seja, não pode ter matrizes de long ou double, mas tipos de referência são aceitos. A instância construída é armazenada como um "resultado" da mesma forma que as instruções de invocação de método armazenam os resultados. Portanto, a instância construída precisa ser movida para um registro com uma instrução move-result-object imediatamente subsequente (se for usada).
25 3rc filled-new-array/range {vCCCC .. vNNNN}, type@BBBB A: Tamanho da matriz e contagem de palavras do argumento (8 bits)
Índice de tipo B: (16 bits)
Registro do primeiro argumento C: (16 bits)
N = A + C - 1
Cria uma matriz do tipo e tamanho especificados, preenchendo-a com o conteúdo fornecido. Os esclarecimentos e as restrições são os mesmos de filled-new-array, descritos acima.
26 31t fill-array-data vAA, +BBBBBBBB (com dados complementares conforme especificado abaixo em "Formato fill-array-data-payload") Referência de matriz A: (8 bits)
B: deslocamento de "ramificação" assinado para a pseudoinstrução de dados da tabela (32 bits)
Preencha a matriz especificada com os dados indicados. A referência precisa ser para uma matriz de primitivos, e a tabela de dados precisa corresponder a ela no tipo e não pode conter mais elementos do que cabe na matriz. Ou seja, a matriz pode ser maior que a tabela. Nesse caso, apenas os elementos iniciais da matriz são definidos, deixando o restante em branco.
27 11x gerar vAA A: registro de exceção (8 bits)
Gera a exceção indicada.
28 10t goto +AA Deslocamento de ramificação assinado A: (8 bits) Saltar incondicionalmente para a instrução indicada.

Observação:O deslocamento de ramificação não pode ser 0. Um loop de spin pode ser construído legalmente com goto/32 ou incluindo um nop como destino antes da ramificação.

29 20t goto/16 +AAAA A: Deslocamento de ramificação assinado (16 bits)
Salta incondicionalmente para a instrução indicada.

Observação:O deslocamento de ramificação não pode ser 0. Um loop de spin pode ser construído legalmente com goto/32 ou incluindo um nop como destino antes da ramificação.

2a 30t goto/32 +AAAAAAAA A: Deslocamento de ramificação assinado (32 bits)
Salta incondicionalmente para a instrução indicada.
2b 31t packed-switch vAA, +BBBBBBBB (com dados complementares conforme especificado abaixo em "Formato packed-switch-payload") Registro A: para teste
B: deslocamento "branch" assinado para a pseudo-instrução de dados da tabela (32 bits)
Salta para uma nova instrução com base no valor no registro fornecido, usando uma tabela de deslocamentos correspondentes a cada valor em um determinado intervalo integral ou pula para a próxima instrução se não houver correspondência.
2c 31t sparse-switch vAA, +BBBBBBBB (com dados complementares conforme especificado abaixo em "Formato sparse-switch-payload") Registro A: para teste
B: deslocamento "branch" assinado para a pseudo-instrução de dados da tabela (32 bits)
Ir para uma nova instrução com base no valor no registro especificado, usando uma tabela ordenada de pares de valor-deslocamento, ou ir para a próxima instrução se não houver correspondência.
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: Primeiro registro ou par de origem
C: Segundo registro ou par de origem
Executa a comparação de ponto flutuante ou long indicada, definindo a como 0 se b == c, 1 se b > c, ou -1 se b < c. O "bias" listado para as operações de ponto flutuante indica como as comparações NaN são tratadas: as instruções "gt bias" retornam 1 para comparações NaN, e as instruções "lt bias" retornam -1.

Por exemplo, para verificar se o ponto flutuante x < y é recomendável usar cmpg-float. Um resultado de -1 indica que o teste foi verdadeiro, e os outros valores indicam que ele foi falso devido a uma comparação válida ou porque um dos valores foi 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: primeiro registro para teste (4 bits)
B: segundo registro para teste (4 bits)
C: deslocamento de ramificação assinado (16 bits)
Faz a ramificação para o destino especificado se os valores dos dois registros forem comparados conforme especificado.

Observação:O deslocamento de ramificação não pode ser 0. Um loop pode ser construído legalmente ramificando em torno de um goto reverso ou incluindo um nop como destino antes da ramificação.

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 teste (8 bits)
Deslocamento de ramificação assinado B: (16 bits)
Faz a ramificação para o destino especificado se o valor do registro for comparável com 0, conforme especificado.

Observação:O deslocamento de ramificação não pode ser 0. Um loop pode ser construído legalmente ramificando em torno de um goto reverso ou incluindo um nop como destino antes da ramificação.

3e..43 10x (não usado)   (não usado)
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 ou par de valor A:; pode ser origem ou destino (8 bits)
Registro de matriz B: (8 bits)
Registro de índice C: (8 bits)
Executa a operação de matriz identificada no índice identificado da matriz especificada, carregando ou armazenando no registro de valor.
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 ou par de valor A:; pode ser origem ou destino (4 bits)
Registro de objeto B: (4 bits)
Índice de referência de campo de instância C: (16 bits)
Executa a operação de campo de instância de objeto identificado com o campo identificado, carregando ou armazenando no registro de valor.

Observação:esses opcodes são candidatos razoáveis para vinculação estática, alterando o argumento de campo para ser um deslocamento mais direto.

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 ou par de valores A:; pode ser origem ou destino (8 bits)
B: índice de referência de campo estático (16 bits)
Executa a operação de campo estático do objeto identificado com o campo estático identificado, carregando ou armazenando no registro de valor.

Observação:esses opcodes são candidatos razoáveis para vinculação estática, alterando o argumento de campo para ser um deslocamento mais direto.

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
Contagem de palavras de argumento A: (4 bits)
Índice de referência de método B: (16 bits)
Registros de argumento C..G: (4 bits cada)
Chame o método indicado. O resultado (se houver) pode ser armazenado com uma variante move-result* adequada como a instrução imediatamente subsequente.

invoke-virtual é usado para invocar um método virtual normal, que é um método que não é static, private ou um contrutor.

Quando o method_id faz referência a um método de uma classe que não é de interface, o invoke-super é usado para invocar o método virtual da superclasse mais próxima (em vez de aquele com o mesmo method_id na classe de chamada). As mesmas restrições de método são válidas para invoke-virtual.

Em arquivos DEX da versão 037 ou mais recente, se o method_id se referir a um método de interface, invoke-super será usado para invocar a versão mais específica não substituída desse método definido nessa interface. As mesmas restrições de método são válidas para invoke-virtual. Em arquivos Dex anteriores à versão 037, ter uma interface method_id é ilegal e indefinido.

invoke-direct é usado para invocar um método direto que não seja static, ou seja, um método de instância que não possa ser substituído por natureza, ou seja, um método de instância private ou um construtor.

invoke-static é usado para invocar um método static, que é sempre considerado um método direto.

invoke-interface é usado para invocar um método interface, ou seja, em um objeto cuja classe concreta não é conhecida, usando um method_id que se refere a um interface.

Observação:esses opcodes são candidatos razoáveis para vinculação estática, alterando o argumento do método para ser um deslocamento mais direto (ou par dele).

73 10x (não usado)   (não usado)
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: contagem de palavras de argumento (8 bits)
B: índice de referência de método (16 bits)
C: registro do primeiro argumento (16 bits)
N = A + C - 1
Chame o método indicado. Consulte a primeira descrição de invoke-kind acima para detalhes, ressalvas e sugestões.
79..7a 10x (não usado)   (não usado)
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 ou par de destino (4 bits)
B: registro ou par de origem (4 bits)
Executar a operação unária identificada no registro de origem, armazenando o resultado no 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
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 ou par de destino (8 bits)
B: primeiro registro ou par de origem (8 bits)
C: segundo registro ou par de origem (8 bits)
Executa a operação binária identificada nos dois registros de origem, armazenando o resultado no registro de destino.

Observação:ao contrário de outras operações matemáticas -long (que usam pares de registros para a primeira e a segunda origem), shl-long, shr-long e ushr-long usam um par de registros para a primeira origem (o valor a ser deslocado), mas um único registro para a segunda origem (a distância de deslocamento).

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: destino e primeiro registro ou par de origem (4 bits)
B: segundo registro ou par de origem (4 bits)
Execute a operação binária identificada nos dois registros de origem, armazenando o resultado no primeiro registro de origem.

Observação:ao contrário de outras operações matemáticas -long/2addr, que usam pares de registros para o destino/primeira fonte e a segunda fonte, shl-long/2addr, shr-long/2addr e ushr-long/2addr usam um par de registros para o destino/primeira fonte (o valor a ser deslocado), mas um único registro para a segunda fonte (a distância de deslocamento).

d0..d7 22s binop/lit16 vA, vB, #+CCCC
d0: add-int/lit16
d1: rsub-int (subtração reversa)
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: registro de destino (4 bits)
B: registro de origem (4 bits)
C: constante de int assinado (16 bits)
Executa a operação binária indicada no registro indicado (primeiro argumento) e no valor literal (segundo argumento), armazenando o resultado no registro de destino.

Observação:rsub-int não tem um sufixo, já que essa versão é o opcode principal da família. Confira abaixo detalhes sobre a 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
A: registro de destino (8 bits)
B: registro de origem (8 bits)
C: constante de int assinada (8 bits)
Executa a operação binária indicada no registro indicado (primeiro argumento) e no valor literal (segundo argumento), armazenando o resultado no registro de destino.

Observação:confira abaixo os detalhes sobre a semântica de rsub-int.

e3..f9 10x (não usado)   (não usado)
fa 45cc invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH A: contagem de palavras de argumento (4 bits)
B: índice de referência de método (16 bits)
C: receptor (4 bits)
D..G: registros de argumento (4 bits cada)
H: índice de referência de protótipo (16 bits)
Invocar o método polimórfico de assinatura indicado. O resultado (se houver) pode ser armazenado com uma variante move-result* adequada como a instrução imediatamente subsequente.

A referência de método precisa ser para um método polimórfico de assinatura, como java.lang.invoke.MethodHandle.invoke ou java.lang.invoke.MethodHandle.invokeExact.

O receptor precisa ser um objeto que ofereça suporte ao método polimórfico de assinatura que está sendo invocado.

A referência do protótipo descreve os tipos de argumentos fornecidos e o tipo de retorno esperado.

O bytecode invoke-polymorphic pode gerar exceções quando é executado. As exceções são descritas na documentação da API para o método polimórfico de assinatura que está sendo invocado.

Presente nos arquivos Dex a partir da versão 038.
fb 4rcc invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: contagem de palavras de argumento (8 bits)
B: índice de referência de método (16 bits)
C: receptor (16 bits)
H: índice de referência de protótipo (16 bits)
N = A + C - 1
Invocar o identificador de método indicado. Consulte a descrição de invoke-polymorphic acima para mais detalhes.

Presente nos arquivos Dex a partir da versão 038.
fc 35c invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB Contagem de palavras de argumento A: (4 bits)
Índice de referência do site de chamada B: (16 bits)
Registros de argumento C..G: (4 bits cada)
Resolve e invoca o site de chamada indicado. O resultado da invocação (se houver) pode ser armazenado com uma variante move-result* adequada como a instrução imediatamente subsequente.

Essa instrução é executada em duas fases: resolução do local de chamada e invocação do local de chamada.

A resolução do site de chamada verifica se o site de chamada indicado tem uma instância java.lang.invoke.CallSite associada. Caso contrário, o método de vinculação de inicialização para o site de chamada indicado será invocado usando argumentos presentes no arquivo DEX (consulte call_site_item). O método de vinculação de inicialização retorna uma instância java.lang.invoke.CallSite que será associada ao site de chamada indicado se nenhuma associação existir. Outra linha de execução pode ter feito a associação primeiro. Se isso acontecer, a execução da instrução continuará com a primeira instância java.lang.invoke.CallSite associada.

A invocação do site de chamada é feita no alvo java.lang.invoke.MethodHandle da instância java.lang.invoke.CallSite resolvida. O destino é invocado como se executando invoke-polymorphic (descrito acima) usando o identificador de método e os argumentos para a instrução invoke-custom como os argumentos para uma invocação exata de identificador de método.

Exceções geradas pelo método de vinculação de inicialização são agrupadas em um java.lang.BootstrapMethodError. Uma BootstrapMethodError também será gerada se:
  • O método de vinculação de inicialização não consegue retornar uma instância de java.lang.invoke.CallSite.
  • O java.lang.invoke.CallSite retornado tem um null como alvo do gerenciador de método.
  • o destino do identificador de método não é do tipo solicitado.
Presente nos arquivos Dex a partir da versão 038.
fd 3rc invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB A: contagem de palavras de argumento (8 bits)
B: índice de referência do site de chamada (16 bits)
C: registro do primeiro argumento (16 bits)
N = A + C - 1
Resolver e invocar um site de chamada. Consulte a descrição de invoke-custom acima para mais detalhes.

Presente nos arquivos Dex a partir da versão 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)
Move uma referência ao identificador de método especificado pelo índice fornecido para o registro especificado.

Presente em arquivos Dex a partir da versão 039.
ff 21c const-method-type vAA, proto@BBBB Registro de destino A: (8 bits)
Referência de protótipo de método B: (16 bits)
Move uma referência ao protótipo do método especificado pelo índice fornecido para o registro especificado.

Presente em arquivos Dex a partir da versão 039.

formato de payload de switch agrupado

Nome Formato Descrição
identificador ushort = 0x0100 identificação de pseudo-operação
size ushort número de entradas na tabela
first_key int primeiro (e menor) valor de caso de alternância
targets int[] lista de size destinos de ramificação relativos. As metas são relativas ao endereço do opcode de alternância, não desta tabela.

Observação:o número total de unidades de código para uma instância dessa tabela é (size * 2) + 4.

formato de payload de switch esparso

Nome Formato Descrição
identificador ushort = 0x0200 identificação de pseudo-operação
size ushort número de entradas na tabela
chaves int[] lista de valores de chave size, classificada de menor para maior
targets int[] lista de destinos de ramificação relativa size, cada um correspondendo ao valor da chave no mesmo índice. As metas são relativas ao endereço do opcode de alternância, não desta tabela.

Observação:o número total de unidades de código para uma instância dessa tabela é (size * 4) + 2.

formato de payload de dados de preenchimento de matriz

Nome Formato Descrição
identificador ushort = 0x0300 identificação de pseudo-operação
element_width ushort número de bytes em cada elemento
size uint número de elementos na tabela
dados ubyte[] valores de dados

Observação:o número total de unidades de código para uma instância dessa tabela é (size * element_width + 1) / 2 + 4.

Detalhes da operação matemática

Observação:as operações de ponto flutuante precisam seguir as regras IEEE 754, usando arredondamento para o valor mais próximo e underflow gradual, exceto quando indicado o contrário.

Código de operação Semântica C Observações
neg-int int32 a;
int32 result = -a;
Complemento unário de dois.
not-int int32 a;
int32 result = ~a;
Complemento unário de 1s.
neg-long int64 a;
int64 result = -a;
Complemento unário de dois.
não-longo int64 a;
int64 result = ~a;
Complemento unário de 1s.
neg-float float a;
float result = -a;
Negação de ponto flutuante.
neg-double double a;
double result = -a;
Negação de ponto flutuante.
int para long int32 a;
int64 result = (int64) a;
Assinatura da extensão de int32 em int64.
int-to-float int32 a;
float result = (float) a;
Conversão de int32 para float, usando a função de arredondamento para o valor mais próximo. Isso perde a precisão de alguns valores.
int-to-double int32 a;
double result = (double) a;
Conversão de int32 para double.
long-to-int int64 a;
int32 result = (int32) a;
Truncamento de int64 em int32.
long-to-float int64 a;
float result = (float) a;
Conversão de int64 para float, usando a função de arredondamento para o valor mais próximo. Isso perde a precisão de alguns valores.
long-to-double int64 a;
double result = (double) a;
Conversão de int64 para double, usando a função de arredondamento para o valor mais próximo. Isso perde a precisão de alguns valores.
float-to-int float a;
int32 result = (int32) a;
Conversão de float para int32, usando a arredondamento para zero. NaN e -0.0 (zero negativo) são convertidos no número inteiro 0. Infinitos e valores com magnitude muito grande para serem representados são convertidos em 0x7fffffff ou -0x80000000, dependendo do sinal.
float-to-long float a;
int64 result = (int64) a;
Conversão de float para int64, usando a arredondamento para zero. As mesmas regras de caso especial de float-to-int se aplicam aqui, exceto que os valores fora do intervalo são convertidos em 0x7fffffffffffffff ou -0x8000000000000000, dependendo do sinal.
float-to-double float a;
double result = (double) a;
Conversão de float para double, preservando exatamente o valor.
double-to-int double a;
int32 result = (int32) a;
Conversão de double para int32, usando a arredondamento para zero. As mesmas regras de caso especial de float-to-int se aplicam aqui.
double-to-long double a;
int64 result = (int64) a;
Conversão de double para int64, usando a arredondamento para zero. As mesmas regras de caso especial de float-to-long se aplicam aqui.
double-to-float double a;
float result = (float) a;
Conversão de double para float, usando a função de arredondamento para o número mais próximo. Isso perde a precisão de alguns valores.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
O truncamento de int32 para int8, sinal que estende o resultado.
int-to-char int32 a;
int32 result = a & 0xffff;
O truncamento de int32 para uint16, sem extensão de sinal.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
O truncamento de int32 para int16, sinal que estende o resultado.
add-int int32 a, b;
int32 result = a + b;
Adição de complemento de dois.
sub-int int32 a, b;
int32 result = a - b;
Subtração de complemento de dois.
rsub-int int32 a, b;
int32 result = b - a;
Subtração reversa de complemento a dois.
mul-int int32 a, b;
int32 result = a * b;
Multiplicação de complemento a dois.
div-int int32 a, b;
int32 result = a / b;
Divisão de complemento a dois, arredondada para zero (ou seja, truncada para número inteiro). Isso gera ArithmeticException se b == 0.
rem-int int32 a, b;
int32 result = a % b;
Resto de complemento de dois após a divisão. O sinal do resultado é o mesmo de a e é definido com mais precisão como result == a - (a / b) * b. Isso gera ArithmeticException se b == 0.
and-int int32 a, b;
int32 result = a & b;
E bit a bit.
or-int int32 a, b;
int32 result = a | b;
OU bit a bit.
xor-int int32 a, b;
int32 result = a ^ b;
XOR bit a bit.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Deslocamento bit a bit para a esquerda (com argumento mascarado).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Deslocamento para a direita com sinal bit a bit (com argumento mascarado).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Deslocamento para a direita sem sinal bit a bit (com argumento mascarado).
add-long int64 a, b;
int64 result = a + b;
Adição de complemento de dois.
sub-long int64 a, b;
int64 result = a - b;
Subtração de complemento de dois.
mul-long int64 a, b;
int64 result = a * b;
Multiplicação de complemento a dois.
div-long int64 a, b;
int64 result = a / b;
Divisão de complemento a dois, arredondada para zero (ou seja, truncada para número inteiro). Isso gera ArithmeticException se b == 0.
rem-long int64 a, b;
int64 result = a % b;
Resto de complemento de dois após a divisão. O sinal do resultado é o mesmo de a e é definido com mais precisão como result == a - (a / b) * b. Isso gera ArithmeticException se b == 0.
and-long int64 a, b;
int64 result = a & b;
E bit a bit.
or-long int64 a, b;
int64 result = a | b;
OU bit a bit.
xor-long int64 a, b;
int64 result = a ^ b;
XOR bit a bit.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Deslocar para a esquerda bit a bit (com argumento mascarado).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Deslocamento para a direita com sinal bit a bit (com argumento mascarado).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Deslocamento para a direita sem sinal bit a bit (com argumento mascarado).
add-float float a, b;
float result = a + b;
Adição de ponto flutuante.
sub-float float a, b;
float result = a - b;
Subtração de ponto flutuante.
mul-float float a, b;
float result = a * b;
Multiplicação de ponto flutuante.
div-float float a, b;
float result = a / b;
Divisão de ponto flutuante.
rem-float float a, b;
float result = a % b;
Resto de ponto flutuante após a divisão. Essa função é diferente do restante IEEE 754 e é definida como result == a - roundTowardZero(a / b) * b.
add-double double a, b;
double result = a + b;
Adição de ponto flutuante.
sub-dupla double a, b;
double result = a - b;
Subtração de ponto flutuante.
mul-double double a, b;
double result = a * b;
Multiplicação de ponto flutuante.
div-double double a, b;
double result = a / b;
Divisão de ponto flutuante.
rem-double double a, b;
double result = a % b;
Resto de ponto flutuante após a divisão. Essa função é diferente do restante IEEE 754 e é definida como result == a - roundTowardZero(a / b) * b.