Skip to content

Latest commit

 

History

History
797 lines (677 loc) · 36 KB

2019-05-08-用Java实现JVM第七章《方法调用和返回》.md

File metadata and controls

797 lines (677 loc) · 36 KB
layout category title tagline tag
post
itstack-demo-jvm
用Java实现JVM第七章《方法调用和返回》
by 付政委
jvm
itstack-demo-jvm

用Java实现JVM第七章《方法调用和返回》

作者:小傅哥
博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!😄

案例介绍

本章节主要用java实现;方法调用指令、返回指令、解析方法符号引用、参数传递等。实现新的指令后我们的虚拟机就可以执行稍微复杂的运算并输出结果。

从调用的角度来看,方法可以分为两类:静态方法(或者类方法)和实例方法。静态方法通过类类调用,实例方法则通过对象引用来调用。静态方法是静态绑定的,也就是说,最终调用的是哪给方法在编译期就已经确定。实例方法则支持动态绑定,最终要调用哪给方法可能要推迟到运行期才能知道。

从实现的角度来看,方法可以分为三类:没有实现(也就是抽象方法)、用Java语言(或者JVM上其他的语言,如Groovy和Scala等)实现和用本地语言(如C或者C++)实现。静态方法和抽象方法是互斥的。在Java 8之前,接口只能包括抽象方法。为了实现Lambda表达式,Java 8放宽了这一限制,在接口中也可以定义静态方法和默认方法。

在Java 7之前,Java虚拟机规范一共提供了4条方法调用指令。其中invokestatic指令用来调用静态方法。invokespecial指令用来调用无须动态绑定的实例方法,包括构造函数、私有方法和通过super关键字调用的超类方法。剩下的情况则属于动态绑定。如果是针对接口类型的引用调用方法,就使用invokeinterface指令,否则使用invokevirtual指令。

环境准备

  1. jdk 1.8.0
  2. IntelliJ IDEA Community Edition 2018.3.1 x64

配置信息

  1. 调试配置
    1. 配置位置:Run/Debug Configurations -> program arguments
    2. 配置内容(选配 verbose true):-Xjre "C:\Program Files\Java\jdk1.8.0_161\jre" E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-07\target\test-classes\org\itstack\demo\test\HelloWorld verbose true

代码示例

itstack-demo-jvm-07
├── pom.xml
└── src
    └── main
    │    └── java
    │        └── org.itstack.demo.jvm
    │             ├── classfile
    │             │   ├── attributes   {BootstrapMethods/Code/ConstantValue...}
    │             │   ├── constantpool {CONSTANT_TAG_CLASS/CONSTANT_TAG_FIELDREF/CONSTANT_TAG_METHODREF...}
    │             │   ├── ClassFile.java
    │             │   ├── ClassReader.java
    │             │   └── MemberInfo.java   
    │             ├── classpath
    │             │   ├── impl
    │             │   │   ├── CompositeEntry.java
    │             │   │   ├── DirEntry.java 
    │             │   │   ├── WildcardEntry.java 
    │             │   │   └── ZipEntry.java    
    │             │   ├── Classpath.java
    │             │   └── Entry.java   
    │             ├── classpath
    │             │   ├── base
    │             │   │   ├── BytecodeReader.java
    │             │   │   ├── ClassInitLogic.java
    │             │   │   ├── Instruction.java
    │             │   │   ├── InstructionBranch.java
    │             │   │   ├── InstructionIndex8.java
    │             │   │   ├── InstructionIndex16.java
    │             │   │   ├── InstructionNoOperands.java	
    │             │   │   └── MethodInvokeLogic.java
    │             │   ├── comparisons
    │             │   ├── constants
    │             │   ├── control
    │             │   ├── conversions
    │             │   ├── extended
    │             │   ├── loads
    │             │   ├── math
    │             │   ├── references
    │             │   │   ├── CHECK_CAST.java
    │             │   │   ├── GET_FIELD.java
    │             │   │   ├── GET_STATIC.java
    │             │   │   ├── INSTANCE_OF.java
    │             │   │   ├── INVOKE_INTERFACE.java
    │             │   │   ├── INVOKE_SPECIAL.java
    │             │   │   ├── INVOKE_STATIC.java
    │             │   │   ├── INVOKE_VIRTUAL.java
    │             │   │   ├── NEW.java
    │             │   │   ├── PUT_FIELD.java
    │             │   │   └── PUT_STATIC.java
    │             │   ├── stack
    │             │   ├── store
    │             │   └── Factory   
    │             ├── rtda
    │             │   ├── heap
    │             │   │   ├── constantpool
    │             │   │   ├── methodarea
    │             │   │   │   ├── Class.java    
    │             │   │   │   ├── ClassMember.java  
    │             │   │   │   ├── Field.java    
    │             │   │   │   ├── Method.java 
    │             │   │   │   ├── MethodDescriptor.java 
    │             │   │   │   ├── MethodDescriptorParser.java 
    │             │   │   │   ├── MethodLookup.java 	
    │             │   │   │   ├── Object.java   
    │             │   │   │   └── Slots.java        
    │             │   │   └── ClassLoader.java  
    │             │   ├── Frame.java
    │             │   ├── JvmStack.java
    │             │   ├── LocalVars.java
    │             │   ├── OperandStack.java
    │             │   ├── Slot.java 
    │             │   └── Thread.java
    │             ├── Cmd.java
    │             ├── Interpret.java    
    │             └── Main.java
    └── test
         └── java
             └── org.itstack.demo.test
                 └── HelloWorld.java

