Merge "Add a method for dumping disassembly in tests"
diff --git a/build.gradle b/build.gradle
index 2e70b1e..e469e03 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1199,10 +1199,10 @@
         kotlin.Kotlinc.KotlinTargetVersion.values().each { kotlinTargetVersion ->
             def name = dir.getName()
             def taskName = "jar_kotlinR8TestResources_${name}_${kotlinTargetVersion}"
-            def outputFile = "build/test/r8KotlinTestResources/${kotlinTargetVersion}/${name}.jar"
-            def javaOutput = "build/test/r8KotlinTestResources/${kotlinTargetVersion}/${name}/java"
+            def outputFile = "build/test/kotlinR8TestResources/${kotlinTargetVersion}/${name}.jar"
+            def javaOutput = "build/test/kotlinR8TestResources/${kotlinTargetVersion}/${name}/java"
             def javaOutputJarName = "${name}.java.jar"
-            def javaOutputJarDir = "build/test/r8KotlinTestResources/${kotlinTargetVersion}"
+            def javaOutputJarDir = "build/test/kotlinR8TestResources/${kotlinTargetVersion}"
             task "${taskName}Kotlin"(type: kotlin.Kotlinc) {
                 source = fileTree(dir: file("${examplesDir}/${name}"),
                         include: ['**/*.kt', '**/*.java'])
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 737ab05..72e2887 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
@@ -943,10 +943,16 @@
     if (options.disableAssertions) {
       codeRewriter.disableAssertions(appInfo, method, code, feedback);
     }
+
+    previous = printMethod(code, "IR after disable assertions (SSA)", previous);
+
     if (options.enableNonNullTracking && nonNullTracker != null) {
       nonNullTracker.addNonNull(code);
       assert code.isConsistentSSA();
     }
+
+    previous = printMethod(code, "IR after null tracking (SSA)", previous);
+
     if (!isDebugMode && options.enableInlining && inliner != null) {
       // TODO(zerny): Should we support inlining in debug mode? b/62937285
       inliner.performInlining(method, code, isProcessedConcurrently, callSiteInformation);
@@ -1000,7 +1006,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, code);
+      nonNullTracker.computeNonNullParamOnNormalExits(feedback, method, code);
       nonNullTracker.cleanupNonNull(code);
       assert code.isConsistentSSA();
     }
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 463b7fc..2094584 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
@@ -119,7 +119,7 @@
             knownToBeNonNullValues.add(knownToBeNonNullValue);
           }
         }
