用Java实现JVM第五章《指令集和解释器》

129 阅读7分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

简介

Java虚拟机顾名思义,就是一台虚拟的机器,而字节码(bytecode)就是运行在这台虚拟机器上的机器码。我们已经知道,每一个类或者接口都会被Java编译器编译成一个class文件,类或接口的方法信息就放在class文件的method_info结构中。

image-20210817170406591.png

Java字节码指令大全

指令工厂

具体指令可查阅docs.oracle.com/javase/spec…

package com.black.cat.jvm.instructions;

import com.black.cat.jvm.instructions.base.Instruction;
import com.black.cat.jvm.instructions.comparisons.dcmp.DCMPG;
import com.black.cat.jvm.instructions.comparisons.dcmp.DCMPL;
import com.black.cat.jvm.instructions.comparisons.fcmp.FCMPG;
import com.black.cat.jvm.instructions.comparisons.fcmp.FCMPL;
import com.black.cat.jvm.instructions.comparisons.if_acmp.IF_ACMPEQ;
import com.black.cat.jvm.instructions.comparisons.if_acmp.IF_ACMPNE;
import com.black.cat.jvm.instructions.comparisons.if_icmp.*;
import com.black.cat.jvm.instructions.comparisons.ifcond.*;
import com.black.cat.jvm.instructions.comparisons.lcmp.LCMP;
import com.black.cat.jvm.instructions.constants.consts.*;
import com.black.cat.jvm.instructions.constants.ipush.BIPUSH;
import com.black.cat.jvm.instructions.constants.ipush.SIPUSH;
import com.black.cat.jvm.instructions.constants.nop.NOP;
import com.black.cat.jvm.instructions.control.GOTO;
import com.black.cat.jvm.instructions.control.LOOKUP_SWITCH;
import com.black.cat.jvm.instructions.control.TABLE_SWITCH;
import com.black.cat.jvm.instructions.conversions.d2x.D2F;
import com.black.cat.jvm.instructions.conversions.d2x.D2I;
import com.black.cat.jvm.instructions.conversions.d2x.D2L;
import com.black.cat.jvm.instructions.conversions.f2x.F2D;
import com.black.cat.jvm.instructions.conversions.f2x.F2I;
import com.black.cat.jvm.instructions.conversions.f2x.F2L;
import com.black.cat.jvm.instructions.conversions.i2x.*;
import com.black.cat.jvm.instructions.conversions.l2x.L2D;
import com.black.cat.jvm.instructions.conversions.l2x.L2F;
import com.black.cat.jvm.instructions.conversions.l2x.L2I;
import com.black.cat.jvm.instructions.extended.GOTO_W;
import com.black.cat.jvm.instructions.extended.WIDE;
import com.black.cat.jvm.instructions.extended.ifnull.IFNONNULL;
import com.black.cat.jvm.instructions.extended.ifnull.IFNULL;
import com.black.cat.jvm.instructions.loads.aload.*;
import com.black.cat.jvm.instructions.loads.dload.*;
import com.black.cat.jvm.instructions.loads.fload.*;
import com.black.cat.jvm.instructions.loads.iload.*;
import com.black.cat.jvm.instructions.loads.lload.*;
import com.black.cat.jvm.instructions.math.add.DADD;
import com.black.cat.jvm.instructions.math.add.FADD;
import com.black.cat.jvm.instructions.math.add.IADD;
import com.black.cat.jvm.instructions.math.add.LADD;
import com.black.cat.jvm.instructions.math.and.IAND;
import com.black.cat.jvm.instructions.math.and.LAND;
import com.black.cat.jvm.instructions.math.div.DDIV;
import com.black.cat.jvm.instructions.math.div.FDIV;
import com.black.cat.jvm.instructions.math.div.IDIV;
import com.black.cat.jvm.instructions.math.div.LDIV;
import com.black.cat.jvm.instructions.math.iinc.IINC;
import com.black.cat.jvm.instructions.math.mul.DMUL;
import com.black.cat.jvm.instructions.math.mul.FMUL;
import com.black.cat.jvm.instructions.math.mul.IMUL;
import com.black.cat.jvm.instructions.math.mul.LMUL;
import com.black.cat.jvm.instructions.math.neg.DNEG;
import com.black.cat.jvm.instructions.math.neg.FNEG;
import com.black.cat.jvm.instructions.math.neg.INEG;
import com.black.cat.jvm.instructions.math.neg.LNEG;
import com.black.cat.jvm.instructions.math.or.IOR;
import com.black.cat.jvm.instructions.math.or.LOR;
import com.black.cat.jvm.instructions.math.rem.DREM;
import com.black.cat.jvm.instructions.math.rem.FREM;
import com.black.cat.jvm.instructions.math.rem.IREM;
import com.black.cat.jvm.instructions.math.rem.LREM;
import com.black.cat.jvm.instructions.math.sh.*;
import com.black.cat.jvm.instructions.math.sub.DSUB;
import com.black.cat.jvm.instructions.math.sub.FSUB;
import com.black.cat.jvm.instructions.math.sub.ISUB;
import com.black.cat.jvm.instructions.math.sub.LSUB;
import com.black.cat.jvm.instructions.math.xor.IXOR;
import com.black.cat.jvm.instructions.math.xor.LXOR;
import com.black.cat.jvm.instructions.stack.dup.*;
import com.black.cat.jvm.instructions.stack.pop.POP;
import com.black.cat.jvm.instructions.stack.pop.POP2;
import com.black.cat.jvm.instructions.stack.swap.SWAP;
import com.black.cat.jvm.instructions.stores.astore.*;
import com.black.cat.jvm.instructions.stores.dstore.*;
import com.black.cat.jvm.instructions.stores.fstore.*;
import com.black.cat.jvm.instructions.stores.istore.*;
import com.black.cat.jvm.instructions.stores.lstore.*;


