用Java实现JVM第四章《运行时数据区》

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

运行时数据区概述

Java虚拟机规范把这些内存区域叫作运行时数据区。运行时数据区可以分为两类:一类是多线程共享的,另一类则是线程私有的。

多线程共享的内存区域主要存放两类数据:类数据和类实例(也就是对象)。对象数据存放在堆(Heap)中,类数据存放在方法区(Method Area)中。 每个线程都有自己的pc寄存器(Program Counter)和Java虚拟机栈(JVMStack)。Java虚拟机栈又由栈帧(Stack Frame,后面简称帧)构成,帧中保存方法执行的状态,包括局部变量表(Local Variable)和操作数栈(Operand Stack)等。

image-20210815133600238.png

代码

image-20210816075144357.png

线程

/**
 * @Author blackcat
 * @create 2021/8/12 15:28
 * @version: 1.0
 * @description:线程
 */
public class JThread {

    //Program Counter 寄存器
    private int pc;

    //虚拟机栈
    private JvmStack stack;


    public JThread(){
        this.stack = new JvmStack(1024);
    }

    public int pc(){
        return this.pc;
    }

    public void setPC(int pc){
        this.pc = pc;
    }

    public void pushFrame(Frame frame){
        this.stack.push(frame);
    }

    public Frame popFrame(){
        return this.stack.pop();
    }

    public Frame currentFrame(){
        return this.stack.top();
    }
}

复制代码

虚拟机栈

Java 虚拟机栈(Java Virtual Machine Stacks),早期也叫 Java 栈。每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次 Java 方法调用,是线程私有的,生命周期和线程一致。



/**
 * @Author blackcat
 * @create 2021/8/12 15:28
 * @version: 1.0
 * @description:虚拟机栈
 */
public class JvmStack {

    //栈的容量,最多可以容纳多少帧
    private int maxSize;
    //栈的当前大小
    private int size;
    //栈顶指针
    private Frame _top;


    public JvmStack(int maxSize) {
        this.maxSize = maxSize;
    }

    //帧推入栈顶
    public void push(Frame frame) {
        //如果栈已经满了,StackOverflowError异常
        if (this.size > this.maxSize) {
            throw new StackOverflowError();
        }

        if (this._top != null) {
            frame.lower = this._top;
        }

        this._top = frame;
        this.size++;
    }

    public Frame pop() {
        if (this._top == null) {
            throw new RuntimeException("jvm stack is empty!");
        }

        Frame top = this._top;
        this._top = top.lower;
        top.lower = null;
        this.size--;

        return top;
    }

    public Frame top(){
        if (this._top == null){
            throw new RuntimeException("jvm stack is empty!");
        }
        return this._top;
    }
}

复制代码

栈帧

每个栈帧(Stack Frame)中存储着:

局部变量表(Local Variables)

操作数栈(Operand Stack)(或称为表达式栈)

动态链接(Dynamic Linking):指向运行时常量池的方法引用

方法返回地址(Return Address):方法正常退出或异常退出的地址

一些附加信息

0082zybply1gc8tjehg8bj318m0lbtbu.jpg

本例只包含前面两个

/**
 * @Author blackcat
 * @create 2021/8/12 15:29
 * @version: 1.0
 * @description:栈帧
 */
public class Frame {

    //stack is implemented as linked list
    Frame lower;

    //局部变量表
    private LocalVars localVars;

    //操作数栈
    private OperandStack operandStack;

    public Frame(int maxLocals, int maxStack) {
        this.localVars = new LocalVars(maxLocals);
        this.operandStack = new OperandStack(maxStack);
    }

    public LocalVars localVars(){
        return localVars;
    }

    public OperandStack operandStack(){
        return operandStack;
    }
}

复制代码

局部变量

/**
 * @Author blackcat
 * @create 2021/8/12 15:32
 * @version: 1.0
 * @description:局部变量表
 */
public class LocalVars {

    private Slot[] localVars;


    public LocalVars(int maxLocals) {
        if (maxLocals > 0) {
            localVars = new Slot[maxLocals];
            for (int i = 0; i < maxLocals; i++) {
                localVars[i] = new Slot();
            }
        }
    }

    public void setInt(int pos, int val) {
        checkIndex(pos);
        localVars[pos].num = val;
    }

    public int getInt(int pos) throws NoSuchElementException {
        checkIndex(pos);
        return localVars[pos].num;
    }

    public void setFloat(int pos, float val) {
        checkIndex(pos);
        localVars[pos].num = Float.floatToIntBits(val);
    }

