Código de bytes Dalvik

Projeto geral

  • O modelo de 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 tamanhos dos quadros são fixados na criação. Cada quadro consiste em um número específico de registradores (especificado pelo método), bem como quaisquer dados adjuntos 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 usado para valores de bits (como números inteiros e números de ponto flutuante), os registradores são considerados com 32 bits de largura. Pares de registradores adjacentes são usados ​​para valores de 64 bits. Não há requisito de alinhamento para pares de registradores.
    • 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 aterrissam nos ú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 uma referência this como seu primeiro argumento.
  • A unidade de armazenamento no fluxo de instruções é uma quantidade sem sinal 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 inteiros 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 porque a necessidade de mais de oito registradores é razoavelmente comum, muitas instruções são limitadas a apenas endereçar os primeiros 16 registradores. Quando razoavelmente possível, as instruções permitem referências até os primeiros 256 registradores. Além disso, algumas instruções têm variantes que permitem contagens de registradores muito maiores, incluindo um par de instruções de move catch-all que podem endereçar registradores 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" que são 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 de número par (ou seja, alinhados com 4 bytes). Para atender a esse requisito, as ferramentas de geração dex devem emitir uma instrução nop extra como um espaçador se tal instrução for desalinhada. Finalmente, embora não seja obrigatório, espera-se que a maioria das ferramentas opte por emitir essas instruções nas extremidades dos métodos, pois, caso contrário, provavelmente seriam necessárias instruções adicionais para ramificá-las.
  • Quando instalado em um sistema em execução, algumas instruções podem ser alteradas, alterando seu formato, como uma otimização de link estático em tempo de instalação. Isso é para permitir uma execução mais rápida assim que a ligação for conhecida. Consulte o documento de formatos de instrução associados para as variantes sugeridas. A palavra "sugerido" é usada com cautela; não é obrigatório implementá-los.
  • Sintaxe humana e mnemônicos:
    • Ordenação de dest-then-source 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 são marcados.
      • Os opcodes de tipo geral de 64 bits são sufixados com -wide .
      • Os opcodes específicos de tipo são sufixados com seu tipo (ou uma abreviação 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 de instruções ou opções. Estes sufixos são separados dos nomes principais por uma barra (" / ") e existem principalmente para fazer um mapeamento um-para-um com constantes estáticas no código que gera e interpreta os executáveis ​​(isto é, 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 opera em dados amplos (64 bits).
      • " from16 " é o sufixo opcode, indicando uma variante que tem uma referência de registro de 16 bits como fonte.
      • " vAA " é o registrador de destino (implicado pela operação; novamente, a regra é que os argumentos de destino sempre venham primeiro), que deve estar no intervalo v0v255 .
      • " vBBBB " é o registro de origem, que deve estar no intervalo v0v65535 .
  • Consulte o documento de formatos de instrução para obter mais detalhes sobre os vários formatos de instrução (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 bytecodes

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

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

01 12x mover vA, vB A: registrador de destino (4 bits)
B: registrador de origem (4 bits)
Mova o conteúdo de um registrador não-objeto para outro.
02 22x mover/de16 vAA, vBBBB A: registrador de destino (8 bits)
B: registrador de origem (16 bits)
Mova o conteúdo de um registrador não-objeto para outro.
03 32x mover/16 vAAAA, vBBBB A: registrador de destino (16 bits)
B: registrador de origem (16 bits)
Mova o conteúdo de um registrador 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 registradores para outro.

Nota: É legal mover de v N para v N-1 ou v N+1 , portanto, as implementações devem providenciar para 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 registradores para outro.

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

06 32x movimento amplo/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 registradores para outro.

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

07 12x mover-objeto vA, vB A: registrador de destino (4 bits)
B: registrador de origem (4 bits)
Mova o conteúdo de um registrador portador de objeto para outro.
08 22x move-object/from16 vAA, vBBBB A: registrador de destino (8 bits)
B: registrador de origem (16 bits)
Mova o conteúdo de um registrador portador de objeto para outro.
09 32x move-object/16 vAAAA, vBBBB A: registrador de destino (16 bits)
B: registrador de origem (16 bits)
Mova o conteúdo de um registrador portador de objeto para outro.
0a 11x movimento-resultado vAA A: registrador de destino (8 bits) Mova o resultado não-objeto de palavra única do invoke- kind mais recente para o registrador indicado. Isso deve ser feito como a instrução imediatamente após um invoke- kind cujo resultado (palavra única, não objeto) não deve ser ignorado; qualquer outro lugar é inválido.
0b 11x vAA para todo o resultado do movimento A: par de registradores de destino (8 bits) Mova o resultado de 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; qualquer outro lugar é inválido.
0c 11x mover-resultado-objeto vAA A: registrador de destino (8 bits) Mova o resultado do objeto do invoke- kind mais recente para o registrador 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; qualquer outro lugar é inválido.
0d 11x exceção de movimento vAA A: registrador 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 essa instrução deve ocorrer apenas como a primeira instrução de um manipulador de exceção; qualquer outro lugar é inválido.
0e 10x retorno nulo Retorno de um método void .
0f 11x retornar vAA A: registrador de valor de retorno (8 bits) Retorno de um método de retorno de valor sem objeto de largura única (32 bits).
10 11x vAA de retorno A: valor de retorno par de registradores (8 bits) Retorno 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) Retorno de um método de retorno de objeto.
12 11n const/4vA, #+B A: registrador de destino (4 bits)
B: assinado int (4 bits)
Mova o valor literal fornecido (sinal estendido para 32 bits) no registrador especificado.
13 21s const/16vAA, #+BBBB A: registrador de destino (8 bits)
B: assinado int (16 bits)
Mova o valor literal fornecido (sinal estendido para 32 bits) no registrador especificado.
14 31i const vAA, #+BBBBBBBB A: registrador de destino (8 bits)
B: constante arbitrária de 32 bits
Mova o valor literal fornecido para o registrador especificado.
15 21h const/high16 vAA, #+BBBB0000 A: registrador de destino (8 bits)
B: assinado int (16 bits)
Mova o valor literal fornecido (extensão de zero à direita para 32 bits) no registrador especificado.
16 21s const-wide/16 vAA, #+BBBB A: registrador de destino (8 bits)
B: assinado int (16 bits)
Mova o valor literal fornecido (sinal estendido para 64 bits) no par de registradores especificado.
17 31i const-wide/32 vAA, #+BBBBBBBB A: registrador de destino (8 bits)
B: assinado int (32 bits)
Mova o valor literal fornecido (sinal estendido para 64 bits) no par de registradores especificado.
18 51l vAA const-wide, #+BBBBBBBBBBBBBBBB A: registrador de destino (8 bits)
B: constante arbitrária de largura dupla (64 bits)
Mova o valor literal fornecido para o par de registradores especificado.
19 21h const-wide/high16 vAA, #+BBBB000000000000 A: registrador de destino (8 bits)
B: assinado int (16 bits)
Mova o valor literal fornecido (extensão de zero à direita para 64 bits) para o par de registradores especificado.
1a 21c const-string vAA, string@BBBB A: registrador de destino (8 bits)
B: índice de strings
Mova uma referência à string especificada pelo índice fornecido para o registrador especificado.
1b 31c const-string/jumbo vAA, string@BBBBBBBB A: registrador de destino (8 bits)
B: índice de strings
Mova uma referência à string especificada pelo índice fornecido para o registrador especificado.
1c 21c vAA classe const, digite @BBBB A: registrador de destino (8 bits)
B: índice de tipo
Mova uma referência à classe especificada pelo índice fornecido para o registrador especificado. No caso em que o tipo indicado for primitivo, isso armazenará uma referência à classe degenerada do tipo primitivo.
1d 11x monitor-entrar vAA A: registrador de referência (8 bits) Adquira o monitor para o objeto indicado.
1e 11x monitor-saída vAA A: registrador de referência (8 bits) Solte o monitor para o objeto indicado.

Nota: Se esta instrução precisar lançar uma exceção, deve 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. Essa definição possibilita que um método use um bloco catch-all de limpeza de monitor (por exemplo, finally ) como a limpeza de monitor para esse bloco em si, como uma maneira de lidar com as exceções arbitrárias que podem ser lançadas devido à implementação histórica de Thread.stop() , enquanto ainda consegue manter a higiene adequada do monitor.

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

Nota: Como A deve sempre 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: registrador de destino (4 bits)
B: registrador de referência (4 bits)
C: tipo índice (16 bits)
Armazenar no registrador de destino dado 1 se a referência indicada for uma instância do tipo dado, ou 0 se não for.

Nota: Como B deve ser sempre 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: registrador de destino (4 bits)
B: registro de referência de matriz (4 bits)
Armazenar no registrador de destino dado o comprimento do array indicado, em entradas
22 21c vAA de nova instância, digite@BBBB A: registrador 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 matriz.
23 22c nova matriz vA, vB, tipo@CCCC A: registrador de destino (4 bits)
B: registro de tamanho
C: tipo de índice
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}, digite @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 uma matriz do tipo e tamanho fornecidos, preenchendo-a com o conteúdo fornecido. O tipo deve ser um tipo de matriz. O conteúdo do array deve ser de uma única palavra (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, então a instância construída deve ser movida para um registrador com uma instrução move-result-object imediatamente subsequente (se for usada ).
25 3rc nova matriz/intervalo preenchida {vCCCC .. vNNNN}, digite@BBBB A: tamanho do array e contagem de palavras de argumento (8 bits)
B: índice de tipo (16 bits)
C: registrador do primeiro argumento (16 bits)
N = A + C - 1
Construa uma matriz do tipo e tamanho fornecidos, preenchendo-a com o conteúdo fornecido. Esclarecimentos e restrições são os mesmos que filled-new-array , descritos acima.
26 31t fill-array-data vAA, +BBBBBBBB (com dados suplementares conforme especificado abaixo em " fill-array-data-payload Format") A: referência de array (8 bits)
B: deslocamento "ramo" assinado para pseudo-instrução de dados de tabela (32 bits)
Preencha a matriz fornecida com os dados indicados. A referência deve ser para uma matriz de primitivos, e a tabela de dados deve corresponder a ela em tipo e não deve conter mais elementos do que cabem na matriz. Ou seja, a matriz pode ser maior que a tabela e, se for, apenas os elementos iniciais da matriz são definidos, deixando o restante em paz.
27 11x jogar vAA A: registrador portador de exceção (8 bits)
Lance a exceção indicada.
28 10t vá para +AA A: deslocamento de ramal assinado (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 do branch.)

29 20t goto/16 +AAAA A: deslocamento de ramal assinado (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 do branch.)

2a 30t goto/32 +AAAAAAAA A: deslocamento de ramal assinado (32 bits)
Salte incondicionalmente para a instrução indicada.
2b 31t vAA de switch embalado, +BBBBBBBB (com dados suplementares conforme especificado abaixo em "Formato packed-switch-payload ") A: cadastre-se para testar
B: deslocamento "ramo" assinado para pseudo-instrução de dados de tabela (32 bits)
Pule para uma nova instrução com base no valor no registrador fornecido, usando uma tabela de deslocamentos correspondentes a cada valor em uma faixa integral específica, ou passe para a próxima instrução se não houver correspondência.
2c 31t vAA de comutador esparso, +BBBBBBBB (com dados suplementares conforme especificado abaixo em "Formato sparse-switch-payload ") A: cadastre-se para testar
B: deslocamento "ramo" assinado para pseudo-instrução de dados de tabela (32 bits)
Saltar para uma nova instrução com base no valor no registrador fornecido, usando uma tabela ordenada de pares valor-deslocamento, ou passar para a próxima instrução se não houver correspondência.
2d..31 23x cmp tipo vAA, vBB, vCC
2d: cmpl-float (polarização lt)
2e: cmpg-float (viés gt)
2f: cmpl-double (polarização lt)
30: cmpg-double (viés gt)
31: cmp de comprimento
A: registrador de destino (8 bits)
B: primeiro registrador ou par de fonte
C: segundo registrador ou par de origem
Execute o ponto flutuante indicado ou a comparação long , configurando a para 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 é aconselhável usar cmpg-float ; um resultado de -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 if- teste vA, vB, +CCCC
32: se-eq
33: se-ne
34: se-lt
35: if-ge
36: se-gt
37: if-le
A: primeiro registrador a testar (4 bits)
B: segundo registrador a testar (4 bits)
C: deslocamento de ramal assinado (16 bits)
Desvia para o destino dado se os valores dos dois registradores 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 do desvio.)

38..3d 21t if- teste z vAA, +BBBB
38: if-eqz
39: if-nez
3a: if-ltz
3b: if-gez
3c: if-gtz
3d: if-lez
A: registrar para testar (8 bits)
B: deslocamento de ramal assinado (16 bits)
Ramifique para o destino dado se o valor do registrador 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 do desvio.)