-        if (current.isInvokeMethod()) {
+        if (current.isInvokeMethod() && !current.isInvokePolymorphic()) {
           DexEncodedMethod singleTarget =
               current.asInvokeMethod().lookupSingleTarget(appInfo, code.method.method.getHolder());
           if (singleTarget != null
@@ -350,11 +350,12 @@
         && typeLattice.isReference();
   }
 
-  public void computeNonNullParamOnNormalExits(OptimizationFeedback feedback, IRCode code) {
+  public void computeNonNullParamOnNormalExits(
+      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
     Set<BasicBlock> normalExits = Sets.newIdentityHashSet();
     normalExits.addAll(code.computeNormalExitBlocks());
     DominatorTree dominatorTree = new DominatorTree(code, MAY_HAVE_UNREACHABLE_BLOCKS);
-    List<Value> arguments = code.collectArguments(true);
+    List<Value> arguments = code.collectArguments();
     BitSet facts = new BitSet();
     Set<BasicBlock> nullCheckedBlocks = Sets.newIdentityHashSet();
     for (int index = 0; index < arguments.size(); index++) {
@@ -363,6 +364,10 @@
       if (!argument.getTypeLattice().isReference()) {
         continue;
       }
+      if (index == 0 && !method.accessFlags.isStatic()) {
+        // The receiver is always non-null after an invocation;
+        facts.set(index);
+      }
       // Collect basic blocks that check nullability of the parameter.
       nullCheckedBlocks.clear();
       for (Instruction user : argument.uniqueUsers()) {
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 63dd265..9139583 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -9,9 +9,7 @@
 import java.nio.file.Paths;
 
 public abstract class KotlinTestBase extends TestBase {
-  // It is important that Kotlin is capitalized, otherwise the string will be relocated when
-  // building tests for r8lib with relocated dependencies.
-  private static final String RSRC = "r8KotlinTestResources";
+  private static final String RSRC = "kotlinR8TestResources";
 
   protected final KotlinTargetVersion targetVersion;
 
@@ -19,21 +17,18 @@
     this.targetVersion = targetVersion;
   }
 
-  protected static Path getKotlinJarFile(String folder, KotlinTargetVersion targetVersion) {
+  protected Path getKotlinJarFile(String folder) {
     return Paths.get(ToolHelper.TESTS_BUILD_DIR, RSRC,
         targetVersion.getFolderName(), folder + FileUtils.JAR_EXTENSION);
   }
 
-  protected Path getKotlinJarFile(String folder) {
-    return getKotlinJarFile(folder, targetVersion);
-  }
-
-  protected static Path getJavaJarFile(String folder, KotlinTargetVersion targetVersion) {
+  protected Path getJavaJarFile(String folder) {
     return Paths.get(ToolHelper.TESTS_BUILD_DIR, RSRC,
         targetVersion.getFolderName(), folder + ".java" + FileUtils.JAR_EXTENSION);
   }
 
-  protected Path getJavaJarFile(String folder) {
-    return getJavaJarFile(folder, targetVersion);
+  protected Path getMappingfile(String folder, String mappingFileName) {
+    return Paths.get(ToolHelper.TESTS_DIR, RSRC, folder, mappingFileName);
   }
+
 }
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 5692a55..10b9a63 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
@@ -10,7 +10,16 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ir.optimize.nonnull.IntrinsicsDeputy;
-import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvoke;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeDirect;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeInterface;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeInterfaceMain;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeStatic;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeVirtual;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamAfterInvokeVirtualMain;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterface;
+import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterfaceImpl;
+import com.android.tools.r8.ir.optimize.nonnull.NotPinnedClass;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -18,6 +27,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Streams;
 import java.util.Collection;
+import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -36,22 +46,35 @@
     this.backend = backend;
   }
 
-  CodeInspector buildAndRun(Class<?> mainClass, Collection<Class<?>> classes) throws Exception {
+  private void noModification(InternalOptions options) {}
+
+  private void disableDevirtualization(InternalOptions options) {
+    options.enableDevirtualization = false;
+  }
+
+  CodeInspector buildAndRun(
+      Class<?> mainClass,
+      Collection<Class<?>> classes,
+      Consumer<InternalOptions> optionsModification)
+      throws Exception {
     String javaOutput = runOnJava(mainClass);
 
     return testForR8(backend)
         .addProgramClasses(classes)
         .enableProguardTestOptions()
         .enableInliningAnnotations()
+        .enableClassInliningAnnotations()
+        .enableMergeAnnotations()
         .addKeepMainRule(mainClass)
         .addKeepRules(
             ImmutableList.of(
-                "-keepattributes InnerClasses,Signature,EnclosingMethod",
-                "-dontobfuscate"))
-        .addOptionsModification(options -> {
-          // Need to increase a little bit to inline System.out.println
-          options.inliningInstructionLimit = 4;
-        })
+                "-keepattributes InnerClasses,Signature,EnclosingMethod", "-dontobfuscate"))
+        .addOptionsModification(
+            options -> {
+              // Need to increase a little bit to inline System.out.println
+              options.inliningInstructionLimit = 4;
+            })
+        .addOptionsModification(optionsModification)
         .run(mainClass)
         .assertSuccessWithOutput(javaOutput)
         .inspector();
@@ -60,8 +83,9 @@
   @Test
   public void testIntrinsics() throws Exception {
     Class mainClass = IntrinsicsDeputy.class;
-    CodeInspector inspector = buildAndRun(mainClass,
-        ImmutableList.of(NeverInline.class, mainClass));
+    CodeInspector inspector =
+        buildAndRun(
+            mainClass, ImmutableList.of(NeverInline.class, mainClass), this::noModification);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
@@ -92,21 +116,23 @@
   }
 
   @Test
-  public void testNonNullParamAfterInvoke() throws Exception {
-    Class mainClass = NonNullParamAfterInvoke.class;
-    CodeInspector inspector = buildAndRun(mainClass, ImmutableList.of(
-        NeverInline.class,
-        IntrinsicsDeputy.class,
-        NonNullParamAfterInvoke.NotPinnedClass.class,
-        mainClass));
+  public void testNonNullParamAfterInvokeStatic() throws Exception {
+    Class<?> mainClass = NonNullParamAfterInvokeStatic.class;
+    CodeInspector inspector =
+        buildAndRun(
+            mainClass,
+            ImmutableList.of(
+                NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+            this::noModification);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
 
-    String argTypeName = NonNullParamAfterInvoke.NotPinnedClass.class.getName();
+    String argTypeName = NotPinnedClass.class.getName();
     MethodSubject checkViaCall =
         mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
     assertThat(checkViaCall, isPresent());
+    assertEquals(0, countActCall(checkViaCall));
     assertEquals(2, countPrintCall(checkViaCall));
 
     MethodSubject checkViaIntrinsic =
@@ -122,6 +148,107 @@
     assertEquals(0, countThrow(checkAtOneLevelHigher));
   }
 
+  @Test
+  public void testNonNullParamAfterInvokeDirect() throws Exception {
+    Class<?> mainClass = NonNullParamAfterInvokeDirect.class;
+    CodeInspector inspector =
+        buildAndRun(
+            mainClass,
+            ImmutableList.of(
+                NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+            this::noModification);
+
+    ClassSubject mainSubject = inspector.clazz(mainClass);
+    assertThat(mainSubject, isPresent());
+
+    String argTypeName = NotPinnedClass.class.getName();
+    MethodSubject checkViaCall =
+        mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
+    assertThat(checkViaCall, isPresent());
+    assertEquals(0, countActCall(checkViaCall));
+    assertEquals(2, countPrintCall(checkViaCall));
+
+    MethodSubject checkViaIntrinsic =
+        mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(argTypeName));
+    assertThat(checkViaIntrinsic, isPresent());
+    assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
+    assertEquals(1, countPrintCall(checkViaIntrinsic));
+
+    MethodSubject checkAtOneLevelHigher =
+        mainSubject.method("void", "checkAtOneLevelHigher", ImmutableList.of(argTypeName));
+    assertThat(checkAtOneLevelHigher, isPresent());
+    assertEquals(1, countPrintCall(checkAtOneLevelHigher));
+    assertEquals(0, countThrow(checkAtOneLevelHigher));
+  }
+
+  @Test
+  public void testNonNullParamAfterInvokeVirtual() throws Exception {
+    Class<?> mainClass = NonNullParamAfterInvokeVirtualMain.class;
+    CodeInspector inspector =
+        buildAndRun(
+            mainClass,
+            ImmutableList.of(
+                NeverInline.class,
+                IntrinsicsDeputy.class,
+                NonNullParamAfterInvokeVirtual.class,
+                NotPinnedClass.class,
+                mainClass),
+            this::noModification);
+
+    ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeVirtual.class);
+    assertThat(mainSubject, isPresent());
+
+    String argTypeName = NotPinnedClass.class.getName();
+    MethodSubject checkViaCall =
+        mainSubject.method("void", "checkViaCall", ImmutableList.of(argTypeName, argTypeName));
+    assertThat(checkViaCall, isPresent());
+    assertEquals(0, countActCall(checkViaCall));
+    assertEquals(2, countPrintCall(checkViaCall));
+
+    MethodSubject checkViaIntrinsic =
+        mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(argTypeName));
+    assertThat(checkViaIntrinsic, isPresent());
+    assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
+    assertEquals(1, countPrintCall(checkViaIntrinsic));
+
+    MethodSubject checkAtOneLevelHigher =
+        mainSubject.method("void", "checkAtOneLevelHigher", ImmutableList.of(argTypeName));
+    assertThat(checkAtOneLevelHigher, isPresent());
+    assertEquals(1, countPrintCall(checkAtOneLevelHigher));
+    assertEquals(0, countThrow(checkAtOneLevelHigher));
+  }
+
+  @Test
+  public void testNonNullParamAfterInvokeInterface() throws Exception {
+    Class<?> mainClass = NonNullParamAfterInvokeInterfaceMain.class;
+    CodeInspector inspector =
+        buildAndRun(
+            mainClass,
+            ImmutableList.of(
+                NeverInline.class,
+                IntrinsicsDeputy.class,
+                NonNullParamInterface.class,
+                NonNullParamInterfaceImpl.class,
+                NonNullParamAfterInvokeInterface.class,
+                NotPinnedClass.class,
+                mainClass),
+            this::disableDevirtualization);
+
+    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));
+    assertThat(checkViaCall, isPresent());
+    assertEquals(0, countActCall(checkViaCall));
+    // The DEX backend reuses the System.out.println invoke.
+    assertEquals(backend == Backend.CF ? 2 : 1, countPrintCall(checkViaCall));
+  }
+
   private long countCallToParamNullCheck(MethodSubject method) {
     return countCall(method, IntrinsicsDeputy.class.getSimpleName(), "checkParameterIsNotNull");
   }
@@ -130,6 +257,10 @@
     return countCall(method, "PrintStream", "print");
   }
 
+  private long countActCall(MethodSubject method) {
+    return countCall(method, NotPinnedClass.class.getSimpleName(), "act");
+  }
+
   private long countThrow(MethodSubject method) {
     return Streams.stream(method.iterateInstructions(InstructionSubject::isThrow)).count();
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeDirect.java
similarity index 61%
copy from src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java
copy to src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeDirect.java
index bac33ad..ae94a6d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeDirect.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// 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.ir.optimize.nonnull;
@@ -7,25 +7,15 @@
 
 import com.android.tools.r8.NeverInline;
 
-public class NonNullParamAfterInvoke {
-
-  public static class NotPinnedClass {
-    final int field;
-    NotPinnedClass(int field) {
-      this.field = field;
-    }
-    void act() {
-      System.out.println(field);
-    }
-  }
+public class NonNullParamAfterInvokeDirect {
 
   @NeverInline
-  static int sum(NotPinnedClass arg1, NotPinnedClass arg2) {
+  private int sum(NotPinnedClass arg1, NotPinnedClass arg2) {
     return arg1.field + arg2.field;
   }
 
   @NeverInline
-  static void checkViaCall(NotPinnedClass arg1, NotPinnedClass arg2) {
+  private void checkViaCall(NotPinnedClass arg1, NotPinnedClass arg2) {
     // After the call to sum(...), we can know parameters arg1 and arg2 are not null.
     if (sum(arg1, arg2) > 0) {
       // Hence, inlineable.
@@ -37,14 +27,14 @@
   }
 
   @NeverInline
-  static void checkViaIntrinsic(NotPinnedClass arg) {
+  private void checkViaIntrinsic(NotPinnedClass arg) {
     checkParameterIsNotNull(arg, "arg");
     // Parameter arg is not null.
     arg.act();
   }
 
   @NeverInline
-  static void checkAtOneLevelHigher(NotPinnedClass arg) {
+  private void checkAtOneLevelHigher(NotPinnedClass arg) {
     checkViaIntrinsic(arg);
     // Parameter arg is not null.
     arg.act();
@@ -53,9 +43,9 @@
   public static void main(String[] args) {
     NotPinnedClass arg1 = new NotPinnedClass(1);
     NotPinnedClass arg2 = new NotPinnedClass(2);
-    checkViaCall(arg1, arg2);
-    checkViaIntrinsic(arg1);
-    checkAtOneLevelHigher(arg2);
+    NonNullParamAfterInvokeDirect instance = new NonNullParamAfterInvokeDirect();
+    instance.checkViaCall(arg1, arg2);
+    instance.checkViaIntrinsic(arg1);
+    instance.checkAtOneLevelHigher(arg2);
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterface.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterface.java
new file mode 100644
index 0000000..5da26c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterface.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.ir.optimize.nonnull;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class NonNullParamAfterInvokeInterface {
+
+  @NeverInline
+  void checkViaCall(NonNullParamInterface receiver, NotPinnedClass arg1, NotPinnedClass arg2) {
+    // After the call to sum(...), we can know parameters arg1 and arg2 are not null.
+    if (receiver.sum(arg1, arg2) > 0) {
+      // Hence, inlineable.
+      arg1.act();
+    } else {
+      // Ditto.
+      arg2.act();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterfaceMain.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterfaceMain.java
new file mode 100644
index 0000000..b2c322c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeInterfaceMain.java
@@ -0,0 +1,15 @@
+// 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.ir.optimize.nonnull;
+
+public class NonNullParamAfterInvokeInterfaceMain {
+
+  public static void main(String[] args) {
+    NotPinnedClass arg1 = new NotPinnedClass(1);
+    NotPinnedClass arg2 = new NotPinnedClass(2);
+    NonNullParamAfterInvokeInterface instance = new NonNullParamAfterInvokeInterface();
+    NonNullParamInterfaceImpl receiver = new NonNullParamInterfaceImpl();
+    instance.checkViaCall(receiver, arg1, arg2);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeStatic.java
similarity index 81%
rename from src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java
rename to src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeStatic.java
index bac33ad..944c024 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvoke.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeStatic.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// 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.ir.optimize.nonnull;
@@ -7,17 +7,7 @@
 
 import com.android.tools.r8.NeverInline;
 
-public class NonNullParamAfterInvoke {
-
-  public static class NotPinnedClass {
-    final int field;
-    NotPinnedClass(int field) {
-      this.field = field;
-    }
-    void act() {
-      System.out.println(field);
-    }
-  }
+public class NonNullParamAfterInvokeStatic {
 
   @NeverInline
   static int sum(NotPinnedClass arg1, NotPinnedClass arg2) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
new file mode 100644
index 0000000..994c87a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
@@ -0,0 +1,42 @@
+// 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.ir.optimize.nonnull;
+
+import static com.android.tools.r8.ir.optimize.nonnull.IntrinsicsDeputy.checkParameterIsNotNull;
+
+import com.android.tools.r8.NeverInline;
+
+public class NonNullParamAfterInvokeVirtual {
+
+  @NeverInline
+  int sum(NotPinnedClass arg1, NotPinnedClass arg2) {
+    return arg1.field + arg2.field;
+  }
+
+  @NeverInline
+  void checkViaCall(NotPinnedClass arg1, NotPinnedClass arg2) {
+    // After the call to sum(...), we can know parameters arg1 and arg2 are not null.
+    if (sum(arg1, arg2) > 0) {
+      // Hence, inlineable.
+      arg1.act();
+    } else {
+      // Ditto.
+      arg2.act();
+    }
+  }
+
+  @NeverInline
+  void checkViaIntrinsic(NotPinnedClass arg) {
+    checkParameterIsNotNull(arg, "arg");
+    // Parameter arg is not null.
+    arg.act();
+  }
+
+  @NeverInline
+  void checkAtOneLevelHigher(NotPinnedClass arg) {
+    checkViaIntrinsic(arg);
+    // Parameter arg is not null.
+    arg.act();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtualMain.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtualMain.java
new file mode 100644
index 0000000..8fac6cb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtualMain.java
@@ -0,0 +1,16 @@
+// 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.ir.optimize.nonnull;
+
+public class NonNullParamAfterInvokeVirtualMain {
+
+  public static void main(String[] args) {
+    NotPinnedClass arg1 = new NotPinnedClass(1);
+    NotPinnedClass arg2 = new NotPinnedClass(2);
+    NonNullParamAfterInvokeVirtual instance = new NonNullParamAfterInvokeVirtual();
+    instance.checkViaCall(arg1, arg2);
+    instance.checkViaIntrinsic(arg1);
+    instance.checkAtOneLevelHigher(arg2);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java
new file mode 100644
index 0000000..e20992e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java
@@ -0,0 +1,11 @@
+// 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.ir.optimize.nonnull;
+
+import com.android.tools.r8.NeverMerge;
+
+@NeverMerge
+public interface NonNullParamInterface {
+  int sum(NotPinnedClass arg1, NotPinnedClass arg2);
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterfaceImpl.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterfaceImpl.java
new file mode 100644
index 0000000..4f1dc5f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterfaceImpl.java
@@ -0,0 +1,13 @@
+// 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.ir.optimize.nonnull;
+
+import com.android.tools.r8.NeverInline;
+
+public class NonNullParamInterfaceImpl implements NonNullParamInterface {
+  @NeverInline
+  public int sum(NotPinnedClass arg1, NotPinnedClass arg2) {
+    return arg1.field + arg2.field;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NotPinnedClass.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NotPinnedClass.java
new file mode 100644
index 0000000..b9f368d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NotPinnedClass.java
@@ -0,0 +1,16 @@
+// 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.ir.optimize.nonnull;
+
+public class NotPinnedClass {
+  final int field;
+
+  NotPinnedClass(int field) {
+    this.field = field;
+  }
+
+  void act() {
+    System.out.println(field);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index 4229213..9380115 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -10,9 +10,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.graph.Code;
@@ -24,6 +24,7 @@
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -31,6 +32,7 @@
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -44,7 +46,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public abstract class AbstractR8KotlinTestBase extends KotlinTestBase {
+public abstract class AbstractR8KotlinTestBase extends TestBase {
 
   // This is the name of the Jasmin-generated class which contains the "main" method which will
   // invoke the tested method.
@@ -61,10 +63,6 @@
     return buildParameters(BooleanUtils.values(), KotlinTargetVersion.values());
   }
 
-  public AbstractR8KotlinTestBase() {
-    super(KotlinTargetVersion.JAVA_6);
-  }
-
   protected void addExtraClasspath(Path path) {
     extraClasspath.add(path);
   }
@@ -232,8 +230,8 @@
 
     // Build classpath for compilation (and java execution)
     classpath.clear();
-    classpath.add(getKotlinJarFile(folder, targetVersion));
-    classpath.add(getJavaJarFile(folder, targetVersion));
+    classpath.add(getKotlinJarFile(folder));
+    classpath.add(getJavaJarFile(folder));
     classpath.addAll(extraClasspath);
 
     // Build with R8
@@ -298,6 +296,16 @@
     }
   }
 
+  private Path getKotlinJarFile(String folder) {
+    return Paths.get(ToolHelper.TESTS_BUILD_DIR, "kotlinR8TestResources",
+        targetVersion.getFolderName(), folder + FileUtils.JAR_EXTENSION);
+  }
+
+  private Path getJavaJarFile(String folder) {
+    return Paths.get(ToolHelper.TESTS_BUILD_DIR, "kotlinR8TestResources",
+        targetVersion.getFolderName(), folder + ".java" + FileUtils.JAR_EXTENSION);
+  }
+
   @FunctionalInterface
   interface AndroidAppInspector {