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