1418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// for details. All rights reserved. Use of this source code is governed by a 3418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// BSD-style license that can be found in the LICENSE file. 4418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpackage com.android.tools.r8; 5418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 6418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static org.junit.Assert.assertEquals; 7418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 8418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.ToolHelper.DexVm; 9418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.shaking.ProguardRuleParserException; 10418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.google.common.collect.ImmutableList; 11418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.google.common.collect.ImmutableMap; 12418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.File; 13418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.IOException; 14418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Paths; 15418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Arrays; 16418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Collection; 17418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.List; 18418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Map; 19418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.concurrent.ExecutionException; 20418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.Rule; 21418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.Test; 22418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.rules.ExpectedException; 23418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.rules.TemporaryFolder; 24418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.runner.RunWith; 25418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.runners.Parameterized; 26418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.runners.Parameterized.Parameters; 27418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 28418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager@RunWith(Parameterized.class) 29418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpublic class R8RunSmaliTestsTest { 30418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 31418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Rule 32418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public ExpectedException thrown = ExpectedException.none(); 33418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 34418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private static final String SMALI_DIR = ToolHelper.SMALI_BUILD_DIR; 35418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 36418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // Tests where the original smali code fails on Art, but runs after R8 processing. 37418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private static Map<DexVm, List<String>> originalFailingOnArtVersions = ImmutableMap.of( 38418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager DexVm.ART_5_1_1, ImmutableList.of( 39418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "sparse-switch", 40418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "regression/33846227" 41418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ) 42418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ); 43418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 44418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // Tests where the original smali code runs on Art, but fails after R8 processing 45418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private static Map<String, List<String>> failingOnArtVersions = ImmutableMap.of( 46418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // This list is currently empty! 47418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ); 48418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 49418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Rule 50418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest(); 51418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 52418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Parameters(name = "{0}") 53418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public static Collection<String[]> data() { 54418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return Arrays.asList(new String[][]{ 55418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"arithmetic", "-1\n3\n2\n3\n3.0\n1\n0\n-131580\n-131580\n2\n4\n-2\n"}, 56418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"controlflow", "2\n1\n2\n1\n2\n1\n2\n1\n2\n1\n2\n1\n2\n"}, 57418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"fibonacci", "55\n55\n55\n55\n"}, 58418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"fill-array-data", "[1, 2, 3][4, 5, 6]"}, 59418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"filled-new-array", "[1, 2, 3][4, 5, 6][1, 2, 3, 4, 5, 6][6, 5, 4, 3, 2, 1]"}, 60418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"packed-switch", "12345"}, 61418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"sparse-switch", "12345"}, 62418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"unreachable-code-1", "777"}, 63418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"multiple-returns", "TFtf\n1\n4611686018427387904\ntrue\nfalse\n"}, 64418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"try-catch", ""}, 65418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"phi-removal-regression", "returnBoolean\n"}, 66418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"overlapping-long-registers", "-9151314442816847872\n-9151314442816319488\n"}, 67418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"type-confusion-regression", "java.lang.RuntimeException: Test.<init>()\n"}, 68418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"type-confusion-regression2", 69418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "java.lang.NullPointerException: Attempt to read from null array\n"}, 70418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"type-confusion-regression3", 71418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "java.lang.NullPointerException: Attempt to read from field 'byte[] Test.a'" + 72418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager " on a null object reference\n"}, 73418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"type-confusion-regression4", ""}, 74418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"type-confusion-regression5", "java.lang.RuntimeException: getId()I\n"}, 75418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"chain-of-loops", "java.lang.RuntimeException: f(II)\n"}, 76418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"new-instance-and-init", "Test(0)\nTest(0)\nTest(0)\n"}, 77418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"bad-codegen", 78418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "java.lang.NullPointerException: Attempt to read from field " + 79418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "'Test Test.a' on a null object reference\n"}, 80418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"merge-blocks-regression", "java.lang.NullPointerException: Attempt to invoke virtual" 81809eff339d2e29d5c2947712e907e4d1946b195cStephan Herhut + " method 'Test Test.bW_()' on a null object reference\n"}, 82418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"self-is-catch-block", "100\n-1\n"}, 83418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"infinite-loop", ""}, 84418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"regression/33336471", 85418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n" + 86418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n"}, 87418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager {"regression/33846227", ""}, 88809eff339d2e29d5c2947712e907e4d1946b195cStephan Herhut {"illegal-invokes", "ICCE\nICCE\n"}, 89418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager }); 90418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 91418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 92418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private String directoryName; 93418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private String dexFileName; 94418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private String expectedOutput; 95418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 96418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public R8RunSmaliTestsTest(String name, String expectedOutput) { 97418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.directoryName = name; 98418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.dexFileName = name.substring(name.lastIndexOf('/') + 1) + ".dex"; 99418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.expectedOutput = expectedOutput; 100418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 101418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 102418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Test 103418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public void SmaliTest() 104418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throws IOException, ProguardRuleParserException, ExecutionException, CompilationException { 105418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager File originalDexFile = Paths.get(SMALI_DIR, directoryName, dexFileName).toFile(); 106418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String outputPath = temp.getRoot().getCanonicalPath(); 107418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ToolHelper.runR8(originalDexFile.getCanonicalPath(), outputPath); 108418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 109418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (!ToolHelper.artSupported()) { 110418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return; 111418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 112418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 113418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String mainClass = "Test"; 114418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String generated = outputPath + "/classes.dex"; 115418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String output; 116418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 117418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // If the original smali code fails on the target VM, only run the code produced by R8. 118418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (originalFailingOnArtVersions.containsKey(ToolHelper.getDexVm()) 119418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager && originalFailingOnArtVersions.get(ToolHelper.getDexVm()).contains(directoryName)) { 120418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager output = ToolHelper.runArtNoVerificationErrors(generated, mainClass); 121418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else { 122418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (failingOnArtVersions.containsKey(ToolHelper.getDexVm()) 123418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager && failingOnArtVersions.get(ToolHelper.getDexVm()).contains(directoryName)) { 124418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager thrown.expect(Throwable.class); 125418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 126418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager output = 127809eff339d2e29d5c2947712e907e4d1946b195cStephan Herhut ToolHelper 128809eff339d2e29d5c2947712e907e4d1946b195cStephan Herhut .checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null); 129418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 130418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager assertEquals(expectedOutput, output); 131418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 132418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager} 133