diff --git a/src/main/java/kilim/analysis/MethodWeaver.java b/src/main/java/kilim/analysis/MethodWeaver.java index e1d942f..fc73fc7 100755 --- a/src/main/java/kilim/analysis/MethodWeaver.java +++ b/src/main/java/kilim/analysis/MethodWeaver.java @@ -417,15 +417,17 @@ private void genException(MethodVisitor mv, BasicBlock bb, List cwLi VMType.loadVar(mv, VMType.TOBJECT, getFiberVar()); mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "upEx", "()I"); // fiber.pc is on stack - Label[] labels = new Label[cwList.size() + 1]; - labels[0] = resumeLabel; + Label[] labels = new Label[cwList.size()]; + int[] keys = new int[cwList.size()]; for (int i = 0; i < cwList.size(); i++) { - labels[i + 1] = new Label(); + labels[i] = new Label(); + keys[i] = callWeavers.indexOf(cwList.get(i)) + 1; } - mv.visitTableSwitchInsn(0, cwList.size(), resumeLabel, labels); - int i = 1; + + mv.visitLookupSwitchInsn(resumeLabel, keys, labels); + int i = 0; for (CallWeaver cw: cwList) { - if (i > 1) { + if (i > 0) { // This is the jump (to normal exception handling) for the previous // switch case. mv.visitJumpInsn(GOTO, resumeLabel); diff --git a/src/test/java/kilim/test/TestYieldExceptions.java b/src/test/java/kilim/test/TestYieldExceptions.java index 894758a..6f82d2d 100755 --- a/src/test/java/kilim/test/TestYieldExceptions.java +++ b/src/test/java/kilim/test/TestYieldExceptions.java @@ -39,4 +39,9 @@ public void testNestedException() throws Exception { public void testTryCatchFinally() throws Exception { TestYield.runTask(new kilim.test.ex.ExCatch(3)); } + + + public void testPausableBlocksBeforeCatch() throws Exception { + TestYield.runTask(new kilim.test.ex.ExCatch(4)); + } } diff --git a/src/test/java/kilim/test/ex/ExCatch.java b/src/test/java/kilim/test/ex/ExCatch.java index 93ca137..1b04e19 100755 --- a/src/test/java/kilim/test/ex/ExCatch.java +++ b/src/test/java/kilim/test/ex/ExCatch.java @@ -30,6 +30,7 @@ private void test() throws Pausable { case 1: pausableCatch(); break; case 2: nestedPausableCatch(); break; case 3: tryCatchFinally(); break; + case 4: pausableBeforeCatch(); break; default: throw new IllegalStateException("Unknown test case: " + testCase); } } @@ -72,6 +73,32 @@ void pausableCatch() throws Pausable { verify(l); } + // Issue#6 on github. A pausable block before the catch block. + void pausableBeforeCatch() throws Pausable { + int foo = 0; + Task.sleep(1); + if (foo != 0) throw new RuntimeException("Expected 0"); + + foo = 1; + Task.sleep(1); + if (foo != 1) throw new RuntimeException("Expected 1"); + + foo = 2; + Task.sleep(1); + if (foo != 2) throw new RuntimeException("Expected 2"); + + try { + foo = 3; + throwEx(); + } catch (Throwable t) { + if (foo != 3) throw new RuntimeException("Expected 3"); + } + } + private static void throwEx() throws Pausable { + Task.sleep(1); + throw new RuntimeException(); + } + void tryCatchFinally() throws Pausable { short sh = fsh; String s = fs;