Read frames into JarCode for CF backend fallback

When we throw Unimplemented in IR->CF construction because we
encountered an unimplemented IR instruction, we output the original
JarCode instead. In this case the JarCode must contain the frames from
the input file, or our output will fail verification.

Change-Id: Ia0c6ebde06d75fe891283ffa20c1be054e22d216
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index f9ea993..8933353 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -187,8 +187,14 @@
     if (context != null) {
       // The SecondVistor is in charge of setting the context to null.
       DexProgramClass owner = context.owner;
-      new ClassReader(context.classCache).accept(new SecondVisitor(context, application),
-          ClassReader.SKIP_FRAMES);
+      int flags = ClassReader.SKIP_FRAMES;
+      if (application.options.isGeneratingClassFiles()) {
+        // TODO(mathiasr): Keep frames in JarCode until IR->CF construction is complete.
+        // When we throw Unimplemented in IR->CF construction, the original JarCode is output
+        // instead. In this case we must output frames as well, or we will fail verification.
+        flags = 0;
+      }
+      new ClassReader(context.classCache).accept(new SecondVisitor(context, application), flags);
       assert verifyNoReparseContext(owner);
     }
   }
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 aa51da1..894ba4f 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
@@ -53,6 +53,7 @@
 import org.objectweb.asm.Type;
 import org.objectweb.asm.tree.AbstractInsnNode;
 import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.FrameNode;
 import org.objectweb.asm.tree.IincInsnNode;
 import org.objectweb.asm.tree.InsnNode;
 import org.objectweb.asm.tree.IntInsnNode;
@@ -1173,6 +1174,9 @@
       case AbstractInsnNode.LINE:
         updateState((LineNumberNode) insn);
         break;
+      case AbstractInsnNode.FRAME:
+        updateState((FrameNode) insn);
+        break;
       default:
         throw new Unreachable("Unexpected instruction " + insn);
     }
@@ -1794,6 +1798,11 @@
     // Intentionally empty.
   }
 
+  private void updateState(FrameNode insn) {
+    assert application.options.isGeneratingClassFiles();
+    // Intentionally empty.
+  }
+
   private void updateStateForConversion(Type from, Type to) {
     state.pop();
     state.push(to);
@@ -1848,6 +1857,9 @@
       case AbstractInsnNode.LINE:
         build((LineNumberNode) insn, builder);
         break;
+      case AbstractInsnNode.FRAME:
+        build((FrameNode) insn, builder);
+        break;
       default:
         throw new Unreachable("Unexpected instruction " + insn);
     }
@@ -2916,6 +2928,11 @@
     builder.addDebugPosition(currentPosition);
   }
 
+  private void build(FrameNode insn, IRBuilder builder) {
+    assert application.options.isGeneratingClassFiles();
+    // Intentionally empty.
+  }
+
   @Override
   public Position getDebugPositionAtOffset(int offset) {
     if (offset == EXCEPTIONAL_SYNC_EXIT_OFFSET) {
diff --git a/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java b/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java
index 5c48073..aeddc54 100644
--- a/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java
@@ -13,17 +13,17 @@
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.origin.Origin;
 import java.nio.file.Path;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
 public class AnnotationTestRunner {
   static final Class CLASS = AnnotationTest.class;
-  @Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+
+  @Rule
+  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
   @Test
-  @Ignore
   public void test() throws Exception {
     ProcessResult runInput =
         ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());