KEMBAR78
Mastering Java ByteCode | PPT
Mastering byte code
The master plan

•   JVM
•   javap
•   opcode
•   ClassLoader
•   Toolkits
•   Puzzles
Stack

1+2

      PUSH 1     1
12+   PUSH 2     2
Stack

1+2

      PUSH 1     3
12+   PUSH 2
      ADD
Stack

1+2

      ICONST_1     3
12+   ICONST_2
      IADD
Frame
Local Variables & Stack
Java Stack Machine

•   JVM is a stack-based machine
•   Each thread has a stack
•   Stack stores frames
•   Frame is created on method invocation
•   Frame:
     o
       Operand stack
     o
       Array of local variables
     o
       Reference to the runtime constant pool
Compiling to binary

C/C++ (*.h, *.cpp)   Java (*.java)



Assembler                     Bytecode


Intel opcode                 Sun opcode
javap
•   Java class file disassembler
•   Used with no options shows class
    structure only
•   Methods, superclass, interfaces, etc
•   -c – shows the bytecode
•   -private – shows all classes and
    members
•   -s – prints internal types signatures
•   -verbose – prints stack size, number of
    locals and args for methods
javap -c -verbose Clazz
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c
Compiled from "SimpleProgram.java"
public class SimpleProgram extends java.lang.Object{
public SimpleProgram();
    Code:
    0:   aload_0
    1:   invokespecial    #1; //Method java/lang/Object."":()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 Java Fusion!
    5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    8:   return

}
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c
Compiled from "SimpleProgram.java"
public class SimpleProgram extends java.lang.Object{
public SimpleProgram();// The default constructor
 Code:
    0:   aload_0 //Push this sto stack
    1:   invokespecial #1; //Method java/lang/Object."":()V //Invoke <init> on this
    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 Java Fusion!
    5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    8:   return


}
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c
Compiled from "SimpleProgram.java"
public class SimpleProgram extends java.lang.Object{
public SimpleProgram();
    Code:
    0:   aload_0
    1:   invokespecial   #1; //Method java/lang/Object."":()V
    4:   return
public static void main(java.lang.String[]);
    Code:
    0:   getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; //get static field
    3:   ldc #3; //String Hello Java Fusion! //Load String to the stack
    5:   invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V //invoke method with parameter
    8:   return


}
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c
Compiled from "SimpleProgram.java"
public class SimpleProgram extends java.lang.Object{
public SimpleProgram();
    Code:
    0:   aload_0
    1:   invokespecial    #1; //Method java/lang/Object."":()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 Java Fusion!
    5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
    8:   return

}
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}

javap SimpleProgram -c -verbose
Compiled from "SimpleProgram.java“
public class SimpleProgram extends java.lang.Object
SourceFile: "SimpleProgram.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #6.#20; // java/lang/Object."<init>":()V
const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream;
const #3 = String #23; // Hello Java Fusion!
const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V
const #5 = class #26; // SimpleProgram
const #6 = class #27; // java/lang/Object
сonst #7 = Asciz <init>;
...
Bytecode

One-byte instructions
256 possible opcodes
207 in use
49 currently unassigned for opcodes and are reserved
for future use
TYPE OPERATION
Instructions fall into a number of broad groups:
•Local variables and stack interaction (e.g. aload_0,istore)
•Array operations (aload, astore)
•Arithmetic and logic (e.g. ladd,fcmpl)
•Type conversion (e.g. i2b,d2i)
•Object creation and manipulation (new, putfield)
•Operand stack management (e.g. swap,dup2)
•Control transfer (e.g. ifeq, goto)
•Method invocation and return (e.g. invokespecial,areturn)
•Operations with constant values (ldc, iconst_1)
•Math (add, sub, mul, div)
•Boolean/bitwise operations (iand, ixor)
•Comparisons (cmpg, cmpl, ifne)
•...
Opcode type
Prefix/Suffix   Operand Type
i               integer
l               long
s               short
b               byte
c               char
f               float
d               double
a               reference
public java.lang.String getName();
 Code:
 Stack=1, Locals=1, Args_size=1
 0: aload_0
 1: getfield     #2; //Field name:Ljava/lang/String;
 4: areturn
LocalVariableTable:
 Start Length Slot Name Signature
 0    5          0         this   LGet;
public java.lang.String getName();
 Code:
 Stack=1, Locals=1, Args_size=1
 0: aload_0
 1: getfield     #2; //Field name:Ljava/lang/String;
 4: areturn
