Formato de bytecode Dalvik

Projeto geral

  • O modelo da máquina e as convenções de chamada destinam-se a imitar aproximadamente arquiteturas reais comuns e convenções de chamada no estilo C:
    • A máquina é baseada em registro e os quadros têm tamanho fixo no momento da criação. Cada quadro consiste em um determinado número de registros (especificados pelo método), bem como quaisquer dados auxiliares necessários para executar o método, como (mas não limitado a) o contador do programa e uma referência ao arquivo .dex que contém o método .
    • Quando usados ​​para valores de bits (como inteiros e números de ponto flutuante), os registradores são considerados com largura de 32 bits. Pares de registros adjacentes são usados ​​para valores de 64 bits. Não há nenhum requisito de alinhamento para pares de registros.
    • Quando usados ​​para referências de objetos, os registradores são considerados amplos o suficiente para conter exatamente uma dessas referências.
    • Em termos de representação bit a bit, (Object) null == (int) 0 .
    • Os N argumentos para um método chegam aos últimos N registros do quadro de invocação do método, em ordem. Argumentos amplos consomem dois registros. Os métodos de instância recebem this referência como seu 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/devem ser zero.
  • As instruções não são limitadas gratuitamente a um tipo específico. Por exemplo, instruções que movem valores de registradores de 32 bits sem interpretação não precisam especificar se estão movendo ints ou floats.
  • Existem conjuntos de constantes enumerados e indexados separadamente para referências a strings, tipos, campos e métodos.
  • Os dados literais bit a bit são representados em linha no fluxo de instruções.
  • Como, na prática, é incomum que um método precise de mais de 16 registradores, e como a necessidade de mais de oito registradores é razoavelmente comum, muitas instruções são limitadas a abordar apenas os primeiros 16 registradores. Quando razoavelmente possível, as instruções permitem referências aos 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 de move abrangentes que podem endereçar registros no intervalo v0v65535 . Nos casos em que uma variante de instrução não está disponível para endereçar um registrador desejado, espera-se que o conteúdo do registrador seja movido do registrador original para um registrador baixo (antes da operação) e/ou movido de um registrador de resultado baixo para um registrador alto. registrar (após a operação).
  • Existem várias "pseudo-instruções" usadas para armazenar cargas úteis de dados de comprimento variável, que são referidas por instruções regulares (por exemplo, fill-array-data ). Tais instruções nunca devem ser encontradas durante o fluxo normal de execução. Além disso, as instruções devem estar localizadas em deslocamentos de bytecode pares (ou seja, alinhados em 4 bytes). Para atender a esse requisito, as ferramentas de geração dex devem emitir uma instrução nop extra como espaçador, caso tal instrução fique desalinhada. Finalmente, embora não seja obrigatório, espera-se que a maioria das ferramentas opte por emitir essas instruções no final dos métodos, caso contrário, provavelmente seriam necessárias instruções adicionais para diversificá-las.
  • Quando instaladas em um sistema em execução, algumas instruções podem ser alteradas, alterando seu formato, como uma otimização de link estático no momento da instalação. Isso permite uma execução mais rápida quando a ligação for conhecida. Consulte o documento de formatos de instruções associados para as variantes sugeridas. A palavra “sugerido” é usada deliberadamente; não é obrigatório implementá-los.
  • Sintaxe humana e mnemônicos:
    • Ordenação destino-então-fonte para argumentos.
    • Alguns opcodes têm um sufixo de nome desambiguante para indicar o(s) tipo(s) em que operam:
      • Os opcodes de tipo geral de 32 bits não estão marcados.
      • Os códigos de operação gerais de 64 bits têm o sufixo -wide .
      • Os opcodes específicos do tipo são sufixados com seu tipo (ou uma abreviatura direta), um dos seguintes: -boolean -byte -char -short -int -long -float -double -object -string -class -void .
    • Alguns opcodes têm um sufixo de desambiguação para distinguir operações idênticas que possuem diferentes layouts ou opções de instruções. Esses sufixos são separados dos nomes principais por uma barra (" / ") e existem principalmente para fazer com 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 (indicando, 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 registrador).
      • " wide " é o sufixo do nome, indicando que ele opera em dados amplos (64 bits).
      • " from16 " é o sufixo do opcode, indicando uma variante que possui uma referência de registro de 16 bits como origem.
      • " vAA " é o registrador de destino (implícito na operação; novamente, a regra é que os argumentos de destino sempre vêm primeiro), que deve estar no intervalo v0v255 .
      • " vBBBB " é o registro fonte, que deve estar no intervalo v0v65535 .
  • Consulte o documento de formatos de instruções para obter mais detalhes sobre os vários formatos de instruções (listados em "Op & Format"), bem como detalhes sobre a sintaxe do opcode.
  • Consulte o documento de formato de arquivo .dex para obter mais detalhes sobre onde o bytecode se encaixa no quadro geral.