3e..43 10x (sem uso) (sem uso)
44..51 23x arrayop vAA, vBB, vCC
44: obter
45: geral
46: obter-objeto
47: aget-boolean
48: get-byte
49: aget-char
4a: abreviar
4b: colocar
4c: aput-wide
4d: aput-objeto
4e: aput-boolean
4f: byte de entrada
50: aput-char
51: aput-curto
A: registrador ou par de valor; 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 dado, carregando ou armazenando no registrador de valor.
52..5f 22c i instanceop vA, vB, field@CCCC
52: iget
53: todo o iget
54: iget-objeto
55: iget-boolean
56: iget-byte
57: iget-char
58: iget-curto
59: entrada
5a: todo o iput
5b: iput-objeto
5c: iput-boolean
5d: iput-byte
5e: iput-char
5f: iput-curto
A: registrador ou par de valor; pode ser origem ou destino (4 bits)
B: registrador de objeto (4 bits)
C: índice de referência de campo de instância (16 bits)
Execute a operação do 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 de campo para um deslocamento mais direto.

60..6d 21c s staticop vAA, field@BBBB
60: começar
61: amplo
62: objeto sget
63: sget-boolean
64: byte sget
65: sget-char
66: curto
67: cuspir
68: em todo o sput
69: objeto sput
6a: sput-boolean
6b: byte de saída
6c: sput-char
6d: cuspe-curto
A: registrador ou par de valor; pode ser origem ou destino (8 bits)
B: índice de referência de campo estático (16 bits)
Execute a operação de 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 de campo para um deslocamento mais direto.