LocalVariableTable:
 Start Length Slot Name Signature
 0    5          0         this   LGet;
public java.lang.String getName();
 Code:
 Stack=1, Locals=1, Args_size=1
 0: aload_0
 1: getfield     #2; //Field name:Ljava/lang/String;
 4: areturn
LocalVariableTable:
 Start Length Slot Name Signature
 0    5          0         this   LGet;
public java.lang.String getName();
 Code:
 Stack=1, Locals=1, Args_size=1
 0: aload_0
 1: getfield     #2; //Field name:Ljava/lang/String;
 4: areturn
LocalVariableTable:
 Start Length Slot Name Signature
 0    5          0         this   LGet;
ClassLoader

- Works with bytecode
- Has native methods
- Bytecode Verification via SecurityManager.class
Toolkits

JVM:
•ASM
•Javassist
•BCEL (Byte Code Engineering Library)

Jrebel
Terracotta
Common sample
public class SimpleProgram
{
  public static void main(String[] args)
  {
       System.out.println("Hello Java Fusion!");
  }
}
ASM sample
public class ASMSample extends ClassLoader implements Opcodes {
{
  public static void main(String[] args)
  {
     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null);
    }
}
ASM sample
public class ASMSample extends ClassLoader implements Opcodes {
{
  public static void main(String[] args)
  {
     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null); // creates a GeneratorAdapter
for the (implicit) constructor
      Method m = Method.getMethod("void <init> ()");
      GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
      mg.loadThis();
      mg.invokeConstructor(Type.getType(Object.class), m);
      mg.returnValue();
      mg.endMethod();
    }
}
ASM sample
public class ASMSample extends ClassLoader implements Opcodes {
{
  public static void main(String[] args)
  {
     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null);
      // creates a GeneratorAdapter for the (implicit) constructor
      Method m = Method.getMethod("void <init> ()");
      GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
      mg.loadThis();
      mg.invokeConstructor(Type.getType(Object.class), m);
      mg.returnValue();
      mg.endMethod();       // creates a GeneratorAdapter for the 'main' method
      m = Method.getMethod("void main (String[])");
      mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
      mg.getStatic(Type.getType(System.class), "out",Type.getType(PrintStream.class));
      mg.push("Hello Java Fusion!");
      mg.invokeVirtual(Type.getType(PrintStream.class),
            Method.getMethod("void println (String)"));
      mg.returnValue();
      mg.endMethod();
      cw.visitEnd();
    }
}
ASM sample
public class ASMSample extends ClassLoader implements Opcodes {
{
  public static void main(String[] args)
  {
     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null);
      // creates a GeneratorAdapter for the (implicit) constructor
      Method m = Method.getMethod("void <init> ()");
      GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
      mg.loadThis();
      mg.invokeConstructor(Type.getType(Object.class), m);
      mg.returnValue();
      mg.endMethod();
      // creates a GeneratorAdapter for the 'main' method
      m = Method.getMethod("void main (String[])");
      mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
      mg.getStatic(Type.getType(System.class), "out",Type.getType(PrintStream.class));
      mg.push("Hello Java Fusion!");
      mg.invokeVirtual(Type.getType(PrintStream.class),
            Method.getMethod("void println (String)"));
      mg.returnValue();
      mg.endMethod();
      cw.visitEnd();    byte[] code = cw.toByteArray();
      ASMSample loader = new ASMSample ();
      Class<?> exampleClass = loader.defineClass("SimpleProgram", code, 0, code.length);
      // uses the dynamically generated class to print 'Hello Java Fusion'
      exampleClass.getMethods()[0].invoke(null, new Object[] { null } );
    }
}
ASM vs. Javassist
•        Javassist source level API is much easier to use than the
actual bytecode manipulation in ASM
•       Javassist provides a higher level abstraction layer over complex
bytecode level operations. Javassist source level API requires very less or
no knowledge of actual bytecodes, so much easier & faster to
implement.
•      Javassist uses reflection mechanism which makes it slower
compared to ASM which uses Classworking techniques at runtime.
•          Overall ASM is much faster & gives better performance than
Javassist. Javassist uses a simplified version of Java source code, which
it then compiles into bytecode. That makes Javassist very easy to use, but
it also limits the use of bytecode to what can be expressed within the limits
of the Javassist source code.
•       In conclusion, if someone needs easier way of dynamically
manipulating or creating Java classes Javassist API should be used &
where the performance is the key issue ASM library should be used.
JRebel
Redeploying sucks, so JRebel
eliminates it. How?


    JRebel maps your project workspace directly to the
  application under development. When you change any
 class or resource in your IDE, the change is immediately
     reflected in the application, skipping the build and
                       redeploy phases.
