Merge "Centralize kotlin package name and prevent relocate"
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 908c4c5..b500296 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "1.4.20-dev";
+  public static final String LABEL = "1.4.21-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index ab56f30..4934336 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -956,6 +956,7 @@
     // This info is used by {@link UninstantiatedTypeOptimization#rewriteInvoke} that replaces an
     // invocation with null throwing code if an always-null argument is passed. Also used by Inliner
     // to give a credit to null-safe code, e.g., Kotlin's null safe argument.
+    // Note that this bit set takes into account the receiver for instance methods.
     private BitSet nonNullParamOrThrow = null;
     // Stores information about nullability facts per parameter. If set, that means, the method
     // somehow (e.g., null check, such as arg != null, or NPE-throwing instructions such as array
@@ -963,6 +964,7 @@
     // guaranteed until the normal exits. That is, if the invocation of this method is finished
     // normally, the recorded parameter is definitely not null. These facts are used to propagate
     // non-null information through {@link NonNullTracker}.
+    // Note that this bit set takes into account the receiver for instance methods.
     private BitSet nonNullParamOnNormalExits = null;
     private boolean reachabilitySensitive = false;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
index ad8edd3..14aad66 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Value;
 
 /**
@@ -346,24 +345,6 @@
     return appInfo.dexItemFactory.createReferenceTypeLatticeElement(type, isNullable, appInfo);
   }
 
-  public static TypeLatticeElement fromNumericType(NumericType type) {
-    switch (type) {
-      case BYTE:
-      case CHAR:
-      case SHORT:
-      case INT:
-        return INT;
-      case LONG:
-        return LONG;
-      case FLOAT:
-        return FLOAT;
-      case DOUBLE:
-        return DOUBLE;
-      default:
-        throw new Unreachable("Unexpected numeric type: " + type);
-    }
-  }
-
   public boolean isValueTypeCompatible(TypeLatticeElement other) {
     return (isReference() && other.isReference())
         || (isSingle() && other.isSingle())
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index 931a584..54567b5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -135,7 +136,7 @@
 
   @Override
   public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromNumericType(type);
+    return PrimitiveTypeLatticeElement.fromNumericType(type);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 8f32081..6e5e5d7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -155,12 +155,14 @@
     LoadStoreHelper loadStoreHelper = new LoadStoreHelper(code, typeVerificationHelper, appInfo);
     loadStoreHelper.insertLoadsAndStores();
     // Run optimizations on phis and basic blocks in a fixpoint.
-    PhiOptimizations phiOptimizations = new PhiOptimizations();
-    boolean reachedFixpoint = false;
-    phiOptimizations.optimize(code);
-    while (!reachedFixpoint) {
-      BasicBlockMuncher.optimize(code);
-      reachedFixpoint = !phiOptimizations.optimize(code);
+    if (!options.testing.disallowLoadStoreOptimization) {
+      PhiOptimizations phiOptimizations = new PhiOptimizations();
+      boolean reachedFixpoint = false;
+      phiOptimizations.optimize(code);
+      while (!reachedFixpoint) {
+        BasicBlockMuncher.optimize(code);
+        reachedFixpoint = !phiOptimizations.optimize(code);
+      }
     }
     registerAllocator = new CfRegisterAllocator(code, options, typeVerificationHelper);
     registerAllocator.allocateRegisters();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 8c16d04..4ecda95 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -1001,7 +1001,7 @@
 
     if (options.enableNonNullTracking && nonNullTracker != null) {
       // Computation of non-null parameters on normal exits rely on the existence of non-null IRs.
-      nonNullTracker.computeNonNullParamOnNormalExits(feedback, method, code);
+      nonNullTracker.computeNonNullParamOnNormalExits(feedback, code);
       nonNullTracker.cleanupNonNull(code);
       assert code.isConsistentSSA();
     }
@@ -1155,7 +1155,7 @@
 
   private void computeNonNullParamHints(
     OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
-    List<Value> arguments = code.collectArguments(true);
+    List<Value> arguments = code.collectArguments();
     BitSet paramsCheckedForNull = new BitSet();
     for (int index = 0; index < arguments.size(); index++) {
       Value argument = arguments.get(index);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index e08e9c4..41faa04 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -95,15 +95,11 @@
 
   private static ConstNumber createConstNumberReplacement(
       IRCode code, long constant, TypeLatticeElement typeLattice, DebugLocalInfo debugLocalInfo) {
-    ConstNumber replacement;
-    if (typeLattice.isReference()) {
-      assert constant == 0;
-      replacement = code.createConstNull();
-    } else {
-      Value returnedValue = code.createValue(typeLattice, debugLocalInfo);
-      replacement = new ConstNumber(returnedValue, constant);
-    }
-    return replacement;
+    assert !typeLattice.isReference() || constant == 0;
+    Value returnedValue =
+        code.createValue(
+            typeLattice.isReference() ? TypeLatticeElement.NULL : typeLattice, debugLocalInfo);
+    return new ConstNumber(returnedValue, constant);
   }
 
   private void setValueRangeFromProguardRule(ProguardMemberRule rule, Value value) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index b417c48..cbdeaac 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -124,9 +124,9 @@
               current.asInvokeMethod().lookupSingleTarget(appInfo, code.method.method.getHolder());
           if (singleTarget != null
               && singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits() != null) {
-            BitSet hints = singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits();
+            BitSet facts = singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits();
             for (int i = 0; i < current.inValues().size(); i++) {
-              if (hints.get(i)) {
+              if (facts.get(i)) {
                 Value knownToBeNonNullValue = current.inValues().get(i);
                 if (isNonNullCandidate(knownToBeNonNullValue)) {
                   knownToBeNonNullValues.add(knownToBeNonNullValue);
@@ -350,8 +350,7 @@
         && typeLattice.isReference();
   }
 
-  public void computeNonNullParamOnNormalExits(
-      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
+  public void computeNonNullParamOnNormalExits(OptimizationFeedback feedback, IRCode code) {
     Set<BasicBlock> normalExits = Sets.newIdentityHashSet();
     normalExits.addAll(code.computeNormalExitBlocks());
     DominatorTree dominatorTree = new DominatorTree(code, MAY_HAVE_UNREACHABLE_BLOCKS);
@@ -364,9 +363,10 @@
       if (!argument.getTypeLattice().isReference()) {
         continue;
       }
-      if (index == 0 && !method.accessFlags.isStatic()) {
-        // The receiver is always non-null after an invocation;
+      // The receiver is always non-null on normal exits.
+      if (argument.isThis()) {
         facts.set(index);
+        continue;
       }
       // Collect basic blocks that check nullability of the parameter.
       nullCheckedBlocks.clear();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index f9740c6..7966d3a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.Add;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -273,7 +274,7 @@
         inValues.add(
             builder.readRegister(register, ValueTypeConstraint.fromNumericType(numericType)));
       }
-      TypeLatticeElement latticeElement = TypeLatticeElement.fromNumericType(numericType);
+      TypeLatticeElement latticeElement = PrimitiveTypeLatticeElement.fromNumericType(numericType);
       Value outValue =
           builder.writeRegister(outline.argumentCount(), latticeElement, ThrowingInfo.CAN_THROW);
       Instruction newInstruction = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 74e9c6a..6a43c03 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -498,22 +498,17 @@
       return;
     }
 
-    BitSet nonNullParamHints = target.getOptimizationInfo().getNonNullParamOrThrow();
-    if (nonNullParamHints != null) {
-      int argumentIndex = target.isStatic() ? 0 : 1;
-      int nonNullParamHintIndex = 0;
-      while (argumentIndex < invoke.arguments().size()) {
-        Value argument = invoke.arguments().get(argumentIndex);
-        if (isAlwaysNull(argument) && nonNullParamHints.get(nonNullParamHintIndex)) {
+    BitSet facts = target.getOptimizationInfo().getNonNullParamOrThrow();
+    if (facts != null) {
+      for (int i = 0; i < invoke.arguments().size(); i++) {
+        Value argument = invoke.arguments().get(i);
+        if (isAlwaysNull(argument) && facts.get(i)) {
           replaceCurrentInstructionWithThrowNull(
               invoke, blockIterator, instructionIterator, code, blocksToBeRemoved);
           ++numberOfInvokesWithNullArgument;
           return;
         }
-        argumentIndex++;
-        nonNullParamHintIndex++;
       }
-      assert argumentIndex == nonNullParamHintIndex + (target.isStatic() ? 0 : 1);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 243a0ee..c0c6e59 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -529,6 +529,7 @@
     public boolean allowFailureOnInnerClassErrors = false;
     public boolean noLocalsTableOnInput = false;
     public boolean forceNameReflectionOptimization = false;
+    public boolean disallowLoadStoreOptimization = false;
   }
 
   private boolean hasMinApi(AndroidApiLevel level) {
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 3b5ddd8..e9d85be 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -76,6 +76,7 @@
       Collections.addAll(
           command,
           getJavaExecutable(),
+          "-ea",
           "-cp",
           r8jar.toAbsolutePath().toString(),
           R8.class.getTypeName(),
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 8276a06..cbd0cb9 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -58,7 +58,9 @@
       throws CompilationFailedException;
 
   public T addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
-    this.optionsConsumer = this.optionsConsumer.andThen(optionsConsumer);
+    if (optionsConsumer != null) {
+      this.optionsConsumer = this.optionsConsumer.andThen(optionsConsumer);
+    }
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/cf/TryRangeTest.java b/src/test/java/com/android/tools/r8/cf/TryRangeTest.java
new file mode 100644
index 0000000..08e01ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/TryRangeTest.java
@@ -0,0 +1,41 @@
+// 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.cf;
+
+import com.android.tools.r8.NeverInline;
+
+public class TryRangeTest {
+
+  @NeverInline
+  public static float doSomething(int x) throws Exception {
+    if (x == 42) {
+      throw new Exception("is 42");
+    } else {
+      return 1;
+    }
+  }
+
+  @NeverInline
+  public static void test(int count) {
+    int x = count;
+    float y;
+    if (x == 7) {
+      try {
+        y = doSomething(x);
+      } catch (Exception e) {
+        System.out.println(x);
+        return;
+      }
+    } else {
+      System.out.println(x);
+      y = 7;
+    }
+    System.out.println(y);
+  }
+
+  public static void main(String[] args) {
+    test(10);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
new file mode 100644
index 0000000..98542ff
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
@@ -0,0 +1,33 @@
+// 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.cf;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.TestBase;
+import org.junit.Test;
+
+/**
+ * This tests that we produce valid code when having normal-flow with exceptional edges in blocks.
+ * We might perform optimizations that add operations (dup, swap, etc.) before and after
+ * instructions that lie on the boundary of the exception table that is generated for a basic block.
+ * If live-ranges are minimized this could produce VerifyErrors. TODO(b/119771771) Will fail if
+ * shorten live ranges without shorten exception table range.
+ */
+public class TryRangeTestRunner extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    testForR8(Backend.CF)
+        .addProgramClasses(TryRangeTest.class)
+        .addKeepMainRule(TryRangeTest.class)
+        .setMode(CompilationMode.RELEASE)
+        .minification(false)
+        .noTreeShaking()
+        .enableInliningAnnotations()
+        .addOptionsModification(o -> o.testing.disallowLoadStoreOptimization = true)
+        .run(TryRangeTest.class)
+        .assertSuccess();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
index 83dbd9e..04477bd 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
@@ -9,6 +9,7 @@
 
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.DebuggeeState;
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.FrameInspector;
+import com.android.tools.r8.debug.DebugTestConfig.RuntimeKind;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringUtils;
@@ -288,8 +289,10 @@
     String sig = reference.getMethodSignature();
     List<Variable> variables = reference.getVisibleVariables();
     int frameDepth = reference.getFrameDepth();
