Version 0.1.8

Merge: Fix addition/exclusion of Jasmin code in Art tests.
CL: https://r8-review.googlesource.com/c/r8/+/5621

Merge: Reapply "Instructions can be targeted by both normal and exceptional flow.
CL: https://r8-review.googlesource.com/c/r8/+/5622

Change-Id: I821f9fa26819c17fa483402639910da8317c2e17
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index c997595..5e43513 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -55,7 +55,7 @@
  */
 public final class D8 {
 
-  private static final String VERSION = "v0.1.7";
+  private static final String VERSION = "v0.1.8";
   private static final int STATUS_ERROR = 1;
 
   private D8() {}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 6b127da..e8efb59 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,7 +71,7 @@
 
 public class R8 {
 
-  private static final String VERSION = "v0.1.7";
+  private static final String VERSION = "v0.1.8";
   private final Timing timing = new Timing("R8");
   private final InternalOptions options;
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 3dff4f3..61ed928 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -27,6 +27,7 @@
   }
 
   public void setPosition(DebugPosition position) {
+    assert this.position == null;
     this.position = position;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 9e07ad6..d1c42ee 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.code.MoveResultWide;
 import com.android.tools.r8.code.SwitchPayload;
 import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexAccessFlags;
 import com.android.tools.r8.graph.DexCode;
@@ -39,6 +40,7 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.MoveType;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -161,6 +163,17 @@
   }
 
   @Override
+  public int getMoveExceptionRegister() {
+    // No register, move-exception is manually entered during construction.
+    return -1;
+  }
+
+  @Override
+  public DebugPosition getDebugPositionAtOffset(int offset) {
+    throw new Unreachable();
+  }
+
+  @Override
   public boolean verifyCurrentInstructionCanThrow() {
     return currentDexInstruction.canThrow();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index aa86057..7a1212a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -93,6 +93,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -124,6 +125,15 @@
     }
   }
 