How JRebel works
1) Classes


• JRebel integrates with the JVM and rewrites each class to be
updateable
• JRebel versions each class individually, instead of an application or
  module at a time
• It does not use classloaders!
• Changes to classes are always visible in the Reflection API
How JRebel works
2) Workspace mapping




                                                petclinic.war

                            • JRebel integrates with application
                              servers, frameworks and your IDE
                            • When a class or resource is being
                              looked up, JRebel redirects straight
                              to the workspace
                            • When an HTTP resource needs to
                              be served, JRebel serves it from the
                              workspace
Size and speed issues
Size and speed issues




top1 and top2 are functionally identical
Size and speed issues
Method int top1()
 0 aload_0          //Push the object reference(this) at index
              //0 of the local variable table.
 1 getfield #6 <Field int intArr[]>
              //Pop the object reference(this) and push
              //the object reference for intArr accessed
              //from the constant pool.
 4 iconst_0         //Push 0.
 5 iaload         //Pop the top two values and push the
              //value at index 0 of intArr.
 6 ireturn        //Pop top value and push it on the operand
              //stack of the invoking method. Exit.
Size and speed issues
Method int top2()
 0 aload_0
 1 astore_2
 2 aload_2
 3 monitorenter
    4 aload_0
    5 getfield #6 <Field int intArr[]>
    8 iconst_0       //Push 0.
    9 iaload
    10 istore_1
    11 jsr 19
    14 iload_1       .
    15 ireturn
    16 aload_2
    17 monitorexit   .                   Exception table:    //If any exception occurs between
    18 athrow      .                     from to target type //location 4 (inclusive) and location
    19 astore_3                           4 16 16 any //16 (exclusive) jump to location 16
    20 aload_2
    21 monitorexit
    22 ret 3
.
Size and speed issues




top1 and top2 are functionally identical
top1 is 13% faster than top2 as well as much smaller.
Puzzle Cutting Class
                                                          public class Strange2 {
public class Strange1 {
                                                               public static void main(String[] args) {
     public static void main(String[] args) {
                                                                  Missing m;         try {
        try {
                                                                     m = new Missing();           } catch
           Missing m = new Missing();           } catch
                                                          (java.lang.NoClassDefFoundError ex) {
(java.lang.NoClassDefFoundError ex) {
                                                                     System.out.println("Got it!");
           System.out.println("Got it!");
                                                                  }
        }
                                                               }
     }
                                                             }
   }




  class Missing {
       Missing() { }
   }
Puzzle Cutting Class
                                                          public class Strange2 {
public class Strange1 {
                                                               public static void main(String[] args) {
     public static void main(String[] args) {
                                                                  Missing m;         try {
        try {
                                                                     m = new Missing();           } catch
           Missing m = new Missing();           } catch
                                                          (java.lang.NoClassDefFoundError ex) {
(java.lang.NoClassDefFoundError ex) {
                                                                     System.out.println("Got it!");
           System.out.println("Got it!");
                                                                  }
        }
                                                               }
     }
                                                             }
   }




  class Missing {
       Missing() { }
   }
Puzzle Cutting Class
                                                              public class Strange2 {
public class Strange1 {
                                                                   public static void main(String[] args) {
     public static void main(String[] args) {
                                                                      Missing m;         try {
        try {
                                                                         m = new Missing();           } catch
           Missing m = new Missing();            } catch
                                                              (java.lang.NoClassDefFoundError ex) {
(java.lang.NoClassDefFoundError ex) {
                                                                         System.out.println("Got it!");
           System.out.println("Got it!");
                                                                      }
        }
                                                                   }
     }
                                                                 }
   }
                                          class Missing {
                                              Missing() { }
                                           }




                                                     ???
           System.out.println("Got it!");                       throws an uncaught
                                                                NoClassDefFoundError
