Download PPT

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Manipulação de
Bytecodes Java
Giuliano Mega
1
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)
2
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
3
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
4
Reflexão Computacional (cont.)
• Meta-sistema
• Domínio = outro sistema.
• Sistema-objeto.
• Sistema reflexivo
• Meta-sistema causalmente
sistema-objeto é ele próprio.
conexo
cujo
• Conseqüência
• Pode modificar aspectos de sua execução
como efeito dela mesma.
5
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
6
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?
7
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
8
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].
9
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.
10
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].
11
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));
}
}
12
JVM – formato das classes
Formato de classes Java [9]
13
JVM – básico
• JVM é um processador virtual
• pilhas, “registradores”
• Preocupação com segurança
• verificação
• opcodes tipados (tipos primitivos)
14
JVM - A linguagem de montagem
• Um pequeno exemplo:
• Estáticos:
• Tamanho máximo da pilha
• Número de variáveis locais (slots)
15
Manipulação Revisitada
• Manipular classes:
• Complexo
• Muitas dependências
• Classe = array de bytes
• Necessário interpretar os dados
• Arcabouços (BCEL e muitos outros):
16
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.
17
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;
}
18
Javassist (cont.)
• Desempenho
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;
}
• Class Loader
• O Javassist já provê um esqueleto
• javassist.Loader extends java.lang.ClassLoader
• Você só escreve os ganchos
• interface javassist.Translator
19
Javassist (cont.)
• Translator
public interface Translator {
public void start(ClassPool pool)
throws NotFoundException, CannotCompileException;
public void onLoad(ClassPool pool, String classname)
throws NotFoundException, CannotCompileException;
}
• Restrições
• variáveis locais (lembre-se do bytecode...)
• como faço para implementar o exemplo?
• “expressão idiomática Javassist” prá isso
20
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);
}
21
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.
22
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
23
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();
}
24
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);
25
BCEL (cont.)
• Problemas
•
•
•
•
Ainda é lento;
pode ser muito complexo;
manipulação direta de bytecodes;
muito fácil gerar código inválido.
26
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.
27
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).
28
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 contraexemplo
• Problemas de decidibildade
• Restrições mais fortes do que o necessário.
• Rejeita código “válido”.
29
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.
30
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.
31
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.
32
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.
33
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
34
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. AddisonWesley, 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]
35
Dúvidas?
36