代码篇幅较长,只列重点代码块

MethodInvokeLogic.java

package org.itstack.demo.jvm.instructions.base;

import org.itstack.demo.jvm.rtda.Frame;
import org.itstack.demo.jvm.rtda.Slot;
import org.itstack.demo.jvm.rtda.Thread;
import org.itstack.demo.jvm.rtda.heap.methodarea.Method;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class MethodInvokeLogic {

    public static void invokeMethod(Frame invokerFrame, Method method) {
        Thread thread = invokerFrame.thread();
        Frame newFrame = thread.newFrame(method);
        thread.pushFrame(newFrame);

        int argSlotCount = method.argSlotCount();
        if (argSlotCount > 0) {
            for (int i = argSlotCount - 1; i >= 0; i--) {
                Slot slot = invokerFrame.operandStack().popSlot();
                newFrame.localVars().setSlot(i, slot);
            }
        }

        //hack
        if (method.isNative()) {
            if ("registerNatives".equals(method.name())) {
                thread.popFrame();
            } else {
                throw new RuntimeException("native method " + method.name());
            }
        }
    }

}

INVOKE_INTERFACE.java

package org.itstack.demo.jvm.instructions.references;

import org.itstack.demo.jvm.instructions.base.BytecodeReader;
import org.itstack.demo.jvm.instructions.base.Instruction;
import org.itstack.demo.jvm.instructions.base.MethodInvokeLogic;
import org.itstack.demo.jvm.rtda.Frame;
import org.itstack.demo.jvm.rtda.heap.constantpool.InterfaceMethodRef;
import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;
import org.itstack.demo.jvm.rtda.heap.methodarea.Method;
import org.itstack.demo.jvm.rtda.heap.methodarea.MethodLookup;
import org.itstack.demo.jvm.rtda.heap.methodarea.Object;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class INVOKE_INTERFACE implements Instruction {

    private int idx;

    @Override
    public void fetchOperands(BytecodeReader reader) {
        this.idx = reader.readShort();
        reader.readByte();
        reader.readByte();
    }

    @Override
    public void execute(Frame frame) {
        RunTimeConstantPool runTimeConstantPool = frame.method().clazz().constantPool();
        InterfaceMethodRef methodRef = (InterfaceMethodRef) runTimeConstantPool.getConstants(this.idx);
        Method resolvedMethod = methodRef.resolvedInterfaceMethod();
        if (resolvedMethod.isStatic() || resolvedMethod.isPrivate()) {
            throw new IncompatibleClassChangeError();
        }
        Object ref = frame.operandStack().getRefFromTop(resolvedMethod.argSlotCount() - 1);
        if (null == ref) {
            throw new NullPointerException();
        }
        if (!ref.clazz().isImplements(methodRef.resolvedClass())) {
            throw new IncompatibleClassChangeError();
        }
        Method methodToBeInvoked = MethodLookup.lookupMethodInClass(ref.clazz(), methodRef.name(), methodRef.descriptor());
        if (null == methodToBeInvoked || methodToBeInvoked.isAbstract()) {
            throw new AbstractMethodError();
        }
        if (!methodToBeInvoked.isPublic()) {
            throw new IllegalAccessError();
        }

        MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked);

    }

}

