Files
haidnorJVM/src/main/java/haidnor/jvm/runtime/Frame.java
2023-10-25 15:21:04 +08:00

244 lines
6.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package haidnor.jvm.runtime;
import haidnor.jvm.bcel.Const;
import haidnor.jvm.bcel.classfile.Code;
import haidnor.jvm.bcel.classfile.JavaClass;
import haidnor.jvm.bcel.classfile.JavaMethod;
import haidnor.jvm.rtda.Instance;
import haidnor.jvm.util.CodeStream;
import lombok.Getter;
import java.util.Stack;
/**
* JVM 线程栈帧
*/
public class Frame {
/**
* 每个栈帧中包含一个指向运行时常量池中该栈帧所属的方法的引用。包含这个引用的目的就是为了支持当前方法实现动态链接
* 有了这个引用,执行引擎就可以找到指定的方法,加载字节码指令
*/
@Getter
public final JavaClass javaClass;
/**
* 当前栈帧所处于的 JVM 线程
*/
@Getter
private final JVMThread jvmThread;
/**
* 栈帧所属的方法
* <p>
* <<深入理解JAVA虚拟机>>:
* 每一个栈帧都包含一个指向运行时常量池中该栈帧所属的方法引用,持有这个引用的目的是为了支持方法调用过程中的动态链接(Dynamic Linking)
*/
@Getter
private final JavaMethod javaMethod;
/**
* 栈帧所属的方法代码对象
*/
private final Code code;
@Getter
private final CodeStream codeStream;
/**
* 操作数栈
*/
private final Stack<StackValue> operandStack = new Stack<>();
/**
* 槽位
*/
private final Slot[] slots;
public Frame(JVMThread thread, JavaMethod javaMethod) {
this.jvmThread = thread;
this.javaClass = javaMethod.getJavaClass();
this.javaMethod = javaMethod;
this.code = javaMethod.getCode();
this.codeStream = new CodeStream(javaMethod.getCode());
this.slots = new Slot[code.getMaxLocals()];
}
public int getCodeLength() {
return this.code.getCode().length;
}
public JavaMethod getMetaMethod() {
return javaMethod;
}
/* 操作数栈操作 --------------------------------------------------------------------------------------------------- */
/**
* 压入操作数栈
*/
public void push(StackValue stackValue) {
this.operandStack.push(stackValue);
}
/**
* 弹出操作数栈顶元素
*/
public StackValue pop() {
return this.operandStack.pop();
}
/**
* 弹出操作数栈顶元素
*/
public StackValue peek() {
return this.operandStack.peek();
}
/**
* 从操作数栈中弹出指定数量的元素的值
*/
public Object[] popStacksValue(int num) {
Object[] objArr = new Object[num];
for (int i = num - 1; i >= 0; i--) {
StackValue stackValue = operandStack.pop();
switch (stackValue.getValueType()) {
case Const.T_CHAR, Const.T_INT, Const.T_OBJECT, Const.T_LONG, Const.T_DOUBLE, Const.T_FLOAT:
break;
case Const.T_ARRAY:
throw new Error("数组类型,未作处理");
default:
throw new Error("无法识别的参数类型");
}
objArr[i] = stackValue.getValue();
}
return objArr;
}
public int popInt() {
StackValue stackValue = pop();
return (int) stackValue.getValue();
}
public void pushInt(int value) {
push(new StackValue(Const.T_INT, value));
}
public long popLong() {
StackValue stackValue = pop();
return (long) stackValue.getValue();
}
public void pushLong(long value) {
push(new StackValue(Const.T_LONG, value));
}
public float popFloat() {
StackValue stackValue = pop();
return (float) stackValue.getValue();
}
public void pushFloat(float value) {
push(new StackValue(Const.T_FLOAT, value));
}
public double popDouble() {
StackValue stackValue = pop();
return (double) stackValue.getValue();
}
public void pushDouble(double value) {
push(new StackValue(Const.T_DOUBLE, value));
}
public Instance popRef() {
StackValue stackValue = pop();
return (Instance) stackValue.getValue();
}
public void pushRef(Object value) {
push(new StackValue(Const.T_OBJECT, value));
}
/**
* 获取操作数栈中元素的数量
*/
public int operandStackSize() {
return this.operandStack.size();
}
/* 局部变量表操作 --------------------------------------------------------------------------------------------------- */
public void slotSetInt(int index, int val) {
slots[index] = new Slot(val);
}
public int slotGetInt(int index) {
return slots[index].num;
}
public void slotSetFloat(int index, float val) {
int tmp = Float.floatToIntBits(val);
slots[index] = new Slot(tmp);
}
public float slotGetFloat(int index) {
int num = slots[index].num;
return Float.intBitsToFloat(num);
}
public long slotGetLong(int index) {
int high = slots[index].num;
int low = slots[index + 1].num;
long l1 = (high & 0x000000ffffffffL) << 32;
long l2 = low & 0x00000000ffffffffL;
return l1 | l2;
}
public void slotSetLong(int index, long val) {
// high 32
int high = (int) (val >> 32);
// low 32
int low = (int) (val & 0x000000ffffffffL);
slots[index] = new Slot(high);
slots[index + 1] = new Slot(low);
}
public void slotSetDouble(int index, double val) {
long tmp = Double.doubleToLongBits(val);
// high 32
int high = (int) (tmp >> 32);
// low 32
int low = (int) (tmp & 0x000000ffffffffL);
slots[index] = new Slot(high);
slots[index + 1] = new Slot(low);
}
public double slotGetDouble(int index) {
long tmp = this.slotGetLong(index);
return Double.longBitsToDouble(tmp);
}
public void slotSetRef(int index, Object ref) {
slots[index] = new Slot(ref);
}
public Object slotGetRef(int index) {
return slots[index].ref;
}
public void slotSet(int index, StackValue stackValue) {
switch (stackValue.getValueType()) {
case Const.T_CHAR -> throw new Error("T_CHAR未作处理");
case Const.T_INT -> slotSetInt(index, (int) stackValue.getValue());
case Const.T_OBJECT -> slotSetRef(index, stackValue.getValue());
case Const.T_LONG -> slotSetLong(index, (long) stackValue.getValue());
case Const.T_DOUBLE -> slotSetDouble(index, (double) stackValue.getValue());
case Const.T_FLOAT -> slotSetFloat(index, (float) stackValue.getValue());
case Const.T_ARRAY -> throw new Error("T_ARRAY未作处理");
default -> throw new Error("无法识别的参数类型");
}
}
}