mirror of
https://github.com/FranzHaidnor/haidnorJVM.git
synced 2026-03-14 06:03:50 +08:00
update JavaExecutionEngine.java
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class Klass {
|
||||
/**
|
||||
* 静态字段
|
||||
*/
|
||||
private Map<String, KlassField> staticFieldMap = new HashMap<>();
|
||||
private final Map<String, KlassField> staticFieldMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 加载类元数据并将类放入元空间
|
||||
|
||||
@@ -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("无法识别的参数类型");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user