1 / 38

Mitsuo Takaki

Java Bytecode. Software Básico. Mitsuo Takaki. Java Bytecode. O que é Bytecode Formato de um arquivo .class Principais comandos Motivações para aprender bytecode Principais Dificuldades. Java Bytecode. O que é Bytecode Formato de um arquivo .class Principais comandos

august
Download Presentation

Mitsuo Takaki

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Java Bytecode Software Básico Mitsuo Takaki

  2. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  3. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  4. Passos 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.

  5. Passos de Compilação de Java Compilador JVM compila interpreta .java .class

  6. O 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).

  7. Motivaçõ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.

  8. Motivaçõ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.

  9. Có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.

  10. int foo(int a): 0: ILOAD_1 1: IFEQ 4 2: BIPUSH 1 3: IRETURN 4: BIPUSH 0 5: IRETURN Códigos Equivalentes • int foo(int a) { • if (a == 0) { • return 0; • } else { • return 1; • } • }

  11. 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 Códigos Equivalentes • int foo() { • int result = 0; • while (result < 2) { • result++; • } • return result; • }

  12. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  13. Formato 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. • ...

  14. Formato de um Arquivo .class

  15. Constant Pool • Local onde estão armazenadas todas as constantes. • Nome das classes usadas. • Nome dos métodos. • Valores iniciais. • ...

  16. Inner 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: HelloWorld$1.class

  17. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  18. Principais Comandos • Aritméticos (inteiros): • IADD – soma. • ISUB – subtração. • IMUL – multiplicação. • IDIV – divisão. • ...

  19. Principais Comandos • Pilha: • BIPUSH – empilha uma constante (inteiro). • POP – remove da pilha (independente de tipo). • LDC – empilha uma constant (string ou double). • ...

  20. Principais 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).

  21. Principais 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)

  22. Parâ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.

  23. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  24. Por 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.

  25. Por 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.

  26. Motivaçõ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.

  27. Motivaçõ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.

  28. Ferramentas que Usam Manipulação de Bytecode • AspectJ • Ferramenta de Orientação a Aspectos. • EclEmma • Mede cobertura dos testes. • JAD (JAva Decompiler) • Descompila classes Java.

  29. Java Bytecode • O que é Bytecode • Formato de um arquivo .class • Principais comandos • Motivações para aprender bytecode • Principais Dificuldades

  30. Principais 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.

  31. Principais 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.

  32. Principais 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.

  33. Principais 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

  34. Modificando 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

  35. Modificando 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

  36. Modificando 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.

  37. Principais 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.

  38. 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 Principais Dificuldades - Ifs • void foo(int x, int y) { • if (x > y) { • ... • } else { • ... • } • }

More Related