Puzzle Cutting Class
                                                            public class Strange2 {
public class Strange1 {
                                                                 public static void main(String[] args) {
     public static void main(String[] args) {
                                                                    Missing m;         try {
        try {
                                                                       m = new Missing();           } catch
           Missing m = new Missing();           } catch
                                                            (java.lang.NoClassDefFoundError ex) {
(java.lang.NoClassDefFoundError ex) {
                                                                       System.out.println("Got it!");
           System.out.println("Got it!");
                                                                    }
        }
                                                                 }
     }

                                        class Missing {
                                            Missing() { }
                                         }




           System.out.println("Got it!");        Expected     throws an uncaught
                                                              NoClassDefFoundError


           throws an uncaught                    Result       System.out.println("Got it!");
           NoClassDefFoundError
Puzzle Cutting Class
0: new             #2; // class Missing

3: dup

4: invokespecial #3; // Method Missing."<init>":()V

7: astore_1

8: goto 20

11: astore_1

12: getstatic      #5; // Field System.out:Ljava/io/PrintStream;

15: ldc            #6; // String "Got it!"

17: invokevirtual #7; // Method PrintStream.println:(String;)V

20: return

Exception table:

from to target type

  0 8 11 Class java/lang/NoClassDefFoundError

The corresponding code for Strange2.main differs in only one instruction:
11: astore_2 //Store ex catch parameter




javap -c Strange1
Using reflection
public class Strange {

    public static void main(String[] args) throws Exception {

        try {

            Object m = Class.forName("Missing").newInstance();

        } catch (ClassNotFoundException ex) {

            System.err.println("Got it!");

        }

    }

}
Benefits

• Improve speed and size of your applications
• Critical when debugging and doing performance and
  memory usage tuning
• Realtime injection
• Build ORM project
• Clustering with AOP
• Know your platform!
• Create your own compile/decompiler?
Mastering Java ByteCode

Mastering Java ByteCode

  • 1.
  • 2.
    The master plan • JVM • javap • opcode • ClassLoader • Toolkits • Puzzles
  • 3.
    Stack 1+2 PUSH 1 1 12+ PUSH 2 2
  • 4.
    Stack 1+2 PUSH 1 3 12+ PUSH 2 ADD
  • 5.
    Stack 1+2 ICONST_1 3 12+ ICONST_2 IADD
  • 6.
  • 8.
  • 9.
    Java Stack Machine • JVM is a stack-based machine • Each thread has a stack • Stack stores frames • Frame is created on method invocation • Frame: o Operand stack o Array of local variables o Reference to the runtime constant pool
  • 10.
    Compiling to binary C/C++(*.h, *.cpp) Java (*.java) Assembler Bytecode Intel opcode Sun opcode
  • 11.
    javap • Java class file disassembler • Used with no options shows class structure only • Methods, superclass, interfaces, etc • -c – shows the bytecode • -private – shows all classes and members • -s – prints internal types signatures • -verbose – prints stack size, number of locals and args for methods
  • 12.
  • 13.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } }
  • 14.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c
  • 15.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c Compiled from "SimpleProgram.java" public class SimpleProgram extends java.lang.Object{ public SimpleProgram(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()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 Java Fusion! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return }
  • 16.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c Compiled from "SimpleProgram.java" public class SimpleProgram extends java.lang.Object{ public SimpleProgram();// The default constructor Code: 0: aload_0 //Push this sto stack 1: invokespecial #1; //Method java/lang/Object."":()V //Invoke <init> on this 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 Java Fusion! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return }
  • 17.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c Compiled from "SimpleProgram.java" public class SimpleProgram extends java.lang.Object{ public SimpleProgram(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; //get static field 3: ldc #3; //String Hello Java Fusion! //Load String to the stack 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V //invoke method with parameter 8: return }
  • 18.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c Compiled from "SimpleProgram.java" public class SimpleProgram extends java.lang.Object{ public SimpleProgram(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()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 Java Fusion! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return }
  • 19.
    public class SimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } } javap SimpleProgram -c -verbose Compiled from "SimpleProgram.java“ public class SimpleProgram extends java.lang.Object SourceFile: "SimpleProgram.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#20; // java/lang/Object."<init>":()V const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #23; // Hello Java Fusion! const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #26; // SimpleProgram const #6 = class #27; // java/lang/Object сonst #7 = Asciz <init>; ...
  • 20.
    Bytecode One-byte instructions 256 possibleopcodes 207 in use 49 currently unassigned for opcodes and are reserved for future use
  • 21.
    TYPE OPERATION Instructions fallinto a number of broad groups: •Local variables and stack interaction (e.g. aload_0,istore) •Array operations (aload, astore) •Arithmetic and logic (e.g. ladd,fcmpl) •Type conversion (e.g. i2b,d2i) •Object creation and manipulation (new, putfield) •Operand stack management (e.g. swap,dup2) •Control transfer (e.g. ifeq, goto) •Method invocation and return (e.g. invokespecial,areturn) •Operations with constant values (ldc, iconst_1) •Math (add, sub, mul, div) •Boolean/bitwise operations (iand, ixor) •Comparisons (cmpg, cmpl, ifne) •...
  • 22.
    Opcode type Prefix/Suffix Operand Type i integer l long s short b byte c char f float d double a reference
  • 23.
    public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  • 24.
    public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  • 25.
    public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  • 26.
    public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  • 27.
    ClassLoader - Works withbytecode - Has native methods - Bytecode Verification via SecurityManager.class
  • 28.
    Toolkits JVM: •ASM •Javassist •BCEL (Byte CodeEngineering Library) Jrebel Terracotta
  • 29.
    Common sample public classSimpleProgram { public static void main(String[] args) { System.out.println("Hello Java Fusion!"); } }
  • 30.
    ASM sample public classASMSample extends ClassLoader implements Opcodes { { public static void main(String[] args) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null); } }
  • 31.
    ASM sample public classASMSample extends ClassLoader implements Opcodes { { public static void main(String[] args) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null); // creates a GeneratorAdapter for the (implicit) constructor Method m = Method.getMethod("void <init> ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m); mg.returnValue(); mg.endMethod(); } }
  • 32.
    ASM sample public classASMSample extends ClassLoader implements Opcodes { { public static void main(String[] args) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null); // creates a GeneratorAdapter for the (implicit) constructor Method m = Method.getMethod("void <init> ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m); mg.returnValue(); mg.endMethod(); // creates a GeneratorAdapter for the 'main' method m = Method.getMethod("void main (String[])"); mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); mg.getStatic(Type.getType(System.class), "out",Type.getType(PrintStream.class)); mg.push("Hello Java Fusion!"); mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); mg.returnValue(); mg.endMethod(); cw.visitEnd(); } }
  • 33.
    ASM sample public classASMSample extends ClassLoader implements Opcodes { { public static void main(String[] args) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "SimpleProgram", null, "java/lang/Object", null); // creates a GeneratorAdapter for the (implicit) constructor Method m = Method.getMethod("void <init> ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m); mg.returnValue(); mg.endMethod(); // creates a GeneratorAdapter for the 'main' method m = Method.getMethod("void main (String[])"); mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); mg.getStatic(Type.getType(System.class), "out",Type.getType(PrintStream.class)); mg.push("Hello Java Fusion!"); mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); mg.returnValue(); mg.endMethod(); cw.visitEnd(); byte[] code = cw.toByteArray(); ASMSample loader = new ASMSample (); Class<?> exampleClass = loader.defineClass("SimpleProgram", code, 0, code.length); // uses the dynamically generated class to print 'Hello Java Fusion' exampleClass.getMethods()[0].invoke(null, new Object[] { null } ); } }
  • 34.
    ASM vs. Javassist • Javassist source level API is much easier to use than the actual bytecode manipulation in ASM • Javassist provides a higher level abstraction layer over complex bytecode level operations. Javassist source level API requires very less or no knowledge of actual bytecodes, so much easier & faster to implement. • Javassist uses reflection mechanism which makes it slower compared to ASM which uses Classworking techniques at runtime. • Overall ASM is much faster & gives better performance than Javassist. Javassist uses a simplified version of Java source code, which it then compiles into bytecode. That makes Javassist very easy to use, but it also limits the use of bytecode to what can be expressed within the limits of the Javassist source code. • In conclusion, if someone needs easier way of dynamically manipulating or creating Java classes Javassist API should be used & where the performance is the key issue ASM library should be used.
  • 35.
    JRebel Redeploying sucks, soJRebel eliminates it. How? JRebel maps your project workspace directly to the application under development. When you change any class or resource in your IDE, the change is immediately reflected in the application, skipping the build and redeploy phases.
  • 36.
    How JRebel works 1)Classes • JRebel integrates with the JVM and rewrites each class to be updateable • JRebel versions each class individually, instead of an application or module at a time • It does not use classloaders! • Changes to classes are always visible in the Reflection API
  • 37.
    How JRebel works 2)Workspace mapping petclinic.war • JRebel integrates with application servers, frameworks and your IDE • When a class or resource is being looked up, JRebel redirects straight to the workspace • When an HTTP resource needs to be served, JRebel serves it from the workspace
  • 38.
  • 39.
    Size and speedissues top1 and top2 are functionally identical
  • 40.
    Size and speedissues Method int top1() 0 aload_0 //Push the object reference(this) at index //0 of the local variable table. 1 getfield #6 <Field int intArr[]> //Pop the object reference(this) and push //the object reference for intArr accessed //from the constant pool. 4 iconst_0 //Push 0. 5 iaload //Pop the top two values and push the //value at index 0 of intArr. 6 ireturn //Pop top value and push it on the operand //stack of the invoking method. Exit.
  • 41.
    Size and speedissues Method int top2() 0 aload_0 1 astore_2 2 aload_2 3 monitorenter 4 aload_0 5 getfield #6 <Field int intArr[]> 8 iconst_0 //Push 0. 9 iaload 10 istore_1 11 jsr 19 14 iload_1 . 15 ireturn 16 aload_2 17 monitorexit . Exception table: //If any exception occurs between 18 athrow . from to target type //location 4 (inclusive) and location 19 astore_3 4 16 16 any //16 (exclusive) jump to location 16 20 aload_2 21 monitorexit 22 ret 3 .
  • 42.
    Size and speedissues top1 and top2 are functionally identical top1 is 13% faster than top2 as well as much smaller.
  • 43.
    Puzzle Cutting Class public class Strange2 { public class Strange1 { public static void main(String[] args) { public static void main(String[] args) { Missing m; try { try { m = new Missing(); } catch Missing m = new Missing(); } catch (java.lang.NoClassDefFoundError ex) { (java.lang.NoClassDefFoundError ex) { System.out.println("Got it!"); System.out.println("Got it!"); } } } } } } class Missing { Missing() { } }
  • 44.
    Puzzle Cutting Class public class Strange2 { public class Strange1 { public static void main(String[] args) { public static void main(String[] args) { Missing m; try { try { m = new Missing(); } catch Missing m = new Missing(); } catch (java.lang.NoClassDefFoundError ex) { (java.lang.NoClassDefFoundError ex) { System.out.println("Got it!"); System.out.println("Got it!"); } } } } } } class Missing { Missing() { } }
  • 45.
    Puzzle Cutting Class public class Strange2 { public class Strange1 { public static void main(String[] args) { public static void main(String[] args) { Missing m; try { try { m = new Missing(); } catch Missing m = new Missing(); } catch (java.lang.NoClassDefFoundError ex) { (java.lang.NoClassDefFoundError ex) { System.out.println("Got it!"); System.out.println("Got it!"); } } } } } } class Missing { Missing() { } } ??? System.out.println("Got it!"); throws an uncaught NoClassDefFoundError
  • 46.
    Puzzle Cutting Class public class Strange2 { public class Strange1 { public static void main(String[] args) { public static void main(String[] args) { Missing m; try { try { m = new Missing(); } catch Missing m = new Missing(); } catch (java.lang.NoClassDefFoundError ex) { (java.lang.NoClassDefFoundError ex) { System.out.println("Got it!"); System.out.println("Got it!"); } } } } class Missing { Missing() { } } System.out.println("Got it!"); Expected throws an uncaught NoClassDefFoundError throws an uncaught Result System.out.println("Got it!"); NoClassDefFoundError
  • 47.
    Puzzle Cutting Class 0:new #2; // class Missing 3: dup 4: invokespecial #3; // Method Missing."<init>":()V 7: astore_1 8: goto 20 11: astore_1 12: getstatic #5; // Field System.out:Ljava/io/PrintStream; 15: ldc #6; // String "Got it!" 17: invokevirtual #7; // Method PrintStream.println:(String;)V 20: return Exception table: from to target type 0 8 11 Class java/lang/NoClassDefFoundError The corresponding code for Strange2.main differs in only one instruction: 11: astore_2 //Store ex catch parameter javap -c Strange1
  • 48.
    Using reflection public classStrange { public static void main(String[] args) throws Exception { try { Object m = Class.forName("Missing").newInstance(); } catch (ClassNotFoundException ex) { System.err.println("Got it!"); } } }
  • 49.
    Benefits • Improve speedand size of your applications • Critical when debugging and doing performance and memory usage tuning • Realtime injection • Build ORM project • Clustering with AOP • Know your platform! • Create your own compile/decompiler?

Editor's Notes

  • #3 Добавить много Realtime примеров в Far и Inteliji Idea или Eclipse!!!!
  • #4 #1, #2 и т.д. храняться в пуле констант. Подробней в -verbose
  • #5 #1, #2 и т.д. храняться в пуле констант. Подробней в -verbose
  • #6 #1, #2 и т.д. храняться в пуле констант. Подробней в -verbose
  • #7 #1, #2 и т.д. храняться в пуле констант. Подробней в -verbose The array of local variables, also called the local variable table, contains the parameters of the method and is also used to hold the values of the local variables.
  • #9 Байт-кода стеко-ориентированный язык, похожий по своей структуре на ассемблер. Что бы произвести операции с данными их сначала нужно положит на стек. Мы хотим взять поле у объект. Что бы это сделять нужно его положить в стек. В байт-коде нет имен переменных, у них есть номера. Нулевой номер у ссылки на текущий объект или у переменой this. Потом идут параметры исполняемого метода. Затем остальные переменные.
  • #10 Each thread has a JVM stack which stores frames . A frame is created each time a method is invoked, and consists of an operand stack, an array of local variables, and a reference to the runtime constant pool of the class of the current method.
  • #11 Intel opcode выполняються в среде ОС, Sun opcode в среде JVM Платформы java имеется две особенности. Для обеспечения кроссплатформенности программа сначала компилируется в промежуточный язык низкого уровня - байт-код. Вторая особенность загрузка исполняемых классов происходит с помощью расширяемых classloader. Это механизм обеспечивает большую гибкость и позволяет модифицировать исполняемый код при загрузки, создавать и подгружать новые классы во время выполнения программы. Такая техника широко применяется для реализации AOP, создания тестовых фреймворков, ORM.
  • #12 Каждому классу в java соответствует один откомпилированный файл. Это справедливо даже для подклассов или анонимным классов. Такой файл содержит информацию об имени класса, его родители, список интерфейсов которые он реализует, перечисление его полей и методов. Важно отметить, что после компиляции информации которая содержит директива import теряется и все классы именуются теперь через полный путь. Например в место String будет записано java/lang/String.
  • #19 #1, #2 и т.д. храняться в пуле констант
  • #20 Добавить диограму с Constant pool
  • #23 prefix определяет тип, для которого предназначен opcode
  • #24 Each method has a corresponding bytecode array. These values correspond to the index into the array where each opcode and its arguments are stored. You might wonder why the values are not sequential. Since bytecode got its name because each instruction occupies one byte, why are the indexes not 0, 1, and 2? The reason is some of the opcodes have parameters that take up space in the bytecode array. For example, the aload_0 instruction has no parameters and naturally occupies one byte in the bytecode array. Therefore, the next opcode, getfield, is in location 1. However, areturn is in location 4. This is because the getfield opcode and its parameters occupy location 1, 2, and 3
  • #28 Class Loader при загрузке байткода проверяет его на безопастность и исправность. Больше информации про Class loader
  • #29 Добавить утелиты для реалных примеров (Jrebel), изменение байт кода без деплоя и тд?
  • #30 Создадим класс SimpleProgram с помощью библиотеки ASM
  • #35 Добавить диаграму разницы
  • #36 Добавить Realtime примеры в Far и Inteliji Idea или Eclipse!!!!
  • #37 Добавить Realtime примеры в Far и Inteliji Idea или Eclipse!!!!
  • #38 Добавить Realtime примеры в Far и Inteliji Idea или Eclipse!!!!
  • #39 В чем разница межжу top1 and top2 ?
  • #40 Они одинаковые. Методы работают с одной скоростю, если нет, то какой быстрее?
  • #41 Они одинаковые. Методы работают с одной скоростю, если нет, то какой быстрее?
  • #42 Они одинаковые. Методы работают с одной скоростю, если нет, то какой быстрее?
  • #43 показать байт коды классов?
  • #48 Strange2 хранит в astore_1 ex, а в astore_2 Missing. Strange1 хранить в a_store_1 Missing. Как же правильно сделать прверку? Обяснить подробней
  • #49 Правильный способ проверки наличия класса. Обяснить его подробней?