+    RuntimeKind referenceRuntime = reference.getConfig().getRuntimeKind();
     for (int i = 1; i < states.size(); i++) {
       DebuggeeState state = states.get(i);
+      RuntimeKind stateRuntime = state.getConfig().getRuntimeKind();
       if (verifyFiles) {
         assertEquals("source file mismatch", file, state.getSourceFile());
       }
@@ -304,7 +307,11 @@
             "method mismatch", method + sig, state.getMethodName() + state.getMethodSignature());
       }
       if (verifyVariables) {
-        verifyVariablesEqual(variables, state.getVisibleVariables());
+        verifyVariablesEqual(
+            referenceRuntime,
+            reference.getVisibleVariables(),
+            stateRuntime,
+            state.getVisibleVariables());
       }
       if (verifyStack) {
         assertEquals(frameDepth, state.getFrameDepth());
@@ -312,20 +319,33 @@
           FrameInspector referenceInspector = reference.getFrame(j);
           FrameInspector stateInspector = state.getFrame(j);
           verifyVariablesEqual(
-              referenceInspector.getVisibleVariables(), stateInspector.getVisibleVariables());
+              referenceRuntime,
+              referenceInspector.getVisibleVariables(),
+              stateRuntime,
+              stateInspector.getVisibleVariables());
         }
       }
     }
   }
 
