manipulação de bytecodes java

36
1 Manipulação de Bytecodes Java Giuliano Mega

Upload: lilly

Post on 18-Mar-2016

36 views

Category:

Documents


2 download

DESCRIPTION

Manipulação de Bytecodes Java. Giuliano Mega. Introdução. O que é bytecode ? Código intermediário Semelhante aos códigos de montagem ( assembly ) Byte-code – opcodes de 1 byte Processadores virtuais (Virtual Machines) Quem usa? Java (JVM), Smalltalk (Slang), .NET (CLR). Introdução. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Manipulação de Bytecodes Java

1

Manipulação de Bytecodes Java

Giuliano Mega

Page 2: Manipulação de Bytecodes Java

2

Introdução

• O que é bytecode?• Código intermediário• Semelhante aos códigos de

montagem (assembly)• Byte-code – opcodes de 1 byte• Processadores virtuais (Virtual

Machines)• Quem usa?

• Java (JVM), Smalltalk (Slang), .NET (CLR)

Page 3: Manipulação de Bytecodes Java

3

Introdução

• Assuntos em pauta• Por que?

• Reflexão• Como?

• JVM• Bytecodes• Técnicas de compilação• Arcabouços

• Suposição• Você conhece Java• Você sabe o que é um Class Loader

Page 4: Manipulação de Bytecodes Java

4

Reflexão Computacional

• Sistemas computacionais• Sistema de computador que responde

perguntas ou dá apoio a certas ações sobre algum domínio

• Sistema representa o seu domínio por meio de estruturas de dados

• Representação causalmente conexa

Page 5: Manipulação de Bytecodes Java

5

Reflexão Computacional (cont.)

• Meta-sistema• Domínio = outro sistema.• Sistema-objeto.

• Sistema reflexivo• Meta-sistema causalmente conexo cujo

sistema-objeto é ele próprio. • Conseqüência

• Pode modificar aspectos de sua execução como efeito dela mesma.

Page 6: Manipulação de Bytecodes Java

6

Arquiteturas Reflexivas

• Linguagem dá acesso a estruturas que modificam aspectos da interpretação da linguagem.

• Interpretadores metacirculares e variantes• Forma muito explorada de implementação;• poderosa e garantida;• conexão causal garantida pela circularidade.

programa

interpretador

Page 7: Manipulação de Bytecodes Java

7

Arquiteturas Reflexivas (cont.)

• Reflexão [1]• Ad hoc• Facilidades providas pela linguagem• Arquitetura reflexiva:

• Reconhece reflexão como conceito;• provê meios para fazê-la.• Finalidade aberta (open-ended).

• Alguns exemplos:• 3-LISP,BROWN (funcionais)• META-PROLOG, FOL (lógicas)• TEIRESIAS, SOAR (regras)• 3-KRS, SuperEgo (OO)

• Prá que que serve afinal?

Page 8: Manipulação de Bytecodes Java

8

Reflexão - aplicações

• Aplicações• depuração [1];• prog. concorrente [2];• backtracking [3];• futures [4];• AOP [5];• etc.

• Tudo isso no nível da linguagem• Sem extensões sinistras

ao interpretador

Page 9: Manipulação de Bytecodes Java

9

Reflexão Java

• Afinal, Java é “reflexiva”?• Não conta com uma arquitetura

reflexiva.• Segunda categoria

• Ausência de meta-nível claro• Introspecção confusa

• Limitada• Class loaders• Proxies dinâmicos (JDK 1.3)

• Justificativa: desempenho, type-safety [6].

Page 10: Manipulação de Bytecodes Java

10

Reflexão Java (cont.)

• Programadores Java também precisam de reflexão• logging, estatísticas, tracing, depuração,

persistência, AOP...• Reflexão comportamental/estrutural

• Proxies dinâmicos• Factories• Não-ortogonais• Aplicações já prontas – difícil.

Page 11: Manipulação de Bytecodes Java

11

Reflexão Java (cont.)

• “Reflexão” em tempo de compilação (Open Java [7] e cia.)• Não é reflexão, é metaprogramação.

• Reflexão em tempo de carga.• Class loaders• Portável entre JVMs• Dizem que é reflexão estrutural• Opinião pessoal: forçada de barra

• Formas desajeitadas e não-portáveis de reflexão comportamental/estrutural pela JVMTI (Sun).

• Java e adaptação não combinam.• Flexibilidade => adaptação [8].

Page 12: Manipulação de Bytecodes Java

12

Manipulação em Tempo de Carga

• Forma mais comum e aceita• Portável• Não requer código fonte• “Fácil” e “eficiente”

class SRLoader extends ClassLoader { public Class loadClass(String name) { byte[] bytecode = readClassFile(name); <mexa no bytecode o quanto quiser> return resolveClass(defineClass(bytecode)); }}

Page 13: Manipulação de Bytecodes Java

13

JVM – formato das classes

Formato de classes Java [9]

Page 14: Manipulação de Bytecodes Java

14

JVM – básico

• JVM é um processador virtual• pilhas, “registradores”

• Preocupação com segurança• verificação• opcodes tipados (tipos primitivos)

