Mastering Java Bytecode With ASM - 33rd degree, 2012

70
Main sponsor Mastering Java Bytecode With ASM Anton Arhipov

description

 

Transcript of Mastering Java Bytecode With ASM - 33rd degree, 2012

Page 1: Mastering Java Bytecode With ASM - 33rd degree, 2012

Main sponsor

Mastering Java Bytecode With ASMAnton Arhipov

Page 2: Mastering Java Bytecode With ASM - 33rd degree, 2012

Me

Anton ArhipovJRebel @Product manager by day, coding monkey by night

[email protected]@antonarhipov

Page 3: Mastering Java Bytecode With ASM - 33rd degree, 2012

Bytecode

• One-byte instructions• 256 possible opcodes (200+ in use)• Stack based (pop, push)

Page 4: Mastering Java Bytecode With ASM - 33rd degree, 2012

ASM

• Low-level API for bytecode crunching• Core API – visitors• Tree API – nodes• Analysis package

• http://asm.ow2.org

Page 5: Mastering Java Bytecode With ASM - 33rd degree, 2012

Why?

• Compilers for JVM• Programming model (AOP, ORM)• Awesome tools for JVM

JRebel

Page 6: Mastering Java Bytecode With ASM - 33rd degree, 2012
Page 7: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 8: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 9: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 10: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 11: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 12: Mastering Java Bytecode With ASM - 33rd degree, 2012

Basic Process

• Construct ClassWriter• Stack up the visitors for:• annotations, methods, fields, etc

• Write out bytes

Page 13: Mastering Java Bytecode With ASM - 33rd degree, 2012

javap

Page 14: Mastering Java Bytecode With ASM - 33rd degree, 2012

ClassWriter

ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

Page 15: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Class cw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});

Page 16: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Class cw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});

Page 17: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Class cw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});

Page 18: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Class cw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});

Page 19: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Class cw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});

Page 20: Mastering Java Bytecode With ASM - 33rd degree, 2012

Fieldprivate List<Integer> ids = new ArrayList<Integer>();

private List<Integer> ids;

public Items() { ids = new ArrayList<Integer>();}

Page 21: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Field

FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;", null);

Page 22: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Field

FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;", null);

Page 23: Mastering Java Bytecode With ASM - 33rd degree, 2012

Descriptor

• Primitives• B, C, S, I, J, F, D, Z, V

• References• Ljava/lang/Object;

