commit ff0fcd92bd3e69bb8d0d68cc70afe8bb4b364290 Author: wangxiang <276644985@qq.com> Date: Wed Jul 19 18:06:38 2023 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdb6b0a --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# haidnorJVM +使用 Java17 编写的 Java 虚拟机 + +## 意义 +1. 纸上得来终觉浅,绝知此事要躬行。只学习 JVM 机制和理论,很多时候任然觉得缺乏那种大彻大悟之感 +2. 使用简单的方式实现 JVM,用于学习理解 JVM 运行原理 + +## 主要技术选型 +* [Java 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) +* [Apache Commons BCEL](https://commons.apache.org/proper/commons-bcel/) +* [Apache Commons CLI](https://commons.apache.org/proper/commons-cli/) + +# 实现功能与局限性 +* 支持基本数据类型数学运算 +* 支持循环、条件结构代码 +* 支持创建对象,访问对象 +* 支持多态 +* 支持访问静态方法 +* 不支持多线程 +* 垃圾回收依靠宿主 JVM + +# 快速体验 +## 你需要准备什么 +1. 集成开发环境 (IDE)。你可以选择包括 IntelliJ IDEA、Spring Tools、Visual Studio Code 或 Eclipse 等等 +2. JDK 17。并配置 JAVA_HOME +3. JDK 8。强烈推荐! haidnorJVM 的主要目标是运行 Java8 本版的字节码文件。(haidnorVM 没有强制要求字节码文件是 Java8 版本) +4. Maven + +## 配置 haidnorJVM +### 配置日志输出级别 +修改 `simplelogger.properties` 文件中的内容。配置日志输出级别,一般使用 `debug`、`info` + +### 配置 rt.jar +修改 `haidnorJVM.properties` 文件中的内容。配置 rt.jar 的绝对路径,例如`rt.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar` + +## 运行单元测试用例 +打开 test 目录下的 `haidnor.jvm.test.TestJVM` 类文件。 这是 haidnorJVM 功能的主要测试类。 里面的测试方法可以解析并加载一些class字节码文件。 +```java +@Test +public void test_LSUB() throws Exception { + runMainClass(LSUB.class); +} +``` +例如以上代码会加载 LSUB.class 类在 target 目录下的字节码文件,然后使用 haidnorJVM 运行其中的 main 函数。你可以使用打断点的方式看到 haidnorJVM 是如何解释运行 Java 字节码的。 +值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。 + +## 运行 .class 文件 +1. 使用 maven 命令将项目编译打包,得到 `haidnorJVM-1.0.jar` 文件 +2. 编写一个简单的程序,例如以下代码 + ```java + public class HelloWorld { + public static void main(String[] args) { + System.out.println("HelloWorld"); + } + } + ``` +3. 编译代码,得到 HelloWorld.class 文件。(推荐使用 JDK8 进行编译) +4. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM-1.0-SNAPSHOT.jar -class R:\HelloWorld.class`。注意需要 class 文件的绝对路径 + +## 运行 .jar 文件 +开发中... + +# 联系作者 +个人微信账号: haidnor (请备注 "JVM") \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b146cf7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + haindor.vm + haidnorJVM + 1.0 + + + 17 + 17 + UTF-8 + + + + + + commons-cli + commons-cli + 1.5.0 + + + + + org.apache.bcel + bcel + 6.7.0 + + + + org.projectlombok + lombok + 1.18.26 + + + + + org.slf4j + slf4j-api + 2.0.7 + + + + + org.slf4j + slf4j-simple + 2.0.7 + + + + junit + junit + 4.13.1 + test + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + + + haidnor.jvm.Main + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/Main.java b/src/main/java/haidnor/jvm/Main.java new file mode 100644 index 0000000..4f2f5ad --- /dev/null +++ b/src/main/java/haidnor/jvm/Main.java @@ -0,0 +1,48 @@ +package haidnor.jvm; + +import haidnor.jvm.classloader.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 haidnor.jvm.runtime.JvmThread; +import haidnor.jvm.util.JavaClassUtil; +import haidnor.jvm.util.JvmThreadHolder; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.cli.*; + +@Slf4j +public class Main { + + @SneakyThrows + public static void main(String[] args) { + Option jarOption = new Option("jar", true, "运行 jar 程序"); + Option classOption = new Option("class", true, "运行 .class 字节码文件"); + + OptionGroup optionGroup = new OptionGroup(); + optionGroup.addOption(jarOption).addOption(classOption); + + Options options = new Options(); + options.addOptionGroup(optionGroup); + + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = parser.parse(options, args); + + if (cmd.hasOption("jar")) { + String path = cmd.getOptionValue("jar"); + // TODO + } + if (cmd.hasOption("class")) { + String path = cmd.getOptionValue("class"); + ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader"); + Klass mainMeteKlass = bootClassLoader.loadClassWithAbsolutePath(path); + KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass); + Metaspace.registerJavaClass(mainMeteKlass); + JvmThreadHolder.set(new JvmThread()); + + JavaExecutionEngine.callMainStaticMethod(mainKlassMethod); + } + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java b/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java new file mode 100644 index 0000000..68c4e9a --- /dev/null +++ b/src/main/java/haidnor/jvm/classloader/BootstrapClassLoader.java @@ -0,0 +1,5 @@ +package haidnor.jvm.classloader; + +public class BootstrapClassLoader { + +} diff --git a/src/main/java/haidnor/jvm/classloader/ClassLoader.java b/src/main/java/haidnor/jvm/classloader/ClassLoader.java new file mode 100644 index 0000000..45e244a --- /dev/null +++ b/src/main/java/haidnor/jvm/classloader/ClassLoader.java @@ -0,0 +1,82 @@ +package haidnor.jvm.classloader; + +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.metaspace.Metaspace; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +public class ClassLoader { + + public final String name; + + public final static String rtJarPath; + + static { + URL resource = ClassLoader.class.getResource("/"); + String path = resource.getPath(); + FileInputStream fis; + try { + fis = new FileInputStream(path + "/haidnorJVM.properties"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + Properties properties = new Properties(); + try { + properties.load(fis); + } catch (IOException e) { + throw new RuntimeException(e); + } + rtJarPath = properties.getProperty("rt.jar"); + } + + public ClassLoader(String name) { + this.name = name; + } + + /** + * @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader + */ + public Klass loadClass(String classPath) throws IOException { + ClassParser classParser; + if (classPath.startsWith("java/")) { + String rtJarPath = getRtJarPath(); + + if (!new File(rtJarPath).exists()) { + throw new IllegalStateException("rt.jar not found"); + } + classParser = new ClassParser(rtJarPath, classPath + ".class"); + } else { + URL resource = this.getClass().getResource("/"); + String fileName = resource.getPath() + classPath + ".class"; + classParser = new ClassParser(fileName); + } + + JavaClass javaClass = classParser.parse(); + Klass klass = new Klass(this, javaClass); + Metaspace.registerJavaClass(klass); + return klass; + } + + public Klass loadClassWithAbsolutePath(String absolutePath) throws IOException { + ClassParser classParser = new ClassParser(absolutePath); + JavaClass javaClass = classParser.parse(); + Klass klass = new Klass(this, javaClass); + Metaspace.registerJavaClass(klass); + return klass; + } + + private String getRtJarPath() { + // String javaHome = System.getenv("JAVA_HOME"); + // Path rtJarPath = Paths.get(javaHome, "jre", "lib", "rt.jar"); + return rtJarPath; + } + + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/core/Interpreter.java b/src/main/java/haidnor/jvm/core/Interpreter.java new file mode 100644 index 0000000..a563928 --- /dev/null +++ b/src/main/java/haidnor/jvm/core/Interpreter.java @@ -0,0 +1,49 @@ +package haidnor.jvm.core; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.instruction.InstructionFactory; +import haidnor.jvm.instruction.control.RETURN; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * 字节码执行解释器 + */ +@Slf4j +public class Interpreter { + + @SneakyThrows + public static void executeFrame(Frame frame) { + log.debug("------------------------------ Frame START {}", frame.hashCode()); + Map instructionMap = new HashMap<>(); + + // 解析方法中的字节码指令 + log.debug(">>>>>>>>>>>>>>>> PARSE INST START"); + CodeStream codeStream = frame.getCodeStream(); + while (codeStream.available() > 0) { + Instruction instruction = InstructionFactory.creatInstruction(codeStream); + log.debug("{}", instruction); + instructionMap.put(instruction.index(), instruction); + } + log.debug(">>>>>>>>>>>>>>>> PARSE INST END"); + + // 执行方法中的字节码指令 + // int i, 相当于程序计数器, 记录当前执行到的字节码指令的”行号“ + for (int i = 0; i < frame.getCodeLength(); ) { + Instruction instruction = instructionMap.get(i); + log.debug("{}", instruction); + instruction.execute(frame); + if (instruction instanceof RETURN) { + break; + } + i += instruction.offSet(); + } + log.debug("------------------------------ Frame End {}", frame.hashCode()); + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java new file mode 100644 index 0000000..d12ae5f --- /dev/null +++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java @@ -0,0 +1,57 @@ +package haidnor.jvm.core; + + +import haidnor.jvm.rtda.heap.KlassMethod; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.JvmThread; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.JvmThreadHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.bcel.classfile.LocalVariable; +import org.apache.bcel.classfile.LocalVariableTable; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.Utility; + +@Slf4j +public class JavaExecutionEngine { + + public static void callMainStaticMethod(KlassMethod klassMethod) { + JvmThread jvmThread = JvmThreadHolder.get(); + // 每个栈帧中包含一个指向运行时常量池中该栈帧所属的方法的引用。包含这个引用的目的就是为了支持当前方法实现动态链接 + // 有了这个引用,执行引擎就可以找到指定的方法,加载字节码指令 + Frame frame = new Frame(jvmThread, klassMethod); + jvmThread.push(frame); + Interpreter.executeFrame(frame); + } + + public static void callMethod(Frame lastFrame, KlassMethod klassMethod) { + JvmThread jvmThread = JvmThreadHolder.get(); + Frame newFrame = new Frame(jvmThread, klassMethod); + + Method method = klassMethod.javaMethod; + String signature = method.getSignature(); + String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature); + + 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); + } + } + jvmThread.push(newFrame); + Interpreter.executeFrame(newFrame); + } + + +} diff --git a/src/main/java/haidnor/jvm/instruction/Instruction.java b/src/main/java/haidnor/jvm/instruction/Instruction.java new file mode 100644 index 0000000..dd25027 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/Instruction.java @@ -0,0 +1,40 @@ +package haidnor.jvm.instruction; + +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public abstract class Instruction { + /** + * 指令坐在 code 数组中的索引下标 + */ + private final int index; + + /** + * 执行下一个执行的偏移量 + */ + private int offSet = 1; + + public Instruction(CodeStream codeStream) { + this.index = codeStream.index(); + } + + public abstract void execute(Frame frame); + + public int index() { + return index; + } + + public final int offSet() { + return this.offSet; + } + + public void setOffSet(int offSet) { + this.offSet = offSet; + } + + @Override + public String toString() { + return index + " " + this.getClass().getSimpleName(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/InstructionFactory.java b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java new file mode 100644 index 0000000..1184570 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java @@ -0,0 +1,631 @@ +package haidnor.jvm.instruction; + +import haidnor.jvm.instruction.comparisons.*; +import haidnor.jvm.instruction.constants.*; +import haidnor.jvm.instruction.control.*; +import haidnor.jvm.instruction.conversions.*; +import haidnor.jvm.instruction.extended.GOTO; +import haidnor.jvm.instruction.extended.GOTO_W; +import haidnor.jvm.instruction.extended.IFNONNULL; +import haidnor.jvm.instruction.extended.IFNULL; +import haidnor.jvm.instruction.loads.*; +import haidnor.jvm.instruction.math.*; +import haidnor.jvm.instruction.references.*; +import haidnor.jvm.instruction.stack.*; +import haidnor.jvm.instruction.stores.*; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public abstract class InstructionFactory { + + public static Instruction creatInstruction(CodeStream codeStream) { + int opcode = codeStream.readJavaVmOpcode(); + switch (opcode) { + case Const.NOP -> { + return new NOP(codeStream); + } + case Const.ACONST_NULL -> { + return new ACONST_NULL(codeStream); + } + case Const.ICONST_M1 -> { + return new ICONST_M1(codeStream); + } + case Const.ICONST_0 -> { + return new ICONST_0(codeStream); + } + case Const.ICONST_1 -> { + return new ICONST_1(codeStream); + } + case Const.ICONST_2 -> { + return new ICONST_2(codeStream); + } + case Const.ICONST_3 -> { + return new ICONST_3(codeStream); + } + case Const.ICONST_4 -> { + return new ICONST_4(codeStream); + } + case Const.ICONST_5 -> { + return new ICONST_5(codeStream); + } + case Const.LCONST_0 -> { + return new LCONST_0(codeStream); + } + case Const.LCONST_1 -> { + return new LCONST_1(codeStream); + } + case Const.FCONST_1 -> { + return new FCONST_1(codeStream); + } + case Const.FCONST_2 -> { + return new FCONST_2(codeStream); + } + case Const.DCONST_0 -> { + return new DCONST_0(codeStream); + } + case Const.DCONST_1 -> { + return new DCONST_1(codeStream); + } + case Const.BIPUSH -> { + return new BIPUSH(codeStream); + } + case Const.SIPUSH -> { + return new SIPUSH(codeStream); + } + case Const.LDC -> { + return new LDC(codeStream); + } + case Const.LDC_W -> { + return new LDC_W(codeStream); + } + case Const.LDC2_W -> { + return new LDC2W(codeStream); + } + case Const.ILOAD -> { + return new ILOAD(codeStream); + } + case Const.LLOAD -> { + return new LLOAD(codeStream); + } + case Const.FLOAD -> { + return new FLOAD(codeStream); + } + case Const.DLOAD -> { + return new DLOAD(codeStream); + } + case Const.ALOAD -> { + return new ALOAD(codeStream); + } + case Const.ILOAD_0 -> { + return new ILOAD_0(codeStream); + } + case Const.ILOAD_1 -> { + return new ILOAD_1(codeStream); + } + case Const.ILOAD_2 -> { + return new ILOAD_2(codeStream); + } + case Const.ILOAD_3 -> { + return new ILOAD_3(codeStream); + } + case Const.LLOAD_0 -> { + return new LLOAD_0(codeStream); + } + case Const.LLOAD_1 -> { + return new LLOAD_1(codeStream); + } + case Const.LLOAD_2 -> { + return new LLOAD_2(codeStream); + } + case Const.LLOAD_3 -> { + return new LLOAD_3(codeStream); + } + case Const.FLOAD_0 -> { + return new FLOAD_0(codeStream); + } + case Const.FLOAD_1 -> { + return new FLOAD_1(codeStream); + } + case Const.FLOAD_2 -> { + return new FLOAD_2(codeStream); + } + case Const.FLOAD_3 -> { + return new FLOAD_3(codeStream); + } + case Const.DLOAD_0 -> { + return new DLOAD_0(codeStream); + } + case Const.DLOAD_1 -> { + return new DLOAD_1(codeStream); + } + case Const.DLOAD_2 -> { + return new DLOAD_2(codeStream); + } + case Const.DLOAD_3 -> { + return new DLOAD_3(codeStream); + } + case Const.ALOAD_0 -> { + return new ALOAD_0(codeStream); + } + case Const.ALOAD_1 -> { + return new ALOAD_1(codeStream); + } + case Const.ALOAD_2 -> { + return new ALOAD_2(codeStream); + } + case Const.ALOAD_3 -> { + return new ALOAD_3(codeStream); + } + case Const.IALOAD -> { + return new IALOAD(codeStream); + } + case Const.LALOAD -> { + return new LALOAD(codeStream); + } + case Const.FALOAD -> { + return new FALOAD(codeStream); + } + case Const.DALOAD -> { + return new DALOAD(codeStream); + } + case Const.AALOAD -> { + return new AALOAD(codeStream); + } + case Const.BALOAD -> { + return new BALOAD(codeStream); + } + case Const.CALOAD -> { + return new CALOAD(codeStream); + } + case Const.SALOAD -> { + return new SALOAD(codeStream); + } + case Const.ISTORE -> { + return new ISTORE(codeStream); + } + case Const.LSTORE -> { + return new LSTORE(codeStream); + } + case Const.FSTORE -> { + return new FSTORE(codeStream); + } + case Const.DSTORE -> { + return new DSTORE(codeStream); + } + case Const.ASTORE -> { + return new ASTORE(codeStream); + } + case Const.ISTORE_0 -> { + return new ISTORE_0(codeStream); + } + case Const.ISTORE_1 -> { + return new ISTORE_1(codeStream); + } + case Const.ISTORE_2 -> { + return new ISTORE_2(codeStream); + } + case Const.ISTORE_3 -> { + return new ISTORE_3(codeStream); + } + case Const.LSTORE_0 -> { + return new LSTORE_0(codeStream); + } + case Const.LSTORE_1 -> { + return new LSTORE_1(codeStream); + } + case Const.LSTORE_2 -> { + return new LSTORE_2(codeStream); + } + case Const.LSTORE_3 -> { + return new LSTORE_3(codeStream); + } + case Const.FSTORE_0 -> { + return new FSTORE_0(codeStream); + } + case Const.FSTORE_1 -> { + return new FSTORE_1(codeStream); + } + case Const.FSTORE_2 -> { + return new FSTORE_2(codeStream); + } + case Const.FSTORE_3 -> { + return new FSTORE_3(codeStream); + } + case Const.DSTORE_0 -> { + return new DSTORE_0(codeStream); + } + case Const.DSTORE_1 -> { + return new DSTORE_1(codeStream); + } + case Const.DSTORE_2 -> { + return new DSTORE_2(codeStream); + } + case Const.DSTORE_3 -> { + return new DSTORE_3(codeStream); + } + case Const.ASTORE_0 -> { + return new ASTORE_0(codeStream); + } + case Const.ASTORE_1 -> { + return new ASTORE_1(codeStream); + } + case Const.ASTORE_2 -> { + return new ASTORE_2(codeStream); + } + case Const.ASTORE_3 -> { + return new ASTORE_3(codeStream); + } + case Const.IASTORE -> { + return new IASTORE(codeStream); + } + case Const.LASTORE -> { + return new LASTORE(codeStream); + } + case Const.FASTORE -> { + return new FASTORE(codeStream); + } + case Const.DASTORE -> { + return new DASTORE(codeStream); + } + case Const.AASTORE -> { + return new AASTORE(codeStream); + } + case Const.BASTORE -> { + return new BASTORE(codeStream); + } + case Const.CASTORE -> { + return new CASTORE(codeStream); + } + case Const.SASTORE -> { + return new SASTORE(codeStream); + } + case Const.POP -> { + return new POP(codeStream); + } + case Const.POP2 -> { + return new POP2(codeStream); + } + case Const.DUP -> { + return new DUP(codeStream); + } + case Const.DUP_X1 -> { + return new DUP_X1(codeStream); + } + case Const.DUP_X2 -> { + return new DUP_X2(codeStream); + } + case Const.DUP2 -> { + return new DUP2(codeStream); + } + case Const.DUP2_X1 -> { + throw new Error("Not support JavaVM opcode DUP2_X1"); + } + case Const.DUP2_X2 -> { + throw new Error("Not support JavaVM opcode DUP2_X2"); + } + case Const.SWAP -> { + return new SWAP(codeStream); + } + case Const.IADD -> { + return new IADD(codeStream); + } + case Const.LADD -> { + return new LADD(codeStream); + } + case Const.FADD -> { + return new FADD(codeStream); + } + case Const.DADD -> { + return new DADD(codeStream); + } + case Const.ISUB -> { + return new ISUB(codeStream); + } + case Const.LSUB -> { + return new LSUB(codeStream); + } + case Const.FSUB -> { + return new FSUB(codeStream); + } + case Const.DSUB -> { + return new DSUB(codeStream); + } + case Const.IMUL -> { + return new IMUL(codeStream); + } + case Const.LMUL -> { + return new LMUL(codeStream); + } + case Const.FMUL -> { + return new FMUL(codeStream); + } + case Const.DMUL -> { + return new DMUL(codeStream); + } + case Const.IDIV -> { + return new IDIV(codeStream); + } + case Const.LDIV -> { + return new LDIV(codeStream); + } + case Const.FDIV -> { + return new FDIV(codeStream); + } + case Const.DDIV -> { + return new DDIV(codeStream); + } + case Const.IREM -> { + return new IREM(codeStream); + } + case Const.LREM -> { + return new LREM(codeStream); + } + case Const.FREM -> { + return new FREM(codeStream); + } + case Const.DREM -> { + return new DREM(codeStream); + } + case Const.INEG -> { + return new INEG(codeStream); + } + case Const.LNEG -> { + return new LNEG(codeStream); + } + case Const.FNEG -> { + return new FNEG(codeStream); + } + case Const.DNEG -> { + return new DNEG(codeStream); + } + case Const.ISHL -> { + return new ISHL(codeStream); + } + case Const.LSHL -> { + return new LSHL(codeStream); + } + case Const.ISHR -> { + return new ISHR(codeStream); + } + case Const.LSHR -> { + return new LSHR(codeStream); + } + case Const.IUSHR -> { + return new IUSHR(codeStream); + } + case Const.LUSHR -> { + return new LUSHR(codeStream); + } + case Const.IAND -> { + return new IAND(codeStream); + } + case Const.LAND -> { + return new LAND(codeStream); + } + case Const.IOR -> { + return new IOR(codeStream); + } + case Const.LOR -> { + return new LOR(codeStream); + } + case Const.IXOR -> { + return new IXOR(codeStream); + } + case Const.LXOR -> { + return new LXOR(codeStream); + } + case Const.IINC -> { + return new IINC(codeStream); + } + case Const.I2L -> { + return new I2L(codeStream); + } + case Const.I2F -> { + return new I2F(codeStream); + } + case Const.I2D -> { + return new I2D(codeStream); + } + case Const.L2I -> { + return new L2I(codeStream); + } + case Const.L2F -> { + return new L2F(codeStream); + } + case Const.L2D -> { + return new L2D(codeStream); + } + case Const.F2I -> { + return new F2I(codeStream); + } + case Const.F2L -> { + return new F2L(codeStream); + } + case Const.F2D -> { + return new F2D(codeStream); + } + case Const.D2I -> { + return new D2I(codeStream); + } + case Const.D2L -> { + return new D2L(codeStream); + } + case Const.D2F -> { + return new D2F(codeStream); + } + case Const.I2B -> { + return new I2B(codeStream); + } + case Const.I2C -> { + return new I2C(codeStream); + } + case Const.I2S -> { + return new I2S(codeStream); + } + case Const.LCMP -> { + return new LCMP(codeStream); + } + case Const.FCMPL -> { + return new FCMPL(codeStream); + } + case Const.FCMPG -> { + return new FCMPG(codeStream); + } + case Const.DCMPL -> { + return new DCMPL(codeStream); + } + case Const.DCMPG -> { + return new DCMPG(codeStream); + } + case Const.IFEQ -> { + return new IFEQ(codeStream); + } + case Const.IFNE -> { + return new IFNE(codeStream); + } + case Const.IFLT -> { + return new IFLT(codeStream); + } + case Const.IFGE -> { + return new IFGE(codeStream); + } + case Const.IFGT -> { + return new IFGT(codeStream); + } + case Const.IFLE -> { + return new IFLE(codeStream); + } + case Const.IF_ICMPEQ -> { + return new IF_ICMPEQ(codeStream); + } + case Const.IF_ICMPNE -> { + return new IF_ICMPNE(codeStream); + } + case Const.IF_ICMPLT -> { + return new IF_ICMPLT(codeStream); + } + case Const.IF_ICMPGE -> { + return new IF_ICMPGE(codeStream); + } + case Const.IF_ICMPGT -> { + return new IF_ICMPGT(codeStream); + } + case Const.IF_ICMPLE -> { + return new IF_ICMPLE(codeStream); + } + case Const.IF_ACMPEQ -> { + return new IF_ACMPEQ(codeStream); + } + case Const.IF_ACMPNE -> { + return new IF_ACMPNE(codeStream); + } + case Const.GOTO -> { + return new GOTO(codeStream); + } + case Const.JSR -> { + return new JSR(codeStream); + } + case Const.RET -> { + return new RET(codeStream); + } + case Const.TABLESWITCH -> { + throw new Error("Not support JavaVM opcode TABLESWITCH"); + } + case Const.LOOKUPSWITCH -> { + throw new Error("Not support JavaVM opcode LOOKUPSWITCH"); + } + case Const.IRETURN -> { + return new IRETURN(codeStream); + } + case Const.LRETURN -> { + return new LRETURN(codeStream); + } + case Const.FRETURN -> { + return new FRETURN(codeStream); + } + case Const.DRETURN -> { + return new DRETURN(codeStream); + } + case Const.ARETURN -> { + throw new Error("Not support JavaVM opcode ARETURN"); + } + case Const.RETURN -> { + return new RETURN(codeStream); + } + case Const.GETSTATIC -> { + return new GETSTATIC(codeStream); + } + case Const.PUTSTATIC -> { + throw new Error("Not support JavaVM opcode PUTSTATIC"); + } + case Const.GETFIELD -> { + return new GETFIELD(codeStream); + } + case Const.PUTFIELD -> { + return new PUTFIELD(codeStream); + } + case Const.INVOKEVIRTUAL -> { + return new INVOKEVIRTUAL(codeStream); + } + case Const.INVOKESPECIAL -> { + return new INVOKESPECIAL(codeStream); + } + case Const.INVOKESTATIC -> { + return new INVOKESTATIC(codeStream); + } + case Const.INVOKEINTERFACE -> { + throw new Error("Not support JavaVM opcode INVOKEINTERFACE"); + } + case Const.INVOKEDYNAMIC -> { + throw new Error("Not support JavaVM opcode INVOKEDYNAMIC"); + } + case Const.NEW -> { + return new NEW(codeStream); + } + case Const.NEWARRAY -> { + return new NEWARRAY(codeStream); + } + case Const.ANEWARRAY -> { + return new ANEWARRAY(codeStream); + } + case Const.ARRAYLENGTH -> { + return new ARRAYLENGTH(codeStream); + } + case Const.ATHROW -> { + throw new Error("Not support JavaVM opcode ATHROW"); + } + case Const.CHECKCAST -> { + return new CHECKCAST(codeStream); + } + case Const.INSTANCEOF -> { + throw new Error("Not support JavaVM opcode INSTANCEOF"); + } + case Const.MONITORENTER -> { + throw new Error("Not support JavaVM opcode MONITORENTER"); + } + case Const.MONITOREXIT -> { + throw new Error("Not support JavaVM opcode MONITOREXIT"); + } + case Const.WIDE -> { + throw new Error("Not support JavaVM opcode WIDE"); + } + case Const.MULTIANEWARRAY -> { + throw new Error("Not support JavaVM opcode MULTIANEWARRAY"); + } + case Const.IFNULL -> { + return new IFNULL(codeStream); + } + case Const.IFNONNULL -> { + return new IFNONNULL(codeStream); + } + case Const.GOTO_W -> { + return new GOTO_W(codeStream); + } + case Const.JSR_W -> { + return new JSR_W(codeStream); + } + default -> throw new Error("Unknown JavaVM opcode " + opcode); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/DCMPG.java b/src/main/java/haidnor/jvm/instruction/comparisons/DCMPG.java new file mode 100644 index 0000000..79e4f09 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/DCMPG.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class DCMPG extends Instruction { + + public DCMPG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double v2 = frame.popDouble(); + double v1 = frame.popDouble(); + if (v1 == v2) { + frame.pushInt(0); + return; + } + if (v1 < v2) { + frame.pushInt(-1); + return; + } + frame.pushInt(1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/DCMPL.java b/src/main/java/haidnor/jvm/instruction/comparisons/DCMPL.java new file mode 100644 index 0000000..ef7156b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/DCMPL.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class DCMPL extends Instruction { + + public DCMPL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Double v2 = frame.popDouble(); + Double v1 = frame.popDouble(); + if (v1.equals(v2)) { + frame.pushInt(0); + return; + } + if (v1 < v2) { + frame.pushInt(-1); + return; + } + frame.pushInt(1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/FCMPG.java b/src/main/java/haidnor/jvm/instruction/comparisons/FCMPG.java new file mode 100644 index 0000000..eb0ecc9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/FCMPG.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class FCMPG extends Instruction { + + public FCMPG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float v2 = frame.popFloat(); + float v1 = frame.popFloat(); + if (v1 == v2) { + frame.pushInt(0); + return; + } + if (v1 < v2) { + frame.pushInt(-1); + return; + } + frame.pushInt(1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/FCMPL.java b/src/main/java/haidnor/jvm/instruction/comparisons/FCMPL.java new file mode 100644 index 0000000..9c4adf5 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/FCMPL.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class FCMPL extends Instruction { + + public FCMPL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float v2 = frame.popFloat(); + float v1 = frame.popFloat(); + if (v1 == v2) { + frame.pushInt(0); + return; + } + if (v1 < v2) { + frame.pushInt(-1); + return; + } + frame.pushInt(1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFEQ.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFEQ.java new file mode 100644 index 0000000..98359d8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFEQ.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFEQ extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFEQ(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() == 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFGE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFGE.java new file mode 100644 index 0000000..1ff335f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFGE.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFGE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFGE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() >= 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFGT.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFGT.java new file mode 100644 index 0000000..5a18f0b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFGT.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFGT extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFGT(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() > 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFLE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFLE.java new file mode 100644 index 0000000..819f5cc --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFLE.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFLE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFLE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() <= 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFLT.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFLT.java new file mode 100644 index 0000000..45bbba2 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFLT.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFLT extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFLT(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() < 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IFNE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IFNE.java new file mode 100644 index 0000000..a803536 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IFNE.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFNE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFNE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if ((int) v1.getValue() != 0) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPEQ.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPEQ.java new file mode 100644 index 0000000..e0b9f0a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPEQ.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IF_ACMPEQ extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ACMPEQ(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + Object val2 = frame.popRef(); + Object val1 = frame.popRef(); + if (val1 == val2) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPNE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPNE.java new file mode 100644 index 0000000..d260876 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ACMPNE.java @@ -0,0 +1,34 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IF_ACMPNE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ACMPNE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + Object val2 = frame.popRef(); + Object val1 = frame.popRef(); + if (val1 != val2) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPEQ.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPEQ.java new file mode 100644 index 0000000..00f624b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPEQ.java @@ -0,0 +1,41 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPEQ extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPEQ(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + StackValue v2 = frame.pop(); + + if ((int) v1.getValue() == (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGE.java new file mode 100644 index 0000000..d7cca6d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGE.java @@ -0,0 +1,42 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPGE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPGE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v2 = frame.pop(); + StackValue v1 = frame.pop(); + + if ((int) v1.getValue() >= (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGT.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGT.java new file mode 100644 index 0000000..dae8e92 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPGT.java @@ -0,0 +1,42 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPGT extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPGT(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v2 = frame.pop(); + StackValue v1 = frame.pop(); + + if ((int) v1.getValue() > (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLE.java new file mode 100644 index 0000000..e15d932 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLE.java @@ -0,0 +1,42 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPLE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPLE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v2 = frame.pop(); + StackValue v1 = frame.pop(); + + if ((int) v1.getValue() <= (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLT.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLT.java new file mode 100644 index 0000000..d60cb76 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPLT.java @@ -0,0 +1,42 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPLT extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPLT(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v2 = frame.pop(); + StackValue v1 = frame.pop(); + + if ((int) v1.getValue() < (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPNE.java b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPNE.java new file mode 100644 index 0000000..cc5696f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/IF_ICMPNE.java @@ -0,0 +1,42 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode + * definitions in The Java Virtual Machine Specification + */ +public class IF_ICMPNE extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IF_ICMPNE(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + StackValue v2 = frame.pop(); + + if ((int) v1.getValue() != (int) v2.getValue()) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/comparisons/LCMP.java b/src/main/java/haidnor/jvm/instruction/comparisons/LCMP.java new file mode 100644 index 0000000..60e3daf --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/comparisons/LCMP.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.comparisons; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LCMP extends Instruction { + + public LCMP(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Long v2 = frame.popLong(); + Long v1 = frame.popLong(); + if (v1.equals(v2)) { + frame.pushInt(0); + return; + } + if (v1 < v2) { + frame.pushInt(-1); + return; + } + frame.pushInt(1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ACONST_NULL.java b/src/main/java/haidnor/jvm/instruction/constants/ACONST_NULL.java new file mode 100644 index 0000000..13d834a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ACONST_NULL.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ACONST_NULL extends Instruction { + + public ACONST_NULL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_OBJECT, null)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/BIPUSH.java b/src/main/java/haidnor/jvm/instruction/constants/BIPUSH.java new file mode 100644 index 0000000..8fb95be --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/BIPUSH.java @@ -0,0 +1,29 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions in + * The Java Virtual Machine Specification + */ +public class BIPUSH extends Instruction { + + private final int value; + + public BIPUSH(CodeStream codeStream) { + super(codeStream); + this.value = codeStream.readByte(this); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/DCONST_0.java b/src/main/java/haidnor/jvm/instruction/constants/DCONST_0.java new file mode 100644 index 0000000..b22fe45 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/DCONST_0.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class DCONST_0 extends Instruction { + + public DCONST_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_DOUBLE, 0.0D)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/DCONST_1.java b/src/main/java/haidnor/jvm/instruction/constants/DCONST_1.java new file mode 100644 index 0000000..6123104 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/DCONST_1.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class DCONST_1 extends Instruction { + + public DCONST_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_DOUBLE, 1.0D)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/FCONST_1.java b/src/main/java/haidnor/jvm/instruction/constants/FCONST_1.java new file mode 100644 index 0000000..4f22abe --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/FCONST_1.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class FCONST_1 extends Instruction { + + public FCONST_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_FLOAT, 1.0f)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/FCONST_2.java b/src/main/java/haidnor/jvm/instruction/constants/FCONST_2.java new file mode 100644 index 0000000..2ddeda6 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/FCONST_2.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class FCONST_2 extends Instruction { + + public FCONST_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_FLOAT, 2.0f)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_0.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_0.java new file mode 100644 index 0000000..7ee6c0b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_0.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_0 extends Instruction { + + public ICONST_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 0)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_1.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_1.java new file mode 100644 index 0000000..daf2b0f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_1.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_1 extends Instruction { + + public ICONST_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 1)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_2.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_2.java new file mode 100644 index 0000000..5478225 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_2.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_2 extends Instruction { + + public ICONST_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 2)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_3.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_3.java new file mode 100644 index 0000000..e17f8c4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_3.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_3 extends Instruction { + + public ICONST_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 3)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_4.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_4.java new file mode 100644 index 0000000..ef73844 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_4.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_4 extends Instruction { + + public ICONST_4(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 4)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_5.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_5.java new file mode 100644 index 0000000..c45a4bd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_5.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_5 extends Instruction { + + public ICONST_5(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, 5)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/ICONST_M1.java b/src/main/java/haidnor/jvm/instruction/constants/ICONST_M1.java new file mode 100644 index 0000000..7913a7f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/ICONST_M1.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.5.iconst_i + */ +public class ICONST_M1 extends Instruction { + + public ICONST_M1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, -1)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/LCONST_0.java b/src/main/java/haidnor/jvm/instruction/constants/LCONST_0.java new file mode 100644 index 0000000..f2ba981 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/LCONST_0.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class LCONST_0 extends Instruction { + + public LCONST_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_LONG, 0L)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/LCONST_1.java b/src/main/java/haidnor/jvm/instruction/constants/LCONST_1.java new file mode 100644 index 0000000..694fa21 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/LCONST_1.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions + * in The Java Virtual Machine Specification + */ +public class LCONST_1 extends Instruction { + + public LCONST_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_LONG, 1L)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/LDC.java b/src/main/java/haidnor/jvm/instruction/constants/LDC.java new file mode 100644 index 0000000..822d44c --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/LDC.java @@ -0,0 +1,58 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.*; + +/** + * Java VM opcode. + * + * @see Opcode definitions in The + * Java Virtual Machine Specification + */ +public class LDC extends Instruction { + + private final int constantIndex; + + public LDC(CodeStream codeStream) { + super(codeStream); + this.constantIndex = codeStream.readUnsignedByte(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + + // 从常量池中获取值 + Constant constant = constantPool.getConstant(constantIndex); + + switch (constant.getTag()) { + case Const.CONSTANT_Integer: { + ConstantInteger constantInteger = (ConstantInteger) constant; + Object value = constantInteger.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_INT, value)); + break; + } + case Const.CONSTANT_Float: { + ConstantFloat constantFloat = (ConstantFloat) constant; + Object value = constantFloat.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_FLOAT, value)); + break; + } + case Const.CONSTANT_String: { + ConstantString constString = (ConstantString) constant; + Object value = constString.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_OBJECT, value)); + break; + } + default: + throw new Error("not supported LDC type" + constant.getTag()); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/LDC2W.java b/src/main/java/haidnor/jvm/instruction/constants/LDC2W.java new file mode 100644 index 0000000..ecca253 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/LDC2W.java @@ -0,0 +1,48 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantDouble; +import org.apache.bcel.classfile.ConstantLong; +import org.apache.bcel.classfile.ConstantPool; + +/** + * 将 long 或 double 型常量从常量池中推送至栈顶 (宽索引) + */ +public class LDC2W extends Instruction { + + private final byte constantTag; + + private long longValue; + + private double doubleValue; + + public LDC2W(CodeStream codeStream) { + super(codeStream); + int index = codeStream.readUnsignedShort(this); + ConstantPool constantPool = codeStream.getCode().getConstantPool(); + Constant constant = constantPool.getConstant(index); + this.constantTag = constant.getTag(); + if (constantTag == Const.CONSTANT_Long) { + ConstantLong constantLong = (ConstantLong) constant; + this.longValue = constantLong.getBytes(); + } else if (constantTag == Const.CONSTANT_Double) { + ConstantDouble constantDouble = (ConstantDouble) constant; + this.doubleValue = constantDouble.getBytes(); + } + } + + @Override + public void execute(Frame frame) { + if (constantTag == Const.CONSTANT_Long) { + frame.push(new StackValue(Const.T_LONG, this.longValue)); + } else if (constantTag == Const.CONSTANT_Double) { + frame.push(new StackValue(Const.T_DOUBLE, this.doubleValue)); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/LDC_W.java b/src/main/java/haidnor/jvm/instruction/constants/LDC_W.java new file mode 100644 index 0000000..a10aeac --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/LDC_W.java @@ -0,0 +1,58 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.*; + +/** + * Java VM opcode. + * + * @see Opcode definitions in + * The Java Virtual Machine Specification + */ +public class LDC_W extends Instruction { + + private final int constantIndex; + + public LDC_W(CodeStream codeStream) { + super(codeStream); + this.constantIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + + // 从常量池中获取值 + Constant constant = constantPool.getConstant(constantIndex); + + switch (constant.getTag()) { + case Const.CONSTANT_Integer: { + ConstantInteger constantInteger = (ConstantInteger) constant; + Object value = constantInteger.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_INT, value)); + break; + } + case Const.CONSTANT_Float: { + ConstantFloat constantFloat = (ConstantFloat) constant; + Object value = constantFloat.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_FLOAT, value)); + break; + } + case Const.CONSTANT_String: { + ConstantString constString = (ConstantString) constant; + Object value = constString.getConstantValue(constantPool); + frame.push(new StackValue(Const.T_OBJECT, value)); + break; + } + default: + throw new Error("not supported LDCW type" + constant.getTag()); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/NOP.java b/src/main/java/haidnor/jvm/instruction/constants/NOP.java new file mode 100644 index 0000000..2ffdbea --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/NOP.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode definitions in The + * Java Virtual Machine Specification + */ +public class NOP extends Instruction { + + public NOP(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/constants/SIPUSH.java b/src/main/java/haidnor/jvm/instruction/constants/SIPUSH.java new file mode 100644 index 0000000..7bcc6b3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/constants/SIPUSH.java @@ -0,0 +1,29 @@ +package haidnor.jvm.instruction.constants; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * Java VM opcode. + * + * @see Opcode definitions in + * The Java Virtual Machine Specification + */ +public class SIPUSH extends Instruction { + + private final int value; + + public SIPUSH(CodeStream codeStream) { + super(codeStream); + this.value = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/DRETURN.java b/src/main/java/haidnor/jvm/instruction/control/DRETURN.java new file mode 100644 index 0000000..16da89f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/DRETURN.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JvmThreadHolder; + +public class DRETURN extends Instruction { + + public DRETURN(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + // 弹出操作数栈中的值 + StackValue stackValue = frame.pop(); + // 将当前栈帧从 jvm 线程栈中弹出 + JvmThreadHolder.get().pop(); + // 将方法返回值压入前一个栈帧的操作数栈中 + Frame topFrame = JvmThreadHolder.get().peek(); + topFrame.push(stackValue); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/FRETURN.java b/src/main/java/haidnor/jvm/instruction/control/FRETURN.java new file mode 100644 index 0000000..b0bc326 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/FRETURN.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JvmThreadHolder; + +public class FRETURN extends Instruction { + + public FRETURN(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + // 弹出操作数栈中的值 + StackValue stackValue = frame.pop(); + // 将当前栈帧从 jvm 线程栈中弹出 + JvmThreadHolder.get().pop(); + // 将方法返回值压入前一个栈帧的操作数栈中 + Frame topFrame = JvmThreadHolder.get().peek(); + topFrame.push(stackValue); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/IRETURN.java b/src/main/java/haidnor/jvm/instruction/control/IRETURN.java new file mode 100644 index 0000000..f7781c0 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/IRETURN.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JvmThreadHolder; + +public class IRETURN extends Instruction { + + public IRETURN(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + // 弹出操作数栈中的值 + StackValue stackValue = frame.pop(); + // 将当前栈帧从 jvm 线程栈中弹出 + JvmThreadHolder.get().pop(); + // 将方法返回值压入前一个栈帧的操作数栈中 + Frame topFrame = JvmThreadHolder.get().peek(); + topFrame.push(stackValue); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/LRETURN.java b/src/main/java/haidnor/jvm/instruction/control/LRETURN.java new file mode 100644 index 0000000..2fa2187 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/LRETURN.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JvmThreadHolder; + +public class LRETURN extends Instruction { + + public LRETURN(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + // 弹出操作数栈中的值 + StackValue stackValue = frame.pop(); + // 将当前栈帧从 jvm 线程栈中弹出 + JvmThreadHolder.get().pop(); + // 将方法返回值压入前一个栈帧的操作数栈中 + Frame topFrame = JvmThreadHolder.get().peek(); + topFrame.push(stackValue); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/RET.java b/src/main/java/haidnor/jvm/instruction/control/RET.java new file mode 100644 index 0000000..18410e8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/RET.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * RET(Return)指令是 Java 虚拟机中的一条指令,用于从方法中返回并将控制流转移到调用该方法的位置。 + *