-  private static void verifyVariablesEqual(List<Variable> xs, List<Variable> ys) {
+  private static boolean shouldIgnoreVariable(Variable variable, RuntimeKind runtime) {
+    return runtime == RuntimeKind.DEX && variable.getName().isEmpty();
+  }
+
+  private static void verifyVariablesEqual(
+      RuntimeKind xRuntime, List<Variable> xs, RuntimeKind yRuntime, List<Variable> ys) {
     Map<String, Variable> map = new HashMap<>(xs.size());
     for (Variable x : xs) {
-      map.put(x.getName(), x);
+      if (!shouldIgnoreVariable(x, xRuntime)) {
+        map.put(x.getName(), x);
+      }
     }
     List<Variable> unexpected = new ArrayList<>(ys.size());
     List<Pair<Variable, Variable>> different = new ArrayList<>(Math.min(xs.size(), ys.size()));
     for (Variable y : ys) {
+      if (shouldIgnoreVariable(y, yRuntime)) {
+        continue;
+      }
       Variable x = map.remove(y.getName());
       if (x == null) {
         unexpected.add(y);
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index 099f55b..17d5077 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -81,8 +81,7 @@
 
   @Test
   public void testBridgeMethod() throws Exception {
-    // TODO(b/79671093): D8 has local variables with empty names.
-    testDebuggingJvmOnly("bridge", "BridgeMethod");
+    testDebugging("bridge", "BridgeMethod");
   }
 
   @Test
@@ -107,8 +106,7 @@
 
   @Test
   public void testFloatingPointValuedAnnotation() throws Exception {
-    // D8 has no source file.
-    testDebuggingJvmOnly("floating_point_annotations", "FloatingPointValuedAnnotationTest");
+    testDebugging("floating_point_annotations", "FloatingPointValuedAnnotationTest");
   }
 
   @Test
@@ -190,14 +188,14 @@
 
   @Test
   public void testSync() throws Exception {
-    // D8 has two local variables with empty names.
+    // TODO(b/79671093): Line number mismatch in D8.
     testDebuggingJvmOnly("sync", "Sync");
   }
 
   @Test
   public void testThrowing() throws Exception {
-    // TODO(b/79671093): We don't match JVM's behavior on this example.
-    testDebuggingJvmOutputOnly("throwing", "Throwing");
+    // TODO(b/79671093): D8 has unexpected variables (this in throwing.c <init>).
+    testDebuggingJvmOnly("throwing", "Throwing");
   }
 
   @Test
@@ -205,11 +203,9 @@
     testDebugging("trivial", "Trivial");
   }
 
-  @Ignore("TODO(mathiasr): InvalidDebugInfoException in CfSourceCode")
   @Test
   public void testTryCatch() throws Exception {
-    // TODO(b/79671093): We don't match JVM's behavior on this example.
-    testDebuggingJvmOutputOnly("trycatch", "TryCatch");
+    testDebugging("trycatch", "TryCatch");
   }
 
   @Test
@@ -259,8 +255,7 @@
 
   @Test
   public void testRegress62300145() throws Exception {
-    // D8 has no source file.
-    testDebuggingJvmOnly("regress_62300145", "Regress");
+    testDebugging("regress_62300145", "Regress");
   }
 
   @Test
@@ -281,21 +276,17 @@
 
   @Test
   public void testRegress70736958() throws Exception {
-    // D8 has a local variable with empty name.
-    testDebuggingJvmOnly("regress_70736958", "Test");
+    testDebugging("regress_70736958", "Test");
   }
 
-  @Ignore("TODO(mathiasr): Different behavior CfSourceCode vs JarSourceCode")
   @Test
   public void testRegress70737019() throws Exception {
-    // TODO(b/79671093): We don't match JVM's behavior on this example.
-    testDebuggingJvmOutputOnly("regress_70737019", "Test");
+    testDebugging("regress_70737019", "Test");
   }
 
   @Test
   public void testRegress72361252() throws Exception {
-    // D8 output has variable with empty name.
-    testDebuggingJvmOnly("regress_72361252", "Test");
+    testDebugging("regress_72361252", "Test");
   }
 
   @Test
@@ -341,6 +332,8 @@
         .add("R8/CfSourceCode", r8cf())
         .add("R8/JarSourceCode", r8jar())
         .add("D8", d8())
+        // When running on CF and DEX runtimes, filter down to states within the test package.
+        .setFilter(state -> state.getClassName().startsWith(pkg))
         .compare();
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index 518ea8d..44497b5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -46,8 +46,6 @@
     this.backend = backend;
   }
 
-  private void noModification(InternalOptions options) {}
-
   private void disableDevirtualization(InternalOptions options) {
     options.enableDevirtualization = false;
   }
@@ -67,8 +65,9 @@
         .enableMergeAnnotations()
         .addKeepMainRule(mainClass)
         .addKeepRules(
-            ImmutableList.of(
-                "-keepattributes InnerClasses,Signature,EnclosingMethod", "-dontobfuscate"))
+            ImmutableList.of("-keepattributes InnerClasses,Signature,EnclosingMethod"))
+        // All tests are checking if invocations to certain null-check utils are gone.
+        .noMinification()
         .addOptionsModification(
             options -> {
               // Need to increase a little bit to inline System.out.println
@@ -82,34 +81,31 @@
 
   @Test
   public void testIntrinsics() throws Exception {
-    Class mainClass = IntrinsicsDeputy.class;
+    Class<?> mainClass = IntrinsicsDeputy.class;
     CodeInspector inspector =
-        buildAndRun(
-            mainClass, ImmutableList.of(NeverInline.class, mainClass), this::noModification);
+        buildAndRun(mainClass, ImmutableList.of(NeverInline.class, mainClass), null);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
 
-    MethodSubject selfCheck = mainSubject.method("void", "selfCheck", ImmutableList.of());
+    MethodSubject selfCheck = mainSubject.uniqueMethodWithName("selfCheck");
     assertThat(selfCheck, isPresent());
     assertEquals(1, countCallToParamNullCheck(selfCheck));
     assertEquals(1, countPrintCall(selfCheck));
     assertEquals(0, countThrow(selfCheck));
 
-    MethodSubject checkNull = mainSubject.method("void", "checkNull", ImmutableList.of());
+    MethodSubject checkNull = mainSubject.uniqueMethodWithName("checkNull");
     assertThat(checkNull, isPresent());
     assertEquals(1, countCallToParamNullCheck(checkNull));
     assertEquals(1, countPrintCall(checkNull));
     assertEquals(0, countThrow(checkNull));
 
-    MethodSubject paramCheck =
-        mainSubject.method("void", "nonNullAfterParamCheck", ImmutableList.of());
+    MethodSubject paramCheck = mainSubject.uniqueMethodWithName("nonNullAfterParamCheck");
     assertThat(paramCheck, isPresent());
     assertEquals(1, countPrintCall(paramCheck));
     assertEquals(0, countThrow(paramCheck));
 
-    paramCheck = mainSubject.method(
-        "void", "nonNullAfterParamCheckDifferently", ImmutableList.of());
+    paramCheck = mainSubject.uniqueMethodWithName("nonNullAfterParamCheckDifferently");
     assertThat(paramCheck, isPresent());
     assertEquals(1, countPrintCall(paramCheck));
     assertEquals(0, countThrow(paramCheck));
@@ -123,26 +119,22 @@
             mainClass,
             ImmutableList.of(
                 NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
-            this::noModification);
+            null);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
 
-    String argTypeName = NotPinnedClass.class.getName();
-    MethodSubject checkViaCall =
-        mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
+    MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
     assertEquals(2, countPrintCall(checkViaCall));
 
-    MethodSubject checkViaIntrinsic =
-        mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(argTypeName));
+    MethodSubject checkViaIntrinsic = mainSubject.uniqueMethodWithName("checkViaIntrinsic");
     assertThat(checkViaIntrinsic, isPresent());
     assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
     assertEquals(1, countPrintCall(checkViaIntrinsic));
 
-    MethodSubject checkAtOneLevelHigher =
-        mainSubject.method("void", "checkAtOneLevelHigher", ImmutableList.of(argTypeName));
+    MethodSubject checkAtOneLevelHigher = mainSubject.uniqueMethodWithName("checkAtOneLevelHigher");
     assertThat(checkAtOneLevelHigher, isPresent());
     assertEquals(1, countPrintCall(checkAtOneLevelHigher));
     assertEquals(0, countThrow(checkAtOneLevelHigher));
@@ -156,26 +148,22 @@
             mainClass,
             ImmutableList.of(
                 NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
-            this::noModification);
+            null);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
 
-    String argTypeName = NotPinnedClass.class.getName();
-    MethodSubject checkViaCall =
-        mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
+    MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
     assertEquals(2, countPrintCall(checkViaCall));
 
-    MethodSubject checkViaIntrinsic =
-        mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(argTypeName));
+    MethodSubject checkViaIntrinsic = mainSubject.uniqueMethodWithName("checkViaIntrinsic");
     assertThat(checkViaIntrinsic, isPresent());
     assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
     assertEquals(1, countPrintCall(checkViaIntrinsic));
 