Page 15: Manipulação de Bytecodes Java

15

JVM - A linguagem de montagem

• Um pequeno exemplo:

• Estáticos:• Tamanho máximo da pilha• Número de variáveis locais (slots)

Page 16: Manipulação de Bytecodes Java

16

Manipulação Revisitada

• Manipular classes:• Complexo• Muitas dependências• Classe = array de bytes• Necessário interpretar os dados

• Arcabouços (BCEL e muitos outros):

Page 17: Manipulação de Bytecodes Java

17

Arcabouços de Manipulação

• Forma OO de representar/manipular o bytecode

• Variam em grau de abstração, tamanho, desempenho...• ByteCode Engineering Library* (BCEL) [10]• ASM [11]• Java Assistant* (Javassist) [12]• Code Generation LIBrary (CGLIB)• SERP• JOIE• etc.

Page 18: Manipulação de Bytecodes Java

18

O Java Assistant (Javassist)

• Nosso foco: manipulação de alto nível• Intuitivo• Fácil de usar• Dificilmente produz código inválido

• Exemplo:• Medir desempenho (interceptadores): private String buildString(int length) { String result = ""; for (int i = 0; i < length; i++){ result += (char)(i%26 + 'a'); } return result; }

Page 19: Manipulação de Bytecodes Java

19

Javassist (cont.)

• Desempenho

• Class Loader• O Javassist já provê um esqueleto

• javassist.Loader extends java.lang.ClassLoader• Você só escreve os ganchos

• interface javassist.Translator

private String buildString(int length) { long start = System.currentTimeMillis(); String result = ""; for (int i = 0; i < length; i++) { result += (char)(i%26 + 'a'); } System.out.println("Call to buildString took " + (System.currentTimeMillis()-start) + " ms."); return result; }

Page 20: Manipulação de Bytecodes Java

20

Javassist (cont.)

• Translator

• Restrições• variáveis locais (lembre-se do

bytecode...)• como faço para implementar o exemplo?• “expressão idiomática Javassist” prá isso

public interface Translator { public void start(ClassPool pool) throws NotFoundException, CannotCompileException; public void onLoad(ClassPool pool, String classname) throws NotFoundException, CannotCompileException;}

Page 21: Manipulação de Bytecodes Java

21

Javassist (cont.) CtClass clas = pool.get(cname);CtMethod[] meths = clas.getDeclaredMethods();for (int i = 0; i < meths.length; i++) { CtMethod mold = methds[i]; String nname = mname+"$impl"; /* 1) Muda o nome do método e duplica com o nome antigo */ mold.setName(nname); CtMethod mnew = CtNewMethod.copy(mold, mname, clas, null);

/* 2) Cria o embrulho-cronômetro para o método original */ String type = mold.getReturnType().getName(); StringBuffer body = new StringBuffer(); body.append("{\nlong start = System.currentTimeMillis();\n"); if (!"void".equals(type)) { body.append(type + " result = "); } body.append(nname + "($$);\n"); ...

/* 3) Substitui o código do método embrulhado */ mnew.setBody(body.toString()); clas.addMethod(mnew);}

Page 22: Manipulação de Bytecodes Java

22

Javassist (cont.)

• A técnica envolve ainda um “lançador”• Em geral provido pelo arcabouço

• Limitações• Não é muito flexível• Classes internas e anônimas• Código original vai parar em outro

método• Lento• Modificações internas

• Introspecção limitada• Proposta não é essa

• Tem uma API para bytecodes.

Page 23: Manipulação de Bytecodes Java

23

A ByteCode Engineering Library (BCEL)

• Transforma a classe Java num grafo• ByteCodes orientados a objeto

• Poderoso• Mais “intuitivo” que o Javassist

• Prá quem conhece bytecodes• Mais rápido que o Javassist

• Exemplo:• Instrumentar todos os métodos Run de

todos os Runnables

Page 24: Manipulação de Bytecodes Java

24

BCEL (cont.)

public JavaClass modifyClass(JavaClass jc) { /* 1) Testa se a classe é instância de Runnable */ JavaClass runnableIntf = Repository.lookupClass("java.lang.Runnable"); if(!jc.instanceOf(runnableIntf)) return jc; Method [] methods = jc.getMethods(); int i = 0; for(i = 0; i < methods.length; i++){ if(methods[i].getName().equals("run")) break; } /* 2) Cria as versões maleáveis (de-serializa) e as modifica */ ClassGen newClass = new ClassGen(jc); ConstantPoolGen cg = newClass.getConstantPool(); MethodGen mg = new MethodGen(m, newClass.getClassName(), cg); newClass.removeMethod(methods[i]); ...

/* 3) Calcula dados estáticos, re-serializa o bytecode */ mg.setMaxStack(); mg.setMaxLocals(); newClass.addMethod(mg.getMethod()); return newClass.getJavaClass();}

Page 25: Manipulação de Bytecodes Java

25

BCEL (cont.)

InstructionList il = new InstructionList(); InstructionFactory iFactory = new InstructionFactory(nc);

il.append(iFactory.createFieldAccess("java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC)); il.append(new PUSH(cg, "Método \"run\" chamado na classe " + jc.getName()); il.append(iFactory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));