+ * RET 指令在早期版本的 Java 虚拟机中使用,但自从 Java SE 6 版本以后,它已经被废弃不再使用。取而代之的是通过 JSR 和 RET 指令的组合实现的子例程(subroutines)已经被新的字节码指令 invokedynamic 所取代。 + *

+ * RET 指令需要一个操作数,作为局部变量表(local variable table)中一个给定索引处的值。这个索引通常是由 JSR(Jump SubRoutine)指令记录的,JSR 指令在携带一个偏移量的情况下,会将指令执行的位置压入操作数栈,并跳转到指定的位置。RET 指令则使用这个记录的位置来返回。 + *

+ * 需要注意的是,由于 RET 指令被废弃,所以在现代的 Java 虚拟机中,解释器或即时编译器会将 RET 指令替换为其他的指令序列来实现相同的功能。 + */ +public class RET extends Instruction { + + public RET(CodeStream codeStream) { + super(codeStream); + throw new UnsupportedOperationException("RET"); + } + + @Override + public void execute(Frame frame) { + throw new UnsupportedOperationException("RET"); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/control/RETURN.java b/src/main/java/haidnor/jvm/instruction/control/RETURN.java new file mode 100644 index 0000000..56ff11a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/control/RETURN.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.control; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JvmThreadHolder; + +public class RETURN extends Instruction { + + public RETURN(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + JvmThreadHolder.get().pop(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/D2F.java b/src/main/java/haidnor/jvm/instruction/conversions/D2F.java new file mode 100644 index 0000000..bbfc874 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/D2F.java @@ -0,0 +1,20 @@ + +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class D2F extends Instruction { + + public D2F(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double doubleVal = frame.popDouble(); + frame.pushFloat(Double.valueOf(doubleVal).floatValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/D2I.java b/src/main/java/haidnor/jvm/instruction/conversions/D2I.java new file mode 100644 index 0000000..94f5e44 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/D2I.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class D2I extends Instruction { + + public D2I(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double doubleVal = frame.popDouble(); + frame.pushInt(Double.valueOf(doubleVal).intValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/D2L.java b/src/main/java/haidnor/jvm/instruction/conversions/D2L.java new file mode 100644 index 0000000..1bba3f0 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/D2L.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class D2L extends Instruction { + + public D2L(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double doubleVal = frame.popDouble(); + frame.pushLong(Double.valueOf(doubleVal).longValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/F2D.java b/src/main/java/haidnor/jvm/instruction/conversions/F2D.java new file mode 100644 index 0000000..a4a0d77 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/F2D.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class F2D extends Instruction { + + public F2D(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float floatVal = frame.popFloat(); + frame.pushDouble(Float.valueOf(floatVal).doubleValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/F2I.java b/src/main/java/haidnor/jvm/instruction/conversions/F2I.java new file mode 100644 index 0000000..0a95939 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/F2I.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class F2I extends Instruction { + + public F2I(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float floatVal = frame.popFloat(); + frame.pushInt(Float.valueOf(floatVal).intValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/F2L.java b/src/main/java/haidnor/jvm/instruction/conversions/F2L.java new file mode 100644 index 0000000..cdadf34 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/F2L.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class F2L extends Instruction { + + public F2L(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float floatVal = frame.popFloat(); + frame.pushLong(Float.valueOf(floatVal).longValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2B.java b/src/main/java/haidnor/jvm/instruction/conversions/I2B.java new file mode 100644 index 0000000..1b84a80 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2B.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * JVM中的I2B指令是用于执行将整数类型(int)转换为字节类型(byte)的指令。该指令将一个int类型的数值从操作数栈中弹出,并将其转换为一个字节(byte)。 + * 然后,将转换后的字节值压入操作数栈顶。 + *

+ * byte 类型的数据是以 int 形式存在的,因此不需要做任何处理 + */ +public class I2B extends Instruction { + + public I2B(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2C.java b/src/main/java/haidnor/jvm/instruction/conversions/I2C.java new file mode 100644 index 0000000..04a9b08 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2C.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * char 类型的数据是以 int 形式存在的,因此不需要做任何处理 + */ +public class I2C extends Instruction { + + public I2C(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2D.java b/src/main/java/haidnor/jvm/instruction/conversions/I2D.java new file mode 100644 index 0000000..e62a3dd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2D.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class I2D extends Instruction { + + public I2D(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int intVal = frame.popInt(); + frame.pushDouble(Integer.valueOf(intVal).doubleValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2F.java b/src/main/java/haidnor/jvm/instruction/conversions/I2F.java new file mode 100644 index 0000000..7c4daf5 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2F.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class I2F extends Instruction { + + public I2F(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int intVal = frame.popInt(); + frame.pushFloat(Integer.valueOf(intVal).floatValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2L.java b/src/main/java/haidnor/jvm/instruction/conversions/I2L.java new file mode 100644 index 0000000..6bb9ac8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2L.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class I2L extends Instruction { + + public I2L(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int intVal = frame.popInt(); + frame.pushLong(Integer.valueOf(intVal).longValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/I2S.java b/src/main/java/haidnor/jvm/instruction/conversions/I2S.java new file mode 100644 index 0000000..fe9cd1e --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/I2S.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class I2S extends Instruction { + + public I2S(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int intVal = frame.popInt(); + short shortValue = Integer.valueOf(intVal).shortValue(); + frame.pushInt(((int) shortValue)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/L2D.java b/src/main/java/haidnor/jvm/instruction/conversions/L2D.java new file mode 100644 index 0000000..fd38919 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/L2D.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class L2D extends Instruction { + + public L2D(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long longVal = frame.popLong(); + frame.pushDouble(Long.valueOf(longVal).doubleValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/L2F.java b/src/main/java/haidnor/jvm/instruction/conversions/L2F.java new file mode 100644 index 0000000..ae4d084 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/L2F.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class L2F extends Instruction { + + public L2F(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long longVal = frame.popLong(); + frame.pushFloat(Long.valueOf(longVal).floatValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/conversions/L2I.java b/src/main/java/haidnor/jvm/instruction/conversions/L2I.java new file mode 100644 index 0000000..7e43556 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/conversions/L2I.java @@ -0,0 +1,19 @@ +package haidnor.jvm.instruction.conversions; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class L2I extends Instruction { + + public L2I(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long longVal = frame.popLong(); + frame.pushInt(Long.valueOf(longVal).intValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/extended/GOTO.java b/src/main/java/haidnor/jvm/instruction/extended/GOTO.java new file mode 100644 index 0000000..a7fc5d4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/extended/GOTO.java @@ -0,0 +1,33 @@ +package haidnor.jvm.instruction.extended; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode definitions in + * The Java Virtual Machine Specification + */ +public class GOTO extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public GOTO(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + super.setOffSet(offSet); + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } +} diff --git a/src/main/java/haidnor/jvm/instruction/extended/GOTO_W.java b/src/main/java/haidnor/jvm/instruction/extended/GOTO_W.java new file mode 100644 index 0000000..e79bb2b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/extended/GOTO_W.java @@ -0,0 +1,27 @@ +package haidnor.jvm.instruction.extended; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class GOTO_W extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public GOTO_W(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readInt(this); + } + + @Override + public void execute(Frame frame) { + super.setOffSet(offSet); + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } +} diff --git a/src/main/java/haidnor/jvm/instruction/extended/IFNONNULL.java b/src/main/java/haidnor/jvm/instruction/extended/IFNONNULL.java new file mode 100644 index 0000000..2c7f73c --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/extended/IFNONNULL.java @@ -0,0 +1,33 @@ +package haidnor.jvm.instruction.extended; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFNONNULL extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFNONNULL(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if (v1.getValue() != null) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } +} diff --git a/src/main/java/haidnor/jvm/instruction/extended/IFNULL.java b/src/main/java/haidnor/jvm/instruction/extended/IFNULL.java new file mode 100644 index 0000000..af693eb --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/extended/IFNULL.java @@ -0,0 +1,33 @@ +package haidnor.jvm.instruction.extended; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class IFNULL extends Instruction { + /** + * 下次再执行的偏移量 + */ + private final int offSet; + + public IFNULL(CodeStream codeStream) { + super(codeStream); + this.offSet = codeStream.readShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue v1 = frame.pop(); + if (v1.getValue() == null) { + super.setOffSet(offSet); + } else { + super.setOffSet(3); + } + } + + @Override + public String toString() { + return super.index() + " " + this.getClass().getSimpleName() + " " + offSet; + } +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/AALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/AALOAD.java new file mode 100644 index 0000000..acc30b6 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/AALOAD.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.InstanceArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class AALOAD extends Instruction { + + public AALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + InstanceArray array = (InstanceArray) frame.popRef(); + Instance item = (Instance) array.items[index]; + frame.pushRef(item); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/ALOAD.java new file mode 100644 index 0000000..2819ae4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ALOAD.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + + +public class ALOAD extends Instruction { + + private final int index; + + public ALOAD(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + Object value = frame.slotGetRef(index); + frame.push(new StackValue(Const.T_OBJECT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ALOAD_0.java b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_0.java new file mode 100644 index 0000000..5f83857 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_0.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ALOAD_0 extends Instruction { + + public ALOAD_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Object value = frame.slotGetRef(0); + frame.push(new StackValue(Const.T_OBJECT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ALOAD_1.java b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_1.java new file mode 100644 index 0000000..0d7f851 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_1.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ALOAD_1 extends Instruction { + + public ALOAD_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Object value = frame.slotGetRef(1); + frame.push(new StackValue(Const.T_OBJECT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ALOAD_2.java b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_2.java new file mode 100644 index 0000000..2f1867d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_2.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ALOAD_2 extends Instruction { + + public ALOAD_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Object value = frame.slotGetRef(2); + frame.push(new StackValue(Const.T_OBJECT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ALOAD_3.java b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_3.java new file mode 100644 index 0000000..005ccc0 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ALOAD_3.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ALOAD_3 extends Instruction { + + public ALOAD_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Object value = frame.slotGetRef(3); + frame.push(new StackValue(Const.T_OBJECT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/BALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/BALOAD.java new file mode 100644 index 0000000..f069c41 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/BALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class BALOAD extends Instruction { + + public BALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushInt(array.ints[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/CALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/CALOAD.java new file mode 100644 index 0000000..edc9cd7 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/CALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class CALOAD extends Instruction { + + public CALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushInt(array.ints[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/DALOAD.java new file mode 100644 index 0000000..59ef521 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class DALOAD extends Instruction { + + public DALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushDouble(array.doubles[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DLOAD.java b/src/main/java/haidnor/jvm/instruction/loads/DLOAD.java new file mode 100644 index 0000000..35a1235 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DLOAD.java @@ -0,0 +1,25 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + + +public class DLOAD extends Instruction { + + private final int index; + + public DLOAD(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + double value = frame.slotGetDouble(index); + frame.push(new StackValue(Const.T_DOUBLE, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DLOAD_0.java b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_0.java new file mode 100644 index 0000000..5e39063 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_0.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DLOAD_0 extends Instruction { + + public DLOAD_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double value = frame.slotGetDouble(0); + frame.push(new StackValue(Const.T_DOUBLE, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DLOAD_1.java b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_1.java new file mode 100644 index 0000000..7cbb195 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_1.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DLOAD_1 extends Instruction { + + public DLOAD_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double value = frame.slotGetDouble(1); + frame.push(new StackValue(Const.T_DOUBLE, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DLOAD_2.java b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_2.java new file mode 100644 index 0000000..1648b66 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_2.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DLOAD_2 extends Instruction { + + public DLOAD_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double value = frame.slotGetDouble(2); + frame.push(new StackValue(Const.T_DOUBLE, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/DLOAD_3.java b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_3.java new file mode 100644 index 0000000..f5405ce --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/DLOAD_3.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DLOAD_3 extends Instruction { + + public DLOAD_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double value = frame.slotGetDouble(3); + frame.push(new StackValue(Const.T_DOUBLE, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/FALOAD.java new file mode 100644 index 0000000..66be156 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class FALOAD extends Instruction { + + public FALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushFloat(array.floats[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FLOAD.java b/src/main/java/haidnor/jvm/instruction/loads/FLOAD.java new file mode 100644 index 0000000..7ce6301 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FLOAD.java @@ -0,0 +1,25 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + + +public class FLOAD extends Instruction { + + private final int index; + + public FLOAD(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + float value = frame.slotGetFloat(index); + frame.push(new StackValue(Const.T_FLOAT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FLOAD_0.java b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_0.java new file mode 100644 index 0000000..5a3ae65 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_0.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FLOAD_0 extends Instruction { + + public FLOAD_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float value = frame.slotGetFloat(0); + frame.push(new StackValue(Const.T_FLOAT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FLOAD_1.java b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_1.java new file mode 100644 index 0000000..eb6aca2 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_1.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FLOAD_1 extends Instruction { + + public FLOAD_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float value = frame.slotGetFloat(1); + frame.push(new StackValue(Const.T_FLOAT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FLOAD_2.java b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_2.java new file mode 100644 index 0000000..cc740f2 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_2.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FLOAD_2 extends Instruction { + + public FLOAD_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float value = frame.slotGetFloat(2); + frame.push(new StackValue(Const.T_FLOAT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/FLOAD_3.java b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_3.java new file mode 100644 index 0000000..d2ead70 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/FLOAD_3.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FLOAD_3 extends Instruction { + + public FLOAD_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float value = frame.slotGetFloat(3); + frame.push(new StackValue(Const.T_FLOAT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/IALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/IALOAD.java new file mode 100644 index 0000000..1a58fe7 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/IALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class IALOAD extends Instruction { + + public IALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushInt(array.ints[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ILOAD.java b/src/main/java/haidnor/jvm/instruction/loads/ILOAD.java new file mode 100644 index 0000000..78c5304 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ILOAD.java @@ -0,0 +1,25 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + + +public class ILOAD extends Instruction { + + private final int index; + + public ILOAD(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(index); + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ILOAD_0.java b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_0.java new file mode 100644 index 0000000..4396c21 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_0.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iload_n + */ +public class ILOAD_0 extends Instruction { + + public ILOAD_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(0); + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ILOAD_1.java b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_1.java new file mode 100644 index 0000000..9ea6009 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_1.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iload_n + */ +public class ILOAD_1 extends Instruction { + + public ILOAD_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(1); + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ILOAD_2.java b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_2.java new file mode 100644 index 0000000..e8a00a4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_2.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iload_n + */ +public class ILOAD_2 extends Instruction { + + public ILOAD_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(2); + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/ILOAD_3.java b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_3.java new file mode 100644 index 0000000..6adc81a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/ILOAD_3.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +/** + * https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iload_n + */ +public class ILOAD_3 extends Instruction { + + public ILOAD_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(3); + frame.push(new StackValue(Const.T_INT, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/LALOAD.java new file mode 100644 index 0000000..9b676a4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class LALOAD extends Instruction { + + public LALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushLong(array.longs[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LLOAD.java b/src/main/java/haidnor/jvm/instruction/loads/LLOAD.java new file mode 100644 index 0000000..702139d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LLOAD.java @@ -0,0 +1,25 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + + +public class LLOAD extends Instruction { + + private final int index; + + public LLOAD(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + long value = frame.slotGetLong(index); + frame.push(new StackValue(Const.T_LONG, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LLOAD_0.java b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_0.java new file mode 100644 index 0000000..2a7a29d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_0.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LLOAD_0 extends Instruction { + + public LLOAD_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long value = frame.slotGetLong(0); + frame.push(new StackValue(Const.T_LONG, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LLOAD_1.java b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_1.java new file mode 100644 index 0000000..00b07e6 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_1.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LLOAD_1 extends Instruction { + + public LLOAD_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long value = frame.slotGetLong(1); + frame.push(new StackValue(Const.T_LONG, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LLOAD_2.java b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_2.java new file mode 100644 index 0000000..acb724f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_2.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LLOAD_2 extends Instruction { + + public LLOAD_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long value = frame.slotGetLong(2); + frame.push(new StackValue(Const.T_LONG, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/LLOAD_3.java b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_3.java new file mode 100644 index 0000000..0c831fe --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/LLOAD_3.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LLOAD_3 extends Instruction { + + public LLOAD_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long value = frame.slotGetLong(3); + frame.push(new StackValue(Const.T_LONG, value)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/loads/SALOAD.java b/src/main/java/haidnor/jvm/instruction/loads/SALOAD.java new file mode 100644 index 0000000..3428db7 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/loads/SALOAD.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.loads; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + + +public class SALOAD extends Instruction { + + public SALOAD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + frame.pushInt(array.ints[index]); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DADD.java b/src/main/java/haidnor/jvm/instruction/math/DADD.java new file mode 100644 index 0000000..cd0f3d5 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DADD.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DADD extends Instruction { + + public DADD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + double result = (double) value1.getValue() + (double) value2.getValue(); + frame.push(new StackValue(Const.T_DOUBLE, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DDIV.java b/src/main/java/haidnor/jvm/instruction/math/DDIV.java new file mode 100644 index 0000000..7db3560 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DDIV.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DDIV extends Instruction { + + public DDIV(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + double result = (double) value1.getValue() / (double) value2.getValue(); + frame.push(new StackValue(Const.T_DOUBLE, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DMUL.java b/src/main/java/haidnor/jvm/instruction/math/DMUL.java new file mode 100644 index 0000000..0b66ca9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DMUL.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DMUL extends Instruction { + + public DMUL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + double result = (double) value1.getValue() * (double) value2.getValue(); + frame.push(new StackValue(Const.T_DOUBLE, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DNEG.java b/src/main/java/haidnor/jvm/instruction/math/DNEG.java new file mode 100644 index 0000000..efd5b75 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DNEG.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DNEG extends Instruction { + + public DNEG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue stackValue = frame.pop(); + double value = (double) stackValue.getValue(); + double tmp = -value; + frame.push(new StackValue(Const.T_DOUBLE, tmp)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DREM.java b/src/main/java/haidnor/jvm/instruction/math/DREM.java new file mode 100644 index 0000000..2fc29de --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DREM.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DREM extends Instruction { + + public DREM(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + double result = (double) value1.getValue() % (double) value2.getValue(); + frame.push(new StackValue(Const.T_DOUBLE, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/DSUB.java b/src/main/java/haidnor/jvm/instruction/math/DSUB.java new file mode 100644 index 0000000..d25ff6f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/DSUB.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class DSUB extends Instruction { + + public DSUB(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + double result = (double) value1.getValue() - (double) value2.getValue(); + frame.push(new StackValue(Const.T_DOUBLE, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FADD.java b/src/main/java/haidnor/jvm/instruction/math/FADD.java new file mode 100644 index 0000000..c4a73c4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FADD.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FADD extends Instruction { + + public FADD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + float result = (float) value1.getValue() + (float) value2.getValue(); + frame.push(new StackValue(Const.T_FLOAT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FDIV.java b/src/main/java/haidnor/jvm/instruction/math/FDIV.java new file mode 100644 index 0000000..6e7e768 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FDIV.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FDIV extends Instruction { + + public FDIV(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + float result = (float) value1.getValue() / (float) value2.getValue(); + frame.push(new StackValue(Const.T_FLOAT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FMUL.java b/src/main/java/haidnor/jvm/instruction/math/FMUL.java new file mode 100644 index 0000000..7c82541 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FMUL.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FMUL extends Instruction { + + public FMUL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + float result = (float) value1.getValue() * (float) value2.getValue(); + frame.push(new StackValue(Const.T_FLOAT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FNEG.java b/src/main/java/haidnor/jvm/instruction/math/FNEG.java new file mode 100644 index 0000000..e245a33 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FNEG.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FNEG extends Instruction { + + public FNEG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue stackValue = frame.pop(); + float value = (float) stackValue.getValue(); + float tmp = -value; + frame.push(new StackValue(Const.T_FLOAT, tmp)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FREM.java b/src/main/java/haidnor/jvm/instruction/math/FREM.java new file mode 100644 index 0000000..280de40 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FREM.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FREM extends Instruction { + + public FREM(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + float result = (float) value1.getValue() % (float) value2.getValue(); + frame.push(new StackValue(Const.T_FLOAT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/FSUB.java b/src/main/java/haidnor/jvm/instruction/math/FSUB.java new file mode 100644 index 0000000..0b83e45 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/FSUB.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class FSUB extends Instruction { + + public FSUB(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + float result = (float) value1.getValue() - (float) value2.getValue(); + frame.push(new StackValue(Const.T_FLOAT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IADD.java b/src/main/java/haidnor/jvm/instruction/math/IADD.java new file mode 100644 index 0000000..d6c311f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IADD.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class IADD extends Instruction { + + public IADD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + int result = (int) value1.getValue() + (int) value2.getValue(); + frame.push(new StackValue(Const.T_INT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IAND.java b/src/main/java/haidnor/jvm/instruction/math/IAND.java new file mode 100644 index 0000000..396420f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IAND.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IAND extends Instruction { + + public IAND(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Integer v2 = frame.popInt(); + Integer v1 = frame.popInt(); + int val = v1 & v2; + frame.pushInt(val); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IDIV.java b/src/main/java/haidnor/jvm/instruction/math/IDIV.java new file mode 100644 index 0000000..fb2e53c --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IDIV.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class IDIV extends Instruction { + + public IDIV(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + int result = (int) value1.getValue() / (int) value2.getValue(); + frame.push(new StackValue(Const.T_INT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IINC.java b/src/main/java/haidnor/jvm/instruction/math/IINC.java new file mode 100644 index 0000000..8dd1958 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IINC.java @@ -0,0 +1,37 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * Java VM opcode. + * + * @see Opcode definitions in + * The Java Virtual Machine Specification + */ +public class IINC extends Instruction { + + /** + * 局部变量表中需要被自增元素的索引 + */ + public final int index; + + /** + * 自增值 + */ + public final int increment; + + public IINC(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + this.increment = codeStream.readByte(this); + } + + @Override + public void execute(Frame frame) { + int value = frame.slotGetInt(index); + frame.slotSetInt(index, value + increment); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IMUL.java b/src/main/java/haidnor/jvm/instruction/math/IMUL.java new file mode 100644 index 0000000..6ffaed8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IMUL.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class IMUL extends Instruction { + + public IMUL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + int result = (int) value1.getValue() * (int) value2.getValue(); + frame.push(new StackValue(Const.T_INT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/INEG.java b/src/main/java/haidnor/jvm/instruction/math/INEG.java new file mode 100644 index 0000000..6e2c073 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/INEG.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class INEG extends Instruction { + + public INEG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue stackValue = frame.pop(); + int value = (int) stackValue.getValue(); + int tmp = -value; + frame.push(new StackValue(Const.T_INT, tmp)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IOR.java b/src/main/java/haidnor/jvm/instruction/math/IOR.java new file mode 100644 index 0000000..0202bb3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IOR.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IOR extends Instruction { + + public IOR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + int v1 = frame.popInt(); + frame.pushInt(v1 | v2); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IREM.java b/src/main/java/haidnor/jvm/instruction/math/IREM.java new file mode 100644 index 0000000..62f6ae5 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IREM.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class IREM extends Instruction { + + public IREM(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + int result = (int) value1.getValue() % (int) value2.getValue(); + frame.push(new StackValue(Const.T_INT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/ISHL.java b/src/main/java/haidnor/jvm/instruction/math/ISHL.java new file mode 100644 index 0000000..d9273b5 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/ISHL.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class ISHL extends Instruction { + + public ISHL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + int v1 = frame.popInt(); + int s = v2 & 0x1f; + int ret = v1 << s; + frame.pushInt(ret); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/ISHR.java b/src/main/java/haidnor/jvm/instruction/math/ISHR.java new file mode 100644 index 0000000..ae36c0d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/ISHR.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class ISHR extends Instruction { + + public ISHR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + int v1 = frame.popInt(); + int s = v2 & 0x1f; + int ret = v1 >> s; + frame.pushInt(ret); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/ISUB.java b/src/main/java/haidnor/jvm/instruction/math/ISUB.java new file mode 100644 index 0000000..8e39ccd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/ISUB.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class ISUB extends Instruction { + + public ISUB(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + int result = (int) value1.getValue() - (int) value2.getValue(); + frame.push(new StackValue(Const.T_INT, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IUSHR.java b/src/main/java/haidnor/jvm/instruction/math/IUSHR.java new file mode 100644 index 0000000..7f0c822 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IUSHR.java @@ -0,0 +1,37 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +/** + * JVM中的IUSHR指令是用于执行无符号右移操作的指令。该指令将两个整数值从操作数栈中弹出, + * 然后将第一个操作数的位表示向右移动第二个操作数指定的位数,移位过程中高位用零填充。最后,将结果压入操作数栈中。 + * + * 在Java虚拟机规范中,IUSHR指令的操作码为0x7C,它属于逻辑指令家族(logical instructions)。 + * 这个指令通常需用到无符号数值在位级上的运算,因此它主要用于一些特定的计算和算法中。 + * + * 需要注意的是,IUSHR指令只适用于int类型的数据。如果操作数是long类型,则需要使用LUSHR指令进行无符号右移操作。 + */ +public class IUSHR extends Instruction { + + public IUSHR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + int v1 = frame.popInt(); + int s = v2 & 0x1f; + + if (v1 >= 0) { + int ret = v1 >> s; + frame.pushInt(ret); + return; + } + int ret = (v1 >> s) + (2 << ~s); + frame.pushInt(ret); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/IXOR.java b/src/main/java/haidnor/jvm/instruction/math/IXOR.java new file mode 100644 index 0000000..f6aceba --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/IXOR.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IXOR extends Instruction { + + public IXOR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + final int v2 = frame.popInt(); + final int v1 = frame.popInt(); + frame.pushInt(v1 ^ v2); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LADD.java b/src/main/java/haidnor/jvm/instruction/math/LADD.java new file mode 100644 index 0000000..06bf035 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LADD.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LADD extends Instruction { + + public LADD(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + long result = (long) value1.getValue() + (long) value2.getValue(); + frame.push(new StackValue(Const.T_LONG, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LAND.java b/src/main/java/haidnor/jvm/instruction/math/LAND.java new file mode 100644 index 0000000..06988b9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LAND.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LAND extends Instruction { + + public LAND(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long a1 = frame.popLong(); + long a2 = frame.popLong(); + frame.pushLong(a2 & a1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LDIV.java b/src/main/java/haidnor/jvm/instruction/math/LDIV.java new file mode 100644 index 0000000..fbcf6e6 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LDIV.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LDIV extends Instruction { + + public LDIV(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + long result = (long) value1.getValue() / (long) value2.getValue(); + frame.push(new StackValue(Const.T_LONG, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LMUL.java b/src/main/java/haidnor/jvm/instruction/math/LMUL.java new file mode 100644 index 0000000..6b448eb --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LMUL.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LMUL extends Instruction { + + public LMUL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + long result = (long) value1.getValue() * (long) value2.getValue(); + frame.push(new StackValue(Const.T_LONG, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LNEG.java b/src/main/java/haidnor/jvm/instruction/math/LNEG.java new file mode 100644 index 0000000..385f17b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LNEG.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LNEG extends Instruction { + + public LNEG(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue stackValue = frame.pop(); + long value = (long) stackValue.getValue(); + long tmp = -value; + frame.push(new StackValue(Const.T_LONG, tmp)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LOR.java b/src/main/java/haidnor/jvm/instruction/math/LOR.java new file mode 100644 index 0000000..024a15d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LOR.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LOR extends Instruction { + + public LOR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Long v2 = frame.popLong(); + Long v1 = frame.popLong(); + frame.pushLong(v1 | v2); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LREM.java b/src/main/java/haidnor/jvm/instruction/math/LREM.java new file mode 100644 index 0000000..f3afcf4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LREM.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LREM extends Instruction { + + public LREM(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + long result = (long) value1.getValue() % (long) value2.getValue(); + frame.push(new StackValue(Const.T_LONG, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LSHL.java b/src/main/java/haidnor/jvm/instruction/math/LSHL.java new file mode 100644 index 0000000..8177ad2 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LSHL.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LSHL extends Instruction { + + public LSHL(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + long v1 = frame.popLong(); + int s = v2 & 0x1f; + long ret = v1 << s; + frame.pushLong(ret); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LSHR.java b/src/main/java/haidnor/jvm/instruction/math/LSHR.java new file mode 100644 index 0000000..7837209 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LSHR.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LSHR extends Instruction { + + public LSHR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + final int v2 = frame.popInt(); + final long v1 = frame.popLong(); + frame.pushLong(v1 >> v2); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LSUB.java b/src/main/java/haidnor/jvm/instruction/math/LSUB.java new file mode 100644 index 0000000..e4f4229 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LSUB.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import org.apache.bcel.Const; + +public class LSUB extends Instruction { + + public LSUB(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value2 = frame.pop(); + StackValue value1 = frame.pop(); + long result = (long) value1.getValue() - (long) value2.getValue(); + frame.push(new StackValue(Const.T_LONG, result)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LUSHR.java b/src/main/java/haidnor/jvm/instruction/math/LUSHR.java new file mode 100644 index 0000000..fbe63a9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LUSHR.java @@ -0,0 +1,28 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LUSHR extends Instruction { + + public LUSHR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int v2 = frame.popInt(); + long v1 = frame.popLong(); + int s = v2 & 0x3f; + + if (v1 >= 0) { + long ret = v1 >> s; + frame.pushLong(ret); + return; + } + long ret = (v1 >> s) + (2L << ~s); + frame.pushLong(ret); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/math/LXOR.java b/src/main/java/haidnor/jvm/instruction/math/LXOR.java new file mode 100644 index 0000000..cb13220 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/math/LXOR.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.math; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LXOR extends Instruction { + + public LXOR(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long v2 = frame.popLong(); + long v1 = frame.popLong(); + frame.pushLong(v1 ^ v2); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java b/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java new file mode 100644 index 0000000..5a2a27a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java @@ -0,0 +1,47 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.InstanceArray; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.metaspace.Metaspace; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.Utility; + +public class ANEWARRAY extends Instruction { + + private final int constantClassIndex; + + public ANEWARRAY(CodeStream codeStream) { + super(codeStream); + this.constantClassIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); + ConstantClass constantClass = constantPool.getConstant(constantClassIndex); + String className = constantPoolUtil.getClassName(constantClass); + + Klass klass = Metaspace.getJavaClass(Utility.compactClassName(className)); + if (klass == null) { + // 如果在元空间中找不到已加载的类,则开始进行类加载流程 + klass = frame.getMetaClass().getClassLoader().loadClass(className); + } + int size = frame.popInt(); + Instance[] items = new Instance[size]; + InstanceArray instanceArray = new InstanceArray(klass, items); + + frame.push(new StackValue(Const.T_OBJECT, instanceArray)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/ARRAYLENGTH.java b/src/main/java/haidnor/jvm/instruction/references/ARRAYLENGTH.java new file mode 100644 index 0000000..4d245df --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/ARRAYLENGTH.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.ArrayInstance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class ARRAYLENGTH extends Instruction { + + public ARRAYLENGTH(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ArrayInstance array = (ArrayInstance) frame.popRef(); + frame.pushInt(array.size); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/CHECKCAST.java b/src/main/java/haidnor/jvm/instruction/references/CHECKCAST.java new file mode 100644 index 0000000..15a4874 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/CHECKCAST.java @@ -0,0 +1,24 @@ + +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class CHECKCAST extends Instruction { + + private final int constantClassIndex; + + public CHECKCAST(CodeStream codeStream) { + super(codeStream); + this.constantClassIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + // 暂时不支持 + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/GETFIELD.java b/src/main/java/haidnor/jvm/instruction/references/GETFIELD.java new file mode 100644 index 0000000..edd13d7 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/GETFIELD.java @@ -0,0 +1,52 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.KlassField; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import lombok.SneakyThrows; + +public class GETFIELD extends Instruction { + + private final int constantFieldrefIndex; + + public GETFIELD(CodeStream codeStream) { + super(codeStream); + this.constantFieldrefIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPoolUtil constantPool = frame.getConstantPoolUtil(); + String filedName = constantPool.getFieldName(constantFieldrefIndex); + String fieldSignature = constantPool.getFieldSignature(constantFieldrefIndex); + + Instance instanceRef = frame.popRef(); + KlassField field = instanceRef.getField(filedName, fieldSignature); + switch (field.descriptor) { + case "Z": + case "C": + case "B": + case "S": + case "I": + frame.pushInt((int) field.getValue()); + break; + case "J": + frame.pushLong((long) field.getValue()); + break; + case "F": + frame.pushFloat((float) field.getValue()); + break; + case "D": + frame.pushDouble((double) field.getValue()); + break; + default: // ref + frame.pushRef(field.getValue()); + break; + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java b/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java new file mode 100644 index 0000000..46fcf0e --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/GETSTATIC.java @@ -0,0 +1,46 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.ConstantFieldref; +import org.apache.bcel.classfile.ConstantPool; + +import java.lang.reflect.Field; + +/** + * 获取字段符号引用指定的对象或者值(类的静态字段 static 修饰),并将其压入操作数栈 + */ +public class GETSTATIC extends Instruction { + + private final int constantFieldrefIndex; + + public GETSTATIC(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文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数. + + Class clazz = Class.forName(className.replace('/', '.')); + Field field = clazz.getField(fieldName); + Object staticFiledValue = field.get(null); // 获取静态字段上的值 + + frame.push(new StackValue(Const.T_OBJECT, staticFiledValue)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/INVOKESPECIAL.java b/src/main/java/haidnor/jvm/instruction/references/INVOKESPECIAL.java new file mode 100644 index 0000000..0c7b8c3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/INVOKESPECIAL.java @@ -0,0 +1,87 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.classloader.ClassLoader; +import haidnor.jvm.core.JavaExecutionEngine; +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; +import haidnor.jvm.rtda.metaspace.Metaspace; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import haidnor.jvm.util.SignatureUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.*; + +/** + * 调用一些需要特殊处理的实例方法,包括构造器方法,私有方法,父类方法,这些方法都是静态绑定的,不会在调用时进行动态分配 + */ +public class INVOKESPECIAL extends Instruction { + + private final int constantMethodrefIndex; + + public INVOKESPECIAL(CodeStream codeStream) { + super(codeStream); + this.constantMethodrefIndex = codeStream.readUnsignedShort(this); + } + + @SneakyThrows + @Override + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); + ConstantMethodref methodref = constantPool.getConstant(constantMethodrefIndex); + + String className = constantPoolUtil.getBelongClassName(methodref); + String methodName = constantPoolUtil.getMethodName(methodref); + String methodSignature = constantPoolUtil.getMethodSignature(methodref); + + Klass klass = Metaspace.getJavaClass(Utility.compactClassName(className)); + JavaClass javaClass; + if (klass != null) { + javaClass = klass.getJavaClass(); + } else { + ClassLoader classLoader = frame.getMetaClass().getClassLoader(); + klass = classLoader.loadClass(className); + javaClass = klass.getJavaClass(); + } + + if (className.startsWith("java/")) { + // 执行 RT.jar 中 Java 对象构造方法的时候创建java对象 + if (methodName.equals("")) { + // 执行方法的参数列表 + Class[] parameterTypeArr = SignatureUtil.getParameterTypes(methodSignature); + // 执行方法的参数值 + Object[] args = frame.popStacksValue(parameterTypeArr.length); + // 将特定的参数转换为基本类型 + for (int i = 0; i < parameterTypeArr.length; i++) { + Class clazz = parameterTypeArr[i]; + if (clazz.getName().equals("boolean")) { // boolean 存储方式为 int 类型 + int booleanFlag = (int) args[i]; + args[i] = booleanFlag == 1; + } else if (clazz.getName().equals("char")) { // char 存储方式为 + int charInt = (int) args[i]; + char c = (char) charInt; + args[i] = c; + } + } + Object javaObj = Class.forName(Utility.compactClassName(className,false)).getDeclaredConstructor(parameterTypeArr).newInstance(args); + frame.push(new StackValue(Const.T_OBJECT, javaObj)); // NEW + frame.push(new StackValue(Const.T_OBJECT, javaObj)); // DUP + return; + } + } + + for (Method method : javaClass.getMethods()) { + if (method.getSignature().equals(methodSignature) && method.getName().equals(methodName)) { + KlassMethod klassMethod = new KlassMethod(klass, method); + JavaExecutionEngine.callMethod(frame, klassMethod); + break; + } + } + } + + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/INVOKESTATIC.java b/src/main/java/haidnor/jvm/instruction/references/INVOKESTATIC.java new file mode 100644 index 0000000..1dc3857 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/INVOKESTATIC.java @@ -0,0 +1,81 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.core.JavaExecutionEngine; +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; +import haidnor.jvm.rtda.metaspace.Metaspace; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import haidnor.jvm.util.SignatureUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.*; + +import java.util.Objects; + +/** + * 调用 static 静态方法.这是静态绑定的 + */ +public class INVOKESTATIC extends Instruction { + + private final int constantMethodrefIndex; + + public INVOKESTATIC(CodeStream codeStream) { + super(codeStream); + this.constantMethodrefIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); + + ConstantMethodref methodref = constantPool.getConstant(constantMethodrefIndex); + String className = constantPoolUtil.getBelongClassName(methodref); + String methodName = constantPoolUtil.getMethodName(methodref); + String methodSignature = constantPoolUtil.getMethodSignature(methodref); + + // 系统类反射 自定义类另外处理 + if (className.startsWith("java/")) { + // 解析方法签名得到方法的返回类型 + String returnType = Utility.methodSignatureReturnType(methodSignature, false); + java.lang.Class[] parameterTypeArr = SignatureUtil.getParameterTypes(methodSignature); + Object[] stacksValueArr = frame.popStacksValue(parameterTypeArr.length); + for (int i = 0; i < parameterTypeArr.length; i++) { + java.lang.Class aClass = parameterTypeArr[i]; + if (aClass.getName().equals("boolean")) { + int booleanFlag = (int) stacksValueArr[i]; + stacksValueArr[i] = booleanFlag == 1; + } + } + + Class javaClass = Class.forName(Utility.compactClassName(className,false)); + java.lang.reflect.Method method = javaClass.getMethod(methodName, parameterTypeArr); + method.setAccessible(true); + Object value = method.invoke(null, stacksValueArr); + if (!Objects.equals(Const.getTypeName(Const.T_VOID), returnType)) { // void 调用的方法无返回值 + frame.push(new StackValue(Const.T_OBJECT, value)); + } + } + // 自定义类的方法 + else { + Klass meteKlass = Metaspace.getJavaClass(Utility.compactClassName(className)); + if (meteKlass != null) { + JavaClass javaClass = meteKlass.getJavaClass(); + for (Method method : javaClass.getMethods()) { + if (method.getSignature().equals(methodSignature) && method.getName().equals(methodName)) { + KlassMethod klassMethod = new KlassMethod(meteKlass, method); + JavaExecutionEngine.callMethod(frame, klassMethod); + break; + } + } + } + } + + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/INVOKEVIRTUAL.java b/src/main/java/haidnor/jvm/instruction/references/INVOKEVIRTUAL.java new file mode 100644 index 0000000..7f093b3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/INVOKEVIRTUAL.java @@ -0,0 +1,95 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.core.JavaExecutionEngine; +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import haidnor.jvm.util.SignatureUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.ConstantMethodref; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Utility; + +import java.lang.reflect.Method; +import java.util.Objects; + +/** + * 调用对象实例方法,根据对象的实际类型进行分派(虚方法分派),支持多态 + */ +public class INVOKEVIRTUAL extends Instruction { + + private final int constantMethodrefIndex; + + public INVOKEVIRTUAL(CodeStream codeStream) { + super(codeStream); + this.constantMethodrefIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); + + ConstantMethodref methodref = constantPool.getConstant(constantMethodrefIndex); + + String className = constantPoolUtil.getBelongClassName(methodref); + String methodName = constantPoolUtil.getMethodName(methodref); + String methodSignature = constantPoolUtil.getMethodSignature(methodref); + + // 系统类反射 自定义类另外处理 + if (className.startsWith("java/")) { + // 解析方法签名得到方法的返回类型 + String returnType = Utility.methodSignatureReturnType(methodSignature, false); + // 执行方法的参数列表 + Class[] parameterTypeArr = SignatureUtil.getParameterTypes(methodSignature); + // 执行方法的参数值 + Object[] args = frame.popStacksValue(parameterTypeArr.length); + // 将特定的参数转换为基本类型 + for (int i = 0; i < parameterTypeArr.length; i++) { + Class clazz = parameterTypeArr[i]; + if (clazz.getName().equals("boolean")) { // boolean 存储方式为 int 类型 + int booleanFlag = (int) args[i]; + args[i] = booleanFlag == 1; + } else if (clazz.getName().equals("char")) { // char 存储方式为 + int charInt = (int) args[i]; + char c = (char) charInt; + args[i] = c; + } + } + + StackValue stackValue = frame.pop(); + Object obj = stackValue.getValue(); + Method method = obj.getClass().getMethod(methodName, parameterTypeArr); + method.setAccessible(true); + Object value = method.invoke(obj, args); + if (!Objects.equals(Const.getTypeName(Const.T_VOID), returnType)) { // void 调用的方法无返回值 + frame.push(new StackValue(Const.T_OBJECT, value)); + } + } + // 调用自定义类的方法 + else { + // 获得栈顶对象实例,根据对象的实际类型进行分派(虚方法分派),支持多态 + StackValue stackValue = frame.peek(); + Instance instance = (Instance) stackValue.getValue(); + Klass meteKlass = instance.klass; + JavaClass javaClass = meteKlass.getJavaClass(); + for (org.apache.bcel.classfile.Method method : javaClass.getMethods()) { + if (method.getSignature().equals(methodSignature) && method.getName().equals(methodName)) { + KlassMethod klassMethod = new KlassMethod(meteKlass, method); + JavaExecutionEngine.callMethod(frame, klassMethod); + break; + } + } + } + } + + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/JSR.java b/src/main/java/haidnor/jvm/instruction/references/JSR.java new file mode 100644 index 0000000..eccb23c --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/JSR.java @@ -0,0 +1,30 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +/** + * JSR(Jump to Subroutine)指令是一条在Java虚拟机中用于进行子程序调用的指令。它将当前指令的返回地址压入操作数栈,并跳转到指定的子程序代码执行。子程序执行完毕后,通过RET(Return)指令返回到主程序的下一条指令继续执行。 + *

+ * JSR指令的操作码为0xA8,属于控制指令家族(Control Instructions)。它的操作数是一个16位的无符号偏移量,用于表示跳转目标的字节码偏移量。 + *

+ * 使用JSR指令可以实现方法的调用和返回,但在实际的Java字节码中,更常见的是使用invokestatic、invokevirtual等指令来进行方法调用。 + *

+ * 需要注意的是,JSR指令只在早期版本的Java虚拟机规范中存在,在Java SE 6及以后的版本中已被废弃,并且不建议在新的Java代码中使用。 + */ +public class JSR extends Instruction { + + public JSR(CodeStream codeStream) { + super(codeStream); + throw new UnsupportedOperationException("JSR"); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + throw new UnsupportedOperationException("JSR"); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/JSR_W.java b/src/main/java/haidnor/jvm/instruction/references/JSR_W.java new file mode 100644 index 0000000..09513e8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/JSR_W.java @@ -0,0 +1,26 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +/** + * 在早期版本的Java虚拟机规范中,存在JSR和JSR_W两个指令。其中,JSR指令用于进行子程序调用,而JSR_W指令用于进行宽跳转的子程序调用。宽跳转指令可以用于在字节码中的跳转偏移量超过16位时进行有效的跳转。 + *

+ * 然而,从Java SE 6及以后的版本开始,Java虚拟机规范已废弃了JSR_W指令,并且不建议在新的Java代码中使用。而是通过其他方式来实现跳转,例如使用ldc_w、ldc2_w和goto_w等指令结合进行宽跳转。 + */ +public class JSR_W extends Instruction { + + public JSR_W(CodeStream codeStream) { + super(codeStream); + throw new UnsupportedOperationException("JSR_W"); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + throw new UnsupportedOperationException("JSR"); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/NEW.java b/src/main/java/haidnor/jvm/instruction/references/NEW.java new file mode 100644 index 0000000..59a7c6f --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/NEW.java @@ -0,0 +1,48 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.metaspace.Metaspace; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import lombok.SneakyThrows; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.Utility; + +public class NEW extends Instruction { + + private final int constantClassIndex; + + public NEW(CodeStream codeStream) { + super(codeStream); + this.constantClassIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPool constantPool = frame.getConstantPool(); + ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); + ConstantClass constantClass = constantPool.getConstant(constantClassIndex); + String className = constantPoolUtil.getClassName(constantClass); + + if (className.startsWith("java/")) { + frame.push(new StackValue(Const.T_OBJECT, null)); + return; + } + + Klass klass = Metaspace.getJavaClass(Utility.compactClassName(className)); + if (klass == null) { + // 如果在元空间中找不到已加载的类,则开始进行类加载流程 + klass = frame.getMetaClass().getClassLoader().loadClass(className); + } + Instance instance = klass.newInstance(); + frame.push(new StackValue(Const.T_OBJECT, instance)); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/NEWARRAY.java b/src/main/java/haidnor/jvm/instruction/references/NEWARRAY.java new file mode 100644 index 0000000..5c0a3e8 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/NEWARRAY.java @@ -0,0 +1,53 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; +import org.apache.bcel.Const; + +public class NEWARRAY extends Instruction { + + private final int type; + + public NEWARRAY(CodeStream codeStream) { + super(codeStream); + this.type = codeStream.readUnsignedByte(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + int size = frame.popInt(); + switch (type) { + case Const.T_BOOLEAN -> { + frame.pushRef(BasicTypeArray.boolArray(size)); + } + case Const.T_CHAR -> { + frame.pushRef(BasicTypeArray.charArray(size)); + } + case Const.T_FLOAT -> { + frame.pushRef(BasicTypeArray.floatArray(size)); + } + case Const.T_DOUBLE -> { + frame.pushRef(BasicTypeArray.doubleArray(size)); + } + case Const.T_BYTE -> { + frame.pushRef(BasicTypeArray.byteArray(size)); + } + case Const.T_SHORT -> { + frame.pushRef(BasicTypeArray.shortArray(size)); + } + case Const.T_INT -> { + frame.pushRef(BasicTypeArray.intArray(size)); + } + case Const.T_LONG -> { + frame.pushRef(BasicTypeArray.longArray(size)); + } + default -> throw new IllegalArgumentException(); + } + + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/references/PUTFIELD.java b/src/main/java/haidnor/jvm/instruction/references/PUTFIELD.java new file mode 100644 index 0000000..9866e36 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/references/PUTFIELD.java @@ -0,0 +1,35 @@ +package haidnor.jvm.instruction.references; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.KlassField; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import lombok.SneakyThrows; + +public class PUTFIELD extends Instruction { + + private final int constantFieldrefIndex; + + public PUTFIELD(CodeStream codeStream) { + super(codeStream); + this.constantFieldrefIndex = codeStream.readUnsignedShort(this); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + ConstantPoolUtil constantPool = frame.getConstantPoolUtil(); + String filedName = constantPool.getFieldName(constantFieldrefIndex); + String fieldSignature = constantPool.getFieldSignature(constantFieldrefIndex); + + StackValue stackValue = frame.pop(); + + Instance instance = frame.popRef(); + KlassField field = instance.getField(filedName, fieldSignature); + field.setVal(stackValue); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/DUP.java b/src/main/java/haidnor/jvm/instruction/stack/DUP.java new file mode 100644 index 0000000..e29a03b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/DUP.java @@ -0,0 +1,27 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class DUP extends Instruction { + + public DUP(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + StackValue stackValue = frame.pop(); + + // 判空是为了兼容创建 Java 对象, 创建rt.jar java对象时,执行 NEW 指令会在栈帧中存放一个 NULL + if (stackValue.getValue() != null) { + frame.push(stackValue); + frame.push(stackValue); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/DUP2.java b/src/main/java/haidnor/jvm/instruction/stack/DUP2.java new file mode 100644 index 0000000..ea7e3dd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/DUP2.java @@ -0,0 +1,41 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +/** + * DUP2指令是一条Java虚拟机指令,用于复制栈顶两个元素,并将复制的值插入到栈顶之后。 + *

+ * DUP2指令有以下几种形式: + *

+ * 栈顶元素为A的情况: + *

+ * 执行DUP2指令后,栈的状态变为:A(副本)、A。 + * 栈顶元素为A和B的情况: + *

+ * 执行DUP2指令后,栈的状态变为:A(副本)、B、A、B。 + * 需要注意的是,在执行DUP2指令时,操作数栈必须至少有一个或两个元素,具体取决于栈顶元素的数量。如果栈顶元素只有一个,则只会复制该元素一次;如果栈顶元素有两个,则会分别复制两个元素。 + *

+ * 在Java虚拟机规范中,DUP2指令的操作码为0x5C,也属于堆栈管理指令家族(Stack Management Instructions)。 + */ +public class DUP2 extends Instruction { + + public DUP2(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + StackValue stackValue1 = frame.pop(); + StackValue stackValue2 = frame.pop(); + frame.push(stackValue2); + frame.push(stackValue1); + frame.push(stackValue2); + frame.push(stackValue1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/DUP_X1.java b/src/main/java/haidnor/jvm/instruction/stack/DUP_X1.java new file mode 100644 index 0000000..6829c32 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/DUP_X1.java @@ -0,0 +1,36 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +/** + * DUP_X1指令是一条Java虚拟机指令,用于复制栈顶元素并插入到栈顶下面的第二个元素位置。 + *

+ * 具体而言,DUP_X1指令的作用是将栈顶元素复制一份,并将复制出的值插入到栈顶下面的第二个元素位置。这种操作会在栈上产生一个额外的副本,栈的深度会增加1。 + *

+ * 例如,如果栈顶是A,下面的两个元素是B和C,执行DUP_X1指令后,栈的状态将变为:A(副本)、B、C、A。 + *

+ * 在Java虚拟机规范中,DUP_X1指令的操作码为0x5A,属于堆栈管理指令家族(Stack Management Instructions)。 + *

+ * 需要注意的是,执行DUP_X1指令时,操作数栈必须至少有两个元素,否则指令无法正常执行。 + */ +public class DUP_X1 extends Instruction { + + public DUP_X1(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + StackValue stackValue1 = frame.pop(); + StackValue stackValue2 = frame.pop(); + frame.push(stackValue1); + frame.push(stackValue2); + frame.push(stackValue1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/DUP_X2.java b/src/main/java/haidnor/jvm/instruction/stack/DUP_X2.java new file mode 100644 index 0000000..e8430a3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/DUP_X2.java @@ -0,0 +1,47 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +/** + * DUP_X2指令是一条Java虚拟机指令,用于复制栈顶元素并插入到栈顶下面的第三个元素位置。 + *

+ * 具体而言,DUP_X2指令的作用是将栈顶元素复制一份,并将复制出的值插入到栈顶下面的第三个元素位置。这种操作会在栈上产生一个额外的副本,栈的深度会增加1。 + *

+ * 根据栈顶元素以及其后面的元素数量,DUP_X2指令有三种不同的形式: + *

+ * 栈顶元素为A,下面两个元素为B和C的情况: + *

+ * 执行DUP_X2指令后,栈的状态变为:A(副本)、B、C、A。 + * 栈顶元素为A,下面三个元素为B、C和D的情况: + *

+ * 执行DUP_X2指令后,栈的状态变为:A(副本)、B、C、D、A。 + * 栈顶元素为A,下面一个元素为B的情况: + *

+ * 执行DUP_X2指令后,栈的状态变为:A(副本)、B、A。 + * 在Java虚拟机规范中,DUP_X2指令的操作码为0x5C,也属于堆栈管理指令家族(Stack Management Instructions)。 + *

+ * 需要注意的是,执行DUP_X2指令时,操作数栈必须至少有两个或三个元素,具体取决于栈顶元素和其后面的元素的数量,否则指令无法正常执行。 + */ +public class DUP_X2 extends Instruction { + + public DUP_X2(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + StackValue stackValue1 = frame.pop(); + StackValue stackValue2 = frame.pop(); + StackValue stackValue3 = frame.pop(); + frame.push(stackValue1); + frame.push(stackValue3); + frame.push(stackValue2); + frame.push(stackValue1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/POP.java b/src/main/java/haidnor/jvm/instruction/stack/POP.java new file mode 100644 index 0000000..3543f15 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/POP.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class POP extends Instruction { + + public POP(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + frame.pop(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/POP2.java b/src/main/java/haidnor/jvm/instruction/stack/POP2.java new file mode 100644 index 0000000..289ae75 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/POP2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class POP2 extends Instruction { + + public POP2(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + frame.pop(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stack/SWAP.java b/src/main/java/haidnor/jvm/instruction/stack/SWAP.java new file mode 100644 index 0000000..3cd35d1 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stack/SWAP.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.stack; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.SneakyThrows; + +public class SWAP extends Instruction { + + public SWAP(CodeStream codeStream) { + super(codeStream); + } + + @Override + @SneakyThrows + public void execute(Frame frame) { + Instance v2 = frame.popRef(); + Instance v1 = frame.popRef(); + frame.pushRef(v2); + frame.pushRef(v1); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/AASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/AASTORE.java new file mode 100644 index 0000000..bc17d68 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/AASTORE.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.InstanceArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class AASTORE extends Instruction { + + public AASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + Instance val = frame.popRef(); + int index = frame.popInt(); + InstanceArray array = (InstanceArray) frame.popRef(); + array.items[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/ASTORE.java new file mode 100644 index 0000000..f8dfa7d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ASTORE.java @@ -0,0 +1,24 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ASTORE extends Instruction { + + private final int index; + + public ASTORE(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetRef(index, (Instance) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ASTORE_0.java b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_0.java new file mode 100644 index 0000000..19d39ad --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_0.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ASTORE_0 extends Instruction { + + public ASTORE_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetRef(0, (Instance) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ASTORE_1.java b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_1.java new file mode 100644 index 0000000..14faefe --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_1.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ASTORE_1 extends Instruction { + + public ASTORE_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetRef(1, value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ASTORE_2.java b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_2.java new file mode 100644 index 0000000..c04efc9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ASTORE_2 extends Instruction { + + public ASTORE_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetRef(2, value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ASTORE_3.java b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_3.java new file mode 100644 index 0000000..0ea75d6 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ASTORE_3.java @@ -0,0 +1,21 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ASTORE_3 extends Instruction { + + public ASTORE_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetRef(3, (Instance) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/BASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/BASTORE.java new file mode 100644 index 0000000..d92693a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/BASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class BASTORE extends Instruction { + + public BASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int val = frame.popInt(); + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.ints[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/CASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/CASTORE.java new file mode 100644 index 0000000..5677d74 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/CASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class CASTORE extends Instruction { + + public CASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int val = frame.popInt(); + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.ints[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/DASTORE.java new file mode 100644 index 0000000..ab3dac1 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class DASTORE extends Instruction { + + public DASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + double val = frame.popDouble(); + int index = frame.popInt(); + final BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.doubles[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DSTORE.java b/src/main/java/haidnor/jvm/instruction/stores/DSTORE.java new file mode 100644 index 0000000..a6f18d9 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DSTORE.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class DSTORE extends Instruction { + + private final int index; + + public DSTORE(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetDouble(index, (double) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DSTORE_0.java b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_0.java new file mode 100644 index 0000000..e3e188b --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_0.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class DSTORE_0 extends Instruction { + + public DSTORE_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetDouble(0, (double) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DSTORE_1.java b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_1.java new file mode 100644 index 0000000..9e9aad3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_1.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class DSTORE_1 extends Instruction { + + public DSTORE_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetDouble(1, (double) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DSTORE_2.java b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_2.java new file mode 100644 index 0000000..943ce56 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class DSTORE_2 extends Instruction { + + public DSTORE_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetDouble(2, (double) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/DSTORE_3.java b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_3.java new file mode 100644 index 0000000..874ecff --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/DSTORE_3.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class DSTORE_3 extends Instruction { + + public DSTORE_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetDouble(3, (double) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/FASTORE.java new file mode 100644 index 0000000..d172a64 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class FASTORE extends Instruction { + + public FASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + float val = frame.popFloat(); + int index = frame.popInt(); + final BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.floats[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FSTORE.java b/src/main/java/haidnor/jvm/instruction/stores/FSTORE.java new file mode 100644 index 0000000..354aabd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FSTORE.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class FSTORE extends Instruction { + + private final int index; + + public FSTORE(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetFloat(index, (float) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FSTORE_0.java b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_0.java new file mode 100644 index 0000000..9f3d662 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_0.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class FSTORE_0 extends Instruction { + + public FSTORE_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetFloat(0, (float) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FSTORE_1.java b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_1.java new file mode 100644 index 0000000..39a02d4 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_1.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class FSTORE_1 extends Instruction { + + public FSTORE_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetFloat(1, (float) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FSTORE_2.java b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_2.java new file mode 100644 index 0000000..93c878d --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class FSTORE_2 extends Instruction { + + public FSTORE_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetFloat(2, (float) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/FSTORE_3.java b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_3.java new file mode 100644 index 0000000..2fbc978 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/FSTORE_3.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class FSTORE_3 extends Instruction { + + public FSTORE_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetFloat(3, (float) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/IASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/IASTORE.java new file mode 100644 index 0000000..62a5804 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/IASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class IASTORE extends Instruction { + + public IASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int val = frame.popInt(); + int index = frame.popInt(); + final BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.ints[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ISTORE.java b/src/main/java/haidnor/jvm/instruction/stores/ISTORE.java new file mode 100644 index 0000000..20095e2 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ISTORE.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ISTORE extends Instruction { + + private final int index; + + public ISTORE(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedShort(this); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetInt(index, (int) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ISTORE_0.java b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_0.java new file mode 100644 index 0000000..34b1c45 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_0.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ISTORE_0 extends Instruction { + + public ISTORE_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetInt(0, (int) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ISTORE_1.java b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_1.java new file mode 100644 index 0000000..d48c064 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_1.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ISTORE_1 extends Instruction { + + public ISTORE_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetInt(1, (int) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ISTORE_2.java b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_2.java new file mode 100644 index 0000000..166bc3a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ISTORE_2 extends Instruction { + + public ISTORE_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetInt(2, (int) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/ISTORE_3.java b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_3.java new file mode 100644 index 0000000..7e9fe6e --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/ISTORE_3.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class ISTORE_3 extends Instruction { + + public ISTORE_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetInt(3, (int) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/LASTORE.java new file mode 100644 index 0000000..273fa56 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class LASTORE extends Instruction { + + public LASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + long val = frame.popLong(); + int index = frame.popInt(); + final BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.longs[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LSTORE.java b/src/main/java/haidnor/jvm/instruction/stores/LSTORE.java new file mode 100644 index 0000000..764dbfd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LSTORE.java @@ -0,0 +1,23 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class LSTORE extends Instruction { + + private final int index; + + public LSTORE(CodeStream codeStream) { + super(codeStream); + this.index = codeStream.readUnsignedByte(this); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetLong(index, (long) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LSTORE_0.java b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_0.java new file mode 100644 index 0000000..2c5711a --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_0.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class LSTORE_0 extends Instruction { + + public LSTORE_0(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetLong(0, (long) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LSTORE_1.java b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_1.java new file mode 100644 index 0000000..3b3d390 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_1.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class LSTORE_1 extends Instruction { + + public LSTORE_1(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetLong(1, (long) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LSTORE_2.java b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_2.java new file mode 100644 index 0000000..e993b72 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_2.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class LSTORE_2 extends Instruction { + + public LSTORE_2(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetLong(2, (long) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/LSTORE_3.java b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_3.java new file mode 100644 index 0000000..eb4cb25 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/LSTORE_3.java @@ -0,0 +1,20 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; + +public class LSTORE_3 extends Instruction { + + public LSTORE_3(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + StackValue value = frame.pop(); + frame.slotSetLong(3, (long) value.getValue()); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/stores/SASTORE.java b/src/main/java/haidnor/jvm/instruction/stores/SASTORE.java new file mode 100644 index 0000000..00b8bbd --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/stores/SASTORE.java @@ -0,0 +1,22 @@ +package haidnor.jvm.instruction.stores; + +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.rtda.heap.BasicTypeArray; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; + +public class SASTORE extends Instruction { + + public SASTORE(CodeStream codeStream) { + super(codeStream); + } + + @Override + public void execute(Frame frame) { + int val = frame.popInt(); + int index = frame.popInt(); + BasicTypeArray array = (BasicTypeArray) frame.popRef(); + array.ints[index] = val; + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/UnionSlot.java b/src/main/java/haidnor/jvm/rtda/UnionSlot.java new file mode 100644 index 0000000..adf9761 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/UnionSlot.java @@ -0,0 +1,103 @@ +package haidnor.jvm.rtda; + +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.runtime.Slot; + +/** + * 用于字段的联合 Slot + */ +public class UnionSlot { + + private Slot high; + private Slot low; + + private UnionSlot(Slot high, Slot low) { + this.high = high; + this.low = low; + } + + // 初始化 + public static UnionSlot of(Slot high, Slot low) { + return new UnionSlot(high, low); + } + + public static UnionSlot of(Slot high) { + return new UnionSlot(high, null); + } + + public static UnionSlot of(Instance instance) { + return new UnionSlot(new Slot(instance), null); + } + + public static UnionSlot of(int val) { + return new UnionSlot(new Slot(val), null); + } + + public static UnionSlot of(float val) { + return of(Float.floatToIntBits(val)); + } + + public static UnionSlot of(long val) { + int high = (int) (val >> 32); //高32位 + int low = (int) (val & 0x000000ffffffffL); //低32位 + return new UnionSlot(new Slot(high), new Slot(low)); + } + + public static UnionSlot of(double val) { + return of(Double.doubleToLongBits(val)); + } + + // 存 + public void setRef(Instance val) { + high.ref = val; + } + + public void setInt(int val) { + high.num = val; + } + + public void setFloat(float val) { + setInt(Float.floatToIntBits(val)); + } + + public void setLong(long val) { + int highV = (int) (val >> 32); //高32位 + int lowV = (int) (val & 0x000000ffffffffL); //低32位 + high.num = highV; + low.num = lowV; + } + + public void setDouble(double val) { + setLong(Double.doubleToLongBits(val)); + } + + public void set(UnionSlot neo) { + this.high = neo.high; + this.low = neo.low; + } + + // 取 + public Object getRef() { + return high.ref; + } + + public int getInt() { + return high.num; + } + + public float getFloat() { + return Float.intBitsToFloat(getInt()); + } + + public long getLong() { + final int high = this.high.num; + final int low = this.low.num; + long l1 = (high & 0x000000ffffffffL) << 32; + long l2 = low & 0x00000000ffffffffL; + return l1 | l2; + } + + public double getDouble() { + return Double.longBitsToDouble(getLong()); + } +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/rtda/heap/ArrayInstance.java b/src/main/java/haidnor/jvm/rtda/heap/ArrayInstance.java new file mode 100644 index 0000000..53e00fc --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/ArrayInstance.java @@ -0,0 +1,12 @@ +package haidnor.jvm.rtda.heap; + +public abstract class ArrayInstance extends Instance { + + public final int size; + + public ArrayInstance(Klass klass, int size) { + super(klass); + this.size = size; + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/BasicTypeArray.java b/src/main/java/haidnor/jvm/rtda/heap/BasicTypeArray.java new file mode 100644 index 0000000..41ced9a --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/BasicTypeArray.java @@ -0,0 +1,62 @@ +package haidnor.jvm.rtda.heap; + +public class BasicTypeArray extends ArrayInstance { + + public int[] ints; + public long[] longs; + public float[] floats; + public double[] doubles; + + private BasicTypeArray(int size) { + super(null, size); + } + + public static BasicTypeArray charArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray boolArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray byteArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray shortArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray intArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray longArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.longs = new long[size]; + return array; + } + + public static BasicTypeArray floatArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.floats = new float[size]; + return array; + } + + public static BasicTypeArray doubleArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.doubles = new double[size]; + return array; + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/rtda/heap/Heap.java b/src/main/java/haidnor/jvm/rtda/heap/Heap.java new file mode 100644 index 0000000..ca3a372 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/Heap.java @@ -0,0 +1,7 @@ +package haidnor.jvm.rtda.heap; + +/** + * 堆空间 + */ +public class Heap { +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/Instance.java b/src/main/java/haidnor/jvm/rtda/heap/Instance.java new file mode 100644 index 0000000..ee67354 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/Instance.java @@ -0,0 +1,67 @@ +package haidnor.jvm.rtda.heap; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * JVM 中的 Java 对象实例 + */ +public class Instance { + + public final Klass klass; + + public final List fields; + + private Instance superInstance; + + public Instance(Klass klass) { + this.klass = klass; + this.fields = new ArrayList<>(); + } + + public Instance(List fields, Klass klass) { + this.fields = fields; + this.klass = klass; + } + + + public void setSuperInstance(Instance superInstance) { + this.superInstance = superInstance; + } + + /** + * 获取字段 + * + * @param name 字段名称 + * @param signature 字段签名 + */ + public KlassField getField(String name, String signature) { + // this object + for (KlassField field : fields) { + if (Objects.equals(field.name, name) && Objects.equals(field.descriptor, signature)) { + return field; + } + } + if (this.superInstance == null) { + return null; + } + // super object + return this.superInstance.getField(name, signature); + } + +// /** +// * 设置字段 +// * +// * @param name 字段名称 +// * @param signature 字段签名 +// * @param val 值 +// */ +// public void setField(String name, String signature, UnionSlot val) { +// JavaField field = this.getField(name, signature); +// field.set(val); +// } + + +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/InstanceArray.java b/src/main/java/haidnor/jvm/rtda/heap/InstanceArray.java new file mode 100644 index 0000000..d036024 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/InstanceArray.java @@ -0,0 +1,12 @@ +package haidnor.jvm.rtda.heap; + +public class InstanceArray extends ArrayInstance { + + public final Instance[] items; + + public InstanceArray(Klass klass, Instance[] items) { + super(klass, items.length); + this.items = items; + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/rtda/heap/Klass.java b/src/main/java/haidnor/jvm/rtda/heap/Klass.java new file mode 100644 index 0000000..9a071fd --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/Klass.java @@ -0,0 +1,76 @@ +package haidnor.jvm.rtda.heap; + +import haidnor.jvm.classloader.ClassLoader; +import lombok.SneakyThrows; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * 类元信息 + */ +public class Klass { + + /** + * BCEL JavaClass + */ + private final JavaClass javaClass; + + /** + * 加载此 Class 的类加载器 + */ + private final ClassLoader classLoader; + + /** + * 此 Class 名称. 例如 java.util.ArrayList + */ + private final String className; + + public final String superClassName; + + private Klass superKlass; + + @SneakyThrows + public Klass(ClassLoader classLoader, JavaClass javaClass) { + this.javaClass = javaClass; + this.classLoader = classLoader; + this.className = javaClass.getClassName(); + this.superClassName = javaClass.getSuperclassName(); + + JavaClass superJavaClass = javaClass.getSuperClass(); + if (superJavaClass != null) { + this.superKlass = new Klass(classLoader, superJavaClass); + } + } + + public Instance newInstance() { + // 创建对象存放字段的内存空间 + List klassFieldList = new ArrayList<>(); + for (Field field : javaClass.getFields()) { + KlassField klassField = new KlassField(field); + klassFieldList.add(klassField); + } + // 创建 JVM 中的对象实例 + Instance obj = new Instance(klassFieldList, this); + // 加载父类 + if (this.superKlass != null) { + obj.setSuperInstance(this.superKlass.newInstance()); + } + return obj; + } + + public JavaClass getJavaClass() { + return javaClass; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public String getClassName() { + return className; + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/KlassField.java b/src/main/java/haidnor/jvm/rtda/heap/KlassField.java new file mode 100644 index 0000000..cf971aa --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/KlassField.java @@ -0,0 +1,50 @@ +package haidnor.jvm.rtda.heap; + +import haidnor.jvm.runtime.StackValue; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.Field; + +/** + * 类元信息字段 + */ +public class KlassField { + + public final int accessFlags; + + public final String name; + + public final String descriptor; + + /** + * 值类型 + */ + private int type; + /** + * 值 + */ + private Object value; + + + public KlassField(Field field) { + this.accessFlags = field.getAccessFlags(); + this.name = field.getName(); + this.descriptor = field.getSignature(); + } + + public boolean isStatic() { + return (accessFlags & Const.ACC_STATIC) != 0; + } + + public void setVal(StackValue stackValue) { + this.type = stackValue.getType(); + this.value = stackValue.getValue(); + } + + public int getType() { + return type; + } + + public Object getValue() { + return value; + } +} diff --git a/src/main/java/haidnor/jvm/rtda/heap/KlassMethod.java b/src/main/java/haidnor/jvm/rtda/heap/KlassMethod.java new file mode 100644 index 0000000..be51c10 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/heap/KlassMethod.java @@ -0,0 +1,19 @@ +package haidnor.jvm.rtda.heap; + +import org.apache.bcel.classfile.Method; + +/** + * 类元信息方法 + */ +public class KlassMethod { + + public final Klass aKlass; + + public final Method javaMethod; + + public KlassMethod(Klass klass, Method javaMethod) { + this.aKlass = klass; + this.javaMethod = javaMethod; + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/metaspace/Metaspace.java b/src/main/java/haidnor/jvm/rtda/metaspace/Metaspace.java new file mode 100644 index 0000000..863977f --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/metaspace/Metaspace.java @@ -0,0 +1,32 @@ +package haidnor.jvm.rtda.metaspace; + +import haidnor.jvm.rtda.heap.Klass; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 元空间 + */ +public class Metaspace { + + private static final Map javaClassMapMap = new ConcurrentHashMap<>(); + + /** + * 名称用.符号分割 + * 例如: haidnor.jvm.test.instruction.references.NEW + */ + public static Klass getJavaClass(String className) { + return javaClassMapMap.get(className); + } + + /** + * 注册名称用.符号分割 + * 例如: haidnor.jvm.test.instruction.references.NEW + */ + public static void registerJavaClass(Klass javaKlass) { + String className = javaKlass.getClassName(); + javaClassMapMap.put(className, javaKlass); + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/package-info.java b/src/main/java/haidnor/jvm/rtda/package-info.java new file mode 100644 index 0000000..bb8b9ce --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/package-info.java @@ -0,0 +1,17 @@ +/* +JVM(Java虚拟机)的 RTDA(Run-time Data Area)是指在程序运行时分配给Java应用程序使用的内存区域,它包含了几个重要的组成部分。 + +1.程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它保存着当前线程所执行的字节码指令的地址或索引。每个线程都有自己独立的程序计数器,用于记录线程执行的位置,以便线程切换后能够恢复执行。 + +2.Java虚拟机栈(Java Virtual Machine Stacks):每个线程在创建时都会分配一个对应的Java虚拟机栈,用于存储局部变量、方法参数、动态链接信息和方法返回值等数据。每个方法在执行时会创建一个栈帧(Stack Frame),栈帧用于存储方法的局部变量和操作数栈等信息。 + +3.本地方法栈(Native Method Stack):本地方法栈与Java虚拟机栈类似,但是它为本地方法(即用其他语言编写的方法)服务。本地方法栈也会为本地方法的调用和执行提供内存空间。 + +4.Java堆(Java Heap):Java堆是Java虚拟机管理的最大的一块内存区域,用于存储对象实例和数组数据。几乎所有的对象都在Java堆上分配内存,垃圾收集器也主要针对Java堆进行垃圾回收。 + +5.方法区(Method Area):方法区是存储类的结构信息、常量池、字段和方法的字节码等数据的内存区域。它包括运行时常量池,用于存放编译期生成的各种字面量和符号引用。 + +RTDA是JVM在运行时为Java应用程序提供的数据区域,每个线程都有自己的私有数据区域(程序计数器、虚拟机栈和本地方法栈),而Java堆和方法区则是所有线程共享的。这些区域的组合提供了Java程序运行所需的内存空间。 + +*/ +package haidnor.jvm.rtda; \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/runtime/Frame.java b/src/main/java/haidnor/jvm/runtime/Frame.java new file mode 100644 index 0000000..91f5b4a --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/Frame.java @@ -0,0 +1,292 @@ +package haidnor.jvm.runtime; + +import haidnor.jvm.rtda.heap.Instance; +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.ConstantPoolUtil; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.LocalVariableTable; + +import java.util.Stack; + +/** + * JVM 线程栈帧 + */ +public class Frame { + /** + * 当前栈帧所处于的 JVM 线程 + */ + private final JvmThread jvmThread; + + /** + * 栈帧所属的方法 + *

+ * <<深入理解JAVA虚拟机>>: + * 每一个栈帧都包含一个指向运行时常量池中该栈帧所属的方法引用,持有这个引用的目的是为了支持方法调用过程中的动态链接(Dynamic Linking) + */ + private final org.apache.bcel.classfile.Method method; + + private final KlassMethod klassMethod; + + public final Klass aKlass; + + /** + * 栈帧所属的方法代码对象 + */ + private final Code code; + + private final CodeStream codeStream; + + private final ConstantPool constantPool; + + private final ConstantPoolUtil constantPoolUtil; + + /** + * 操作数栈 + */ + private final Stack operandStack = new Stack<>(); + + /** + * 局部变量表 + */ + private final LocalVariableTable localVariableTable; + + /** + * 槽位 + */ + private final Slot[] slots; + + public Frame(JvmThread jvmThread, KlassMethod klassMethod) { + this.jvmThread = jvmThread; + this.aKlass = klassMethod.aKlass; + this.klassMethod = klassMethod; + this.method = klassMethod.javaMethod; + this.code = method.getCode(); + this.constantPool = method.getConstantPool(); + this.constantPoolUtil = new ConstantPoolUtil(constantPool); + this.codeStream = new CodeStream(method.getCode()); + this.localVariableTable = code.getLocalVariableTable(); + this.slots = new Slot[code.getMaxLocals()]; + } + + public JvmThread getJvmThread() { + return jvmThread; + } + + public int getCodeLength() { + return this.code.getCode().length; + } + + public CodeStream getCodeStream() { + return codeStream; + } + + public org.apache.bcel.classfile.Method getMethod() { + return method; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ConstantPoolUtil getConstantPoolUtil() { + return constantPoolUtil; + } + + public KlassMethod getMetaMethod() { + return klassMethod; + } + + public Klass getMetaClass() { + return aKlass; + } + + /* 操作数栈操作 --------------------------------------------------------------------------------------------------- */ + + /** + * 压入操作数栈 + */ + 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.getType()) { + 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.getType()) { + case Const.T_CHAR: + throw new Error("T_CHAR,未作处理"); + case Const.T_INT: + slotSetInt(index, (int) stackValue.getValue()); + break; + case Const.T_OBJECT: + slotSetRef(index, stackValue.getValue()); + break; + case Const.T_LONG: + slotSetLong(index, (long) stackValue.getValue()); + break; + case Const.T_DOUBLE: + slotSetDouble(index, (double) stackValue.getValue()); + break; + case Const.T_FLOAT: + slotSetFloat(index, (float) stackValue.getValue()); + break; + case Const.T_ARRAY: + throw new Error("T_ARRAY,未作处理"); + default: + throw new Error("无法识别的参数类型"); + } + } + +} diff --git a/src/main/java/haidnor/jvm/runtime/JvmThread.java b/src/main/java/haidnor/jvm/runtime/JvmThread.java new file mode 100644 index 0000000..02ce178 --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/JvmThread.java @@ -0,0 +1,31 @@ +package haidnor.jvm.runtime; + +import java.util.Stack; + +/** + * JVM 线程 + */ +public class JvmThread extends Thread { + + /** + * JVM 线程栈 + */ + private final Stack stack = new Stack<>(); + + public void push(Frame frame) { + this.stack.push(frame); + } + + public Frame peek() { + return this.stack.peek(); + } + + public void pop() { + this.stack.pop(); + } + + public int stackSize() { + return this.stack.size(); + } + +} diff --git a/src/main/java/haidnor/jvm/runtime/Slot.java b/src/main/java/haidnor/jvm/runtime/Slot.java new file mode 100644 index 0000000..426e5bb --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/Slot.java @@ -0,0 +1,26 @@ +package haidnor.jvm.runtime; + + +public class Slot { + public Integer num; + public Object ref; + + public Slot(int num) { + this.num = num; + this.ref = null; + } + + public Slot(Object ref) { + this.num = null; + this.ref = ref; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Slot{"); + sb.append("num=").append(num); + sb.append(", ref=").append(ref); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/haidnor/jvm/runtime/StackValue.java b/src/main/java/haidnor/jvm/runtime/StackValue.java new file mode 100644 index 0000000..39a3bef --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/StackValue.java @@ -0,0 +1,24 @@ +package haidnor.jvm.runtime; + +import lombok.Data; + +/** + * 操作数栈中的值对象 + */ +@Data +public class StackValue { + /** + * 类型 + */ + private int type; + /** + * 值 + */ + private Object value; + + public StackValue(int type, Object val) { + this.type = type; + this.value = val; + } + +} diff --git a/src/main/java/haidnor/jvm/util/CodeStream.java b/src/main/java/haidnor/jvm/util/CodeStream.java new file mode 100644 index 0000000..0caf9a6 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/CodeStream.java @@ -0,0 +1,100 @@ +package haidnor.jvm.util; + +import haidnor.jvm.instruction.Instruction; +import lombok.SneakyThrows; +import org.apache.bcel.classfile.Code; + +import java.io.DataInputStream; + +public class CodeStream { + + /** + * 当前读取到的数组下标 + * -1 代表还没有开始读 + */ + private int index = -1; + + public Code code; + + private final DataInputStream codeStream; + + public CodeStream(Code code) { + this.code = code; + this.codeStream = IoUtil.getDataInputStream(code.getCode()); + } + + @SneakyThrows + public int available() { + return codeStream.available(); + } + + /** + * 读取占用一个字节指定代码 + */ + @SneakyThrows + public int readJavaVmOpcode() { + this.index += 1; + return this.codeStream.readUnsignedByte(); + } + + /** + * 读取占用一个字节的操作数 + */ + @SneakyThrows + public int readByte(Instruction instruction) { + instruction.setOffSet(instruction.offSet() + 1); + this.index += 1; + return this.codeStream.readByte(); + } + + /** + * 读取占用一个字节的操作数 + * int 类型 + */ + @SneakyThrows + public int readUnsignedByte(Instruction instruction) { + instruction.setOffSet(instruction.offSet() + 1); + this.index += 1; + return this.codeStream.readUnsignedByte(); + } + + /** + * 读取占用两个字节的操作数 + */ + @SneakyThrows + public int readShort(Instruction instruction) { + instruction.setOffSet(instruction.offSet() + 2); + this.index += 2; + return this.codeStream.readShort(); + } + + /** + * 读取占用两个字节的操作数 + * int 类型 + */ + @SneakyThrows + public int readUnsignedShort(Instruction instruction) { + instruction.setOffSet(instruction.offSet() + 2); + this.index += 2; + return this.codeStream.readUnsignedShort(); + } + + /** + * 读取占用四个字节的操作数 + */ + @SneakyThrows + public int readInt(Instruction instruction) { + instruction.setOffSet(instruction.offSet() + 4); + this.index += 4; + return this.codeStream.readInt(); + } + + public int index() { + return this.index; + } + + public Code getCode() { + return code; + } + +} diff --git a/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java b/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java new file mode 100644 index 0000000..a37f8d8 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java @@ -0,0 +1,119 @@ +package haidnor.jvm.util; + +import org.apache.bcel.classfile.*; + +/** + * ConstantPoolUtil + */ +public class ConstantPoolUtil { + + private final ConstantPool cp; + + public ConstantPoolUtil(ConstantPool cp) { + this.cp = cp; + } + + public ConstantFieldref getConstantFieldref(int constantFieldrefIndex) { + return cp.getConstant(constantFieldrefIndex); + } + + public ConstantMethodref getConstantMethodref(int constantMethodrefIndex) { + return cp.getConstant(constantMethodrefIndex); + } + + public ConstantClass getConstantClass(int constantClassIndex) { + return cp.getConstant(constantClassIndex); + } + + public ConstantNameAndType getConstantNameAndType(int constantNameAndTypeIndex) { + return cp.getConstant(constantNameAndTypeIndex); + } + + // ConstantClass --------------------------------------------------------------------------------------------------- + + /** + * 获取长类名, 例如 java/lang/String + */ + public String getClassName(final ConstantClass constantClass) { + ConstantUtf8 constantUtf8 = cp.getConstant(constantClass.getNameIndex()); + return constantUtf8.getBytes(); + } + + // ConstantFieldref ------------------------------------------------------------------------------------------------ + + /** + * 获取字段所处于Java类的类名, 例如 java/lang/String + */ + public String getFiledBelongClassName(final ConstantFieldref constantFieldref) { + ConstantClass constClass = cp.getConstant(constantFieldref.getClassIndex()); + return (String) constClass.getConstantValue(cp); + } + + /** + * 获取字段所处于Java类的类名, 例如 java/lang/String + */ + public String getFiledBelongClassName(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return getFiledBelongClassName(constantFieldref); + } + + /** + * 获取字段名称 + */ + public String getFieldName(final ConstantFieldref constantFieldref) { + ConstantNameAndType constNameAndType = cp.getConstant(constantFieldref.getNameAndTypeIndex()); + return constNameAndType.getName(cp); + } + + /** + * 获取字段名称 + */ + public String getFieldName(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return getFieldName(constantFieldref); + } + + /** + * 获取字段类型签名 + */ + public String getFieldSignature(final ConstantFieldref constantFieldref) { + ConstantNameAndType constNameAndType = cp.getConstant(constantFieldref.getNameAndTypeIndex()); + return constNameAndType.getSignature(cp); + } + + /** + * 获取字段类型签名 + */ + public String getFieldSignature(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return getFieldSignature(constantFieldref); + } + + // ConstantMethodref ----------------------------------------------------------------------------------------------- + + /** + * 获取方法所处于Java类的类名 + * 名称使用/分割,例如 haidnor/jvm/test/instruction/references/NEW + */ + public String getBelongClassName(final ConstantMethodref methodref) { + ConstantClass constClass = cp.getConstant(methodref.getClassIndex()); + return (String) constClass.getConstantValue(cp); + } + + /** + * 获取方法名 + */ + public String getMethodName(final ConstantMethodref methodref) { + ConstantNameAndType constNameAndType = cp.getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getName(cp); + } + + /** + * 获取方法签名 + */ + public String getMethodSignature(final ConstantMethodref methodref) { + ConstantNameAndType constNameAndType = cp.getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getSignature(cp); + } + +} diff --git a/src/main/java/haidnor/jvm/util/IoUtil.java b/src/main/java/haidnor/jvm/util/IoUtil.java new file mode 100644 index 0000000..05b8355 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/IoUtil.java @@ -0,0 +1,17 @@ +package haidnor.jvm.util; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +public abstract class IoUtil { + + public static DataInputStream getDataInputStream(byte[] bytes) { + ByteArrayInputStream inputStream = getByteArrayInputStream(bytes); + return new DataInputStream(inputStream); + } + + public static ByteArrayInputStream getByteArrayInputStream(byte[] bytes) { + return new ByteArrayInputStream(bytes); + } + +} diff --git a/src/main/java/haidnor/jvm/util/JavaClassUtil.java b/src/main/java/haidnor/jvm/util/JavaClassUtil.java new file mode 100644 index 0000000..501e4a5 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/JavaClassUtil.java @@ -0,0 +1,22 @@ +package haidnor.jvm.util; + +import haidnor.jvm.rtda.heap.Klass; +import haidnor.jvm.rtda.heap.KlassMethod; +import org.apache.bcel.classfile.JavaClass; + +public abstract class JavaClassUtil { + + /** + * 获取 main 方法 + */ + public static KlassMethod getMainMethod(Klass aKlass) { + JavaClass javaClass = aKlass.getJavaClass(); + for (org.apache.bcel.classfile.Method method : javaClass.getMethods()) { + if (method.toString().startsWith("public static void main(String[] args)")) { + return new KlassMethod(aKlass, method); + } + } + return null; + } + +} diff --git a/src/main/java/haidnor/jvm/util/JvmThreadHolder.java b/src/main/java/haidnor/jvm/util/JvmThreadHolder.java new file mode 100644 index 0000000..21cc38f --- /dev/null +++ b/src/main/java/haidnor/jvm/util/JvmThreadHolder.java @@ -0,0 +1,17 @@ +package haidnor.jvm.util; + +import haidnor.jvm.runtime.JvmThread; + +public abstract class JvmThreadHolder { + + private static final ThreadLocal holder = new ThreadLocal<>(); + + public static void set(JvmThread thread) { + holder.set(thread); + } + + public static JvmThread get() { + return holder.get(); + } + +} diff --git a/src/main/java/haidnor/jvm/util/SignatureUtil.java b/src/main/java/haidnor/jvm/util/SignatureUtil.java new file mode 100644 index 0000000..66b58ec --- /dev/null +++ b/src/main/java/haidnor/jvm/util/SignatureUtil.java @@ -0,0 +1,51 @@ +package haidnor.jvm.util; + +import lombok.SneakyThrows; +import org.apache.bcel.classfile.Utility; + +public abstract class SignatureUtil { + + /** + * 解析方法签名返回方法参数类型数组 + */ + @SneakyThrows + public static Class[] getParameterTypes(String methodeSignature) { + String[] argumentTypeArr = Utility.methodSignatureArgumentTypes(methodeSignature, false); + Class[] argumentClassArr = new Class[argumentTypeArr.length]; + for (int i = 0; i < argumentTypeArr.length; i++) { + Class argumentClass; + String argumentType = argumentTypeArr[i]; + switch (argumentType) { + case "byte": + argumentClass = byte.class; + break; + case "short": + argumentClass = short.class; + break; + case "boolean": + argumentClass = boolean.class; + break; + case "char": + argumentClass = char.class; + break; + case "int": + argumentClass = int.class; + break; + case "long": + argumentClass = long.class; + break; + case "float": + argumentClass = float.class; + break; + case "double": + argumentClass = double.class; + break; + default: + argumentClass = Class.forName(argumentType); + } + argumentClassArr[i] = argumentClass; + } + return argumentClassArr; + } + +} diff --git a/src/main/resources/haidnorJVM.properties b/src/main/resources/haidnorJVM.properties new file mode 100644 index 0000000..62cd3fc --- /dev/null +++ b/src/main/resources/haidnorJVM.properties @@ -0,0 +1 @@ +rt.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar \ No newline at end of file diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 0000000..eafa2b0 --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1 @@ +org.slf4j.simpleLogger.defaultLogLevel=debug \ No newline at end of file diff --git a/src/test/java/haidnor/jvm/test/TestJVM.java b/src/test/java/haidnor/jvm/test/TestJVM.java new file mode 100644 index 0000000..6e11e46 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/TestJVM.java @@ -0,0 +1,84 @@ +package haidnor.jvm.test; + +import haidnor.jvm.classloader.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 haidnor.jvm.runtime.JvmThread; +import haidnor.jvm.test.demo.Demo1; +import haidnor.jvm.test.demo.Demo2; +import haidnor.jvm.test.demo.Demo3; +import haidnor.jvm.test.instruction.Array; +import haidnor.jvm.test.instruction.DO_WHILE; +import haidnor.jvm.test.instruction.math.ISUB; +import haidnor.jvm.test.instruction.math.LSUB; +import haidnor.jvm.test.instruction.references.INVOKEINTERFACE; +import haidnor.jvm.test.instruction.references.NEW; +import haidnor.jvm.util.JavaClassUtil; +import haidnor.jvm.util.JvmThreadHolder; +import lombok.SneakyThrows; +import org.junit.Test; + +public class TestJVM { + + @SneakyThrows + public static void runMainClass(java.lang.Class mainClass) { + ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader"); + Klass mainMeteKlass = bootClassLoader.loadClass(mainClass.getName().replace('.', '/')); + KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass); + Metaspace.registerJavaClass(mainMeteKlass); + JvmThreadHolder.set(new JvmThread()); + + JavaExecutionEngine.callMainStaticMethod(mainKlassMethod); + } + + /** + * hello,world + */ + @Test + public void test_1() throws Exception { + runMainClass(Demo1.class); + } + + @Test + public void test_2() throws Exception { + runMainClass(Demo2.class); + } + + @Test + public void test_3() throws Exception { + runMainClass(Demo3.class); + } + + @Test + public void test_NEW() throws Exception { + runMainClass(NEW.class); + } + + @Test + public void test_ISUB() throws Exception { + runMainClass(ISUB.class); + } + + @Test + public void test_LSUB() throws Exception { + runMainClass(LSUB.class); + } + + + @Test + public void test_DOWHILE() throws Exception { + runMainClass(DO_WHILE.class); + } + + @Test + public void test_Array() throws Exception { + runMainClass(Array.class); + } + + @Test + public void test_INVOKEINTERFACE() throws Exception { + runMainClass(INVOKEINTERFACE.class); + } +} diff --git a/src/test/java/haidnor/jvm/test/clazz/Baby.java b/src/test/java/haidnor/jvm/test/clazz/Baby.java new file mode 100644 index 0000000..7deb2ab --- /dev/null +++ b/src/test/java/haidnor/jvm/test/clazz/Baby.java @@ -0,0 +1,7 @@ +package haidnor.jvm.test.clazz; + +public class Baby { + public void eat() { + System.out.println("婴儿吃奶粉"); + } +} diff --git a/src/test/java/haidnor/jvm/test/clazz/Func.java b/src/test/java/haidnor/jvm/test/clazz/Func.java new file mode 100644 index 0000000..96212c9 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/clazz/Func.java @@ -0,0 +1,7 @@ +package haidnor.jvm.test.clazz; + +@FunctionalInterface +public interface Func { + + boolean func(String str); +} diff --git a/src/test/java/haidnor/jvm/test/clazz/Person.java b/src/test/java/haidnor/jvm/test/clazz/Person.java new file mode 100644 index 0000000..195865f --- /dev/null +++ b/src/test/java/haidnor/jvm/test/clazz/Person.java @@ -0,0 +1,7 @@ +package haidnor.jvm.test.clazz; + +public interface Person { + + void eat(); + +} diff --git a/src/test/java/haidnor/jvm/test/clazz/Student.java b/src/test/java/haidnor/jvm/test/clazz/Student.java new file mode 100644 index 0000000..96f9f83 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/clazz/Student.java @@ -0,0 +1,10 @@ +package haidnor.jvm.test.clazz; + +public class Student implements Person { + + @Override + public void eat() { + System.out.println("学生只能在学校食堂吃饭"); + } + +} diff --git a/src/test/java/haidnor/jvm/test/demo/Demo1.java b/src/test/java/haidnor/jvm/test/demo/Demo1.java new file mode 100644 index 0000000..8abfedb --- /dev/null +++ b/src/test/java/haidnor/jvm/test/demo/Demo1.java @@ -0,0 +1,7 @@ +package haidnor.jvm.test.demo; + +public class Demo1 { + public static void main(String[] args) { + System.out.println("hello,world"); + } +} diff --git a/src/test/java/haidnor/jvm/test/demo/Demo2.java b/src/test/java/haidnor/jvm/test/demo/Demo2.java new file mode 100644 index 0000000..77ae088 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/demo/Demo2.java @@ -0,0 +1,12 @@ +package haidnor.jvm.test.demo; + +public class Demo2 { + + public static void main(String[] args) { + long longVal = 1L; + float floatVal = 1f; + double doubleVal = 1D; + int intVal = 1; + } + +} diff --git a/src/test/java/haidnor/jvm/test/demo/Demo3.java b/src/test/java/haidnor/jvm/test/demo/Demo3.java new file mode 100644 index 0000000..0df013c --- /dev/null +++ b/src/test/java/haidnor/jvm/test/demo/Demo3.java @@ -0,0 +1,46 @@ +package haidnor.jvm.test.demo; + +import java.util.HashMap; + +public class Demo3 { + + public static void main(String[] args) { + Student sut1 = new Student(1); + Student sut2 = new Student(2); + + if (sut1 == sut2) { + + } + + HashMap hashMap = new HashMap<>(); + hashMap.put(sut1, "张三"); + hashMap.put(sut2, "张三"); + + System.out.println(hashMap.get(sut1)); // 1 + System.out.println(hashMap.get(sut2)); // 2 + } + +} + +class Student { + + public int age; + + public Student(int age) { + this.age = age; + } + +// @Override +// public boolean equals(Object o) { +// Student student = (Student) o; +// System.out.println("调用了 equals 方法, 将 age=" + age + " 与 age=" + student.age + " 的对象进行比较"); +// return age == student.age; +// } + + @Override + public int hashCode() { + System.out.println("调用了 hashCode 方法"); + return 123; // 这个 hashCode() 算法很糟糕, 100% hash冲突 + } + +} diff --git a/src/test/java/haidnor/jvm/test/demo/Demo4.java b/src/test/java/haidnor/jvm/test/demo/Demo4.java new file mode 100644 index 0000000..0bb3e44 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/demo/Demo4.java @@ -0,0 +1,10 @@ +package haidnor.jvm.test.demo; + +public class Demo4 { + + public static String str = "ABC"; + + public static void main(String[] args) { +// System.out.println(Demo3.str == Demo4.str); // true + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/Array.java b/src/test/java/haidnor/jvm/test/instruction/Array.java new file mode 100644 index 0000000..efece48 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/Array.java @@ -0,0 +1,10 @@ +package haidnor.jvm.test.instruction; + +import haidnor.jvm.test.instruction.loads.Student1; + +public class Array { + public static void main(String[] args) { + Student1[] strArr = new Student1[10]; + strArr[5] = new Student1(); + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/ClassA.java b/src/test/java/haidnor/jvm/test/instruction/ClassA.java new file mode 100644 index 0000000..17dcc7c --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/ClassA.java @@ -0,0 +1,12 @@ +package haidnor.jvm.test.instruction; + +public class ClassA { + public static class ClassB { + + public int a; + + public ClassB(int a) { + this.a = a; + } + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/DO_WHILE.java b/src/test/java/haidnor/jvm/test/instruction/DO_WHILE.java new file mode 100644 index 0000000..3427855 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/DO_WHILE.java @@ -0,0 +1,11 @@ +package haidnor.jvm.test.instruction; + +public class DO_WHILE { + public static void main(String[] args) { + int a = 3; + do { + System.out.println(a); + a--; + } while (a != 0); + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/InnerClass.java b/src/test/java/haidnor/jvm/test/instruction/InnerClass.java new file mode 100644 index 0000000..c407f98 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/InnerClass.java @@ -0,0 +1,9 @@ +package haidnor.jvm.test.instruction; + +public class InnerClass { + public static void main(String[] args) { + ClassA.ClassB classB = new ClassA.ClassB(999); + + System.out.println(classB.a); + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/extended/GOTO.java b/src/test/java/haidnor/jvm/test/instruction/extended/GOTO.java new file mode 100644 index 0000000..36309df --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/extended/GOTO.java @@ -0,0 +1,13 @@ +package haidnor.jvm.test.instruction.extended; + +public class GOTO { + + public static void main(String[] args) { + int a = 1; + while (a < 10) { + System.out.println(a); + a++; + } + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/loads/Person.java b/src/test/java/haidnor/jvm/test/instruction/loads/Person.java new file mode 100644 index 0000000..012d01b --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/loads/Person.java @@ -0,0 +1,4 @@ +package haidnor.jvm.test.instruction.loads; + +public abstract class Person { +} diff --git a/src/test/java/haidnor/jvm/test/instruction/loads/Student.java b/src/test/java/haidnor/jvm/test/instruction/loads/Student.java new file mode 100644 index 0000000..2ae059c --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/loads/Student.java @@ -0,0 +1,31 @@ +package haidnor.jvm.test.instruction.loads; + +public class Student { + + public byte byteVal; + + public short shortVal; + + public float floatVal; + + public double doubleVal; + + public int intVal; + + public long longVal; + + public char charVal; + + public boolean booleanVal; + + public Student(byte byteVal, short shortVal, float floatVal, double doubleVal, int intVal, long longVal, char charVal, boolean booleanVal) { + this.byteVal = byteVal; + this.shortVal = shortVal; + this.floatVal = floatVal; + this.doubleVal = doubleVal; + this.intVal = intVal; + this.longVal = longVal; + this.charVal = charVal; + this.booleanVal = booleanVal; + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/loads/Student1.java b/src/test/java/haidnor/jvm/test/instruction/loads/Student1.java new file mode 100644 index 0000000..3a552a8 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/loads/Student1.java @@ -0,0 +1,13 @@ +package haidnor.jvm.test.instruction.loads; + +public class Student1 { + + public int a() { + return b(); + } + + public int b() { + return 233; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/DADD.java b/src/test/java/haidnor/jvm/test/instruction/math/DADD.java new file mode 100644 index 0000000..34b8e7b --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/DADD.java @@ -0,0 +1,15 @@ +package haidnor.jvm.test.instruction.math; + +public class DADD { + + public static void main(String[] args) { + double c = add(1D, 2D); + System.out.println(c); + } + + public static double add(double a, double b) { + double c = a + b; + return c; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/FADD.java b/src/test/java/haidnor/jvm/test/instruction/math/FADD.java new file mode 100644 index 0000000..94bf9fa --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/FADD.java @@ -0,0 +1,15 @@ +package haidnor.jvm.test.instruction.math; + +public class FADD { + + public static void main(String[] args) { + float c = add(1, 2); + System.out.println(c); + } + + public static float add(float a, float b) { + float c = a + b; + return c; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/IADD.java b/src/test/java/haidnor/jvm/test/instruction/math/IADD.java new file mode 100644 index 0000000..e033ba7 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/IADD.java @@ -0,0 +1,15 @@ +package haidnor.jvm.test.instruction.math; + +public class IADD { + + public static void main(String[] args) { + int c = add(1, 2); + System.out.println(c); + } + + public static int add(int a, int b) { + int c = a + b; + return c; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/IINC.java b/src/test/java/haidnor/jvm/test/instruction/math/IINC.java new file mode 100644 index 0000000..4396311 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/IINC.java @@ -0,0 +1,23 @@ +package haidnor.jvm.test.instruction.math; + +public class IINC { + + public static void main(String[] args) { + int a = -127; + a++; + System.out.println(a); + + int b = 129; + b++; + System.out.println(b); + + int c = 321; + c++; + System.out.println(c); + + int d = 0; + d++; + System.out.println(d); + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/ISUB.java b/src/test/java/haidnor/jvm/test/instruction/math/ISUB.java new file mode 100644 index 0000000..ebdc7a0 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/ISUB.java @@ -0,0 +1,10 @@ +package haidnor.jvm.test.instruction.math; + +public class ISUB { + public static void main(String[] args) { + int a = 2; + int b = 1; + int c = a - b; + System.out.println(c); + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/LADD.java b/src/test/java/haidnor/jvm/test/instruction/math/LADD.java new file mode 100644 index 0000000..dd3abb2 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/LADD.java @@ -0,0 +1,15 @@ +package haidnor.jvm.test.instruction.math; + +public class LADD { + + public static void main(String[] args) { + long c = add(1, 2); + System.out.println(c); + } + + public static long add(long a, long b) { + long c = a + b; + return c; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/math/LSUB.java b/src/test/java/haidnor/jvm/test/instruction/math/LSUB.java new file mode 100644 index 0000000..dd65c37 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/math/LSUB.java @@ -0,0 +1,10 @@ +package haidnor.jvm.test.instruction.math; + +public class LSUB { + public static void main(String[] args) { + long a = 2000L; + long b = 1000L; + long c = a - b; + System.out.println(c); + } +} diff --git a/src/test/java/haidnor/jvm/test/instruction/references/CallStaticMethod.java b/src/test/java/haidnor/jvm/test/instruction/references/CallStaticMethod.java new file mode 100644 index 0000000..f32ff38 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/references/CallStaticMethod.java @@ -0,0 +1,14 @@ +package haidnor.jvm.test.instruction.references; + +public class CallStaticMethod { + + public static void main(String[] args) { + float i = staticMethod(); + System.out.println(i); + } + + public static float staticMethod() { + return 1321.321f; + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/references/INVOKEINTERFACE.java b/src/test/java/haidnor/jvm/test/instruction/references/INVOKEINTERFACE.java new file mode 100644 index 0000000..69bff69 --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/references/INVOKEINTERFACE.java @@ -0,0 +1,14 @@ +package haidnor.jvm.test.instruction.references; + +import java.util.HashSet; + +public class INVOKEINTERFACE { + + public static void main(String[] args) { + HashSet set = new HashSet<>(); + set.add(1); + int size = set.size(); + System.out.println(size); + } + +} diff --git a/src/test/java/haidnor/jvm/test/instruction/references/NEW.java b/src/test/java/haidnor/jvm/test/instruction/references/NEW.java new file mode 100644 index 0000000..746a5fb --- /dev/null +++ b/src/test/java/haidnor/jvm/test/instruction/references/NEW.java @@ -0,0 +1,21 @@ +package haidnor.jvm.test.instruction.references; + +import java.io.IOException; + +public class NEW { + + public static void main(String[] args) throws IOException { + add(1, 2, 3, 4, 5, 6, 7); + } + + public static void add(int a, int b, int c, int d, int e, int f, int g) { + System.out.println(a); + System.out.println(b); + System.out.println(c); + System.out.println(d); + System.out.println(e); + System.out.println(f); + System.out.println(g); + } + +} diff --git a/src/test/resources/haidnorJVM.properties b/src/test/resources/haidnorJVM.properties new file mode 100644 index 0000000..62cd3fc --- /dev/null +++ b/src/test/resources/haidnorJVM.properties @@ -0,0 +1 @@ +rt.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar \ No newline at end of file diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties new file mode 100644 index 0000000..eafa2b0 --- /dev/null +++ b/src/test/resources/simplelogger.properties @@ -0,0 +1 @@ +org.slf4j.simpleLogger.defaultLogLevel=debug \ No newline at end of file