INVOKE_SPECIAL.java

package org.itstack.demo.jvm.instructions.references;

import org.itstack.demo.jvm.instructions.base.InstructionIndex16;
import org.itstack.demo.jvm.instructions.base.MethodInvokeLogic;
import org.itstack.demo.jvm.rtda.Frame;
import org.itstack.demo.jvm.rtda.heap.constantpool.MethodRef;
import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;
import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
import org.itstack.demo.jvm.rtda.heap.methodarea.Method;
import org.itstack.demo.jvm.rtda.heap.methodarea.MethodLookup;
import org.itstack.demo.jvm.rtda.heap.methodarea.Object;

public class INVOKE_SPECIAL extends InstructionIndex16 {

    @Override
    public void execute(Frame frame) {
        Class currentClass = frame.method().clazz();
        RunTimeConstantPool runTimeConstantPool = currentClass.constantPool();
        MethodRef methodRef = (MethodRef) runTimeConstantPool.getConstants(this.idx);
        Class resolvedClass = methodRef.resolvedClass();
        Method resolvedMethod = methodRef.ResolvedMethod();
        if ("<init>".equals(resolvedMethod.name()) && resolvedMethod.clazz() != resolvedClass) {
            throw new NoSuchMethodError();
        }
        if (resolvedMethod.isStatic()) {
            throw new IncompatibleClassChangeError();
        }

        Object ref = frame.operandStack().getRefFromTop(resolvedMethod.argSlotCount() - 1);
        if (null == ref) {
            throw new NullPointerException();
        }

        if (resolvedMethod.isProtected() &&
                resolvedMethod.clazz().isSubClassOf(currentClass) &&
                !resolvedMethod.clazz().getPackageName().equals(currentClass.getPackageName()) &&
                ref.clazz() != currentClass &&
                !ref.clazz().isSubClassOf(currentClass)) {
            throw new IllegalAccessError();
        }

        Method methodToBeInvoked = resolvedMethod;
        if (currentClass.isSuper() &&
                resolvedClass.isSubClassOf(currentClass) &&
                !resolvedMethod.name().equals("<init>")) {
            MethodLookup.lookupMethodInClass(currentClass.superClass, methodRef.name(), methodRef.descriptor());
        }

        if (methodToBeInvoked.isAbstract()) {
            throw new AbstractMethodError();
        }

        MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked);

    }

}

INVOKE_STATIC.java

package org.itstack.demo.jvm.instructions.references;

import org.itstack.demo.jvm.instructions.base.ClassInitLogic;
import org.itstack.demo.jvm.instructions.base.InstructionIndex16;
import org.itstack.demo.jvm.instructions.base.MethodInvokeLogic;
import org.itstack.demo.jvm.rtda.Frame;
import org.itstack.demo.jvm.rtda.heap.constantpool.MethodRef;
import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;
import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
import org.itstack.demo.jvm.rtda.heap.methodarea.Method;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class INVOKE_STATIC extends InstructionIndex16 {

    @Override
    public void execute(Frame frame) {
        RunTimeConstantPool runTimeConstantPool = frame.method().clazz().constantPool();
        MethodRef methodRef = (MethodRef) runTimeConstantPool.getConstants(this.idx);
        Method resolvedMethod = methodRef.ResolvedMethod();

        if (!resolvedMethod.isStatic()) {
            throw new IncompatibleClassChangeError();
        }

        Class clazz = resolvedMethod.clazz();
        if (!clazz.initStarted()) {
            frame.revertNextPC();
            ClassInitLogic.initClass(frame.thread(), clazz);
            return;
        }

        MethodInvokeLogic.invokeMethod(frame, resolvedMethod);
    }
}

INVOKE_VIRTUAL.java

package org.itstack.demo.jvm.instructions.references;

import org.itstack.demo.jvm.instructions.base.InstructionIndex16;
import org.itstack.demo.jvm.instructions.base.MethodInvokeLogic;
import org.itstack.demo.jvm.rtda.Frame;
import org.itstack.demo.jvm.rtda.OperandStack;
import org.itstack.demo.jvm.rtda.heap.constantpool.MethodRef;
import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;
import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
import org.itstack.demo.jvm.rtda.heap.methodarea.Method;
import org.itstack.demo.jvm.rtda.heap.methodarea.MethodLookup;
import org.itstack.demo.jvm.rtda.heap.methodarea.Object;