-    MethodSubject checkAtOneLevelHigher =
-        mainSubject.method("void", "checkAtOneLevelHigher", ImmutableList.of(argTypeName));
+    MethodSubject checkAtOneLevelHigher = mainSubject.uniqueMethodWithName("checkAtOneLevelHigher");
     assertThat(checkAtOneLevelHigher, isPresent());
     assertEquals(1, countPrintCall(checkAtOneLevelHigher));
     assertEquals(0, countThrow(checkAtOneLevelHigher));
@@ -193,26 +181,22 @@
                 NonNullParamAfterInvokeVirtual.class,
                 NotPinnedClass.class,
                 mainClass),
-            this::noModification);
+            null);
 
     ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeVirtual.class);
     assertThat(mainSubject, isPresent());
 
-    String argTypeName = NotPinnedClass.class.getName();
-    MethodSubject checkViaCall =
-        mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
+    MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
     assertEquals(2, countPrintCall(checkViaCall));
 
-    MethodSubject checkViaIntrinsic =
-        mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(argTypeName));
+    MethodSubject checkViaIntrinsic = mainSubject.uniqueMethodWithName("checkViaIntrinsic");
     assertThat(checkViaIntrinsic, isPresent());
     assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
     assertEquals(1, countPrintCall(checkViaIntrinsic));
 