/**
 * @Author blackcat
 * @create 2021/8/13 14:14
 * @version: 1.0
 * @description:指令工厂
 */
public class InstructionFactory {

    //constants(常量指令)
    //loads(加载指令)
    //store(存储指令)
    //stack(操作数栈指令)
    //math(数学指令)
    //conversions(转换指令)
    //comparisons(比较指令)
    //control(控制指令)
    //references(引用指令)
    //extended(拓展指令)
    //reserved(保留指令)
    public static Instruction newInstruction(byte opcode) {

        switch (opcode) {
            case 0x00:
                return new NOP();
            case 0x01:
                return new ACONST_NULL();
            case 0x02:
                return new ICONST_M1();
            case 0x03:
                return new ICONST_0();
            case 0x04:
                return new ICONST_1();
            case 0x05:
                return new ICONST_2();
            case 0x06:
                return new ICONST_3();
            case 0x07:
                return new ICONST_4();
            case 0x08:
                return new ICONST_5();
            case 0x09:
                return new LCONST_0();
            case 0x0a:
                return new LCONST_1();
            case 0x0b:
                return new FCONST_0();
            case 0x0c:
                return new FCONST_1();
            case 0x0d:
                return new FCONST_2();
            case 0x0e:
                return new DCONST_0();
            case 0x0f:
                return new DCONST_1();
            case 0x10:
                return new BIPUSH();
            case 0x11:
                return new SIPUSH();
            // case 0x12:
            // 	return &LDC{}
            // case 0x13:
            // 	return &LDC_W{}
            // case 0x14:
            // 	return &LDC2_W{}
            case 0x15:
                return new ILOAD();
            case 0x16:
                return new LLOAD();
            case 0x17:
                return new FLOAD();
            case 0x18:
                return new DLOAD();
            case 0x19:
                return new ALOAD();
            case 0x1a:
                return new ILOAD_0();
            case 0x1b:
                return new ILOAD_1();
            case 0x1c:
                return new ILOAD_2();
            case 0x1d:
                return new ILOAD_3();
            case 0x1e:
                return new LLOAD_0();
            case 0x1f:
                return new LLOAD_1();
            case 0x20:
                return new LLOAD_2();
            case 0x21:
                return new LLOAD_3();
            case 0x22:
                return new FLOAD_0();
            case 0x23:
                return new FLOAD_1();
            case 0x24:
                return new FLOAD_2();
            case 0x25:
                return new FLOAD_3();
            case 0x26:
                return new DLOAD_0();
            case 0x27:
                return new DLOAD_1();
            case 0x28:
                return new DLOAD_2();
            case 0x29:
                return new DLOAD_3();
            case 0x2a:
                return new ALOAD_0();
            case 0x2b:
                return new ALOAD_1();
            case 0x2c:
                return new ALOAD_2();
            case 0x2d:
                return new ALOAD_3();
            // case 0x2e:
            // 	return iaload
            // case 0x2f:
            // 	return laload
            // case 0x30:
            // 	return faload
            // case 0x31:
            // 	return daload
            // case 0x32:
            // 	return aaload
            // case 0x33:
            // 	return baload
            // case 0x34:
            // 	return caload
            // case 0x35:
            // 	return saload
            case 0x36:
                return new ISTORE();
            case 0x37:
                return new LSTORE();
            case 0x38:
                return new FSTORE();
            case 0x39:
                return new DSTORE();
            case 0x3a:
                return new ASTORE();
            case 0x3b:
                return new ISTORE_0();
            case 0x3c:
                return new ISTORE_1();
            case 0x3d:
                return new ISTORE_2();
            case 0x3e:
                return new ISTORE_3();
            case 0x3f:
                return new LSTORE_0();
            case 0x40:
                return new LSTORE_1();
            case 0x41:
                return new LSTORE_2();
            case 0x42:
                return new LSTORE_3();
            case 0x43:
                return new FSTORE_0();
            case 0x44:
                return new FSTORE_1();
            case 0x45:
                return new FSTORE_2();
            case 0x46:
                return new FSTORE_3();
            case 0x47:
                return new DSTORE_0();
            case 0x48:
                return new DSTORE_1();
            case 0x49:
                return new DSTORE_2();
            case 0x4a:
                return new DSTORE_3();
            case 0x4b:
                return new ASTORE_0();
            case 0x4c:
                return new ASTORE_1();
            case 0x4d:
                return new ASTORE_2();
            case 0x4e:
                return new ASTORE_3();
            // case 0x4f:
            // 	return iastore
            // case 0x50:
            // 	return lastore
            // case 0x51:
            // 	return fastore
            // case 0x52:
            // 	return dastore
            // case 0x53:
            // 	return aastore
            // case 0x54:
            // 	return bastore
            // case 0x55:
            // 	return castore
            // case 0x56:
            // 	return sastore
            case 0x57:
                return new POP();
            case 0x58:
                return new POP2();
            case 0x59:
                return new DUP();
            case 0x5a:
                return new DUP_X1();
            case 0x5b:
                return new DUP_X2();
            case 0x5c:
                return new DUP2();
            case 0x5d:
                return new DUP2_X1();
            case 0x5e:
                return new DUP2_X2();
            case 0x5f:
                return new SWAP();
            case 0x60:
                return new IADD();
            case 0x61:
                return new LADD();
            case 0x62:
                return new FADD();
            case 0x63:
                return new DADD();
            case 0x64:
                return new ISUB();
            case 0x65:
                return new LSUB();
            case 0x66:
                return new FSUB();
            case 0x67:
                return new DSUB();
            case 0x68:
                return new IMUL();
            case 0x69:
                return new LMUL();
            case 0x6a:
                return new FMUL();
            case 0x6b:
                return new DMUL();
            case 0x6c:
                return new IDIV();
            case 0x6d:
                return new LDIV();
            case 0x6e:
                return new FDIV();
            case 0x6f:
                return new DDIV();
            case 0x70:
                return new IREM();
            case 0x71:
                return new LREM();
            case 0x72:
                return new FREM();
            case 0x73:
                return new DREM();
            case 0x74:
                return new INEG();
            case 0x75:
                return new LNEG();
            case 0x76:
                return new FNEG();
            case 0x77:
                return new DNEG();
            case 0x78:
                return new ISHL();
            case 0x79:
                return new LSHL();
            case 0x7a:
                return new ISHR();
            case 0x7b:
                return new LSHR();
            case 0x7c:
                return new IUSHR();
            case 0x7d:
                return new LUSHR();
            case 0x7e:
                return new IAND();
            case 0x7f:
                return new LAND();
            case (byte) 0x80:
                return new IOR();
            case (byte) 0x81:
                return new LOR();
            case (byte) 0x82:
                return new IXOR();
            case (byte) 0x83:
                return new LXOR();
            case (byte) 0x84:
                return new IINC();
            case (byte) 0x85:
                return new I2L();
            case (byte) 0x86:
                return new I2F();
            case (byte) 0x87:
                return new I2D();
            case (byte) 0x88:
                return new L2I();
            case (byte) 0x89:
                return new L2F();
            case (byte) 0x8a:
                return new L2D();
            case (byte) 0x8b:
                return new F2I();
            case (byte) 0x8c:
                return new F2L();
            case (byte) 0x8d:
                return new F2D();
            case (byte) 0x8e:
                return new D2I();
            case (byte) 0x8f:
                return new D2L();
            case (byte) 0x90:
                return new D2F();
            case (byte) 0x91:
                return new I2B();
            case (byte) 0x92:
                return new I2C();
            case (byte) 0x93:
                return new I2S();
            case (byte) 0x94:
                return new LCMP();
            case (byte) 0x95:
                return new FCMPL();
            case (byte) 0x96:
                return new FCMPG();
            case (byte) 0x97:
                return new DCMPL();
            case (byte) 0x98:
                return new DCMPG();
            case (byte) 0x99:
                return new IFEQ();
            case (byte) 0x9a:
                return new IFNE();
            case (byte) 0x9b:
                return new IFLT();
            case (byte) 0x9c:
                return new IFGE();
            case (byte) 0x9d:
                return new IFGT();
            case (byte) 0x9e:
                return new IFLE();
            case (byte) 0x9f:
                return new IF_ICMPEQ();
            case (byte) 0xa0:
                return new IF_ICMPNE();
            case (byte) 0xa1:
                return new IF_ICMPLT();
            case (byte) 0xa2:
                return new IF_ICMPGE();
            case (byte) 0xa3:
                return new IF_ICMPGT();
            case (byte) 0xa4:
                return new IF_ICMPLE();
            case (byte) 0xa5:
                return new IF_ACMPEQ();
            case (byte) 0xa6:
                return new IF_ACMPNE();
            case (byte) 0xa7:
                return new GOTO();
            // case 0xa8:
            // 	return &JSR{}
            // case 0xa9:
            // 	return &RET{}
            case (byte) 0xaa:
                return new TABLE_SWITCH();
            case (byte) 0xab:
                return new LOOKUP_SWITCH();
            // case 0xac:
            // 	return ireturn
            // case 0xad:
            // 	return lreturn
            // case 0xae:
            // 	return freturn
            // case 0xaf:
            // 	return dreturn
            // case 0xb0:
            // 	return areturn
            // case 0xb1:
            // 	return _return
            //	case 0xb2:
            //		return &GET_STATIC{}
            // case 0xb3:
            // 	return &PUT_STATIC{}
            // case 0xb4:
            // 	return &GET_FIELD{}
            // case 0xb5:
            // 	return &PUT_FIELD{}
            //	case 0xb6:
            //		return &INVOKE_VIRTUAL{}
            // case 0xb7:
            // 	return &INVOKE_SPECIAL{}
            // case 0xb8:
            // 	return &INVOKE_STATIC{}
            // case 0xb9:
            // 	return &INVOKE_INTERFACE{}
            // case 0xba:
            // 	return &INVOKE_DYNAMIC{}
            // case 0xbb:
            // 	return &NEW{}
            // case 0xbc:
            // 	return &NEW_ARRAY{}
            // case 0xbd:
            // 	return &ANEW_ARRAY{}
            // case 0xbe:
            // 	return arraylength
            // case 0xbf:
            // 	return athrow
            // case 0xc0:
            // 	return &CHECK_CAST{}
            // case 0xc1:
            // 	return &INSTANCE_OF{}
            // case 0xc2:
            // 	return monitorenter
            // case 0xc3:
            // 	return monitorexit
            case (byte) 0xc4:
                return new WIDE();
            // case 0xc5:
            // 	return &MULTI_ANEW_ARRAY{}
            case (byte) 0xc6:
                return new IFNULL();
            case (byte) 0xc7:
                return new IFNONNULL();
            case (byte) 0xc8:
                return new GOTO_W();
            // case 0xc9:
            // 	return &JSR_W{}
            //保留指令
            // case 0xca: breakpoint
            // case 0xfe: impdep1
            // case 0xff: impdep2
            default:
                return null;

        }
    }
}

