diff --git a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java index 246934e..fb3a649 100644 --- a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java +++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java @@ -12,10 +12,8 @@ import haidnor.jvm.util.CodeStream; import haidnor.jvm.util.JvmThreadHolder; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.bcel.classfile.LocalVariable; -import org.apache.bcel.classfile.LocalVariableTable; -import org.apache.bcel.classfile.Method; -import org.apache.bcel.classfile.Utility; +import org.apache.bcel.Const; +import org.apache.bcel.classfile.*; import java.util.HashMap; import java.util.Map; @@ -94,11 +92,42 @@ public class JavaExecutionEngine { for (int i = 0; i < frame.getCodeLength(); ) { Instruction instruction = instructionMap.get(i); log.debug("{}│ {}", blank, instruction); - instruction.execute(frame); - if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) { - break; + try { + instruction.execute(frame); + if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) { + break; + } + i += instruction.offSet(); + } catch (Exception exception) { + Integer handlerPC = null; + + CodeException[] exceptionTable = frame.getMethod().getCode().getExceptionTable(); + for (CodeException codeException : exceptionTable) { + if (codeException.getStartPC() <= i & i <= 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. + if (catchType == 0) { + frame.push(new StackValue(Const.T_OBJECT, exception)); + handlerPC = codeException.getHandlerPC(); + } else { + String exceptionClassName = frame.getConstantPoolUtil().getConstantClassClassName(catchType); + exceptionClassName = Utility.compactClassName(exceptionClassName, false); + Class exceptionClass = Class.forName(exceptionClassName); + if (exceptionClass.isAssignableFrom(exception.getClass())) { + frame.push(new StackValue(Const.T_OBJECT, exception)); + handlerPC = codeException.getHandlerPC(); + } + } + } + } + if (handlerPC != null) { + i = handlerPC; + } else { + log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize); + throw exception; + } } - i += instruction.offSet(); + } log.debug("{}└──────────────────[{}] {} | {}", blank, stackSize, frame.klass.getClassName(), frame.getMethod()); diff --git a/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java b/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java index 30f694f..f283597 100644 --- a/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java +++ b/src/main/java/haidnor/jvm/instruction/references/ANEWARRAY.java @@ -30,7 +30,7 @@ public class ANEWARRAY extends Instruction { ConstantPool constantPool = frame.getConstantPool(); ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); ConstantClass constantClass = constantPool.getConstant(constantClassIndex); - String className = constantPoolUtil.getClassName(constantClass); + String className = constantPoolUtil.getConstantClassClassName(constantClass); Klass klass = Metaspace.getJavaClass(Utility.compactClassName(className)); if (klass == null) { diff --git a/src/main/java/haidnor/jvm/instruction/references/ATHROW.java b/src/main/java/haidnor/jvm/instruction/references/ATHROW.java index 708f19c..fc5a2c0 100644 --- a/src/main/java/haidnor/jvm/instruction/references/ATHROW.java +++ b/src/main/java/haidnor/jvm/instruction/references/ATHROW.java @@ -2,6 +2,7 @@ package haidnor.jvm.instruction.references; import haidnor.jvm.instruction.Instruction; import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.StackValue; import haidnor.jvm.util.CodeStream; import lombok.SneakyThrows; @@ -14,7 +15,8 @@ public class ATHROW extends Instruction { @Override @SneakyThrows public void execute(Frame frame) { - + StackValue pop = frame.pop(); + throw (Exception) pop.getValue(); } } diff --git a/src/main/java/haidnor/jvm/instruction/references/INSTANCEOF.java b/src/main/java/haidnor/jvm/instruction/references/INSTANCEOF.java index 1ecfdc3..5987438 100644 --- a/src/main/java/haidnor/jvm/instruction/references/INSTANCEOF.java +++ b/src/main/java/haidnor/jvm/instruction/references/INSTANCEOF.java @@ -30,7 +30,7 @@ public class INSTANCEOF extends Instruction { ConstantPool constantPool = frame.getConstantPool(); ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); ConstantClass constantClass = constantPool.getConstant(constantClassIndex); - String className = constantPoolUtil.getClassName(constantClass); + String className = constantPoolUtil.getConstantClassClassName(constantClass); className = Utility.compactClassName(className); StackValue stackValue = frame.pop(); diff --git a/src/main/java/haidnor/jvm/instruction/references/NEW.java b/src/main/java/haidnor/jvm/instruction/references/NEW.java index 67c0d05..632709b 100644 --- a/src/main/java/haidnor/jvm/instruction/references/NEW.java +++ b/src/main/java/haidnor/jvm/instruction/references/NEW.java @@ -29,7 +29,7 @@ public class NEW extends Instruction { ConstantPool constantPool = frame.getConstantPool(); ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil(); ConstantClass constantClass = constantPool.getConstant(constantClassIndex); - String className = constantPoolUtil.getClassName(constantClass); + String className = constantPoolUtil.getConstantClassClassName(constantClass); if (className.startsWith("java/")) { frame.push(new StackValue(Const.T_OBJECT, null)); diff --git a/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java b/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java index 6523800..1b8dffe 100644 --- a/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java +++ b/src/main/java/haidnor/jvm/util/ConstantPoolUtil.java @@ -42,16 +42,16 @@ public class ConstantPoolUtil { /** * 获取长类名, 例如 java/lang/String */ - public String getClassName(final ConstantClass constantClass) { + public String getConstantClassClassName(final ConstantClass constantClass) { ConstantUtf8 constantUtf8 = cp.getConstant(constantClass.getNameIndex()); return constantUtf8.getBytes(); } /** * 获取长类名, 例如 java/lang/String */ - public String getClassName(int index) { - ConstantClass constantClass = cp.getConstant(index); - return getClassName(constantClass); + public String getConstantClassClassName(int constantClassIndex) { + ConstantClass constantClass = cp.getConstant(constantClassIndex); + return getConstantClassClassName(constantClass); } diff --git a/src/test/java/haidnor/jvm/test/demo/Demo7.java b/src/test/java/haidnor/jvm/test/demo/Demo7.java index 1db1fb6..3c12882 100644 --- a/src/test/java/haidnor/jvm/test/demo/Demo7.java +++ b/src/test/java/haidnor/jvm/test/demo/Demo7.java @@ -4,17 +4,17 @@ package haidnor.jvm.test.demo; public class Demo7 { public static void main(String[] args) { - String fun = fun(); - System.out.println(fun); - } - - public static String fun() { - String str = "hello"; try { - return str; - } finally { - System.out.println("zhangsan"); + String name = fun(); + System.out.println(name); + } catch (Exception exception) { + System.out.println("计算错误"); } } + public static String fun() { + System.out.println(1 / 0); + return "zhangsan"; + } + }