-    MethodSubject checkAtOneLevelHigher =
-        mainSubject.method("void", "checkAtOneLevelHigher", ImmutableList.of(argTypeName));
+    MethodSubject checkAtOneLevelHigher = mainSubject.uniqueMethodWithName("checkAtOneLevelHigher");
     assertThat(checkAtOneLevelHigher, isPresent());
     assertEquals(1, countPrintCall(checkAtOneLevelHigher));
     assertEquals(0, countThrow(checkAtOneLevelHigher));
@@ -237,12 +221,7 @@
     ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeInterface.class);
     assertThat(mainSubject, isPresent());
 
-    String argTypeName = NotPinnedClass.class.getName();
-    MethodSubject checkViaCall =
-        mainSubject.method(
-            "void",
-            "checkViaCall",
-            ImmutableList.of(NonNullParamInterface.class.getName(), argTypeName, argTypeName));
+    MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
     // The DEX backend reuses the System.out.println invoke.
diff --git a/src/test/java/com/android/tools/r8/regress/b120164595/B120164595.java b/src/test/java/com/android/tools/r8/regress/b120164595/B120164595.java
new file mode 100644
index 0000000..08e86e6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b120164595/B120164595.java
@@ -0,0 +1,79 @@
+// 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.regress.b120164595;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.Test;
+
+/**
+ * Regression test for art issue with multi catch-handlers.
+ * The problem is that if d8/r8 creates the same target address for two different exceptions,
+ * art will use that address to check if it was already handled.
+ */
+class TestClass {
+  public static void main(String[] args) {
+    for (int i = 0; i < 20000; i++) {
+      toBeOptimized();
+    }
+  }
+
+  private static void toBeOptimized() {
+    try {
+      willThrow();
+    } catch (IllegalStateException | NullPointerException e) {
+      if (e instanceof NullPointerException) {
+        return;
+      }
+      throw new Error("Expected NullPointerException");
+    }
+  }
+
+  private static void willThrow() {
+    throw new NullPointerException();
+  }
+}
+
+public class B120164595 extends TestBase {
+  @Test
+  public void testD8()
+      throws IOException, CompilationFailedException {
+    TestCompileResult d8Result = testForD8().addProgramClasses(TestClass.class).compile();
+    checkArt(d8Result);
+  }
+
+  @Test
+  public void testR8()
+      throws IOException, CompilationFailedException {
+    TestCompileResult r8Result = testForR8(Backend.DEX)
+        .addProgramClasses(TestClass.class)
+        .addKeepClassAndMembersRules(TestClass.class)
+        .compile();
+    checkArt(r8Result);
+  }
+
+  private void checkArt(TestCompileResult result) throws IOException {
+    ProcessResult artResult = runOnArtRaw(
+        result.app,
+        TestClass.class.getCanonicalName(),
+        builder -> {
+          builder.appendArtOption("-Xusejit:true");
+        },
+        DexVm.ART_9_0_0_HOST
+    );
+    // TODO(120164595): Remove when workaround lands.
+    assertNotEquals(artResult.exitCode, 0);
+    assertTrue(artResult.stderr.contains("Expected NullPointerException"));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java b/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java
index 94c9896..9f2488e 100644
--- a/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertThat;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.base.Charsets;
@@ -84,7 +85,11 @@
                 "}")));
     assertThat(
         proguardConfigOut,
-        containsString("-printconfiguration " + proguardConfigOutFile.toAbsolutePath().toString()));
+        containsString(
+            "-printconfiguration "
+                + (ToolHelper.isWindows()
+                    ? ("'" + proguardConfigOutFile.toAbsolutePath().toString() + "'")
+                    : proguardConfigOutFile.toAbsolutePath().toString())));
   }
 
   @Test
