From f8504c32556497704bf345db88b058774b5b4e39 Mon Sep 17 00:00:00 2001 From: wangxiang <276644985haidnor@gmail.com> Date: Sun, 30 Jul 2023 00:41:59 +0800 Subject: [PATCH] update JavaExecutionEngine.java --- src/main/java/haidnor/jvm/Main.java | 37 ++++++++-------- .../haidnor/jvm/core/JavaExecutionEngine.java | 44 ++++++++++++++----- src/main/java/haidnor/jvm/rtda/Klass.java | 2 +- src/main/java/haidnor/jvm/runtime/Frame.java | 29 ++++-------- .../java/haidnor/jvm/util/SignatureUtil.java | 39 +++++----------- 5 files changed, 71 insertions(+), 80 deletions(-) diff --git a/src/main/java/haidnor/jvm/Main.java b/src/main/java/haidnor/jvm/Main.java index 36fbc44..0670f68 100644 --- a/src/main/java/haidnor/jvm/Main.java +++ b/src/main/java/haidnor/jvm/Main.java @@ -1,11 +1,6 @@ package haidnor.jvm; -import org.apache.commons.cli.CommandLine; -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 org.apache.commons.cli.*; import haidnor.jvm.classloader.ClassLoader; import haidnor.jvm.core.JavaExecutionEngine; @@ -28,21 +23,11 @@ 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); + CommandLine cmd = initCommandLine(args); + // 指定从 .jar 文件运行 if (cmd.hasOption("jar")) { String jarFilePath = cmd.getOptionValue("jar"); - try (JarFile jarFile = new JarFile(jarFilePath)) { ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader"); String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); @@ -64,6 +49,8 @@ public class Main { } } } + + // 指定从 .class 文件运行 if (cmd.hasOption("class")) { JvmThreadHolder.set(new JVMThread()); 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); + } + } \ 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 index 81abe97..904c6ec 100644 --- a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java +++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java @@ -63,18 +63,16 @@ public class JavaExecutionEngine { executeFrame(newFrame); } + /** + * 执行 JVM 线程栈栈帧 (haidnorJVM 中最关键的代码) + * + * @author wang xiang + */ @SneakyThrows public static void executeFrame(Frame frame) { int stackSize = frame.getJvmThread().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; - } - + String blank = getDebugStackInfoBlank(stackSize); log.debug("{}┌──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod()); // 解析方法中的字节码指令 @@ -93,21 +91,25 @@ public class JavaExecutionEngine { Instruction instruction = instructionMap.get(pc); log.debug("{}│ {}", blank, instruction); try { + // 执行栈帧 instruction.execute(frame); if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) { break; } + // 程序计数器值增加. 指向下一次执行的字节码行号 pc += instruction.offSet(); } - // catch instruction.execute() Exception + // 捕获执行栈帧运行抛出的异常 catch (Exception exception) { - Integer handlerPC = null; - + // 从类元信息中获取异常表 CodeException[] exceptionTable = frame.getMethod().getCode().getExceptionTable(); + + // handlerPC 是从异常表中获取的处理异常的字节码行号 (如果查询不到就会一直为 null. 代表方法无异常处理代码) + Integer handlerPC = null; for (CodeException codeException : exceptionTable) { if (codeException.getStartPC() <= pc & pc <= codeException.getEndPC()) { 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) { frame.push(new StackValue(Const.T_OBJECT, exception)); handlerPC = codeException.getHandlerPC(); @@ -123,8 +125,10 @@ public class JavaExecutionEngine { } } if (handlerPC != null) { + // 将程序计数器跳转到处理异常的字节码指令上 pc = handlerPC; } else { + // 方法无异常处理. 异常退出.结束栈帧 log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize); throw exception; } @@ -135,5 +139,21 @@ public class JavaExecutionEngine { 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(); + } } diff --git a/src/main/java/haidnor/jvm/rtda/Klass.java b/src/main/java/haidnor/jvm/rtda/Klass.java index ef9d8ec..1209a88 100644 --- a/src/main/java/haidnor/jvm/rtda/Klass.java +++ b/src/main/java/haidnor/jvm/rtda/Klass.java @@ -41,7 +41,7 @@ public class Klass { /** * 静态字段 */ - private Map staticFieldMap = new HashMap<>(); + private final Map staticFieldMap = new HashMap<>(); /** * 加载类元数据并将类放入元空间 diff --git a/src/main/java/haidnor/jvm/runtime/Frame.java b/src/main/java/haidnor/jvm/runtime/Frame.java index 5d3019e..5336673 100644 --- a/src/main/java/haidnor/jvm/runtime/Frame.java +++ b/src/main/java/haidnor/jvm/runtime/Frame.java @@ -264,27 +264,14 @@ public class Frame { 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("无法识别的参数类型"); + case Const.T_CHAR -> throw new Error("T_CHAR,未作处理"); + case Const.T_INT -> slotSetInt(index, (int) stackValue.getValue()); + case Const.T_OBJECT -> slotSetRef(index, stackValue.getValue()); + case Const.T_LONG -> slotSetLong(index, (long) stackValue.getValue()); + case Const.T_DOUBLE -> slotSetDouble(index, (double) stackValue.getValue()); + case Const.T_FLOAT -> slotSetFloat(index, (float) stackValue.getValue()); + case Const.T_ARRAY -> throw new Error("T_ARRAY,未作处理"); + default -> throw new Error("无法识别的参数类型"); } } diff --git a/src/main/java/haidnor/jvm/util/SignatureUtil.java b/src/main/java/haidnor/jvm/util/SignatureUtil.java index 05117f0..9f647bd 100644 --- a/src/main/java/haidnor/jvm/util/SignatureUtil.java +++ b/src/main/java/haidnor/jvm/util/SignatureUtil.java @@ -18,34 +18,17 @@ public abstract class SignatureUtil { 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); - } + argumentClass = switch (argumentType) { + case "byte" -> byte.class; + case "short" -> short.class; + case "boolean" -> boolean.class; + case "char" -> char.class; + case "int" -> int.class; + case "long" -> long.class; + case "float" -> float.class; + case "double" -> double.class; + default -> Class.forName(argumentType); + }; argumentClassArr[i] = argumentClass; } return argumentClassArr;