diff --git a/src/org/jetbrains/eval4j/interpreterLoop.kt b/src/org/jetbrains/eval4j/interpreterLoop.kt index d9dcfc1eaa1..b63d49a689c 100644 --- a/src/org/jetbrains/eval4j/interpreterLoop.kt +++ b/src/org/jetbrains/eval4j/interpreterLoop.kt @@ -5,7 +5,6 @@ import org.objectweb.asm.tree.analysis.Frame import org.objectweb.asm.tree.MethodNode import org.objectweb.asm.Type import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.tree.analysis.Interpreter import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.VarInsnNode import org.objectweb.asm.util.Printer @@ -45,8 +44,12 @@ trait InterpretationEventHandler { fun exceptionCaught(currentState: Frame, currentInsn: AbstractInsnNode, exception: Value): InterpreterResult? } -class ThrownFromEvalException(val exception: Value): RuntimeException() { - fun toString(): String = "Thrown by evaluator: $exception" +class ThrownFromEvalException(cause: Throwable): RuntimeException(cause) { + fun toString(): String = "Thrown by evaluator: ${getCause()}" +} + +class ThrownFromEvaluatedCodeException(val exception: Value): RuntimeException() { + fun toString(): String = "Thrown from evaluated code: $exception" } fun interpreterLoop( @@ -71,13 +74,13 @@ fun interpreterLoop( class ResultException(val result: InterpreterResult): RuntimeException() - fun exceptionCaught(exceptionValue: Value): Boolean { + fun exceptionCaught(exceptionValue: Value, instanceOf: (Type) -> Boolean): Boolean { val catchBlocks = handlers[m.instructions.indexOf(currentInsn)] ?: listOf() for (catch in catchBlocks) { val exceptionTypeInternalName = catch.`type` if (exceptionTypeInternalName != null) { val exceptionType = Type.getObjectType(exceptionTypeInternalName) - if (eval.isInstanceOf(exceptionValue, exceptionType)) { + if (instanceOf(exceptionType)) { val handled = handler.exceptionCaught(frame, currentInsn, exceptionValue) if (handled != null) throw ResultException(handled) frame.clearStack() @@ -90,6 +93,29 @@ fun interpreterLoop( return false } + fun exceptionCaught(exceptionValue: Value): Boolean = exceptionCaught(exceptionValue) { + exceptionType -> eval.isInstanceOf(exceptionValue, exceptionType) + } + + fun exceptionFromEvalCaught(exception: Throwable, exceptionValue: Value): Boolean { + return exceptionCaught(exceptionValue) { + exceptionType -> + try { + val exceptionClass = exception.javaClass + val _class = Class.forName( + exceptionType.getInternalName().replace('/', '.'), + true, + exceptionClass.getClassLoader() + ) + _class.isAssignableFrom(exceptionClass) + } + catch (e: ClassNotFoundException) { + // If the class is not available in this VM, it can not be a superclass of an exception trown in it + false + } + } + } + try { while (true) { val insnOpcode = currentInsn.getOpcode() @@ -175,6 +201,15 @@ fun interpreterLoop( frame.execute(currentInsn, interpreter) } catch (e: ThrownFromEvalException) { + val exception = e.getCause()!! + val exceptionValue = ObjectValue(exception, Type.getType(exception.javaClass)) + val handled = handler.exceptionThrown(frame, currentInsn, + exceptionValue) + if (handled != null) return handled + if (exceptionFromEvalCaught(exception, exceptionValue)) continue + return ExceptionThrown(exceptionValue) + } + catch (e: ThrownFromEvaluatedCodeException) { val handled = handler.exceptionThrown(frame, currentInsn, e.exception) if (handled != null) return handled if (exceptionCaught(e.exception)) continue diff --git a/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/src/org/jetbrains/eval4j/jdi/jdiEval.kt index e17be8a36cf..dd927dc64a4 100644 --- a/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -208,6 +208,6 @@ fun mayThrow(f: () -> T): T { return f() } catch (e: jdi.InvocationException) { - throw ThrownFromEvalException(e.exception().asValue()) + throw ThrownFromEvaluatedCodeException(e.exception().asValue()) } } \ No newline at end of file diff --git a/src/org/jetbrains/eval4j/values.kt b/src/org/jetbrains/eval4j/values.kt index 932cb6163e9..445fd92fcae 100644 --- a/src/org/jetbrains/eval4j/values.kt +++ b/src/org/jetbrains/eval4j/values.kt @@ -107,5 +107,5 @@ fun T?.checkNull(): T { } fun throwEvalException(e: Throwable): Nothing { - throw ThrownFromEvalException(ObjectValue(e, Type.getType(e.javaClass))) + throw ThrownFromEvalException(e) } \ No newline at end of file diff --git a/test/org/jetbrains/eval4j/test/main.kt b/test/org/jetbrains/eval4j/test/main.kt index 7b29911bdeb..0b48bcbcfed 100644 --- a/test/org/jetbrains/eval4j/test/main.kt +++ b/test/org/jetbrains/eval4j/test/main.kt @@ -170,7 +170,7 @@ object REFLECTION_EVAL : Eval { } } catch (e: Throwable) { - throwEvalException(e) + throw ThrownFromEvaluatedCodeException(ObjectValue(e, Type.getType(e.javaClass))) } }