Resumo do conjunto de bytes

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

Nota: Pseudo-instruções contendo dados são marcadas com este opcode, caso em que o byte de ordem superior da unidade do opcode indica a natureza dos dados. Consulte "formato packed-switch-payload ", "formato sparse-switch-payload " e "formato fill-array-data-payload " abaixo.

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

Nota: É legal passar de v N para v N-1 ou v N+1 , portanto as implementações devem providenciar que ambas as metades de um par de registradores sejam lidas antes que qualquer coisa seja escrita.

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

Nota: As considerações de implementação são as mesmas do move-wide acima.

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

Nota: As considerações de implementação são as mesmas do move-wide acima.

07 12x mover objeto vA, vB A: registro de destino (4 bits)
B: registro de origem (4 bits)
Mova o conteúdo de um registro portador de objeto para outro.
08 22x mover-objeto/from16 vAA, vBBBB A: registro de destino (8 bits)
B: registro de origem (16 bits)
Mova o conteúdo de um registro portador de objeto para outro.
09 32x mover-objeto/16 vAAAA, vBBBB A: registro de destino (16 bits)
B: registro de origem (16 bits)
Mova o conteúdo de um registro portador de objeto para outro.
0a 11x resultado da movimentação vAA A: registro de destino (8 bits) Mova o resultado não-objeto de palavra única do invoke- kind mais recente para o registro indicado. Isso deve ser feito como a instrução imediatamente após uma invoke- kind cujo resultado (palavra única, não-objeto) não deve ser ignorado; em qualquer outro lugar é inválido.
0b 11x vAA para todo o resultado da movimentação A: par de registradores de destino (8 bits) Mova o resultado da palavra dupla do invoke- kind mais recente para o par de registradores indicado. Isso deve ser feito como a instrução imediatamente após um invoke- kind cujo resultado (palavra dupla) não deve ser ignorado; em qualquer outro lugar é inválido.
0c 11x mover-objeto de resultado vAA A: registro de destino (8 bits) Mova o resultado do objeto do invoke- kind mais recente para o registro indicado. Isso deve ser feito como a instrução imediatamente após um invoke- kind ou filled-new-array cujo resultado (objeto) não deve ser ignorado; em qualquer outro lugar é inválido.
0d 11x exceção de movimento vAA A: registro de destino (8 bits) Salve uma exceção recém-capturada no registro fornecido. Esta deve ser a primeira instrução de qualquer manipulador de exceção cuja exceção capturada não deve ser ignorada, e esta instrução deve ocorrer como a primeira instrução de um manipulador de exceção; em qualquer outro lugar é inválido.
0e 10x retorno vazio Retornar de um método void .
0f 11x retornar vAA A: registrador de valor de retorno (8 bits) Retornar de um método de retorno de valor sem objeto de largura única (32 bits).
10 11x vAA para todo o retorno A: par de registradores de valor de retorno (8 bits) Retornar de um método de retorno de valor de largura dupla (64 bits).
11 11x objeto de retorno vAA A: registrador de valor de retorno (8 bits) Retornar de um método de retorno de objeto.
12 11n const/4 vA, #+B A: registro de destino (4 bits)
B: int assinado (4 bits)
Mova o valor literal fornecido (com sinal estendido para 32 bits) para o registro especificado.
13 21s const/16 vAA, #+BBB A: registro de destino (8 bits)
B: int assinado (16 bits)
Mova o valor literal fornecido (com sinal estendido para 32 bits) para o registro especificado.
14 31i const vAA, #+BBBBBBB A: registro de destino (8 bits)
B: constante arbitrária de 32 bits
Mova o valor literal fornecido para o registro especificado.
15 21h const/alta16 vAA, #+BBBB0000 A: registro de destino (8 bits)
B: int assinado (16 bits)
Mova o valor literal fornecido (zero à direita estendido para 32 bits) para o registro especificado.
16 21s largura const/16 vAA, #+BBBB A: registro de destino (8 bits)
B: int assinado (16 bits)
Mova o valor literal fornecido (sinal estendido para 64 bits) para o par de registros especificado.
17 31i largura const/32 vAA, #+BBBBBBBB A: registro de destino (8 bits)
B: int assinado (32 bits)
Mova o valor literal fornecido (sinal estendido para 64 bits) para o par de registros especificado.
18 51l vAA em toda a const, #+BBBBBBBBBBBBBB A: registro de destino (8 bits)
B: constante arbitrária de largura dupla (64 bits)
Mova o valor literal fornecido para o par de registros especificado.
19 21h const-amplo/alto16 vAA, #+BBBB000000000000 A: registro de destino (8 bits)
B: int assinado (16 bits)
Mova o valor literal fornecido (zero à direita estendido para 64 bits) para o par de registros especificado.
1a 21c const-string vAA, string@BBBB A: registro de destino (8 bits)
B: índice de string
Mova uma referência à string especificada pelo índice fornecido para o registro especificado.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: registro de destino (8 bits)
B: índice de string
Mova uma referência à string especificada pelo índice fornecido para o registro especificado.
1c 21c classe const vAA, tipo@BBBB A: registro de destino (8 bits)
B: índice de tipo
Mova uma referência à classe especificada pelo índice fornecido para o registro especificado. No caso em que o tipo indicado é primitivo, armazenará uma referência à classe degenerada do tipo primitivo.
1d 11x monitor-entrada vAA A: registro de referência (8 bits) Adquira o monitor para o objeto indicado.
1e 11x saída do monitor vAA A: registro de referência (8 bits) Solte o monitor para o objeto indicado.

