diff --git a/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml b/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml
index 7866c5dc168..d2f989a9d19 100644
--- a/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml
+++ b/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml
@@ -386,6 +386,9 @@
-
+ -
+
+
-
@@ -551,6 +554,12 @@
-
+ -
+
+
+ -
+
+
-
diff --git a/src/org/jetbrains/eval4j/interpreter.kt b/src/org/jetbrains/eval4j/interpreter.kt
index 6395d1ff5a5..0d249e2edb8 100644
--- a/src/org/jetbrains/eval4j/interpreter.kt
+++ b/src/org/jetbrains/eval4j/interpreter.kt
@@ -20,8 +20,7 @@ trait Eval {
fun loadClass(classType: Type): Value
fun loadString(str: String): Value
fun newInstance(classType: Type): Value
- fun checkCast(value: Value, targetType: Type): Value
- fun isInsetanceOf(value: Value, targetType: Type): Boolean
+ fun isInstanceOf(value: Value, targetType: Type): Boolean
fun newArray(arrayType: Type, size: Int): Value
fun newMultiDimensionalArray(arrayType: Type, dimensionSizes: List): Value
@@ -176,12 +175,20 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter(
CHECKCAST -> {
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
- eval.checkCast(value, targetType)
+ if (eval.isInstanceOf(value, targetType)) {
+ ObjectValue(value.obj, targetType)
+ }
+ else {
+ throw ThrownFromEvalException(ObjectValue(
+ ClassCastException("Value '$value' cannot be cast to $targetType"),
+ Type.getType(javaClass())
+ ))
+ }
}
INSTANCEOF -> {
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
- boolean(eval.isInsetanceOf(value, targetType))
+ boolean(eval.isInstanceOf(value, targetType))
}
// TODO: maybe just do nothing?
diff --git a/src/org/jetbrains/eval4j/interpreterLoop.kt b/src/org/jetbrains/eval4j/interpreterLoop.kt
index 6762f9c4501..e0656f436ef 100644
--- a/src/org/jetbrains/eval4j/interpreterLoop.kt
+++ b/src/org/jetbrains/eval4j/interpreterLoop.kt
@@ -9,6 +9,8 @@ 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
+import org.objectweb.asm.tree.TryCatchBlockNode
+import java.util.ArrayList
trait InterpreterResult {
fun toString(): String
@@ -62,11 +64,27 @@ fun interpreterLoop(
}
val interpreter = SingleInstructionInterpreter(eval)
- var frame = initFrame(ownerClassInternalName, m, interpreter)
+ val frame = initFrame(ownerClassInternalName, m, interpreter)
+ val handlers = computeHandlers(m)
+
+ fun exceptionCaught(exceptionValue: Value): Boolean {
+ val catchBlocks = handlers[m.instructions.indexOf(currentInsn)] ?: listOf()
+ for (catch in catchBlocks) {
+ val exceptionTypeDesc = catch.`type`
+ if (exceptionTypeDesc != null) {
+ val exceptionType = Type.getType(exceptionTypeDesc)
+ if (eval.isInstanceOf(exceptionValue, exceptionType)) {
+ frame.clearStack()
+ frame.push(exceptionValue)
+ goto(catch.handler)
+ return true
+ }
+ }
+ }
+ return false
+ }
while (true) {
- // TODO try-catch-finally support
-
val insnOpcode = currentInsn.getOpcode()
val insnType = currentInsn.getType()
@@ -134,11 +152,11 @@ fun interpreterLoop(
}
}
- // TODO: try/catch/finally
ATHROW -> {
val exceptionValue = frame.getStack(0)!!
val handled = handler.exceptionThrown(frame, currentInsn, exceptionValue)
if (handled != null) return handled
+ if (exceptionCaught(exceptionValue)) continue
return ExceptionThrown(exceptionValue)
}
@@ -153,6 +171,7 @@ fun interpreterLoop(
// TODO: try/catch.finaly
val handled = handler.exceptionThrown(frame, currentInsn, e.exception)
if (handled != null) return handled
+ if (exceptionCaught(e.exception)) continue
return ExceptionThrown(e.exception)
}
}
@@ -193,4 +212,21 @@ fun initFrame(
}
return current
+}
+
+fun computeHandlers(m: MethodNode): Array?> {
+ val insns = m.instructions
+ val handlers = Array?>(insns.size()) {null}
+ for (tcb in m.tryCatchBlocks) {
+ val begin = insns.indexOf(tcb.start)
+ val end = insns.indexOf(tcb.end)
+ for (i in begin..end - 1) {
+ val insnHandlers = handlers[i] ?: ArrayList()
+ handlers[i] = insnHandlers
+
+ insnHandlers.add(tcb)
+ }
+ }
+
+ return handlers
}
\ No newline at end of file
diff --git a/test/org/jetbrains/eval4j/test/TestData.java b/test/org/jetbrains/eval4j/test/TestData.java
index 88d890325ce..16afc02f18e 100644
--- a/test/org/jetbrains/eval4j/test/TestData.java
+++ b/test/org/jetbrains/eval4j/test/TestData.java
@@ -208,4 +208,44 @@ class TestData {
static int constructorCallWithArgs() {
return new C(10).y;
}
+
+ static class MyEx extends RuntimeException {
+ final int x;
+
+ MyEx(int x) {
+ this.x = x;
+ }
+ }
+
+ static int tryCatch() {
+ try {
+ throw new MyEx(10);
+ }
+ catch (MyEx e) {
+ return e.x;
+ }
+ }
+
+ static int tryWiderCatch() {
+ int a = 10;
+ try {
+ if (a > 0) {
+ throw new MyEx(10);
+ }
+ } catch (Exception e) {
+ return ((MyEx) e).x;
+ }
+ return 2;
+ }
+
+ static int classCastException() {
+ Object a = "";
+ try {
+ Integer s = (Integer) a;
+ }
+ catch (ClassCastException e) {
+ return 1;
+ }
+ return 2;
+ }
}
diff --git a/test/org/jetbrains/eval4j/test/main.kt b/test/org/jetbrains/eval4j/test/main.kt
index 5fce03afe39..5e60db79c9e 100644
--- a/test/org/jetbrains/eval4j/test/main.kt
+++ b/test/org/jetbrains/eval4j/test/main.kt
@@ -111,11 +111,9 @@ object REFLECTION_EVAL : Eval {
return NewObjectValue(_class, classType)
}
- override fun checkCast(value: Value, targetType: Type): Value {
- throw UnsupportedOperationException()
- }
- override fun isInsetanceOf(value: Value, targetType: Type): Boolean {
- throw UnsupportedOperationException()
+ override fun isInstanceOf(value: Value, targetType: Type): Boolean {
+ val _class = findClass(targetType.getInternalName())
+ return _class.isInstance(value.obj)
}
override fun newArray(arrayType: Type, size: Int): Value {