常量指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x01aconst_nullnull值入栈。
0x02iconst_m1-1(int)值入栈。
0x03iconst_00(int)值入栈。
0x04iconst_11(int)值入栈。
0x05iconst_22(int)值入栈。
0x06iconst_33(int)值入栈。
0x07iconst_44(int)值入栈。
0x08iconst_55(int)值入栈。
0x09lconst_00(long)值入栈。
0x0alconst_11(long)值入栈。
0x0bfconst_00(float)值入栈。
0x0cfconst_11(float)值入栈。
0x0dfconst_22(float)值入栈。
0x0edconst_00(double)值入栈。
0x0fdconst_11(double)值入栈。
0x10bipushvaluebytevaluebyte值带符号扩展成int值入栈。
0x11sipushvaluebyte1valuebyte2(valuebyte1 << 8) | valuebyte2 值带符号扩展成int值入栈。
0x12ldcindexbyte1常量池中的常量值(int, float, string reference, object reference)入栈。
0x13ldc_windexbyte1indexbyte2常量池中常量(int, float, string reference, object reference)入栈。
0x14ldc2_windexbyte1indexbyte2常量池中常量(long, double)入栈。

存储指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x3a(wide)astoreindexbyte将栈顶引用类型值保存到局部变量indexbyte中。
0x4bastroe_0将栈顶引用类型值保存到局部变量0中。
0x4castore_1将栈顶引用类型值保存到局部变量1中。
0x4dastore_2将栈顶引用类型值保存到局部变量2中。
0x4eastore_3将栈顶引用类型值保存到局部变量3中。
0x36(wide)istoreindexbyte将栈顶int类型值保存到局部变量indexbyte中。
0x3bistore_0将栈顶int类型值保存到局部变量0中。
0x3cistore_1将栈顶int类型值保存到局部变量1中。
0x3distore_2将栈顶int类型值保存到局部变量2中。
0x3eistore_3将栈顶int类型值保存到局部变量3中。
0x37(wide)lstoreindexbyte将栈顶long类型值保存到局部变量indexbyte中。
0x3flstore_0将栈顶long类型值保存到局部变量0中。
0x40lstore_1将栈顶long类型值保存到局部变量1中。
0x41lstore_2将栈顶long类型值保存到局部变量2中。
0x42lstroe_3将栈顶long类型值保存到局部变量3中。
0x38(wide)fstoreindexbyte将栈顶float类型值保存到局部变量indexbyte中。
0x43fstore_0将栈顶float类型值保存到局部变量0中。
0x44fstore_1将栈顶float类型值保存到局部变量1中。
0x45fstore_2将栈顶float类型值保存到局部变量2中。
0x46fstore_3将栈顶float类型值保存到局部变量3中。
0x39(wide)dstoreindexbyte将栈顶double类型值保存到局部变量indexbyte中。
0x47dstore_0将栈顶double类型值保存到局部变量0中。
0x48dstore_1将栈顶double类型值保存到局部变量1中。
0x49dstore_2将栈顶double类型值保存到局部变量2中。
0x4adstore_3将栈顶double类型值保存到局部变量3中。
0x53aastore将栈顶引用类型值保存到指定引用类型数组的指定项。
0x4fiastore将栈顶int类型值保存到指定int类型数组的指定项。
0x50lastore将栈顶long类型值保存到指定long类型数组的指定项。
0x51fastore将栈顶float类型值保存到指定float类型数组的指定项。
0x52dastore将栈顶double类型值保存到指定double类型数组的指定项。
0x54bastroe将栈顶boolean类型值或byte类型值保存到指定boolean类型数组或byte类型数组的指定项。
0x55castore将栈顶char类型值保存到指定char类型数组的指定项。
0x56sastore将栈顶short类型值保存到指定short类型数组的指定项。