• Arrays• Prefixed with [, i.e. [Ljava/lang/Object;

Page 24: Mastering Java Bytecode With ASM - 33rd degree, 2012

Descriptor

([Ljava/lang/String;)V

Ljava/util/List;

Page 25: Mastering Java Bytecode With ASM - 33rd degree, 2012

org.objectweb.asm.Type

Type.getObjectType("java/lang/String")

Ljava/lang/String;

Page 26: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Method

MethodVisitor constructor = cw.visitMethod( Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);

Page 27: Mastering Java Bytecode With ASM - 33rd degree, 2012

Visit Method

MethodVisitor get = cw.visitMethod( Opcodes.ACC_PUBLIC, "get", "(I)I", null, null);

Page 28: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 29: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 30: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 31: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 32: Mastering Java Bytecode With ASM - 33rd degree, 2012

0: aload_0 1: invokespecial #1 // Object.<init>

super()

MethodVisitor mv = …

mv.visitVarInsn(ALOAD, 0);mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");

Page 33: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 34: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 35: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids

Page 36: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids

Create instance

Page 37: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids

Assign to a field

Page 38: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: astore_1 #4 // ids

Assign to local variable

Page 39: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

mv.visitVarInsn(ALOAD, 0);mv.visitTypeInsn(NEW, "java/util/ArrayList");mv.visitInsn(DUP);mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");mv.visitFieldInsn(PUTFIELD, "zt/asm/Items", "ids", "Ljava/util/List;");

Page 40: Mastering Java Bytecode With ASM - 33rd degree, 2012

Assignment

mv.visitVarInsn(ALOAD, 0);mv.visitTypeInsn(NEW, "java/util/ArrayList");mv.visitInsn(DUP);mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");mv.visitFieldInsn(PUTFIELD, "zt/asm/Items", "ids", "Ljava/util/List;");

Page 41: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 42: Mastering Java Bytecode With ASM - 33rd degree, 2012

public Items() { super();

ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}

Page 43: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 44: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 45: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 46: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 47: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 48: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: iconst_1 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(1)

Page 49: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: bipush 10020: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(100)

Page 50: Mastering Java Bytecode With ASM - 33rd degree, 2012

15: aload_0 16: getfield #4 // ids19: ldc #7 // int 100000 20: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop

ids.add(100_000)

Page 51: Mastering Java Bytecode With ASM - 33rd degree, 2012

mv.visitVarInsn(ALOAD, 0);mv.visitFieldInsn(GETFIELD, "zt/asm/Items", "ids", "Ljava/util/List;");mv.visitInsn(ICONST_1);mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");mv.visitInsn(POP);

Page 52: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class Items implements Serializable { private List<Integer> ids = new ArrayList<Integer>(); { ids.add(1); ids.add(100); ids.add(100000); }

public int getId(int i) { return ids.get(i); }}

Page 53: Mastering Java Bytecode With ASM - 33rd degree, 2012

ASMifiedmv = cw.visitMethod(ACC_PUBLIC, "getId", "(I)I", null, null);mv.visitCode();Label l0 = new Label();mv.visitLabel(l0);mv.visitLineNumber(16, l0);mv.visitVarInsn(ALOAD, 0);mv.visitFieldInsn(GETFIELD, "zt/asm/Items", "ids", "Ljava/util/List;");mv.visitVarInsn(ILOAD, 1);mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");mv.visitInsn(IRETURN);Label l1 = new Label();mv.visitLabel(l1);mv.visitLocalVariable("this", "Lzt/asm/Items;", null, l0, l1, 0);mv.visitLocalVariable("i", "I", null, l0, l1, 1);mv.visitMaxs(2, 2);mv.visitEnd();

Page 54: Mastering Java Bytecode With ASM - 33rd degree, 2012

ASMifiedmv = cw.visitMethod(ACC_PUBLIC, "getId", "(I)I", null, null);mv.visitCode();Label l0 = new Label();mv.visitLabel(l0);mv.visitLineNumber(16, l0);mv.visitVarInsn(ALOAD, 0);mv.visitFieldInsn(GETFIELD, "zt/asm/Items", "ids", "Ljava/util/List;");mv.visitVarInsn(ILOAD, 1);mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");mv.visitInsn(IRETURN);Label l1 = new Label();mv.visitLabel(l1);mv.visitLocalVariable("this", "Lzt/asm/Items;", null, l0, l1, 0);mv.visitLocalVariable("i", "I", null, l0, l1, 1);mv.visitMaxs(2, 2);mv.visitEnd();

java -cp asm-all-3.3.1.jar:asm-util-3.3.1.jar \org.objectweb.asm.util.ASMifierClassVisitor \Items.class

Page 55: Mastering Java Bytecode With ASM - 33rd degree, 2012

javappublic class zt.asm.deg.Items { public java.util.List<java.lang.Integer> ids;

public int getId(int); Code: 0: aload_0 1: getfield #4 4: iload_1 5: invokeinterface #8, 2 10: checkcast #9 13: invokevirtual #10 16: ireturn }

Page 56: Mastering Java Bytecode With ASM - 33rd degree, 2012

Groovyfiedpublic class zt/asm/Items { public Ljava/util/List; ids

@groovyx.ast.bytecode.Bytecode public int getId(int a) { aload 0 getfield zt.asm.Items.ids >> List iload 1 invokeinterface List.get(int) >> Object checkcast Integer invokevirtual Integer.intValue() >> int ireturn }}

https://github.com/melix/groovy-bytecode-ast

Page 57: Mastering Java Bytecode With ASM - 33rd degree, 2012

Generating bytecode from scratch is too simple …

Transforming the bytecode is much more fun!

Page 58: Mastering Java Bytecode With ASM - 33rd degree, 2012

Instrumentsome bytecode

Page 59: Mastering Java Bytecode With ASM - 33rd degree, 2012

1010101010111000101010101010100010001000111011011101011

1010101010111100001010101010100010001000111011011101110

Ninja.class Ninja.class’

Page 60: Mastering Java Bytecode With ASM - 33rd degree, 2012

How?

• Add –javaagent to hook into class loading process

• Implement ClassFileTransformer• Use bytecode manipulation libraries (Javassist,

cglib, asm) to add any custom logic

java.lang.instrument

Page 61: Mastering Java Bytecode With ASM - 33rd degree, 2012

How ? (2)

• Use custom ClassLoader–Override ClassLoader#findClass–Use ClassReader(String) to read the class

in and transform it via visitor chain–Call ClassLoader#defineClass explicitly

with the result from the transformation step

Page 62: Mastering Java Bytecode With ASM - 33rd degree, 2012

java.lang.instrument

import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;

public class Agent {public static void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer(), true); }

public static void agentmain(String args, Instrumentation inst) { premain(args,inst); }}

Page 63: Mastering Java Bytecode With ASM - 33rd degree, 2012

java.lang.instrument

import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;

public class Agent {public static void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer(), true); }

public static void agentmain(String args, Instrumentation inst) { premain(args,inst); }}

Page 64: Mastering Java Bytecode With ASM - 33rd degree, 2012

java.lang.instrument

import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;

public class Agent {public static void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer(), true); }

public static void agentmain(String args, Instrumentation inst) { premain(args,inst); }}

META-INF/MANIFEST.MFPremain-Class: AgentAgent-Class: Agent

java –javaagent:agent.jar …

Page 65: Mastering Java Bytecode With ASM - 33rd degree, 2012

j.l.instrument.ClassFileTransformernew ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); MyAdapter ca = new MyAdapter(cw); cr.accept(ca, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); }

Page 66: Mastering Java Bytecode With ASM - 33rd degree, 2012

j.l.instrument.ClassFileTransformernew ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); MyAdapter ca = new MyAdapter(cw); cr.accept(ca, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); }

Page 67: Mastering Java Bytecode With ASM - 33rd degree, 2012

j.l.instrument.ClassFileTransformernew ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

MyAdapter ca = new MyAdapter(cw); cr.accept(ca, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); }

Page 68: Mastering Java Bytecode With ASM - 33rd degree, 2012

public class MyClassLoader extends ClassLoader {

protected Class findClass(String name) throws ClassNotFoundException {

ClassReader cr = new ClassReader(name); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

MyClassAdapter ca = new MyClassAdapter(cw);

cr.accept(ca, ClassReader.EXPAND_FRAMES);

byte b[] = cw.toByteArray(); return defineClass(name, b, 0, b.length); }

}

Page 69: Mastering Java Bytecode With ASM - 33rd degree, 2012

SLIDESGOTO IDESLIDESIDE: DEMO

Page 70: Mastering Java Bytecode With ASM - 33rd degree, 2012

@antonarhipov

[email protected]