+  private static class MoveExceptionWorklistItem extends WorklistItem {
+    private final int targetOffset;
+
+    private MoveExceptionWorklistItem(BasicBlock block, int targetOffset) {
+      super(block, -1);
+      this.targetOffset = targetOffset;
+    }
+  }
+
   /**
    * Representation of lists of values that can be used as keys in maps. A list of
    * values is equal to another list of values if it contains exactly the same values
@@ -449,6 +459,11 @@
       setCurrentBlock(item.block);
       blocks.add(currentBlock);
       currentBlock.setNumber(nextBlockNumber++);
+      // Process synthesized move-exception block specially.
+      if (item instanceof MoveExceptionWorklistItem) {
+        processMoveExceptionItem((MoveExceptionWorklistItem) item);
+        continue;
+      }
       // Build IR for each dex instruction in the block.
       for (int i = item.firstInstructionIndex; i < source.instructionCount(); ++i) {
         if (currentBlock == null) {
@@ -467,6 +482,22 @@
     }
   }
 
+  private void processMoveExceptionItem(MoveExceptionWorklistItem moveExceptionItem) {
+    // TODO(zerny): Link with outer try-block handlers, if any. b/65203529
+    int moveExceptionDest = source.getMoveExceptionRegister();
+    assert moveExceptionDest >= 0;
+    int targetIndex = source.instructionIndex(moveExceptionItem.targetOffset);
+    Value out = writeRegister(moveExceptionDest, MoveType.OBJECT, ThrowingInfo.NO_THROW, null);
+    MoveException moveException = new MoveException(out);
+    moveException.setPosition(source.getDebugPositionAtOffset(moveExceptionItem.targetOffset));
+    currentBlock.add(moveException);
+    currentBlock.add(new Goto());
+    BasicBlock targetBlock = getTarget(moveExceptionItem.targetOffset);
+    currentBlock.link(targetBlock);
+    addToWorklist(targetBlock, targetIndex);
+    closeCurrentBlock();
+  }
+
   // Helper to resolve switch payloads and build switch instructions (dex code only).
   public void resolveAndBuildSwitch(int value, int fallthroughOffset, int payloadOffset) {
     source.resolveAndBuildSwitch(value, fallthroughOffset, payloadOffset, this);
@@ -1567,9 +1598,7 @@
   // Private instruction helpers.
   private void addInstruction(Instruction ir) {
     attachLocalChanges(ir);
-    if (currentDebugPosition != null && !ir.isMoveException()) {
-      flushCurrentDebugPosition();
-    }
+    flushCurrentDebugPosition(ir);
     currentBlock.add(ir);
     if (ir.instructionTypeCanThrow()) {
       assert source.verifyCurrentInstructionCanThrow();
@@ -1578,18 +1607,33 @@
         assert !throwingInstructionInCurrentBlock;
         throwingInstructionInCurrentBlock = true;
         List<BasicBlock> targets = new ArrayList<>(catchHandlers.getAllTargets().size());
-        for (int targetOffset : catchHandlers.getAllTargets()) {
-          BasicBlock target = getTarget(targetOffset);
-          addToWorklist(target, source.instructionIndex(targetOffset));
-          targets.add(target);
+        int moveExceptionDest = source.getMoveExceptionRegister();
+        if (moveExceptionDest < 0) {
+          for (int targetOffset : catchHandlers.getAllTargets()) {
+            BasicBlock target = getTarget(targetOffset);
+            addToWorklist(target, source.instructionIndex(targetOffset));
+            targets.add(target);
+          }
+        } else {
+          // If there is a well-defined move-exception destination register (eg, compiling from
+          // Java-bytecode) then we construct move-exception header blocks for each unique target.
+          Map<BasicBlock, BasicBlock> moveExceptionHeaders =
+              new IdentityHashMap<>(catchHandlers.getUniqueTargets().size());
+          for (int targetOffset : catchHandlers.getAllTargets()) {
+            BasicBlock target = getTarget(targetOffset);
+            BasicBlock header = moveExceptionHeaders.get(target);
+            if (header == null) {
+              header = new BasicBlock();
+              header.incrementUnfilledPredecessorCount();
+              moveExceptionHeaders.put(target, header);
+              ssaWorklist.add(new MoveExceptionWorklistItem(header, targetOffset));
+            }
+            targets.add(header);
+          }
         }
         currentBlock.linkCatchSuccessors(catchHandlers.getGuards(), targets);
       }
     }
-    if (currentDebugPosition != null) {
-      assert ir.isMoveException();
-      flushCurrentDebugPosition();
-    }
   }
 
   private void attachLocalChanges(Instruction ir) {
@@ -1976,26 +2020,23 @@
 
   public void updateCurrentDebugPosition(int line, DexString file) {
     // Stack-trace support requires position information in both debug and release mode.
-    flushCurrentDebugPosition();
+    flushCurrentDebugPosition(null);
     currentDebugPosition = new DebugPosition(line, file);
     attachLocalChanges(currentDebugPosition);
   }
 
-  private void flushCurrentDebugPosition() {
+  private void flushCurrentDebugPosition(Instruction instruction) {
     if (currentDebugPosition != null) {
       DebugPosition position = currentDebugPosition;
       currentDebugPosition = null;
-      if (!currentBlock.getInstructions().isEmpty()) {
-        MoveException move = currentBlock.getInstructions().getLast().asMoveException();
-        if (move != null && move.getPosition() == null) {
-          // Set the position on the move-exception instruction.
-          // ART/DX associates the move-exception pc with the catch-declaration line.
-          // See debug.ExceptionTest.testStepOnCatch().
-          move.setPosition(position);
-          return;
-        }
+      if (instruction != null && instruction.isMoveException()) {
+        // Set the position on the move-exception instruction.
+        // ART/DX associates the move-exception pc with the catch-declaration line.
+        // See debug.ExceptionTest.testStepOnCatch().
+        instruction.asMoveException().setPosition(position);
+      } else {
+        addInstruction(position);
       }
-      addInstruction(position);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 8d36ef7..d7a0428 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.code.CatchHandlers;
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.ConstType;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.MemberType;
@@ -132,10 +133,10 @@
       "([Ljava/lang/Object;)Ljava/lang/Object;";
 
   // Language types.
-  private static final Type CLASS_TYPE = Type.getObjectType("java/lang/Class");
-  private static final Type STRING_TYPE = Type.getObjectType("java/lang/String");
-  private static final Type INT_ARRAY_TYPE = Type.getObjectType(INT_ARRAY_DESC);
-  private static final Type THROWABLE_TYPE = Type.getObjectType("java/lang/Throwable");
+  static final Type CLASS_TYPE = Type.getObjectType("java/lang/Class");
+  static final Type STRING_TYPE = Type.getObjectType("java/lang/String");
+  static final Type INT_ARRAY_TYPE = Type.getObjectType(INT_ARRAY_DESC);
+  static final Type THROWABLE_TYPE = Type.getObjectType("java/lang/Throwable");
 
   private static final int[] NO_TARGETS = {};
 
@@ -361,14 +362,6 @@
     state.recordStateForTarget(0, this);
     for (JarStateWorklistItem item = worklist.poll(); item != null; item = worklist.poll()) {
       state.restoreState(item.instructionIndex);
-      // If the block being restored is a try-catch handler push the exception on the stack.
-      for (int i = 0; i < node.tryCatchBlocks.size(); i++) {
-        TryCatchBlockNode tryCatchBlockNode = (TryCatchBlockNode) node.tryCatchBlocks.get(i);
-        if (tryCatchBlockNode.handler == getInstruction(item.instructionIndex)) {
-          state.push(THROWABLE_TYPE);
-          break;
-        }
-      }
       // Iterate each of the instructions in the block to compute the outgoing JarState.
       for (int i = item.instructionIndex; i <= instructionCount(); ++i) {
         // If we are at the end of the instruction stream or if we have reached the start
@@ -426,10 +419,8 @@
   private void buildExceptionalPostlude(IRBuilder builder) {
     assert isSynchronized();
     generatingMethodSynchronization = true;
-    int exceptionRegister = 0; // We are exiting the method so we just overwrite register 0.
-    builder.addMoveException(exceptionRegister);
     buildMonitorExit(builder);
-    builder.addThrow(exceptionRegister);
+    builder.addThrow(getMoveExceptionRegister());
     generatingMethodSynchronization = false;
   }
 
@@ -459,14 +450,6 @@
     // If a new block is starting here, we restore the computed JarState.
     if (builder.getCFG().containsKey(instructionIndex) || instructionIndex == 0) {
       state.restoreState(instructionIndex);
-      // If the block being restored is a try-catch handler push the exception on the stack.
-      for (int i = 0; i < node.tryCatchBlocks.size(); i++) {
-        TryCatchBlockNode tryCatchBlockNode = (TryCatchBlockNode) node.tryCatchBlocks.get(i);
-        if (tryCatchBlockNode.handler == insn) {
-          builder.addMoveException(state.push(THROWABLE_TYPE));
-          break;
-        }
-      }
     }
 
     String preInstructionState;
@@ -537,6 +520,11 @@
   }
 
   @Override
+  public int getMoveExceptionRegister() {
+    return state.startOfStack;
+  }
+
+  @Override
   public boolean verifyCurrentInstructionCanThrow() {
     return generatingMethodSynchronization || canThrow(currentInstruction);
   }
@@ -2792,6 +2780,23 @@
     builder.updateCurrentDebugPosition(insn.line, null);
   }
 
+  @Override
+  public DebugPosition getDebugPositionAtOffset(int offset) {
+    int index = instructionIndex(offset);
+    if (index < 0 || instructionCount() <= index) {
+      return null;
+    }
+    AbstractInsnNode insn = node.instructions.get(index);
+    if (insn instanceof LabelNode) {
+      insn = insn.getNext();
+    }
+    if (insn instanceof LineNumberNode) {
+      LineNumberNode line = (LineNumberNode) insn;
+      return new DebugPosition(line.line, null);
+    }
+    return null;
+  }
+
   // Printing helpers.
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
index 0801216..ebe220b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
@@ -165,7 +165,7 @@
     }
   }
 
-  private final int startOfStack;
+  final int startOfStack;
   private int topOfStack;
 
   // Locals are split into three parts based on types:
@@ -470,7 +470,10 @@
   }
 
   public boolean recordStateForExceptionalTarget(int target, JarSourceCode source) {
-    return recordStateForTarget(target, locals.clone(), ImmutableList.of(), source);
+    return recordStateForTarget(target,
+        locals.clone(),
+        ImmutableList.of(new Slot(startOfStack, JarSourceCode.THROWABLE_TYPE)),
+        source);
   }
 
   private boolean recordStateForTarget(int target, Local[] locals, ImmutableList<Slot> stack,
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
index b1f9a14..70e6218 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 
 /**
  * Abstraction of the input/source code for the IRBuilder.
@@ -26,6 +27,8 @@
 
   DebugLocalInfo getCurrentLocal(int register);
 
+  DebugPosition getDebugPositionAtOffset(int offset);
+
   /**
    * Trace block structure of the source-program.
    *
@@ -57,6 +60,7 @@
   void resolveAndBuildNewArrayFilledData(int arrayRef, int payloadOffset, IRBuilder builder);
 
   CatchHandlers<Integer> getCurrentCatchHandlers();
+  int getMoveExceptionRegister();
 
   // For debugging/verification purpose.
   boolean verifyRegister(int register);
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 3857c1f..ea26926 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
@@ -27,6 +27,7 @@
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.Div;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
@@ -928,6 +929,16 @@
     }
 
     @Override
+    public int getMoveExceptionRegister() {
+      throw new Unreachable();
+    }
+
+    @Override
+    public DebugPosition getDebugPositionAtOffset(int offset) {
+      throw new Unreachable();
+    }
+
+    @Override
     public boolean verifyCurrentInstructionCanThrow() {
       // TODO(sgjesse): Check more here?
       return true;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
index bd7efce..410e4b8 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -196,6 +197,16 @@
   }
 
   @Override
+  public int getMoveExceptionRegister() {
+    throw new Unreachable();
+  }
+
+  @Override
+  public DebugPosition getDebugPositionAtOffset(int offset) {
+    throw new Unreachable();
+  }
+
+  @Override
   public final boolean verifyCurrentInstructionCanThrow() {
     return true;
   }
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index ab350a7..3a6277c 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -3,11 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
-import static com.android.tools.r8.TestCondition.compilers;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import com.android.tools.r8.JctfTestSpecifications.Outcome;
+import com.android.tools.r8.TestCondition.RuntimeSet;
 import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -82,6 +82,12 @@
   private static final String ART_TESTS_NATIVE_LIBRARY_DIR = "tests/2017-07-27/art/lib64";
   private static final String ART_LEGACY_TESTS_NATIVE_LIBRARY_DIR = "tests/2016-12-19/art/lib64";
 
+  private static final RuntimeSet LEGACY_RUNTIME = TestCondition.runtimes(
+      DexVm.ART_4_4_4,
+      DexVm.ART_5_1_1,
+      DexVm.ART_6_0_1,
+      DexVm.ART_7_0_0);
+
   // Input jar for jctf tests.
   private static final String JCTF_COMMON_JAR = "build/libs/jctfCommon.jar";
 
@@ -527,8 +533,6 @@
           // keeps the instances alive is dead and could be garbage collected. The compiler reuses
           // the register for the list and therefore there are no live instances.
           .put("099-vmdebug", TestCondition.any())
-          // This test relies on output on stderr, which we currently do not collect.
-          .put("143-string-value", TestCondition.any())
           .put(
               "800-smali",
               TestCondition.match(
@@ -577,7 +581,7 @@
               "370-dex-v37",
               TestCondition.match(
                   TestCondition.tools(DexTool.JACK, DexTool.DX),
-                  compilers(CompilerUnderTest.R8, CompilerUnderTest.D8),
+                  TestCondition.compilers(CompilerUnderTest.R8, CompilerUnderTest.D8),
                   TestCondition.runtimes(DexVm.ART_4_4_4, DexVm.ART_5_1_1, DexVm.ART_6_0_1)))
           // Array index out of bounds exception.
           .put("449-checker-bce", TestCondition.any())
@@ -680,21 +684,15 @@
           // iput on a static field.
           .put("600-verifier-fails", TestCondition.match(TestCondition.R8_COMPILER))
           // Contains a method that falls off the end without a return.
-          .put("606-erroneous-class", TestCondition
-              .match(TestCondition.tools(DexTool.DX, DexTool.JACK),
-                  TestCondition.R8_NOT_AFTER_D8_COMPILER))
-          .put("064-field-access", TestCondition
-              .match(TestCondition.tools(DexTool.NONE), TestCondition.D8_COMPILER))
+          .put("606-erroneous-class", TestCondition.match(
+              TestCondition.tools(DexTool.DX, DexTool.JACK),
+              TestCondition.R8_NOT_AFTER_D8_COMPILER,
+              LEGACY_RUNTIME))
           .build();
 
   // Tests that are invalid dex files and on which R8/D8 fails and that is OK.
   private static final Multimap<String, TestCondition> expectedToFailWithCompiler =
       new ImmutableListMultimap.Builder<String, TestCondition>()
-          // When starting from the Dex frontend we see two definitions of the same class coming
-          // from two differents dex files.
-          .put("064-field-access",
-              TestCondition.match(TestCondition.tools(DexTool.DX, DexTool.JACK),
-                  TestCondition.runtimes(DexVm.ART_DEFAULT)))
           // When starting from the Jar frontend we see the A$B class both from the Java source
           // code and from the smali dex code. We reject that because there are then two definitions
           // of the same class in the application. When running from the final dex files there is
@@ -702,18 +700,8 @@
           .put("121-modifiers", TestCondition.match(TestCondition.tools(DexTool.NONE)))
           // This test uses register r1 in method that is declared to only use 1 register (r0).
           .put("142-classloader2", TestCondition.match(TestCondition.R8_COMPILER))
-          // When starting from the Dex frontend we see two definitions of the same class coming
-          // from two differents dex files.
-          .put("162-method-resolution",
-              TestCondition.match(TestCondition.tools(DexTool.DX, DexTool.JACK)))
           // This test uses an uninitialized register.
           .put("471-uninitialized-locals", TestCondition.match(TestCondition.R8_COMPILER))
-          // When starting from the Dex frontend we see two definitions of the same class coming
-          // from two differents dex files.
-          .put("606-erroneous-class",
-              TestCondition
-                  .match(TestCondition.tools(DexTool.DX, DexTool.JACK), TestCondition.D8_COMPILER,
-                      TestCondition.runtimes(DexVm.ART_DEFAULT)))
           // This test is starting from invalid dex code. It splits up a double value and uses
           // the first register of a double with the second register of another double.
           .put("800-smali", TestCondition.match(TestCondition.R8_COMPILER))
@@ -729,9 +717,7 @@
 
   // Tests that does not have valid input for us to be compatible with jack/dx running.
   private static List<String> noInputJar = ImmutableList.of(
-      "064-field-access", // Missing classes2 dir (has src2)
       "097-duplicate-method", // No input class files.
-      "162-method-resolution", // Based on multiple jasmin files
       "630-safecast-array", // No input class files.
       "801-VoidCheckCast", // No input class files.
       "804-class-extends-itself", // No input class files.
@@ -767,12 +753,19 @@
   // Tests to skip on some conditions
   private static final Multimap<String, TestCondition> testToSkip =
       new ImmutableListMultimap.Builder<String, TestCondition>()
+          // When running R8 on dex input (D8, DX or JACK) this test non-deterministically fails
+          // with a compiler exception, due to invoke-virtual on an interface, or it completes but
+          // the output when run on Art is not as expected. b/65233869
+          .put("162-method-resolution",
+              TestCondition.match(
+                  TestCondition.tools(DexTool.DX, DexTool.JACK), TestCondition.R8_COMPILER))
           // Old runtimes used the legacy test directory which does not contain input for tools
           // NONE and DX.
           .put("952-invoke-custom", TestCondition.match(
               TestCondition.tools(DexTool.NONE, DexTool.DX),
-              TestCondition.runtimes(
-                  DexVm.ART_4_4_4, DexVm.ART_5_1_1, DexVm.ART_6_0_1, DexVm.ART_7_0_0)))
+              LEGACY_RUNTIME))
+          // No input dex files for DX
+          .put("952-invoke-custom-kinds", TestCondition.match(TestCondition.tools(DexTool.DX)))
           .build();
 
   public static List<String> requireInliningToBeDisabled = ImmutableList.of(
@@ -956,7 +949,7 @@
   private static Map<SpecificationKey, TestSpecification> getTestsMap(
       CompilerUnderTest compilerUnderTest, CompilationMode compilationMode, DexVm dexVm) {
     File artTestDir = new File(ART_TESTS_DIR);
-    if (dexVm != DexVm.ART_DEFAULT) {
+    if (LEGACY_RUNTIME.set.contains(dexVm)) {
       artTestDir = new File(ART_LEGACY_TESTS_DIR);
     }
     if (!artTestDir.exists()) {
@@ -1447,25 +1440,20 @@
 
     File[] inputFiles;
     if (toolchain == DexTool.NONE) {
-      File classes = new File(specification.directory, "classes");
-      inputFiles =
-          com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(classes).filter(
-              (File f) -> !f.isDirectory()).toArray(File.class);
+      inputFiles = addFileTree(new File[0], new File(specification.directory, "classes"));
+      inputFiles = addFileTree(inputFiles, new File(specification.directory, "jasmin_classes"));
       File smali = new File(specification.directory, "smali");
       if (smali.exists()) {
         File smaliDex = new File(smali, "out.dex");
         assert smaliDex.exists();
         inputFiles = ObjectArrays.concat(inputFiles, smaliDex);
       }
-      File classes2 = new File(specification.directory, "classes2");
-      if (classes2.exists()) {
-        inputFiles = ObjectArrays.concat(inputFiles,
-            com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(classes2).filter(
-                (File f) -> !f.isDirectory()).toArray(File.class), File.class);
-      }
+      inputFiles = addFileTree(inputFiles, new File(specification.directory, "classes2"));
+      inputFiles = addFileTree(inputFiles, new File(specification.directory, "jasmin_classes2"));
     } else {
       inputFiles =
-          specification.directory.listFiles((File file) -> file.getName().endsWith(".dex"));
+          specification.directory.listFiles((File file) ->
+              file.getName().endsWith(".dex") && !file.getName().startsWith("jasmin"));
     }
     List<String> fileNames = new ArrayList<>();
     for (File file : inputFiles) {
@@ -1504,6 +1492,18 @@
     }
   }
 
+  private File[] addFileTree(File[] files, File directory) {
+    if (!directory.exists()) {
+      return files;
+    }
+    return ObjectArrays.concat(
+        files,
+        com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(directory)
+            .filter(f -> !f.isDirectory())
+            .toArray(File.class),
+        File.class);
+  }
+
   private void runArtTestDoRunOnArt(
       DexVm version,
       CompilerUnderTest compilerUnderTest,
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index a296a3e..32f5174 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -36,6 +36,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
@@ -689,6 +690,16 @@
     }
 
     @Override
+    public int getMoveExceptionRegister() {
+      throw new Unreachable();
+    }
+
+    @Override
+    public DebugPosition getDebugPositionAtOffset(int offset) {
+      throw new Unreachable();
+    }
+
+    @Override
     public boolean verifyRegister(int register) {
       throw new Unreachable();
     }