Introduce LirToLirDesugaredLibraryApiConverter
This introduces a subclass of DesugaredLibraryAPIConverter, which will be used in lir-to-lir library desugaring.
This also rewrites DesugaredLibraryAPIConverter to mostly not use CfInvoke, since we do not have a CfInvoke in lir-to-lir library desugaring.
Bug: b/391572031
Change-Id: I487ecbd75d9f554e8b1a0a01b131833263f6b6c3
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index fc0080a..5bba7c1 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.dex;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.isVivifiedType;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.isVivifiedType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryMethod.java b/src/main/java/com/android/tools/r8/graph/LibraryMethod.java
index 29cdc41..66eb26a 100644
--- a/src/main/java/com/android/tools/r8/graph/LibraryMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/LibraryMethod.java
@@ -11,6 +11,10 @@
super(holder, method);
}
+ public static LibraryMethod asLibraryMethodOrNull(DexClassAndMethod method) {
+ return method != null && method.isLibraryMethod() ? method.asLibraryMethod() : null;
+ }
+
@Override
public DexLibraryClass getHolder() {
DexClass holder = super.getHolder();
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 aef9da4..d20e039 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
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaring;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.CfToCfDesugaredLibraryApiConverter;
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;
@@ -43,7 +44,6 @@
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThrowingConsumer;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
@@ -66,7 +66,7 @@
private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
private final InterfaceMethodRewriter interfaceMethodRewriter;
- private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
+ private final CfToCfDesugaredLibraryApiConverter desugaredLibraryAPIConverter;
private final DesugaredLibraryDisableDesugarer disableDesugarer;
private final CfInstructionDesugaring[][] asmOpcodeOrCompareToIdToDesugaringsMap;
@@ -164,15 +164,11 @@
desugarings.add(new OutlineArrayCloneFromInterfaceMethodDesugaring(appView));
}
desugaredLibraryAPIConverter =
- appView.options().getLibraryDesugaringOptions().hasTypeRewriter()
- ? new DesugaredLibraryAPIConverter(
- appView,
- SetUtils.newImmutableSetExcludingNullItems(
- interfaceMethodRewriter, desugaredLibraryRetargeter, backportedMethodRewriter),
- interfaceMethodRewriter != null
- ? interfaceMethodRewriter.getEmulatedMethods()
- : ImmutableSet.of())
- : null;
+ DesugaredLibraryAPIConverter.createForCfToCf(
+ appView,
+ SetUtils.newImmutableSetExcludingNullItems(
+ interfaceMethodRewriter, desugaredLibraryRetargeter, backportedMethodRewriter),
+ interfaceMethodRewriter);
if (desugaredLibraryAPIConverter != null) {
desugarings.add(desugaredLibraryAPIConverter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/LibraryDesugaringOptions.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/LibraryDesugaringOptions.java
index bfc67df..1a965ae 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/LibraryDesugaringOptions.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/LibraryDesugaringOptions.java
@@ -78,7 +78,11 @@
return !synthesizedClassPrefix.isEmpty();
}
- public boolean isR8LirToLirLibraryDesugaringEnabled() {
+ public boolean isCfToCfLibraryDesugaringEnabled() {
+ return !isLirToLirLibraryDesugaringEnabled();
+ }
+
+ public boolean isLirToLirLibraryDesugaringEnabled() {
return options.partialSubCompilationConfiguration != null;
}
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 66e7600..16099e7 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
@@ -18,7 +18,10 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringCollection;
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.itf.InterfaceMethodProcessorFacade;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.utils.InternalOptions;
@@ -48,7 +51,7 @@
InternalOptions options = appView.options();
if (options.isDesugaring()
&& options.getLibraryDesugaringOptions().isEnabled()
- && options.getLibraryDesugaringOptions().isR8LirToLirLibraryDesugaringEnabled()
+ && options.getLibraryDesugaringOptions().isLirToLirLibraryDesugaringEnabled()
&& options.isGeneratingDex()) {
new R8LibraryDesugaring(appView).run(executorService, timing);
}
@@ -87,10 +90,15 @@
ConcurrentProgramMethodSet synthesizedMethods,
ExecutorService executorService)
throws ExecutionException {
- ProcessorContext processorContext = appView.createProcessorContext();
CfInstructionDesugaringEventConsumer eventConsumer =
CfInstructionDesugaringEventConsumer.createForR8LirToLirLibraryDesugaring(
appView, profileCollectionAdditions);
+ // TODO(b/391572031): Implement lir-to-lir interface method rewriting.
+ InterfaceMethodRewriter interfaceMethodRewriter = null;
+ LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter =
+ DesugaredLibraryAPIConverter.createForLirToLir(
+ appView, eventConsumer, interfaceMethodRewriter);
+ ProcessorContext processorContext = appView.createProcessorContext();
LensCodeRewriterUtils emptyRewriterUtils = LensCodeRewriterUtils.empty();
ThreadUtils.processItems(
appView.appInfo().classes(),
@@ -102,7 +110,12 @@
processorContext.createMethodProcessingContext(method);
R8LibraryDesugaringGraphLens libraryDesugaringGraphLens =
new R8LibraryDesugaringGraphLens(
- appView, eventConsumer, method, methodProcessingContext);
+ appView,
+ desugaredLibraryAPIConverter,
+ interfaceMethodRewriter,
+ eventConsumer,
+ method,
+ methodProcessingContext);
LirConverter.rewriteLirMethodWithLens(
method, appView, libraryDesugaringGraphLens, emptyRewriterUtils);
}),
@@ -114,7 +127,9 @@
List<ProgramMethod> needsProcessing = eventConsumer.finalizeDesugaring();
assert needsProcessing.isEmpty();
- // TODO(b/391572031): Generate desugared library API tracking warnings.
+ if (desugaredLibraryAPIConverter != null) {
+ desugaredLibraryAPIConverter.generateTrackingWarnings();
+ }
// Commit pending synthetics.
appView.rebuildAppInfo();
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 25a7ae1..22252fd 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
@@ -22,12 +22,19 @@
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.LirToLirDesugaredLibraryApiConverter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
import java.util.Collections;
import java.util.Set;
public class R8LibraryDesugaringGraphLens extends DefaultNonIdentityGraphLens {
+ private final LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter;
+
+ @SuppressWarnings("UnusedVariable")
+ private final InterfaceMethodRewriter interfaceMethodRewriter;
+
@SuppressWarnings("UnusedVariable")
private final CfInstructionDesugaringEventConsumer eventConsumer;
@@ -39,10 +46,14 @@
public R8LibraryDesugaringGraphLens(
AppView<? extends AppInfoWithClassHierarchy> appView,
+ LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter,
+ InterfaceMethodRewriter interfaceMethodRewriter,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod method,
MethodProcessingContext methodProcessingContext) {
super(appView);
+ this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
+ this.interfaceMethodRewriter = interfaceMethodRewriter;
this.eventConsumer = eventConsumer;
this.method = method;
this.methodProcessingContext = methodProcessingContext;
@@ -69,6 +80,12 @@
MethodLookupResult previous, DexMethod context, GraphLens codeLens) {
// TODO(b/391572031): Implement invoke desugaring.
assert previous.getPrototypeChanges().isEmpty();
+
+ if (desugaredLibraryAPIConverter != null) {
+ return desugaredLibraryAPIConverter.lookupMethod(
+ previous, method, methodProcessingContext, this);
+ }
+
return previous;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/CfToCfDesugaredLibraryApiConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/CfToCfDesugaredLibraryApiConverter.java
new file mode 100644
index 0000000..376b294
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/CfToCfDesugaredLibraryApiConverter.java
@@ -0,0 +1,114 @@
+// 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.apiconversion;
+
+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.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.InvokeType;
+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.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
+
+public class CfToCfDesugaredLibraryApiConverter extends DesugaredLibraryAPIConverter
+ implements CfInstructionDesugaring {
+
+ private final Set<CfInstructionDesugaring> precedingDesugarings;
+
+ CfToCfDesugaredLibraryApiConverter(
+ AppView<?> appView,
+ InterfaceMethodRewriter interfaceMethodRewriter,
+ Set<CfInstructionDesugaring> precedingDesugarings) {
+ super(appView, interfaceMethodRewriter);
+ this.precedingDesugarings = precedingDesugarings;
+ }
+
+ @Override
+ public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+ CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+ }
+
+ @Override
+ public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
+ if (!instruction.isInvoke()) {
+ return DesugarDescription.nothing();
+ }
+ CfInvoke invoke = instruction.asInvoke();
+ InvokeType invokeType =
+ invoke.getInvokeType(
+ appView, context.getDefinition().getCode().getCodeLens(appView), context);
+ if (!invokeNeedsDesugaring(invoke.getMethod(), invokeType, invoke.isInterface(), context)
+ || isAlreadyDesugared(invoke, context)) {
+ return DesugarDescription.nothing();
+ }
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (position,
+ freshLocalProvider,
+ localStackAllocator,
+ desugaringInfo,
+ eventConsumer,
+ theContext,
+ methodProcessingContext,
+ desugaringCollection,
+ dexItemFactory) ->
+ rewriteLibraryInvoke(
+ invoke,
+ invokeType,
+ methodProcessingContext,
+ freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context))
+ .build();
+ }
+
+ private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
+ return Iterables.any(
+ precedingDesugarings, desugaring -> desugaring.compute(invoke, context).needsDesugaring());
+ }
+
+ private Collection<CfInstruction> rewriteLibraryInvoke(
+ CfInvoke invoke,
+ InvokeType invokeType,
+ MethodProcessingContext methodProcessingContext,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ ProgramMethod context) {
+ DexMethod retargetMethod =
+ getRetargetMethod(
+ invoke.getMethod(),
+ invokeType,
+ invoke.isInterface(),
+ eventConsumer,
+ context,
+ methodProcessingContext);
+ if (retargetMethod != null) {
+ return Collections.singletonList(new CfInvoke(Opcodes.INVOKESTATIC, retargetMethod, false));
+ }
+ return getConversionCfProvider()
+ .generateInlinedAPIConversion(
+ invoke,
+ invokeType,
+ methodProcessingContext,
+ freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index 04b88ee..837225a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -1,37 +1,31 @@
// 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.apiconversion;
-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 static com.android.tools.r8.graph.LibraryMethod.asLibraryMethodOrNull;
+
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
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.LibraryMethod;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.InvokeType;
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.FreshLocalProvider;
-import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryTypeRewriter;
-import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.LibraryDesugaringOptions;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.Iterables;
-import java.util.Collection;
import java.util.Collections;
import java.util.Set;
-import java.util.function.IntConsumer;
-import org.objectweb.asm.Opcodes;
// I convert library calls with desugared parameters/return values so they can work normally.
// In the JSON of the desugared library, one can specify conversions between desugared and
@@ -47,25 +41,28 @@
// DesugarType is only a rewritten type (generated through rewriting of type).
// The type, from the library, may either be rewritten to the desugarType,
// or be a rewritten type (generated through rewriting of vivifiedType).
-public class DesugaredLibraryAPIConverter implements CfInstructionDesugaring {
+public abstract class DesugaredLibraryAPIConverter {
- static final String VIVIFIED_PREFIX = "$-vivified-$.";
- public static final String DESCRIPTOR_VIVIFIED_PREFIX = "L$-vivified-$/";
-
- private final AppView<?> appView;
- private final Set<CfInstructionDesugaring> precedingDesugarings;
+ final AppView<?> appView;
private final Set<DexString> emulatedMethods;
+ private final MachineDesugaredLibrarySpecification libraryDesugaringSpecification;
+ private final DesugaredLibraryTypeRewriter typeRewriter;
private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizor;
private final Set<DexMethod> trackedAPIs;
- public DesugaredLibraryAPIConverter(
- AppView<?> appView,
- Set<CfInstructionDesugaring> precedingDesugarings,
- Set<DexString> emulatedMethods) {
+ DesugaredLibraryAPIConverter(
+ AppView<?> appView, InterfaceMethodRewriter interfaceMethodRewriter) {
this.appView = appView;
- this.precedingDesugarings = precedingDesugarings;
- this.emulatedMethods = emulatedMethods;
+ this.emulatedMethods =
+ interfaceMethodRewriter != null
+ ? interfaceMethodRewriter.getEmulatedMethods()
+ : Collections.emptySet();
+ LibraryDesugaringOptions libraryDesugaringOptions =
+ appView.options().getLibraryDesugaringOptions();
+ this.libraryDesugaringSpecification =
+ libraryDesugaringOptions.getMachineDesugaredLibrarySpecification();
+ this.typeRewriter = libraryDesugaringOptions.getTypeRewriter();
this.wrapperSynthesizor = new DesugaredLibraryWrapperSynthesizer(appView);
if (appView.options().testing.trackDesugaredApiConversions) {
trackedAPIs = SetUtils.newConcurrentHashSet();
@@ -74,49 +71,54 @@
}
}
- private boolean invokeNeedsDesugaring(CfInvoke invoke, ProgramMethod context) {
+ public static CfToCfDesugaredLibraryApiConverter createForCfToCf(
+ AppView<?> appView,
+ Set<CfInstructionDesugaring> precedingDesugarings,
+ InterfaceMethodRewriter interfaceMethodRewriter) {
+ LibraryDesugaringOptions libraryDesugaringOptions =
+ appView.options().getLibraryDesugaringOptions();
+ if (libraryDesugaringOptions.isCfToCfLibraryDesugaringEnabled()
+ && libraryDesugaringOptions.hasTypeRewriter()) {
+ return new CfToCfDesugaredLibraryApiConverter(
+ appView, interfaceMethodRewriter, precedingDesugarings);
+ }
+ return null;
+ }
+
+ public static LirToLirDesugaredLibraryApiConverter createForLirToLir(
+ AppView<?> appView,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ InterfaceMethodRewriter interfaceMethodRewriter) {
+ LibraryDesugaringOptions libraryDesugaringOptions =
+ appView.options().getLibraryDesugaringOptions();
+ if (libraryDesugaringOptions.isLirToLirLibraryDesugaringEnabled()
+ && libraryDesugaringOptions.hasTypeRewriter()) {
+ return new LirToLirDesugaredLibraryApiConverter(
+ appView, eventConsumer, interfaceMethodRewriter);
+ }
+ return null;
+ }
+
+ boolean invokeNeedsDesugaring(
+ DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
if (isAPIConversionSyntheticType(context.getHolderType(), wrapperSynthesizor, appView)) {
return false;
}
- if (appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())) {
+ if (appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())
+ || invokedMethod.getHolderType().isArrayType()) {
return false;
}
- return shouldRewriteInvoke(invoke.asInvoke(), context);
- }
-
- @Override
- public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
- CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
- }
-
- @Override
- public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
- if (!instruction.isInvoke()) {
- return DesugarDescription.nothing();
+ LibraryMethod resolvedMethod =
+ getMethodForDesugaring(invokedMethod, invokeType, isInterface, context);
+ if (resolvedMethod == null
+ || typeRewriter.hasRewrittenType(resolvedMethod.getHolderType())
+ || isEmulatedInterfaceOverride(resolvedMethod)) {
+ return false;
}
- CfInvoke invoke = instruction.asInvoke();
- if (!invokeNeedsDesugaring(invoke, context)) {
- return DesugarDescription.nothing();
- }
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- theContext,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) ->
- rewriteLibraryInvoke(
- invoke,
- methodProcessingContext,
- freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context))
- .build();
+ return libraryDesugaringSpecification
+ .getApiGenericConversion()
+ .containsKey(resolvedMethod.getReference())
+ || typeRewriter.hasRewrittenTypeInSignature(invokedMethod.getProto());
}
static boolean isAPIConversionSyntheticType(
@@ -125,62 +127,18 @@
|| appView.getSyntheticItems().isSyntheticOfKind(type, kinds -> kinds.API_CONVERSION);
}
- public static boolean isVivifiedType(DexType type) {
- return type.descriptor.toString().startsWith(DESCRIPTOR_VIVIFIED_PREFIX);
- }
-
- private DexClassAndMethod getMethodForDesugaring(CfInvoke invoke, ProgramMethod context) {
- DexMethod invokedMethod = invoke.getMethod();
+ private LibraryMethod getMethodForDesugaring(
+ DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
// TODO(b/191656218): Use lookupInvokeSpecial instead when this is all to Cf.
AppInfoWithClassHierarchy appInfoForDesugaring = appView.appInfoForDesugaring();
- return invoke.isInvokeSuper(context.getHolderType())
- ? appInfoForDesugaring.lookupSuperTarget(
- invokedMethod, context, appView, appInfoForDesugaring)
- : appInfoForDesugaring
- .resolveMethodLegacy(invokedMethod, invoke.isInterface())
- .getResolutionPair();
- }
-
- // TODO(b/191656218): Consider caching the result.
- private boolean shouldRewriteInvoke(CfInvoke invoke, ProgramMethod context) {
- DexClassAndMethod invokedMethod = getMethodForDesugaring(invoke, context);
- if (invokedMethod == null) {
- // Implies a resolution/look-up failure, we do not convert to keep the runtime error.
- return false;
- }
- DexType holderType = invokedMethod.getHolderType();
- if (appView
- .options()
- .getLibraryDesugaringOptions()
- .getTypeRewriter()
- .hasRewrittenType(holderType)
- || holderType.isArrayType()) {
- return false;
- }
- DexClass dexClass = appView.definitionFor(holderType);
- if (dexClass == null || !dexClass.isLibraryClass()) {
- return false;
- }
- if (isEmulatedInterfaceOverride(invokedMethod)) {
- return false;
- }
- if (isAlreadyDesugared(invoke, context)) {
- return false;
- }
- if (appView
- .options()
- .getLibraryDesugaringOptions()
- .getMachineDesugaredLibrarySpecification()
- .getApiGenericConversion()
- .get(invokedMethod.getReference())
- != null) {
- return true;
- }
- return appView
- .options()
- .getLibraryDesugaringOptions()
- .getTypeRewriter()
- .hasRewrittenTypeInSignature(invokedMethod.getProto());
+ DexClassAndMethod resolvedMethod =
+ invokeType.isSuper()
+ ? appInfoForDesugaring.lookupSuperTarget(
+ invokedMethod, context, appView, appInfoForDesugaring)
+ : appInfoForDesugaring
+ .resolveMethodLegacy(invokedMethod, isInterface)
+ .getResolutionPair();
+ return asLibraryMethodOrNull(resolvedMethod);
}
// The problem is that a method can resolve into a library method which is not present at runtime,
@@ -194,40 +152,11 @@
.appInfoForDesugaring()
.lookupMaximallySpecificMethod(invokedMethod.getHolder(), invokedMethod.getReference());
return interfaceResult != null
- && appView
- .options()
- .getLibraryDesugaringOptions()
- .getMachineDesugaredLibrarySpecification()
+ && libraryDesugaringSpecification
.getEmulatedInterfaces()
.containsKey(interfaceResult.getHolderType());
}
- private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
- return Iterables.any(
- precedingDesugarings, desugaring -> desugaring.compute(invoke, context).needsDesugaring());
- }
-
- public static DexMethod methodWithVivifiedTypeInSignature(
- DexMethod originalMethod, DexType holder, AppView<?> appView) {
- DexType[] newParameters = originalMethod.getParameters().getBacking().clone();
- DesugaredLibraryTypeRewriter typeRewriter =
- appView.options().getLibraryDesugaringOptions().getTypeRewriter();
- int index = 0;
- for (DexType param : originalMethod.getParameters()) {
- if (typeRewriter.hasRewrittenType(param)) {
- newParameters[index] = vivifiedTypeFor(param, appView);
- }
- index++;
- }
- DexType returnType = originalMethod.getReturnType();
- DexType newReturnType =
- typeRewriter.hasRewrittenType(returnType)
- ? vivifiedTypeFor(returnType, appView)
- : returnType;
- DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters);
- return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name);
- }
-
public void generateTrackingWarnings() {
generateTrackDesugaredAPIWarnings(trackedAPIs, "", appView);
}
@@ -247,81 +176,58 @@
tracked.clear();
}
- public static DexType vivifiedTypeFor(DexType type, AppView<?> appView) {
- DexType vivifiedType =
- appView
- .dexItemFactory()
- .createSynthesizedType(
- DescriptorUtils.javaTypeToDescriptor(VIVIFIED_PREFIX + type.toString()));
- // We would need to ensure a classpath class for each type to remove this rewriteType call.
- appView
- .options()
- .getLibraryDesugaringOptions()
- .getTypeRewriter()
- .rewriteType(vivifiedType, type);
- return vivifiedType;
+ public DesugaredLibraryConversionCfProvider getConversionCfProvider() {
+ return wrapperSynthesizor.getConversionCfProvider();
}
- private Collection<CfInstruction> rewriteLibraryInvoke(
- CfInvoke invoke,
- MethodProcessingContext methodProcessingContext,
- FreshLocalProvider freshLocalProvider,
- LocalStackAllocator localStackAllocator,
- CfInstructionDesugaringEventConsumer eventConsumer,
- ProgramMethod context) {
- DexMethod invokedMethod = invoke.getMethod();
- if (trackedAPIs != null) {
- trackedAPIs.add(invokedMethod);
+ public DexMethod getRetargetMethod(
+ DexMethod invokedMethod,
+ InvokeType invokeType,
+ boolean isInterface,
+ DesugaredLibraryAPIConverterEventConsumer eventConsumer,
+ ProgramMethod method,
+ MethodProcessingContext methodProcessingContext) {
+ if (shouldOutlineAPIConversion(invokedMethod, invokeType, isInterface, method)) {
+ return getConversionCfProvider()
+ .generateOutlinedAPIConversion(
+ invokedMethod,
+ invokeType,
+ isInterface,
+ eventConsumer,
+ method,
+ methodProcessingContext)
+ .getReference();
}
- if (shouldOutlineAPIConversion(invoke, context)) {
- DexMethod outlinedAPIConversion =
- wrapperSynthesizor
- .getConversionCfProvider()
- .generateOutlinedAPIConversion(
- invoke, eventConsumer, context, methodProcessingContext)
- .getReference();
- return Collections.singletonList(
- new CfInvoke(Opcodes.INVOKESTATIC, outlinedAPIConversion, false));
- }
- return wrapperSynthesizor
- .getConversionCfProvider()
- .generateInlinedAPIConversion(
- invoke,
- methodProcessingContext,
- freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context);
+ return null;
}
// If the option is set, we try to outline API conversions as much as possible to reduce the
- // number
- // of soft verification failures. We cannot outline API conversions through super invokes, to
- // instance initializers and to non public methods.
- private boolean shouldOutlineAPIConversion(CfInvoke invoke, ProgramMethod context) {
- if (appView.options().testing.forceInlineApiConversions) {
+ // number of soft verification failures. We cannot outline API conversions through super invokes,
+ // to instance initializers and to non public methods.
+ public boolean shouldOutlineAPIConversion(
+ DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
+ if (trackedAPIs != null) {
+ trackedAPIs.add(invokedMethod);
+ }
+ if (appView.testing().forceInlineApiConversions) {
return false;
}
- if (invoke.isInvokeSuper(context.getHolderType())) {
+ if (invokeType.isSuper()) {
return false;
}
- if (invoke.getMethod().isInstanceInitializer(appView.dexItemFactory())) {
+ if (invokedMethod.isInstanceInitializer(appView.dexItemFactory())) {
return false;
}
- DexClassAndMethod methodForDesugaring = getMethodForDesugaring(invoke, context);
+ DexClassAndMethod methodForDesugaring =
+ getMethodForDesugaring(invokedMethod, invokeType, isInterface, context);
assert methodForDesugaring != null;
// Specific apis that we never want to outline, namely, apis for stack introspection since it
// confuses developers in debug mode.
- if (appView
- .options()
- .getLibraryDesugaringOptions()
- .getMachineDesugaredLibrarySpecification()
+ if (libraryDesugaringSpecification
.getNeverOutlineApi()
.contains(methodForDesugaring.getReference())) {
return false;
}
return methodForDesugaring.getAccessFlags().isPublic();
}
-
-
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
index adda377..586b913 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.vivifiedTypeFor;
import com.android.tools.r8.cf.code.CfArrayLoad;
import com.android.tools.r8.cf.code.CfArrayStore;
@@ -34,6 +34,7 @@
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.code.InvokeType;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
@@ -227,18 +228,17 @@
}
public ProgramMethod generateOutlinedAPIConversion(
- CfInvoke invoke,
+ DexMethod method,
+ InvokeType invokeType,
+ boolean isInterface,
DesugaredLibraryAPIConverterEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
- DexMethod method = invoke.getMethod();
- DexProto newProto = factory.prependHolderToProtoIf(method, !invoke.isInvokeStatic());
+ DexProto newProto = factory.prependHolderToProtoIf(method, !invokeType.isStatic());
DexMethod returnConversion =
- computeReturnConversion(
- method, false, eventConsumer, context, methodProcessingContext::createUniqueContext);
+ computeReturnConversion(method, false, eventConsumer, context, methodProcessingContext);
DexMethod[] parameterConversions =
- computeParameterConversions(
- method, true, eventConsumer, context, methodProcessingContext::createUniqueContext);
+ computeParameterConversions(method, true, eventConsumer, context, methodProcessingContext);
ProgramMethod outline =
appView
.getSyntheticItems()
@@ -259,10 +259,10 @@
methodSignature.holder,
convertedMethod(
method, true, returnConversion, parameterConversions),
- invoke.isInterface(),
+ isInterface,
returnConversion,
parameterConversions,
- invoke.getOpcode())
+ invokeType.getCfOpcode())
.generateCfCode()));
eventConsumer.acceptAPIConversionOutline(outline, context);
return outline;
@@ -270,49 +270,33 @@
public Collection<CfInstruction> generateInlinedAPIConversion(
CfInvoke invoke,
+ InvokeType invokeType,
MethodProcessingContext methodProcessingContext,
FreshLocalProvider freshLocalProvider,
LocalStackAllocator localStackAllocator,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context) {
-
DexMethod invokedMethod = invoke.getMethod();
DexMethod returnConversion =
computeReturnConversion(
- invokedMethod,
- false,
- eventConsumer,
- context,
- methodProcessingContext::createUniqueContext);
+ invokedMethod, false, eventConsumer, context, methodProcessingContext);
DexMethod[] parameterConversions =
computeParameterConversions(
- invokedMethod,
- true,
- eventConsumer,
- context,
- methodProcessingContext::createUniqueContext);
+ invokedMethod, true, eventConsumer, context, methodProcessingContext);
ArrayList<CfInstruction> cfInstructions = new ArrayList<>();
if (!invokedMethod.getParameters().isEmpty()) {
- // If only the last 2 parameters require conversion, we do everything inlined.
- // If other parameters require conversion, we outline the parameter conversion but keep the
- // API call inlined. The returned value is always converted inlined.
- boolean requireOutlinedParameterConversion = false;
- for (int i = 0; i < parameterConversions.length - 2; i++) {
- requireOutlinedParameterConversion |= parameterConversions[i] != null;
- }
- // We cannot use the swap instruction if the last parameter is wide.
- requireOutlinedParameterConversion |= invokedMethod.getParameters().getLast().isWideType();
-
- if (requireOutlinedParameterConversion) {
+ DexMethod parameterConversionTarget =
+ getParameterConversionTarget(
+ parameterConversions, invokedMethod, false, eventConsumer, methodProcessingContext);
+ if (parameterConversionTarget != null) {
addOutlineParameterConversionInstructions(
parameterConversions,
+ parameterConversionTarget,
cfInstructions,
- methodProcessingContext,
invokedMethod,
freshLocalProvider,
- localStackAllocator,
- eventConsumer);
+ localStackAllocator);
} else {
addInlineParameterConversionInstructions(
parameterConversions, cfInstructions, invokedMethod);
@@ -327,7 +311,7 @@
assert returnConversion.getArity() == 1 || returnConversion.getArity() == 2;
if (returnConversion.getArity() == 2) {
// If there is a second parameter, pass the receiver.
- if (!invoke.isInvokeSuper(context.getHolderType())) {
+ if (!invokeType.isSuper()) {
appView
.reporter()
.error(
@@ -344,17 +328,27 @@
return cfInstructions;
}
- // The parameters are converted and returned in an array of converted parameters. The parameter
- // array then needs to be unwrapped at the call site.
- private void addOutlineParameterConversionInstructions(
+ public DexMethod getParameterConversionTarget(
DexMethod[] parameterConversions,
- ArrayList<CfInstruction> cfInstructions,
- MethodProcessingContext methodProcessingContext,
DexMethod invokedMethod,
- FreshLocalProvider freshLocalProvider,
- LocalStackAllocator localStackAllocator,
- CfInstructionDesugaringEventConsumer eventConsumer) {
- localStackAllocator.allocateLocalStack(4);
+ boolean canSwapWide,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ // If only the last 2 parameters require conversion, we do everything inlined.
+ // If other parameters require conversion, we outline the parameter conversion but keep the
+ // API call inlined. The returned value is always converted inlined.
+ boolean requireOutlinedParameterConversion = false;
+ for (int i = 0; i < parameterConversions.length - 2; i++) {
+ requireOutlinedParameterConversion |= parameterConversions[i] != null;
+ }
+ // We cannot use the swap instruction if the last parameter is wide.
+ if (!canSwapWide && invokedMethod.getParameters().getLast().isWideType()) {
+ requireOutlinedParameterConversion = true;
+ }
+ if (!requireOutlinedParameterConversion) {
+ return null;
+ }
+
DexProto newProto =
appView
.dexItemFactory()
@@ -379,8 +373,20 @@
methodSignature.holder, invokedMethod, parameterConversions)));
eventConsumer.acceptAPIConversionOutline(
parameterConversion, methodProcessingContext.getMethodContext());
- cfInstructions.add(
- new CfInvoke(Opcodes.INVOKESTATIC, parameterConversion.getReference(), false));
+ return parameterConversion.getReference();
+ }
+
+ // The parameters are converted and returned in an array of converted parameters. The parameter
+ // array then needs to be unwrapped at the call site.
+ private void addOutlineParameterConversionInstructions(
+ DexMethod[] parameterConversions,
+ DexMethod parameterConversionTarget,
+ ArrayList<CfInstruction> cfInstructions,
+ DexMethod invokedMethod,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator) {
+ localStackAllocator.allocateLocalStack(4);
+ cfInstructions.add(new CfInvoke(Opcodes.INVOKESTATIC, parameterConversionTarget, false));
int arrayLocal = freshLocalProvider.getFreshLocal(ValueType.OBJECT.requiredRegisters());
cfInstructions.add(new CfStore(ValueType.OBJECT, arrayLocal));
for (int i = 0; i < parameterConversions.length; i++) {
@@ -460,6 +466,20 @@
.getResolvedProgramMethod();
}
+ public DexMethod computeReturnConversion(
+ DexMethod invokedMethod,
+ boolean destIsVivified,
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ return computeReturnConversion(
+ invokedMethod,
+ destIsVivified,
+ eventConsumer,
+ context,
+ methodProcessingContext::createUniqueContext);
+ }
+
private DexMethod computeReturnConversion(
DexMethod invokedMethod,
boolean destIsVivified,
@@ -511,6 +531,20 @@
return null;
}
+ public DexMethod[] computeParameterConversions(
+ DexMethod invokedMethod,
+ boolean destIsVivified,
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ return computeParameterConversions(
+ invokedMethod,
+ destIsVivified,
+ eventConsumer,
+ context,
+ methodProcessingContext::createUniqueContext);
+ }
+
private DexMethod[] computeParameterConversions(
DexMethod invokedMethod,
boolean destIsVivified,
@@ -584,7 +618,7 @@
return conversions == null ? null : conversions[parameterIndex];
}
- private DexMethod convertedMethod(
+ public DexMethod convertedMethod(
DexMethod method,
boolean parameterDestIsVivified,
DexMethod returnConversion,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
index afe4481..7080794 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.vivifiedTypeFor;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index f060b91..35802f8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -415,7 +415,7 @@
}
private DexType vivifiedTypeFor(DexType type) {
- return DesugaredLibraryAPIConverter.vivifiedTypeFor(type, appView);
+ return VivifiedTypeUtils.vivifiedTypeFor(type, appView);
}
static class WrapperConversions {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/LirToLirDesugaredLibraryApiConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/LirToLirDesugaredLibraryApiConverter.java
new file mode 100644
index 0000000..69b87a2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/LirToLirDesugaredLibraryApiConverter.java
@@ -0,0 +1,59 @@
+// 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.apiconversion;
+
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+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.desugaredlibrary.R8LibraryDesugaringGraphLens;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+
+public class LirToLirDesugaredLibraryApiConverter extends DesugaredLibraryAPIConverter {
+
+ private final DesugaredLibraryAPIConverterEventConsumer eventConsumer;
+
+ LirToLirDesugaredLibraryApiConverter(
+ AppView<?> appView,
+ DesugaredLibraryAPIConverterEventConsumer eventConsumer,
+ InterfaceMethodRewriter interfaceMethodRewriter) {
+ super(appView, interfaceMethodRewriter);
+ this.eventConsumer = eventConsumer;
+ }
+
+ public MethodLookupResult lookupMethod(
+ MethodLookupResult previous,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext,
+ R8LibraryDesugaringGraphLens lens) {
+ DexMethod method = previous.getReference();
+ InvokeType invokeType = previous.getType();
+ boolean isInterface = previous.isInterface().toBoolean();
+ if (!invokeNeedsDesugaring(method, invokeType, isInterface, context)) {
+ return previous;
+ }
+ DexMethod retargetMethod =
+ getRetargetMethod(
+ method, invokeType, isInterface, eventConsumer, context, methodProcessingContext);
+ if (retargetMethod != null) {
+ return MethodLookupResult.builder(lens, lens.getPrevious())
+ .setReference(retargetMethod)
+ .setReboundReference(retargetMethod)
+ .setIsInterface(false)
+ .setType(InvokeType.STATIC)
+ .build();
+ } else {
+ return MethodLookupResult.builder(lens, lens.getPrevious())
+ .setReference(previous.getReference())
+ .setReboundReference(previous.getReboundReference())
+ .setIsInterface(isInterface)
+ .setNeedsDesugaredLibraryApiConversion()
+ .setType(previous.getType())
+ .build();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/VivifiedTypeUtils.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/VivifiedTypeUtils.java
new file mode 100644
index 0000000..11ab188
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/VivifiedTypeUtils.java
@@ -0,0 +1,57 @@
+// 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.apiconversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryTypeRewriter;
+import com.android.tools.r8.utils.DescriptorUtils;
+
+public class VivifiedTypeUtils {
+
+ private static final String VIVIFIED_PREFIX = "$-vivified-$.";
+ public static final String DESCRIPTOR_VIVIFIED_PREFIX = "L$-vivified-$/";
+
+ public static boolean isVivifiedType(DexType type) {
+ return type.descriptor.toString().startsWith(DESCRIPTOR_VIVIFIED_PREFIX);
+ }
+
+ public static DexMethod methodWithVivifiedTypeInSignature(
+ DexMethod originalMethod, DexType holder, AppView<?> appView) {
+ DexType[] newParameters = originalMethod.getParameters().getBacking().clone();
+ DesugaredLibraryTypeRewriter typeRewriter =
+ appView.options().getLibraryDesugaringOptions().getTypeRewriter();
+ int index = 0;
+ for (DexType param : originalMethod.getParameters()) {
+ if (typeRewriter.hasRewrittenType(param)) {
+ newParameters[index] = vivifiedTypeFor(param, appView);
+ }
+ index++;
+ }
+ DexType returnType = originalMethod.getReturnType();
+ DexType newReturnType =
+ typeRewriter.hasRewrittenType(returnType)
+ ? vivifiedTypeFor(returnType, appView)
+ : returnType;
+ DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters);
+ return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name);
+ }
+
+ public static DexType vivifiedTypeFor(DexType type, AppView<?> appView) {
+ DexType vivifiedType =
+ appView
+ .dexItemFactory()
+ .createSynthesizedType(
+ DescriptorUtils.javaTypeToDescriptor(VIVIFIED_PREFIX + type.toString()));
+ // We would need to ensure a classpath class for each type to remove this rewriteType call.
+ appView
+ .options()
+ .getLibraryDesugaringOptions()
+ .getTypeRewriter()
+ .rewriteType(vivifiedType, type);
+ return vivifiedType;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
index 0a2adad..66763a0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.vivifiedTypeFor;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index babfe6a..d98e17f 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult.isOverriding;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.isVivifiedType;
import static com.android.tools.r8.utils.collections.ThrowingSet.isThrowingSet;
import com.android.tools.r8.cf.CfVersion;
@@ -54,7 +55,6 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.naming.SeedMapper;
import com.android.tools.r8.repackaging.RepackagingUtils;
import com.android.tools.r8.shaking.KeepInfo.Joiner;
@@ -527,7 +527,7 @@
|| deadProtoTypes.contains(type)
|| getMissingClasses().contains(type)
// TODO(b/150736225): Not sure how to remove these.
- || DesugaredLibraryAPIConverter.isVivifiedType(type)
+ || isVivifiedType(type)
: "Failed lookup of non-missing type: " + type;
return definition;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 12eecf3..20e6f76 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.FieldAccessInfoImpl.MISSING_FIELD_ACCESS_INFO;
import static com.android.tools.r8.ir.desugar.LambdaDescriptor.isLambdaMetafactoryMethod;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.methodWithVivifiedTypeInSignature;
import static com.android.tools.r8.naming.IdentifierNameStringUtils.identifyIdentifier;
import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
import static com.android.tools.r8.shaking.KeepInfo.Joiner.asClassJoinerOrNull;
@@ -3128,7 +3129,7 @@
.getTypeRewriter()
.hasRewrittenTypeInSignature(method.getProto())) {
DexMethod methodToResolve =
- DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature(
+ methodWithVivifiedTypeInSignature(
method.getReference(), method.getHolderType(), appView);
assert methodToResolve != method.getReference();
markLibraryOrClasspathOverrideLive(
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index a036577..bfe978f 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.shaking;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.VivifiedTypeUtils.DESCRIPTOR_VIVIFIED_PREFIX;
import static com.android.tools.r8.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
import com.android.tools.r8.androidapi.CovariantReturnTypeMethods;