栈操作指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x00nop空操作。
0x57pop从栈顶弹出一个字长的数据。
0x58pop2从栈顶弹出两个字长的数据。
0x59dup复制栈顶一个字长的数据,将复制后的数据压栈。
0x5adup_x1复制栈顶一个字长的数据,弹出栈顶两个字长数据,先将复制后的数据压栈,再将弹出的两个字长数据压栈。
0x5bdup_x2复制栈顶一个字长的数据,弹出栈顶三个字长的数据,将复制后的数据压栈,再将弹出的三个字长的数据压栈。
0x5cdup2复制栈顶两个字长的数据,将复制后的两个字长的数据压栈。
0x5ddup2_x1复制栈顶两个字长的数据,弹出栈顶三个字长的数据,将复制后的两个字长的数据压栈,再将弹出的三个字长的数据压栈。
0x5edup2_x2复制栈顶两个字长的数据,弹出栈顶四个字长的数据,将复制后的两个字长的数据压栈,再将弹出的四个字长的数据压栈。
0x5fswap交换栈顶两个字长的数据的位置。Java指令中没有提供以两个字长为单位的交换指令。

算术指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x60iadd将栈顶两int类型数相加,结果入栈。
0x64isub将栈顶两int类型数相减,结果入栈。
0x68imul将栈顶两int类型数相乘,结果入栈。
0x6cidiv将栈顶两int类型数相除,结果入栈。
0x70irem将栈顶两int类型数取模,结果入栈。
0x74ineg将栈顶int类型值取负,结果入栈。
0x61ladd将栈顶两long类型数相加,结果入栈。
0x65lsub将栈顶两long类型数相减,结果入栈。
0x69lmul将栈顶两long类型数相乘,结果入栈。
0x6dldiv将栈顶两long类型数相除,结果入栈。
0x71lrem将栈顶两long类型数取模,结果入栈。
0x75lneg将栈顶long类型值取负,结果入栈。
0x84(wide)iincindexbyteconstbyte将整数值constbyte加到indexbyte指定的int类型的局部变量中。

