《自己动手写java虚拟机》学习笔记(八)-----线程私有运行时数据区(java)

项目地址:https://github.com/gongxianshengjiadexiaohuihui

《自己动手写java虚拟机》学习笔记(八)-----线程私有运行时数据区(java)_第1张图片

这个图就是线程私有的数据区结构

我们按照从外到内的方式来构建

线程Thread

package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 14 27
 * @Description:线程
 */
public class Thread {
    /**
     * 如果当前方法是java方法,存放正在执行的java虚拟机指令的地址,否则当前方法是本地方法,存放的值没有明确定义
     */
    private int pc;
    /**
     * java虚拟机栈
     */
    private Stack stack;

    public Thread() {
        /**
         * 默认虚拟机栈可以存放1024个栈帧
         */
        stack = new Stack(1024);
    }

    public int getPc() {
        return pc;
    }

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

    /**
     * 进栈
     * @param frame
     */
    public void pushFrame(Frame frame){
        stack.push(frame);
    }

    /**
     * 出栈
     * @return
     */
    public Frame popFrame(){
        return stack.pop();
    }

    /**
     * 返回当前帧
     * @return
     */
    public Frame getCurrentFrame(){
        return stack.top();
    }
}

线程包含两个部分,一个pc计数器,用来存放正在执行指令的地址,一个jvm栈,用来执行指令,基本单位是栈帧,一帧相当于执行一次操作

jvm栈

package classfile.rtda;

import java.util.EmptyStackException;

/**
 * @Author:ggp
 * @Date:2019/2/13 14 28
 * @Description:虚拟机栈
 */
public class Stack {
    /**
     * 最大容量
     */
    private int maxSize;
    /**
     * 实际栈帧数量
     */
    private int size;
    /**
     * 栈顶的帧
     */
    private Frame top;

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

    /**
     * 进栈
     * @param frame
     */
    public void push(Frame frame){
        if(size >= maxSize){
            /**
             * 如果栈已经满了,就抛出StackOverflowError错误
             */
            throw new StackOverflowError();
        }
        if(top != null){
            /**
             * 如果栈顶不为空,就可以让新的栈帧把它压下去一个位置,把它保留在next位置
             */
            frame.next = top;
        }
        top = frame;
        size++;
    }

    /**
     * 出栈
     * @return
     */
    public Frame pop(){
        if(top == null){
            /**
             * 如果栈为空,就抛出EmptyStackException异常
             */
            throw new EmptyStackException();
        }
        Frame tamp = top;
        top = top.next;
        tamp.next = null;
        size--;
        return tamp;
    }
    public Frame top(){
        if(top == null){
            /**
             * 如果栈为空,就抛出EmptyStackException异常
             */
            throw new EmptyStackException();
        }
        return top;
    }

}

就是一个栈是由栈帧组成的链表,包含进栈出栈等操作

栈帧Frame

package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 14 34
 * @Description:
 */
public class Frame {
    /**
     * 指向相邻的下一个栈帧
     */
    public Frame next;
    /**
     * 局部变量表
     */
    private LocalVars localVars;
    /**
     * 操作数栈
     */
    private OperandStack operandStack;
    public Frame(int maxlocals, int maxStack){
        localVars = new LocalVars(maxlocals);
        operandStack = new OperandStack(maxStack);
    }

    public LocalVars getLocalVars() {
        return localVars;
    }

    public OperandStack getOperandStack() {
        return operandStack;
    }
}

是一个链表的基本单位,包含局部变量表(用来存放计算过程中的变量和临时生成的变量),操作数栈(用来存放待计算的变量)

slot

package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 14 23
 * @Description:
 * 局部变量表是按照索引访问的,所以可以把它想象成一个数组,根据虚拟机规范,这个数组每个元素至少可以容纳一个int,或引用值,两个连续的元素可以容纳一个一个long或double值
 */
public class Slot {
    public int num;
    public Object ref;
    public Slot(){};
}

局部变量表和操作数栈的基本组成单位。可以存放一个基本类型或引用

引用

package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 14 22
 * @Description:作为对象引用
 */
public class Object {

}

局部变量表和操作数栈

package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 15 04
 * @Description:
 */
public class LocalVars {
    private Slot[] localvars;
    public LocalVars(int maxLocals){
        if(maxLocals > 0){
            localvars = new Slot[maxLocals];
        }else {
            throw new RuntimeException("maxLocal < 0");
        }
    }

    /**
     *局部变量表中存的数据是基本类型和引用,下面是他们的get set 方法
     */
    public void setInt(int index, int val){
        Slot slot = new Slot();
        slot.num = val;
        localvars[index] = slot;
    }
    public int getInt(int index){
        return localvars[index].num;
    }

    public void setFloat(int index, float val){
        Slot slot = new Slot();
        slot.num = Float.floatToIntBits(val);
        localvars[index] = slot;
    }
    public float getFloat(int index){
        return Float.intBitsToFloat(localvars[index].num);
    }

    public void setLong(int index, long val){
        /**
         * 低32位
         */
        Slot low = new Slot();
        low.num = (int)val;
        localvars[index] = low;
        /**
         * 高32位
         */
        Slot high = new Slot();
        high.num = (int)(val >> 32);
        localvars[index + 1] = high;
    }
    public long getLong(int index){
        /**
         * 如果是负数,jvm会根据符号位扩展,填充32个1
         */
        long low = (long)localvars[index].num & 0xffffffff;
        long high = (long)localvars[index + 1].num << 32;
        return high|low;
    }