    public Float getFloat(int pos) {
        checkIndex(pos);
        return Float.intBitsToFloat(localVars[pos].num);
    }

    public void setLong(int pos, long val) {
        checkIndex(pos + 1);
        int[] ints = ByteUtil.long2IntArr(val);
        localVars[pos].num = ints[0];
        localVars[pos + 1].num = ints[1];
    }

    public long getLong(int pos) {
        checkIndex(pos + 1);
        return ByteUtil.int2Long(localVars[pos].num, localVars[pos + 1].num);
    }

    public void setDouble(int pos, double val) {
        checkIndex(pos);
        long l = Double.doubleToLongBits(val);
        setLong(pos, l);
    }

    public double getDouble(int pos) {
        long res = getLong(pos);
        return Double.longBitsToDouble(res);
    }

    public void setRef(int pos, Object ref) {
        checkIndex(pos);
        localVars[pos].ref = ref;
    }

    public Object getRef(int pos) {
        checkIndex(pos);
        return localVars[pos].ref;
    }

    private void checkIndex(int pos) {
        if (pos < 0 || pos >= size()) {
            throw new IllegalArgumentException("invalid index, " + pos);
        }
    }

    public int size() {
        return localVars.length;
    }
}

复制代码

操作数栈

/**
 * @Author blackcat
 * @create 2021/8/12 15:33
 * @version: 1.0
 * @description:操作数栈
 */
public class OperandStack {

    private int size = 0;
    private Slot[] operands;


    public OperandStack(int size) {
        operands = new Slot[size];
        for (int i = 0; i < size; i++) {
            operands[i] = new Slot();
        }
    }

    public void pushInt(int val) {
        operands[size].num = val;
        size++;
    }

    public int popInt() {
        size--;
        return operands[size].num;
    }

    public void pushRef(Object val) {
        operands[size].ref = val;
        size++;
    }

    public Object popRef() {
        size--;
        Object val = operands[size].ref;
        operands[size].ref = null;
        return val;
    }


    public void pushFloat(float val) {
        operands[size].num = Float.floatToIntBits(val);
        size++;
    }

    public Float popFloat() {
        --size;
        return Float.intBitsToFloat(operands[size].num);
    }

    public void pushLong(long val) {
        int[] ints = ByteUtil.long2IntArr(val);
        operands[size++].num = ints[0];
        operands[size++].num = ints[1];
    }

    public long popLong() {
        size--;
        size--;
        return ByteUtil.int2Long(operands[size].num, operands[size + 1].num);
    }

    public void pushDouble(double val) {
        long res = Double.doubleToLongBits(val);
        pushLong(res);
    }

    public double popDouble() {
        long res = popLong();
        return Double.longBitsToDouble(res);
    }

}

/**
 * @Author blackcat
 * @create 2021/8/12 15:33
 * @version: 1.0
 * @description:数据槽
 */
public class Slot {

    int num;
    Object ref;
}
复制代码

测试

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-03\\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 args) {
        Frame frame = new Frame(100, 100);
        test_localVars(frame.localVars());
        test_operandStack(frame.operandStack());
    }

    private static void test_localVars(LocalVars vars){
        vars.setInt(0,100);
        vars.setInt(1,-100);
        vars.setLong(2, 2997924580L);
        vars.setLong(4, -2997924580L);
        vars.setFloat(6, 3.1415926F);
        vars.setDouble(7, 2.71828182845);
        vars.setRef(9, null);
        System.out.println(vars.getInt(0));
        System.out.println(vars.getInt(1));
        System.out.println(vars.getLong(2));
        System.out.println(vars.getLong(4));
        System.out.println(vars.getFloat(6));
        System.out.println(vars.getDouble(7));
        System.out.println(vars.getRef(9));
    }

    private static void test_operandStack(OperandStack ops){
        ops.pushInt(100);
        ops.pushInt(-100);
        ops.pushLong(2997924580L);
        ops.pushLong(-2997924580L);
        ops.pushFloat(3.1415926F);
        ops.pushDouble(2.71828182845);
        ops.pushRef(null);
        System.out.println(ops.popRef());
        System.out.println(ops.popDouble());
        System.out.println(ops.popFloat());
        System.out.println(ops.popLong());
        System.out.println(ops.popLong());
        System.out.println(ops.popInt());
        System.out.println(ops.popInt());
    }

}

复制代码

结果

备注:float 存在一些精度问题

100
-100
2997924580
-2997924580
3.1415925
2.71828182845
null
null
2.71828182845
3.1415925
-2997924580
2997924580
-100
100
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享