类型转换指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x86i2f将栈顶int类型值转换为float类型值。
0x85i2l将栈顶int类型值转换为long类型值。
0x87i2d将栈顶int类型值转换为double类型值。
0x8bf2i将栈顶float类型值转换为int类型值。
0x8cf2l将栈顶float类型值转换为long类型值。
0x8df2d将栈顶float类型值转换为double类型值。
0x88l2i将栈顶long类型值转换为int类型值。
0x89l2f将栈顶long类型值转换为float类型值。
0x8al2d将栈顶long类型值转换double类型值。
0x8ed2i将栈顶double类型值转换为int类型值。
0x90d2f将栈顶double类型值转换为float类型值。
0x8fd2l将栈顶double类型值转换为long类型值。
0x91i2b将栈顶int类型值截断成byte类型,后带符号扩展成int类型值入栈。
0x92i2c将栈顶int类型值截断成char类型值,后带符号扩展成int类型值入栈。
0x93i2s将栈顶int类型值截断成short类型值,后带符号扩展成int类型值入栈。

比较指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x94lcmp比较栈顶两long类型值,前者大,1入栈;相等,0入栈;后者大,-1入栈。
0x95fcmpl比较栈顶两float类型值,前者大,1入栈;相等,0入栈;后者大,-1入栈;有NaN存在,-1入栈。
0x96fcmpg比较栈顶两float类型值,前者大,1入栈;相等,0入栈;后者大,-1入栈;有NaN存在,-1入栈。
0x97dcmpl比较栈顶两double类型值,前者大,1入栈;相等,0入栈;后者大,-1入栈;有NaN存在,-1入栈。
0x98dcmpg比较栈顶两double类型值,前者大,1入栈;相等,0入栈;后者大,-1入栈;有NaN存在,-1入栈。