public class INVOKE_VIRTUAL extends InstructionIndex16 {

    @Override
    public void execute(Frame frame) {

        Class currentClass = frame.method().clazz();
        RunTimeConstantPool runTimeConstantPool = currentClass.constantPool();
        MethodRef methodRef = (MethodRef) runTimeConstantPool.getConstants(this.idx);
        Method resolvedMethod = methodRef.ResolvedMethod();
        if (resolvedMethod.isStatic()) {
            throw new IncompatibleClassChangeError();
        }

        Object ref = frame.operandStack().getRefFromTop(resolvedMethod.argSlotCount() - 1);
        if (null == ref) {
            if ("println".equals(methodRef.name())) {
                _println(frame.operandStack(), methodRef.descriptor());
                return;
            }
            throw new NullPointerException();
        }

        if (resolvedMethod.isProtected() &&
                resolvedMethod.clazz().isSubClassOf(currentClass) &&
                !resolvedMethod.clazz().getPackageName().equals(currentClass.getPackageName()) &&
                ref.clazz() != currentClass &&
                !ref.clazz().isSubClassOf(currentClass)) {
            throw new IllegalAccessError();
        }

        Method methodToBeInvoked = MethodLookup.lookupMethodInClass(ref.clazz(), methodRef.name(), methodRef.descriptor());
        if (null == methodToBeInvoked || methodToBeInvoked.isAbstract()) {
            throw new AbstractMethodError();
        }

        MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked);
    }

    //hack
    private void _println(OperandStack stack, String descriptor) {
        switch (descriptor) {
            case "(Z)V":
                System.out.println(stack.popInt() != 0);
                break;
            case "(C)V":
                System.out.println(stack.popInt());
                break;
            case "(I)V":
            case "(B)V":
            case "(S)V":
                System.out.println(stack.popInt());
                break;
            case "(F)V":
                System.out.println(stack.popFloat());
                break;
            case "(J)V":
                System.out.println(stack.popLong());
                break;
            case "(D)V":
                System.out.println(stack.popDouble());
                break;
            default:
                System.out.println(descriptor);
                break;
        }
        stack.popRef();
    }
}

MethodDescriptor.java

package org.itstack.demo.jvm.rtda.heap.methodarea;

import java.util.ArrayList;
import java.util.List;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class MethodDescriptor {

    public List<String> parameterTypes = new ArrayList<>();
    public String returnType;

    public void addParameterType(String type){
        this.parameterTypes.add(type);
    }

}

MethodDescriptorParser.java

package org.itstack.demo.jvm.rtda.heap.methodarea;

import javax.management.ObjectName;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class MethodDescriptorParser {

    private String raw;
    private int offset;
    private MethodDescriptor parsed;

    public static MethodDescriptor parseMethodDescriptorParser(String descriptor) {
        MethodDescriptorParser parser = new MethodDescriptorParser();
        return parser.parse(descriptor);
    }

    public MethodDescriptor parse(String descriptor) {
        this.raw = descriptor;
        this.parsed = new MethodDescriptor();
        this.startParams();
        this.parseParamTypes();
        this.endParams();
        this.parseReturnType();
        this.finish();
        return this.parsed;
    }

    private void startParams() {
        if (this.readUint8() != '(') {
            causePanic();
        }
    }

    private void endParams() {
        if (this.readUint8() != ')') {
            causePanic();
        }
    }

    public void finish(){
        if (this.offset != this.raw.length()){
            this.causePanic();
        }
    }

    public void causePanic() {
        throw new RuntimeException("BAD descriptor:" + this.raw);
    }

    public byte readUint8() {
        byte[] bytes = this.raw.getBytes();
        byte b = bytes[this.offset];
        this.offset++;
        return b;
    }

    public void unreadUint8() {
        this.offset--;
    }

    public void parseParamTypes() {
        while (true) {
            String type = this.parseFieldType();
            if ("".equals(type)) break;
            this.parsed.addParameterType(type);
        }
    }

    public void parseReturnType() {
        if (this.readUint8() == 'V'){
            this.parsed.returnType = "V";
            return;
        }

        this.unreadUint8();
        String type = this.parseFieldType();
        if (!"".equals(type)){
            this.parsed.returnType = type;
            return;
        }

        this.causePanic();
    }

    public String parseFieldType() {
        switch (this.readUint8()) {
            case 'B':
                return "B";
            case 'C':
                return "C";
            case 'D':
                return "D";
            case 'F':
                return "F";
            case 'I':
                return "I";
            case 'J':
                return "J";
            case 'S':
                return "S";
            case 'Z':
                return "Z";
            case 'L':
                return this.parseObjectType();
            case '[':
                return this.parseArrayType();
            default:
                this.unreadUint8();
                return "";
        }
    }

    private String parseObjectType() {
        String unread = this.raw.substring(this.offset);
        int semicolonIndx = unread.indexOf(";");
        if (semicolonIndx == -1) {
            this.causePanic();
            return "";
        }
        int objStart = this.offset - 1;
        int ojbEnd = this.offset + semicolonIndx + 1;
        this.offset = ojbEnd;
        //descriptor
        return this.raw.substring(objStart, ojbEnd);
    }

    private String parseArrayType() {
        int arrStart = this.offset - 1;
        this.parseFieldType();
        int arrEnd = this.offset;
        //descriptor
        return this.raw.substring(arrStart, arrEnd);
    }


}

