Deep into jvm kernel - principle, diagnose and optimize -10. jvm bytecode execution

Posted by phpisawesome on Wed, 02 Oct 2019 16:46:01 +0200

1. Bytecode

javap
 Simple bytecode execution process
 Common bytecodes
 Generating Java bytecode with ASM
 JIT and its related parameters
  1. 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
    

  2. Simple bytecode execution process

  3. Common bytecodes

  4. Common bytecodes

  5. 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....");
    		}
    	}
    
  6. 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.
    

Topics: Programming Java jvm IntelliJ IDEA