控制指令

指令码操作码(助记符)操作数描述(栈指操作数栈)
0x99ifeqbranchbyte1branchbyte2若栈顶int类型值为0则跳转。
0x9aifnebranchbyte1branchbyte2若栈顶int类型值不为0则跳转。
0x9bifltbranchbyte1branchbyte2若栈顶int类型值小于0则跳转。
0x9eiflebranchbyte1branchbyte2若栈顶int类型值小于等于0则跳转。
0x9difgtbranchbyte1branchbyte2若栈顶int类型值大于0则跳转。
0x9cifgebranchbyte1branchbyte2若栈顶int类型值大于等于0则跳转。
0x9fif_icmpeqbranchbyte1branchbyte2若栈顶两int类型值相等则跳转。
0xa0if_icmpnebranchbyte1branchbyte2若栈顶两int类型值不相等则跳转。
0xa1if_icmpltbranchbyte1branchbyte2若栈顶两int类型值前小于后则跳转。
0xa4if_icmplebranchbyte1branchbyte2若栈顶两int类型值前小于等于后则跳转。
0xa3if_icmpgtbranchbyte1branchbyte2若栈顶两int类型值前大于后则跳转。
0xa2if_icmpgebranchbyte1branchbyte2若栈顶两int类型值前大于等于后则跳转。
0xc6ifnullbranchbyte1branchbyte2若栈顶引用值为null则跳转。
0xc7ifnonnullbranchbyte1branchbyte2若栈顶引用值不为null则跳转。
0xa5if_acmpeqbranchbyte1branchbyte2若栈顶两引用类型值相等则跳转。
0xa6if_acmpnebranchbyte1branchbyte2若栈顶两引用类型值不相等则跳转。

