no dark magic - byte code engineering in the real world

45
Java Byte Code Engineering No black magic Torsten Curdt

Upload: tcurdt

Post on 15-Jan-2015

3.279 views

Category:

Technology


3 download

DESCRIPTION

ften byte code engineering is perceived as "black magic" and considered too low level. This session will not bore you with all the details of the JVM specification but provide you with a practical overview of how this byte code "swizzling" can be used in the real world instead. Several projects have sucessfully leveraged this technique to achieve some amazing things (e.g. AOP). This session will go through some of these examples and try to outline the differences between the two major libraries (BCEL and ASM). Maybe your next project can then benefit from some of this "magic".

TRANSCRIPT

Page 1: No dark magic - Byte code engineering in the real world

JavaByte Code

EngineeringNo black magic

Torsten Curdt

Page 2: No dark magic - Byte code engineering in the real world

Virtual CPU

Java

Virtual Machine

Physical Machine

Page 3: No dark magic - Byte code engineering in the real world

.section __TEXT,__text,regular,pure_instructions .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 .machine ppc .cstring .align 2LC0: .ascii "Hello, world\0" .text .align 2 .globl _main_main: mflr r0 stmw r30,-8(r1) stw r0,8(r1) stwu r1,-80(r1) mr r30,r1 bcl 20,31,"L00000000001$pb""L00000000001$pb": mflr r31 stw r3,104(r30) addis r2,r31,ha16(LC0-"L00000000001$pb") la r3,lo16(LC0-"L00000000001$pb")(r2) bl L_printf$LDBLStub$stub li r0,0 mr r3,r0 lwz r1,0(r1) lwz r0,8(r1) mtlr r0 lmw r30,-8(r1) blr .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 .align 5L_printf$LDBLStub$stub: .indirect_symbol _printf$LDBLStub mflr r0 bcl 20,31,"L00000000001$spb""L00000000001$spb": mflr r11 addis r11,r11,ha16(L_printf$LDBLStub$lazy_ptr-"L00000000001$spb") mtlr r0 lwzu r12,lo16(L_printf$LDBLStub$lazy_ptr-"L00000000001$spb")(r11) mtctr r12 bctr .lazy_symbol_pointerL_printf$LDBLStub$lazy_ptr: .indirect_symbol _printf$LDBLStub .long dyld_stub_binding_helper .subsections_via_symbols

Native Assembler

#include <stdio.h>

int main(char** args) { printf("Hello, world"); return 0;}

gcc -S HelloWorld.c

Page 4: No dark magic - Byte code engineering in the real world

#include <stdio.h>

int main(char** args) { printf("Hello, world"); return 0;}

Native Assembler_main: mflr r0 stmw r30,-8(r1) stw r0,8(r1) stwu r1,-80(r1) mr r30,r1 bcl 20,31,"L00000000001$pb" ...

gcc -S HelloWorld.c

Page 5: No dark magic - Byte code engineering in the real world