diff --git a/tools/historic_memory_usage.py b/tools/historic_memory_usage.py
index fec7b31..f23faaa 100755
--- a/tools/historic_memory_usage.py
+++ b/tools/historic_memory_usage.py
@@ -16,6 +16,7 @@
 import sys
 import utils
 
+MASTER_COMMITS = 'gs://r8-releases/raw/master'
 APPS = ['gmscore', 'nest', 'youtube', 'gmail', 'chrome']
 COMPILERS = ['d8', 'r8']
 
@@ -41,8 +42,9 @@
 
 
 class GitCommit(object):
-  def __init__(self, git_hash, destination, timestamp):
+  def __init__(self, git_hash, destination_dir, destination, timestamp):
     self.git_hash = git_hash
+    self.destination_dir = destination_dir
     self.destination = destination
     self.timestamp = timestamp
 
@@ -56,8 +58,9 @@
   commit_timestamp = subprocess.check_output(['git', 'show', '--no-patch',
                                          '--no-notes', '--pretty=\'%ct\'',
                                          hash]).strip().strip('\'')
-  destination = 'gs://r8-releases/raw/master/%s/r8.jar' % hash
-  commit = GitCommit(hash, destination, commit_timestamp)
+  destination_dir = '%s/%s/' % (MASTER_COMMITS, hash)
+  destination = '%s%s' % (destination_dir, 'r8.jar')
+  commit = GitCommit(hash, destination_dir, destination, commit_timestamp)
   return commit
 
 def enumerate_git_commits(options):
