Version 1.6.43
Cherry pick: Require a checksum supplier for all program classes.
CL: https://r8-review.googlesource.com/c/r8/+/44921
Bug: 141736069
Change-Id: I7824c0148649a13bc8024c2cf93fc79e2a6a700b
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index ed74e0b..36adabe 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -217,7 +217,6 @@
null,
options,
marker == null ? null : ImmutableList.copyOf(markers),
- app.getChecksums(),
GraphLense.getIdentityLense(),
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(options, rewritePrefix),
null)
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index e728f6d..1ed8cac 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -100,7 +100,6 @@
null,
options,
markers,
- null,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null);
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 595e1e3..2dee6ef 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -101,7 +101,6 @@
null,
options,
markers,
- null,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null,
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 4cd2f7b..813bbd6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -207,7 +207,6 @@
appView,
options,
Collections.singletonList(marker),
- null,
graphLense,
namingLens,
proguardMapSupplier)
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index e337dd1..ff5752e 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.6.42";
+ public static final String LABEL = "1.6.43";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 6b386c5..1d09319 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -186,8 +186,7 @@
StringConsumer proguardMapConsumer = options.proguardMapConsumer;
AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
ApplicationWriter writer =
- new ApplicationWriter(
- app, null, options, null, null, null, NamingLens.getIdentityLens(), null);
+ new ApplicationWriter(app, null, options, null, null, NamingLens.getIdentityLens(), null);
writer.write(executor);
options.signalFinishedToConsumers();
compatSink.build().writeToDirectory(output, OutputMode.DexIndexed);
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index cfe4d9f..ae946fc 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -59,7 +59,6 @@
private final DexItemFactory itemFactory;
private final Timing timing;
private final AndroidApp inputApp;
- private final ClassesChecksum checksums = new ClassesChecksum();
public interface ProgramClassConflictResolver {
DexProgramClass resolveClassConflict(DexProgramClass a, DexProgramClass b);
@@ -124,10 +123,6 @@
ClassReader classReader = new ClassReader(executorService, futures);
JarClassFileReader jcf = classReader.readSources();
ThreadUtils.awaitFutures(futures);
- // Merge all the checksum gathered from the class file's CRC as well as the marker
- // implanted into the dex file.
- builder.mergeChecksums(jcf.getChecksums());
- builder.mergeChecksums(classReader.application.options.itemFactory.extractChecksum());
classReader.initializeLazyClassCollection(builder);
for (ProgramResourceProvider provider : inputApp.getProgramResourceProviders()) {
DataResourceProvider dataResourceProvider = provider.getDataResourceProvider();
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 431805b..6cdea02 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -46,12 +46,10 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
import com.google.common.collect.ObjectArrays;
-import com.google.common.primitives.Longs;
+import it.unimi.dsi.fastutil.objects.Object2LongMap;
+import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import java.io.IOException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -63,7 +61,6 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
-import java.util.zip.CRC32;
public class ApplicationWriter {
@@ -74,7 +71,6 @@
public final InternalOptions options;
public List<Marker> markers;
public List<DexString> markerStrings;
- private final ClassesChecksum checksums;
public DexIndexedConsumer programConsumer;
public final ProguardMapSupplier proguardMapSupplier;
@@ -141,7 +137,6 @@
AppView<?> appView,
InternalOptions options,
List<Marker> markers,
- ClassesChecksum checksums,
GraphLense graphLense,
NamingLens namingLens,
ProguardMapSupplier proguardMapSupplier) {
@@ -150,7 +145,6 @@
appView,
options,
markers,
- checksums,
graphLense,
namingLens,
proguardMapSupplier,
@@ -162,7 +156,6 @@
AppView<?> appView,
InternalOptions options,
List<Marker> markers,
- ClassesChecksum checksums,
GraphLense graphLense,
NamingLens namingLens,
ProguardMapSupplier proguardMapSupplier,
@@ -173,7 +166,6 @@
assert options != null;
this.options = options;
this.markers = markers;
- this.checksums = checksums;
this.graphLense = graphLense;
this.namingLens = namingLens;
this.proguardMapSupplier = proguardMapSupplier;
@@ -207,49 +199,17 @@
* This needs to be done after distribute but before dex string sorting.
*/
private void encodeChecksums(Iterable<VirtualFile> files) {
- ImmutableMap<String, Long> inputChecksums = checksums.getChecksums();
- Map<String, Long> synthesizedChecksums = Maps.newHashMap();
- for (DexProgramClass clazz : application.classes()) {
- Collection<DexProgramClass> synthesizedFrom = clazz.getSynthesizedFrom();
-
- if (synthesizedFrom.isEmpty()) {
- if (inputChecksums.containsKey(clazz.getType().descriptor.toASCIIString())) {
- continue;
- } else {
- throw new CompilationError(clazz + " from " + clazz.origin +
- " has no checksum information while checksum encoding is requested");
- }
- }
-
- // Checksum of synthesized classes are compute based off the depending input. This might
- // create false positives (ie: unchanged lambda class detected as changed even thought only
- // an unrelated part from a synthesizedFrom class is changed).
-
- // Ideally, we should use some hashcode of the dex program class that is deterministic across
- // compiles.
- ByteBuffer buffer = ByteBuffer.allocate(synthesizedFrom.size() * Longs.BYTES);
- for (DexProgramClass from : synthesizedFrom) {
- buffer.putLong(inputChecksums.get(from.getType().descriptor.toASCIIString()));
- }
- CRC32 crc = new CRC32();
- crc.update(buffer.array());
- synthesizedChecksums.put(clazz.getType().descriptor.toASCIIString(), crc.getValue());
+ List<DexProgramClass> classes = application.classes();
+ Object2LongMap<String> inputChecksums = new Object2LongOpenHashMap<>(classes.size());
+ for (DexProgramClass clazz : classes) {
+ inputChecksums.put(clazz.getType().descriptor.toASCIIString(), clazz.getChecksum());
}
-
- for (VirtualFile f : files) {
+ for (VirtualFile file : files) {
ClassesChecksum toWrite = new ClassesChecksum();
- for (String desc : f.getClassDescriptors()) {
- Long checksum = inputChecksums.get(desc);
- if (checksum == null) {
- checksum = synthesizedChecksums.get(desc);
- }
-
- // All classes should have a checksum from the inputChecksum (previous marker) or it was
- // computed eariler in the function. Otherwise, we would have throw an compilation error.
- assert checksum != null;
- toWrite.addChecksum(desc, checksum);
+ for (String desc : file.getClassDescriptors()) {
+ toWrite.addChecksum(desc, inputChecksums.getLong(desc));
}
- f.injectString(application.dexItemFactory.createString(toWrite.toString()));
+ file.injectString(application.dexItemFactory.createString(toWrite.toJsonString()));
}
}
@@ -281,7 +241,6 @@
if (options.encodeChecksums) {
encodeChecksums(virtualFiles);
}
-
application.dexItemFactory.sort(namingLens);
assert markers == null
|| markers.isEmpty()
diff --git a/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java b/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
index d5c7a64..07d2176 100644
--- a/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
+++ b/src/main/java/com/android/tools/r8/dex/ClassesChecksum.java
@@ -1,12 +1,12 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.graph.DexString;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
+import it.unimi.dsi.fastutil.objects.Object2LongMap;
+import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import java.util.Comparator;
import java.util.Map;
@@ -16,53 +16,47 @@
private static final char PREFIX_CHAR1 = '~';
private static final char PREFIX_CHAR2 = '~';
+ private Object2LongMap<String> dictionary = null;
- // private final JsonObject dictionary;
- Map<String, Long> dictionary = Maps.newHashMap();
-
- /**
- * Checksum to be inserted.
- */
public ClassesChecksum() {
}
- private ClassesChecksum(JsonObject json) {
- json.entrySet().forEach(entry ->
- dictionary.put(entry.getKey(), Long.parseLong(entry.getValue().getAsString(), 16)));
- }
-
- public synchronized ClassesChecksum addChecksum(String classDescriptor, Long crc) {
- dictionary.put(classDescriptor, crc);
- return this;
- }
-
- public synchronized ImmutableMap<String, Long> getChecksums() {
- return ImmutableMap.copyOf(dictionary);
- }
-
- public synchronized ClassesChecksum merge(ClassesChecksum other) {
- if (other != null) {
- other.dictionary.entrySet().stream().forEach(entry -> this.dictionary.put(
- entry.getKey(), entry.getValue()));
+ private void ensureMap() {
+ if (dictionary == null) {
+ dictionary = new Object2LongOpenHashMap<>();
}
- return this;
}
- @Override
- public synchronized String toString() {
+ private void append(JsonObject json) {
+ ensureMap();
+ json.entrySet()
+ .forEach(
+ entry ->
+ dictionary.put(entry.getKey(), Long.parseLong(entry.getValue().getAsString(), 16)));
+ }
+
+ public void addChecksum(String classDescriptor, long crc) {
+ ensureMap();
+ dictionary.put(classDescriptor, crc);
+ }
+
+ public Object2LongMap<String> getChecksums() {
+ return dictionary;
+ }
+
+ public String toJsonString() {
// In order to make printing of markers deterministic we sort the entries by key.
final JsonObject sortedJson = new JsonObject();
- dictionary.entrySet()
- .stream()
+ dictionary.object2LongEntrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(
- entry -> sortedJson.addProperty(entry.getKey(), Long.toHexString(entry.getValue())));
+ entry ->
+ sortedJson.addProperty(entry.getKey(), Long.toString(entry.getLongValue(), 16)));
return "" + PREFIX_CHAR0 + PREFIX_CHAR1 + PREFIX_CHAR2 + sortedJson;
}
- // Try to parse str as a marker.
- // Returns null if parsing fails.
- public static ClassesChecksum parse(DexString dexString) {
+ // Try to parse the string as a marker and append its content if successful.
+ public void tryParseAndAppend(DexString dexString) {
if (dexString.size > 2
&& dexString.content[0] == PREFIX_CHAR0
&& dexString.content[1] == PREFIX_CHAR1
@@ -71,11 +65,10 @@
try {
JsonElement result = new JsonParser().parse(str);
if (result.isJsonObject()) {
- return new ClassesChecksum(result.getAsJsonObject());
+ append(result.getAsJsonObject());
}
} catch (JsonSyntaxException ignored) {}
}
- return null;
}
public static boolean preceedChecksumMarker(DexString string) {
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 28b60a3..e722669 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -40,6 +40,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -60,11 +62,11 @@
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
-import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Object2LongMap;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -87,7 +89,7 @@
private int[] stringIDs;
private final ClassKind classKind;
private final InternalOptions options;
- private ImmutableMap<String, Long> checksums;
+ private Object2LongMap<String> checksums;
public static DexSection[] parseMapFrom(Path file) throws IOException {
return parseMapFrom(Files.newInputStream(file), new PathOrigin(file));
@@ -712,9 +714,10 @@
DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
AnnotationsDirectory annotationsDirectory = annotationsDirectoryAt(annotationsOffsets[i]);
+ Long checksum = null;
if (checksums != null && classDataOffsets[i] != 0) {
String desc = type.descriptor.toASCIIString();
- Long checksum = checksums.get(desc);
+ checksum = checksums.getOrDefault(desc, null);
if (!options.dexClassChecksumFilter.test(desc, checksum)) {
continue;
}
@@ -752,6 +755,10 @@
AttributesAndAnnotations attrs =
new AttributesAndAnnotations(type, annotationsDirectory.clazz, options.itemFactory);
+ Long finalChecksum = checksum;
+ ChecksumSupplier checksumSupplier =
+ finalChecksum == null ? DexProgramClass::invalidChecksumRequest : c -> finalChecksum;
+
DexClass clazz =
classKind.create(
type,
@@ -770,7 +777,8 @@
instanceFields,
directMethods,
virtualMethods,
- dexItemFactory.getSkipNameValidationForTesting());
+ dexItemFactory.getSkipNameValidationForTesting(),
+ checksumSupplier);
classCollection.accept(clazz); // Update the application object.
}
}
@@ -939,23 +947,15 @@
}
private void populateChecksums() {
- ClassesChecksum checksums = null;
+ ClassesChecksum parsedChecksums = new ClassesChecksum();
for (int i = stringIDs.length - 1; i >= 0; i--) {
DexString value = indexedItems.getString(i);
- ClassesChecksum checksum = ClassesChecksum.parse(value);
- if (checksum != null) {
- if (checksums == null) {
- checksums = checksum;
- } else {
- checksums.merge(checksum);
- }
- } else if (ClassesChecksum.preceedChecksumMarker(value)) {
+ if (ClassesChecksum.preceedChecksumMarker(value)) {
break;
}
+ parsedChecksums.tryParseAndAppend(value);
}
- if (checksums != null) {
- this.checksums = checksums.getChecksums();
- }
+ this.checksums = parsedChecksums.getChecksums();
}
/**
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
index 6443795..14fa13e 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -4,7 +4,8 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.origin.Origin;
import java.util.List;
import java.util.function.Consumer;
@@ -13,13 +14,89 @@
/** Kind of the application class. Can be program, classpath or library. */
public enum ClassKind {
PROGRAM(DexProgramClass::new, DexClass::isProgramClass),
- CLASSPATH(DexClasspathClass::new, DexClass::isClasspathClass),
- LIBRARY(DexLibraryClass::new, DexClass::isLibraryClass);
+ CLASSPATH(
+ (type,
+ kind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ nestHost,
+ nestMembers,
+ enclosingMember,
+ innerClasses,
+ annotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods,
+ skipNameValidationForTesting,
+ checksumSupplier) -> {
+ return new DexClasspathClass(
+ type,
+ kind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ nestHost,
+ nestMembers,
+ enclosingMember,
+ innerClasses,
+ annotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods,
+ skipNameValidationForTesting);
+ },
+ DexClass::isClasspathClass),
+ LIBRARY(
+ (type,
+ kind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ nestHost,
+ nestMembers,
+ enclosingMember,
+ innerClasses,
+ annotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods,
+ skipNameValidationForTesting,
+ checksumSupplier) -> {
+ return new DexLibraryClass(
+ type,
+ kind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ nestHost,
+ nestMembers,
+ enclosingMember,
+ innerClasses,
+ annotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods,
+ skipNameValidationForTesting);
+ },
+ DexClass::isLibraryClass);
private interface Factory {
DexClass create(
DexType type,
- ProgramResource.Kind kind,
+ Kind kind,
Origin origin,
ClassAccessFlags accessFlags,
DexType superType,
@@ -34,7 +111,8 @@
DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods,
- boolean skipNameValidationForTesting);
+ boolean skipNameValidationForTesting,
+ ChecksumSupplier checksumSupplier);
}
private final Factory factory;
@@ -47,7 +125,7 @@
public DexClass create(
DexType type,
- ProgramResource.Kind kind,
+ Kind kind,
Origin origin,
ClassAccessFlags accessFlags,
DexType superType,
@@ -62,7 +140,8 @@
DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods,
- boolean skipNameValidationForTesting) {
+ boolean skipNameValidationForTesting,
+ ChecksumSupplier checksumSupplier) {
return factory.create(
type,
kind,
@@ -80,7 +159,8 @@
instanceFields,
directMethods,
virtualMethods,
- skipNameValidationForTesting);
+ skipNameValidationForTesting,
+ checksumSupplier);
}
public boolean isOfKind(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index c2375c5..29af63e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
-import com.android.tools.r8.dex.ClassesChecksum;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.InternalOptions;
@@ -35,7 +34,6 @@
public final InternalOptions options;
public final DexItemFactory dexItemFactory;
- public final ClassesChecksum checksums;
// Information on the lexicographically largest string referenced from code.
public final DexString highestSortingString;
@@ -45,14 +43,12 @@
ClassNameMapper proguardMap,
ImmutableList<DataResourceProvider> dataResourceProviders,
ImmutableSet<DexType> mainDexList,
- ClassesChecksum checksums,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
this.proguardMap = proguardMap;
this.dataResourceProviders = dataResourceProviders;
this.mainDexList = mainDexList;
- this.checksums = checksums;
this.options = options;
this.dexItemFactory = options.itemFactory;
this.highestSortingString = highestSortingString;
@@ -108,10 +104,6 @@
return classes;
}
- public ClassesChecksum getChecksums() {
- return checksums;
- }
-
public abstract DexClass definitionFor(DexType type);
public abstract DexProgramClass programDefinitionFor(DexType type);
@@ -137,7 +129,6 @@
public final InternalOptions options;
public final DexItemFactory dexItemFactory;
- protected ClassesChecksum checksums;
ClassNameMapper proguardMap;
final Timing timing;
@@ -150,7 +141,6 @@
this.dexItemFactory = options.itemFactory;
this.timing = timing;
this.synthesizedClasses = new ArrayList<>();
- this.checksums = null;
}
abstract T self();
@@ -165,7 +155,6 @@
dexItemFactory = application.dexItemFactory;
mainDexList.addAll(application.mainDexList);
synthesizedClasses = new ArrayList<>();
- checksums = application.checksums;
}
public synchronized T setProguardMap(ClassNameMapper proguardMap) {
@@ -224,15 +213,6 @@
return this;
}
- public Builder<T> mergeChecksums(ClassesChecksum other) {
- if (checksums == null) {
- checksums = other;
- } else {
- checksums.merge(other);
- }
- return this;
- }
-
public abstract DexApplication 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 e52c246..b9df2a1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement.computeLeastUpperBoundOfInterfaces;
import static com.google.common.base.Predicates.alwaysTrue;
-import com.android.tools.r8.dex.ClassesChecksum;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
@@ -49,7 +48,6 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -1183,11 +1181,6 @@
return markers;
}
- public synchronized ClassesChecksum extractChecksum() {
- return strings.keySet().stream().map(s -> ClassesChecksum.parse(s)).filter(Objects::nonNull)
- .reduce(null, (s1, s2) -> s1 == null ? s2 : s1.merge(s2));
- }
-
synchronized public DexType createType(DexString descriptor) {
assert !sorted;
assert descriptor != null;
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 7bfe2a6..92a4963 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.kotlin.KotlinInfo;
import com.android.tools.r8.origin.Origin;
import java.util.ArrayList;
@@ -20,6 +21,12 @@
import java.util.function.Supplier;
public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {
+
+ @FunctionalInterface
+ public interface ChecksumSupplier {
+ long getChecksum(DexProgramClass programClass);
+ }
+
public static final DexProgramClass[] EMPTY_ARRAY = {};
private static final DexEncodedArray SENTINEL_NOT_YET_COMPUTED =
@@ -31,9 +38,11 @@
private int initialClassFileVersion = -1;
private KotlinInfo kotlinInfo = null;
+ private final ChecksumSupplier checksumSupplier;
+
public DexProgramClass(
DexType type,
- ProgramResource.Kind originKind,
+ Kind originKind,
Origin origin,
ClassAccessFlags accessFlags,
DexType superType,
@@ -48,7 +57,8 @@
DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods,
- boolean skipNameValidationForTesting) {
+ boolean skipNameValidationForTesting,
+ ChecksumSupplier checksumSupplier) {
this(
type,
originKind,
@@ -67,12 +77,13 @@
directMethods,
virtualMethods,
skipNameValidationForTesting,
+ checksumSupplier,
Collections.emptyList());
}
public DexProgramClass(
DexType type,
- ProgramResource.Kind originKind,
+ Kind originKind,
Origin origin,
ClassAccessFlags accessFlags,
DexType superType,
@@ -88,6 +99,7 @@
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods,
boolean skipNameValidationForTesting,
+ ChecksumSupplier checksumSupplier,
Collection<DexProgramClass> synthesizedDirectlyFrom) {
super(
sourceFile,
@@ -106,8 +118,10 @@
classAnnotations,
origin,
skipNameValidationForTesting);
+ assert checksumSupplier != null;
assert classAnnotations != null;
this.originKind = originKind;
+ this.checksumSupplier = checksumSupplier;
this.synthesizedFrom = new HashSet<>();
synthesizedDirectlyFrom.forEach(this::addSynthesizedFrom);
}
@@ -471,4 +485,17 @@
}
};
}
+
+ public static long invalidChecksumRequest(DexProgramClass clazz) {
+ throw new CompilationError(
+ clazz + " has no checksum information while checksum encoding is requested", clazz.origin);
+ }
+
+ public static long checksumFromType(DexProgramClass clazz) {
+ return clazz.type.hashCode();
+ }
+
+ public long getChecksum() {
+ return checksumSupplier.getChecksum(this);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index efe63f6..6308a16 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -7,7 +7,6 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.DataResourceProvider;
-import com.android.tools.r8.dex.ClassesChecksum;
import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.InternalOptions;
@@ -41,7 +40,6 @@
ImmutableList<DexLibraryClass> libraryClasses,
ImmutableList<DataResourceProvider> dataResourceProviders,
ImmutableSet<DexType> mainDexList,
- ClassesChecksum checksums,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
@@ -49,7 +47,6 @@
proguardMap,
dataResourceProviders,
mainDexList,
- checksums,
options,
highestSortingString,
timing);
@@ -203,7 +200,6 @@
libraryClasses,
ImmutableList.copyOf(dataResourceProviders),
ImmutableSet.copyOf(mainDexList),
- checksums,
options,
highestSortingString,
timing);
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 1c359f3..d6fbdba 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -12,10 +12,10 @@
import static org.objectweb.asm.Opcodes.V9;
import com.android.tools.r8.ProgramResource.Kind;
-import com.android.tools.r8.dex.ClassesChecksum;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueBoolean;
@@ -75,13 +75,11 @@
private final JarApplicationReader application;
private final Consumer<DexClass> classConsumer;
- private final ClassesChecksum checksums;
public JarClassFileReader(
JarApplicationReader application, Consumer<DexClass> classConsumer) {
this.application = application;
this.classConsumer = classConsumer;
- this.checksums = new ClassesChecksum();
}
public void read(Origin origin, ClassKind classKind, InputStream input) throws IOException {
@@ -116,8 +114,9 @@
parsingOptions |= SKIP_DEBUG;
}
}
- reader.accept(new CreateDexClassVisitor(
- origin, classKind, reader.b, application, classConsumer, checksums), parsingOptions);
+ reader.accept(
+ new CreateDexClassVisitor(origin, classKind, reader.b, application, classConsumer),
+ parsingOptions);
// Read marker.
if (reader.getItemCount() > CfApplicationWriter.MARKER_STRING_CONSTANT_POOL_INDEX
@@ -136,10 +135,6 @@
}
}
- public ClassesChecksum getChecksums() {
- return checksums;
- }
-
private static int cleanAccessFlags(int access) {
// Clear the "synthetic attribute" and "deprecated" attribute-flags if present.
return access & ~ACC_SYNTHETIC_ATTRIBUTE & ~ACC_DEPRECATED;
@@ -218,22 +213,19 @@
private final List<DexEncodedMethod> virtualMethods = new ArrayList<>();
private final Set<Wrapper<DexMethod>> methodSignatures = new HashSet<>();
private boolean hasReachabilitySensitiveMethod = false;
- private ClassesChecksum checksums;
public CreateDexClassVisitor(
Origin origin,
ClassKind classKind,
byte[] classCache,
JarApplicationReader application,
- Consumer<DexClass> classConsumer,
- ClassesChecksum checksums) {
+ Consumer<DexClass> classConsumer) {
super(ASM_VERSION);
this.origin = origin;
this.classKind = classKind;
this.classConsumer = classConsumer;
this.context.classCache = classCache;
this.application = application;
- this.checksums = checksums;
}
@Override
@@ -419,7 +411,8 @@
instanceFields.toArray(DexEncodedField.EMPTY_ARRAY),
directMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
virtualMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
- application.getFactory().getSkipNameValidationForTesting());
+ application.getFactory().getSkipNameValidationForTesting(),
+ getChecksumSupplier(classKind));
InnerClassAttribute innerClassAttribute = clazz.getInnerClassAttributeForThisClass();
// A member class should not be a local or anonymous class.
if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
@@ -453,16 +446,22 @@
context.owner = clazz;
}
if (clazz.isProgramClass()) {
- clazz.asProgramClass().setInitialClassFileVersion(version);
- if (application.options.encodeChecksums) {
- CRC32 crc = new CRC32();
- crc.update(this.context.classCache);
- checksums.addChecksum(type.descriptor.toASCIIString(), crc.getValue());
- }
+ DexProgramClass programClass = clazz.asProgramClass();
+ programClass.setInitialClassFileVersion(version);
}
classConsumer.accept(clazz);
}
+ private ChecksumSupplier getChecksumSupplier(ClassKind classKind) {
+ if (application.options.encodeChecksums && classKind == ClassKind.PROGRAM) {
+ CRC32 crc = new CRC32();
+ crc.update(this.context.classCache, 0, this.context.classCache.length);
+ final long value = crc.getValue();
+ return clazz -> value;
+ }
+ return DexProgramClass::invalidChecksumRequest;
+ }
+
private void checkName(String name) {
if (!application.getFactory().getSkipNameValidationForTesting()
&& !DexString.isValidSimpleName(application.options.minApiLevel, name)) {
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 0458321..24ec3c3 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
-import com.android.tools.r8.dex.ClassesChecksum;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.ClasspathClassCollection;
import com.android.tools.r8.utils.InternalOptions;
@@ -36,7 +35,6 @@
ClasspathClassCollection classpathClasses,
LibraryClassCollection libraryClasses,
ImmutableSet<DexType> mainDexList,
- ClassesChecksum checksum,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
@@ -44,7 +42,6 @@
proguardMap,
dataResourceProviders,
mainDexList,
- checksum,
options,
highestSortingString,
timing);
@@ -236,7 +233,6 @@
classpathClasses,
libraryClasses,
ImmutableSet.copyOf(mainDexList),
- checksums,
options,
highestSortingString,
timing);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 0e13782..09f2b7e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -48,6 +49,7 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
@@ -184,6 +186,7 @@
new DexEncodedMethod[] {dexEncodedMethod},
DexEncodedMethod.EMPTY_ARRAY,
factory.getSkipNameValidationForTesting(),
+ getChecksumSupplier(dexEncodedMethod),
referencingClasses);
boolean addToMainDexList =
referencingClasses.stream()
@@ -195,6 +198,14 @@
}
}
+ private ChecksumSupplier getChecksumSupplier(DexEncodedMethod method) {
+ if (!appView.options().encodeChecksums) {
+ return DexProgramClass::invalidChecksumRequest;
+ }
+ long hash = Objects.hash(method, method.getCode());
+ return c -> hash;
+ }
+
private MethodProvider getMethodProviderOrNull(DexMethod method) {
DexMethod original = appView.graphLense().getOriginalMethodSignature(method);
assert original != null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 320935f..0cb8a52 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -732,6 +732,7 @@
emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
DexEncodedMethod.EMPTY_ARRAY,
factory.getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType,
Collections.singletonList(theInterface));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 8a990f2..8b8ef05 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
@@ -190,10 +191,19 @@
companionMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
DexEncodedMethod.EMPTY_ARRAY,
rewriter.factory.getSkipNameValidationForTesting(),
+ getChecksumSupplier(iface),
Collections.singletonList(iface));
syntheticClasses.put(iface.type, companionClass);
}
+ private ChecksumSupplier getChecksumSupplier(DexProgramClass iface) {
+ if (!appView.options().encodeChecksums) {
+ return DexProgramClass::invalidChecksumRequest;
+ }
+ long checksum = iface.getChecksum();
+ return c -> 7 * checksum;
+ }
+
List<DexEncodedMethod> process(DexLibraryClass iface, Set<DexProgramClass> callers) {
assert iface.isInterface();
@@ -263,6 +273,7 @@
dispatchMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
DexEncodedMethod.EMPTY_ARRAY,
rewriter.factory.getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType,
callers);
syntheticClasses.put(iface.type, dispatchClass);
return dispatchMethods;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index a397cd7..40932cb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -30,12 +30,15 @@
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.google.common.base.Suppliers;
+import com.google.common.primitives.Longs;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
+import java.util.zip.CRC32;
/**
* Represents lambda class generated for a lambda descriptor in context of lambda instantiation
@@ -167,7 +170,8 @@
synthesizeInstanceFields(),
synthesizeDirectMethods(),
synthesizeVirtualMethods(mainMethod),
- rewriter.factory.getSkipNameValidationForTesting());
+ rewriter.factory.getSkipNameValidationForTesting(),
+ LambdaClass::computeChecksumForSynthesizedClass);
// Optimize main method.
rewriter.converter.appView.appInfo().addSynthesizedClass(clazz);
rewriter.converter.optimizeSynthesizedMethod(clazz.lookupVirtualMethod(mainMethod));
@@ -180,6 +184,24 @@
return clazz;
}
+ private static long computeChecksumForSynthesizedClass(DexProgramClass clazz) {
+ // Checksum of synthesized classes are compute based off the depending input. This might
+ // create false positives (ie: unchanged lambda class detected as changed even thought only
+ // an unrelated part from a synthesizedFrom class is changed).
+
+ // Ideally, we should use some hashcode of the dex program class that is deterministic across
+ // compiles.
+ Collection<DexProgramClass> synthesizedFrom = clazz.getSynthesizedFrom();
+ ByteBuffer buffer = ByteBuffer.allocate(synthesizedFrom.size() * Longs.BYTES);
+ for (DexProgramClass from : synthesizedFrom) {
+ buffer.putLong(from.getChecksum());
+ }
+ CRC32 crc = new CRC32();
+ byte[] array = buffer.array();
+ crc.update(array, 0, array.length);
+ return crc.getValue();
+ }
+
final DexField getCaptureField(int index) {
return rewriter.factory.createField(this.type,
descriptor.captures.values[index], rewriter.factory.createString("f$" + index));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 449f404..e8e7b14 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -164,7 +164,8 @@
DexEncodedField.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY,
- appView.dexItemFactory().getSkipNameValidationForTesting());
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType);
}
void synthetizeNestConstructor(DexApplication.Builder<?> builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index 12d43cb..c94d5b0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -152,6 +152,7 @@
new DexEncodedMethod[] {method},
DexEncodedMethod.EMPTY_ARRAY,
appView.dexItemFactory().getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType,
referencingClasses);
// Process created class and method.
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 4837545..cbdf50d 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
@@ -19,6 +19,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -1342,27 +1343,29 @@
DexTypeList interfaces = DexTypeList.empty();
DexString sourceFile = appView.dexItemFactory().createString("outline");
ClassAccessFlags accessFlags = ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC);
- DexProgramClass clazz =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("outlining", getClass()),
- accessFlags,
- superType,
- interfaces,
- sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- // TODO: Build dex annotations structure.
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY, // Static fields.
- DexEncodedField.EMPTY_ARRAY, // Instance fields.
- direct,
- DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
- appView.dexItemFactory().getSkipNameValidationForTesting());
- return clazz;
+ assert !appView.options().encodeChecksums;
+ // The outliner is R8 only and checksum is not a supported part of R8 compilation.
+ ChecksumSupplier checksumSupplier = DexProgramClass::invalidChecksumRequest;
+ return new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin("outlining", getClass()),
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ // TODO: Build dex annotations structure.
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY, // Static fields.
+ DexEncodedField.EMPTY_ARRAY, // Instance fields.
+ direct,
+ DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ checksumSupplier);
}
private List<Outline> selectOutlines() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
index 7830f6e..451788f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
@@ -184,6 +185,8 @@
DexType serviceLoaderType =
appView.dexItemFactory().createType("L" + SERVICE_LOADER_CLASS_NAME + ";");
if (synthesizedClass == null) {
+ assert !appView.options().encodeChecksums;
+ ChecksumSupplier checksumSupplier = DexProgramClass::invalidChecksumRequest;
synthesizedClass =
new DexProgramClass(
serviceLoaderType,
@@ -203,7 +206,8 @@
DexEncodedField.EMPTY_ARRAY, // Instance fields.
DexEncodedMethod.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
- appView.dexItemFactory().getSkipNameValidationForTesting());
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ checksumSupplier);
appView.appInfo().addSynthesizedClass(synthesizedClass);
}
DexProto proto = appView.dexItemFactory().createProto(appView.dexItemFactory().iteratorType);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
index 4ce3033..5c3e91c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
import com.android.tools.r8.kotlin.Kotlin;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
@@ -166,13 +167,19 @@
protected abstract String getGroupSuffix();
- final DexProgramClass synthesizeClass(DexItemFactory factory) {
+ final DexProgramClass synthesizeClass(InternalOptions options) {
assert classType == null;
assert verifyLambdaIds(true);
List<LambdaInfo> lambdas = Lists.newArrayList(this.lambdas.values());
- classType = factory.createType(
- "L" + getTypePackage() + "-$$LambdaGroup$" + getGroupSuffix() + createHash(lambdas) + ";");
- return getBuilder(factory).synthesizeClass();
+ classType =
+ options.itemFactory.createType(
+ "L"
+ + getTypePackage()
+ + "-$$LambdaGroup$"
+ + getGroupSuffix()
+ + createHash(lambdas)
+ + ";");
+ return getBuilder(options.itemFactory).synthesizeClass(options);
}
protected abstract LambdaGroupClassBuilder getBuilder(DexItemFactory factory);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
index 4f5f110..e569714 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.utils.InternalOptions;
import java.util.Collections;
import java.util.List;
@@ -31,28 +32,31 @@
this.origin = origin;
}
- public final DexProgramClass synthesizeClass() {
+ public final DexProgramClass synthesizeClass(InternalOptions options) {
DexType groupClassType = group.getGroupClassType();
DexType superClassType = getSuperClassType();
-
- return new DexProgramClass(
- groupClassType,
- null,
- new SynthesizedOrigin(origin, getClass()),
- buildAccessFlags(),
- superClassType,
- buildInterfaces(),
- factory.createString(origin),
- null,
- Collections.emptyList(),
- buildEnclosingMethodAttribute(),
- buildInnerClasses(),
- buildAnnotations(),
- buildStaticFields(),
- buildInstanceFields(),
- buildDirectMethods(),
- buildVirtualMethods(),
- factory.getSkipNameValidationForTesting());
+ DexProgramClass programClass =
+ new DexProgramClass(
+ groupClassType,
+ null,
+ new SynthesizedOrigin(origin, getClass()),
+ buildAccessFlags(),
+ superClassType,
+ buildInterfaces(),
+ factory.createString(origin),
+ null,
+ Collections.emptyList(),
+ buildEnclosingMethodAttribute(),
+ buildInnerClasses(),
+ buildAnnotations(),
+ buildStaticFields(),
+ buildInstanceFields(),
+ buildDirectMethods(),
+ buildVirtualMethods(),
+ factory.getSkipNameValidationForTesting(),
+ // The name of the class is based on the hash of the content.
+ DexProgramClass::checksumFromType);
+ return programClass;
}
protected abstract DexType getSuperClassType();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 89451c9..24d4548 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -327,7 +327,7 @@
for (LambdaGroup group : groups.values()) {
assert !group.isTrivial() : "No trivial group is expected here.";
group.compact();
- DexProgramClass lambdaGroupClass = group.synthesizeClass(factory);
+ DexProgramClass lambdaGroupClass = group.synthesizeClass(appView.options());
result.put(group, lambdaGroupClass);
// We have to register this new class as a subtype of object.
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index 8b40ea9..5b94aac 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -87,49 +87,60 @@
code);
}
- private DexProgramClass makeClass(String name, int stringCount, int startOffset,
+ private DexProgramClass makeClass(
+ InternalOptions options,
+ String name,
+ int stringCount,
+ int startOffset,
Collection<DexProgramClass> synthesizedFrom) {
String desc = DescriptorUtils.javaTypeToDescriptor(name);
DexType type = dexItemFactory.createType(desc);
- return new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("test", getClass()),
- ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC),
- dexItemFactory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- new DexEncodedMethod[] {makeMethod(type, stringCount, startOffset)},
- false,
- synthesizedFrom);
+ DexProgramClass programClass =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin("test", getClass()),
+ ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC),
+ dexItemFactory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ new DexEncodedMethod[] {makeMethod(type, stringCount, startOffset)},
+ false,
+ DexProgramClass::invalidChecksumRequest,
+ synthesizedFrom);
+ return programClass;
}
@Test
public void manyFilesWithSharedSynthesizedClass() throws ExecutionException, IOException {
+ InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
// Create classes that all reference enough strings to overflow the index, but are all
// at different offsets in the strings array. This ensures we trigger multiple rounds of
// rewrites.
List<DexProgramClass> classes = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_FILES; i++) {
- classes.add(makeClass("Class" + i, Constants.MAX_NON_JUMBO_INDEX - 1, i % 100,
- Collections.emptyList()));
+ classes.add(
+ makeClass(
+ options,
+ "Class" + i,
+ Constants.MAX_NON_JUMBO_INDEX - 1,
+ i % 100,
+ Collections.emptyList()));
}
// Create a shared class that references strings above the maximum.
- DexProgramClass sharedSynthesizedClass = makeClass("SharedSynthesized", 100,
- Constants.MAX_NON_JUMBO_INDEX - 1,
- classes);
+ DexProgramClass sharedSynthesizedClass =
+ makeClass(options, "SharedSynthesized", 100, Constants.MAX_NON_JUMBO_INDEX - 1, classes);
- InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
DexApplication.Builder builder =
DirectMappedDexApplication.builder(options, new Timing("SharedClassWritingTest"));
builder.addSynthesizedClass(sharedSynthesizedClass, false);
@@ -144,7 +155,6 @@
null,
options,
null,
- null,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null);
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 fdc4296..6ebd77c 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -836,7 +836,7 @@
method.setCode(ir, allocator, appView);
directMethods[i] = method;
}
- builder.addProgramClass(
+ DexProgramClass programClass =
new DexProgramClass(
type,
null,
@@ -854,7 +854,9 @@
DexEncodedField.EMPTY_ARRAY,
directMethods,
DexEncodedMethod.EMPTY_ARRAY,
- false));
+ false,
+ DexProgramClass::invalidChecksumRequest);
+ builder.addProgramClass(programClass);
}
DirectMappedDexApplication application = builder.build().toDirect();
ApplicationWriter writer =
@@ -863,7 +865,6 @@
null,
options,
null,
- null,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null);
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 3d1ec2b..0092be2 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -117,7 +117,6 @@
null,
options,
null,
- null,
GraphLense.getIdentityLense(),
NamingLens.getIdentityLens(),
null);