1. Bytecode
javap Simple bytecode execution process Common bytecodes Generating Java bytecode with ASM JIT and its related parameters
-
javap(class file disassembly tool)
public class Calc { public int calc() { int a = 500; int b = 200; int c = 50; return (a + b) / c; } }
javap –verbose Calc
-
Simple bytecode execution process
-
Common bytecodes
-
Common bytecodes
-
Generating Java bytecode with ASM
Example:
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>5.0.3</version> </dependency>
GrandParent.java
public class GrandParent { public void test() { System.out.println("test of GrandParent"); } }
Parent.java
public class Parent extends GrandParent{ public void test() { System.out.println("test of Parent"); } }
Son.java
public class Son extends Parent{ public void test() { System.out.println("test of Son"); } }
ASMByteCodeManipulation.java
/** * description: * * [@author](https://my.oschina.net/arthor): dawn.he QQ: 905845006 * [@email](https://my.oschina.net/u/159820): dawn.he@cloudwise.com * [@email](https://my.oschina.net/u/159820): 905845006@qq.com * @date: 2019/9/30 9:21 PM */ import java.io.FileOutputStream; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class ASMByteCodeManipulation extends ClassLoader implements Opcodes { public static void main(String args[]) throws Exception { test1(); // test2(); } //print hello word public static void test1() throws Exception{ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); cw.visit(V1_7, ACC_PUBLIC, "Example", null, "java/lang/Object", null); MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); //this stack //There are limitations in using invokespecial, which can only be invoked from subclasses. Otherwise, mistake will be reported: mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(0, 0); mw.visitEnd(); mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mw.visitLdcInsn("Hello world!"); mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mw.visitInsn(RETURN); mw.visitMaxs(0,0); mw.visitEnd(); byte[] code = cw.toByteArray(); ASMByteCodeManipulation loader = new ASMByteCodeManipulation(); Class exampleClass = loader .defineClass("Example", code, 0, code.length); exampleClass.getMethods()[0].invoke(null, new Object[] { null }); } //print hello word public static void test2() throws Exception{ ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "Son", null); // creates a MethodWriter for the (implicit) constructor MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Son", "<init>", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); // creates a MethodWriter for the 'test' method mw = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null); mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mw.visitLdcInsn("test of AI3"); mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "GrandParent", "test", "()V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Parent", "test", "()V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Son", "test", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(2, 1); mw.visitEnd(); byte[] code = cw.toByteArray(); FileOutputStream fos = new FileOutputStream("Example.class"); fos.write(code); fos.close(); ASMByteCodeManipulation loader = new ASMByteCodeManipulation(); Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length); Object obj = exampleClass.newInstance(); exampleClass.getMethod("test", null).invoke(obj, null); } }
class file generated by test2 method
public class Example extends Son { public Example() { } public void test() { System.out.println("test of AI3"); super.test(); super.test(); super.test(); } }
Example 2:
Account.java
public class Account { public void operation() { System.out.println("operation...."); } }
Content to be embedded
SecurityChecker.java
public class SecurityChecker { public static boolean checkSecurity() { System.out.println("SecurityChecker.checkSecurity ..."); return true; } }
AddSecurityCheckClassAdapter.java
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:39 PM */ public class AddSecurityCheckClassAdapter extends ClassVisitor { public AddSecurityCheckClassAdapter( ClassVisitor cv) { super(Opcodes.ASM5, cv); } // Rewrite visitMethod to access the "operation" method. // Give a custom Method Visitor, and actually rewrite the content of the method. public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions); MethodVisitor wrappedMv = mv; if (mv != null) { // For the "operation" approach if (name.equals("operation")) { // Use custom Method Visitor to actually rewrite method content wrappedMv = new AddSecurityCheckMethodAdapter(mv); } } return wrappedMv; } }
AddSecurityCheckMethodAdapter.java
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:40 PM */ public class AddSecurityCheckMethodAdapter extends MethodVisitor { public AddSecurityCheckMethodAdapter(MethodVisitor mv) { super(Opcodes.ASM5,mv); } public void visitCode() { // visitMethodInsn(Opcodes.INVOKESTATIC, "geym/jvm/ch10/asm/SecurityChecker", visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker", "checkSecurity", "()Z"); super.visitCode(); } }
Generator.java
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import java.io.File; import java.io.FileOutputStream; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:40 PM */ public class Generator extends ClassLoader { public static void main(String args[]) throws Exception { // ClassReader cr = new ClassReader("geym.jvm.ch10.asm.Account"); ClassReader cr = new ClassReader("Account"); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); AddSecurityCheckClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw); cr.accept(classAdapter, ClassReader.SKIP_DEBUG); byte[] data = cw.toByteArray(); //Where does the class file go? // File file = new File("bin/geym/jvm/ch10/asm/Account.class"); File file = new File("Account.class"); FileOutputStream fout = new FileOutputStream(file); fout.write(data); fout.close(); Generator loader = new Generator(); Class<?> exampleClass = loader.defineClass("Account", data, 0, data.length); Object obj = exampleClass.newInstance(); exampleClass.getMethod("operation", null).invoke(obj, null); } }
Execute main method Output:
SecurityChecker.checkSecurity ... operation....
Generated class
Account.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // public class Account { public Account() { } public void operation() { SecurityChecker.checkSecurity(); System.out.println("operation...."); } }
-
JIT and its related parameters
The performance of bytecode execution is poor, so it can be compiled into machine code for hot code and then executed at run time. It's called JIT Just-In-Time The basic idea of JIT is to compile hotspot code into machine code by executing it frequently.