Your SlideShare is downloading. ×
0
Main sponsorMastering Java Bytecode       With ASM       Anton Arhipov
MeAnton ArhipovJRebel @Product manager byday, coding monkey bynightanton@zeroturnaround.com@antonarhipov
Bytecode• One-byte instructions• 256 possible opcodes (200+ in use)• Stack based (pop, push)
ASM• Low-level API for bytecode crunching  • Core API – visitors  • Tree API – nodes    • Analysis package• http://asm.ow2...
Why?• Compilers for JVM• Programming model (AOP, ORM)• Awesome tools for JVM
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
Basic Process• Construct ClassWriter• Stack up the visitors for:  • annotations, methods, fields, etc• Write out bytes
javap
ClassWriterClassWriter cw = new ClassWriter(     ClassWriter.COMPUTE_MAXS |     ClassWriter.COMPUTE_FRAMES);
Visit Classcw.visit(   Opcodes.V1_6,   Opcodes.ACC_PUBLIC,   "zt/asm/Items",   null,   "java/lang/Object",   new String[] ...
Visit Classcw.visit(   Opcodes.V1_6,   Opcodes.ACC_PUBLIC,   "zt/asm/Items",   null,   "java/lang/Object",   new String[] ...
Visit Classcw.visit(   Opcodes.V1_6,   Opcodes.ACC_PUBLIC,   "zt/asm/Items",   null,   "java/lang/Object",   new String[] ...
Visit Classcw.visit(   Opcodes.V1_6,   Opcodes.ACC_PUBLIC,   "zt/asm/Items",   null,   "java/lang/Object",   new String[] ...
Visit Classcw.visit(   Opcodes.V1_6,   Opcodes.ACC_PUBLIC,   "zt/asm/Items",   null,   "java/lang/Object",   new String[] ...
Fieldprivate List<Integer> ids       = new ArrayList<Integer>();private List<Integer> ids;public Items() {  ids = new Arra...
Visit FieldFieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;",...
Visit FieldFieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;",...
Descriptor• Primitives  • B, C, S, I, J, F, D, Z, V• References  • Ljava/lang/Object;• Arrays  • Prefixed with [, i.e. [Lj...
Descriptor  Ljava/util/List;([Ljava/lang/String;)V
org.objectweb.asm.TypeType.getObjectType("java/lang/String")         Ljava/lang/String;
Visit MethodMethodVisitor constructor =   cw.visitMethod(      Opcodes.ACC_PUBLIC,      "<init>",      "()V",      null,  ...
Visit MethodMethodVisitor get =   cw.visitMethod(      Opcodes.ACC_PUBLIC,      "get",      "(I)I",      null,      null);
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
super()   0: aload_0   1: invokespecial #1 // Object.<init>MethodVisitor mv = …mv.visitVarInsn(ALOAD, 0);mv.visitMethodIns...
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
Assignment 4:   aload_0 5:   new           #2 // ArrayList 8:   dup 9:   invokespecial #3 // <init>12:   putfield      #4 ...
Assignment                       Create instance 4:   aload_0 5:   new           #2 // ArrayList 8:   dup 9:   invokespeci...
Assignment 4:   aload_0 5:   new           #2 // ArrayList 8:   dup 9:   invokespecial #3 // <init>12:   putfield      #4 ...
Assignment 5:   new           #2 // ArrayList 8:   dup 9:   invokespecial #3 // <init>12:   astore_1      #4 // ids       ...
Assignmentmv.visitVarInsn(ALOAD, 0);mv.visitTypeInsn(NEW, "java/util/ArrayList");mv.visitInsn(DUP);mv.visitMethodInsn(INVO...
Assignmentmv.visitVarInsn(ALOAD, 0);mv.visitTypeInsn(NEW, "java/util/ArrayList");mv.visitInsn(DUP);mv.visitMethodInsn(INVO...
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
public Items() {    super();    ids = new ArrayList<Integer>();    ids.add(1);    ids.add(100);    ids.add(100000);}
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(1)15:   aload_016:   getfield   #4 // ids19:   iconst_120:   invokestatic #5 // Integer.valueOf23:   invokeinterfa...
ids.add(100)15:   aload_016:   getfield   #4 // ids19:   bipush 10020:   invokestatic #5 // Integer.valueOf23:   invokeint...
ids.add(100_000)15:   aload_016:   getfield   #4 // ids19:   ldc #7 // int 10000020:   invokestatic #5 // Integer.valueOf2...
mv.visitVarInsn(ALOAD, 0);mv.visitFieldInsn(GETFIELD,"zt/asm/Items", "ids","Ljava/util/List;");mv.visitInsn(ICONST_1);mv.v...
public class Items implements Serializable {  private List<Integer> ids       = new ArrayList<Integer>();  {    ids.add(1)...
ASMifiedmv = cw.visitMethod(ACC_PUBLIC, "getId", "(I)I", null, null);mv.visitCode();Label l0 = new Label();mv.visitLabel(l...
ASMifiedmv = cw.visitMethod(ACC_PUBLIC, "getId", "(I)I", null, null);mv.visitCode();Label l0 = new Label();  java -cp asm-...
javappublic class zt.asm.deg.Items {  public java.util.List<java.lang.Integer> ids;    public int getId(int);       Code: ...
Groovyfiedpublic class zt/asm/Items {   public Ljava/util/List; ids    @groovyx.ast.bytecode.Bytecode    public int getId(...
Generating bytecode            from scratch                     is too simple …Transforming the bytecode is               ...
Instrument  some bytecode
Ninja.class   Ninja.class’10101010101   1010101010111000101010   1110000101010101010001   1010101000100010001110   0001000...
How?• Add –javaagent to hook into class loading  process• Implement ClassFileTransformer• Use bytecode manipulation librar...
How ? (2)• Use custom ClassLoader  – Override ClassLoader#findClass  – Use ClassReader(String) to read the class    in and...
java.lang.instrumentimport java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;public cl...
java.lang.instrumentimport java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;public cl...
java.lang.instrumentimport java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;public cl...
j.l.instrument.ClassFileTransformernew ClassFileTransformer() {  public byte[] transform(ClassLoader loader, String classN...
j.l.instrument.ClassFileTransformernew ClassFileTransformer() {  public byte[] transform(ClassLoader loader, String classN...
j.l.instrument.ClassFileTransformernew ClassFileTransformer() {  public byte[] transform(ClassLoader loader, String classN...
public class MyClassLoader extends ClassLoader { protected Class findClass(String name)                          throws Cl...
SLIDESGOTO IDESLIDESIDE: DEMO
@antonarhipovanton@zeroturnaround.com
Mastering Java Bytecode With ASM - 33rd degree, 2012
Upcoming SlideShare
Loading in...5
×

Mastering Java Bytecode With ASM - 33rd degree, 2012

7,864

Published on

Published in: Technology, Education
1 Comment
24 Likes
Statistics
Notes
No Downloads
Views
Total Views
7,864
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
179
Comments
1
Likes
24
Embeds 0
No embeds

No notes for slide
  • Programs are composed of classes, classes are thebytecode, blah blahblahJava bytecode is stack based: most of the operations push to the stack of consume values from the stack
  • ObjectWeb ASM is the de-facto standard decomposing, modifying, and recomposing Javabytecode. ASM provides a simple library that exposes the internal aggregate components of a given Java class through its visitor oriented API. On top of visitor API ASM provides tree API that represents classes as object constructs.ASM is very popular and is used widely in various Java open-source projects. In fact, this could be the primary motivation for someone the learn this library.
  • Why would learn Java bytecode and ASM at all?Well, creating a brand new JVM language might be a good idea  This is what all the cool kids are doing, right?Secondly – programming model that is exposed by many frameworks is backed with bytecode generation or instrumentation. AspectJ, for instance uses bytecode instrumentation extensively.Also, there are some many awesome tools that do awesome stuff, like …. JRebel for instance 
  • This presentation gives some pointe
  • Let’s start with an example: the class “Items” implements an interface,…
  • Includes a field declaration &amp; assignment,..
  • Initializer block, ..
  • and a virtual method.
  • The most common scenario to generate bytecode that corresponds to the example source, is to create ClassWriter, visit the structure – fields, methods, etc, and after the job is done, write out the final bytes.
  • Actually, before going further, let’s mention javap– the Java class disassembler. The output of javap command isn’t particularly useful as there’s no way to modify it and compile back to the executable code. However, it is much more easier to read the bytecodes produced by javap, rather than the code that is written using ASM API. So, javap is good for reference when studying the bytecode.
  • Let’s go on and construct a ClassWriter.. The constructor takes anint which is composed of different flags.COMPUTE_MAXS says that the sizes of local variables and operand stack parts will be computed automatically. Still have to call visitMaxs with any argumentsCOMPUTE_FRAMES – everything is computed automatically. ASM will compute the stack map, still have to call visitMaxs
  • To create class signature, we’ll call ClassWriter#visit methodThe interface is full of constants, as one may notice.
  • Java version. V1_1 – V1_7 are available.
  • Accessor modifiers:ACC_PUBLIC, ACC_PRIVATEACC_SYNTHETIC, ACC_BRIDGE
  • Types declared as strings 
  • Even this API call, not that complex, but looks ugly
  • Field declaration with assignment is actually split between the field declaration for the class, and assignment is performed in constructor. So this is something we need to keep in mind when generating the code.
  • fisitField method creates the field declaration
  • The ugliest part of ASM API is the descriptiors. Sorry, I’d like to rant the library a bit on this one 
  • Blah blah descriptors, blah blah descriptors, blah blah…
  • some descriptor examples…
  • Fortunately, Type can help a bit with all this descriptor mess
  • Let’s generate some methods nowFirst of all, the constructor. There isn’t a special API to generate a constructor, only the special name, &lt;init&gt;, tells that the method is actually a constructor.
  • The real method isn’t any different from the constructor from the API point of view
  • Now it is time to generate the constructor body
  • The constructor consists of super() callField assignmentSome method calls
  • The super() call for the regular class is the call to Obect.&lt;init&gt;
  • Assigning a value to a field takes a series of opcodes to complete
  • At first the value has to be created and placed on the stack
  • Next,putfield, putstatic or xstoreopcode can be used to assign the value to the required location
  • The ASM code doesn’t look very different to the javap-like code, besides all the noise it brings
  • After the field is initialized, let’s add some values to the list: a byte, a short and an integer
  • Adding the values to the list results in method calls with a parameter. The parameter has to be loaded to the stack in order to be passed to a method.As the autoboxing takes place, Integer.valueOf is called in order to add an Integer to the List
  • The ASM code is getting uglier… and the captain doesn’t like it.
  • Let’s take a step back and select a shortcut for the taks
  • ASM code can be easily generated
  • ... using ASMifierClassVisitor (ASMifier in ASM4). The output is rather noisy, with all the labels,but the noise is easy to remove.
  • However,javap output is still the cleanest and easiest to read and there are some alternatives to ASM visitor API
  • For instance, Groovy AST transformations make it possible to write code which is very close to javap output.
  • Transcript of "Mastering Java Bytecode With ASM - 33rd degree, 2012"

    1. 1. Main sponsorMastering Java Bytecode With ASM Anton Arhipov
    2. 2. MeAnton ArhipovJRebel @Product manager byday, coding monkey bynightanton@zeroturnaround.com@antonarhipov
    3. 3. Bytecode• One-byte instructions• 256 possible opcodes (200+ in use)• Stack based (pop, push)
    4. 4. ASM• Low-level API for bytecode crunching • Core API – visitors • Tree API – nodes • Analysis package• http://asm.ow2.org
    5. 5. Why?• Compilers for JVM• Programming model (AOP, ORM)• Awesome tools for JVM
    6. 6. 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); }}
    7. 7. 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); }}
    8. 8. 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); }}
    9. 9. 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); }}
    10. 10. 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); }}
    11. 11. Basic Process• Construct ClassWriter• Stack up the visitors for: • annotations, methods, fields, etc• Write out bytes
    12. 12. javap
    13. 13. ClassWriterClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    14. 14. Visit Classcw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});
    15. 15. Visit Classcw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});
    16. 16. Visit Classcw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});
    17. 17. Visit Classcw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});
    18. 18. Visit Classcw.visit( Opcodes.V1_6, Opcodes.ACC_PUBLIC, "zt/asm/Items", null, "java/lang/Object", new String[] {"java/io/Serializable"});
    19. 19. Fieldprivate List<Integer> ids = new ArrayList<Integer>();private List<Integer> ids;public Items() { ids = new ArrayList<Integer>();}
    20. 20. Visit FieldFieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;", null);
    21. 21. Visit FieldFieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE,"ids","Ljava/util/List;","Ljava/util/List<Lj/l/Integer;>;", null);
    22. 22. Descriptor• Primitives • B, C, S, I, J, F, D, Z, V• References • Ljava/lang/Object;• Arrays • Prefixed with [, i.e. [Ljava/lang/Object;
    23. 23. Descriptor Ljava/util/List;([Ljava/lang/String;)V
    24. 24. org.objectweb.asm.TypeType.getObjectType("java/lang/String") Ljava/lang/String;
    25. 25. Visit MethodMethodVisitor constructor = cw.visitMethod( Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
    26. 26. Visit MethodMethodVisitor get = cw.visitMethod( Opcodes.ACC_PUBLIC, "get", "(I)I", null, null);
    27. 27. 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); }}
    28. 28. 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); }}
    29. 29. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    30. 30. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    31. 31. super() 0: aload_0 1: invokespecial #1 // Object.<init>MethodVisitor mv = …mv.visitVarInsn(ALOAD, 0);mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
    32. 32. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    33. 33. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    34. 34. Assignment 4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids
    35. 35. Assignment Create instance 4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids
    36. 36. Assignment 4: aload_0 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: putfield #4 // ids Assign to a field
    37. 37. Assignment 5: new #2 // ArrayList 8: dup 9: invokespecial #3 // <init>12: astore_1 #4 // ids Assign to local variable
    38. 38. Assignmentmv.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;");
    39. 39. Assignmentmv.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;");
    40. 40. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    41. 41. public Items() { super(); ids = new ArrayList<Integer>(); ids.add(1); ids.add(100); ids.add(100000);}
    42. 42. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    43. 43. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    44. 44. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    45. 45. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    46. 46. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    47. 47. ids.add(1)15: aload_016: getfield #4 // ids19: iconst_120: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    48. 48. ids.add(100)15: aload_016: getfield #4 // ids19: bipush 10020: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    49. 49. ids.add(100_000)15: aload_016: getfield #4 // ids19: ldc #7 // int 10000020: invokestatic #5 // Integer.valueOf23: invokeinterface #6, 2 // List.add28: pop
    50. 50. 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);
    51. 51. 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); }}
    52. 52. 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();
    53. 53. ASMifiedmv = cw.visitMethod(ACC_PUBLIC, "getId", "(I)I", null, null);mv.visitCode();Label l0 = new Label(); java -cp asm-all-3.3.1.jar:asm-util-3.3.1.jar mv.visitLabel(l0);mv.visitLineNumber(16, l0); org.objectweb.asm.util.ASMifierClassVisitor mv.visitVarInsn(ALOAD, 0); Items.classmv.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();
    54. 54. 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}
    55. 55. 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
    56. 56. Generating bytecode from scratch is too simple …Transforming the bytecode is much more fun! 
    57. 57. Instrument some bytecode
    58. 58. Ninja.class Ninja.class’10101010101 1010101010111000101010 1110000101010101010001 1010101000100010001110 0001000111011011101011 11011101110
    59. 59. 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
    60. 60. 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
    61. 61. java.lang.instrumentimport 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); }}
    62. 62. java.lang.instrumentimport 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); }}
    63. 63. java.lang.instrumentimport 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.MF Premain-Class: Agent java –javaagent:agent.jar … Agent-Class: Agent
    64. 64. 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();}
    65. 65. 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();}
    66. 66. 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();}
    67. 67. 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); }
    68. 68. SLIDESGOTO IDESLIDESIDE: DEMO
    69. 69. @antonarhipovanton@zeroturnaround.com
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×