Nota: Se esta instrução precisar lançar uma exceção, ela deverá fazê-lo como se o pc já tivesse avançado além da instrução. Pode ser útil pensar nisso como a instrução sendo executada com sucesso (em certo sentido), e a exceção sendo lançada após a instrução, mas antes que a próxima tenha a chance de ser executada. Esta definição torna possível que um método use um bloco pega-tudo de limpeza de monitor (por exemplo, finally ) como a limpeza de monitor para esse bloco em si, como uma forma de lidar com as exceções arbitrárias que podem ser lançadas devido à implementação histórica de Thread.stop() , ao mesmo tempo em que consegue manter a higiene adequada do monitor.

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

Nota: Como A sempre deve ser uma referência (e não um valor primitivo), isso necessariamente falhará em tempo de execução (ou seja, lançará uma exceção) se B se referir a um tipo primitivo.

20 22c instância de vA, vB, tipo@CCCC A: registro de destino (4 bits)
B: registro de referência (4 bits)
C: índice de tipo (16 bits)
Armazene no registrador de destino fornecido 1 se a referência indicada for uma instância do tipo determinado, ou 0 se não for.

Nota: Como B deve sempre ser uma referência (e não um valor primitivo), isso sempre resultará no armazenamento de 0 se C se referir a um tipo primitivo.

21 12x comprimento da matriz vA, vB A: registro de destino (4 bits)
B: registro de referência de matriz (4 bits)
Armazene no registrador de destino fornecido o comprimento do array indicado, em entradas
22 21c nova instância vAA, digite@BBBB A: registro de destino (8 bits)
B: índice de tipo
Construa uma nova instância do tipo indicado, armazenando uma referência a ela no destino. O tipo deve se referir a uma classe que não seja de array.
23 22c nova matriz vA, vB, tipo@CCCC A: registro de destino (4 bits)
B: registro de tamanho
C: índice de tipo
Construa uma nova matriz do tipo e tamanho indicados. O tipo deve ser um tipo de matriz.
24 35c nova matriz preenchida {vC, vD, vE, vF, vG}, tipo@BBBB A: tamanho do array e contagem de palavras de argumento (4 bits)
B: índice de tipo (16 bits)
C..G: registradores de argumentos (4 bits cada)
Construa um array de determinado tipo e tamanho, preenchendo-o com o conteúdo fornecido. O tipo deve ser um tipo de matriz. O conteúdo do array deve ser de palavra única (ou seja, nenhum array de long ou double , mas tipos de referência são aceitáveis). A instância construída é armazenada como um "resultado" da mesma forma que as instruções de invocação de método armazenam seus resultados, portanto a instância construída deve ser movida para um registro com uma instrução move-result-object imediatamente subsequente (se for usada ).
25 3rc nova matriz/intervalo preenchido {vCCCC .. vNNNN}, digite@BBBB A: tamanho do array e contagem de palavras de argumento (8 bits)
B: índice de tipo (16 bits)
C: registro do primeiro argumento (16 bits)
N = A + C - 1
Construa um array de determinado tipo e tamanho, preenchendo-o com o conteúdo fornecido. Esclarecimentos e restrições são iguais aos de filled-new-array , descritos acima.
26 31t fill-array-data vAA, +BBBBBBBB (com dados suplementares conforme especificado abaixo em "formato fill-array-data-payload ") A: referência de array (8 bits)
B: deslocamento de "ramificação" assinado para pseudo-instrução de dados da tabela (32 bits)
Preencha o array fornecido com os dados indicados. A referência deve ser a um array de primitivos, e a tabela de dados deve corresponder ao tipo e não deve conter mais elementos do que cabem no array. Ou seja, o array pode ser maior que a tabela e, nesse caso, apenas os elementos iniciais do array são definidos, deixando o restante em paz.
27 11x lançar vAA A: registro portador de exceção (8 bits)
Lance a exceção indicada.
28 10t ir para +AA A: deslocamento de ramificação assinada (8 bits) Salte incondicionalmente para a instrução indicada.

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

