add PUTSTATIC Instruction

支持静态变量
This commit is contained in:
wangxiang
2023-07-21 14:11:51 +08:00
parent 2e89a8585e
commit 6211a0d8f1
9 changed files with 132 additions and 26 deletions

View File

@@ -1,5 +1,8 @@
package haidnor.jvm.classloader; package haidnor.jvm.classloader;
/**
* @author wang xiang
*/
public class BootstrapClassLoader { public class BootstrapClassLoader {
} }

View File

@@ -1,9 +1,12 @@
package haidnor.jvm.classloader; package haidnor.jvm.classloader;
import haidnor.jvm.core.JavaExecutionEngine;
import haidnor.jvm.rtda.heap.Klass; import haidnor.jvm.rtda.heap.Klass;
import haidnor.jvm.rtda.heap.KlassMethod;
import haidnor.jvm.rtda.metaspace.Metaspace; import haidnor.jvm.rtda.metaspace.Metaspace;
import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -12,6 +15,9 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Properties; import java.util.Properties;
/**
* @author wang xiang
*/
public class ClassLoader { public class ClassLoader {
public final String name; public final String name;
@@ -46,7 +52,6 @@ public class ClassLoader {
public Klass loadClass(String classPath) throws IOException { public Klass loadClass(String classPath) throws IOException {
ClassParser classParser; ClassParser classParser;
if (classPath.startsWith("java/")) { if (classPath.startsWith("java/")) {
if (!new File(rtJarPath).exists()) { if (!new File(rtJarPath).exists()) {
throw new IllegalStateException("rt.jar not found"); throw new IllegalStateException("rt.jar not found");
} }
@@ -60,6 +65,17 @@ public class ClassLoader {
JavaClass javaClass = classParser.parse(); JavaClass javaClass = classParser.parse();
Klass klass = new Klass(this, javaClass); Klass klass = new Klass(this, javaClass);
Metaspace.registerJavaClass(klass); Metaspace.registerJavaClass(klass);
if (!classPath.startsWith("java/")) {
// do clinit
for (Method method : javaClass.getMethods()) {
if (method.toString().equals("static void <clinit>()")) {
KlassMethod klassMethod = new KlassMethod(klass, method);
JavaExecutionEngine.callMethod(null, klassMethod);
break;
}
}
}
return klass; return klass;
} }
@@ -68,6 +84,14 @@ public class ClassLoader {
JavaClass javaClass = classParser.parse(); JavaClass javaClass = classParser.parse();
Klass klass = new Klass(this, javaClass); Klass klass = new Klass(this, javaClass);
Metaspace.registerJavaClass(klass); Metaspace.registerJavaClass(klass);
// do clinit
for (Method method : javaClass.getMethods()) {
if (method.toString().equals("static void <clinit>()")) {
KlassMethod klassMethod = new KlassMethod(klass, method);
JavaExecutionEngine.callMethod(null, klassMethod);
break;
}
}
return klass; return klass;
} }

View File

@@ -28,27 +28,31 @@ public class JavaExecutionEngine {
JvmThread jvmThread = JvmThreadHolder.get(); JvmThread jvmThread = JvmThreadHolder.get();
Frame newFrame = new Frame(jvmThread, klassMethod); Frame newFrame = new Frame(jvmThread, klassMethod);
Method method = klassMethod.javaMethod; // 如果有上一个栈帧, 代表需要传参
String signature = method.getSignature(); if (lastFrame != null) {
String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature); Method method = klassMethod.javaMethod;
String signature = method.getSignature();
String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature);
int argumentSlotSize = argumentTypes.length; int argumentSlotSize = argumentTypes.length;
if (!method.isStatic()) { if (!method.isStatic()) {
argumentSlotSize++; argumentSlotSize++;
} }
// 静态方法调用传参 // 方法调用传参
// 将上一个栈帧操作数栈中数据弹出,存入下一个栈帧的局部变量表中 // 将上一个栈帧操作数栈中数据弹出,存入下一个栈帧的局部变量表中
LocalVariableTable localVariableTable = method.getLocalVariableTable(); LocalVariableTable localVariableTable = method.getLocalVariableTable();
if (localVariableTable != null) { if (localVariableTable != null) {
for (int i = argumentSlotSize - 1; i >= 0; i--) { for (int i = argumentSlotSize - 1; i >= 0; i--) {
LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable(); LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable();
LocalVariable localVariable = localVariableArr[i]; LocalVariable localVariable = localVariableArr[i];
int slotIndex = localVariable.getIndex(); int slotIndex = localVariable.getIndex();
StackValue stackValue = lastFrame.pop(); StackValue stackValue = lastFrame.pop();
newFrame.slotSet(slotIndex, stackValue); newFrame.slotSet(slotIndex, stackValue);
}
} }
} }
jvmThread.push(newFrame); jvmThread.push(newFrame);
Interpreter.executeFrame(newFrame); Interpreter.executeFrame(newFrame);
} }

View File

@@ -556,7 +556,7 @@ public abstract class InstructionFactory {
return new GETSTATIC(codeStream); return new GETSTATIC(codeStream);
} }
case Const.PUTSTATIC -> { case Const.PUTSTATIC -> {
throw new Error("Not support JavaVM opcode PUTSTATIC"); return new PUTSTATIC(codeStream);
} }
case Const.GETFIELD -> { case Const.GETFIELD -> {
return new GETFIELD(codeStream); return new GETFIELD(codeStream);

View File

@@ -1,6 +1,9 @@
package haidnor.jvm.instruction.references; package haidnor.jvm.instruction.references;
import haidnor.jvm.instruction.Instruction; import haidnor.jvm.instruction.Instruction;
import haidnor.jvm.rtda.heap.Klass;
import haidnor.jvm.rtda.heap.KlassField;
import haidnor.jvm.rtda.metaspace.Metaspace;
import haidnor.jvm.runtime.Frame; import haidnor.jvm.runtime.Frame;
import haidnor.jvm.runtime.StackValue; import haidnor.jvm.runtime.StackValue;
import haidnor.jvm.util.CodeStream; import haidnor.jvm.util.CodeStream;
@@ -9,11 +12,14 @@ import lombok.SneakyThrows;
import org.apache.bcel.Const; import org.apache.bcel.Const;
import org.apache.bcel.classfile.ConstantFieldref; import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.Utility;
import java.lang.reflect.Field; import java.lang.reflect.Field;
/** /**
* 获取字段符号引用指定的对象或者值(类的静态字段 static 修饰),并将其压入操作数栈 * 获取字段符号引用指定的对象或者值(类的静态字段 static 修饰),并将其压入操作数栈
*
* @author wang xiang
*/ */
public class GETSTATIC extends Instruction { public class GETSTATIC extends Instruction {
@@ -23,6 +29,7 @@ public class GETSTATIC extends Instruction {
super(codeStream); super(codeStream);
this.constantFieldrefIndex = codeStream.readUnsignedShort(this); this.constantFieldrefIndex = codeStream.readUnsignedShort(this);
} }
@Override @Override
@SneakyThrows @SneakyThrows
public void execute(Frame frame) { public void execute(Frame frame) {
@@ -33,14 +40,18 @@ public class GETSTATIC extends Instruction {
String className = constantPoolUtil.getFiledBelongClassName(constFieldref); String className = constantPoolUtil.getFiledBelongClassName(constFieldref);
// 动态链接. 找到字段的名字 // 动态链接. 找到字段的名字
String fieldName = constantPoolUtil.getFieldName(constFieldref); String fieldName = constantPoolUtil.getFieldName(constFieldref);
// 以上代码体现了动态链接.Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数. // 以上代码体现了动态链接.Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数.
Class<?> clazz = Class.forName(className.replace('/', '.')); if (className.startsWith("java/")) {
Field field = clazz.getField(fieldName); Class<?> clazz = Class.forName(className.replace('/', '.'));
Object staticFiledValue = field.get(null); // 获取静态字段上的值 Field field = clazz.getField(fieldName);
Object staticFiledValue = field.get(null); // 获取静态字段上的值
frame.push(new StackValue(Const.T_OBJECT, staticFiledValue)); frame.push(new StackValue(Const.T_OBJECT, staticFiledValue));
} else {
Klass javaClass = Metaspace.getJavaClass(Utility.compactClassName(className));
KlassField staticField = javaClass.getStaticField(fieldName);
frame.push(new StackValue(Const.T_OBJECT, staticField.getValue()));
}
} }
} }

View File

@@ -0,0 +1,44 @@
package haidnor.jvm.instruction.references;
import haidnor.jvm.instruction.Instruction;
import haidnor.jvm.rtda.heap.Klass;
import haidnor.jvm.rtda.heap.KlassField;
import haidnor.jvm.rtda.metaspace.Metaspace;
import haidnor.jvm.runtime.Frame;
import haidnor.jvm.util.CodeStream;
import haidnor.jvm.util.ConstantPoolUtil;
import lombok.SneakyThrows;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.Utility;
/**
* @author wang xiang
*/
public class PUTSTATIC extends Instruction {
private final int constantFieldrefIndex;
public PUTSTATIC(CodeStream codeStream) {
super(codeStream);
this.constantFieldrefIndex = codeStream.readUnsignedShort(this);
}
@Override
@SneakyThrows
public void execute(Frame frame) {
ConstantPool constantPool = frame.getConstantPool();
ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil();
ConstantFieldref constFieldref = constantPool.getConstant(constantFieldrefIndex);
// 动态链接. 找到字段所属的 Java 类
String className = constantPoolUtil.getFiledBelongClassName(constFieldref);
// 动态链接. 找到字段的名字
String fieldName = constantPoolUtil.getFieldName(constFieldref);
// 以上代码体现了动态链接.Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数.
Klass javaClass = Metaspace.getJavaClass(Utility.compactClassName(className));
KlassField staticField = javaClass.getStaticField(fieldName);
staticField.setVal(frame.pop());
}
}

View File

@@ -6,7 +6,9 @@ import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.JavaClass;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 类元信息 * 类元信息
@@ -32,6 +34,11 @@ public class Klass {
private Klass superKlass; private Klass superKlass;
/**
* 静态字段
*/
private Map<String, KlassField> staticFieldMap = new HashMap<>();
@SneakyThrows @SneakyThrows
public Klass(ClassLoader classLoader, JavaClass javaClass) { public Klass(ClassLoader classLoader, JavaClass javaClass) {
this.javaClass = javaClass; this.javaClass = javaClass;
@@ -39,12 +46,24 @@ public class Klass {
this.className = javaClass.getClassName(); this.className = javaClass.getClassName();
this.superClassName = javaClass.getSuperclassName(); this.superClassName = javaClass.getSuperclassName();
// init staticFieldMap
for (Field field : javaClass.getFields()) {
if (field.isStatic()) {
staticFieldMap.put(field.getName(), new KlassField(field));
}
}
// loader super class
JavaClass superJavaClass = javaClass.getSuperClass(); JavaClass superJavaClass = javaClass.getSuperClass();
if (superJavaClass != null) { if (superJavaClass != null) {
this.superKlass = new Klass(classLoader, superJavaClass); this.superKlass = new Klass(classLoader, superJavaClass);
} }
} }
public KlassField getStaticField(String filedName) {
return staticFieldMap.get(filedName);
}
public Instance newInstance() { public Instance newInstance() {
// 创建对象存放字段的内存空间 // 创建对象存放字段的内存空间
List<KlassField> klassFieldList = new ArrayList<>(); List<KlassField> klassFieldList = new ArrayList<>();

View File

@@ -2,4 +2,6 @@ package haidnor.jvm.test.clazz;
public class Student extends Human { public class Student extends Human {
public static String name = "张三";
} }

View File

@@ -7,7 +7,6 @@ public class Demo4 {
public static void main(String[] args) { public static void main(String[] args) {
Student student = new Student(); Student student = new Student();
student.eat(); student.eat();
new Thread(() -> {}).start();
} }
} }