@@ -79,9 +82,10 @@
   return commits
 
 def get_available_commits(commits):
+  cloud_commits = subprocess.check_output(['gsutil.py', 'ls', MASTER_COMMITS]).splitlines()
   available_commits = []
   for commit in commits:
-    if utils.cloud_storage_exists(commit.destination):
+    if commit.destination_dir in cloud_commits:
       available_commits.append(commit)
   return available_commits
 
@@ -119,7 +123,7 @@
   app = options.app
   compiler = options.compiler
   cmd = ['tools/run_on_app.py', '--app', app, '--compiler', compiler,
-         '--find-min-xmx']
+         '--no-build', '--find-min-xmx']
   stdout = subprocess.check_output(cmd)
   output_path = options.output or 'build'
   time_commit = '%s_%s' % (commit.timestamp, commit.git_hash)
@@ -134,8 +138,14 @@
 
 def benchmark(commits, options):
   commit_permutations = permutate(len(commits))
+  count = 0
   for index in commit_permutations:
+    count += 1
+    print('Running commit %s out of %s' % (count, len(commits)))
     commit = commits[index]
+    if not utils.cloud_storage_exists(commit.destination):
+      # We may have a directory, but no r8.jar
+      continue
     pull_r8_from_cloud(commit)
     print('Running for commit: %s' % commit.git_hash)
     run_on_app(options, commit)