29 20t ir para/16 +AAAA A: deslocamento de ramificação assinada (16 bits)
Salte incondicionalmente para a instrução indicada.

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

2h30 ir para/32 +AAAAAAAA A: deslocamento de ramificação assinada (32 bits)
Salte incondicionalmente para a instrução indicada.
2b 31t pack-switch vAA, +BBBBBBBB (com dados suplementares conforme especificado abaixo em "formato packed-switch-payload ") A: registre-se para testar
B: deslocamento de "ramificação" assinado para pseudo-instrução de dados da tabela (32 bits)
Salte para uma nova instrução com base no valor no registro fornecido, usando uma tabela de deslocamentos correspondentes a cada valor em um intervalo integral específico, ou passe para a próxima instrução se não houver correspondência.
2c 31t sparse-switch vAA, +BBBBBBBB (com dados suplementares conforme especificado abaixo em "formato sparse-switch-payload ") A: registre-se para testar
B: deslocamento de "ramificação" assinado para pseudo-instrução de dados da tabela (32 bits)
Pule para uma nova instrução com base no valor no registro fornecido, usando uma tabela ordenada de pares valor-deslocamento, ou passe para a próxima instrução se não houver correspondência.
2d..31 23x cmp tipo vAA, vBB, vCC
2d: cmpl-float (viés lt)
2e: cmpg-float (viés gt)
2f: cmpl-double (tendência lt)
30: cmpg-double (viés gt)
31: cmp de comprimento
A: registro de destino (8 bits)
B: primeiro registro ou par de fonte
C: segundo registro ou par de fonte
Execute o ponto flutuante indicado ou comparação long , definindo a como 0 se b == c , 1 se b > c ou -1 se b < c . O "viés" listado para as operações de ponto flutuante indica como as comparações NaN são tratadas: as instruções "gt polarização" retornam 1 para comparações NaN e as instruções "lt polarização" retornam -1 .

Por exemplo, para verificar se o ponto flutuante x < y é aconselhável usar cmpg-float ; um resultado -1 indica que o teste foi verdadeiro e os outros valores indicam que foi falso devido a uma comparação válida ou porque um dos valores era NaN .

32..37 22t se- teste vA, vB, +CCCC
32: se-eq
33: se não
34: se-lt
35: se-ge
36: se-gt
37: se-le
A: primeiro registro a testar (4 bits)
B: segundo registro para testar (4 bits)
C: deslocamento de ramificação assinada (16 bits)
Ramifique para o destino fornecido se os valores dos dois registros fornecidos forem comparados conforme especificado.

Nota: O deslocamento da ramificação não deve ser 0 . (Um loop de spin pode ser legalmente construído ramificando-se em torno de um goto para trás ou incluindo um nop como alvo antes da ramificação.)

38..3d 21t se- teste z vAA, +BBBB
38: se-eqz
39: if-nez
3a: se-ltz
3b: se-gez
3c: se-gtz
3d: if-lez
A: registre-se para testar (8 bits)
B: deslocamento de ramificação assinada (16 bits)
Ramifique para o destino fornecido se o valor do registro fornecido for comparado com 0 conforme especificado.

Nota: O deslocamento da ramificação não deve ser 0 . (Um loop de spin pode ser legalmente construído ramificando-se em torno de um goto para trás ou incluindo um nop como alvo antes da ramificação.)

3e..43 10x (não utilizado) (não utilizado)
44..51 23x arrayop vAA, vBB, vCC
44: idade
45: toda a idade
46: objeto-aget
47: age-booleano
48: age-byte
49: idade-char
4a: falta de idade
4b: colocar
4c: largura de entrada
4d: objeto aput
4e: aput-booleano
4f: byte de entrada
50: aput-char
51: aput-curto
A: registrador ou par de valores; pode ser origem ou destino (8 bits)
B: registrador de matriz (8 bits)
C: registrador de índice (8 bits)
Execute a operação do array identificado no índice identificado do array fornecido, carregando ou armazenando no registrador de valor.
52..5f 22c eu instânciaop vA, vB, campo@CCCC
52: iget
53: iget-largo
54: objeto iget
55: iget-booleano
56: iget byte
57: iget-char
58: iget-curto
59: eu coloco
5a: todo o iput
5b: objeto iput
5c: iput-booleano
5d: byte de entrada
5e: iput-char
5f: iput-curto
A: registrador ou par de valores; pode ser origem ou destino (4 bits)
B: registro de objeto (4 bits)
C: índice de referência de campo de instância (16 bits)
Execute a operação de campo da instância do objeto identificado com o campo identificado, carregando ou armazenando no registrador de valor.

