Disallow vertical class merging of invoke-special to default interface method
Change-Id: Ifc07308c7b739fa1500db698ef054aeea668657c
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 6e55f3c..8d38af0 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -442,6 +442,22 @@
}
return false;
}
+
+ // If there is an invoke-special to a default interface method and we are not merging into an
+ // interface, then abort, since invoke-special to a virtual class method requires desugaring.
+ if (sourceClass.isInterface() && !targetClass.isInterface()) {
+ TraversalContinuation result =
+ sourceClass.traverseProgramMethods(
+ method -> {
+ boolean foundInvokeSpecialToDefaultLibraryMethod =
+ method.registerCodeReferencesWithResult(
+ new InvokeSpecialToDefaultLibraryMethodUseRegistry(appView, method));
+ return TraversalContinuation.breakIf(foundInvokeSpecialToDefaultLibraryMethod);
+ });
+ if (result.shouldBreak()) {
+ return false;
+ }
+ }
return true;
}
@@ -2113,6 +2129,62 @@
}
}
+ public static class InvokeSpecialToDefaultLibraryMethodUseRegistry
+ extends UseRegistryWithResult<Boolean, ProgramMethod> {
+
+ InvokeSpecialToDefaultLibraryMethodUseRegistry(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ super(appView, context, false);
+ assert context.getHolder().isInterface();
+ }
+
+ @Override
+ public void registerInvokeSpecial(DexMethod method) {
+ ProgramMethod context = getContext();
+ if (method.getHolderType() != context.getHolderType()) {
+ return;
+ }
+
+ DexEncodedMethod definition = context.getHolder().lookupMethod(method);
+ if (definition != null && definition.belongsToVirtualPool()) {
+ setResult(true);
+ }
+ }
+
+ @Override
+ public void registerInitClass(DexType type) {}
+
+ @Override
+ public void registerInvokeDirect(DexMethod method) {}
+
+ @Override
+ public void registerInvokeInterface(DexMethod method) {}
+
+ @Override
+ public void registerInvokeStatic(DexMethod method) {}
+
+ @Override
+ public void registerInvokeSuper(DexMethod method) {}
+
+ @Override
+ public void registerInvokeVirtual(DexMethod method) {}
+
+ @Override
+ public void registerInstanceFieldRead(DexField field) {}
+
+ @Override
+ public void registerInstanceFieldWrite(DexField field) {}
+
+ @Override
+ public void registerStaticFieldRead(DexField field) {}
+
+ @Override
+ public void registerStaticFieldWrite(DexField field) {}
+
+ @Override
+ public void registerTypeReference(DexType type) {}
+ }
+
protected static class SynthesizedBridgeCode extends AbstractSynthesizedCode {
private DexMethod method;
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
index 2d8efe3..0e9d873 100644
--- a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
+++ b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
@@ -9,6 +9,10 @@
CONTINUE,
BREAK;
+ public static TraversalContinuation breakIf(boolean condition) {
+ return continueIf(!condition);
+ }
+
public static TraversalContinuation continueIf(boolean condition) {
return condition ? CONTINUE : BREAK;
}