update JavaExecutionEngine.java

This commit is contained in:
wangxiang
2023-07-30 00:41:59 +08:00
parent f0f6cceb7a
commit f8504c3255
5 changed files with 71 additions and 80 deletions

View File

@@ -1,11 +1,6 @@
package haidnor.jvm; package haidnor.jvm;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.*;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import haidnor.jvm.classloader.ClassLoader; import haidnor.jvm.classloader.ClassLoader;
import haidnor.jvm.core.JavaExecutionEngine; import haidnor.jvm.core.JavaExecutionEngine;
@@ -28,21 +23,11 @@ public class Main {
@SneakyThrows @SneakyThrows
public static void main(String[] args) { public static void main(String[] args) {
Option jarOption = new Option("jar", true, "运行 jar 程序"); CommandLine cmd = initCommandLine(args);
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);
// 指定从 .jar 文件运行
if (cmd.hasOption("jar")) { if (cmd.hasOption("jar")) {
String jarFilePath = cmd.getOptionValue("jar"); String jarFilePath = cmd.getOptionValue("jar");
try (JarFile jarFile = new JarFile(jarFilePath)) { try (JarFile jarFile = new JarFile(jarFilePath)) {
ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader"); ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader");
String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class");
@@ -64,6 +49,8 @@ public class Main {
} }
} }
} }
// 指定从 .class 文件运行
if (cmd.hasOption("class")) { if (cmd.hasOption("class")) {
JvmThreadHolder.set(new JVMThread()); JvmThreadHolder.set(new JVMThread());
String path = cmd.getOptionValue("class"); String path = cmd.getOptionValue("class");
@@ -76,4 +63,18 @@ public class Main {
} }
} }
private static CommandLine initCommandLine(String[] args) throws ParseException {
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();
return parser.parse(options, args);
}
} }

View File