Nota: Esses opcodes são candidatos razoáveis ​​para vinculação estática, alterando o argumento do campo para ser um deslocamento mais direto.

60..6d 21c s staticop vAA, campo@BBBB
60: chegar
61: todo o espaço
62: objeto sget
63: sget-booleano
64: sget-byte
65: sget-char
66: sget-curto
67: cuspir
68: todo o espectro
69: objeto sput
6a: sput-booleano
6b: byte de saída
6c: caractere de saída
6d: cuspido curto
A: registrador ou par de valores; pode ser origem ou destino (8 bits)
B: índice de referência de campo estático (16 bits)
Execute a operação do campo estático do objeto identificado com o campo estático identificado, carregando ou armazenando no registrador de valor.

Nota: Esses opcodes são candidatos razoáveis ​​para vinculação estática, alterando o argumento do campo para ser um deslocamento mais direto.

6e..72 35c invocar- tipo {vC, vD, vE, vF, vG}, meth@BBBB
6e: invocar-virtual
6f: invocar-super
70: invocar direto
71: invocar-estático
72: interface de invocação
A: contagem de palavras de argumento (4 bits)
B: índice de referência do método (16 bits)
C..G: registradores de argumentos (4 bits cada)
Chame o método indicado. O resultado (se houver) pode ser armazenado com uma variante move-result* apropriada como a instrução imediatamente subsequente.

invoke-virtual é usado para invocar um método virtual normal (um método que não é private , static ou final e também não é um construtor).

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

Nos arquivos Dex versão 037 ou posterior, se o method_id se referir a um método de interface, invoke-super será usado para invocar a versão mais específica e 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 não static (ou seja, um método de instância que é, por natureza, não substituível, 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 uma interface .

Nota: 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 deles).

73 10x (não utilizado) (não utilizado)
74..78 3rc invocar- tipo / intervalo {vCCCC .. vNNNN}, meth@BBBB
74: invocar-virtual/intervalo
75: invocar-super/intervalo
76: invocar direto/intervalo
77: invocar-estático/intervalo
78: interface de invocação/intervalo
A: contagem de palavras de argumento (8 bits)
B: índice de referência do método (16 bits)
C: registro do primeiro argumento (16 bits)
N = A + C - 1
Chame o método indicado. Veja a primeira descrição invoke- kind acima para obter detalhes, advertências e sugestões.
79..7a 10x (não utilizado) (não utilizado)
7b..8f 12x unop vA, vB
7b: neg-int
7c: não-int
7d: neg-longo
7e: não muito tempo
7f: neg-float
80: negativo-duplo
81: inteiro para longo
82: int para float
83: int-para-duplo
84: longo para int
85: longo para flutuar
86: longo para dobrar
87: float para int
88: flutuante para longo
89: float para duplo
8a: duplo para int
8b: duplo para longo
8c: duplo para flutuar
8d: int para byte
8e: int-to-char
8f: int-para-curto
A: registro ou par de destino (4 bits)
B: registro ou par de origem (4 bits)
Execute a operação unária identificada no registrador de origem, armazenando o resultado no registrador de destino.
90..af 23x binop vAA, vBB, vCC
90: suplemento
91: sub-int
92: mul-int
93: div-int
94: rem-int
95: e-int
96: ou-int
97: xor-int
98: shl-int
99: sh-int
9a: ushr-int
9b: adição longa
9c: sublongo
9d: mul-longo
9e: div-longo
9f: rem-longo
a0: e-longo
a1: ou longo
a2: xor-longo
a3: shl-longo
a4: shr-longo
a5: ushr-longo
a6: adicionar float
a7: subflutuante
a8: mul-float
a9: div-float
aa: rem-float
ab: adição-duplo
ac: sub-duplo
anúncio: mul-duplo
ae: div-duplo
af: rem-duplo
A: registro ou par de destino (8 bits)
B: primeiro registro ou par de origem (8 bits)
C: segundo registro ou par de fonte (8 bits)
Execute a operação binária identificada nos dois registradores de origem, armazenando o resultado no registrador de destino.

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

