Merge "Read frames into JarCode for CF backend fallback"
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
index 4d18b92..d8e78e5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -62,4 +63,9 @@
     // They should also have a non-empty set of debug values (see RegAlloc::computeDebugInfo)
     return false;
   }
+
+  @Override
+  public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
+    // Non-materializing so no stack values are needed.
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/IdentifierUtils.java b/src/main/java/com/android/tools/r8/utils/IdentifierUtils.java
index 07074ff..3097a07 100644
--- a/src/main/java/com/android/tools/r8/utils/IdentifierUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IdentifierUtils.java
@@ -15,25 +15,33 @@
   }
 
   private static boolean isSimpleNameChar(char ch) {
-    // Test if we have a SimpleChar,
-    // see https://source.android.com/devices/tech/dalvik/dex-format#string-syntax.
-    //
-    // NOTE: we assume the input strings are well-formed UTF-16 strings.
-    // This matters when checking the range 0x10000..0x10ffff, which is represented by a pair of
-    // UTF-16 surrogates. In that case, instead of checking the actual code point, we let pass all
-    // characters which are high or low surrogates.
-    return ('A' <= ch && ch <= 'Z')
-        || ('a' <= ch && ch <= 'z')
-        || ('0' <= ch && ch <= '9')
-        || ch == '$'
-        || ch == '-'
-        || ch == '_'
-        || (0x00a1 <= ch && ch <= 0x1fff)
-        || (0x2010 <= ch && ch <= 0x2027)
-        // The next range consists of these ranges:
-        // 0x2030..0xd7ff, then
-        // 0xd800..0xdfff (low or high surrogates), then
-        // 0xe000..0xffef.
-        || (0x2030 <= ch && ch <= 0xffef);
+    if (ch >= 'A' && ch <= 'Z') {
+      return true;
+    }
+    if (ch >= 'a' && ch <= 'z') {
+      return true;
+    }
+    if (ch >= '0' && ch <= '9') {
+      return true;
+    }
+    if (ch == '$' || ch == '-' || ch == '_') {
+      return true;
+    }
+    if (ch >= 0x00a1 && ch <= 0x1fff) {
+      return true;
+    }
+    if (ch >= 0x2010 && ch <= 0x2027) {
+      return true;
+    }
+    if (ch >= 0x2030 && ch <= 0xd7ff) {
+      return true;
+    }
+    if (ch >= 0xe000 && ch <= 0xffef) {
+      return true;
+    }
+    if (ch >= 0x10000 && ch <= 0x10ffff) {
+      return true;
+    }
+    return false;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 4b6b962..ebb8100 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ToolHelper.DexVm.Kind;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ArtErrorParser;
@@ -78,7 +79,8 @@
   public enum CompilerUnderTest {
     D8,
     R8,
-    R8_AFTER_D8 // refers to the R8 (default: debug) step but implies a previous D8 step as well
+    R8_AFTER_D8, // refers to the R8 (default: debug) step but implies a previous D8 step as well
+    D8_AFTER_R8CF
   }
 
   private static final String ART_TESTS_DIR = "tests/2017-10-04/art";
@@ -551,11 +553,18 @@
           // This test relies on specific field access patterns, which we rewrite.
           .put("064-field-access",
               TestCondition.match(
-                  TestCondition.R8_NOT_AFTER_D8_COMPILER,
+                  TestCondition.R8DEX_NOT_AFTER_D8_COMPILER,
                   TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
           .put("064-field-access",
               TestCondition.match(
-                  TestCondition.R8_COMPILER,
+                  TestCondition.R8DEX_COMPILER,
+                  TestCondition.runtimes(
+                      DexVm.Version.DEFAULT, DexVm.Version.V7_0_0, DexVm.Version.V6_0_1,
+                      DexVm.Version.V5_1_1)))
+          .put("064-field-access",
+              TestCondition.match(
+                  TestCondition.tools(DexTool.NONE),
+                  TestCondition.D8_AFTER_R8CF_COMPILER,
                   TestCondition.runtimes(
                       DexVm.Version.DEFAULT, DexVm.Version.V7_0_0, DexVm.Version.V6_0_1,
                       DexVm.Version.V5_1_1)))
@@ -605,10 +614,10 @@
           .put("600-verifier-fails",
               TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
           // VFY: args to if-eq/if-ne must both be refs or cat1.
-          .put("134-reg-promotion",
+          .put(
+              "134-reg-promotion",
               TestCondition.match(
-                  TestCondition.R8_COMPILER,
-                  TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
+                  TestCondition.R8DEX_COMPILER, TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
           // VFY: tried to get class from non-ref register.
           .put("506-verify-aput",
               TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
@@ -639,7 +648,7 @@
           .put("551-implicit-null-checks",
               TestCondition.match(
                   TestCondition.tools(DexTool.NONE, DexTool.DX),
-                  TestCondition.R8_COMPILER,
+                  TestCondition.R8DEX_COMPILER,
                   TestCondition.runtimes(DexVm.Version.V5_1_1)))
           // Contains a method (B.<init>) which pass too few arguments to invoke. Also, contains an
           // iput on a static field.
@@ -704,7 +713,7 @@
           .put("474-fp-sub-neg",
               TestCondition.match(
                   TestCondition.tools(DexTool.NONE, DexTool.JACK),
-                  TestCondition.D8_COMPILER,
+                  TestCondition.D8_NOT_AFTER_R8CF_COMPILER,
                   TestCondition.runtimes(DexVm.Version.V6_0_1)))
           .build();
 
@@ -759,7 +768,7 @@
               TestCondition.match(
                   TestCondition.runtimes(DexVm.Version.V4_0_4, DexVm.Version.V4_4_4,
                       DexVm.Version.V5_1_1, DexVm.Version.V6_0_1, DexVm.Version.V7_0_0)))
-          .put("454-get-vreg", TestCondition.match(TestCondition.R8_COMPILER))
+          .put("454-get-vreg", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Fails: regs_jni.cc:42] Check failed: GetVReg(m, 0, kIntVReg, &value)
           // The R8/D8 code does not put values in the same registers as the tests expects.
           .put(
@@ -767,14 +776,14 @@
               TestCondition.match(
                   TestCondition.runtimes(DexVm.Version.V4_0_4, DexVm.Version.V4_4_4,
                       DexVm.Version.V5_1_1, DexVm.Version.V6_0_1, DexVm.Version.V7_0_0)))
-          .put("457-regs", TestCondition.match(TestCondition.R8_COMPILER))
+          .put("457-regs", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Class not found.
           .put("529-checker-unresolved", TestCondition.any())
           // Fails: env_long_ref.cc:44] Check failed: GetVReg(m, 1, kReferenceVReg, &value)
           // The R8/D8 code does not produce values in the same registers as the tests expects in
           // the stack frame for TestCase.testCase checked by the native Main.lookForMyRegisters
           // (v1 vs v0).
-          .put("543-env-long-ref", TestCondition.match(TestCondition.R8_COMPILER))
+          .put("543-env-long-ref", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Array index out of bounds exception.
           .put("555-UnsafeGetLong-regression", TestCondition.any())
           // Array index out of bounds exception.
@@ -795,9 +804,9 @@
           // Main.testThisWithInstanceCall checked by the native Main.doNativeCallRef (v0 vs. v1 and
           // only 1 register instead fof 2).
           .put("461-get-reference-vreg", TestCondition.match(TestCondition.R8_COMPILER))
-          // This test uses register r1 in method that is declared to only use 1 register (r0). This
-          // is in dex code which D8 does not convert. Therefore the error is a verification error
-          // at runtime and that is expected.
+          // This test uses register r1 in method that is declared to only use 1 register (r0).
+          // This is in dex code which D8 does not convert and which R8/CF does not process.
+          // Therefore the error is a verification error at runtime and that is expected.
           .put("142-classloader2", TestCondition.match(TestCondition.D8_COMPILER))
           // Invoke-custom is supported by D8 and R8, but it can only run on our newest version
           // of art.
@@ -840,9 +849,9 @@
       new ImmutableListMultimap.Builder<String, TestCondition>()
           // Contains two methods with the same name and signature but different code.
           .put("097-duplicate-method", TestCondition.any())
-          // Contains a method (B.<init>) which pass too few arguments to invoke. Also, contains an
-          // iput on a static field.
-          .put("600-verifier-fails", TestCondition.match(TestCondition.R8_COMPILER))
+          // Dex code contains a method (B.<init>) which pass too few arguments to invoke, and it
+          // also contains an iput on a static field.
+          .put("600-verifier-fails", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Contains a method that falls off the end without a return.
           .put("606-erroneous-class", TestCondition.match(
               TestCondition.tools(DexTool.JACK),
@@ -851,11 +860,15 @@
               TestCondition.tools(DexTool.DX),
               TestCondition.R8_NOT_AFTER_D8_COMPILER,
               LEGACY_RUNTIME))
-          // Contains an illegal invoke that R8 will fail to compile.
-          .put("594-invoke-super", TestCondition.match(
-              TestCondition.R8_COMPILER))
-          .put("974-verify-interface-super", TestCondition.match(
-              TestCondition.R8_COMPILER))
+          // Dex input contains an illegal InvokeSuper in Z.foo() to Y.foo()
+          // that R8 will fail to compile.
+          .put("594-invoke-super", TestCondition.match(TestCondition.R8DEX_COMPILER))
+          .put("974-verify-interface-super", TestCondition.match(TestCondition.R8DEX_COMPILER))
+          // R8 generates too large code in Goto.bigGoto(). b/74327727
+          .put("003-omnibus-opcodes", TestCondition.match(TestCondition.D8_AFTER_R8CF_COMPILER))
+          // Contains a subset of JUnit which collides with library definitions of JUnit.
+          .put("021-string2", TestCondition.match(TestCondition.D8_AFTER_R8CF_COMPILER))
+          .put("082-inline-execute", TestCondition.match(TestCondition.D8_AFTER_R8CF_COMPILER))
           .build();
 
   // Tests that are invalid dex files and on which R8/D8 fails and that is OK.
@@ -867,12 +880,12 @@
           // only one A$B class because of a custom build script that merges them.
           .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))
+          .put("142-classloader2", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // This test uses an uninitialized register.
-          .put("471-uninitialized-locals", TestCondition.match(TestCondition.R8_COMPILER))
+          .put("471-uninitialized-locals", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // 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))
+          .put("800-smali", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Contains a loop in the class hierarchy.
           .put("804-class-extends-itself", TestCondition.any())
           // These tests have illegal class flag combinations, so we reject them.
@@ -1326,6 +1339,7 @@
         break;
       case D8:
       case R8_AFTER_D8:
+      case D8_AFTER_R8CF:
         compilationMode = CompilationMode.DEBUG;
         break;
       default:
@@ -1394,6 +1408,97 @@
         CompilationFailedException {
     assert mode != null;
     switch (compilerUnderTest) {
+      case D8_AFTER_R8CF:
+        {
+          assert keepRulesFile == null : "Keep-rules file specified for D8.";
+
+          List<ProgramResource> dexInputs = new ArrayList<>();
+          List<ProgramResource> cfInputs = new ArrayList<>();
+          for (String f : fileNames) {
+            Path p = Paths.get(f);
+            if (FileUtils.isDexFile(p)) {
+              dexInputs.add(ProgramResource.fromFile(ProgramResource.Kind.DEX, p));
+            } else if (FileUtils.isClassFile(p)) {
+              cfInputs.add(ProgramResource.fromFile(ProgramResource.Kind.CF, p));
+            } else {
+              assert FileUtils.isArchive(p);
+              ArchiveProgramResourceProvider provider =
+                  ArchiveProgramResourceProvider.fromArchive(p);
+
+              try {
+                for (ProgramResource pr : provider.getProgramResources()) {
+                  if (pr.getKind() == ProgramResource.Kind.DEX) {
+                    dexInputs.add(pr);
+                  } else {
+                    assert pr.getKind() == ProgramResource.Kind.CF;
+                    cfInputs.add(pr);
+                  }
+                }
+              } catch (ResourceException e) {
+                throw new CompilationException(e);
+              }
+            }
+          }
+
+          D8Command.Builder builder =
+              D8Command.builder()
+                  .setMode(mode)
+                  .addProgramResourceProvider(
+                      new ProgramResourceProvider() {
+                        @Override
+                        public Collection<ProgramResource> getProgramResources()
+                            throws ResourceException {
+                          return dexInputs;
+                        }
+                      })
+                  .setOutput(Paths.get(resultPath), OutputMode.DexIndexed);
+
+          Origin cfOrigin =
+              new Origin(Origin.root()) {
+                @Override
+                public String part() {
+                  return "R8/CF";
+                }
+              };
+
+          R8Command.Builder r8builder =
+              R8Command.builder()
+                  .setMode(mode)
+                  .setProgramConsumer(
+                      new ClassFileConsumer() {
+
+                        @Override
+                        public synchronized void accept(
+                            byte[] data, String descriptor, DiagnosticsHandler handler) {
+                          builder.addClassProgramData(data, cfOrigin);
+                        }
+
+                        @Override
+                        public void finished(DiagnosticsHandler handler) {}
+                      })
+                  .addProgramResourceProvider(
+                      new ProgramResourceProvider() {
+                        @Override
+                        public Collection<ProgramResource> getProgramResources()
+                            throws ResourceException {
+                          return cfInputs;
+                        }
+                      });
+
+          AndroidApiLevel minSdkVersion = needMinSdkVersion.get(name);
+          if (minSdkVersion != null) {
+            builder.setMinApiLevel(minSdkVersion.getLevel());
+            r8builder.setMinApiLevel(minSdkVersion.getLevel());
+            builder.addLibraryFiles(ToolHelper.getAndroidJar(minSdkVersion));
+            r8builder.addLibraryFiles(ToolHelper.getAndroidJar(minSdkVersion));
+          } else {
+            builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.getDefault()));
+            r8builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.getDefault()));
+          }
+          ToolHelper.runR8(r8builder.build(), options -> options.ignoreMissingClasses = true);
+          D8.run(builder.build());
+          break;
+        }
       case D8: {
         assert keepRulesFile == null : "Keep-rules file specified for D8.";
         D8Command.Builder builder =
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java
index 309f631..b85e2f2 100644
--- a/src/test/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -53,14 +53,23 @@
     }
   }
 
-  public static final CompilerSet D8_COMPILER = compilers(CompilerUnderTest.D8);
+  public static final CompilerSet D8_COMPILER =
+      compilers(CompilerUnderTest.D8, CompilerUnderTest.D8_AFTER_R8CF);
+  public static final CompilerSet D8_NOT_AFTER_R8CF_COMPILER = compilers(CompilerUnderTest.D8);
+  public static final CompilerSet D8_AFTER_R8CF_COMPILER =
+      compilers(CompilerUnderTest.D8_AFTER_R8CF);
   // R8_COMPILER refers to R8 both in the standalone setting and after D8
   // R8_NOT_AFTER_D8_COMPILER and R8_AFTER_D8_COMPILER refers to the standalone and the combined
   // settings, respectively
   public static final CompilerSet R8_COMPILER =
+      compilers(
+          CompilerUnderTest.R8, CompilerUnderTest.R8_AFTER_D8, CompilerUnderTest.D8_AFTER_R8CF);
+  public static final CompilerSet R8DEX_COMPILER =
       compilers(CompilerUnderTest.R8, CompilerUnderTest.R8_AFTER_D8);
   public static final CompilerSet R8_AFTER_D8_COMPILER = compilers(CompilerUnderTest.R8_AFTER_D8);
-  public static final CompilerSet R8_NOT_AFTER_D8_COMPILER = compilers(CompilerUnderTest.R8);
+  public static final CompilerSet R8_NOT_AFTER_D8_COMPILER =
+      compilers(CompilerUnderTest.R8, CompilerUnderTest.D8_AFTER_R8CF);
+  public static final CompilerSet R8DEX_NOT_AFTER_D8_COMPILER = compilers(CompilerUnderTest.R8);
 
   public static final CompilationModeSet DEBUG_MODE =
       new CompilationModeSet(EnumSet.of(CompilationMode.DEBUG));
diff --git a/src/test/java/com/android/tools/r8/dex/DexStringTest.java b/src/test/java/com/android/tools/r8/dex/DexStringTest.java
index 394ce53..b12d876 100644
--- a/src/test/java/com/android/tools/r8/dex/DexStringTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DexStringTest.java
@@ -8,9 +8,6 @@
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.Set;
 import org.junit.Test;
 
 public class DexStringTest {
@@ -108,24 +105,4 @@
     assertEquals("\\ud800\\udc00", factory.createString("\ud800\udc00").toASCIIString());
     assertEquals("\\udbff\\udfff", factory.createString("\udbff\udfff").toASCIIString());
   }
-
-  @Test
-  public void testIsValid() {
-    DexItemFactory factory = new DexItemFactory();
-    Set<String> goods =
-        ImmutableSet.of(
-            "\u00a1",
-            "\u1fff\u2010\u2027\u2030\ud7ff\ue000\uffef",
-            "a\ud800\udc00\udbff\udfffb\ud800\udc00c\udbff\udfff");
-    Set<String> bads = ImmutableSet.of("\u00a0", "\u2000", "\u202f", "\uffff");
-    Set<String> all = Sets.union(goods, bads);
-
-    for (String s : all) {
-      DexString ds = factory.createString(s);
-      boolean isGood = goods.contains(s);
-      assertEquals(isGood, ds.isValidFieldName());
-      assertEquals(isGood, ds.isValidMethodName());
-      assertEquals(isGood, factory.createString("L" + s + ";").isValidClassDescriptor());
-    }
-  }
 }
diff --git a/tools/create_art_tests.py b/tools/create_art_tests.py
index feb36a2..13757a9 100755
--- a/tools/create_art_tests.py
+++ b/tools/create_art_tests.py
@@ -16,7 +16,7 @@
 JACK_TEST = os.path.join('tests', '2016-12-19', 'art')
 TEST_DIR = os.path.join('tests', '2017-10-04', 'art')
 TOOLCHAINS = ["dx", "jack", "none"]
-TOOLS = ["r8", "d8"]
+TOOLS = ["r8", "d8", "r8cf"]
 TEMPLATE = Template(
 """// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -54,6 +54,7 @@
     rmtree(toolchain_dir)
   makedirs(join(toolchain_dir, "d8"))
   makedirs(join(toolchain_dir, "r8"))
+  makedirs(join(toolchain_dir, "r8cf"))
 
 def write_file(toolchain, tool, class_name, contents):
   file_name = join(OUTPUT_DIR, toolchain, tool, class_name + ".java")
@@ -74,6 +75,10 @@
         tool_enum = 'R8_AFTER_D8'
       else:
         tool_enum = upper(tool)
+      if tool == "r8cf":
+        if toolchain != "none":
+          continue
+        tool_enum = 'D8_AFTER_R8CF'
       contents = TEMPLATE.substitute(
           name=dir,
           compilerUnderTestEnum=tool_enum,