Merge "Relax the dead condition of field reads."
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index 21900a01..42ebde9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -62,7 +62,8 @@
private void write(ThrowingFunction<DexClass, PrintStream, IOException> outputStreamProvider,
Consumer<PrintStream> closer)
throws IOException {
- for (DexProgramClass clazz : application.classes()) {
+ Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
+ for (DexProgramClass clazz : classes) {
if (anyMethodMatches(clazz)) {
PrintStream ps = outputStreamProvider.apply(clazz);
try {
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 37e4dec..c807a5d 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -87,8 +87,8 @@
return self();
}
- public D8TestBuilder setIntermediate(boolean b) {
- builder.setIntermediate(true);
+ public D8TestBuilder setIntermediate(boolean intermediate) {
+ builder.setIntermediate(intermediate);
return self();
}
}
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index 15c03dc..7ad544b 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -8,6 +8,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
+import com.android.tools.r8.utils.ListUtils;
import java.util.ArrayList;
import java.util.List;
import org.hamcrest.Matcher;
@@ -44,25 +45,34 @@
return errors;
}
+ private void assertEmpty(String type, List<Diagnostic> messages) {
+ assertEquals(
+ "Expected no "
+ + type
+ + " messages, got:\n"
+ + String.join("\n", ListUtils.map(messages, m -> m.getDiagnosticMessage())),
+ 0,
+ messages.size());
+ }
public TestDiagnosticMessages assertNoMessages() {
- assertEquals(0, getInfos().size());
- assertEquals(0, getWarnings().size());
- assertEquals(0, getErrors().size());
+ assertEmpty("info", getInfos());
+ assertEmpty("warning", getWarnings());
+ assertEmpty("error", getErrors());
return this;
}
public TestDiagnosticMessages assertOnlyInfos() {
assertNotEquals(0, getInfos().size());
- assertEquals(0, getWarnings().size());
- assertEquals(0, getErrors().size());
+ assertEmpty("warning", getWarnings());
+ assertEmpty("error", getErrors());
return this;
}
public TestDiagnosticMessages assertOnlyWarnings() {
- assertEquals(0, getInfos().size());
+ assertEmpty("info", getInfos());
assertNotEquals(0, getWarnings().size());
- assertEquals(0, getErrors().size());
+ assertEmpty("error", getErrors());
return this;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
new file mode 100644
index 0000000..e9b1b8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
@@ -0,0 +1,25 @@
+// 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.desugar;
+
+public class DefaultLambdaWithInvokeInterfaceTest {
+
+ public interface I {
+ int run();
+ }
+
+ public interface J {
+ default String stateless() {
+ return "hest";
+ }
+
+ default I stateful() {
+ return () -> stateless().length();
+ }
+ }
+
+ public static void main(String[] args) {
+ System.out.println(new J() {}.stateful().run());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
new file mode 100644
index 0000000..732612d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -0,0 +1,35 @@
+// 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.desugar;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+
+public class DefaultLambdaWithInvokeInterfaceTestRunner extends TestBase {
+
+ final Class<?> CLASS = DefaultLambdaWithInvokeInterfaceTest.class;
+ final String EXPECTED = StringUtils.lines("4");
+
+ @Test
+ public void testJvm() throws Exception {
+ testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForD8()
+ .addProgramClassesAndInnerClasses(CLASS)
+ .setMinApi(AndroidApiLevel.K)
+ .compile()
+ // TODO(b/123506120): Add .assertNoMessages()
+ .run(CLASS)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
new file mode 100644
index 0000000..eb4e75b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
@@ -0,0 +1,23 @@
+// 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.desugar;
+
+public class DefaultLambdaWithSelfReferenceTest {
+
+ interface I {
+ String foo();
+
+ default I stateless() {
+ return () -> "stateless";
+ }
+
+ default I stateful() {
+ return () -> "stateful(" + stateless().foo() + ")";
+ }
+ }
+
+ public static void main(String[] args) {
+ System.out.println(((I) () -> "foo").stateful().foo());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
new file mode 100644
index 0000000..bc193c8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -0,0 +1,94 @@
+// 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.desugar;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.Disassemble;
+import com.android.tools.r8.Disassemble.DisassembleCommand;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class DefaultLambdaWithSelfReferenceTestRunner extends TestBase {
+
+ final Class<?> CLASS = DefaultLambdaWithSelfReferenceTest.class;
+ final String EXPECTED = StringUtils.lines("stateful(stateless)");
+
+ @Test
+ public void testJvm() throws Exception {
+ testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void test() throws Exception {
+ Path out1 = temp.newFolder().toPath().resolve("out1.zip");
+ testForD8()
+ .addProgramClassesAndInnerClasses(CLASS)
+ .setMinApi(AndroidApiLevel.K)
+ .compile()
+ // TODO(b/123506120): Add .assertNoMessages()
+ .writeToZip(out1)
+ .run(CLASS)
+ .assertSuccessWithOutput(EXPECTED);
+
+ Path outPerClassDir = temp.newFolder().toPath();
+ Collection<Path> innerClasses =
+ ToolHelper.getClassFilesForInnerClasses(Collections.singleton(CLASS));
+
+ int i = 0;
+ List<Path> outs = new ArrayList<>();
+ {
+ Path mainOut = outPerClassDir.resolve("class" + i++ + ".zip");
+ outs.add(mainOut);
+ testForD8()
+ .addProgramClasses(CLASS)
+ .addClasspathFiles(ToolHelper.getClassPathForTests())
+ .setIntermediate(true)
+ .setMinApi(AndroidApiLevel.K)
+ .compile()
+ // TODO(b/123506120): Add .assertNoMessages()
+ .writeToZip(mainOut);
+ }
+ for (Path innerClass : innerClasses) {
+ Path out = outPerClassDir.resolve("class" + i++ + ".zip");
+ outs.add(out);
+ testForD8()
+ .addProgramFiles(innerClass)
+ .addClasspathFiles(ToolHelper.getClassPathForTests())
+ .setIntermediate(true)
+ .setMinApi(AndroidApiLevel.K)
+ .compile()
+ // TODO(b/123506120): Add .assertNoMessages()
+ .writeToZip(out);
+ }
+
+ Path out2 = temp.newFolder().toPath().resolve("out2.zip");
+ testForD8()
+ .addProgramFiles(outs)
+ .compile()
+ // TODO(b/123506120): Add .assertNoMessages()
+ .writeToZip(out2)
+ .run(CLASS)
+ .assertSuccessWithOutput(EXPECTED);
+
+ Path dissasemble1 = temp.newFolder().toPath().resolve("disassemble1.txt");
+ Path dissasemble2 = temp.newFolder().toPath().resolve("disassemble2.txt");
+ Disassemble.disassemble(
+ DisassembleCommand.builder().addProgramFiles(out1).setOutputPath(dissasemble1).build());
+ Disassemble.disassemble(
+ DisassembleCommand.builder().addProgramFiles(out2).setOutputPath(dissasemble2).build());
+ String content1 = StringUtils.join(Files.readAllLines(dissasemble1), "\n");
+ String content2 = StringUtils.join(Files.readAllLines(dissasemble2), "\n");
+ assertEquals(content1, content2);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
index 5038729..e191921 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.shaking.desugar.interfacemethods;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -60,11 +59,9 @@
MethodSubject m = c.uniqueMethodWithName("m");
assertThat(m, isPresent());
assertTrue(m.getMethod().hasCode());
- // TODO(b/123778921): why are I and C not merged without merge annotations?
+ // TODO(b/124017330): Verify that I$-CC.m() has been inlined into C.m().
//assertTrue(
// m.iterateInstructions(i -> i.isConstString("I::m", JumboStringMode.ALLOW)).hasNext());
-
- // TODO(b/123778921): No companion class is in the output.
//codeInspector.forAllClasses(classSubject -> {
// assertFalse(classSubject.getOriginalDescriptor().contains("$-CC"));
//});
diff --git a/tools/apk_utils.py b/tools/apk_utils.py
index 5a6aa94..af24ec1 100644
--- a/tools/apk_utils.py
+++ b/tools/apk_utils.py
@@ -23,7 +23,8 @@
]
utils.RunCmd(cmd, quiet=quiet)
-def sign_with_apksigner(build_tools_dir, unsigned_apk, signed_apk, keystore, password):
+def sign_with_apksigner(
+ build_tools_dir, unsigned_apk, signed_apk, keystore, password, quiet=False):
cmd = [
os.path.join(build_tools_dir, 'apksigner'),
'sign',
@@ -34,5 +35,4 @@
'--out', signed_apk,
unsigned_apk
]
- utils.PrintCmd(cmd)
- subprocess.check_call(cmd)
+ utils.RunCmd(cmd, quiet=quiet)
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 3a9bf8c..1d8b04a 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -102,11 +102,9 @@
},
'tivi': {
'app_id': 'app.tivi',
- # Forked from https://github.com/chrisbanes/tivi.git removing
- # signingConfigs.
'git_repo': 'https://github.com/sgjesse/tivi.git',
- # TODO(123047413): Fails with R8.
- 'skip': True,
+ 'min_sdk': 23,
+ 'compile_sdk': 28,
},
'Tusky': {
'app_id': 'com.keylesspalace.tusky',
@@ -419,14 +417,13 @@
if options.sign_apks and not os.path.isfile(signed_apk):
assert os.path.isfile(unsigned_apk)
if options.sign_apks:
- keystore = 'app.keystore'
- keystore_password = 'android'
apk_utils.sign_with_apksigner(
utils.ANDROID_BUILD_TOOLS,
unsigned_apk,
signed_apk,
- keystore,
- keystore_password)
+ options.keystore,
+ options.keystore_password,
+ quiet=options.quiet)
if os.path.isfile(signed_apk):
apk_dest = os.path.join(out_dir, signed_apk_name)
@@ -587,6 +584,12 @@
result.add_option('--app',
help='What app to run on',
choices=APPS.keys())
+ result.add_option('--keystore',
+ help='Path to app.keystore',
+ default='app.keystore')
+ result.add_option('--keystore-password', '--keystore_password',
+ help='Password for app.keystore',
+ default='android')
result.add_option('--monkey',
help='Whether to install and run app(s) with monkey',
default=False,