Add LirToLirDesugaredLibraryLibRewriter
This add support for running the DesugaredLibraryLibRewriter cf-to-cf and lir-to-lir.
Bug: b/391572031
Bug: b/404474726
Change-Id: Iaae2ce2763ce8d87dbc16518d357dc9ea4a2b2e6
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index d20e039..b66ceee 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.AutoCloseableRetargeter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.CfToCfDesugaredLibraryLibRewriter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryLibRewriter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
@@ -106,7 +107,8 @@
}
this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
BackportedMethodRewriter backportedMethodRewriter = new BackportedMethodRewriter(appView);
- DesugaredLibraryLibRewriter desugaredLibRewriter = DesugaredLibraryLibRewriter.create(appView);
+ CfToCfDesugaredLibraryLibRewriter desugaredLibRewriter =
+ DesugaredLibraryLibRewriter.createCfToCf(appView);
if (desugaredLibRewriter != null) {
desugarings.add(desugaredLibRewriter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
index 16099e7..d59d1cb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
@@ -20,6 +20,8 @@
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.LirToLirDesugaredLibraryApiConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryLibRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryLibRewriter;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
@@ -93,6 +95,8 @@
CfInstructionDesugaringEventConsumer eventConsumer =
CfInstructionDesugaringEventConsumer.createForR8LirToLirLibraryDesugaring(
appView, profileCollectionAdditions);
+ LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter =
+ DesugaredLibraryLibRewriter.createLirToLir(appView, eventConsumer);
// TODO(b/391572031): Implement lir-to-lir interface method rewriting.
InterfaceMethodRewriter interfaceMethodRewriter = null;
LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter =
@@ -112,6 +116,7 @@
new R8LibraryDesugaringGraphLens(
appView,
desugaredLibraryAPIConverter,
+ desugaredLibraryLibRewriter,
interfaceMethodRewriter,
eventConsumer,
method,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
index 2125d91..867641b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
@@ -33,6 +33,7 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryConversionCfProvider;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.LirToLirDesugaredLibraryApiConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryLibRewriter;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
import java.util.ArrayList;
@@ -43,6 +44,7 @@
public class R8LibraryDesugaringGraphLens extends DefaultNonIdentityGraphLens {
private final LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter;
+ private final LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter;
@SuppressWarnings("UnusedVariable")
private final InterfaceMethodRewriter interfaceMethodRewriter;
@@ -59,12 +61,14 @@
public R8LibraryDesugaringGraphLens(
AppView<? extends AppInfoWithClassHierarchy> appView,
LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter,
+ LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter,
InterfaceMethodRewriter interfaceMethodRewriter,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod method,
MethodProcessingContext methodProcessingContext) {
super(appView);
this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
+ this.desugaredLibraryLibRewriter = desugaredLibraryLibRewriter;
this.interfaceMethodRewriter = interfaceMethodRewriter;
this.eventConsumer = eventConsumer;
this.method = method;
@@ -93,6 +97,14 @@
// TODO(b/391572031): Implement invoke desugaring.
assert previous.getPrototypeChanges().isEmpty();
+ if (desugaredLibraryLibRewriter != null) {
+ MethodLookupResult result =
+ desugaredLibraryLibRewriter.lookupMethod(previous, method, methodProcessingContext, this);
+ if (result != previous) {
+ return result;
+ }
+ }
+
if (desugaredLibraryAPIConverter != null) {
return desugaredLibraryAPIConverter.lookupMethod(
previous, method, methodProcessingContext, this);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryLibRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryLibRewriter.java
new file mode 100644
index 0000000..aadda62
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryLibRewriter.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2025, 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.retargeter;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.DesugarDescription;
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
+
+public class CfToCfDesugaredLibraryLibRewriter extends DesugaredLibraryLibRewriter
+ implements CfInstructionDesugaring {
+
+ CfToCfDesugaredLibraryLibRewriter(
+ AppView<?> appView,
+ Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings) {
+ super(appView, rewritings);
+ }
+
+ @Override
+ public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+ CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+ }
+
+ @Override
+ public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
+ if (!isApplicableToContext(context) || !instruction.isInvoke()) {
+ return DesugarDescription.nothing();
+ }
+ DexMethod invokedMethod = instruction.asInvoke().getMethod();
+ if (!rewritings.containsKey(invokedMethod)) {
+ return DesugarDescription.nothing();
+ }
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (position,
+ freshLocalProvider,
+ localStackAllocator,
+ desugaringInfo,
+ eventConsumer,
+ localContext,
+ methodProcessingContext,
+ desugarings,
+ dexItemFactory) -> {
+ DexMethod newInvokeTarget =
+ getRetargetMethod(
+ invokedMethod, eventConsumer, localContext, methodProcessingContext);
+ assert appView.definitionForHolder(newInvokeTarget, context) != null;
+ assert !appView.definitionForHolder(newInvokeTarget, context).isInterface();
+ return Collections.singletonList(
+ new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
+ })
+ .build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
index 58d5363..30a7efa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
@@ -4,60 +4,70 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
-import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.cf.code.CfOpcodeUtils;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-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.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.DesugarDescription;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.LibraryDesugaringOptions;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.google.common.collect.ImmutableMap;
-import java.util.Collections;
import java.util.Map;
import java.util.function.BiFunction;
-import java.util.function.IntConsumer;
-import org.objectweb.asm.Opcodes;
/**
* This holds specific rewritings when using desugared library and specific libraries such as
* androidx.
*/
-public class DesugaredLibraryLibRewriter implements CfInstructionDesugaring {
+public abstract class DesugaredLibraryLibRewriter {
- private final AppView<?> appView;
- private final Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings;
+ final AppView<?> appView;
+ final Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings;
- private DesugaredLibraryLibRewriter(
+ DesugaredLibraryLibRewriter(
AppView<?> appView,
Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings) {
this.appView = appView;
this.rewritings = rewritings;
}
- public static DesugaredLibraryLibRewriter create(AppView<?> appView) {
- if (appView
- .options()
- .getLibraryDesugaringOptions()
- .getMachineDesugaredLibrarySpecification()
- .getRewriteType()
- .isEmpty()) {
+ public static CfToCfDesugaredLibraryLibRewriter createCfToCf(AppView<?> appView) {
+ LibraryDesugaringOptions libraryDesugaringOptions =
+ appView.options().getLibraryDesugaringOptions();
+ if (libraryDesugaringOptions.isLirToLirLibraryDesugaringEnabled()
+ || libraryDesugaringOptions
+ .getMachineDesugaredLibrarySpecification()
+ .getRewriteType()
+ .isEmpty()) {
return null;
}
Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings = computeMap(appView);
if (rewritings.isEmpty()) {
return null;
}
- return new DesugaredLibraryLibRewriter(appView, rewritings);
+ return new CfToCfDesugaredLibraryLibRewriter(appView, rewritings);
+ }
+
+ public static LirToLirDesugaredLibraryLibRewriter createLirToLir(
+ AppView<?> appView, CfInstructionDesugaringEventConsumer eventConsumer) {
+ LibraryDesugaringOptions libraryDesugaringOptions =
+ appView.options().getLibraryDesugaringOptions();
+ if (libraryDesugaringOptions.isCfToCfLibraryDesugaringEnabled()
+ || libraryDesugaringOptions
+ .getMachineDesugaredLibrarySpecification()
+ .getRewriteType()
+ .isEmpty()) {
+ return null;
+ }
+ Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings = computeMap(appView);
+ if (rewritings.isEmpty()) {
+ return null;
+ }
+ return new LirToLirDesugaredLibraryLibRewriter(appView, eventConsumer, rewritings);
}
public static Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> computeMap(
@@ -67,17 +77,14 @@
if (!appView.appInfo().hasDefinitionForWithoutExistenceAssert(navType)) {
return ImmutableMap.of();
}
- ImmutableMap.Builder<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> builder =
- ImmutableMap.builder();
- DexType navTypeCompanion = factory.createType("Landroidx/navigation/NavType$Companion;");
- DexProto fromProto = factory.createProto(navType, factory.stringType, factory.stringType);
- DexString name = factory.createString("fromArgType");
- DexMethod from = factory.createMethod(navTypeCompanion, fromProto, name);
- DexClassAndMethod dexClassAndMethod = appView.definitionFor(from);
- if (dexClassAndMethod == null) {
+ DexMethod from =
+ factory.createMethod(
+ factory.createType("Landroidx/navigation/NavType$Companion;"),
+ factory.createProto(navType, factory.stringType, factory.stringType),
+ "fromArgType");
+ if (!appView.appInfo().hasDefinitionFor(from)) {
appView
- .options()
- .reporter
+ .reporter()
.warning(
"The class "
+ navType
@@ -91,56 +98,25 @@
}
BiFunction<DexItemFactory, DexMethod, CfCode> cfCodeProvider =
DesugaredLibraryCfMethods::DesugaredLibraryBridge_fromArgType;
- builder.put(from, cfCodeProvider);
- return builder.build();
+ return ImmutableMap.of(from, cfCodeProvider);
}
- @Override
- public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
- CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+ boolean isApplicableToContext(ProgramMethod context) {
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ return !syntheticItems.isSyntheticOfKind(
+ context.getHolderType(), kinds -> kinds.DESUGARED_LIBRARY_BRIDGE);
}
- @Override
- public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
- if (appView
- .getSyntheticItems()
- .isSyntheticOfKind(context.getHolderType(), kinds -> kinds.DESUGARED_LIBRARY_BRIDGE)) {
- return DesugarDescription.nothing();
- }
- if (instruction.isInvoke() && rewritings.containsKey(instruction.asInvoke().getMethod())) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- localContext,
- methodProcessingContext,
- desugarings,
- dexItemFactory) -> {
- DexMethod newInvokeTarget =
- ensureBridge(
- instruction.asInvoke().getMethod(),
- eventConsumer,
- methodProcessingContext,
- localContext);
- assert appView.definitionFor(newInvokeTarget.getHolderType()) != null;
- assert !appView.definitionFor(newInvokeTarget.getHolderType()).isInterface();
- return Collections.singletonList(
- new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
- })
- .build();
- }
- return DesugarDescription.nothing();
- }
-
- private DexMethod ensureBridge(
+ DexMethod getRetargetMethod(
DexMethod source,
CfInstructionDesugaringEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext,
- ProgramMethod localContext) {
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ assert isApplicableToContext(context);
BiFunction<DexItemFactory, DexMethod, CfCode> target = rewritings.get(source);
+ if (target == null) {
+ return null;
+ }
ProgramMethod newMethod =
appView
.getSyntheticItems()
@@ -154,7 +130,7 @@
.setProto(appView.dexItemFactory().prependHolderToProto(source))
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
.setCode(methodSig -> target.apply(appView.dexItemFactory(), methodSig)));
- eventConsumer.acceptDesugaredLibraryBridge(newMethod, localContext);
+ eventConsumer.acceptDesugaredLibraryBridge(newMethod, context);
return newMethod.getReference();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryLibRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryLibRewriter.java
new file mode 100644
index 0000000..fd40977
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryLibRewriter.java
@@ -0,0 +1,51 @@
+// Copyright (c) 2025, 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.retargeter;
+
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.R8LibraryDesugaringGraphLens;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+public class LirToLirDesugaredLibraryLibRewriter extends DesugaredLibraryLibRewriter {
+
+ private final CfInstructionDesugaringEventConsumer eventConsumer;
+
+ LirToLirDesugaredLibraryLibRewriter(
+ AppView<?> appView,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ Map<DexMethod, BiFunction<DexItemFactory, DexMethod, CfCode>> rewritings) {
+ super(appView, rewritings);
+ this.eventConsumer = eventConsumer;
+ }
+
+ public MethodLookupResult lookupMethod(
+ MethodLookupResult previous,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext,
+ R8LibraryDesugaringGraphLens lens) {
+ if (isApplicableToContext(context)) {
+ DexMethod retargetMethod =
+ getRetargetMethod(
+ previous.getReference(), eventConsumer, context, methodProcessingContext);
+ if (retargetMethod != null) {
+ return MethodLookupResult.builder(lens, lens.getPrevious())
+ .setReference(retargetMethod)
+ .setReboundReference(retargetMethod)
+ .setIsInterface(false)
+ .setType(InvokeType.STATIC)
+ .build();
+ }
+ }
+ return previous;
+ }
+}