2. whoami
Anton Arhipov
Java Dev / Product Lead
ZeroTurnaround, JRebel
Messing with bytecode since 2010
anton@zeroturnaround.com
@antonarhipov @javarebel
3. whoami
Anton Arhipov
Java Dev / Product Lead
ZeroTurnaround, JRebel
Messing with bytecode since 2010
anton@zeroturnaround.com
@antonarhipov @javarebel
4. Why Bytecode?
• Know your platform!
• Build your own JVM language?
• Programming models (AOP, ORM)
• Awesome tools (like JRebel )
... just bored?
5. Bytecode 101 Instrumentation API
javap ObjectWeb ASM
51. javap
• Java class file disassembler
• Used with no options shows class structure only
– Methods, superclass, interfaces, etc
• -c shows the bytecode
• -private shows all methods and members
• -s prints internal signatures
• -l prints line numbers and local variable tables
• -verbose for verbosity
54. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code: the default constructor
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
55. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code: push this to stack
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
56. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
invoke <init> on this
57. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V super()
4: return
58. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
59. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
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
60. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
get static field
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
61. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
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
load string to the stack
62. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
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
invoke method with parameter
63. C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
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
64. What’s #1,#2, etc ?
C:workgeeconclasses>javap Hello -c
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
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
99. Enter ASM Loops
Label start = new Label();
Label loop = new Label();
Label end = new Label();
// i = 0
mv.visitLabel(start);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 1);
100. Enter ASM Loops
Label start = new Label();
Label loop = new Label();
Label end = new Label();
// i = 0
mv.visitLabel(start);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 1);
// i < 10
mv.visitLabel(loop);
mv.visitVarInsn(ILOAD, 1);
mv.visitLdcInsn(10);
mv.visitJumpInsn(IF_ICMPGE, end);
101. Enter ASM Loops
Label start = new Label();
Label loop = new Label();
Label end = new Label(); //increment & continue the loop
mv.visitIincInsn(1, 1);
// i = 0 mv.visitJumpInsn(GOTO, loop);
mv.visitLabel(start); mv.visitLabel(end);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 1);
// i < 10
mv.visitLabel(loop);
mv.visitVarInsn(ILOAD, 1);
mv.visitLdcInsn(10);
mv.visitJumpInsn(IF_ICMPGE, end);
109. 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
110. 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
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 provides some pointers to the subject
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.
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.
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
... using ASMifierClassVisitor (ASMifier in ASM4). The output is rather noisy, with all the labels,but the noise is easy to remove.