Compiled from "HelloWorld.java"public class HelloWorld extends java.lang.Object{public HelloWorld(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, world! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return

}

Java Assembler

public class HelloWorld {

public static void main(String[] args) { System.out.println("Hello, world!"); }

}

javap -c HelloWorld

Page 6: No dark magic - Byte code engineering in the real world

public class HelloWorld {

public static void main(String[] args) { System.out.println("Hello, world!"); }

}

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/ 3: ldc #3; //String Hello, world! 5: invokevirtual #4; //Method java/io/ 8: return}

Java Assembler

javap -c HelloWorld

Page 7: No dark magic - Byte code engineering in the real world

public class HelloWorld {

public static void main(String[] args) { System.out.println("Hello, world!"); }

}

.method public static main([Ljava/lang .limit stack 2 .limit locals 1 .line 4 getstatic java/lang/System/out Ljava/ ldc "Hello, world!" invokevirtual java/io/PrintStream/println .line 5 return.end method

Jasmin Syntax

Page 8: No dark magic - Byte code engineering in the real world

Tools

java -jar jasmin.jar HelloWorld.j

•Disassembler: Jasper

• Assembler: Jasmin

java -jar jasper.jar HelloWorld.class

Page 9: No dark magic - Byte code engineering in the real world

Roundtripjasmin

HelloWorld.j HelloWorld.class

jasper

Page 10: No dark magic - Byte code engineering in the real world

Libraries

•ASM (BSD-style)

•BCEL (ASL)

•CGLIB (ASL)

•Javassist (MPL/LGPL)

Page 11: No dark magic - Byte code engineering in the real world

Libraries

JavassistAOP

BCEL

ASM

CGLIB

Page 12: No dark magic - Byte code engineering in the real world

BCEL

•Object model based

•JDK 1.4 support

•Verifier

•“DOM”

Page 13: No dark magic - Byte code engineering in the real world

ASM

•Event driven

•DOM available

•JDK 1.6 support

•“SAX”

Page 14: No dark magic - Byte code engineering in the real world

BCEL vs ASM

•Community

•JDK support

•“DOM” vs “SAX”

•API

•Tool support

Page 15: No dark magic - Byte code engineering in the real world

BCEL vs ASM

•BCEL: xalan, findbugs, aspectj, javaflow, clirr, beanshell, just4log, ...

•ASM: jardiff, javaflow, groovy, cobertura, aspectwerkz, beanshell, retroweaver, ...

Page 16: No dark magic - Byte code engineering in the real world

demo

Page 17: No dark magic - Byte code engineering in the real world

Generation

Page 18: No dark magic - Byte code engineering in the real world

XSLTC

•XSLT to java compiler

•Creates a translet from xslt

•Translet as JAXP transformer

Page 19: No dark magic - Byte code engineering in the real world

XSLTC

XSLT Parser

SAX Parser XPath Parser

XSLT Compiler

BCEL class

na

tive

AP

I

JA

XP

/ T

rAX

AP

I

*.xsl

*.xml

Page 20: No dark magic - Byte code engineering in the real world

XSLTC Speed

gregor msxml jd.xslt xsltc saxon xalan-j

Page 21: No dark magic - Byte code engineering in the real world

Groovy

ASM ClassVisitor class

Groovy Parsergroovy

source

Page 22: No dark magic - Byte code engineering in the real world

Analysis

Page 23: No dark magic - Byte code engineering in the real world

Findbugs

•Static analysis for bug patterns

•False positives

Page 24: No dark magic - Byte code engineering in the real world

Findbugs

Page 25: No dark magic - Byte code engineering in the real world

Findbugs

Page 26: No dark magic - Byte code engineering in the real world

Clirr / Jardiff

•Diff for jars or class files

•Detecting API changes

Page 27: No dark magic - Byte code engineering in the real world

Jardiff

Page 28: No dark magic - Byte code engineering in the real world

Jardiff

Page 29: No dark magic - Byte code engineering in the real world

Dependency

•Analyses class dependencies

•Finding unused classes

•Renaming classes

http://vafer.org/projects/dependency

Page 30: No dark magic - Byte code engineering in the real world

Dependency

Set dependencies = DependencyUtils .getDependenciesOfClass( Class1.class );

Page 31: No dark magic - Byte code engineering in the real world

Dependency

new ResourceRenamer() { String getNewNameFor(String oldName) { if (oldName.startsWith( "java.util.HashMap")) { return "my." + oldName; } return oldName;}

Page 32: No dark magic - Byte code engineering in the real world

Modification

Page 33: No dark magic - Byte code engineering in the real world

Cobertura / Clover

•Testcase coverage

•Recording the execution path

•Maven plugin

Page 34: No dark magic - Byte code engineering in the real world

Cobertura

Page 35: No dark magic - Byte code engineering in the real world

Cobertura

Page 36: No dark magic - Byte code engineering in the real world

Throttling

•Wrap Socket to deliver throughput according to settings

•Cannot rewrite java.* classes

Page 37: No dark magic - Byte code engineering in the real world

Retroweaver

•Compile with jdk 1.5 features, run on 1.4

•Static conversion

•Runtime conversion

Page 38: No dark magic - Byte code engineering in the real world

Just4log

for(int i=0; i<500000; i++) { if(log.isDebugEnabled()) { log.debug("message" + someLongTaskToExecute()); } normalCodeToExecute();}

for(int i=0; i<500000; i++) { if(log.isDebugEnabled()) { log.debug("message" + someLongTaskToExecute()); } normalCodeToExecute();}

Page 39: No dark magic - Byte code engineering in the real world

AspectJ

public aspect LogAspect{ declare precedence : LogAspect, *;

pointcut voidCalls() : !within(LogAspect) && execution(void *.*(..)) );

Page 40: No dark magic - Byte code engineering in the real world

AspectJ

Object around() : voidCalls() {

Signature sig = thisJoinPoint.getSignature(); log.debug('<' + getFullSig(thisJoinPoint)); Object result = proceed(); log.debug('>' + sig.getName());

return result;

Page 41: No dark magic - Byte code engineering in the real world

Javaflow

class MyRunnable implements Runnable { public void run() { for(int i=0; i<10; i++ ) Continuation.suspend(); }}Continuation c = Continuation.startWith( new MyRunnable());Continuation d = Continuation.continueWith(c);...

Page 42: No dark magic - Byte code engineering in the real world

Javaflow

Page 43: No dark magic - Byte code engineering in the real world

What you can do

•reflection without j.l.reflection

•generate classes on the fly

•implement interface on the fly

Page 44: No dark magic - Byte code engineering in the real world

What you can do

•change visibility

•extend classes that are final

•modify vs forking

•...

Page 45: No dark magic - Byte code engineering in the real world

Thanks!