| // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.rewrite.assertions; |
| |
| import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.AssertionsConfiguration; |
| import com.android.tools.r8.D8TestBuilder; |
| import com.android.tools.r8.R8FullTestBuilder; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import com.android.tools.r8.ThrowableConsumer; |
| import com.android.tools.r8.rewrite.assertions.testclasses.TestClassForInnerClass; |
| import com.android.tools.r8.utils.StringUtils; |
| import com.android.tools.r8.utils.ThrowingConsumer; |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.android.tools.r8.utils.codeinspector.InstructionSubject; |
| import com.google.common.collect.ImmutableList; |
| import java.util.List; |
| import org.junit.Assume; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.objectweb.asm.ClassWriter; |
| import org.objectweb.asm.FieldVisitor; |
| import org.objectweb.asm.Label; |
| import org.objectweb.asm.MethodVisitor; |
| import org.objectweb.asm.Opcodes; |
| import org.objectweb.asm.Type; |
| |
| @RunWith(Parameterized.class) |
| public class AssertionsConfigurationTest extends TestBase implements Opcodes { |
| |
| private final TestParameters parameters; |
| |
| private Class<?> class1 = com.android.tools.r8.rewrite.assertions.testclasses.Class1.class; |
| private Class<?> class2 = com.android.tools.r8.rewrite.assertions.testclasses.Class2.class; |
| private Class<?> subpackageClass1 = |
| com.android.tools.r8.rewrite.assertions.testclasses.subpackage.Class1.class; |
| private Class<?> subpackageClass2 = |
| com.android.tools.r8.rewrite.assertions.testclasses.subpackage.Class2.class; |
| |
| private List<Class<?>> testClasses = |
| ImmutableList.of(TestClass.class, class1, class2, subpackageClass1, subpackageClass2); |
| |
| private String packageName = |
| com.android.tools.r8.rewrite.assertions.testclasses.Class1.class.getPackage().getName(); |
| private String subPackageName = |
| com.android.tools.r8.rewrite.assertions.testclasses.subpackage.Class1.class |
| .getPackage() |
| .getName(); |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withAllRuntimes().withAllApiLevels().build(); |
| } |
| |
| public AssertionsConfigurationTest(TestParameters parameters) { |
| this.parameters = parameters; |
| } |
| |
| private void runD8Test( |
| ThrowableConsumer<D8TestBuilder> builderConsumer, |
| ThrowingConsumer<CodeInspector, RuntimeException> inspector, |
| List<String> outputLines) |
| throws Exception { |
| testForD8() |
| .addProgramClasses(testClasses) |
| .setMinApi(parameters.getApiLevel()) |
| .apply(builderConsumer) |
| .compile() |
| .inspect(inspector) |
| .run(parameters.getRuntime(), TestClass.class) |
| .assertSuccessWithOutput(StringUtils.lines(outputLines)); |
| } |
| |
| public void runR8Test( |
| ThrowableConsumer<R8FullTestBuilder> builderConsumer, |
| ThrowingConsumer<CodeInspector, RuntimeException> inspector, |
| List<String> outputLines) |
| throws Exception { |
| runR8Test(builderConsumer, inspector, outputLines, false); |
| } |
| |
| public void runR8Test( |
| ThrowableConsumer<R8FullTestBuilder> builderConsumer, |
| ThrowingConsumer<CodeInspector, RuntimeException> inspector, |
| List<String> outputLines, |
| boolean enableJvmAssertions) |
| throws Exception { |
| |
| testForR8(parameters.getBackend()) |
| .addProgramClasses(testClasses) |
| .addKeepMainRule(TestClass.class) |
| .addKeepClassAndMembersRules(class1, class2, subpackageClass1, subpackageClass2) |
| .setMinApi(parameters.getApiLevel()) |
| .apply(builderConsumer) |
| .compile() |
| .inspect(inspector) |
| .enableRuntimeAssertions(enableJvmAssertions) |
| .run(parameters.getRuntime(), TestClass.class) |
| .assertSuccessWithOutput(StringUtils.lines(outputLines)); |
| } |
| |
| private List<String> allAssertionsExpectedLines() { |
| return ImmutableList.of( |
| "AssertionError in testclasses.Class1", |
| "AssertionError in testclasses.Class2", |
| "AssertionError in testclasses.subpackage.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE"); |
| } |
| |
| private List<String> noAllAssertionsExpectedLines() { |
| return ImmutableList.of("DONE"); |
| } |
| |
| private void checkAssertionCodeRemoved(ClassSubject subject) { |
| assertThat(subject, isPresent()); |
| // <clinit> is removed by R8 as it becomes empty. |
| if (subject.uniqueMethodWithName("<clinit>").isPresent()) { |
| assertFalse( |
| subject |
| .uniqueMethodWithName("<clinit>") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isStaticPut)); |
| } |
| assertFalse( |
| subject |
| .uniqueMethodWithName("m") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isThrow)); |
| } |
| |
| private void checkAssertionCodeRemoved(CodeInspector inspector, Class<?> clazz) { |
| checkAssertionCodeRemoved(inspector.clazz(clazz)); |
| } |
| |
| private void checkAssertionCodeEnabled(ClassSubject subject) { |
| assertThat(subject, isPresent()); |
| // <clinit> is removed by R8. |
| if (subject.uniqueMethodWithName("<clinit>").isPresent()) { |
| assertFalse( |
| subject |
| .uniqueMethodWithName("<clinit>") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isStaticPut)); |
| } |
| assertTrue( |
| subject |
| .uniqueMethodWithName("m") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isThrow)); |
| } |
| |
| private void checkAssertionCodeEnabled(CodeInspector inspector, Class<?> clazz) { |
| checkAssertionCodeEnabled(inspector.clazz(clazz)); |
| } |
| |
| private void checkAssertionCodeLeft(CodeInspector inspector, Class<?> clazz) { |
| ClassSubject subject = inspector.clazz(clazz); |
| assertThat(subject, isPresent()); |
| assertTrue( |
| subject |
| .uniqueMethodWithName("<clinit>") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isStaticPut)); |
| assertTrue( |
| subject |
| .uniqueMethodWithName("m") |
| .streamInstructions() |
| .anyMatch(InstructionSubject::isThrow)); |
| } |
| |
| private void checkAssertionCodeRemoved(CodeInspector inspector) { |
| checkAssertionCodeRemoved(inspector, class1); |
| checkAssertionCodeRemoved(inspector, class2); |
| checkAssertionCodeRemoved(inspector, subpackageClass1); |
| checkAssertionCodeRemoved(inspector, subpackageClass2); |
| } |
| |
| private void checkAssertionCodeEnabled(CodeInspector inspector) { |
| checkAssertionCodeEnabled(inspector, class1); |
| checkAssertionCodeEnabled(inspector, class2); |
| checkAssertionCodeEnabled(inspector, subpackageClass1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| } |
| |
| private void checkAssertionCodeLeft(CodeInspector inspector) { |
| checkAssertionCodeLeft(inspector, class1); |
| checkAssertionCodeLeft(inspector, class2); |
| checkAssertionCodeLeft(inspector, subpackageClass1); |
| checkAssertionCodeLeft(inspector, subpackageClass2); |
| } |
| |
| @Test |
| public void testAssertionsForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| // Leaving assertions in or disabling them on Dalvik/Art means no assertions. |
| runD8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::passthroughAllAssertions), |
| this::checkAssertionCodeLeft, |
| noAllAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::passthroughAllAssertions), |
| this::checkAssertionCodeLeft, |
| noAllAssertionsExpectedLines()); |
| runD8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::disableAllAssertions), |
| this::checkAssertionCodeRemoved, |
| noAllAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::disableAllAssertions), |
| this::checkAssertionCodeRemoved, |
| noAllAssertionsExpectedLines()); |
| // Compile time enabling assertions gives assertions on Dalvik/Art. |
| runD8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::enableAllAssertions), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::enableAllAssertions), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines()); |
| // Enabling for the package should enable all. |
| runD8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| b -> b.setEnable().setScopePackage(packageName).build()), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| b -> b.setEnable().setScopePackage(packageName).build()), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines()); |
| } |
| |
| @Test |
| public void testAssertionsForCf() throws Exception { |
| Assume.assumeTrue(parameters.isCfRuntime()); |
| // Leaving assertion code means assertions are controlled by the -ea flag. |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::passthroughAllAssertions), |
| this::checkAssertionCodeLeft, |
| noAllAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::passthroughAllAssertions), |
| this::checkAssertionCodeLeft, |
| allAssertionsExpectedLines(), |
| true); |
| // Compile time enabling or disabling assertions means the -ea flag has no effect. |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::enableAllAssertions), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::enableAllAssertions), |
| this::checkAssertionCodeEnabled, |
| allAssertionsExpectedLines(), |
| true); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::disableAllAssertions), |
| this::checkAssertionCodeRemoved, |
| noAllAssertionsExpectedLines()); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| AssertionsConfiguration.Builder::disableAllAssertions), |
| this::checkAssertionCodeRemoved, |
| noAllAssertionsExpectedLines(), |
| true); |
| } |
| |
| @Test |
| public void testEnableForPackageForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| runD8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| b -> b.setEnable().setScopePackage(subPackageName).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, subpackageClass1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.subpackage.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| runR8Test( |
| builder -> |
| builder.addAssertionsConfiguration( |
| b -> b.setEnable().setScopePackage(subPackageName).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, subpackageClass1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.subpackage.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| } |
| |
| @Test |
| public void testEnableForClassForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| runD8Test( |
| builder -> |
| builder |
| .addAssertionsConfiguration( |
| b -> b.setEnable().setScopeClass(class1.getCanonicalName()).build()) |
| .addAssertionsConfiguration( |
| b -> b.setEnable().setScopeClass(subpackageClass2.getCanonicalName()).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, class1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| runR8Test( |
| builder -> |
| builder |
| .addAssertionsConfiguration( |
| b -> b.setEnable().setScopeClass(class1.getCanonicalName()).build()) |
| .addAssertionsConfiguration( |
| b -> b.setEnable().setScopeClass(subpackageClass2.getCanonicalName()).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, class1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| } |
| |
| @Test |
| public void testMixedForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| runD8Test( |
| builder -> |
| builder |
| .addAssertionsConfiguration(b -> b.setEnable().setScopePackage(packageName).build()) |
| .addAssertionsConfiguration( |
| b -> b.setDisable().setScopeClass(class2.getCanonicalName()).build()) |
| .addAssertionsConfiguration( |
| b -> b.setDisable().setScopeClass(subpackageClass1.getCanonicalName()).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, class1); |
| checkAssertionCodeRemoved(inspector, class2); |
| checkAssertionCodeRemoved(inspector, subpackageClass1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| runR8Test( |
| builder -> |
| builder |
| .addAssertionsConfiguration(b -> b.setEnable().setScopePackage(packageName).build()) |
| .addAssertionsConfiguration( |
| b -> b.setDisable().setScopeClass(class2.getCanonicalName()).build()) |
| .addAssertionsConfiguration( |
| b -> b.setDisable().setScopeClass(subpackageClass1.getCanonicalName()).build()), |
| inspector -> { |
| checkAssertionCodeEnabled(inspector, class1); |
| checkAssertionCodeRemoved(inspector, class2); |
| checkAssertionCodeRemoved(inspector, subpackageClass1); |
| checkAssertionCodeEnabled(inspector, subpackageClass2); |
| }, |
| ImmutableList.of( |
| "AssertionError in testclasses.Class1", |
| "AssertionError in testclasses.subpackage.Class2", |
| "DONE")); |
| } |
| |
| @Test |
| public void testUnnamedPackageForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| testForD8() |
| .addProgramClasses(class1, class2) |
| .addProgramClassFileData( |
| testClassForUnknownPackage(), |
| classInUnnamedPackage("Class1"), |
| classInUnnamedPackage("Class2")) |
| .setMinApi(parameters.getApiLevel()) |
| .addAssertionsConfiguration(builder -> builder.setEnable().setScopePackage("").build()) |
| .compile() |
| .inspect( |
| inspector -> { |
| checkAssertionCodeEnabled(inspector.clazz("Class1")); |
| checkAssertionCodeEnabled(inspector.clazz("Class2")); |
| checkAssertionCodeRemoved(inspector.clazz(class1)); |
| checkAssertionCodeRemoved(inspector.clazz(class2)); |
| }) |
| .run(parameters.getRuntime(), "Main") |
| .assertSuccessWithOutputLines( |
| "AssertionError in Class1", "AssertionError in Class2", "DONE"); |
| } |
| |
| @Test |
| public void testInnerClassForJvm() throws Exception { |
| Assume.assumeTrue(parameters.isCfRuntime()); |
| // Pointing to the outer class enables assertions for the inner as well. |
| testForJvm() |
| .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class) |
| .addVmArguments("-ea:" + TestClassForInnerClass.class.getCanonicalName()) |
| .run(parameters.getRuntime(), TestClassForInnerClass.class) |
| .assertSuccessWithOutputLines( |
| "AssertionError in TestClassForInnerClass", |
| "AssertionError in TestClassForInnerClass.InnerClass", |
| "DONE"); |
| |
| // Pointing to the inner class enables no assertions. |
| testForJvm() |
| .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class) |
| .addVmArguments("-ea:" + TestClassForInnerClass.InnerClass.class.getCanonicalName()) |
| .run(parameters.getRuntime(), TestClassForInnerClass.class) |
| .assertSuccessWithOutputLines("DONE"); |
| testForJvm() |
| .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class) |
| .addVmArguments("-ea:" + TestClassForInnerClass.InnerClass.class.getTypeName()) |
| .run(parameters.getRuntime(), TestClassForInnerClass.class) |
| .assertSuccessWithOutputLines("DONE"); |
| } |
| |
| @Test |
| public void testInnerClassForDex() throws Exception { |
| Assume.assumeTrue(parameters.isDexRuntime()); |
| testForD8() |
| .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class) |
| .setMinApi(parameters.getApiLevel()) |
| .addAssertionsConfiguration( |
| builder -> |
| builder |
| .setEnable() |
| .setScopeClass(TestClassForInnerClass.class.getCanonicalName()) |
| .build()) |
| .compile() |
| .inspect( |
| inspector -> { |
| checkAssertionCodeEnabled(inspector.clazz(TestClassForInnerClass.class)); |
| checkAssertionCodeEnabled(inspector.clazz(TestClassForInnerClass.InnerClass.class)); |
| }) |
| .run(parameters.getRuntime(), TestClassForInnerClass.class) |
| .assertSuccessWithOutputLines( |
| "AssertionError in TestClassForInnerClass", |
| "AssertionError in TestClassForInnerClass.InnerClass", |
| "DONE"); |
| } |
| /** |
| * Code for the following class in the unnamed package: |
| * |
| * <p>public class Main { public static void main(String[] args) { try { Class1.m(); } catch |
| * (AssertionError e) { System.out.println("AssertionError in Class1"); } try { Class2.m(); } |
| * catch (AssertionError e) { System.out.println("AssertionError in Class2"); } try { |
| * com.android.tools.r8.rewrite.assertions.Class1.m(); } catch (AssertionError e) { |
| * System.out.println("AssertionError in Class1"); } try { |
| * com.android.tools.r8.rewrite.assertions.Class2.m(); } catch (AssertionError e) { |
| * System.out.println("AssertionError in Class2"); } System.out.println("DONE"); } } |
| */ |
| public static byte[] testClassForUnknownPackage() { |
| |
| ClassWriter classWriter = new ClassWriter(0); |
| MethodVisitor methodVisitor; |
| |
| classWriter.visit(V1_8, ACC_FINAL | ACC_SUPER, "Main", null, "java/lang/Object", null); |
| |
| classWriter.visitSource("Main.java", null); |
| |
| { |
| methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null); |
| methodVisitor.visitCode(); |
| Label label0 = new Label(); |
| methodVisitor.visitLabel(label0); |
| methodVisitor.visitLineNumber(1, label0); |
| methodVisitor.visitVarInsn(ALOAD, 0); |
| methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); |
| methodVisitor.visitInsn(RETURN); |
| methodVisitor.visitMaxs(1, 1); |
| methodVisitor.visitEnd(); |
| } |
| { |
| methodVisitor = |
| classWriter.visitMethod( |
| ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); |
| methodVisitor.visitCode(); |
| Label label0 = new Label(); |
| Label label1 = new Label(); |
| Label label2 = new Label(); |
| methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/AssertionError"); |
| Label label3 = new Label(); |
| Label label4 = new Label(); |
| Label label5 = new Label(); |
| methodVisitor.visitTryCatchBlock(label3, label4, label5, "java/lang/AssertionError"); |
| Label label6 = new Label(); |
| Label label7 = new Label(); |
| Label label8 = new Label(); |
| methodVisitor.visitTryCatchBlock(label6, label7, label8, "java/lang/AssertionError"); |
| Label label9 = new Label(); |
| Label label10 = new Label(); |
| Label label11 = new Label(); |
| methodVisitor.visitTryCatchBlock(label9, label10, label11, "java/lang/AssertionError"); |
| methodVisitor.visitLabel(label0); |
| methodVisitor.visitLineNumber(4, label0); |
| methodVisitor.visitMethodInsn(INVOKESTATIC, "Class1", "m", "()V", false); |
| methodVisitor.visitLabel(label1); |
| methodVisitor.visitLineNumber(7, label1); |
| methodVisitor.visitJumpInsn(GOTO, label3); |
| methodVisitor.visitLabel(label2); |
| methodVisitor.visitLineNumber(5, label2); |
| methodVisitor.visitFrame( |
| Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AssertionError"}); |
| methodVisitor.visitVarInsn(ASTORE, 1); |
| Label label12 = new Label(); |
| methodVisitor.visitLabel(label12); |
| methodVisitor.visitLineNumber(6, label12); |
| methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| methodVisitor.visitLdcInsn("AssertionError in Class1"); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| methodVisitor.visitLabel(label3); |
| methodVisitor.visitLineNumber(9, label3); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitMethodInsn(INVOKESTATIC, "Class2", "m", "()V", false); |
| methodVisitor.visitLabel(label4); |
| methodVisitor.visitLineNumber(12, label4); |
| methodVisitor.visitJumpInsn(GOTO, label6); |
| methodVisitor.visitLabel(label5); |
| methodVisitor.visitLineNumber(10, label5); |
| methodVisitor.visitFrame( |
| Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AssertionError"}); |
| methodVisitor.visitVarInsn(ASTORE, 1); |
| Label label13 = new Label(); |
| methodVisitor.visitLabel(label13); |
| methodVisitor.visitLineNumber(11, label13); |
| methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| methodVisitor.visitLdcInsn("AssertionError in Class2"); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| methodVisitor.visitLabel(label6); |
| methodVisitor.visitLineNumber(14, label6); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitMethodInsn( |
| INVOKESTATIC, |
| "com/android/tools/r8/rewrite/assertions/testclasses/Class1", |
| "m", |
| "()V", |
| false); |
| methodVisitor.visitLabel(label7); |
| methodVisitor.visitLineNumber(17, label7); |
| methodVisitor.visitJumpInsn(GOTO, label9); |
| methodVisitor.visitLabel(label8); |
| methodVisitor.visitLineNumber(15, label8); |
| methodVisitor.visitFrame( |
| Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AssertionError"}); |
| methodVisitor.visitVarInsn(ASTORE, 1); |
| Label label14 = new Label(); |
| methodVisitor.visitLabel(label14); |
| methodVisitor.visitLineNumber(16, label14); |
| methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| methodVisitor.visitLdcInsn("AssertionError in testclasses.Class1"); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| methodVisitor.visitLabel(label9); |
| methodVisitor.visitLineNumber(19, label9); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitMethodInsn( |
| INVOKESTATIC, |
| "com/android/tools/r8/rewrite/assertions/testclasses/Class2", |
| "m", |
| "()V", |
| false); |
| methodVisitor.visitLabel(label10); |
| methodVisitor.visitLineNumber(22, label10); |
| Label label15 = new Label(); |
| methodVisitor.visitJumpInsn(GOTO, label15); |
| methodVisitor.visitLabel(label11); |
| methodVisitor.visitLineNumber(20, label11); |
| methodVisitor.visitFrame( |
| Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AssertionError"}); |
| methodVisitor.visitVarInsn(ASTORE, 1); |
| Label label16 = new Label(); |
| methodVisitor.visitLabel(label16); |
| methodVisitor.visitLineNumber(21, label16); |
| methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| methodVisitor.visitLdcInsn("AssertionError in testclasses.Class2"); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| methodVisitor.visitLabel(label15); |
| methodVisitor.visitLineNumber(24, label15); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| methodVisitor.visitLdcInsn("DONE"); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| Label label17 = new Label(); |
| methodVisitor.visitLabel(label17); |
| methodVisitor.visitLineNumber(25, label17); |
| methodVisitor.visitInsn(RETURN); |
| methodVisitor.visitMaxs(2, 2); |
| methodVisitor.visitEnd(); |
| } |
| classWriter.visitEnd(); |
| |
| return classWriter.toByteArray(); |
| } |
| |
| /** |
| * Code for the following class in the unnamed package: |
| * |
| * <p>public class <name> { public static void m() { assert false; } } |
| */ |
| public static byte[] classInUnnamedPackage(String name) { |
| |
| ClassWriter classWriter = new ClassWriter(0); |
| FieldVisitor fieldVisitor; |
| MethodVisitor methodVisitor; |
| |
| classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); |
| |
| classWriter.visitSource(name + ".java", null); |
| |
| { |
| fieldVisitor = |
| classWriter.visitField( |
| ACC_FINAL | ACC_STATIC | ACC_SYNTHETIC, "$assertionsDisabled", "Z", null, null); |
| fieldVisitor.visitEnd(); |
| } |
| { |
| methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
| methodVisitor.visitCode(); |
| Label label0 = new Label(); |
| methodVisitor.visitLabel(label0); |
| methodVisitor.visitLineNumber(1, label0); |
| methodVisitor.visitVarInsn(ALOAD, 0); |
| methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); |
| methodVisitor.visitInsn(RETURN); |
| methodVisitor.visitMaxs(1, 1); |
| methodVisitor.visitEnd(); |
| } |
| { |
| methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null); |
| methodVisitor.visitCode(); |
| Label label0 = new Label(); |
| methodVisitor.visitLabel(label0); |
| methodVisitor.visitLineNumber(3, label0); |
| methodVisitor.visitFieldInsn(GETSTATIC, name, "$assertionsDisabled", "Z"); |
| Label label1 = new Label(); |
| methodVisitor.visitJumpInsn(IFNE, label1); |
| methodVisitor.visitTypeInsn(NEW, "java/lang/AssertionError"); |
| methodVisitor.visitInsn(DUP); |
| methodVisitor.visitMethodInsn( |
| INVOKESPECIAL, "java/lang/AssertionError", "<init>", "()V", false); |
| methodVisitor.visitInsn(ATHROW); |
| methodVisitor.visitLabel(label1); |
| methodVisitor.visitLineNumber(4, label1); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitInsn(RETURN); |
| methodVisitor.visitMaxs(2, 0); |
| methodVisitor.visitEnd(); |
| } |
| { |
| methodVisitor = classWriter.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); |
| methodVisitor.visitCode(); |
| Label label0 = new Label(); |
| methodVisitor.visitLabel(label0); |
| methodVisitor.visitLineNumber(1, label0); |
| methodVisitor.visitLdcInsn(Type.getType("L" + name + ";")); |
| methodVisitor.visitMethodInsn( |
| INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false); |
| Label label1 = new Label(); |
| methodVisitor.visitJumpInsn(IFNE, label1); |
| methodVisitor.visitInsn(ICONST_1); |
| Label label2 = new Label(); |
| methodVisitor.visitJumpInsn(GOTO, label2); |
| methodVisitor.visitLabel(label1); |
| methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| methodVisitor.visitInsn(ICONST_0); |
| methodVisitor.visitLabel(label2); |
| methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {Opcodes.INTEGER}); |
| methodVisitor.visitFieldInsn(PUTSTATIC, name, "$assertionsDisabled", "Z"); |
| methodVisitor.visitInsn(RETURN); |
| methodVisitor.visitMaxs(1, 0); |
| methodVisitor.visitEnd(); |
| } |
| classWriter.visitEnd(); |
| |
| return classWriter.toByteArray(); |
| } |
| |
| static class TestClass { |
| public static void main(String[] args) { |
| try { |
| com.android.tools.r8.rewrite.assertions.testclasses.Class1.m(); |
| } catch (AssertionError e) { |
| System.out.println("AssertionError in testclasses.Class1"); |
| } |
| try { |
| com.android.tools.r8.rewrite.assertions.testclasses.Class2.m(); |
| } catch (AssertionError e) { |
| System.out.println("AssertionError in testclasses.Class2"); |
| } |
| try { |
| com.android.tools.r8.rewrite.assertions.testclasses.subpackage.Class1.m(); |
| } catch (AssertionError e) { |
| System.out.println("AssertionError in testclasses.subpackage.Class1"); |
| } |
| try { |
| com.android.tools.r8.rewrite.assertions.testclasses.subpackage.Class2.m(); |
| } catch (AssertionError e) { |
| System.out.println("AssertionError in testclasses.subpackage.Class2"); |
| } |
| System.out.println("DONE"); |
| } |
| } |
| } |