diff options
4 files changed, 58 insertions, 3 deletions
diff --git a/tools/locked_region_code_injection/Android.mk b/tools/locked_region_code_injection/Android.mk index 0aed0cec27ab..d9217834f871 100644 --- a/tools/locked_region_code_injection/Android.mk +++ b/tools/locked_region_code_injection/Android.mk @@ -9,7 +9,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ asm-5.2 \ asm-commons-5.2 \ asm-tree-5.2 \ - asm-analysis-5.2 - + asm-analysis-5.2 \ + guava-20.0 \ include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java index 9374f23c945e..99ef8a7b707a 100644 --- a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java +++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.TryCatchBlockSorter; @@ -32,6 +33,10 @@ import org.objectweb.asm.tree.analysis.AnalyzerException; import org.objectweb.asm.tree.analysis.BasicValue; import org.objectweb.asm.tree.analysis.Frame; +import static com.google.common.base.Preconditions.checkElementIndex; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + /** * This visitor does two things: * @@ -140,10 +145,26 @@ class LockFindingClassVisitor extends ClassVisitor { if (operand instanceof LockTargetState) { LockTargetState state = (LockTargetState) operand; for (int j = 0; j < state.getTargets().size(); j++) { + // The instruction after a monitor_exit should be a label for the end of the implicit + // catch block that surrounds the synchronized block to call monitor_exit when an exception + // occurs. + checkState(instructions.get(i + 1).getType() == AbstractInsnNode.LABEL, + "Expected to find label after monitor exit"); + + int labelIndex = i + 1; + checkElementIndex(labelIndex, instructions.size()); + + LabelNode label = (LabelNode)instructions.get(labelIndex); + + checkNotNull(handlersMap.get(i)); + checkElementIndex(0, handlersMap.get(i).size()); + checkState(handlersMap.get(i).get(0).end == label, + "Expected label to be the end of monitor exit's try block"); + LockTarget target = state.getTargets().get(j); MethodInsnNode call = new MethodInsnNode(Opcodes.INVOKESTATIC, target.getPostOwner(), target.getPostMethod(), "()V", false); - insertMethodCallAfter(mn, frameMap, handlersMap, s, i, call); + insertMethodCallAfter(mn, frameMap, handlersMap, label, labelIndex, call); } } } diff --git a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java index 1d4f2d455270..b86954d5e377 100644 --- a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java +++ b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java @@ -228,4 +228,26 @@ public class TestMain { Assert.assertEquals(TestTarget.unboostCount, 1); Assert.assertEquals(TestTarget.invokeCount, 1); } + + @Test + public void testUnboostThatThrows() { + TestTarget.resetCount(); + TestTarget t = new TestTarget(); + boolean asserted = false; + + Assert.assertEquals(TestTarget.boostCount, 0); + Assert.assertEquals(TestTarget.unboostCount, 0); + + try { + t.synchronizedThrowsOnUnboost(); + } catch (RuntimeException e) { + asserted = true; + } + + Assert.assertEquals(asserted, true); + Assert.assertEquals(TestTarget.boostCount, 1); + Assert.assertEquals(TestTarget.unboostCount, 0); + Assert.assertEquals(TestTarget.invokeCount, 1); + } + } diff --git a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java index 8e7d478a0e29..d1c8f340a598 100644 --- a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java +++ b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java @@ -17,12 +17,17 @@ public class TestTarget { public static int boostCount = 0; public static int unboostCount = 0; public static int invokeCount = 0; + public static boolean nextUnboostThrows = false; public static void boost() { boostCount++; } public static void unboost() { + if (nextUnboostThrows) { + nextUnboostThrows = false; + throw new RuntimeException(); + } unboostCount++; } @@ -49,4 +54,11 @@ public class TestTarget { invoke(); return this; } + + public void synchronizedThrowsOnUnboost() { + nextUnboostThrows = true; + synchronized(this) { + invoke(); + } + } } |