[Retrace] Add metadata to partitioning and joining
Bug: b/201666766
Bug: b/211603371
Change-Id: Iefc8217346f4efd85d045117c30a2215a2b34ca9
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 9591d26..668f6de 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -418,7 +418,7 @@
return mapVersions;
}
- public MapVersionMappingInformation getFirstMappingInformation() {
+ public MapVersionMappingInformation getFirstMapVersionInformation() {
return mapVersions.isEmpty() ? null : mapVersions.iterator().next();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/MappingPartitionKeyInfo.java b/src/main/java/com/android/tools/r8/retrace/MappingPartitionKeyInfo.java
deleted file mode 100644
index 56f20b1..0000000
--- a/src/main/java/com/android/tools/r8/retrace/MappingPartitionKeyInfo.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2022, 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.retrace;
-
-import com.android.tools.r8.Keep;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.TypeReference;
-import java.util.function.Consumer;
-
-@Keep
-public interface MappingPartitionKeyInfo {
-
- void getKeysForClass(ClassReference reference, Consumer<String> keyConsumer);
-
- void getKeysForClassAndMethodName(
- ClassReference reference, String methodName, Consumer<String> keyConsumer);
-
- void getKeysForMethod(MethodReference reference, Consumer<String> keyConsumer);
-
- void getKeysForField(FieldReference fieldReference, Consumer<String> keyConsumer);
-
- void getKeysForType(TypeReference typeReference, Consumer<String> keyConsumer);
-
- static MappingPartitionKeyInfo getDefault(byte[] metadata) {
- return null;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/MappingSupplier.java b/src/main/java/com/android/tools/r8/retrace/MappingSupplier.java
index d5a8f6a..707023d 100644
--- a/src/main/java/com/android/tools/r8/retrace/MappingSupplier.java
+++ b/src/main/java/com/android/tools/r8/retrace/MappingSupplier.java
@@ -18,7 +18,8 @@
*
* @param classReference The minified class reference allowed to be lookup up.
*/
- public abstract T registerClassUse(ClassReference classReference);
+ public abstract T registerClassUse(
+ DiagnosticsHandler diagnosticsHandler, ClassReference classReference);
public abstract void verifyMappingFileHash(DiagnosticsHandler diagnosticsHandler);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/MappingSupplierBuilder.java b/src/main/java/com/android/tools/r8/retrace/MappingSupplierBuilder.java
index c57d88a..2a8a646 100644
--- a/src/main/java/com/android/tools/r8/retrace/MappingSupplierBuilder.java
+++ b/src/main/java/com/android/tools/r8/retrace/MappingSupplierBuilder.java
@@ -8,7 +8,7 @@
@Keep
public abstract class MappingSupplierBuilder<
- P extends MappingSupplier, T extends MappingSupplierBuilder<P, T>> {
+ P extends MappingSupplier<P>, T extends MappingSupplierBuilder<P, T>> {
public abstract T self();
diff --git a/src/main/java/com/android/tools/r8/retrace/PartitionMappingSupplier.java b/src/main/java/com/android/tools/r8/retrace/PartitionMappingSupplier.java
new file mode 100644
index 0000000..cec8467
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/PartitionMappingSupplier.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2022, 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.retrace;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.retrace.internal.PartitionMappingSupplierBuilderImpl;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+@Keep
+public abstract class PartitionMappingSupplier extends MappingSupplier<PartitionMappingSupplier> {
+
+ public static Builder builder() {
+ return new PartitionMappingSupplierBuilderImpl();
+ }
+
+ @Keep
+ public abstract static class Builder
+ extends MappingSupplierBuilder<PartitionMappingSupplier, Builder> {
+
+ /***
+ * Sets the serialized metadata that was obtained when partitioning.
+ *
+ * @param metadata the serialized metadata
+ */
+ public abstract Builder setMetadata(byte[] metadata);
+
+ /***
+ * Callback to be notified of a partition that is later going to be needed. When all needed
+ * partitions has been found, the callback specified to {@code setPrepareNewPartitions} will
+ * be called.
+ *
+ * @param partitionToFetchConsumer the consumer to get keys for partitions.
+ */
+ public abstract Builder setPartitionToFetchConsumer(Consumer<String> partitionToFetchConsumer);
+
+ /***
+ * A callback notifying that all partitions should be prepared.
+ *
+ * @param run the callback to listen for when partitions should be prepared.
+ */
+ public abstract Builder setPrepareNewPartitions(Runnable run);
+
+ /***
+ * Set the partition supplier that is needed for retracing. All partitions needed has been
+ * declared earlier and this should block until the bytes associated with the partition is
+ * ready.
+ *
+ * @param supplier the function to return a partition to retrace
+ */
+ public abstract Builder setPartitionSupplier(Function<String, byte[]> supplier);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index bb1bd0e..8cc063e 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -361,14 +361,18 @@
parsedStackTrace.forEach(
proxy -> {
if (proxy.hasClassName()) {
- mappingSupplier.registerClassUse(proxy.getClassReference());
+ mappingSupplier.registerClassUse(diagnosticsHandler, proxy.getClassReference());
}
if (proxy.hasMethodArguments()) {
Arrays.stream(proxy.getMethodArguments().split(","))
- .forEach(typeName -> registerUseFromTypeReference(mappingSupplier, typeName));
+ .forEach(
+ typeName ->
+ registerUseFromTypeReference(
+ mappingSupplier, typeName, diagnosticsHandler));
}
if (proxy.hasFieldOrReturnType() && !proxy.getFieldOrReturnType().equals("void")) {
- registerUseFromTypeReference(mappingSupplier, proxy.getFieldOrReturnType());
+ registerUseFromTypeReference(
+ mappingSupplier, proxy.getFieldOrReturnType(), diagnosticsHandler);
}
});
timing.begin("Retracing");
@@ -393,13 +397,13 @@
}
private static void registerUseFromTypeReference(
- MappingSupplier<?> mappingSupplier, String typeName) {
+ MappingSupplier<?> mappingSupplier, String typeName, DiagnosticsHandler diagnosticsHandler) {
TypeReference typeReference = Reference.typeFromTypeName(typeName);
if (typeReference.isArray()) {
typeReference = typeReference.asArray().getBaseType();
}
if (typeReference.isClass()) {
- mappingSupplier.registerClassUse(typeReference.asClass());
+ mappingSupplier.registerClassUse(diagnosticsHandler, typeReference.asClass());
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionKeyStrategy.java b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionKeyStrategy.java
new file mode 100644
index 0000000..ad53968
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionKeyStrategy.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2022, 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.retrace.internal;
+
+public enum MappingPartitionKeyStrategy {
+ OBFUSCATED_TYPE_NAME_AS_KEY(0);
+
+ final int serializedKey;
+
+ MappingPartitionKeyStrategy(int serializedKey) {
+ this.serializedKey = serializedKey;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
new file mode 100644
index 0000000..6c2e3ca
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, 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.retrace.internal;
+
+import static com.android.tools.r8.retrace.internal.MappingPartitionKeyStrategy.OBFUSCATED_TYPE_NAME_AS_KEY;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.google.common.primitives.Ints;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public interface MappingPartitionMetadataInternal extends MappingPartitionMetadata {
+
+ String getKey(ClassReference classReference);
+
+ MapVersion getMapVersion();
+
+ byte ZERO_BYTE = (byte) 0;
+
+ static MappingPartitionMetadataInternal createFromBytes(
+ byte[] bytes, MapVersion fallBackMapVersion, DiagnosticsHandler diagnosticsHandler) {
+ if (bytes == null) {
+ return obfuscatedTypeNameAsKey(fallBackMapVersion);
+ } else if (bytes.length > 2) {
+ int serializedStrategyId = Ints.fromBytes(ZERO_BYTE, ZERO_BYTE, bytes[0], bytes[1]);
+ MapVersion mapVersion = MapVersion.fromName(new String(bytes, 2, bytes.length - 2));
+ if (serializedStrategyId == OBFUSCATED_TYPE_NAME_AS_KEY.serializedKey) {
+ return obfuscatedTypeNameAsKey(mapVersion);
+ }
+ }
+ RuntimeException exception = new RuntimeException("Unable to build key strategy from metadata");
+ diagnosticsHandler.error(new ExceptionDiagnostic(exception));
+ throw exception;
+ }
+
+ static ObfuscatedTypeNameAsKeyMetadata obfuscatedTypeNameAsKey(MapVersion mapVersion) {
+ return new ObfuscatedTypeNameAsKeyMetadata(mapVersion);
+ }
+
+ class ObfuscatedTypeNameAsKeyMetadata implements MappingPartitionMetadataInternal {
+
+ private final MapVersion mapVersion;
+
+ private ObfuscatedTypeNameAsKeyMetadata(MapVersion mapVersion) {
+ this.mapVersion = mapVersion;
+ }
+
+ @Override
+ public String getKey(ClassReference classReference) {
+ return classReference.getTypeName();
+ }
+
+ @Override
+ public MapVersion getMapVersion() {
+ return mapVersion;
+ }
+
+ @Override
+ public byte[] getBytes() {
+ try {
+ ByteArrayOutputStream temp = new ByteArrayOutputStream();
+ DataOutputStream dataOutputStream = new DataOutputStream(temp);
+ dataOutputStream.writeShort(OBFUSCATED_TYPE_NAME_AS_KEY.serializedKey);
+ dataOutputStream.writeBytes(mapVersion.getName());
+ dataOutputStream.close();
+ return temp.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierBuilderImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierBuilderImpl.java
new file mode 100644
index 0000000..f100f97
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierBuilderImpl.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, 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.retrace.internal;
+
+import com.android.tools.r8.retrace.PartitionMappingSupplier;
+import com.android.tools.r8.utils.ConsumerUtils;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class PartitionMappingSupplierBuilderImpl extends PartitionMappingSupplier.Builder {
+
+ private Function<String, byte[]> partitionSupplier;
+ private Consumer<String> partitionToFetchConsumer = ConsumerUtils.emptyConsumer();
+ private Runnable prepare = () -> {};
+ private byte[] metadata;
+ private boolean allowExperimental = false;
+
+ @Override
+ public PartitionMappingSupplier.Builder self() {
+ return this;
+ }
+
+ @Override
+ public PartitionMappingSupplier.Builder setAllowExperimental(boolean allowExperimental) {
+ this.allowExperimental = allowExperimental;
+ return self();
+ }
+
+ @Override
+ public PartitionMappingSupplier.Builder setMetadata(byte[] metadata) {
+ this.metadata = metadata;
+ return self();
+ }
+
+ @Override
+ public PartitionMappingSupplier.Builder setPartitionSupplier(
+ Function<String, byte[]> partitionSupplier) {
+ this.partitionSupplier = partitionSupplier;
+ return self();
+ }
+
+ @Override
+ public PartitionMappingSupplier.Builder setPartitionToFetchConsumer(
+ Consumer<String> partitionToFetchConsumer) {
+ this.partitionToFetchConsumer = partitionToFetchConsumer;
+ return self();
+ }
+
+ @Override
+ public PartitionMappingSupplier.Builder setPrepareNewPartitions(Runnable prepare) {
+ this.prepare = prepare;
+ return self();
+ }
+
+ @Override
+ public PartitionMappingSupplier build() {
+ return new PartitionMappingSupplierImpl(
+ metadata, partitionToFetchConsumer, prepare, partitionSupplier, allowExperimental);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierImpl.java
new file mode 100644
index 0000000..7d7708d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/PartitionMappingSupplierImpl.java
@@ -0,0 +1,131 @@
+// Copyright (c) 2022, 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.retrace.internal;
+
+import static com.google.common.base.Predicates.alwaysTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.ClassNamingForNameMapper;
+import com.android.tools.r8.naming.LineReader;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.InvalidMappingFileException;
+import com.android.tools.r8.retrace.PartitionMappingSupplier;
+import com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.ProguardMapReaderWithFilteringInputBuffer;
+import com.android.tools.r8.utils.StringDiagnostic;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * IntelliJ highlights the class as being invalid because it cannot see getClassNameMapper is
+ * defined on the class for some reason.
+ */
+public class PartitionMappingSupplierImpl extends PartitionMappingSupplier {
+
+ private final byte[] metadata;
+ private final Consumer<String> partitionToFetchConsumer;
+ private final Runnable prepare;
+ private final Function<String, byte[]> partitionSupplier;
+ private final boolean allowExperimental;
+
+ private ClassNameMapper classNameMapper;
+ private final Set<String> pendingKeys = new LinkedHashSet<>();
+ private final Set<String> builtKeys = new HashSet<>();
+
+ private MappingPartitionMetadataInternal mappingPartitionMetadataCache;
+
+ PartitionMappingSupplierImpl(
+ byte[] metadata,
+ Consumer<String> partitionToFetchConsumer,
+ Runnable prepare,
+ Function<String, byte[]> partitionSupplier,
+ boolean allowExperimental) {
+ this.metadata = metadata;
+ this.partitionToFetchConsumer = partitionToFetchConsumer;
+ this.prepare = prepare;
+ this.partitionSupplier = partitionSupplier;
+ this.allowExperimental = allowExperimental;
+ }
+
+ private MappingPartitionMetadataInternal getMetadata(DiagnosticsHandler diagnosticsHandler) {
+ return mappingPartitionMetadataCache =
+ MappingPartitionMetadataInternal.createFromBytes(
+ metadata, MapVersion.MAP_VERSION_NONE, diagnosticsHandler);
+ }
+
+ @Override
+ Set<MapVersionMappingInformation> getMapVersions(DiagnosticsHandler diagnosticsHandler) {
+ return Collections.singleton(
+ new MapVersionMappingInformation(getMetadata(diagnosticsHandler).getMapVersion(), ""));
+ }
+
+ @Override
+ ClassNamingForNameMapper getClassNaming(DiagnosticsHandler diagnosticsHandler, String typeName) {
+ registerClassUse(diagnosticsHandler, Reference.classFromTypeName(typeName));
+ return getClassNameMapper(diagnosticsHandler).getClassNaming(typeName);
+ }
+
+ @Override
+ String getSourceFileForClass(DiagnosticsHandler diagnosticsHandler, String typeName) {
+ // Getting source file should not trigger new fetches of partitions so we are not calling
+ // register here.
+ return getClassNameMapper(diagnosticsHandler).getSourceFile(typeName);
+ }
+
+ private ClassNameMapper getClassNameMapper(DiagnosticsHandler diagnosticsHandler) {
+ MappingPartitionMetadataInternal metadata = getMetadata(diagnosticsHandler);
+ if (!pendingKeys.isEmpty()) {
+ prepare.run();
+ }
+ for (String pendingKey : pendingKeys) {
+ try {
+ LineReader reader =
+ new ProguardMapReaderWithFilteringInputBuffer(
+ new ByteArrayInputStream(partitionSupplier.apply(pendingKey)), alwaysTrue(), true);
+ classNameMapper =
+ ClassNameMapper.mapperFromLineReaderWithFiltering(
+ reader, metadata.getMapVersion(), diagnosticsHandler, true, allowExperimental)
+ .combine(this.classNameMapper);
+ } catch (IOException e) {
+ throw new InvalidMappingFileException(e);
+ }
+ }
+ builtKeys.addAll(pendingKeys);
+ pendingKeys.clear();
+ if (classNameMapper == null) {
+ classNameMapper = ClassNameMapper.builder().build();
+ }
+ return classNameMapper;
+ }
+
+ @Override
+ public PartitionMappingSupplier registerClassUse(
+ DiagnosticsHandler diagnosticsHandler, ClassReference classReference) {
+ registerKeyUse(getMetadata(diagnosticsHandler).getKey(classReference));
+ return this;
+ }
+
+ private void registerKeyUse(String key) {
+ if (!builtKeys.contains(key) && pendingKeys.add(key)) {
+ partitionToFetchConsumer.accept(key);
+ }
+ }
+
+ @Override
+ public void verifyMappingFileHash(DiagnosticsHandler diagnosticsHandler) {
+ String errorMessage = "Cannot verify map file hash for partitions";
+ diagnosticsHandler.error(new StringDiagnostic(errorMessage));
+ throw new RuntimeException(errorMessage);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
index 6253f1a..dc0f565 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.LineReader;
import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
import com.android.tools.r8.retrace.MappingPartition;
import com.android.tools.r8.retrace.MappingPartitionMetadata;
import com.android.tools.r8.retrace.ProguardMapPartitioner;
@@ -55,8 +56,9 @@
proguardMapProducer.get(), alwaysTrue(), true));
// Produce a global mapper to read all from the reader but also to capture all source file
// mappings.
- ClassNameMapper.mapperFromLineReaderWithFiltering(
- reader, MapVersion.MAP_VERSION_UNKNOWN, diagnosticsHandler, true, true);
+ ClassNameMapper classMapper =
+ ClassNameMapper.mapperFromLineReaderWithFiltering(
+ reader, MapVersion.MAP_VERSION_UNKNOWN, diagnosticsHandler, true, true);
// We can then iterate over all sections.
reader.forEachClassMapping(
(classMapping, entries) -> {
@@ -77,7 +79,12 @@
diagnosticsHandler.error(new ExceptionDiagnostic(e));
}
});
- return null;
+ MapVersion mapVersion = MapVersion.MAP_VERSION_UNKNOWN;
+ MapVersionMappingInformation mapVersionInfo = classMapper.getFirstMapVersionInformation();
+ if (mapVersionInfo != null) {
+ mapVersion = mapVersionInfo.getMapVersion();
+ }
+ return MappingPartitionMetadataInternal.obfuscatedTypeNameAsKey(mapVersion);
}
public static class PartitionLineReader implements LineReader {
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
index a6ae27b..632ca66 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
@@ -112,13 +112,14 @@
if (classNameMapper == null) {
return MapVersion.MAP_VERSION_NONE;
} else {
- MapVersionMappingInformation mapVersion = classNameMapper.getFirstMappingInformation();
+ MapVersionMappingInformation mapVersion = classNameMapper.getFirstMapVersionInformation();
return mapVersion == null ? MapVersion.MAP_VERSION_UNKNOWN : mapVersion.getMapVersion();
}
}
@Override
- public ProguardMappingSupplier registerClassUse(ClassReference classReference) {
+ public ProguardMappingSupplier registerClassUse(
+ DiagnosticsHandler diagnosticsHandler, ClassReference classReference) {
if (!hasClassMappingFor(classReference.getTypeName())) {
pendingClassMappings.add(classReference.getTypeName());
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
index 84f5522..731fc0b 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
@@ -38,7 +38,9 @@
RetraceApiOutlineInlineTest.ApiTest.class,
RetraceApiOutlineInOutlineStackTrace.ApiTest.class,
RetraceApiInlineInOutlineTest.ApiTest.class,
- RetraceApiSingleFrameTest.ApiTest.class);
+ RetraceApiSingleFrameTest.ApiTest.class,
+ RetracePartitionStringTest.ApiTest.class,
+ RetracePartitionRoundTripTest.ApiTest.class);
public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
ImmutableList.of();
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionRoundTripTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionRoundTripTest.java
new file mode 100644
index 0000000..6a91dab
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionRoundTripTest.java
@@ -0,0 +1,155 @@
+// Copyright (c) 2022, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import com.android.tools.r8.retrace.PartitionMappingSupplier;
+import com.android.tools.r8.retrace.ProguardMapPartitioner;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.Retracer;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.OptionalInt;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetracePartitionRoundTripTest extends RetraceApiTestBase {
+
+ public RetracePartitionRoundTripTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference outlineRenamed = Reference.classFromTypeName("a");
+ private final ClassReference callsiteOriginal = Reference.classFromTypeName("some.Class");
+ private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
+ + "outline.Class -> "
+ + outlineRenamed.getTypeName()
+ + ":\n"
+ + " 1:2:int outline():0:0 -> a\n"
+ + "# { 'id':'com.android.tools.r8.outline' }\n"
+ + callsiteOriginal.getTypeName()
+ + " -> "
+ + callsiteRenamed.getTypeName()
+ + ":\n"
+ + " 1:1:void foo.bar.Baz.qux():42:42 -> s\n"
+ + " 4:4:int foo.bar.baz.outlineCaller(int):98:98 -> s\n"
+ + " 4:4:int outlineCaller(int):24 -> s\n"
+ + " 27:27:int outlineCaller(int):0:0 -> s\n" // This is the actual call to the outline
+ + "# { 'id':'com.android.tools.r8.outlineCallsite', "
+ + " 'positions': { '1': 4, '2': 5 } }\n";
+
+ private int prepareCounter = 0;
+
+ @Test
+ public void test() throws IOException {
+ ProguardMapProducer proguardMapProducer = ProguardMapProducer.fromString(mapping);
+ Map<String, byte[]> partitions = new HashMap<>();
+ MappingPartitionMetadata metadataData =
+ ProguardMapPartitioner.builder(new DiagnosticsHandler() {})
+ .setProguardMapProducer(proguardMapProducer)
+ .setPartitionConsumer(
+ partition -> partitions.put(partition.getKey(), partition.getPayload()))
+ .build()
+ .run();
+ assertNotNull(metadataData);
+ assertEquals(2, partitions.size());
+
+ Set<String> preFetchedKeys = new LinkedHashSet<>();
+ PartitionMappingSupplier mappingSupplier =
+ PartitionMappingSupplier.builder()
+ .setMetadata(metadataData.getBytes())
+ .setPartitionToFetchConsumer(preFetchedKeys::add)
+ .setPrepareNewPartitions(() -> prepareCounter++)
+ .setPartitionSupplier(
+ key -> {
+ assertTrue(preFetchedKeys.contains(key));
+ return partitions.get(key);
+ })
+ .build();
+ assertEquals(0, prepareCounter);
+ Retracer retracer = Retracer.builder().setMappingSupplier(mappingSupplier).build();
+ List<RetraceFrameElement> outlineRetraced =
+ retracer
+ .retraceFrame(
+ RetraceStackTraceContext.empty(),
+ OptionalInt.of(1),
+ Reference.methodFromDescriptor(outlineRenamed, "a", "()I"))
+ .stream()
+ .collect(Collectors.toList());
+ // The retrace result should not be ambiguous or empty.
+ assertEquals(1, outlineRetraced.size());
+ assertEquals(1, preFetchedKeys.size());
+ assertEquals(1, prepareCounter);
+ RetraceFrameElement retraceFrameElement = outlineRetraced.get(0);
+
+ // Check that visiting all frames report the outline.
+ List<RetracedMethodReference> allMethodReferences =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(1, allMethodReferences.size());
+ assertEquals(0, allMethodReferences.get(0).getOriginalPositionOrDefault(2));
+
+ // Check that visiting rewritten frames will not report anything.
+ List<RetracedMethodReference> rewrittenReferences =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(0, rewrittenReferences.size());
+
+ // Retrace the outline position
+ RetraceStackTraceContext context = retraceFrameElement.getRetraceStackTraceContext();
+ List<RetraceFrameElement> retraceOutlineCallee =
+ retracer
+ .retraceFrame(
+ context,
+ OptionalInt.of(27),
+ Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"))
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, retraceOutlineCallee.size());
+ assertEquals(partitions.keySet(), preFetchedKeys);
+ assertEquals(2, prepareCounter);
+
+ List<RetracedMethodReference> outlineCallSiteFrames =
+ retraceOutlineCallee.get(0).stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
+ assertEquals(2, outlineCallSiteFrames.size());
+ assertEquals(98, outlineCallSiteFrames.get(0).getOriginalPositionOrDefault(27));
+ assertEquals(24, outlineCallSiteFrames.get(1).getOriginalPositionOrDefault(27));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceSplitterStringTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionStringTest.java
similarity index 90%
rename from src/test/java/com/android/tools/r8/retrace/api/RetraceSplitterStringTest.java
rename to src/test/java/com/android/tools/r8/retrace/api/RetracePartitionStringTest.java
index 1194cd6..5183bf6 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceSplitterStringTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionStringTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.retrace.api;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.TestParameters;
@@ -22,9 +22,9 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class RetraceSplitterStringTest extends RetraceApiTestBase {
+public class RetracePartitionStringTest extends RetraceApiTestBase {
- public RetraceSplitterStringTest(TestParameters parameters) {
+ public RetracePartitionStringTest(TestParameters parameters) {
super(parameters);
}
@@ -68,8 +68,7 @@
new String(partition.getPayload(), StandardCharsets.UTF_8)))
.build()
.run();
- // TODO(b/211603371): Figure out what metadata should be.
- assertNull(metadataData);
+ assertNotNull(metadataData);
assertEquals(2, partitions.size());
assertEquals(aMapping, partitions.get("a"));
assertEquals(bMapping, partitions.get("b"));
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index e9e1510..0325801 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-26b0387e484bb583397718f7ddab8d6f13ef8e5d
\ No newline at end of file
+e9a51bfcb895db2b47c64004dd94acb2356a84a4
\ No newline at end of file