aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Béra <clementbera@google.com>2021-03-15 15:46:55 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-03-15 15:46:55 +0000
commit25c3482eeeedcc7a2dd5a9ac048616fa9e02449c (patch)
tree4f0a9cf300a8e7b82118e857668eb52f47699307
parent7340f9474225a361d68fe624c18719759cb02477 (diff)
parent8eca109aa3e72aefa66c28eb3daef548b8dc4b86 (diff)
downloadr8-25c3482eeeedcc7a2dd5a9ac048616fa9e02449c.tar.gz
Support Record dex merge am: 8eca109aa3
Original change: undetermined MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I757b09ddfaca216f9c66aad990d289597a9d502b
-rw-r--r--src/main/java/com/android/tools/r8/dex/DexParser.java7
-rw-r--r--src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java31
-rw-r--r--src/main/java/com/android/tools/r8/graph/DexItemFactory.java8
-rw-r--r--src/main/java/com/android/tools/r8/graph/DexType.java8
-rw-r--r--src/main/java/com/android/tools/r8/graph/JarApplicationReader.java6
-rw-r--r--src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java16
-rw-r--r--src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java4
-rw-r--r--src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java8
-rw-r--r--src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java101
9 files changed, 174 insertions, 15 deletions
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index cd789952c..26bbc5e96 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -12,6 +12,7 @@ import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InstructionFactory;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.ApplicationReaderMap;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexAnnotation;
@@ -79,6 +80,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -992,9 +994,12 @@ public class DexParser<T extends DexClass> {
private void populateTypes() {
DexSection dexSection = lookupSection(Constants.TYPE_TYPE_ID_ITEM);
assert verifyOrderOfTypeIds(dexSection);
+ Map<DexType, DexType> typeMap = ApplicationReaderMap.getTypeMap(options);
indexedItems.initializeTypes(dexSection.length);
for (int i = 0; i < dexSection.length; i++) {
- indexedItems.setType(i, typeAt(i));
+ DexType type = typeAt(i);
+ DexType actualType = typeMap.getOrDefault(type, type);
+ indexedItems.setType(i, actualType);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
new file mode 100644
index 000000000..82b9d7f9f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, 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.graph;
+
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
+public class ApplicationReaderMap {
+
+ public static Map<String, String> getDescriptorMap(InternalOptions options) {
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+ if (options.shouldDesugarRecords()) {
+ builder.put(DexItemFactory.recordTagDescriptorString, DexItemFactory.recordDescriptorString);
+ }
+ return builder.build();
+ }
+
+ public static Map<DexType, DexType> getTypeMap(InternalOptions options) {
+ DexItemFactory factory = options.dexItemFactory();
+ ImmutableMap.Builder<DexType, DexType> builder = ImmutableMap.builder();
+ getDescriptorMap(options)
+ .forEach(
+ (k, v) -> {
+ builder.put(factory.createType(k), factory.createType(v));
+ });
+ return builder.build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 1339701a7..8ba291b93 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -64,6 +64,8 @@ public class DexItemFactory {
public static final String throwableDescriptorString = "Ljava/lang/Throwable;";
public static final String dalvikAnnotationSignatureString = "Ldalvik/annotation/Signature;";
+ public static final String recordTagDescriptorString = "Lcom/android/tools/r8/RecordTag;";
+ public static final String recordDescriptorString = "Ljava/lang/Record;";
/** Set of types that may be synthesized during compilation. */
private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
@@ -215,8 +217,8 @@ public class DexItemFactory {
public final DexString stringDescriptor = createString("Ljava/lang/String;");
public final DexString stringArrayDescriptor = createString("[Ljava/lang/String;");
public final DexString objectDescriptor = createString("Ljava/lang/Object;");
- public final DexString recordDescriptor = createString("Ljava/lang/Record;");
- public final DexString r8RecordDescriptor = createString("Lcom/android/tools/r8/RecordTag;");
+ public final DexString recordDescriptor = createString(recordDescriptorString);
+ public final DexString recordTagDescriptor = createString(recordTagDescriptorString);
public final DexString objectArrayDescriptor = createString("[Ljava/lang/Object;");
public final DexString classDescriptor = createString("Ljava/lang/Class;");
public final DexString classLoaderDescriptor = createString("Ljava/lang/ClassLoader;");
@@ -348,7 +350,7 @@ public class DexItemFactory {
public final DexType stringArrayType = createStaticallyKnownType(stringArrayDescriptor);
public final DexType objectType = createStaticallyKnownType(objectDescriptor);
public final DexType recordType = createStaticallyKnownType(recordDescriptor);
- public final DexType r8RecordType = createStaticallyKnownType(r8RecordDescriptor);
+ public final DexType recordTagType = createStaticallyKnownType(recordTagDescriptor);
public final DexType objectArrayType = createStaticallyKnownType(objectArrayDescriptor);
public final DexType classArrayType = createStaticallyKnownType(classArrayDescriptor);
public final DexType enumType = createStaticallyKnownType(enumDescriptor);
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 75b592b2d..a38770a70 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -315,6 +315,14 @@ public class DexType extends DexReference implements NamingLensComparable<DexTyp
return isDoubleType() || isLongType();
}
+ public boolean isSynthesizedTypeAllowedDuplication() {
+ // If we are desugaring Records, then the r8Record type is mapped back to java.lang.Record, and
+ // java.lang.Record can be duplicated.
+ // If we are not desugaring Records, then the r8Record type can be duplicated instead.
+ return descriptor.toString().equals(DexItemFactory.recordDescriptorString)
+ || descriptor.toString().equals(DexItemFactory.recordTagDescriptorString);
+ }
+
public boolean isLegacySynthesizedTypeAllowedDuplication() {
return oldSynthesizedName(toSourceString());
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
index 8b5977f83..67e7b5ba1 100644
--- a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.objectweb.asm.Type;
@@ -23,9 +24,11 @@ public class JarApplicationReader {
private final ConcurrentHashMap<String, Type> asmObjectTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Type> asmTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>();
+ private final Map<String, String> typeDescriptorMap;
public JarApplicationReader(InternalOptions options) {
this.options = options;
+ typeDescriptorMap = ApplicationReaderMap.getDescriptorMap(options);
}
public Type getAsmObjectType(String name) {
@@ -55,7 +58,8 @@ public class JarApplicationReader {
public DexType getTypeFromDescriptor(String desc) {
assert isValidDescriptor(desc);
- return options.itemFactory.createType(getString(desc));
+ String actualDesc = typeDescriptorMap.getOrDefault(desc, desc);
+ return options.itemFactory.createType(getString(actualDesc));
}
public DexTypeList getTypeListFromNames(String[] names) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
index d94a74700..469f119fe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
@@ -191,7 +191,7 @@ public class RecordRewriter implements CfInstructionDesugaring, CfClassDesugarin
null,
true);
encodedMethod.setCode(
- new RecordGetFieldsAsObjectsCfCodeProvider(appView, factory.r8RecordType, fields)
+ new RecordGetFieldsAsObjectsCfCodeProvider(appView, factory.recordTagType, fields)
.generateCfCode(),
appView);
return new ProgramMethod(clazz, encodedMethod);
@@ -316,7 +316,6 @@ public class RecordRewriter implements CfInstructionDesugaring, CfClassDesugarin
@Override
public boolean needsDesugaring(DexProgramClass clazz) {
- assert clazz.isRecord() || clazz.superType != factory.recordType;
return clazz.isRecord();
}
@@ -460,6 +459,17 @@ public class RecordRewriter implements CfInstructionDesugaring, CfClassDesugarin
private DexProgramClass synthesizeR8Record() {
DexItemFactory factory = appView.dexItemFactory();
+ DexClass r8RecordClass =
+ appView.appInfo().definitionForWithoutExistenceAssert(factory.recordTagType);
+ if (r8RecordClass != null && r8RecordClass.isProgramClass()) {
+ appView
+ .options()
+ .reporter
+ .error(
+ "D8/R8 is compiling a mix of desugared and non desugared input using"
+ + " java.lang.Record, but the application reader did not import correctly "
+ + factory.recordTagType.toString());
+ }
DexClass recordClass =
appView.appInfo().definitionForWithoutExistenceAssert(factory.recordType);
if (recordClass != null && recordClass.isProgramClass()) {
@@ -520,7 +530,7 @@ public class RecordRewriter implements CfInstructionDesugaring, CfClassDesugarin
null,
true);
init.setCode(
- new CallObjectInitCfCodeProvider(appView, factory.r8RecordType).generateCfCode(), appView);
+ new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode(), appView);
return init;
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
index 83fa84e51..e809317af 100644
--- a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
@@ -45,7 +45,7 @@ public class RecordRewritingNamingLens extends NonIdentityNamingLens {
private DexString getRenaming(DexType type) {
if (type == factory.recordType) {
- return factory.r8RecordType.descriptor;
+ return factory.recordTagType.descriptor;
}
return null;
}
@@ -77,7 +77,7 @@ public class RecordRewritingNamingLens extends NonIdentityNamingLens {
@Override
public DexString lookupDescriptorForJavaTypeName(String typeName) {
if (typeName.equals(factory.recordType.toSourceString())) {
- return factory.r8RecordType.descriptor;
+ return factory.recordTagType.descriptor;
}
return namingLens.lookupDescriptorForJavaTypeName(typeName);
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index fff5425e8..8c3e592de 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -62,10 +62,7 @@ public class ProgramClassCollection extends ClassMap<DexProgramClass> {
// All other conflicts are reported as a fatal error.
return (DexProgramClass a, DexProgramClass b) -> {
assert a.type == b.type;
- if (a.originatesFromDexResource()
- && b.originatesFromDexResource()
- && a.accessFlags.isSynthetic()
- && b.accessFlags.isSynthetic()) {
+ if (a.accessFlags.isSynthetic() && b.accessFlags.isSynthetic()) {
return mergeClasses(reporter, a, b);
}
throw reportDuplicateTypes(reporter, a, b);
@@ -82,7 +79,8 @@ public class ProgramClassCollection extends ClassMap<DexProgramClass> {
private static DexProgramClass mergeClasses(
Reporter reporter, DexProgramClass a, DexProgramClass b) {
- if (a.type.isLegacySynthesizedTypeAllowedDuplication()) {
+ if (a.type.isLegacySynthesizedTypeAllowedDuplication()
+ || a.type.isSynthesizedTypeAllowedDuplication()) {
assert assertEqualClasses(a, b);
return a;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
new file mode 100644
index 000000000..bd08a25bd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2021, 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.desugar.records;
+
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.utils.InternalOptions.TestingOptions;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RecordMergeTest extends TestBase {
+
+ private static final String RECORD_NAME_1 = "RecordWithMembers";
+ private static final byte[][] PROGRAM_DATA_1 = RecordTestUtils.getProgramData(RECORD_NAME_1);
+ private static final String MAIN_TYPE_1 = RecordTestUtils.getMainType(RECORD_NAME_1);
+ private static final String EXPECTED_RESULT_1 =
+ StringUtils.lines(
+ "BobX", "43", "BobX", "43", "FelixX", "-1", "FelixX", "-1", "print", "Bob43", "extra");
+
+ private static final String RECORD_NAME_2 = "SimpleRecord";
+ private static final byte[][] PROGRAM_DATA_2 = RecordTestUtils.getProgramData(RECORD_NAME_2);
+ private static final String MAIN_TYPE_2 = RecordTestUtils.getMainType(RECORD_NAME_2);
+ private static final String EXPECTED_RESULT_2 =
+ StringUtils.lines("Jane Doe", "42", "Jane Doe", "42");
+
+ private final TestParameters parameters;
+
+ public RecordMergeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15).
+ return buildParameters(
+ getTestParameters()
+ .withCustomRuntime(CfRuntime.getCheckedInJdk15())
+ .withDexRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build());
+ }
+
+ @Test
+ public void testMergeDesugaredInputs() throws Exception {
+ Path output1 =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_1)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+ .compile()
+ .writeToZip();
+ Path output2 =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_2)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+ .compile()
+ .writeToZip();
+ D8TestCompileResult result =
+ testForD8(parameters.getBackend())
+ .addProgramFiles(output1, output2)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .compile();
+ result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
+ result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
+ }
+
+ @Test
+ public void testMergeDesugaredAndNonDesugaredInputs() throws Exception {
+ Path output1 =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_1)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+ .compile()
+ .writeToZip();
+ D8TestCompileResult result =
+ testForD8(parameters.getBackend())
+ .addProgramFiles(output1)
+ .addProgramClassFileData(PROGRAM_DATA_2)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
+ .compile();
+ result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
+ result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
+ }
+}