mirror of
https://github.com/FranzHaidnor/haidnorJVM.git
synced 2026-03-13 21:43:42 +08:00
add PUTSTATIC Instruction
支持静态变量
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
package haidnor.jvm.classloader;
|
package haidnor.jvm.classloader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wang xiang
|
||||||
|
*/
|
||||||
public class BootstrapClassLoader {
|
public class BootstrapClassLoader {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<>();
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ package haidnor.jvm.test.clazz;
|
|||||||
|
|
||||||
public class Student extends Human {
|
public class Student extends Human {
|
||||||
|
|
||||||
|
public static String name = "张三";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user