This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging

Overview of the runtime data area

The Java Virtual Machine specification calls these memory areas runtime data areas. Runtime data areas can be divided into two categories: those that are shared by multiple threads and those that are thread private.

The memory area shared by multiple threads mainly holds two types of data: class data and class instances (that is, objects). Object data is stored in the Heap, and class data is stored in the Method Area. Each thread has its own PC register (Program Counter) and Java Virtual Machine stack (JVMStack). The Java virtual machine Stack is also composed of Stack frames (frames for short), which hold the state of method execution, including Local Variable and Operand Stack.

code

thread

/ * * *@Author blackcat
 * @createWhen 2021/8/12 *@version: 1.0
 * @description: thread * /
public class JThread {

    //Program Counter register
    private int pc;

    // Virtual machine stack
    private JvmStack stack;


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

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

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

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

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

    public Frame currentFrame(a){
        return this.stack.top(); }}Copy the code

The virtual machine stack

Java Virtual Machine Stacks, also known as Java Stacks in the early days. Each thread creates a virtual machine Stack when it is created, which holds a Stack Frame that corresponds to each Java method call. The Stack Frame is thread private and has the same lifetime as the thread.



/ * * *@Author blackcat
 * @createWhen 2021/8/12 *@version: 1.0
 * @description: Vm stack */
public class JvmStack {

    // The capacity of the stack, the maximum number of frames it can hold
    private int maxSize;
    // The current stack size
    private int size;
    // Top of the stack pointer
    private Frame _top;


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

    // Push the frame to the top of the stack
    public void push(Frame frame) {
        // If the stack is full,StackOverflowError is abnormal
        if (this.size > this.maxSize) {
            throw new StackOverflowError();
        }

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

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

    public Frame pop(a) {
        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(a){
        if (this._top == null) {throw new RuntimeException("jvm stack is empty!");
        }
        return this._top; }}Copy the code

The stack frame

Each Stack Frame contains:

Local Variables

Operand Stack (or expression Stack)

Dynamic Linking: A method reference to a pool of runtime constants

Method Return Address: The Address at which the method exits normally or abnormally

Some additional information

This example contains only the first two

/ * * *@Author blackcat
 * @create2021/8/12 days *@version: 1.0
 * @description: * / stack frame
public class Frame {

    //stack is implemented as linked list
    Frame lower;

    // Local variable table
    private LocalVars localVars;

    // Operand stack
    private OperandStack operandStack;

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

    public LocalVars localVars(a){
        return localVars;
    }

    public OperandStack operandStack(a){
        returnoperandStack; }}Copy the code

A local variable

/ * * *@Author blackcat
 * @create2021/8/12 * descend@version: 1.0
 * @description: Local variable scale */
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] = newSlot(); }}}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(a) {
        returnlocalVars.length; }}Copy the code

The operand stack

/ * * *@Author blackcat
 * @create2021/8/12 15:33 the *@version: 1.0
 * @description: Operand stack */
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] = newSlot(); }}public void pushInt(int val) {
        operands[size].num = val;
        size++;
    }

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

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

    public Object popRef(a) {
        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(a) {
        --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(a) {
        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(a) {
        long res = popLong();
        returnDouble.longBitsToDouble(res); }}/ * * *@Author blackcat
 * @create2021/8/12 15:33 the *@version: 1.0
 * @description: Data slot */
public class Slot {

    int num;
    Object ref;
}
Copy the code

test

import com.black.cat.jvm.rtda.Frame;
import com.black.cat.jvm.rtda.LocalVars;
import com.black.cat.jvm.rtda.OperandStack;


/ * * *@Author blackcat
 * @create2021/8/11 shine forth *@version: 1.0
 * @description: Command line tool */
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: 
      
[-options] class [args...] "
); return; } if (cmd.versionFlag) { System.out.println("Java version \" 1.8.0 comes with \ ""); 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.1415926 F); 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.1415926 F); 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()); }}Copy the code

The results of

Note: Float has some accuracy issues

100-100 2997924580-2997924580 3.1415925 2.71828182845 NULL NULL 2.71828182845 3.1415925-2997924580 2997924580-100 100Copy the code