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