部分代码

package com.black.cat.jvm;

import com.alibaba.fastjson.JSON;
import com.black.cat.jvm.classfile.MemberInfo;
import com.black.cat.jvm.classfile.attribute.CodeAttribute;
import com.black.cat.jvm.instructions.InstructionFactory;
import com.black.cat.jvm.instructions.base.BytecodeReader;
import com.black.cat.jvm.instructions.base.Instruction;
import com.black.cat.jvm.rtda.Frame;
import com.black.cat.jvm.rtda.JThread;

import java.util.Arrays;

/**
 * @Author blackcat
 * @create 2021/8/13 14:07
 * @version: 1.0
 * @description:指令集解释器
 */
public class Interpret {

    Interpret(MemberInfo m) {
        CodeAttribute codeAttr = m.codeAttribute();
        int maxLocals = codeAttr.getMaxLocals();
        int maxStack = codeAttr.getMaxStack();
        byte[] byteCode = codeAttr.getCode();
        JThread thread = new JThread();
        Frame frame = thread.newFrame(maxLocals, maxStack);
        thread.pushFrame(frame);
        loop(thread, byteCode);
    }

    private void loop(JThread thread, byte[] byteCode) {
        Frame frame = thread.popFrame();
        BytecodeReader reader = new BytecodeReader();

        while (true) {
            //循环
            int pc = frame.nextPC();
            thread.setPC(pc);
            //decode
            reader.reset(byteCode, pc);
            byte opcode = reader.readByte();
            Instruction inst = InstructionFactory.newInstruction(opcode);
            if (null == inst) {
                System.out.println("寄存器(指令)尚未实现 " + byteToHexString(new byte[]{opcode}));
                break;
            }
            inst.fetchOperands(reader);
            frame.setNextPC(reader.getPC());
            System.out.println("pc:" + pc + " -> " + "寄存器(指令):" + byteToHexString(new byte[]{opcode}) + " -> " + inst.getClass().getSimpleName() + " => 局部变量表:" + Arrays.toString(frame.localVars().getSlots()) + " 操作数栈:" + Arrays.toString(frame.operandStack().getSlots()));            //exec
            inst.execute(frame);
        }

    }

    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();
    }

}

