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

View File

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

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) {
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("无法识别的参数类型");
}
}

View File

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