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 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
- 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 intervalov0
av65535
. 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çãonop
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 intervalov0
–v255
. - "
vBBBB
" é o registro de origem, que precisa estar no intervalov0
av65535
.
- "
- 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 |
|
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 |
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 |
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 |
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 só 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 |
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 |
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 |
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 |
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 |
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 testeB: 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 testeB: 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 origemC: 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
|
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 |
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 |
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.
Quando o Em arquivos DEX da versão
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 |
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 |
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: |
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
|
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:
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 .
|