Loading tools/locked_region_code_injection/Android.mk +2 −2 Original line number Diff line number Diff line Loading @@ -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) tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java +22 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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: * Loading Loading @@ -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); } } } Loading tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java +22 −0 Original line number Diff line number Diff line Loading @@ -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); } } tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java +12 −0 Original line number Diff line number Diff line Loading @@ -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++; } Loading @@ -49,4 +54,11 @@ public class TestTarget { invoke(); return this; } public void synchronizedThrowsOnUnboost() { nextUnboostThrows = true; synchronized(this) { invoke(); } } } Loading
tools/locked_region_code_injection/Android.mk +2 −2 Original line number Diff line number Diff line Loading @@ -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)
tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java +22 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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: * Loading Loading @@ -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); } } } Loading
tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java +22 −0 Original line number Diff line number Diff line Loading @@ -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); } }
tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java +12 −0 Original line number Diff line number Diff line Loading @@ -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++; } Loading @@ -49,4 +54,11 @@ public class TestTarget { invoke(); return this; } public void synchronizedThrowsOnUnboost() { nextUnboostThrows = true; synchronized(this) { invoke(); } } }