InstructionList old_il = mg.getInstructionList(); InstructionHandle [] handles = old_il.getInstructionHandles(); old_il.insert(handles[0], il); mg.setInstructionList(old_il);

Page 26: Manipulação de Bytecodes Java

26

BCEL (cont.)

• Problemas• Ainda é lento;• pode ser muito complexo;• manipulação direta de bytecodes;• muito fácil gerar código inválido.

Page 27: Manipulação de Bytecodes Java

27

ASM

• Visitor pattern • Não seria/de-seria o grafo• Composição de visitors• Substituição

• Muito rápido• 700% mais rápido que o BCEL• 1100% mais rápido que o SERP

• Compacto • 25 kb vs. 350 kb do BCEL

• Lembra um pull parser prá XML.• Não alivia muito em manipulações

complexas.

Page 28: Manipulação de Bytecodes Java

28

Verificação de Bytecode

• O que há de errado com este (pseudo) bytecode?00 aload_0

01 invokevirtual “MyClass#test()”

02 ifne 05

03 aload_0

04 invokevirtual “MyClass#test()”

05 return

Rode isso e...:

java.lang.VerifyError: stack sizes differ (1 != 0).

Page 29: Manipulação de Bytecodes Java

29

Verificação de Bytecode (cont.)

• Esse código não passa pelo verificador (pág. 12)

• Verificador• Algoritmo de análise de fluxo• Prova um teorema ou arruma um contra-

exemplo• Problemas de decidibildade

• Restrições mais fortes do que o necessário.• Rejeita código “válido”.

Page 30: Manipulação de Bytecodes Java

30

Verificação de Bytecode (cont.)

00 aload_0

01 invokevirtual “MyClass.test()”

02 ifne 05

03 aload_0

04 invokevirtual “MyClass.test()”

05 return

• Análise de tipos + stack merging = código seguro+ chatice.

• Merging em laços.

Page 31: Manipulação de Bytecodes Java

31

Verificação de Bytecode (cont.)

• Compilador “burla” o verificador• Sempre produz código válido;• equivalente ao código-fonte;• nós não temos o código-fonte.

• Transformações difíceis• Armadilhas (traps);• implementadas com subrotinas.

Page 32: Manipulação de Bytecodes Java

32

Problemas Adicionais

• Class Loader que instrumenta:• Tem que definir a classe;• saber o que “deixar passar” (i.e.

java.lang.*);• getSystemClassloader();• a opção -Dendorsed.dirs=...;

• Limitação: classes de sistema.

Page 33: Manipulação de Bytecodes Java

33

Conclusão

• Java: reflexão deficitária.• Desempenho.• Segurança.

• Manipulação:• Reflexão estrutural limitada.

• Manipulação em tempo de carga:• em acordo com a filosofia Java.

• Arcabouços:• facilitam a tarefa.• compromisso entre flexibilidade,

complexidade e desempenho.

Page 34: Manipulação de Bytecodes Java

34

Referências:

[1] P. Maes. Concepts and Experiments in Computational Reflection. In Proceedings of the OOPSLA’87. pages 147-155. Orlando, Florida.

[2] B. Foote. Objects, Reflection and Open Languages. In Proceedings of the 1992 ECOOP Workshop on Object-Oriented reflection and Meta-Level Architectures. Utrecht, Netherlands

[3] W. R. LaLonde and M. V. Gulik. Building a Backtracking Facility in Smalltalk Without Kernel Support. In Proceedings of the OOPSLA’88. pages 105-122. San Diego, California.

[4] B. Foote and R. Johnson. Reflective Facilities in Smalltalk-80. In Proceedings of the OOPSLA’89. pages 327-335. New Orleans, Louisiana.

[5] S. Kojarski and D. Lorentz. AOP as a First-class reflective mechanism. In Companion to the OOPSLA’04. pages 216 – 217. Vancouver, Canada.

[6] S. Liang and G. Bracha. Dynamic Class Loading in the Java Virtual Machine. In Proceedings of the OOPSLA’98. pages 36-44. Vancouver, Canada.

[7] M. Tsubori, S. Chiba et. al. OpenJava: A Class-based Macro System for Java. In Reflection and Software Engineering, LNCS 1826, Springer-Verlag, 2000. /15

Page 35: Manipulação de Bytecodes Java

35

Referências (cont.)

[8] B. Foote. Class Warfare: Classes vs. Prototypes. In Proceedings of the OOPSLA’89 Workshop on Objects without Classes, New Orleans, LA.

[9] T. Lindholm and F. Yellin. The Java Virtual Machine Specification. Addison-Wesley, 2nd edition, 1999.

[10] BCEL website. http://apache.jakarta.org/bcel. [june 9, 2005][11] E. Bruneton, R. Lenglet and T. Coupaye. ASM: a code manipulation tool to

implement adaptable systems. In ACM SIGOPS Adaptable and extensible component systems. 2002, Grenoble, France.

[12] Javassist website. http://www.csg.is.titech.ac.jp/~chiba/javassist [june 8, 2005]

Page 36: Manipulação de Bytecodes Java

36

Dúvidas?