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,