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,