package com.black.cat.jvm;

import com.black.cat.jvm.classfile.ClassFile;
import com.black.cat.jvm.classfile.MemberInfo;
import com.black.cat.jvm.classpath.Classpath;
import com.black.cat.jvm.rtda.Frame;
import com.black.cat.jvm.rtda.LocalVars;
import com.black.cat.jvm.rtda.OperandStack;


/**
 * @Author blackcat
 * @create 2021/8/11 13:43
 * @version: 1.0
 * @description:命令行工具
 */
public class Main {

    public static void main(String[] args) {
        String[] argv = {"-classpath", "D:\\develop\\code\\jjvm\\jvm-05\\target\\classes", "com.black.cat.jvm.MainTest"};
        Cmd cmd = Cmd.parse(argv);
        if (!cmd.ok || cmd.helpFlag) {
            System.out.println("Usage: <main class> [-options] class [args...]");
            return;
        }
        if (cmd.versionFlag) {
            System.out.println("java version \"1.8.0\"");
            return;
        }
        startJVM(cmd);
    }

    private static void startJVM(Cmd cmd) {
        Classpath classpath = new Classpath(cmd.jre, cmd.classpath);
        System.out.printf("classpath:%s class:%s args:%s\n", classpath, cmd.getMainClass(), cmd.getAppArgs());
        String className = cmd.getMainClass().replace(".", "/");
        ClassFile classFile = loadClass(className, classpath);
        MemberInfo mainMethod = getMainMethod(classFile);
        if (null == mainMethod) {
            System.out.println("Main method not found in class " + cmd.classpath);
            return;
        }
        new Interpret(mainMethod);
    }


    private static ClassFile loadClass(String className, Classpath cp) {
        try {
            byte[] classData = cp.readClass(className);
            return new ClassFile(classData);
        } catch (Exception e) {
            System.out.println("Could not find or load main class " + className);
            e.printStackTrace();
        }
        return null;
    }

    //找到主函数入口方法
    private static MemberInfo getMainMethod(ClassFile cf) {
        if (null == cf) return null;
        MemberInfo[] methods = cf.getMethodInfos();
        for (MemberInfo m : methods) {
            if ("main".equals(m.name()) && "([Ljava/lang/String;)V".equals(m.descriptor())) {
                return m;
            }
        }
        return null;
    }
}

package com.black.cat.jvm;

import java.io.IOException;

/**
 * @Author blackcat
 * @create 2021/8/11 15:12
 * @version: 1.0
 * @description:测试类
 */
public class MainTest {


    public static void main(String[] args) throws IOException {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        System.out.println(sum);
    }


}

测试

image-20210817171943773.png

gitee 地址

gitee.com/feicc/jjvm/…