Introduce RetargetMethodSupplier in InterfaceMethodRewriter
This rewrites the InterfaceMethodRewriter from producing a DesugarDescription result to producing a RetargetMethodSupplier, which can be converted into a DesugarDescription.
In order to support lir-to-lir library desugaring the RetargetMethodSupplier will be extended to produce a MethodLookupResult.
Change-Id: I3568325dbe27b20a47b8010ea8e363f10291748e
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 7d420bb..56b60db 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfInvokeDynamic;
import com.android.tools.r8.cf.code.CfOpcodeUtils;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppInfo;
@@ -35,6 +36,7 @@
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.DesugarDescription.ScanCallback;
import com.android.tools.r8.ir.desugar.ProgramAdditions;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
@@ -49,7 +51,6 @@
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -278,11 +279,20 @@
private DesugarDescription compute(
DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
+ RetargetMethodSupplier retargetMethodSupplier =
+ getRetargetMethodSupplier(invokedMethod, invokeType, isInterface, context);
+ return retargetMethodSupplier != RetargetMethodSupplier.none()
+ ? retargetMethodSupplier.toDesugarDescription(context)
+ : DesugarDescription.nothing();
+ }
+
+ private RetargetMethodSupplier getRetargetMethodSupplier(
+ DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
if (isSyntheticMethodThatShouldNotBeDoubleProcessed(context)) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (invokedMethod.getHolderType().isArrayType() || factory.isConstructor(invokedMethod)) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
// Continue with invoke type logic. If the invoke is not an interface invoke, then there should
// generally not be any desugaring. However, there are some cases where the insertion of
@@ -301,7 +311,7 @@
}
}
- private DesugarDescription computeInvokeSpecial(
+ private RetargetMethodSupplier computeInvokeSpecial(
DexClass holder,
DexMethod invokedMethod,
InvokeType invokeType,
@@ -315,9 +325,8 @@
return computeEmulatedInterfaceInvokeSpecial(holder, invokedMethod, context);
}
if (holder == null) {
- return DesugarDescription.builder()
- .addScanEffect(() -> warnMissingType(context, invokedMethod.getHolderType()))
- .build();
+ return new WarningRetargetMethodSupplier(
+ () -> warnMissingType(context, invokedMethod.getHolderType()));
}
MethodResolutionResult resolutionResult =
appView.appInfoForDesugaring().resolveMethodLegacy(invokedMethod, isInterface);
@@ -329,7 +338,7 @@
}
}
- private DesugarDescription computeInvokeStatic(
+ private RetargetMethodSupplier computeInvokeStatic(
DexClass holder,
DexMethod invokedMethod,
InvokeType invokeType,
@@ -337,23 +346,22 @@
ProgramMethod context) {
assert invokeType.isStatic();
if (desugaringMode == LIBRARY_DESUGARING_N_PLUS || !isInterface) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (holder == null) {
- return DesugarDescription.builder()
- .addScanEffect(() -> leavingStaticInvokeToInterface(context))
- .addScanEffect(() -> warnMissingType(context, invokedMethod.getHolderType()))
- .build();
+ return new WarningRetargetMethodSupplier(
+ () -> {
+ leavingStaticInvokeToInterface(context);
+ warnMissingType(context, invokedMethod.getHolderType());
+ });
}
if (!holder.isInterface()) {
- return DesugarDescription.builder()
- .addScanEffect(() -> leavingStaticInvokeToInterface(context))
- .build();
+ return new WarningRetargetMethodSupplier(() -> leavingStaticInvokeToInterface(context));
}
// TODO(b/199135051): This should not be needed. Targeted synthetics should be in place.
if (appView.getSyntheticItems().isPendingSynthetic(invokedMethod.getHolderType())) {
// We did not create this code yet, but it will not require rewriting.
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (isNonDesugaredLibraryClass(holder)) {
// NOTE: we intentionally don't desugar static calls into static interface
@@ -367,9 +375,7 @@
// Retarget call to an appropriate method of companion class.
if (options.canLeaveStaticInterfaceMethodInvokes()) {
// When leaving static interface method invokes upgrade the class file version.
- return DesugarDescription.builder()
- .addScanEffect(() -> leavingStaticInvokeToInterface(context))
- .build();
+ return new WarningRetargetMethodSupplier(() -> leavingStaticInvokeToInterface(context));
}
// On pre-L devices static calls to interface methods result in verifier
// rejecting the whole class. We have to create special dispatch classes,
@@ -380,45 +386,38 @@
// When reprocessing the method generated below, the desugaring asserts this method
// does not need any new desugaring, while the interface method rewriter tries
// to outline again the invoke-static. Just do nothing instead.
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context1,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- ProgramMethod newProgramMethod =
- appView
- .getSyntheticItems()
- .createMethod(
- kind -> kind.STATIC_INTERFACE_CALL,
- methodProcessingContext.createUniqueContext(),
- appView,
- syntheticMethodBuilder ->
- syntheticMethodBuilder
- .setProto(invokedMethod.getProto())
- .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
- .setCode(
- m ->
- ForwardMethodBuilder.builder(factory)
- .setStaticTarget(invokedMethod, true)
- .setStaticSource(m)
- .buildCf()));
- synthesizedMethods.add(newProgramMethod);
- eventConsumer.acceptInvokeStaticInterfaceOutliningMethod(
- newProgramMethod, context1);
- // The synthetic dispatch class has static interface method invokes, so set
- // the class file version accordingly.
- leavingStaticInvokeToInterface(newProgramMethod);
- return getInvokeStaticInstructions(newProgramMethod.getReference());
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ ProgramMethod newProgramMethod =
+ appView
+ .getSyntheticItems()
+ .createMethod(
+ kind -> kind.STATIC_INTERFACE_CALL,
+ methodProcessingContext.createUniqueContext(),
+ appView,
+ syntheticMethodBuilder ->
+ syntheticMethodBuilder
+ .setProto(invokedMethod.getProto())
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(
+ m ->
+ ForwardMethodBuilder.builder(factory)
+ .setStaticTarget(invokedMethod, true)
+ .setStaticSource(m)
+ .buildCf()));
+ synthesizedMethods.add(newProgramMethod);
+ eventConsumer.acceptInvokeStaticInterfaceOutliningMethod(newProgramMethod, context);
+ // The synthetic dispatch class has static interface method invokes, so set
+ // the class file version accordingly.
+ leavingStaticInvokeToInterface(newProgramMethod);
+ return newProgramMethod.getReference();
+ }
+ };
}
SingleResolutionResult<?> resolutionResult =
@@ -433,25 +432,19 @@
assert resolutionResult != null;
assert resolutionResult.getResolvedMethod().isStatic();
DexClassAndMethod method = resolutionResult.getResolutionPair();
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context12,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- DexClassAndMethod companionMethod =
- helper.ensureStaticAsMethodOfCompanionClassStub(method, eventConsumer);
- return getInvokeStaticInstructions(companionMethod.getReference());
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ return helper
+ .ensureStaticAsMethodOfCompanionClassStub(method, eventConsumer)
+ .getReference();
+ }
+ };
}
- private DesugarDescription computeInvokeInterface(
+ private RetargetMethodSupplier computeInvokeInterface(
DexClass holder,
DexMethod invokedMethod,
InvokeType invokeType,
@@ -460,13 +453,13 @@
assert invokeType.isInterface();
if (holder == null) {
// For virtual targets we should not report anything as any virtual dispatch just remains.
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
AppInfoWithClassHierarchy appInfoForDesugaring = appView.appInfoForDesugaring();
SingleResolutionResult<?> resolutionResult =
appInfoForDesugaring.resolveMethodLegacy(invokedMethod, isInterface).asSingleResolution();
if (resolutionResult == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (desugaringMode == LIBRARY_DESUGARING_N_PLUS) {
return computeEmulatedInterfaceVirtualDispatch(resolutionResult);
@@ -482,7 +475,7 @@
return computeEmulatedInterfaceVirtualDispatch(resolutionResult);
}
- private DesugarDescription computeInvokeVirtual(
+ private RetargetMethodSupplier computeInvokeVirtual(
DexClass holder,
DexMethod invokedMethod,
InvokeType invokeType,
@@ -491,26 +484,26 @@
assert invokeType.isVirtual() || invokeType.isPolymorphic();
if (holder == null) {
// For virtual targets we should not report anything as any virtual dispatch just remains.
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
SingleResolutionResult<?> resolutionResult =
appInfo.resolveMethodLegacy(invokedMethod, isInterface).asSingleResolution();
if (resolutionResult == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (desugaringMode == LIBRARY_DESUGARING_N_PLUS) {
if (resolutionResult.getResolvedMethod().isPrivate()
&& resolutionResult.isAccessibleFrom(context, appView, appInfo).isTrue()) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (resolutionResult.getResolvedMethod().isStatic()) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
return computeEmulatedInterfaceVirtualDispatch(resolutionResult);
}
- DesugarDescription description = computeEmulatedInterfaceVirtualDispatch(resolutionResult);
- if (description != DesugarDescription.nothing()) {
+ RetargetMethodSupplier description = computeEmulatedInterfaceVirtualDispatch(resolutionResult);
+ if (description != RetargetMethodSupplier.none()) {
return description;
}
// It may be the case that a virtual invoke resolves to a static method. In such a case, if
@@ -525,45 +518,39 @@
invokedMethod, invokeType, resolutionResult.asSingleResolution());
}
}
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
- private DesugarDescription computeEmulatedInterfaceVirtualDispatch(
+ private RetargetMethodSupplier computeEmulatedInterfaceVirtualDispatch(
SingleResolutionResult<?> resolutionResult) {
assert resolutionResult != null;
EmulatedDispatchMethodDescriptor emulatedDispatchMethodDescriptor =
helper.getEmulatedDispatchDescriptor(
resolutionResult.getInitialResolutionHolder(), resolutionResult.getResolutionPair());
if (emulatedDispatchMethodDescriptor == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context1,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) ->
- getInvokeStaticInstructions(
- helper
- .ensureEmulatedInterfaceDispatchMethod(
- emulatedDispatchMethodDescriptor, eventConsumer)
- .getReference()))
- .build();
+ return new StaticRetargetMethodSupplier() {
+
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ return helper
+ .ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethodDescriptor, eventConsumer)
+ .getReference();
+ }
+ };
}
- private DesugarDescription computeInvokeDirect(
+ private RetargetMethodSupplier computeInvokeDirect(
DexClass clazz,
DexMethod invokedMethod,
InvokeType invokeType,
ProgramMethod context,
MethodResolutionResult resolutionResult) {
if (!clazz.isInterface()) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (clazz.isLibraryClass()) {
@@ -580,47 +567,39 @@
SingleResolutionResult<?> singleResolution = resolutionResult.asSingleResolution();
if (singleResolution == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
DexClassAndMethod directTarget = clazz.lookupClassMethod(invokedMethod);
if (directTarget != null) {
// TODO(b/199135051): Replace this by use of the resolution result.
assert directTarget.getDefinition() == singleResolution.getResolutionPair().getDefinition();
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context1,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- // This can be a private instance method call. Note that the referenced
- // method is expected to be in the current class since it is private, but desugaring
- // may move some methods or their code into other classes.
- DexClassAndMethod companionMethodDefinition;
- DexMethod companionMethod;
- if (directTarget.getDefinition().isPrivateMethod()) {
- if (directTarget.isProgramMethod()) {
- companionMethodDefinition =
- helper.ensurePrivateAsMethodOfProgramCompanionClassStub(
- directTarget.asProgramMethod(), eventConsumer);
- companionMethod = companionMethodDefinition.getReference();
- } else {
- // TODO(b/200938617): Why does this not create a stub on the class path?
- companionMethod = helper.privateAsMethodOfCompanionClass(directTarget);
- }
- } else {
- companionMethodDefinition =
- helper.ensureDefaultAsMethodOfCompanionClassStub(directTarget, eventConsumer);
- companionMethod = companionMethodDefinition.getReference();
- }
- return getInvokeStaticInstructions(companionMethod);
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ // This can be a private instance method call. Note that the referenced
+ // method is expected to be in the current class since it is private, but desugaring
+ // may move some methods or their code into other classes.
+ DexClassAndMethod companionMethodDefinition;
+ if (directTarget.getDefinition().isPrivateMethod()) {
+ if (directTarget.isProgramMethod()) {
+ companionMethodDefinition =
+ helper.ensurePrivateAsMethodOfProgramCompanionClassStub(
+ directTarget.asProgramMethod(), eventConsumer);
+ return companionMethodDefinition.getReference();
+ } else {
+ // TODO(b/200938617): Why does this not create a stub on the class path?
+ return helper.privateAsMethodOfCompanionClass(directTarget);
+ }
+ } else {
+ companionMethodDefinition =
+ helper.ensureDefaultAsMethodOfCompanionClassStub(directTarget, eventConsumer);
+ return companionMethodDefinition.getReference();
+ }
+ }
+ };
} else {
// The method can be a default method in the interface hierarchy.
DexClassAndMethod virtualTarget =
@@ -629,42 +608,36 @@
// TODO(b/199135051): Replace this by use of the resolution result.
assert virtualTarget.getDefinition()
== singleResolution.getResolutionPair().getDefinition();
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context12,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- // This is a invoke-direct call to a virtual method.
- DexClassAndMethod companionMethod =
- helper.ensureDefaultAsMethodOfCompanionClassStub(
- virtualTarget, eventConsumer);
- return getInvokeStaticInstructions(companionMethod.getReference());
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ // This is a invoke-direct call to a virtual method.
+ return helper
+ .ensureDefaultAsMethodOfCompanionClassStub(virtualTarget, eventConsumer)
+ .getReference();
+ }
+ };
} else {
// The below assert is here because a well-type program should have a target, but we
// cannot throw a compilation error, since we have no knowledge about the input.
assert false;
}
}
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
- private DesugarDescription computeInvokeAsThrowRewrite(
+ private RetargetMethodSupplier computeInvokeAsThrowRewrite(
DexMethod invokedMethod, InvokeType invokeType, SingleResolutionResult<?> resolution) {
- return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowRewrite(
- appView, invokedMethod, invokeType, resolution);
- }
+ return new ThrowingRetargetMethodSupplier() {
- private Collection<CfInstruction> getInvokeStaticInstructions(DexMethod newTarget) {
- return Collections.singletonList(
- new CfInvoke(org.objectweb.asm.Opcodes.INVOKESTATIC, newTarget, false));
+ @Override
+ public DesugarDescription toDesugarDescription(ProgramMethod context) {
+ return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowRewrite(
+ appView, invokedMethod, invokeType, resolution);
+ }
+ };
}
private void leavingStaticInvokeToInterface(ProgramMethod method) {
@@ -712,7 +685,7 @@
}
@SuppressWarnings("ReferenceEquality")
- private DesugarDescription rewriteInvokeSuper(
+ private RetargetMethodSupplier rewriteInvokeSuper(
DexClass holder,
DexMethod invokedMethod,
InvokeType invokeType,
@@ -740,98 +713,86 @@
// TODO(b/145775365): This should throw IAE.
return computeInvokeAsThrowRewrite(invokedMethod, invokeType, null);
}
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context1,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- DexClassAndMethod method = resolutionResult.getResolutionPair();
- DexMethod companionMethod;
- if (method.isProgramMethod()) {
- ProgramMethod companionMethodDefinition =
- helper.ensurePrivateAsMethodOfProgramCompanionClassStub(
- method.asProgramMethod(), eventConsumer);
- companionMethod = companionMethodDefinition.getReference();
- } else {
- companionMethod = helper.privateAsMethodOfCompanionClass(method);
- }
- return getInvokeStaticInstructions(companionMethod);
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ DexClassAndMethod method = resolutionResult.getResolutionPair();
+ if (method.isProgramMethod()) {
+ ProgramMethod companionMethodDefinition =
+ helper.ensurePrivateAsMethodOfProgramCompanionClassStub(
+ method.asProgramMethod(), eventConsumer);
+ return companionMethodDefinition.getReference();
+ } else {
+ return helper.privateAsMethodOfCompanionClass(method);
+ }
+ }
+ };
} else {
DexClassAndMethod method = resolutionResult.getResolutionPair();
if (method.getAccessFlags().isAbstract()) {
return computeInvokeAsThrowRewrite(invokedMethod, invokeType, resolutionResult);
}
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context12,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- // TODO(b/199135051): Why do this amend routine. We have done resolution, so would
- // that not be the correct target!? I think this is just legacy from before
- // resolution was implemented in full.
- DexMethod amendedMethod =
- amendDefaultMethod(context12.getHolder(), invokedMethod);
- assert method.getReference() == amendedMethod;
- DexClassAndMethod companionMethod =
- helper.ensureDefaultAsMethodOfCompanionClassStub(method, eventConsumer);
- return getInvokeStaticInstructions(companionMethod.getReference());
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ // TODO(b/199135051): Why do this amend routine. We have done resolution, so would
+ // that not be the correct target!? I think this is just legacy from before
+ // resolution was implemented in full.
+ DexMethod amendedMethod = amendDefaultMethod(context.getHolder(), invokedMethod);
+ assert method.getReference() == amendedMethod;
+ DexClassAndMethod companionMethod =
+ helper.ensureDefaultAsMethodOfCompanionClassStub(method, eventConsumer);
+ return companionMethod.getReference();
+ }
+ };
}
}
- DesugarDescription emulatedInterfaceDesugaring =
+ RetargetMethodSupplier emulatedInterfaceDesugaring =
computeEmulatedInterfaceInvokeSpecial(holder, invokedMethod, context);
- if (!emulatedInterfaceDesugaring.needsDesugaring()) {
+ if (emulatedInterfaceDesugaring == RetargetMethodSupplier.none()) {
if (context.isDefaultMethod()) {
- return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowNSMERewrite(
- appView,
- invokedMethod,
- invokeType,
- () ->
- appView
- .reporter()
- .warning(
- new StringDiagnostic(
- "Interface method desugaring has inserted NoSuchMethodError replacing a"
- + " super call in "
- + context.toSourceString(),
- context.getOrigin())));
+ return new ThrowingRetargetMethodSupplier() {
+ @Override
+ public DesugarDescription toDesugarDescription(ProgramMethod context) {
+ return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowNSMERewrite(
+ appView,
+ invokedMethod,
+ invokeType,
+ () ->
+ appView
+ .reporter()
+ .warning(
+ new StringDiagnostic(
+ "Interface method desugaring has inserted NoSuchMethodError"
+ + " replacing a super call in "
+ + context.toSourceString(),
+ context.getOrigin())));
+ }
+ };
} else {
- return DesugarDescription.builder()
- .addScanEffect(() -> leavingSuperInvokeToInterface(context))
- .build();
+ return new WarningRetargetMethodSupplier(() -> leavingSuperInvokeToInterface(context));
}
}
return emulatedInterfaceDesugaring;
}
- private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
+ private RetargetMethodSupplier computeEmulatedInterfaceInvokeSpecial(
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
assert desugaringMode != LIBRARY_DESUGARING_N_PLUS;
if (clazz == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
DexClassAndMethod superTarget =
appInfo.lookupSuperTarget(invokedMethod, context, appView, appInfo);
if (superTarget == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
if (clazz.isInterface()
&& clazz.isLibraryClass()
@@ -839,31 +800,25 @@
&& !helper.isEmulatedInterface(clazz.type)
&& superTarget.isDefaultMethod()
&& superTarget.isLibraryMethod()) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context13,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) -> {
- DexClassAndMethod companionTarget =
- helper.ensureDefaultAsMethodOfCompanionClassStub(superTarget, eventConsumer);
- return getInvokeStaticInstructions(companionTarget.getReference());
- })
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ return helper
+ .ensureDefaultAsMethodOfCompanionClassStub(superTarget, eventConsumer)
+ .getReference();
+ }
+ };
} else {
return computeInvokeSpecialEmulatedInterfaceForwardingMethod(clazz, superTarget);
}
}
- private DesugarDescription computeInvokeSpecialEmulatedInterfaceForwardingMethod(
+ private RetargetMethodSupplier computeInvokeSpecialEmulatedInterfaceForwardingMethod(
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
if (clazz == null) {
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
DexClassAndMethod superTarget =
@@ -871,7 +826,7 @@
return computeInvokeSpecialEmulatedInterfaceForwardingMethod(clazz, superTarget);
}
- private DesugarDescription computeInvokeSpecialEmulatedInterfaceForwardingMethod(
+ private RetargetMethodSupplier computeInvokeSpecialEmulatedInterfaceForwardingMethod(
DexClass clazz, DexClassAndMethod superTarget) {
// That invoke super may not resolve since the super method may not be present since it's in the
// emulated interface. We need to force resolution. If it resolves to a library method, then it
@@ -879,23 +834,16 @@
DerivedMethod forwardingMethod =
helper.computeEmulatedInterfaceForwardingMethod(clazz, superTarget);
if (forwardingMethod != null) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (position,
- freshLocalProvider,
- localStackAllocator,
- desugaringInfo,
- eventConsumer,
- context14,
- methodProcessingContext,
- desugaringCollection,
- dexItemFactory) ->
- getInvokeStaticInstructions(
- helper.ensureEmulatedInterfaceForwardingMethod(
- forwardingMethod, eventConsumer)))
- .build();
+ return new StaticRetargetMethodSupplier() {
+ @Override
+ public DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext) {
+ return helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod, eventConsumer);
+ }
+ };
}
- return DesugarDescription.nothing();
+ return RetargetMethodSupplier.none();
}
private boolean shouldRewriteToInvokeToThrow(
@@ -1028,4 +976,57 @@
MethodPosition position = new MethodPosition(method);
options.warningMissingTypeForDesugar(origin, position, missing, method);
}
+
+ private interface RetargetMethodSupplier {
+
+ static RetargetMethodSupplier none() {
+ return null;
+ }
+
+ DesugarDescription toDesugarDescription(ProgramMethod context);
+ }
+
+ private abstract static class StaticRetargetMethodSupplier implements RetargetMethodSupplier {
+
+ public abstract DexMethod getRetargetMethod(
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ MethodProcessingContext methodProcessingContext);
+
+ @Override
+ public final DesugarDescription toDesugarDescription(ProgramMethod context) {
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (position,
+ freshLocalProvider,
+ localStackAllocator,
+ desugaringInfo,
+ eventConsumer,
+ context1,
+ methodProcessingContext,
+ desugaringCollection,
+ dexItemFactory) -> {
+ DexMethod retargetMethod =
+ getRetargetMethod(eventConsumer, methodProcessingContext);
+ return Collections.singletonList(
+ new CfInvoke(org.objectweb.asm.Opcodes.INVOKESTATIC, retargetMethod, false));
+ })
+ .build();
+ }
+ }
+
+ private abstract static class ThrowingRetargetMethodSupplier implements RetargetMethodSupplier {}
+
+ private static class WarningRetargetMethodSupplier implements RetargetMethodSupplier {
+
+ private final ScanCallback generator;
+
+ WarningRetargetMethodSupplier(ScanCallback generator) {
+ this.generator = generator;
+ }
+
+ @Override
+ public DesugarDescription toDesugarDescription(ProgramMethod context) {
+ return DesugarDescription.builder().addScanEffect(generator).build();
+ }
+ }
}