    public void setDouble(int index, double val){
        long num = Double.doubleToLongBits(val);
        setLong(index,num);
    }
    public double getDouble(int index){
        return Double.longBitsToDouble(getLong(index));
    }

    public void setRef(int index, Object ref){
        Slot slot = new Slot();
        slot.ref = ref;
        localvars[index] = slot;
    }
    public Object getRef(int index){
        return localvars[index].ref;
    }

}
package classfile.rtda;

/**
 * @Author:ggp
 * @Date:2019/2/13 15 04
 * @Description:
 */
public class OperandStack {
    /**
     * 栈顶元素在数组的位置(index),是基本类型,不初始化默认值是0
     */
    private int size;
    private Slot[] operandStack;

    /**
     *
     * @param maxStack 操作栈的深度
     */
    public OperandStack(int maxStack){
        if(maxStack > 0){
            operandStack = new Slot[maxStack];
        }else{
         throw new RuntimeException("maxStack < 0");
        }

    }

    public void pushInt(int val){
        Slot slot = new Slot();
        slot.num = val;
        operandStack[size++] = slot;
    }
    public int popInt(){
        return operandStack[--size].num;
    }

    public void pushFloat(float val){
        Slot slot = new Slot();
        slot.num = Float.floatToIntBits(val);
        operandStack[size++] =slot;
    }
    public float popFloat(){
        return Float.intBitsToFloat(operandStack[--size].num);
    }

    public void pushLong(long val){
        Slot low = new Slot();
        low.num = (int)val;
        operandStack[size++] = low;

        Slot high = new Slot();
        high.num = (int)(val >> 32);
        operandStack[size++] = high;
    }
    public long popLong(){
        long high = (long)operandStack[--size].num << 32;
        long low = (long)operandStack[--size].num & 0xffffffff;
        return high|low;

    }

    public void pushDouble(double val){
        long num = Double.doubleToLongBits(val);
        pushLong(num);
    }
    public double popDouble(){
        return Double.longBitsToDouble(popLong());
    }
    public void pushRef(Object ref){
        Slot slot = new Slot();
        slot.ref = ref;
        operandStack[size++] = slot;
    }
    public Object popRef(){
        return operandStack[--size].ref;
    }
}

都是有slot数组构成,说明它们存放的只能是基本类型或引用,需要注意的还是,jvm的符号位扩展问题

测试方法,修改Main类

import classfile.ClassFile;
import classfile.rtda.Frame;
import classfile.rtda.LocalVars;
import classfile.rtda.OperandStack;
import classpath.ClassPath;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.Arrays;

/**
 * @ClassName Main
 * @Description TODO
 * @Author Mr.G
 * @Date 2018/10/9 10:43
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args){
        Cmd cmd=new Cmd(args);
        if(!cmd.isRightFmt||cmd.helpFlag){
            cmd.printUsage();
        }else if(cmd.versionFlag){
            System.out.println("version 0.0.1");
        }else{
            startJVM(cmd);
        }
    }
    public static void startJVM(Cmd cmd){
        Frame frame = new Frame(100, 100);
        testLocalVars(frame.getLocalVars());
        testOperandStack(frame.getOperandStack());

    }
    public static void testLocalVars(LocalVars localVars){
        localVars.setInt(0,100);
        localVars.setInt(1, -100);
        localVars.setLong(2, 299792580);
        localVars.setLong(4,-299792580);
        localVars.setFloat(6, (float) 3.12);
        localVars.setFloat(7, (float)-3.12);
        localVars.setDouble(8, 3.14159265358979);
        localVars.setDouble(10, -3.14159265358979);
        localVars.setRef(12, null);
        System.out.println(localVars.getInt(0));
        System.out.println(localVars.getInt(1));
        System.out.println(localVars.getLong(2));
        System.out.println(localVars.getLong(4));
        System.out.println(localVars.getFloat(6));
        System.out.println(localVars.getFloat(7));
        System.out.println(localVars.getDouble(8));
        System.out.println(localVars.getDouble(10));
        System.out.println(localVars.getRef(12));

    }
    public static void testOperandStack(OperandStack operandStack){
        operandStack.pushInt(100);
        operandStack.pushInt(-100);
        operandStack.pushLong(299792580);
        operandStack.pushLong(-299792580);
        operandStack.pushFloat((float) 3.12);
        operandStack.pushFloat((float)-3.12);
        operandStack.pushDouble(3.14159265358979);
        operandStack.pushDouble(-3.14159265358979);
        operandStack.pushRef(null);
        System.out.println(operandStack.popRef());
        System.out.println(operandStack.popDouble());
        System.out.println(operandStack.popDouble());
        System.out.println(operandStack.popFloat());
        System.out.println(operandStack.popFloat());
        System.out.println(operandStack.popLong());
        System.out.println(operandStack.popLong());
        System.out.println(operandStack.popInt());
        System.out.println(operandStack.popInt());

    }


}

测试结果

《自己动手写java虚拟机》学习笔记(八)-----线程私有运行时数据区(java)_第2张图片

你可能感兴趣的:(jvm)