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;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
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("无法识别的参数类型");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user