6e..72 35c tipo de invocação {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 sem 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 .

Em arquivos Dex versão 037 ou posterior, se o method_id se referir a um método de interface, invoke-super é 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 de 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 um deslocamento mais direto (ou par deles).

73 10x (sem uso) (sem uso)
74..78 3rc invocar- kind /range {vCCCC .. vNNNN}, meth@BBBB
74: invocar-virtual/range
75: invocar-super/range
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: registrador do primeiro argumento (16 bits)
N = A + C - 1
Chame o método indicado. Consulte a descrição do primeiro invoke- kind acima para obter detalhes, advertências e sugestões.
79..7a 10x (sem uso) (sem uso)
7b..8f 12x unop vA, vB
7b: neg-int
7c: não-int
7d: neg-longo
7e: não longo
7f: neg-float
80: duplo negativo
81: int-para-longo
82: int para flutuar
83: int-para-duplo
84: longo para int
85: longo para flutuar
86: longo para duplo
87: float-to-int
88: flutuante para longo
89: flutuar para dobrar
8a: duplo para inteiro
8b: duplo a longo
8c: duplo para flutuar
8d: int para byte
8e: int-to-char
8f: int para curto
A: registrador ou par de destino (4 bits)
B: registrador 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.. de 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: add-long
9c: sublongo
9d: mul-longo
9e: div-longo
9f: rem-longo
a0: e-longo
a1: ou-longo
a2: xor-longo
a3: shl-longo
a4: sh-long
a5: ushr-longo
a6: add-float
a7: sub-float
a8: mul-float
a9: div-float
aa: rem-float
ab: add-double
ac: sub-duplo
anúncio: mul-double
ae: div-double
af: rem-double
A: registrador ou par de destino (8 bits)
B: primeiro registrador ou par de origem (8 bits)
C: segundo registrador ou par de origem (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 usam pares de registradores para sua primeira e segunda fonte), shl-long shr-long shr-long e ushr-long pegam um par de registradores 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 /2addr vA, vB
b0: add-int/2addr
b1: sub-int/2addr
b2: mul-int/2addr
b3: div-int/2addr
b4: rem-int/2addr
b5: e-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-longo/2addr
bd: mul-long/2addr
ser: div-long/2addr
bf: rem-long/2addr
c0: e-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-duplo/2addr
cd: mul-double/2addr
ce: div-double/2addr
cf: rem-double/2addr
A: destino e primeiro registrador ou par de origem (4 bits)
B: segundo registrador ou par de origem (4 bits)
Execute a operação binária identificada nos dois registradores de origem, armazenando o resultado no primeiro registrador de origem.

Nota: Ao contrário de outras operações matemáticas -long/2addr (que usam pares de registradores para seu destino/primeira fonte e sua segunda fonte), shl-long/2addr , shr shr-long/2addr e ushr-long/2addr usam um registrador 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: or-int/lit16
d7: xor-int/lit16
A: registrador de destino (4 bits)
B: registrador de origem (4 bits)
C: constante int assinada (16 bits)
Execute a operação binária indicada no registrador indicado (primeiro argumento) e 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
db: div-int/lit8
dc: rem-int/lit8
dd: e-int/lit8
de: or-int/lit8
df: xor-int/lit8
e0: shl-int/lit8
e1: shr-int/lit8
e2: ushr-int/lit8
A: registrador de destino (8 bits)
B: registrador de origem (8 bits)
C: constante int assinada (8 bits)
Execute a operação binária indicada no registrador indicado (primeiro argumento) e valor literal (segundo argumento), armazenando o resultado no registrador de destino.

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

e3..f9 10x (sem uso) (sem uso)
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 para 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 de protótipo descreve os tipos de argumento 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 em arquivos Dex a partir da versão 038 .
fb 4rcc 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 de método indicado. Consulte 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 local 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 de site de chamada e invocação de site 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 do vinculador de 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 não houver associação. Outro encadeamento já pode 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 chamada do site de chamada é feita no destino java.lang.invoke.MethodHandle da instância java.lang.invoke.CallSite resolvida. O alvo é invocado como se estivesse executando invoke-polymorphic (descrito acima) usando o handle de método e argumentos para a instrução invoke-custom como os argumentos para uma invocação de handle de método exato.

As exceções levantadas pelo método do vinculador bootstrap são encapsuladas em um java.lang.BootstrapMethodError . Um BootstrapMethodError também é gerado se:
  • o método do vinculador bootstrap não retorna uma instância java.lang.invoke.CallSite .
  • o java.lang.invoke.CallSite retornado tem um destino de manipulação 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 .
fd 3rc invocar-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: primeiro registro de 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: registrador de destino (8 bits)
B: índice de manipulação do método (16 bits)
Mova uma referência ao manipulador de método especificado pelo índice fornecido para o registro especificado.

Presente em arquivos Dex da versão 039 em diante.
ff 21c vAA do tipo de método const, proto@BBBB A: registrador de destino (8 bits)
B: referência do protótipo do método (16 bits)
Mova uma referência ao protótipo do método especificado pelo índice fornecido para o registrador especificado.

Presente em arquivos Dex da versão 039 em diante.

formato de carga útil de switch compactado

Nome Formato Descrição
identificação ushor = 0x0100 identificando pseudo-opcode
Tamanho ushor número de entradas na tabela
first_key int primeiro (e mais baixo) valor da caixa de comutação
alvos int[] lista de destinos de ramificação relativos ao 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 do switch esparso

Nome Formato Descrição
identificação ushor = 0x0200 identificando pseudo-opcode
Tamanho ushor número de entradas na tabela
chaves int[] lista de valores de chave de size , classificados de baixo para alto
alvos int[] lista de destinos de ramificação relativos ao size , cada um correspondendo ao valor da 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 Formato Descrição
identificação ushor = 0x0300 identificando pseudo-opcode
element_width ushor número de bytes em cada elemento
Tamanho uint 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 arredondada para mais próxima e gradual, exceto onde indicado de outra forma.

Código de operação Semântica C Notas
neg-int int32a;
int32 resultado = -a;
Complemento de dois unário.
não-int int32a;
int32 resultado = ~a;
Unários-complemento.
longo int64a;
int64 resultado = -a;
Complemento de dois unário.
não muito int64a;
int64 resultado = ~a;
Unários-complemento.
neg-float flutuar um;
float result = -a;
Floating point negation.
neg-double double a;
double result = -a;
Floating point negation.
int-to-long int32 a;
int64 result = (int64) a;
Sign extension of int32 into int64 .
int-to-float int32 a;
float result = (float) a;
Conversion of int32 to float , using round-to-nearest. This loses precision for some values.
int-to-double int32 a;
double result = (double) a;
Conversion of int32 to double .
long-to-int int64 a;
int32 result = (int32) a;
Truncation of int64 into int32 .
long-to-float int64 a;
float result = (float) a;
Conversion of int64 to float , using round-to-nearest. This loses precision for some values.
long-to-double int64 a;
double result = (double) a;
Conversion of int64 to double , using round-to-nearest. This loses precision for some values.
float-to-int float a;
int32 result = (int32) a;
Conversion of float to int32 , using round-toward-zero. NaN and -0.0 (negative zero) convert to the integer 0 . Infinities and values with too large a magnitude to be represented get converted to either 0x7fffffff or -0x80000000 depending on sign.
float-to-long float a;
int64 result = (int64) a;
Conversion of float to int64 , using round-toward-zero. The same special case rules as for float-to-int apply here, except that out-of-range values get converted to either 0x7fffffffffffffff or -0x8000000000000000 depending on sign.
float-to-double float a;
double result = (double) a;
Conversion of float to double , preserving the value exactly.
double-to-int double a;
int32 result = (int32) a;
Conversion of double to int32 , using round-toward-zero. The same special case rules as for float-to-int apply here.
double-to-long double a;
int64 result = (int64) a;
Conversion of double to int64 , using round-toward-zero. The same special case rules as for float-to-long apply here.
double-to-float double a;
float result = (float) a;
Conversion of double to float , using round-to-nearest. This loses precision for some values.
int-to-byte int32 a;
int32 result = (a << 24) >> 24;
Truncation of int32 to int8 , sign extending the result.
int-to-char int32 a;
int32 result = a & 0xffff;
Truncation of int32 to uint16 , without sign extension.
int-to-short int32 a;
int32 result = (a << 16) >> 16;
Truncation of int32 to int16 , sign extending the result.
add-int int32 a, b;
int32 result = a + b;
Twos-complement addition.
sub-int int32 a, b;
int32 result = a - b;
Twos-complement subtraction.
rsub-int int32 a, b;
int32 result = b - a;
Twos-complement reverse subtraction.
mul-int int32 a, b;
int32 result = a * b;
Twos-complement multiplication.
div-int int32 a, b;
int32 result = a / b;
Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 .
rem-int int32 a, b;
int32 result = a % b;
Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 .
and-int int32 a, b;
int32 result = a & b;
Bitwise AND.
or-int int32 a, b;
int32 result = a | b;
Bitwise OR.
xor-int int32 a, b;
int32 result = a ^ b;
Bitwise XOR.
shl-int int32 a, b;
int32 result = a << (b & 0x1f);
Bitwise shift left (with masked argument).
shr-int int32 a, b;
int32 result = a >> (b & 0x1f);
Bitwise signed shift right (with masked argument).
ushr-int uint32 a, b;
int32 result = a >> (b & 0x1f);
Bitwise unsigned shift right (with masked argument).
add-long int64 a, b;
int64 result = a + b;
Twos-complement addition.
sub-long int64 a, b;
int64 result = a - b;
Twos-complement subtraction.
mul-long int64 a, b;
int64 result = a * b;
Twos-complement multiplication.
div-long int64 a, b;
int64 result = a / b;
Twos-complement division, rounded towards zero (that is, truncated to integer). This throws ArithmeticException if b == 0 .
rem-long int64 a, b;
int64 result = a % b;
Twos-complement remainder after division. The sign of the result is the same as that of a , and it is more precisely defined as result == a - (a / b) * b . This throws ArithmeticException if b == 0 .
and-long int64 a, b;
int64 result = a & b;
Bitwise AND.
or-long int64 a, b;
int64 result = a | b;
Bitwise OR.
xor-long int64 a, b;
int64 result = a ^ b;
Bitwise XOR.
shl-long int64 a;
int32 b;
int64 result = a << (b & 0x3f);
Bitwise shift left (with masked argument).
shr-long int64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Bitwise signed shift right (with masked argument).
ushr-long uint64 a;
int32 b;
int64 result = a >> (b & 0x3f);
Bitwise unsigned shift right (with masked argument).
add-float float a, b;
float result = a + b;
Floating point addition.
sub-float float a, b;
float result = a - b;
Floating point subtraction.
mul-float float a, b;
float result = a * b;
Floating point multiplication.
div-float float a, b;
float result = a / b;
Floating point division.
rem-float float a, b;
float result = a % b;
Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b .
add-double double a, b;
double result = a + b;
Floating point addition.
sub-double double a, b;
double result = a - b;
Floating point subtraction.
mul-double double a, b;
double result = a * b;
Floating point multiplication.
div-double double a, b;
double result = a / b;
Floating point division.
rem-double double a, b;
double result = a % b;
Floating point remainder after division. This function is different than IEEE 754 remainder and is defined as result == a - roundTowardZero(a / b) * b .