Introduce Machine specifications
Bug: 184026720
Change-Id: I482121268cb0e22313d8c62d2126173b396b813f
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
new file mode 100644
index 0000000..aac8c01
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -0,0 +1,18 @@
+// 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;
+
+/** TODO(b/184026720): Move the rest of the flags. */
+public class MachineDesugaredLibrarySpecification {
+
+ private final boolean libraryCompilation;
+ private final MachineRewritingFlags rewritingFlags;
+
+ public MachineDesugaredLibrarySpecification(
+ boolean libraryCompilation, MachineRewritingFlags rewritingFlags) {
+ this.libraryCompilation = libraryCompilation;
+ this.rewritingFlags = rewritingFlags;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
new file mode 100644
index 0000000..4dd87f6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -0,0 +1,56 @@
+// 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 com.android.tools.r8.graph.DexMethod;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
+public class MachineRewritingFlags {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ MachineRewritingFlags(
+ Map<DexMethod, DexMethod> staticRetarget,
+ Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget) {
+ this.staticRetarget = staticRetarget;
+ this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
+ }
+
+ // Static methods to retarget, duplicated to library boundaries.
+ private final Map<DexMethod, DexMethod> staticRetarget;
+
+ // Virtual methods to retarget, which are guaranteed not to require emulated dispatch.
+ // A method does not require emulated dispatch if two conditions are met:
+ // (1) the method does not override any other library method;
+ // (2) the method is final or installed in a final class.
+ // Any invoke resolving into the method will be rewritten into an invoke-static to the desugared
+ // code.
+ private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
+
+ public static class Builder {
+
+ Builder() {}
+
+ private final ImmutableMap.Builder<DexMethod, DexMethod> staticRetarget =
+ ImmutableMap.builder();
+ private final ImmutableMap.Builder<DexMethod, DexMethod> nonEmulatedVirtualRetarget =
+ ImmutableMap.builder();
+
+ public void putStaticRetarget(DexMethod src, DexMethod dest) {
+ staticRetarget.put(src, dest);
+ }
+
+ public void putNonEmulatedVirtualRetarget(DexMethod src, DexMethod dest) {
+ nonEmulatedVirtualRetarget.put(src, dest);
+ }
+
+ public MachineRewritingFlags build() {
+ return new MachineRewritingFlags(staticRetarget.build(), nonEmulatedVirtualRetarget.build());
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
new file mode 100644
index 0000000..7796c19
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -0,0 +1,139 @@
+// 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.specificationconversion;
+
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.ExecutorService;
+import java.util.function.BiConsumer;
+
+public class HumanToMachineSpecificationConverter {
+
+ public MachineDesugaredLibrarySpecification convert(
+ HumanDesugaredLibrarySpecification humanSpec, Path androidLib, InternalOptions options)
+ throws IOException {
+ DexApplication app = readApp(androidLib, options);
+ AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+ MachineRewritingFlags machineRewritingFlags =
+ convertRewritingFlags(humanSpec.getRewritingFlags(), appView.appInfoForDesugaring());
+ return new MachineDesugaredLibrarySpecification(
+ humanSpec.isLibraryCompilation(), machineRewritingFlags);
+ }
+
+ private MachineRewritingFlags convertRewritingFlags(
+ HumanRewritingFlags rewritingFlags, AppInfoWithClassHierarchy appInfo) {
+ MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
+ SubtypingInfo subtypingInfo = new SubtypingInfo(appInfo);
+ rewritingFlags
+ .getRetargetCoreLibMember()
+ .forEach(
+ (method, type) ->
+ convertRetargetCoreLibMemberFlag(builder, method, type, appInfo, subtypingInfo));
+ return builder.build();
+ }
+
+ private void convertRetargetCoreLibMemberFlag(
+ MachineRewritingFlags.Builder builder,
+ DexMethod method,
+ DexType type,
+ AppInfoWithClassHierarchy appInfo,
+ SubtypingInfo subtypingInfo) {
+ DexClass holder = appInfo.definitionFor(method.holder);
+ DexEncodedMethod foundMethod = holder.lookupMethod(method);
+ assert foundMethod != null;
+ if (foundMethod.isStatic()) {
+ convertStaticRetarget(builder, foundMethod, type, appInfo, subtypingInfo);
+ return;
+ }
+ if (holder.isFinal() || foundMethod.isFinal()) {
+ convertNonEmulatedVirtualRetarget(builder, foundMethod, type, appInfo, subtypingInfo);
+ return;
+ }
+ convertEmulatedVirtualRetarget(builder, foundMethod, type, appInfo, subtypingInfo);
+ }
+
+ private void convertEmulatedVirtualRetarget(
+ MachineRewritingFlags.Builder builder,
+ DexEncodedMethod foundMethod,
+ DexType type,
+ AppInfoWithClassHierarchy appInfo,
+ SubtypingInfo subtypingInfo) {
+ // TODO(b/184026720): To implement.
+ }
+
+ private void convertNonEmulatedRetarget(
+ DexEncodedMethod foundMethod,
+ DexType type,
+ AppInfoWithClassHierarchy appInfo,
+ SubtypingInfo subtypingInfo,
+ BiConsumer<DexMethod, DexMethod> consumer) {
+ DexMethod src = foundMethod.getReference();
+ DexMethod dest = src.withHolder(type, appInfo.dexItemFactory());
+ consumer.accept(src, dest);
+ for (DexType subtype : subtypingInfo.subtypes(foundMethod.getHolderType())) {
+ DexClass subclass = appInfo.definitionFor(subtype);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(subclass, src);
+ if (resolutionResult.isSuccessfulMemberResolutionResult()
+ && resolutionResult.getResolvedMethod().getReference() == src) {
+ consumer.accept(src.withHolder(subtype, appInfo.dexItemFactory()), dest);
+ }
+ }
+ }
+
+ private void convertNonEmulatedVirtualRetarget(
+ MachineRewritingFlags.Builder builder,
+ DexEncodedMethod foundMethod,
+ DexType type,
+ AppInfoWithClassHierarchy appInfo,
+ SubtypingInfo subtypingInfo) {
+ convertNonEmulatedRetarget(
+ foundMethod,
+ type,
+ appInfo,
+ subtypingInfo,
+ (src, dest) ->
+ builder.putNonEmulatedVirtualRetarget(
+ src,
+ dest.withExtraArgumentPrepended(
+ foundMethod.getHolderType(), appInfo.dexItemFactory())));
+ }
+
+ private void convertStaticRetarget(
+ MachineRewritingFlags.Builder builder,
+ DexEncodedMethod foundMethod,
+ DexType type,
+ AppInfoWithClassHierarchy appInfo,
+ SubtypingInfo subtypingInfo) {
+ convertNonEmulatedRetarget(
+ foundMethod, type, appInfo, subtypingInfo, builder::putStaticRetarget);
+ }
+
+ private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
+ AndroidApp androidApp = AndroidApp.builder().addProgramFile(androidLib).build();
+ ApplicationReader applicationReader =
+ new ApplicationReader(androidApp, options, Timing.empty());
+ ExecutorService executorService = ThreadUtils.getExecutorService(options);
+ return applicationReader.read(executorService).toDirect();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index 14898fc..34bf5fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
@@ -43,9 +42,8 @@
import java.util.Map;
import java.util.concurrent.ExecutorService;
-public class LegacyToHumanSpecificationConverter implements SpecificationConverter {
+public class LegacyToHumanSpecificationConverter {
- @Override
public void convertAllAPILevels(
StringResource inputSpecification, Path androidLib, StringConsumer output)
throws IOException {
@@ -136,8 +134,7 @@
libraryFlags.put(level, builder.build());
}
- private DirectMappedDexApplication readApp(Path androidLib, InternalOptions options)
- throws IOException {
+ private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
ApplicationReader applicationReader =
new ApplicationReader(androidApp, options, Timing.empty());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/SpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/SpecificationConverter.java
deleted file mode 100644
index 85a8c8b..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/SpecificationConverter.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
-
-import com.android.tools.r8.StringConsumer;
-import com.android.tools.r8.StringResource;
-import java.io.IOException;
-import java.nio.file.Path;
-
-public interface SpecificationConverter {
-
- void convertAllAPILevels(
- StringResource inputSpecification, Path androidLib, StringConsumer output) throws IOException;
-}