b0..cf 12x binop /2endereço vA, vB
b0: add-int/2addr
b1: subint/2addr
b2: mul-int/2addr
b3: div-int/2addr
b4: rem-int/2addr
b5: e-int/2addr
b6: ou-int/2addr
b7: xor-int/2addr
b8: shl-int/2addr
b9: shr-int/2addr
ba: ushr-int/2addr
bb: add-long/2addr
bc: sub-longo/2addr
bd: mul-long/2addr
ser: div-long/2addr
bf: rem-long/2addr
c0: e-longo/2addr
c1: ou-longo/2addr
c2: xor-long/2addr
c3: shl-longo/2addr
c4: shr-longo/2addr
c5: ushr-long/2addr
c6: adicionar-float/2addr
c7: subfloat/2addr
c8: mul-float/2addr
c9: div-float/2addr
ca: rem-float/2addr
cb: adicionar-duplo/2addr
cc: subduplo/2addr
cd: mul-duplo/2addr
ce: div-double/2addr
cf: rem-duplo/2addr
A: destino e primeiro registrador ou par de origem (4 bits)
B: segundo registro ou par de fonte (4 bits)
Execute a operação binária identificada nos dois registradores fonte, armazenando o resultado no primeiro registrador fonte.

Nota: Ao contrário de outras operações matemáticas -long/2addr (que usam pares de registros para seu destino/primeira fonte e sua segunda fonte), shl-long/2addr , shr-long/2addr e ushr-long/2addr usam um registro par para seu destino/primeira fonte (o valor a ser deslocado), mas um único registro para sua 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: e-int/lit16
d6: ou-int/lit16
d7: xor-int/lit16
A: registro de destino (4 bits)
B: registro de origem (4 bits)
C: constante int assinada (16 bits)
Execute a operação binária indicada no registrador indicado (primeiro argumento) e no valor literal (segundo argumento), armazenando o resultado no registrador de destino.

Nota: rsub-int não possui sufixo, pois esta versão é o principal opcode de sua família. Além disso, veja abaixo detalhes sobre sua semântica.

d8..e2 22b binop /lit8 vAA, vBB, #+CC
d8: add-int/lit8
d9: rsub-int/lit8
da: mul-int/lit8
banco de dados: 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 int assinada (8 bits)
Execute a operação binária indicada no registrador indicado (primeiro argumento) e no valor literal (segundo argumento), armazenando o resultado no registrador de destino.

Nota: Veja abaixo detalhes sobre a semântica de rsub-int .

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

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

O receptor deve ser um objeto que suporte o 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 estão descritas na documentação da API para o método polimórfico de assinatura que está sendo invocado.