@@ -148,7 +158,6 @@
   available_commits = get_available_commits(commits)
   print('Running for:')
   print_commits(available_commits)
-  print('')
   benchmark(available_commits, options)
 
 if __name__ == '__main__':
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 8f37f43..56ea215 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -117,7 +117,7 @@
   return subprocess.check_output(['git', 'clone', git_url]).strip()
 
 def GitPull():
-  return subprocess.check_output(['git', 'pull']).strip()
+  return subprocess.call(['git', 'pull']) == 0
 
 def GitCheckout(file):
   return subprocess.check_output(['git', 'checkout', file]).strip()
@@ -153,19 +153,34 @@
     else:
       return
 
-def BuildAppWithSelectedShrinkers(app, config, options):
+def GetResultsForApp(app, config, options):
   git_repo = config['git_repo']
 
   # Checkout and build in the build directory.
   checkout_dir = os.path.join(WORKING_DIR, app)
 
+  result = {}
+
   if not os.path.exists(checkout_dir):
     with utils.ChangedWorkingDirectory(WORKING_DIR):
       GitClone(git_repo)
   else:
     with utils.ChangedWorkingDirectory(checkout_dir):
-      GitPull()
+      if not GitPull():
+        result['status'] = 'failed'
+        result['error_message'] = 'Unable to pull from remote'
+        return result
 
+  result['status'] = 'success'
+
+  result_per_shrinker = BuildAppWithSelectedShrinkers(
+      app, config, options, checkout_dir)
+  for shrinker, shrinker_result in result_per_shrinker.iteritems():
+    result[shrinker] = shrinker_result
+
+  return result
+
+def BuildAppWithSelectedShrinkers(app, config, options, checkout_dir):
   result_per_shrinker = {}
 
   with utils.ChangedWorkingDirectory(checkout_dir):
@@ -292,6 +307,12 @@
 def LogResults(result_per_shrinker_per_app, options):
   for app, result_per_shrinker in result_per_shrinker_per_app.iteritems():
     print(app + ':')
+
+    if result_per_shrinker.get('status') != 'success':
+      error_message = result_per_shrinker.get('error_message')
+      print('  skipped ({})'.format(error_message))
+      continue
+
     baseline = result_per_shrinker.get('proguard', {}).get('dex_size', -1)
     for shrinker, result in result_per_shrinker.iteritems():
       build_status = result.get('build_status')
@@ -355,12 +376,12 @@
   result_per_shrinker_per_app = {}
 
   if options.app:
-    result_per_shrinker_per_app[options.app] = BuildAppWithSelectedShrinkers(
+    result_per_shrinker_per_app[options.app] = GetResultsForApp(
         options.app, APPS.get(options.app), options)
   else:
     for app, config in APPS.iteritems():
       if not config.get('skip', False):
-        result_per_shrinker_per_app[app] = BuildAppWithSelectedShrinkers(
+        result_per_shrinker_per_app[app] = GetResultsForApp(
             app, config, options)
 
   LogResults(result_per_shrinker_per_app, options)