Initial commit

This commit is contained in:
wangxiang
2023-07-19 18:06:38 +08:00
commit ff0fcd92bd
249 changed files with 7676 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@@ -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

64
README.md Normal file
View File

@@ -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")

86
pom.xml Normal file
View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>haindor.vm</groupId>
<artifactId>haidnorJVM</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.bcel/bcel -->
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>6.7.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>haidnor.jvm.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,5 @@
package haidnor.jvm.classloader;
public class BootstrapClassLoader {
}

View File

@@ -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;
}
}

View File

@@ -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<Integer, Instruction> 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());
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.if_icmp_cond"> Opcode
* definitions in The Java Virtual Machine Specification</a>
*/
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;
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.bipush"> Opcode definitions in
* The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.dconst_d"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.dconst_d"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.fconst_f"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.fconst_f"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.lconst_l"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.lconst_l"> Opcode definitions
* in The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ldc"> Opcode definitions in The
* Java Virtual Machine Specification</a>
*/
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());
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ldc_w"> Opcode definitions in
* The Java Virtual Machine Specification</a>
*/
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());
}
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.nop"> Opcode definitions in The
* Java Virtual Machine Specification</a>
*/
public class NOP extends Instruction {
public NOP(CodeStream codeStream) {
super(codeStream);
}
@Override
public void execute(Frame frame) {
}
}

View File

@@ -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 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.sipush"> Opcode definitions in
* The Java Virtual Machine Specification</a>
*/
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));
}
}

View File

@@ -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);
}
}

Some files were not shown because too many files have changed in this diff Show More