MethodLookup.java

package org.itstack.demo.jvm.rtda.heap.methodarea;

/**
 * http://www.itstack.org
 * create by fuzhengwei on 2019/4/28
 */
public class MethodLookup {

    static public Method lookupMethodInClass(Class clazz, String name, String descriptor) {
        for (Class c = clazz; c != null; c = c.superClass) {
            for (Method method : c.methods) {
                if (method.name.equals(name) && method.descriptor.equals(descriptor)) {
                    return method;
                }
            }
        }
        return null;
    }

    static public Method lookupMethodInInterfaces(Class[] ifaces, String name, String descriptor) {
        for (Class inface : ifaces) {
            for (Method method : inface.methods) {
                if (method.name.equals(name) && method.descriptor.equals(descriptor)) {
                    return method;
                }
            }
        }
        return null;
    }

}

Interpret.java

//指令集解释器
class Interpret {

    Interpret(Method method, boolean logInst) {
        Thread thread = new Thread();
        Frame frame = thread.newFrame(method);
        thread.pushFrame(frame);

        loop(thread, logInst);
    }

    private void loop(Thread thread, boolean logInst) {
        BytecodeReader reader = new BytecodeReader();
        while (true) {
            Frame frame = thread.currentFrame();
            int pc = frame.nextPC();
            thread.setPC(pc);

            reader.reset(frame.method().code, pc);
            byte opcode = reader.readByte();
            Instruction inst = Factory.newInstruction(opcode);
            if (null == inst) {
                System.out.println("Unsupported opcode " + byteToHexString(new byte[]{opcode}));
                break;
            }
            inst.fetchOperands(reader);
            frame.setNextPC(reader.pc());

            if (logInst) {
                logInstruction(frame, inst, opcode);
            }

            //exec
            inst.execute(frame);

            if (thread.isStackEmpty()) {
                break;
            }
        }
    }

    private static void logInstruction(Frame frame, Instruction inst, byte opcode) {
        Method method = frame.method();
        String className = method.clazz().name();
        String methodName = method.name();
        String outStr = (className + "." + methodName + "() \t") +
                "寄存器(指令):" + byteToHexString(new byte[]{opcode}) + " -> " + inst.getClass().getSimpleName() + " => 局部变量表:" + JSON.toJSONString(frame.operandStack().getSlots()) + " 操作数栈:" + JSON.toJSONString(frame.operandStack().getSlots());
        System.out.println(outStr);
    }

    private static String byteToHexString(byte[] codes) {
        StringBuilder sb = new StringBuilder();
        sb.append("0x");
        for (byte b : codes) {
            int value = b & 0xFF;
            String strHex = Integer.toHexString(value);
            if (strHex.length() < 2) {
                strHex = "0" + strHex;
            }
            sb.append(strHex);
        }
        return sb.toString();
    }

}

HelloWorld.java

public class HelloWorld {

    public static void main(String[] args) {
        long x = fibonacci(10);
        System.out.println(x);
    }

    //斐波那契数列(Fibonacci sequence)
    private static long fibonacci(long n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }

}

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。

测试结果 {jvm执行复杂计算:斐波那契数列,输出结果55}

HelloWorld.fibonacci 指令:

