Title: Mitsuo Takaki
1Java Bytecode
Software Básico
Mitsuo Takaki
2Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
3Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
4Passos de Compilação de Java
- A compilação de um código java segue os seguintes
passos - Recebe um código Java (alto nível).
- Compila para uma linguagem intermediária (baixo
nível). - Este procedimento é conhecido como tradução.
- Após esta compilação, o código é interpretado.
5Passos de Compilação de Java
Compilador
JVM
compila
interpreta
.java
.class
6O que é Java Bytecode?
- Java Bytecode é a linguagem intermediária à qual
um código java é modificado. - Utiliza apenas comandos simplificados e baseados
em pilha. - Muito semelhante a Assembly.
- Linguagem baseada em pilha.
- Cada opcode tem o tamanho de 1 byte (origem do
nome bytecode).
7Motivações
- A interpretação de um código Java exigiria uma
maior complexidade do interpretador. - Menor velocidade de interpretação.
- Durante a compilação, otimizações são feitas.
- Códigos mais eficientes são gerados.
- Portabilidade
- É possível executar o código em várias
plataformas por ser interpretado.
8Motivações
- Simplificações são realizadas
- Short, char e boolean se tornam inteiros.
- Laços são simplificados
- For, while, do...while são iguais, apenas se
comportam de forma diferente.
9Códigos Equivalentes
- Dois códigos podem realizar uma mesma tarefa
usando diferentes linguagens. - Desta forma, é possível manter a semântica do
programa original, apenas seu código é
simplificado.
10Códigos Equivalentes
- int foo(int a)
- if (a 0)
- return 0
- else
- return 1
-
- int foo(int a)
- 0 ILOAD_1
- 1 IFEQ 4
- 2 BIPUSH 1
- 3 IRETURN
- 4 BIPUSH 0
- 5 IRETURN
11Códigos Equivalentes
- int foo()
- int result 0
- while (result lt 2)
- result
-
- return result
- int foo()
- 0 BIPUSH 0
- 1 ISTORE_1
- 2 GOTO 4
- 3 IINC 1,1
- 4 ILOAD_1
- 5 BIPUSH 2
- 6 IF_ICMPGE 3
- 7 ILOAD_1
- 8 IRETURN
12Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
13Formato de um Arquivo .class
- O arquivo compilado (.class) armazena as
informações específica da classe. - Métodos (privado, protegido, publico).
- Campos.
- Atributos.
- Constant Pool.
- ...
14Formato de um Arquivo .class
15Constant Pool
- Local onde estão armazenadas todas as constantes.
- Nome das classes usadas.
- Nome dos métodos.
- Valores iniciais.
- ...
16Inner Class
- As inner class, apesar de estarem dentro de uma
classe, após a compilação são extraidas e um
.class é criado para as mesmas. - É criado algo como HelloWorld1.class
17Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
18Principais Comandos
- Aritméticos (inteiros)
- IADD soma.
- ISUB subtração.
- IMUL multiplicação.
- IDIV divisão.
- ...
19Principais Comandos
- Pilha
- BIPUSH empilha uma constante (inteiro).
- POP remove da pilha (independente de tipo).
- LDC empilha uma constant (string ou double).
- ...
20Principais Comandos
- Mudança de fluxo
- IFEQ, IFNE, IFLT, IFLE, IFGT, IFGE
- Compara um inteiro que está na pilha com zero.
- Caso o resultado seja verdadeiro, modifica o
fluxo para o endereço especificado como
parâmetro. - GOTO
- Mudança de fluxo incondicional (modifica o fluxo
sem nenhuma verificação).
21Principais Comandos
- Chamada de métodos
- INVOKESTATIC, INVOKEINTERFACE, INVOKEVIRTUAL,
INVOKESPECIAL. - Chama um método de acordo com o seu modificador
(estático, método de uma interface, método de uma
instância)
22Parâmetros
- Alguns comandos usam parâmetros na pilha.
- INVOKEVIRTUAL precisa que a referência do objeto
esteja na pilha. - Além disto, alguns comandos podem possuir mais de
um parâmetro. - IINC 1, 1 soma o valor 1 a variável com índice
1.
23Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
24Por que aprender bytecode?
- Para se ter proficiência em Java, não é
necessário aprender bytecode. - Da mesma forma que para aprender uma linguagem de
alto nível, não é necessário aprender linguagem
de máquina. - Existem poucas bibliotecas que permitem a
manipulação de bytecode. - BCEL, biblioteca da Apache, não está mais sendo
desenvolvida e possui muitos bugs.
25Por que aprender bytecode?
- Apenas em casos específicos será necessário o
conhecimento de bytecode. - No desenvolvimento de sistemas, dificilmente será
necessário conhecer alguma coisa sobre bytecode. - O compilador de Java já realiza otimizações
eficientes. - Escrever manualmente um código bytecode
possivelmente será menos eficiente que um código
gerado pelo compilador.
26Motivações
- Manipular bytecode permite introduzir novas
funcionalidades a códigos fechados
(instrumentação). - Alguns sistemas são disponibilizados sem código
fonte, a modificação destes códigos se torna
impossível sem a manipulação de bytecode. - Debugging.
- É possível introduzir traces no código para
identificação de bugs e análise de fluxo.
27Motivações
- Análise de cobertura de testes unitários.
- Ferramentas que analizam a cobertura de testes de
unidade utilizam instrumentação para a inserção
de traces no código. - Modificação de operadores de fluxo de controle.
- É possível escrever geradores automáticos de
teste de mutação.
28Ferramentas que Usam Manipulação de Bytecode
- AspectJ
- Ferramenta de Orientação a Aspectos.
- EclEmma
- Mede cobertura dos testes.
- JAD (JAva Decompiler)
- Descompila classes Java.
29Java Bytecode
- O que é Bytecode
- Formato de um arquivo .class
- Principais comandos
- Motivações para aprender bytecode
- Principais Dificuldades
30Principais Dificuldades - Loops
- Devido as suas simplificações, não é possível
distinguir um while, do...while e for. - Por padrão, um loop é toda estrutura de mudança
de fluxo condicional que possui um fluxo no
sentido inverso.
31Principais Dificuldades - Loops
- Todo loop é composto por um operador de fluxo
condicional. - Condição de parada.
- É difícil identificar o inicio e o fim de loop.
32Principais Dificuldades - Loops
- Para identificar um loop é necessário realizar
uma análise do fluxo do programa. - Ai ser encontrado um operador de mudança de fluxo
condicional que mude o fluxo no sentido
contrário, foi encontrado o fim do bloco do loop. - O operador de condição de parada sempre aponta
para o inicio do bloco.
33Principais Dificuldades - Loops
- int foo()
- 0 BIPUSH 0
- 1 ISTORE_1
- 2 GOTO 4
- 3 IINC 1,1
- 4 ILOAD_1
- 5 BIPUSH 2
- 6 IF_ICMPGE 3
- 7 ILOAD_1
- 8 IRETURN
Corpo do loop
Condição de parada
34Modificando um Loop
- int foo()
- 0 BIPUSH 0
- 1 ISTORE_1
- 2 GOTO 4
- 3 IINC 1,1
- 4 ILOAD_1
- 5 BIPUSH 2
- 6 IF_ICMPGE 3
- 7 ILOAD_1
- 8 IRETURN
ILOAD_1 BIPUSH 2 IADD ISTORE_1
35Modificando um Loop
- int foo()
- 0 BIPUSH 0
- 1 ISTORE_1
- 2 GOTO 4
- 3 IINC 1,1
- 4 ILOAD_1
- 5 BIPUSH 2
- 6 IF_ICMPGE 3
- 7 ILOAD_1
- 8 IRETURN
36Modificando um Loop
- int foo()
- 0 BIPUSH 0
- 1 ISTORE_1
- 2 GOTO 11
- 3 ILOAD_1
- 4 BIPUSH 2
- 5 IADD
- 6 ISTORE_1
- 7 IINC 1,1
- 8 ILOAD_1
- 9 BIPUSH 2
- 10 IF_ICMPGE 3
- 11 ILOAD_1
- 12 IRETURN
Atualiza endereços do operadores de mudança de
fluxo.
37Principais Dificuldades - Ifs
- Nem todo operador condicional de mudança de fluxo
pode ser automáticamente traduzido como um if. - Como visto anteriormente, este pode ser a
condição de parada de um loop. - Em um caso de if...else não existem 2 operadores,
apenas um.
38Principais Dificuldades - Ifs
- void foo(int x, int y)
- if (x gt y)
- ...
- else
- ...
-
- void foo(int x, int y)
- 0 ILOAD_1
- 1 ILOAD_2
- 2 IF_ICMPLE 5
- 3 bloco do if
- 4 GOTO 6
- 5 bloco do else
- 6 RETURN