Version 2.1.37 Cherry pick: Revised "Rewrite invoke-super targeting rewritten desugared library methods." CL: https://r8-review.googlesource.com/c/r8/+/52004 Bug: 157806261 In addition this reverts the fix from 2.1.36. Cherry pick: Revert "Rewrite invoke-super targeting rewritten desugared library methods." CL: https://r8-review.googlesource.com/c/r8/+/52003 Change-Id: I4d2cdbdc4724a027ba553c2c2f68944f3562feb1
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java index 3daa05c..f4cd7bf 100644 --- a/src/main/java/com/android/tools/r8/Version.java +++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@ // This field is accessed from release scripts using simple pattern matching. // Therefore, changing this field could break our release scripts. - public static final String LABEL = "2.1.36"; + public static final String LABEL = "2.1.37"; private Version() { }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java index 4e6d0ab..98078c5 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -284,52 +284,82 @@ if (instruction.isInvokeSuper()) { InvokeSuper invokeSuper = instruction.asInvokeSuper(); DexMethod invokedMethod = invokeSuper.getInvokedMethod(); - DexClass clazz = appInfo.definitionForHolder(invokedMethod); + DexClass clazz = appInfo.definitionFor(invokedMethod.holder); if (clazz == null) { // NOTE: leave unchanged those calls to undefined targets. This may lead to runtime // exception but we can not report it as error since it can also be the intended // behavior. warnMissingType(encodedMethod.method, invokedMethod.holder); - continue; - } - if (!clazz.isInterface()) { - // Skip non-interface invokes. - continue; - } - if (!clazz.isLibraryClass()) { - // For program and classpath retarget call to an appropriate method of companion class. + } else if (clazz.isInterface() && !clazz.isLibraryClass()) { + // NOTE: we intentionally don't desugar super calls into interface methods + // coming from android.jar since it is only possible in case v24+ version + // of android.jar is provided. + // + // We assume such calls are properly guarded by if-checks like + // 'if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.XYZ) { ... }' + // + // WARNING: This may result in incorrect code on older platforms! + // Retarget call to an appropriate method of companion class. DexMethod amendedMethod = amendDefaultMethod(appInfo.definitionFor(encodedMethod.holder()), invokedMethod); instructions.replaceCurrentInstruction( new InvokeStatic(defaultAsMethodOfCompanionClass(amendedMethod), invokeSuper.outValue(), invokeSuper.arguments())); } else { - // Rewriting is required if the super invoke resolves to a default method on the - // desugared library. Retarget or rewrite to the desugared library companion class. - DexEncodedMethod dexEncodedMethod = - targetForInvokeSuperDispatchToDefaultMethod( - invokedMethod, clazz.asLibraryClass(), code.context()); - if (dexEncodedMethod != null) { - DexMethod retargetMethod = - options.desugaredLibraryConfiguration.retargetMethod( - dexEncodedMethod.method, appView); - if (retargetMethod == null) { - DexMethod originalCompanionMethod = - instanceAsMethodOfCompanionClass( - dexEncodedMethod.method, DEFAULT_METHOD_PREFIX, factory); - DexMethod companionMethod = - factory.createMethod( - getCompanionClassType(clazz.type), - factory.protoWithDifferentFirstParameter( - originalCompanionMethod.proto, clazz.type), - originalCompanionMethod.name); - instructions.replaceCurrentInstruction( - new InvokeStatic( - companionMethod, invokeSuper.outValue(), invokeSuper.arguments())); - } else { - instructions.replaceCurrentInstruction( - new InvokeStatic( - retargetMethod, invokeSuper.outValue(), invokeSuper.arguments())); + DexType dexType = maximallySpecificEmulatedInterfaceOrNull(invokedMethod); + if (dexType == null) { + if (clazz.isInterface() + && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) { + DexEncodedMethod target = + appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, code.context()); + if (target != null && target.isDefaultMethod()) { + DexClass holder = appView.definitionFor(target.holder()); + if (holder.isLibraryClass() && holder.isInterface()) { + instructions.replaceCurrentInstruction( + new InvokeStatic( + defaultAsMethodOfCompanionClass(target.method, factory), + invokeSuper.outValue(), + invokeSuper.arguments())); + } + } + } + } else { + // 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 needs to be rewritten. + // If it resolves to a program overrides, the invoke-super can remain. + DexEncodedMethod dexEncodedMethod = + appView + .appInfoForDesugaring() + .lookupSuperTarget(invokeSuper.getInvokedMethod(), code.context()); + if (dexEncodedMethod != null) { + DexClass dexClass = appView.definitionFor(dexEncodedMethod.holder()); + if (dexClass != null && dexClass.isLibraryClass()) { + // Rewriting is required because the super invoke resolves into a missing + // method (method is on desugared library). Find out if it needs to be + // retarget or if it just calls a companion class method and rewrite. + DexMethod retargetMethod = + options.desugaredLibraryConfiguration.retargetMethod( + dexEncodedMethod.method, appView); + if (retargetMethod == null) { + DexMethod originalCompanionMethod = + instanceAsMethodOfCompanionClass( + dexEncodedMethod.method, DEFAULT_METHOD_PREFIX, factory); + DexMethod companionMethod = + factory.createMethod( + getCompanionClassType(dexType), + factory.protoWithDifferentFirstParameter( + originalCompanionMethod.proto, dexType), + originalCompanionMethod.name); + instructions.replaceCurrentInstruction( + new InvokeStatic( + companionMethod, invokeSuper.outValue(), invokeSuper.arguments())); + } else { + instructions.replaceCurrentInstruction( + new InvokeStatic( + retargetMethod, invokeSuper.outValue(), invokeSuper.arguments())); + } + } } } } @@ -404,28 +434,6 @@ } } - private DexEncodedMethod targetForInvokeSuperDispatchToDefaultMethod( - DexMethod invokedSuperMethod, DexLibraryClass holder, ProgramMethod context) { - assert invokedSuperMethod.holder == holder.type; - assert holder.isInterface(); - DexEncodedMethod definition = holder.lookupMethod(invokedSuperMethod); - if (definition == null || !definition.isDefaultMethod()) { - return null; - } - // Only default methods on emulated interfaces or rewritten types need to be dealt with. - if (!emulatedMethods.contains(invokedSuperMethod.name) - && !appView.rewritePrefix.hasRewrittenType(holder.type, appView)) { - return null; - } - DexEncodedMethod target = - appView.appInfoForDesugaring().lookupSuperTarget(invokedSuperMethod, context); - DexClass targetHolder = appView.definitionForHolder(target); - if (targetHolder == null || !targetHolder.isLibraryClass()) { - return null; - } - return target; - } - private DexType maximallySpecificEmulatedInterfaceOrNull(DexMethod invokedMethod) { // Here we try to avoid doing the expensive look-up on all invokes. if (!emulatedMethods.contains(invokedMethod.name)) {