lload_0
lconst_1
lcmp
ifgt 7
lload_0
lreturn
lload_0
lconst_1
lsub
invokestatic org/itstack/demo/test/HelloWorld/fibonacci(J)J
lload_0
ldc2_w 2
lsub
invokestatic org/itstack/demo/test/HelloWorld/fibonacci(J)J
ladd
lreturn

执行过程:

org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0x14 -> LDC2_W => 局部变量表:[{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":10},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":0}]
java/lang/Object.<clinit>() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:null 操作数栈:null
java/lang/Object.<clinit>() 	寄存器(指令):0xb1 -> RETURN => 局部变量表:null 操作数栈:null
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":10},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":10},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x94 -> LCMP => 局部变量表:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x9d -> IFGT => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x65 -> LSUB => 局部变量表:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":10},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":9},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":9},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x94 -> LCMP => 局部变量表:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x9d -> IFGT => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x65 -> LSUB => 局部变量表:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":9},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":8},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x94 -> LCMP => 局部变量表:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x9d -> IFGT => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x0a -> LCONST_1 => 局部变量表:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x65 -> LSUB => 局部变量表:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":7},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":7},{"num":0},{"num":1},{"num":0},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x1e -> LLOAD_0 => 局部变量表:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0},{"num":0},{"num":0},{"num":0},{"num":0}]

... ...

org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xad -> LRETURN => 局部变量表:[{"num":1},{"num":0},{"num":0},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":1},{"num":0},{"num":0},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x61 -> LADD => 局部变量表:[{"num":2},{"num":0},{"num":1},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":2},{"num":0},{"num":1},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xad -> LRETURN => 局部变量表:[{"num":3},{"num":0},{"num":1},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":3},{"num":0},{"num":1},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x61 -> LADD => 局部变量表:[{"num":5},{"num":0},{"num":3},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":5},{"num":0},{"num":3},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xad -> LRETURN => 局部变量表:[{"num":8},{"num":0},{"num":3},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":8},{"num":0},{"num":3},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x61 -> LADD => 局部变量表:[{"num":13},{"num":0},{"num":8},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":13},{"num":0},{"num":8},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xad -> LRETURN => 局部变量表:[{"num":21},{"num":0},{"num":8},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":21},{"num":0},{"num":8},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0x61 -> LADD => 局部变量表:[{"num":34},{"num":0},{"num":21},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":34},{"num":0},{"num":21},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.fibonacci() 	寄存器(指令):0xad -> LRETURN => 局部变量表:[{"num":55},{"num":0},{"num":21},{"num":0},{"num":2},{"num":0}] 操作数栈:[{"num":55},{"num":0},{"num":21},{"num":0},{"num":2},{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0x40 -> LSTORE_1 => 局部变量表:[{"num":55},{"num":0},{"num":0}] 操作数栈:[{"num":55},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb2 -> GET_STATIC => 局部变量表:[{"num":55},{"num":0},{"num":0}] 操作数栈:[{"num":55},{"num":0},{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb8 -> INVOKE_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0x01 -> ACONST_NULL => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb3 -> PUT_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0x01 -> ACONST_NULL => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb3 -> PUT_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0x01 -> ACONST_NULL => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb3 -> PUT_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0x01 -> ACONST_NULL => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb3 -> PUT_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0x01 -> ACONST_NULL => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb3 -> PUT_STATIC => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
java/lang/System.<clinit>() 	寄存器(指令):0xb1 -> RETURN => 局部变量表:[{"num":0}] 操作数栈:[{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb2 -> GET_STATIC => 局部变量表:[{"num":55},{"num":0},{"num":0}] 操作数栈:[{"num":55},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0x1f -> LLOAD_1 => 局部变量表:[{"num":55},{"num":0},{"num":0}] 操作数栈:[{"num":55},{"num":0},{"num":0}]
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb6 -> INVOKE_VIRTUAL => 局部变量表:[{"num":55},{"num":55},{"num":0}] 操作数栈:[{"num":55},{"num":55},{"num":0}]
55
org/itstack/demo/test/HelloWorld.main() 	寄存器(指令):0xb1 -> RETURN => 局部变量表:[{"num":55},{"num":55},{"num":0}] 操作数栈:[{"num":55},{"num":55},{"num":0}]

微信搜索「bugstack虫洞栈」公众号,关注后回复「用Java实现jvm源码」获取本文源码&更多原创专题案例!