Presente em arquivos Dex a partir da versão 038 .
fb4rcc invocar-polimórfico/intervalo {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH A: contagem de palavras de argumento (8 bits)
B: índice de referência do método (16 bits)
C: receptor (16 bits)
H: índice de referência do protótipo (16 bits)
N = A + C - 1
Invoque o identificador do método indicado. Veja a descrição invoke-polymorphic acima para obter detalhes.

Presente em arquivos Dex a partir da versão 038 .
FC 35c invocar-custom {vC, vD, vE, vF, vG}, call_site@BBBB A: contagem de palavras de argumento (4 bits)
B: índice de referência do site de chamada (16 bits)
C..G: registradores de argumentos (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* apropriada como a instrução imediatamente subsequente.

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

A resolução do site de chamada verifica se o site de chamada indicado possui uma instância java.lang.invoke.CallSite associada. Caso contrário, o método do vinculador bootstrap para o site de chamada indicado é invocado usando argumentos presentes no arquivo DEX (consulte call_site_item ). O método do vinculador bootstrap retorna uma instância java.lang.invoke.CallSite que será então associada ao site de chamada indicado se nenhuma associação existir. Outro encadeamento pode já ter feito a associação primeiro e, nesse caso, a execução da instrução continua com a primeira instância java.lang.invoke.CallSite associada.

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

As exceções levantadas pelo método do vinculador de bootstrap são agrupadas em java.lang.BootstrapMethodError . Um BootstrapMethodError também será gerado se:
  • o método do vinculador de bootstrap não retorna uma instância java.lang.invoke.CallSite .
  • o java.lang.invoke.CallSite retornado tem um destino de identificador de método null .
  • o destino do identificador do método não é do tipo solicitado.
Presente em arquivos Dex a partir da versão 038 .
fd3rc invocar-custom/intervalo {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
Resolva e invoque um site de chamada. Consulte a descrição invoke-custom acima para obter detalhes.

Presente em arquivos Dex a partir da versão 038 .
fe 21c const-method-handle vAA, method_handle@BBBB A: registro de destino (8 bits)
B: índice de identificador de método (16 bits)
Mova 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 tipo de método const vAA, proto@BBBB A: registro de destino (8 bits)
B: referência de protótipo de método (16 bits)
Mova 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 carga útil de switch compactado

Nome Formatar Descrição
identificar ucurto = 0x0100 identificando pseudo-opcode
tamanho ucurto número de entradas na tabela
primeira_chave interno primeiro (e mais baixo) valor do switch case
alvos interno[] lista de alvos de ramificação relativa size . Os alvos são relativos ao endereço do opcode do switch, não desta tabela.

Nota: O número total de unidades de código para uma instância desta tabela é (size * 2) + 4 .

formato de carga útil de switch esparso

Nome Formatar Descrição
identificar ucurto = 0x0200 identificando pseudo-opcode
tamanho ucurto número de entradas na tabela
chaves interno[] lista de valores-chave size , classificados de menor para maior
alvos interno[] lista de alvos de ramificação relativos size , cada um correspondendo ao valor-chave no mesmo índice. Os alvos são relativos ao endereço do opcode do switch, não desta tabela.

Nota: O número total de unidades de código para uma instância desta tabela é (size * 4) + 2 .

formato de carga útil de dados de matriz de preenchimento

Nome Formatar Descrição
identificar ucurto = 0x0300 identificando pseudo-opcode
largura_do_elemento ucurto número de bytes em cada elemento
tamanho unint número de elementos na tabela
dados ubyte[] valores de dados

Nota: O número total de unidades de código para uma instância desta tabela é (size * element_width + 1) / 2 + 4 .

Detalhes da operação matemática

Nota: As operações de ponto flutuante devem seguir as regras IEEE 754, usando underflow arredondado para mais próximo e gradual, exceto quando indicado de outra forma.

Código de operação Semântica C Notas
neg-int int32a;
resultado int32 = -a;
Complemento unário de dois.
não-int int32a;
resultado int32 = ~a;
Unário-complemento.
neg-longo int64a;
resultado int64 = -a;
Complemento unário de dois.
não muito int64a;
resultado int64 = ~a;
Unário-complemento.
neg-float flutuar um;
resultado flutuante = -a;
Negação de ponto flutuante.
negativo-duplo duplo a;
resultado duplo = -a;
Negação de ponto flutuante.
INT-LONG int32 a;
INT64 resultado = (int64) a;
Extensão de sinal de int32 em int64 .
INT para flutuar int32 a;
resultado flutuante = (flutuação) a;
Conversão de int32 para float , usando redondo para o mais. Isso perde precisão para alguns valores.
int-duplo int32 a;
resultado duplo = (duplo) a;
Conversão de int32 para double .
longo a inseguro int64 a;
INT32 resultado = (int32) a;
Truncamento de int64 em int32 .
longo a flutuar int64 a;
resultado flutuante = (flutuação) a;
Conversão de int64 para float , usando redondo para o mais. Isso perde precisão para alguns valores.
longo, duplo int64 a;
resultado duplo = (duplo) a;
Conversão de int64 para double , usando arredondamento para o mais. Isso perde precisão para alguns valores.
Float-to-Int flutuar a;
INT32 resultado = (int32) a;
Conversão de float para int32 , usando rodovias-zero. NaN e -0.0 (zero negativo) se convertem para o número inteiro 0 . Infinidades e valores com uma magnitude muito grande a serem representados são convertidos em 0x7fffffff ou -0x80000000 , dependendo do sinal.
flutuar a longo flutuar a;
INT64 resultado = (int64) a;
Conversão de float para int64 , usando zero-galo-zero. As mesmas regras de caso especiais que, para float-to-int se aplicam aqui, exceto que os valores fora da faixa são convertidos em 0x7fffffffffffffff ou -0x8000000000000000 , dependendo da sinal.
Float-to-Double flutuar a;
resultado duplo = (duplo) a;
Conversão de float para double , preservando exatamente o valor.
duplo para intimidar duplo a;
INT32 resultado = (int32) a;
Conversão de double em int32 , usando rodovias-zero. As mesmas regras de caso especiais que, para float-to-int se aplicam aqui.
duplo a longo duplo a;
INT64 resultado = (int64) a;
Conversão de double em int64 , usando rodovias-zero. As mesmas regras de caso especiais que para float-to-long se aplicam aqui.
duplo a flutuar duplo a;
resultado flutuante = (flutuação) a;
Conversão de double em float , usando redondo para o mais. Isso perde precisão para alguns valores.
int-byte int32 a;
INT32 resultado = (a << 24) >> 24;
Truncamento de int32 a int8 , assinar estendendo o resultado.
INT-TO-CHAR int32 a;
INT32 resultado = a e 0xffff;
Truncamento de int32 a uint16 , sem extensão de sinal.
INT-Para-Short int32 a;
int32 resultado = (a << 16) >> 16;
Truncamento de int32 a int16 , signo estendendo o resultado.
add-int int32 a, b;
INT32 resultado = a + b;
Adição de dois complementos.
Sub-Int int32 a, b;
INT32 resultado = a - b;
Subtração de complemento de dois.
rsub-int int32 a, b;
Int32 resultado = b - a;
Subtração reversa reversa de complemento de dois.
Mul-Int int32 a, b;
INT32 resultado = a * b;
Multiplicação de dois com complementos.
Div-Int int32 a, b;
INT32 resultado = a / b;
Divisão de complemento de dois, arredondados para zero (ou seja, truncado para o número inteiro). Isso lança ArithmeticException se b == 0 .
REM-INT int32 a, b;
INT32 resultado = A % B;
O restante do complemento de dois dois após a divisão. O sinal do resultado é o mesmo que o de a e é mais precisamente definido como result == a - (a / b) * b . Isso lança ArithmeticException se b == 0 .
e-int int32 a, b;
INT32 Result = A & B;
Bit nejudado e.
ou-insa int32 a, b;
INT32 resultado = a | b;
Bit nejudado ou.
XOR-INT int32 a, b;
INT32 resultado = a ^ b;
Bitwise xor.
shl-int int32 a, b;
int32 resultado = a << (b & 0x1f);
Mudança Bitwise para a esquerda (com argumento mascarado).
shr-int int32 a, b;
INT32 resultado = a >> (b & 0x1f);
Bitwise Shift, sinalizado à direita (com argumento mascarado).
ushr-int uint32 a, b;
INT32 resultado = a >> (b & 0x1f);
Mudança não assinada bitwise (com argumento mascarado).
add-longo int64 a, b;
INT64 resultado = a + b;
Adição de dois complementos.
sub-longo int64 a, b;
INT64 resultado = a - b;
Subtração de complemento de dois.
MuL-Long int64 a, b;
INT64 resultado = a * b;
Multiplicação de dois com complementos.
div-long int64 a, b;
INT64 resultado = a / b;
Divisão de complemento de dois, arredondados para zero (ou seja, truncado para o número inteiro). Isso lança ArithmeticException se b == 0 .
Rem-longo int64 a, b;
resultado int64 = a % b;
O restante do complemento de dois dois após a divisão. O sinal do resultado é o mesmo que o de a e é mais precisamente definido como result == a - (a / b) * b . Isso lança ArithmeticException se b == 0 .
e longo int64 a, b;
INT64 resultado = A&B;
Bit nejudado e.
ou longo int64 a, b;
INT64 resultado = a | b;
Bit nejudado ou.
Xor-longo int64 a, b;
INT64 resultado = a ^ b;
Bitwise xor.
shl-longo int64 a;
int32 b;
INT64 resultado = a << (b & 0x3f);
Mudança Bitwise para a esquerda (com argumento mascarado).
short-long int64 a;
int32 b;
INT64 resultado = a >> (b & 0x3f);
Bitwise Shift, sinalizado à direita (com argumento mascarado).
Ushr-Long uint64 a;
int32 b;
INT64 resultado = a >> (b & 0x3f);
Mudança não assinada bitwise (com argumento mascarado).
add-float flutuar a, b;
resultado flutuante = a + b;
Adição de ponto flutuante.
Sub-float flutuar a, b;
resultado flutuante = a - b;
Subtração de ponto flutuante.
mul-fl-float flutuar a, b;
resultado flutuante = a * b;
Multiplicação de ponto flutuante.
div-float flutuar a, b;
resultado flutuante = a / b;
Divisão de ponto flutuante.
REM-FLOAT flutuar a, b;
resultado flutuante = a % b;
Ponto flutuante restante após a divisão. Esta função é diferente do restante do IEEE 754 e é definida como result == a - roundTowardZero(a / b) * b .
add-dupla duplo a, b;
resultado duplo = a + b;
Adição de ponto flutuante.
sub-duplo duplo a, b;
resultado duplo = a - b;
Subtração de ponto flutuante.
Mul-duplo duplo a, b;
resultado duplo = a * b;
Multiplicação de ponto flutuante.
Div-dupla duplo a, b;
resultado duplo = a / b;
Divisão de ponto flutuante.
Rem-duplo duplo a, b;
resultado duplo = a % b;
Ponto flutuante restante após a divisão. Esta função é diferente do restante do IEEE 754 e é definida como result == a - roundTowardZero(a / b) * b .