diff --git a/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java b/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java index 68c4e9a..7230ee5 100644 --- a/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java +++ b/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java @@ -1,5 +1,8 @@ package haidnor.jvm.classloader; +/** + * @author wang xiang + */ public class BootstrapClassLoader { } diff --git a/src/main/java/haidnor/jvm/classloader/ClassLoader.java b/src/main/java/haidnor/jvm/classloader/ClassLoader.java index 5727204..1cf5cf1 100644 --- a/src/main/java/haidnor/jvm/classloader/ClassLoader.java +++ b/src/main/java/haidnor/jvm/classloader/ClassLoader.java @@ -1,9 +1,12 @@ package haidnor.jvm.classloader; +import haidnor.jvm.core.JavaExecutionEngine; import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; import haidnor.jvm.rtda.metaspace.Metaspace; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; import java.io.File; import java.io.FileInputStream; @@ -12,6 +15,9 @@ import java.io.IOException; import java.net.URL; import java.util.Properties; +/** + * @author wang xiang + */ public class ClassLoader { public final String name; @@ -46,7 +52,6 @@ public class ClassLoader { public Klass loadClass(String classPath) throws IOException { ClassParser classParser; if (classPath.startsWith("java/")) { - if (!new File(rtJarPath).exists()) { throw new IllegalStateException("rt.jar not found"); } @@ -60,6 +65,17 @@ public class ClassLoader { JavaClass javaClass = classParser.parse(); Klass klass = new Klass(this, javaClass); Metaspace.registerJavaClass(klass); + + if (!classPath.startsWith("java/")) { + // do clinit + for (Method method : javaClass.getMethods()) { + if (method.toString().equals("static void ()")) { + KlassMethod klassMethod = new KlassMethod(klass, method); + JavaExecutionEngine.callMethod(null, klassMethod); + break; + } + } + } return klass; } @@ -68,6 +84,14 @@ public class ClassLoader { JavaClass javaClass = classParser.parse(); Klass klass = new Klass(this, javaClass); Metaspace.registerJavaClass(klass); + // do clinit + for (Method method : javaClass.getMethods()) { + if (method.toString().equals("static void ()")) { + KlassMethod klassMethod = new KlassMethod(klass, method); + JavaExecutionEngine.callMethod(null, klassMethod); + break; + } + } return klass; } diff --git a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java index d12ae5f..92d4987 100644 --- a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java +++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java @@ -28,27 +28,31 @@ public class JavaExecutionEngine { JvmThread jvmThread = JvmThreadHolder.get(); Frame newFrame = new Frame(jvmThread, klassMethod); - Method method = klassMethod.javaMethod; - String signature = method.getSignature(); - String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature); + // 如果有上一个栈帧, 代表需要传参 + if (lastFrame != null) { + Method method = klassMethod.javaMethod; + String signature = method.getSignature(); + String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature); - int argumentSlotSize = argumentTypes.length; - if (!method.isStatic()) { - argumentSlotSize++; - } + int argumentSlotSize = argumentTypes.length; + if (!method.isStatic()) { + argumentSlotSize++; + } - // 静态方法调用传参 - // 将上一个栈帧操作数栈中数据弹出,存入下一个栈帧的局部变量表中 - LocalVariableTable localVariableTable = method.getLocalVariableTable(); - if (localVariableTable != null) { - for (int i = argumentSlotSize - 1; i >= 0; i--) { - LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable(); - LocalVariable localVariable = localVariableArr[i]; - int slotIndex = localVariable.getIndex(); - StackValue stackValue = lastFrame.pop(); - newFrame.slotSet(slotIndex, stackValue); + // 方法调用传参 + // 将上一个栈帧操作数栈中数据弹出,存入下一个栈帧的局部变量表中 + LocalVariableTable localVariableTable = method.getLocalVariableTable(); + if (localVariableTable != null) { + for (int i = argumentSlotSize - 1; i >= 0; i--) { + LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable(); + LocalVariable localVariable = localVariableArr[i]; + int slotIndex = localVariable.getIndex(); + StackValue stackValue = lastFrame.pop(); + newFrame.slotSet(slotIndex, stackValue); + } } } + jvmThread.push(newFrame); Interpreter.executeFrame(newFrame); } diff --git a/src/main/java/haidnor/jvm/instruction/InstructionFactory.java b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java index 1184570..370a4f9 100644 --- a/src/main/java/haidnor/jvm/instruction/InstructionFactory.java +++ b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java @@ -556,7 +556,7 @@ public abstract class InstructionFactory { return new GETSTATIC(codeStream); } case Const.PUTSTATIC -> { - throw new Error("Not support JavaVM opcode PUTSTATIC"); + return new PUTSTATIC(codeStream); } case Const.GETFIELD -> { return new GETFIELD(codeStream); diff --git a/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java b/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java index 46fcf0e..46900c5 100644 --- a/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java +++ b/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java @@ -1,6 +1,9 @@ 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.runtime.StackValue; import haidnor.jvm.util.CodeStream; @@ -9,11 +12,14 @@ import lombok.SneakyThrows; import org.apache.bcel.Const; import org.apache.bcel.classfile.ConstantFieldref; import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.Utility; import java.lang.reflect.Field; /** * 获取字段符号引用指定的对象或者值(类的静态字段 static 修饰),并将其压入操作数栈 + * + * @author wang xiang */ public class GETSTATIC extends Instruction { @@ -23,6 +29,7 @@ public class GETSTATIC extends Instruction { super(codeStream); this.constantFieldrefIndex = codeStream.readUnsignedShort(this); } + @Override @SneakyThrows public void execute(Frame frame) { @@ -33,14 +40,18 @@ public class GETSTATIC extends Instruction { String className = constantPoolUtil.getFiledBelongClassName(constFieldref); // 动态链接. 找到字段的名字 String fieldName = constantPoolUtil.getFieldName(constFieldref); - // 以上代码体现了动态链接.Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数. - Class clazz = Class.forName(className.replace('/', '.')); - Field field = clazz.getField(fieldName); - Object staticFiledValue = field.get(null); // 获取静态字段上的值 - - frame.push(new StackValue(Const.T_OBJECT, staticFiledValue)); + if (className.startsWith("java/")) { + Class clazz = Class.forName(className.replace('/', '.')); + Field field = clazz.getField(fieldName); + Object staticFiledValue = field.get(null); // 获取静态字段上的值 + 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())); + } } } diff --git a/src/main/java/haidnor/jvm/instruction/references/PUTSTATIC.java b/src/main/java/haidnor/jvm/instruction/references/PUTSTATIC.java new file mode 100644 index 0000000..5243aa9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/PUTSTATIC.java @@ -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()); + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/Klass.java b/src/main/java/haidnor/jvm/rtda/heap/Klass.java index 9a071fd..190f3d5 100644 --- a/src/main/java/haidnor/jvm/rtda/heap/Klass.java +++ b/src/main/java/haidnor/jvm/rtda/heap/Klass.java @@ -6,7 +6,9 @@ import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.JavaClass; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 类元信息 @@ -32,6 +34,11 @@ public class Klass { private Klass superKlass; + /** + * 静态字段 + */ + private Map staticFieldMap = new HashMap<>(); + @SneakyThrows public Klass(ClassLoader classLoader, JavaClass javaClass) { this.javaClass = javaClass; @@ -39,12 +46,24 @@ public class Klass { this.className = javaClass.getClassName(); 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(); if (superJavaClass != null) { this.superKlass = new Klass(classLoader, superJavaClass); } } + public KlassField getStaticField(String filedName) { + return staticFieldMap.get(filedName); + } + public Instance newInstance() { // 创建对象存放字段的内存空间 List klassFieldList = new ArrayList<>(); diff --git a/src/test/java/haidnor/jvm/test/clazz/Student.java b/src/test/java/haidnor/jvm/test/clazz/Student.java index 3c674ef..e14ad91 100644 --- a/src/test/java/haidnor/jvm/test/clazz/Student.java +++ b/src/test/java/haidnor/jvm/test/clazz/Student.java @@ -2,4 +2,6 @@ package haidnor.jvm.test.clazz; public class Student extends Human { + public static String name = "张三"; + } diff --git a/src/test/java/haidnor/jvm/test/demo/Demo4.java b/src/test/java/haidnor/jvm/test/demo/Demo4.java index 4d91193..c5255ce 100644 --- a/src/test/java/haidnor/jvm/test/demo/Demo4.java +++ b/src/test/java/haidnor/jvm/test/demo/Demo4.java @@ -7,7 +7,6 @@ public class Demo4 { public static void main(String[] args) { Student student = new Student(); student.eat(); - new Thread(() -> {}).start(); } }