Support parsing machine specification
Bug: b/238987119
Change-Id: I83c7f8126ebe15f3b78b6d112748fce3dbbcad0c
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 1aa5f62..5f8e35a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -13,8 +13,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanFieldParser;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanMethodParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.HumanFieldParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.HumanMethodParser;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java
index 6921202..6579f8f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
import com.android.tools.r8.graph.DexMethod;
+import java.util.Objects;
public class CustomConversionDescriptor implements SpecificationDescriptor {
private final DexMethod to;
@@ -30,4 +31,21 @@
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter exporter) {
return exporter.exportCustomConversionDescriptor(this);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof CustomConversionDescriptor)) {
+ return false;
+ }
+ CustomConversionDescriptor that = (CustomConversionDescriptor) o;
+ return to == that.to && from == that.from;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(to, from);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
index 88aec73..dde1f48 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import java.util.Objects;
/**
* A derived method is: - if the holderKind is null, a normal dexMethod; - if the holderKind is
@@ -55,4 +56,21 @@
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter exporter) {
return exporter.exportDerivedMethod(this);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DerivedMethod)) {
+ return false;
+ }
+ DerivedMethod that = (DerivedMethod) o;
+ return method == that.method && Objects.equals(holderKind, that.holderKind);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(method, holderKind);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
index ec81273..9737d09 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexType;
import java.util.LinkedHashMap;
+import java.util.Objects;
public class EmulatedDispatchMethodDescriptor implements SpecificationDescriptor {
@@ -73,4 +74,24 @@
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter exporter) {
return exporter.exportEmulatedDispatchMethodDescriptor(this);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof EmulatedDispatchMethodDescriptor)) {
+ return false;
+ }
+ EmulatedDispatchMethodDescriptor that = (EmulatedDispatchMethodDescriptor) o;
+ return Objects.equals(interfaceMethod, that.interfaceMethod)
+ && Objects.equals(emulatedDispatchMethod, that.emulatedDispatchMethod)
+ && Objects.equals(forwardingMethod, that.forwardingMethod)
+ && Objects.equals(dispatchCases, that.dispatchCases);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(interfaceMethod, emulatedDispatchMethod, forwardingMethod, dispatchCases);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedInterfaceDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedInterfaceDescriptor.java
index bd4ffb1..fb96fe6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedInterfaceDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedInterfaceDescriptor.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import java.util.Map;
+import java.util.Objects;
public class EmulatedInterfaceDescriptor implements SpecificationDescriptor {
private final DexType rewrittenType;
@@ -31,4 +32,21 @@
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter exporter) {
return exporter.exportEmulatedInterfaceDescriptor(this);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof EmulatedInterfaceDescriptor)) {
+ return false;
+ }
+ EmulatedInterfaceDescriptor that = (EmulatedInterfaceDescriptor) o;
+ return rewrittenType == that.rewrittenType && emulatedMethods.equals(that.emulatedMethods);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rewrittenType, emulatedMethods);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 4aa99b6..0d9ef85 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -4,20 +4,24 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.SemanticVersion;
+import com.android.tools.r8.utils.Timing;
+import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
-public class MachineDesugaredLibrarySpecification {
+public class MachineDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
private final boolean libraryCompilation;
private final MachineTopLevelFlags topLevelFlags;
@@ -60,6 +64,14 @@
return libraryCompilation;
}
+ public MachineTopLevelFlags getTopLevelFlags() {
+ return topLevelFlags;
+ }
+
+ public MachineRewritingFlags getRewritingFlags() {
+ return rewritingFlags;
+ }
+
public AndroidApiLevel getRequiredCompilationAPILevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
@@ -208,6 +220,12 @@
return topLevelFlags.getRequiredCompilationAPILevel();
}
+ @Override
+ public MachineDesugaredLibrarySpecification toMachineSpecification(
+ DexApplication app, Timing timing) throws IOException {
+ return this;
+ }
+
public boolean requiresTypeRewriting() {
return !getRewriteType().isEmpty() || !getRewriteDerivedTypeOnly().isEmpty();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
new file mode 100644
index 0000000..6cdd123
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
@@ -0,0 +1,462 @@
+// 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.ir.desugar.desugaredlibrary.machinespecification;
+
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_FIELD_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.AMEND_LIBRARY_METHOD_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.API_GENERIC_TYPES_CONVERSION_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.API_LEVEL_BELOW_OR_EQUAL_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.API_LEVEL_GREATER_OR_EQUAL_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.COMMON_FLAGS_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.COVARIANT_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.CUSTOM_CONVERSION_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.DONT_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.EMULATED_INTERFACE_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.EMULATED_VIRTUAL_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.EMULATED_VIRTUAL_RETARGET_THROUGH_EMULATED_INTERFACE_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.IDENTIFIER_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.LEGACY_BACKPORT_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.LIBRARY_FLAGS_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.MAINTAIN_TYPE_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.NON_EMULATED_VIRTUAL_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.PACKAGE_MAP_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.PROGRAM_FLAGS_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.REQUIRED_COMPILATION_API_LEVEL_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.REWRITE_DERIVED_TYPE_ONLY_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.REWRITE_TYPE_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.SHRINKER_CONFIG_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.STATIC_FIELD_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.STATIC_RETARGET_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSpecificationJsonPool.WRAPPER_KEY;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.MachineFieldParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.MachineMethodParser;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MachineDesugaredLibrarySpecificationParser {
+
+ private static final String ERROR_MESSAGE_PREFIX = "Invalid desugared library specification: ";
+
+ private final DexItemFactory dexItemFactory;
+ private final MachineMethodParser methodParser;
+ private final MachineFieldParser fieldParser;
+ private final Reporter reporter;
+ private final boolean libraryCompilation;
+ private final int minAPILevel;
+ private final SyntheticNaming syntheticNaming;
+
+ private Origin origin;
+ private JsonObject jsonConfig;
+ private Map<String, String> packageMap;
+
+ public MachineDesugaredLibrarySpecificationParser(
+ DexItemFactory dexItemFactory,
+ Reporter reporter,
+ boolean libraryCompilation,
+ int minAPILevel,
+ SyntheticNaming syntheticNaming) {
+ this.dexItemFactory = dexItemFactory;
+ this.methodParser = new MachineMethodParser(dexItemFactory, this::stringDescriptorToDexType);
+ this.fieldParser = new MachineFieldParser(dexItemFactory, this::stringDescriptorToDexType);
+ this.reporter = reporter;
+ this.minAPILevel = minAPILevel;
+ this.syntheticNaming = syntheticNaming;
+ this.libraryCompilation = libraryCompilation;
+ }
+
+ public DexItemFactory dexItemFactory() {
+ return dexItemFactory;
+ }
+
+ public Reporter reporter() {
+ return reporter;
+ }
+
+ public JsonObject getJsonConfig() {
+ return jsonConfig;
+ }
+
+ public Origin getOrigin() {
+ assert origin != null;
+ return origin;
+ }
+
+ JsonElement required(JsonObject json, String key) {
+ if (!json.has(key)) {
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Invalid desugared library configuration. Expected required key '" + key + "'",
+ origin));
+ }
+ return json.get(key);
+ }
+
+ public MachineDesugaredLibrarySpecification parse(StringResource stringResource) {
+ String jsonConfigString = parseJson(stringResource);
+ return parse(origin, jsonConfigString, jsonConfig);
+ }
+
+ public MachineDesugaredLibrarySpecification parse(
+ Origin origin, String jsonConfigString, JsonObject jsonConfig) {
+ this.origin = origin;
+ this.jsonConfig = jsonConfig;
+ MachineTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString);
+ parsePackageMap();
+ MachineRewritingFlags rewritingFlags = parseRewritingFlags();
+ MachineDesugaredLibrarySpecification config =
+ new MachineDesugaredLibrarySpecification(libraryCompilation, topLevelFlags, rewritingFlags);
+ this.origin = null;
+ return config;
+ }
+
+ private void parsePackageMap() {
+ JsonObject packageMapJson = required(jsonConfig, PACKAGE_MAP_KEY).getAsJsonObject();
+ ImmutableBiMap.Builder<String, String> builder = ImmutableBiMap.builder();
+ packageMapJson.entrySet().forEach((e) -> builder.put(e.getValue().getAsString(), e.getKey()));
+ packageMap = builder.build();
+ }
+
+ String parseJson(StringResource stringResource) {
+ setOrigin(stringResource);
+ String jsonConfigString;
+ try {
+ jsonConfigString = stringResource.getString();
+ JsonParser parser = new JsonParser();
+ jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
+ } catch (Exception e) {
+ throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
+ }
+ return jsonConfigString;
+ }
+
+ void setOrigin(StringResource stringResource) {
+ origin = stringResource.getOrigin();
+ assert origin != null;
+ }
+
+ private MachineRewritingFlags parseRewritingFlags() {
+ MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
+ JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
+ JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
+ JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
+ parseFlagsList(commonFlags.getAsJsonArray(), builder);
+ parseFlagsList(
+ libraryCompilation ? libraryFlags.getAsJsonArray() : programFlags.getAsJsonArray(),
+ builder);
+ return builder.build();
+ }
+
+ MachineTopLevelFlags parseTopLevelFlags(String jsonConfigString) {
+ String identifier = required(jsonConfig, IDENTIFIER_KEY).getAsString();
+ String prefix =
+ required(jsonConfig, SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY).getAsString();
+ int required_compilation_api_level =
+ required(jsonConfig, REQUIRED_COMPILATION_API_LEVEL_KEY).getAsInt();
+ String keepRules = required(jsonConfig, SHRINKER_CONFIG_KEY).getAsString();
+ boolean supportAllCallbacksFromLibrary =
+ jsonConfig.get(SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY).getAsBoolean();
+
+ return new MachineTopLevelFlags(
+ AndroidApiLevel.getAndroidApiLevel(required_compilation_api_level),
+ prefix,
+ identifier,
+ jsonConfigString,
+ supportAllCallbacksFromLibrary,
+ ImmutableList.of(keepRules));
+ }
+
+ private void parseFlagsList(JsonArray jsonFlags, MachineRewritingFlags.Builder builder) {
+ for (JsonElement jsonFlagSet : jsonFlags) {
+ JsonObject flag = jsonFlagSet.getAsJsonObject();
+ int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
+ if (minAPILevel <= api_level_below_or_equal) {
+ if (flag.has(API_LEVEL_GREATER_OR_EQUAL_KEY)) {
+ if (minAPILevel >= flag.get(API_LEVEL_GREATER_OR_EQUAL_KEY).getAsInt()) {
+ parseFlags(flag, builder);
+ }
+ } else {
+ parseFlags(flag, builder);
+ }
+ }
+ }
+ }
+
+ void parseFlags(JsonObject jsonFlagSet, MachineRewritingFlags.Builder builder) {
+ if (jsonFlagSet.has(REWRITE_TYPE_KEY)) {
+ for (Map.Entry<String, JsonElement> rewritePrefix :
+ jsonFlagSet.get(REWRITE_TYPE_KEY).getAsJsonObject().entrySet()) {
+ builder.rewriteType(
+ stringDescriptorToDexType(rewritePrefix.getKey()),
+ stringDescriptorToDexType(rewritePrefix.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(MAINTAIN_TYPE_KEY)) {
+ for (JsonElement maintainPrefix : jsonFlagSet.get(MAINTAIN_TYPE_KEY).getAsJsonArray()) {
+ builder.maintainType(stringDescriptorToDexType(maintainPrefix.getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(REWRITE_DERIVED_TYPE_ONLY_KEY)) {
+ for (Map.Entry<String, JsonElement> rewriteDerivedTypeOnly :
+ jsonFlagSet.get(REWRITE_DERIVED_TYPE_ONLY_KEY).getAsJsonObject().entrySet()) {
+ builder.rewriteDerivedTypeOnly(
+ stringDescriptorToDexType(rewriteDerivedTypeOnly.getKey()),
+ stringDescriptorToDexType(rewriteDerivedTypeOnly.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(STATIC_FIELD_RETARGET_KEY)) {
+ for (Map.Entry<String, JsonElement> staticFieldRetarget :
+ jsonFlagSet.get(STATIC_FIELD_RETARGET_KEY).getAsJsonObject().entrySet()) {
+ builder.putStaticFieldRetarget(
+ parseField(staticFieldRetarget.getKey()),
+ parseField(staticFieldRetarget.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(COVARIANT_RETARGET_KEY)) {
+ for (Map.Entry<String, JsonElement> covariantRetarget :
+ jsonFlagSet.get(COVARIANT_RETARGET_KEY).getAsJsonObject().entrySet()) {
+ builder.putCovariantRetarget(
+ parseMethod(covariantRetarget.getKey()),
+ parseMethod(covariantRetarget.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(STATIC_RETARGET_KEY)) {
+ for (Map.Entry<String, JsonElement> staticRetarget :
+ jsonFlagSet.get(STATIC_RETARGET_KEY).getAsJsonObject().entrySet()) {
+ builder.putStaticRetarget(
+ parseMethod(staticRetarget.getKey()),
+ parseMethod(staticRetarget.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(NON_EMULATED_VIRTUAL_RETARGET_KEY)) {
+ for (Map.Entry<String, JsonElement> virtualRetarget :
+ jsonFlagSet.get(NON_EMULATED_VIRTUAL_RETARGET_KEY).getAsJsonObject().entrySet()) {
+ builder.putNonEmulatedVirtualRetarget(
+ parseMethod(virtualRetarget.getKey()),
+ parseMethod(virtualRetarget.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(EMULATED_VIRTUAL_RETARGET_KEY)) {
+ for (Map.Entry<String, JsonElement> virtualRetarget :
+ jsonFlagSet.get(EMULATED_VIRTUAL_RETARGET_KEY).getAsJsonObject().entrySet()) {
+ builder.putEmulatedVirtualRetarget(
+ parseMethod(virtualRetarget.getKey()),
+ parseEmulatedDispatchDescriptor(virtualRetarget.getValue().getAsJsonArray()));
+ }
+ }
+ if (jsonFlagSet.has(EMULATED_VIRTUAL_RETARGET_THROUGH_EMULATED_INTERFACE_KEY)) {
+ for (Map.Entry<String, JsonElement> virtualRetarget :
+ jsonFlagSet
+ .get(EMULATED_VIRTUAL_RETARGET_THROUGH_EMULATED_INTERFACE_KEY)
+ .getAsJsonObject()
+ .entrySet()) {
+ builder.putEmulatedVirtualRetargetThroughEmulatedInterface(
+ parseMethod(virtualRetarget.getKey()),
+ parseMethod(virtualRetarget.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(API_GENERIC_TYPES_CONVERSION_KEY)) {
+ for (Map.Entry<String, JsonElement> apiGenericType :
+ jsonFlagSet.get(API_GENERIC_TYPES_CONVERSION_KEY).getAsJsonObject().entrySet()) {
+ builder.addApiGenericTypesConversion(
+ parseMethod(apiGenericType.getKey()),
+ parseMethodArray(apiGenericType.getValue().getAsJsonArray()));
+ }
+ }
+ if (jsonFlagSet.has(EMULATED_INTERFACE_KEY)) {
+ for (Map.Entry<String, JsonElement> emulatedInterface :
+ jsonFlagSet.get(EMULATED_INTERFACE_KEY).getAsJsonObject().entrySet()) {
+ builder.putEmulatedInterface(
+ stringDescriptorToDexType(emulatedInterface.getKey()),
+ parseEmulatedInterfaceDescriptor(emulatedInterface.getValue().getAsJsonArray()));
+ }
+ }
+ if (jsonFlagSet.has(WRAPPER_KEY)) {
+ for (Map.Entry<String, JsonElement> wrapper :
+ jsonFlagSet.get(WRAPPER_KEY).getAsJsonObject().entrySet()) {
+ builder.addWrapper(
+ stringDescriptorToDexType(wrapper.getKey()),
+ parseWrapperDescriptor(wrapper.getValue().getAsJsonArray()));
+ }
+ }
+ if (jsonFlagSet.has(LEGACY_BACKPORT_KEY)) {
+ for (Map.Entry<String, JsonElement> legacyBackport :
+ jsonFlagSet.get(LEGACY_BACKPORT_KEY).getAsJsonObject().entrySet()) {
+ builder.putLegacyBackport(
+ stringDescriptorToDexType(legacyBackport.getKey()),
+ stringDescriptorToDexType(legacyBackport.getValue().getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(DONT_RETARGET_KEY)) {
+ for (JsonElement dontRetarget : jsonFlagSet.get(DONT_RETARGET_KEY).getAsJsonArray()) {
+ builder.addDontRetarget(stringDescriptorToDexType(dontRetarget.getAsString()));
+ }
+ }
+ if (jsonFlagSet.has(CUSTOM_CONVERSION_KEY)) {
+ for (Map.Entry<String, JsonElement> customConversion :
+ jsonFlagSet.get(CUSTOM_CONVERSION_KEY).getAsJsonObject().entrySet()) {
+ builder.putCustomConversion(
+ stringDescriptorToDexType(customConversion.getKey()),
+ parseCustomConversionDescriptor(customConversion.getValue().getAsJsonArray()));
+ }
+ }
+ if (jsonFlagSet.has(AMEND_LIBRARY_METHOD_KEY)) {
+ JsonArray amendLibraryMember = jsonFlagSet.get(AMEND_LIBRARY_METHOD_KEY).getAsJsonArray();
+ for (JsonElement amend : amendLibraryMember) {
+ methodParser.parseMethod(amend.getAsString());
+ builder.amendLibraryMethod(methodParser.getMethod(), methodParser.getFlags());
+ }
+ }
+ if (jsonFlagSet.has(AMEND_LIBRARY_FIELD_KEY)) {
+ JsonArray amendLibraryMember = jsonFlagSet.get(AMEND_LIBRARY_FIELD_KEY).getAsJsonArray();
+ for (JsonElement amend : amendLibraryMember) {
+ fieldParser.parseField(amend.getAsString());
+ builder.amendLibraryField(fieldParser.getField(), fieldParser.getFlags());
+ }
+ }
+ }
+
+ private CustomConversionDescriptor parseCustomConversionDescriptor(JsonArray jsonArray) {
+ return new CustomConversionDescriptor(
+ parseMethod(jsonArray.get(0).getAsString()), parseMethod(jsonArray.get(1).getAsString()));
+ }
+
+ private WrapperDescriptor parseWrapperDescriptor(JsonArray jsonArray) {
+ List<DexMethod> methods = parseMethodList(jsonArray.get(0).getAsJsonArray());
+ boolean nonPublicAccess = jsonArray.get(1).getAsBoolean();
+ List<DexType> subwrappers = parseTypeList(jsonArray.get(2).getAsJsonArray());
+ return new WrapperDescriptor(methods, subwrappers, nonPublicAccess);
+ }
+
+ private void require(JsonArray jsonArray, int size, String elementString) {
+ if (jsonArray.size() != size) {
+ throw reporter.fatalError(
+ ERROR_MESSAGE_PREFIX + elementString + "(Json array of size " + jsonArray.size() + ")");
+ }
+ }
+
+ private EmulatedInterfaceDescriptor parseEmulatedInterfaceDescriptor(JsonArray jsonArray) {
+ require(jsonArray, 2, "emulated interface descriptor");
+ DexType rewrittenType = stringDescriptorToDexType(jsonArray.get(0).getAsString());
+ Map<DexMethod, EmulatedDispatchMethodDescriptor> methods =
+ parseEmulatedInterfaceMap(jsonArray.get(1).getAsJsonObject());
+ return new EmulatedInterfaceDescriptor(rewrittenType, methods);
+ }
+
+ private Map<DexMethod, EmulatedDispatchMethodDescriptor> parseEmulatedInterfaceMap(
+ JsonObject jsonObject) {
+ Map<DexMethod, EmulatedDispatchMethodDescriptor> map = new IdentityHashMap<>();
+ for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
+ map.put(
+ parseMethod(entry.getKey()),
+ parseEmulatedDispatchDescriptor(entry.getValue().getAsJsonArray()));
+ }
+ return map;
+ }
+
+ private LinkedHashMap<DexType, DerivedMethod> parseEmulatedDispatchMap(JsonObject jsonObject) {
+ LinkedHashMap<DexType, DerivedMethod> map = new LinkedHashMap<>();
+ for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
+ map.put(
+ stringDescriptorToDexType(entry.getKey()),
+ parseDerivedMethod(entry.getValue().getAsJsonArray()));
+ }
+ return map;
+ }
+
+ private EmulatedDispatchMethodDescriptor parseEmulatedDispatchDescriptor(JsonArray jsonArray) {
+ require(jsonArray, 4, "emulated dispatch descriptor");
+ DerivedMethod interfaceMethod = parseDerivedMethod(jsonArray.get(0).getAsJsonArray());
+ DerivedMethod emulatedDispatchMethod = parseDerivedMethod(jsonArray.get(1).getAsJsonArray());
+ DerivedMethod forwardingMethod = parseDerivedMethod(jsonArray.get(2).getAsJsonArray());
+ LinkedHashMap<DexType, DerivedMethod> dispatchCases =
+ parseEmulatedDispatchMap(jsonArray.get(3).getAsJsonObject());
+ return new EmulatedDispatchMethodDescriptor(
+ interfaceMethod, emulatedDispatchMethod, forwardingMethod, dispatchCases);
+ }
+
+ private DerivedMethod parseDerivedMethod(JsonArray jsonArray) {
+ require(jsonArray, 2, "derived method");
+ DexMethod dexMethod = parseMethod(jsonArray.get(0).getAsString());
+ int kind = jsonArray.get(1).getAsInt();
+ if (kind == -1) {
+ return new DerivedMethod(dexMethod);
+ }
+ SyntheticKind syntheticKind = syntheticNaming.fromId(kind);
+ return new DerivedMethod(dexMethod, syntheticKind);
+ }
+
+ private List<DexMethod> parseMethodList(JsonArray array) {
+ List<DexMethod> methods = new ArrayList<>();
+ for (JsonElement method : array) {
+ methods.add(parseMethod(method.getAsString()));
+ }
+ return methods;
+ }
+
+ private List<DexType> parseTypeList(JsonArray array) {
+ List<DexType> types = new ArrayList<>();
+ for (JsonElement typeString : array) {
+ types.add(stringDescriptorToDexType(typeString.getAsString()));
+ }
+ return types;
+ }
+
+ private DexMethod[] parseMethodArray(JsonArray array) {
+ DexMethod[] dexMethods = new DexMethod[array.size()];
+ for (int i = 0; i < array.size(); i++) {
+ String str = array.get(i).getAsString();
+ dexMethods[i] = str.isEmpty() ? null : parseMethod(str);
+ }
+ return dexMethods;
+ }
+
+ private DexMethod parseMethod(String signature) {
+ methodParser.parseMethod(signature);
+ return methodParser.getMethod();
+ }
+
+ private DexField parseField(String signature) {
+ fieldParser.parseField(signature);
+ return fieldParser.getField();
+ }
+
+ public DexType stringDescriptorToDexType(String stringClass) {
+ if (stringClass.charAt(1) != '$') {
+ return dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
+ }
+ String type = stringClass.substring(2);
+ String prefix = packageMap.get(stringClass.substring(0, 2));
+ if (prefix == null) {
+ throw reporter.fatalError(
+ ERROR_MESSAGE_PREFIX + "Missing package mapping for " + stringClass.substring(0, 2));
+ }
+ return dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(prefix + "." + type));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
index ce60cb0..e55127c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
@@ -57,7 +57,8 @@
private final DexItemFactory factory;
private final Map<String, String> packageMap = new TreeMap<>();
- private static final String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String chars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789æÆøØ";
private int next = 0;
public MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter(DexItemFactory factory) {
@@ -148,7 +149,7 @@
String key, Map<? extends DexItem, DexMethod[]> map, Map<String, Object> toJson) {
if (!map.isEmpty()) {
TreeMap<String, Object> stringMap = new TreeMap<>();
- map.forEach((k, v) -> stringMap.put(toString(k), methodArraytoJsonStruct(v)));
+ map.forEach((k, v) -> stringMap.put(toString(k), methodArrayToJsonStruct(v)));
toJson.put(key, stringMap);
}
}
@@ -229,10 +230,10 @@
return stringCol;
}
- private String[] methodArraytoJsonStruct(DexMethod[] methodArray) {
+ private String[] methodArrayToJsonStruct(DexMethod[] methodArray) {
String[] strings = new String[methodArray.length];
for (int i = 0; i < methodArray.length; i++) {
- strings[i] = toString(methodArray[i]);
+ strings[i] = methodArray[i] == null ? "" : toString(methodArray[i]);
}
return strings;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/WrapperDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/WrapperDescriptor.java
index 51a7c5a..156547e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/WrapperDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/WrapperDescriptor.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import java.util.List;
+import java.util.Objects;
public class WrapperDescriptor implements SpecificationDescriptor {
private final List<DexMethod> methods;
@@ -37,4 +38,23 @@
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter exporter) {
return exporter.exportWrapperDescriptor(this);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof WrapperDescriptor)) {
+ return false;
+ }
+ WrapperDescriptor that = (WrapperDescriptor) o;
+ return nonPublicAccess == that.nonPublicAccess
+ && Objects.equals(methods, that.methods)
+ && Objects.equals(subwrappers, that.subwrappers);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(methods, subwrappers, nonPublicAccess);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractFieldParser.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractFieldParser.java
index 8062063..ba3a060 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractFieldParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMemberParser.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMemberParser.java
index 99475b2..1848ed8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMemberParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMethodParser.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMethodParser.java
index 1afff88..c10882d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/AbstractMethodParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanFieldParser.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanFieldParser.java
index 9a5a44d..7f1b03f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanFieldParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanMethodParser.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanMethodParser.java
index d78267b..b7bfd33 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/HumanMethodParser.java
@@ -2,7 +2,7 @@
// 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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineFieldParser.java
new file mode 100644
index 0000000..002a8d3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineFieldParser.java
@@ -0,0 +1,23 @@
+// 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.ir.desugar.desugaredlibrary.memberparser;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Function;
+
+public class MachineFieldParser extends HumanFieldParser {
+ private final Function<String, DexType> typeParser;
+
+ public MachineFieldParser(DexItemFactory factory, Function<String, DexType> typeParser) {
+ super(factory);
+ this.typeParser = typeParser;
+ }
+
+ @Override
+ DexType stringTypeToDexType(String stringType) {
+ return typeParser.apply(stringType);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineMethodParser.java
new file mode 100644
index 0000000..6b88d87
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/memberparser/MachineMethodParser.java
@@ -0,0 +1,23 @@
+// 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.ir.desugar.desugaredlibrary.memberparser;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Function;
+
+public class MachineMethodParser extends HumanMethodParser {
+ private final Function<String, DexType> typeParser;
+
+ public MachineMethodParser(DexItemFactory factory, Function<String, DexType> typeParser) {
+ super(factory);
+ this.typeParser = typeParser;
+ }
+
+ @Override
+ DexType stringTypeToDexType(String stringType) {
+ return typeParser.apply(stringType);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index c352702..ec8c5f7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -4,7 +4,9 @@
package com.android.tools.r8.desugar.desugaredlibrary.specification;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.StringResource;
@@ -15,6 +17,8 @@
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecification;
@@ -22,11 +26,17 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.MultiAPILevelLegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.MultiAPILevelLegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineTopLevelFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
@@ -50,7 +60,7 @@
}
@Test
- public void testMultiLevel() throws IOException {
+ public void testMultiLevelLegacy() throws IOException {
Assume.assumeTrue(ToolHelper.isLocalDevelopment());
LibraryDesugaringSpecification legacySpec = LibraryDesugaringSpecification.JDK8;
@@ -87,6 +97,67 @@
converter2.convertAllAPILevels(humanSpec2, app);
MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.export(
machineSpec1, (string, handler) -> json2.set(string), options.dexItemFactory());
+
+ MachineDesugaredLibrarySpecification machineSpecParsed =
+ new MachineDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(),
+ options.reporter,
+ true,
+ AndroidApiLevel.B.getLevel(),
+ new SyntheticNaming())
+ .parse(StringResource.fromString(json2.get(), Origin.unknown()));
+ assertFalse(machineSpecParsed.getRewriteType().isEmpty());
+ }
+
+ @Test
+ public void testSingleLevel() throws IOException {
+ Assume.assumeTrue(ToolHelper.isLocalDevelopment());
+
+ LibraryDesugaringSpecification humanSpec = LibraryDesugaringSpecification.JDK11_PATH;
+
+ InternalOptions options = new InternalOptions();
+
+ DexApplication app = humanSpec.getAppForTesting(options, true);
+
+ MultiAPILevelHumanDesugaredLibrarySpecification humanSpec2 =
+ new MultiAPILevelHumanDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(), options.reporter)
+ .parseMultiLevelConfiguration(StringResource.fromFile(humanSpec.getSpecification()));
+
+ Box<String> json2 = new Box<>();
+ HumanToMachineSpecificationConverter converter2 =
+ new HumanToMachineSpecificationConverter(Timing.empty());
+ MultiAPILevelMachineDesugaredLibrarySpecification machineSpec1 =
+ converter2.convertAllAPILevels(humanSpec2, app);
+ MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.export(
+ machineSpec1, (string, handler) -> json2.set(string), options.dexItemFactory());
+
+ for (AndroidApiLevel api :
+ new AndroidApiLevel[] {AndroidApiLevel.B, AndroidApiLevel.N, AndroidApiLevel.O}) {
+ MachineDesugaredLibrarySpecification machineSpecParsed =
+ new MachineDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(),
+ options.reporter,
+ true,
+ api.getLevel(),
+ new SyntheticNaming())
+ .parse(StringResource.fromString(json2.get(), Origin.unknown()));
+
+ HumanDesugaredLibrarySpecification humanSpecB =
+ new HumanDesugaredLibrarySpecificationParser(
+ options.dexItemFactory(), options.reporter, true, api.getLevel())
+ .parse(StringResource.fromFile(humanSpec.getSpecification()));
+ MachineDesugaredLibrarySpecification machineSpecConverted =
+ humanSpecB.toMachineSpecification(app, Timing.empty());
+
+ assertSpecEquals(machineSpecConverted, machineSpecParsed);
+ }
+ }
+
+ private void assertSpecEquals(
+ MachineDesugaredLibrarySpecification spec1, MachineDesugaredLibrarySpecification spec2) {
+ assertTopLevelFlagsEquals(spec1.getTopLevelFlags(), spec2.getTopLevelFlags());
+ assertFlagsEquals(spec1.getRewritingFlags(), spec2.getRewritingFlags());
}
private void assertSpecEquals(
@@ -109,6 +180,46 @@
}
private void assertFlagsEquals(
+ MachineRewritingFlags rewritingFlags1, MachineRewritingFlags rewritingFlags2) {
+ assertEquals(rewritingFlags1.getRewriteType(), rewritingFlags2.getRewriteType());
+ assertEquals(rewritingFlags1.getMaintainType(), rewritingFlags2.getMaintainType());
+ assertEquals(
+ rewritingFlags1.getRewriteDerivedTypeOnly(), rewritingFlags2.getRewriteDerivedTypeOnly());
+ assertEquals(
+ rewritingFlags1.getStaticFieldRetarget(), rewritingFlags2.getStaticFieldRetarget());
+ assertEquals(rewritingFlags1.getCovariantRetarget(), rewritingFlags2.getCovariantRetarget());
+ assertEquals(rewritingFlags1.getStaticRetarget(), rewritingFlags2.getStaticRetarget());
+ assertEquals(
+ rewritingFlags1.getNonEmulatedVirtualRetarget(),
+ rewritingFlags2.getNonEmulatedVirtualRetarget());
+ assertEquals(
+ rewritingFlags1.getEmulatedVirtualRetarget(), rewritingFlags2.getEmulatedVirtualRetarget());
+ assertEquals(
+ rewritingFlags1.getEmulatedVirtualRetargetThroughEmulatedInterface(),
+ rewritingFlags2.getEmulatedVirtualRetargetThroughEmulatedInterface());
+ assertEquals(
+ rewritingFlags1.getApiGenericConversion().keySet(),
+ rewritingFlags2.getApiGenericConversion().keySet());
+ rewritingFlags1
+ .getApiGenericConversion()
+ .keySet()
+ .forEach(
+ k ->
+ assertArrayEquals(
+ rewritingFlags1.getApiGenericConversion().get(k),
+ rewritingFlags2.getApiGenericConversion().get(k)));
+ assertEquals(
+ rewritingFlags1.getEmulatedInterfaces().keySet(),
+ rewritingFlags2.getEmulatedInterfaces().keySet());
+ assertEquals(rewritingFlags1.getWrappers().keySet(), rewritingFlags2.getWrappers().keySet());
+ assertEquals(rewritingFlags1.getLegacyBackport(), rewritingFlags2.getLegacyBackport());
+ assertEquals(rewritingFlags1.getDontRetarget(), rewritingFlags2.getDontRetarget());
+ assertEquals(rewritingFlags1.getCustomConversions(), rewritingFlags2.getCustomConversions());
+ assertEquals(rewritingFlags1.getAmendLibraryMethod(), rewritingFlags2.getAmendLibraryMethod());
+ assertEquals(rewritingFlags1.getAmendLibraryField(), rewritingFlags2.getAmendLibraryField());
+ }
+
+ private void assertFlagsEquals(
HumanRewritingFlags humanRewritingFlags1, HumanRewritingFlags humanRewritingFlags2) {
assertEquals(humanRewritingFlags1.getRewritePrefix(), humanRewritingFlags2.getRewritePrefix());
assertEquals(
@@ -136,6 +247,20 @@
}
private void assertTopLevelFlagsEquals(
+ MachineTopLevelFlags topLevelFlags1, MachineTopLevelFlags topLevelFlags2) {
+ String kr1 = String.join("\n", topLevelFlags1.getExtraKeepRules());
+ String kr2 = String.join("\n", topLevelFlags2.getExtraKeepRules());
+ assertEquals(kr1, kr2);
+ assertEquals(topLevelFlags1.getIdentifier(), topLevelFlags2.getIdentifier());
+ assertEquals(
+ topLevelFlags1.getRequiredCompilationAPILevel().getLevel(),
+ topLevelFlags2.getRequiredCompilationAPILevel().getLevel());
+ assertEquals(
+ topLevelFlags1.getSynthesizedLibraryClassesPackagePrefix(),
+ topLevelFlags2.getSynthesizedLibraryClassesPackagePrefix());
+ }
+
+ private void assertTopLevelFlagsEquals(
HumanTopLevelFlags topLevelFlags1, HumanTopLevelFlags topLevelFlags2) {
assertEquals(topLevelFlags1.getExtraKeepRules(), topLevelFlags2.getExtraKeepRules());
assertEquals(topLevelFlags1.getIdentifier(), topLevelFlags2.getIdentifier());