@@ -63,18 +63,16 @@ public class JavaExecutionEngine {
executeFrame(newFrame); executeFrame(newFrame);
} }
/**
* 执行 JVM 线程栈栈帧 (haidnorJVM 中最关键的代码)
*
* @author wang xiang
*/
@SneakyThrows @SneakyThrows
public static void executeFrame(Frame frame) { public static void executeFrame(Frame frame) {
int stackSize = frame.getJvmThread().stackSize(); int stackSize = frame.getJvmThread().stackSize();
StringBuilder blank = new StringBuilder(); String blank = getDebugStackInfoBlank(stackSize);
blank.append(" ".repeat(stackSize - 1));
int index = 0;
for (int i = 0; i < stackSize - 1; i++) {
blank.replace(index, index + 1, "");
index += 20;
}
log.debug("{}┌──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod()); log.debug("{}┌──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod());
// 解析方法中的字节码指令 // 解析方法中的字节码指令
@@ -93,21 +91,25 @@ public class JavaExecutionEngine {
Instruction instruction = instructionMap.get(pc); Instruction instruction = instructionMap.get(pc);
log.debug("{}│ {}", blank, instruction); log.debug("{}│ {}", blank, instruction);
try { try {
// 执行栈帧
instruction.execute(frame); instruction.execute(frame);
if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) { if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) {
break; break;
} }
// 程序计数器值增加. 指向下一次执行的字节码行号
pc += instruction.offSet(); pc += instruction.offSet();
} }
// catch instruction.execute() Exception // 捕获执行栈帧运行抛出的异常
catch (Exception exception) { catch (Exception exception) {
Integer handlerPC = null; // 从类元信息中获取异常表
CodeException[] exceptionTable = frame.getMethod().getCode().getExceptionTable(); CodeException[] exceptionTable = frame.getMethod().getCode().getExceptionTable();
// handlerPC 是从异常表中获取的处理异常的字节码行号 (如果查询不到就会一直为 null. 代表方法无异常处理代码)
Integer handlerPC = null;
for (CodeException codeException : exceptionTable) { for (CodeException codeException : exceptionTable) {
if (codeException.getStartPC() <= pc & pc <= codeException.getEndPC()) { if (codeException.getStartPC() <= pc & pc <= codeException.getEndPC()) {
int catchType = codeException.getCatchType(); int catchType = codeException.getCatchType();
// 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught. // catchType == 0 代表捕获所有类型的异常
if (catchType == 0) { if (catchType == 0) {
frame.push(new StackValue(Const.T_OBJECT, exception)); frame.push(new StackValue(Const.T_OBJECT, exception));
handlerPC = codeException.getHandlerPC(); handlerPC = codeException.getHandlerPC();
@@ -123,8 +125,10 @@ public class JavaExecutionEngine {
} }
} }
if (handlerPC != null) { if (handlerPC != null) {
// 将程序计数器跳转到处理异常的字节码指令上
pc = handlerPC; pc = handlerPC;
} else { } else {
// 方法无异常处理. 异常退出.结束栈帧
log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize); log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize);
throw exception; throw exception;
} }
@@ -135,5 +139,21 @@ public class JavaExecutionEngine {
log.debug("{}└──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod()); log.debug("{}└──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod());
} }
/**
* 计算绘画 jvm 线程栈 debug 日志信息的空格
* 用于表现栈的调用关系.
*
* @param stackSize 当前 JVM 栈的深度
*/
private static String getDebugStackInfoBlank(int stackSize) {
StringBuilder blank = new StringBuilder();
blank.append(" ".repeat(stackSize - 1));
int index = 0;
for (int i = 0; i < stackSize - 1; i++) {
blank.replace(index, index + 1, "");
index += 20;
}
return blank.toString();
}
} }

View File

@@ -41,7 +41,7 @@ public class Klass {
/** /**
* 静态字段 * 静态字段
*/ */
private Map<String, KlassField> staticFieldMap = new HashMap<>(); private final Map<String, KlassField> staticFieldMap = new HashMap<>();
/** /**
* 加载类元数据并将类放入元空间 * 加载类元数据并将类放入元空间

View File

@@ -264,27 +264,14 @@ public class Frame {
public void slotSet(int index, StackValue stackValue) { public void slotSet(int index, StackValue stackValue) {
switch (stackValue.getType()) { switch (stackValue.getType()) {
case Const.T_CHAR: case Const.T_CHAR -> throw new Error("T_CHAR未作处理");
throw new Error("T_CHAR未作处理"); case Const.T_INT -> slotSetInt(index, (int) stackValue.getValue());
case Const.T_INT: case Const.T_OBJECT -> slotSetRef(index, stackValue.getValue());
slotSetInt(index, (int) stackValue.getValue()); case Const.T_LONG -> slotSetLong(index, (long) stackValue.getValue());
break; case Const.T_DOUBLE -> slotSetDouble(index, (double) stackValue.getValue());
case Const.T_OBJECT: case Const.T_FLOAT -> slotSetFloat(index, (float) stackValue.getValue());
slotSetRef(index, stackValue.getValue()); case Const.T_ARRAY -> throw new Error("T_ARRAY未作处理");
break; default -> throw new Error("无法识别的参数类型");
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("无法识别的参数类型");
} }
} }

View File

@@ -18,34 +18,17 @@ public abstract class SignatureUtil {
for (int i = 0; i < argumentTypeArr.length; i++) { for (int i = 0; i < argumentTypeArr.length; i++) {
Class<?> argumentClass; Class<?> argumentClass;
String argumentType = argumentTypeArr[i]; String argumentType = argumentTypeArr[i];
switch (argumentType) { argumentClass = switch (argumentType) {
case "byte": case "byte" -> byte.class;
argumentClass = byte.class; case "short" -> short.class;
break; case "boolean" -> boolean.class;
case "short": case "char" -> char.class;
argumentClass = short.class; case "int" -> int.class;
break; case "long" -> long.class;
case "boolean": case "float" -> float.class;
argumentClass = boolean.class; case "double" -> double.class;
break; default -> Class.forName(argumentType);
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; argumentClassArr[i] = argumentClass;
} }
return argumentClassArr; return argumentClassArr;