Generate wrappers on demand in D8
Bug: 189912077
Change-Id: I4e689f0b5ca568e40286321b7c6d8f9323f2c7b1
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index c89d93c..5fc1537 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -407,11 +407,11 @@
}
DexType returnType = invokedMethod.proto.returnType;
if (appView.rewritePrefix.hasRewrittenType(returnType, appView) && canConvert(returnType)) {
- registerConversionWrappers(returnType, vivifiedTypeFor(returnType, appView));
+ registerConversionWrappers(returnType);
}
for (DexType argType : invokedMethod.proto.parameters.values) {
if (appView.rewritePrefix.hasRewrittenType(argType, appView) && canConvert(argType)) {
- registerConversionWrappers(argType, argType);
+ registerConversionWrappers(argType);
}
}
}
@@ -547,7 +547,7 @@
private Instruction createParameterConversion(
IRCode code, DexType argType, DexType argVivifiedType, Value inValue) {
- DexMethod conversionMethod = createConversionMethod(argType, argType, argVivifiedType);
+ DexMethod conversionMethod = ensureConversionMethod(argType, argType, argVivifiedType);
// The value is null only if the input is null.
Value convertedValue =
createConversionValue(code, inValue.getType().nullability(), argVivifiedType, null);
@@ -556,7 +556,7 @@
private Instruction createReturnConversionAndReplaceUses(
IRCode code, InvokeMethod invokeMethod, DexType returnType, DexType returnVivifiedType) {
- DexMethod conversionMethod = createConversionMethod(returnType, returnVivifiedType, returnType);
+ DexMethod conversionMethod = ensureConversionMethod(returnType, returnVivifiedType, returnType);
Value outValue = invokeMethod.outValue();
Value convertedValue =
createConversionValue(code, Nullability.maybeNull(), returnType, outValue.getLocalInfo());
@@ -567,17 +567,13 @@
return new InvokeStatic(conversionMethod, convertedValue, Collections.singletonList(outValue));
}
- private void registerConversionWrappers(DexType type, DexType srcType) {
+ private void registerConversionWrappers(DexType type) {
if (appView.options().desugaredLibraryConfiguration.getCustomConversions().get(type) == null) {
- if (type == srcType) {
- wrapperSynthesizor.getTypeWrapper(type);
- } else {
- wrapperSynthesizor.getVivifiedTypeWrapper(type);
- }
+ wrapperSynthesizor.registerWrapper(type);
}
}
- public DexMethod createConversionMethod(DexType type, DexType srcType, DexType destType) {
+ public DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
// ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
// But everything is going to be rewritten, so we need to use vivifiedType and type".
DexType conversionHolder =
@@ -585,8 +581,8 @@
if (conversionHolder == null) {
conversionHolder =
type == srcType
- ? wrapperSynthesizor.getTypeWrapper(type)
- : wrapperSynthesizor.getVivifiedTypeWrapper(type);
+ ? wrapperSynthesizor.ensureTypeWrapper(type)
+ : wrapperSynthesizor.ensureVivifiedTypeWrapper(type);
}
assert conversionHolder != null;
return factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index c13bfc1..00c8bff 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -117,26 +117,17 @@
return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type);
}
- DexType getTypeWrapper(DexType type) {
- return registerWrapper(type, SyntheticKind.WRAPPER);
+ DexType ensureTypeWrapper(DexType type) {
+ return ensureWrappers(type).getWrapper().type;
}
- DexType getVivifiedTypeWrapper(DexType type) {
- return registerWrapper(type, SyntheticKind.VIVIFIED_WRAPPER);
+ DexType ensureVivifiedTypeWrapper(DexType type) {
+ return ensureWrappers(type).getVivifiedWrapper().type;
}
- private DexType registerWrapper(DexType type, SyntheticKind kind) {
- assert canGenerateWrapper(type) : type;
+ public void registerWrapper(DexType type) {
wrappersToGenerate.add(type);
- DexClass dexClass = getValidClassToWrap(type);
- assert dexClass != null;
- DexType wrapperType =
- appView.getSyntheticItems().getFixedSyntheticTypeWhileMigrating(kind, dexClass, appView);
- assert converter.canGenerateWrappersAndCallbacks()
- || (appView.definitionFor(wrapperType) != null
- && appView.definitionFor(wrapperType).isClasspathClass())
- : "Wrapper " + wrapperType + " should have been generated in the enqueuer.";
- return wrapperType;
+ assert getValidClassToWrap(type) != null;
}
private DexClass getValidClassToWrap(DexType type) {
@@ -152,12 +143,36 @@
return DesugaredLibraryAPIConverter.vivifiedTypeFor(type, appView);
}
- private void ensureWrappers(DexClass context, Consumer<DexClasspathClass> creationCallback) {
+ static class Wrappers {
+ private final DexClass wrapper;
+ private final DexClass vivifiedWrapper;
+
+ Wrappers(DexClass wrapper, DexClass vivifiedWrapper) {
+ this.wrapper = wrapper;
+ this.vivifiedWrapper = vivifiedWrapper;
+ }
+
+ public DexClass getWrapper() {
+ return wrapper;
+ }
+
+ public DexClass getVivifiedWrapper() {
+ return vivifiedWrapper;
+ }
+ }
+
+ private Wrappers ensureWrappers(DexType type) {
+ assert canGenerateWrapper(type) : type;
+ DexClass dexClass = getValidClassToWrap(type);
+ return ensureWrappers(dexClass, ignored -> {});
+ }
+
+ private Wrappers ensureWrappers(DexClass context, Consumer<DexClasspathClass> creationCallback) {
DexType type = context.type;
DexClass wrapper;
DexClass vivifiedWrapper;
- if (appView.options().isDesugaredLibraryCompilation()) {
- assert context.isProgramClass();
+ if (context.isProgramClass()) {
+ assert appView.options().isDesugaredLibraryCompilation();
DexProgramClass programContext = context.asProgramClass();
wrapper =
ensureProgramWrapper(
@@ -210,11 +225,16 @@
vivifiedWrapperField,
wrapperField);
}
+ return new Wrappers(wrapper, vivifiedWrapper);
+ }
+
+ private DexEncodedField getWrapperUniqueEncodedField(DexClass wrapper) {
+ assert wrapper.instanceFields().size() == 1;
+ return wrapper.instanceFields().get(0);
}
private DexField getWrapperUniqueField(DexClass wrapper) {
- assert wrapper.instanceFields().size() == 1;
- return wrapper.instanceFields().get(0).getReference();
+ return getWrapperUniqueEncodedField(wrapper).getReference();
}
private DexProgramClass ensureProgramWrapper(
@@ -229,10 +249,12 @@
kind,
programContext,
appView,
- builder ->
- buildWrapper(
- wrappingType, wrappedType, programContext, virtualMethodProvider, builder),
- ignored -> {});
+ builder -> buildWrapper(wrappingType, wrappedType, programContext, builder),
+ // The creation of virtual methods may require new wrappers, this needs to happen
+ // once the wrapper is created to avoid infinite recursion.
+ wrapper ->
+ wrapper.setVirtualMethods(
+ virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper))));
}
private DexClasspathClass ensureClasspathWrapper(
@@ -250,12 +272,14 @@
appView,
builder ->
buildWrapper(
- wrappingType,
- wrappedType,
- classpathOrLibraryContext.asDexClass(),
- virtualMethodProvider,
- builder),
- creationCallback);
+ wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder),
+ // The creation of virtual methods may require new wrappers, this needs to happen
+ // once the wrapper is created to avoid infinite recursion.
+ wrapper -> {
+ wrapper.setVirtualMethods(
+ virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
+ creationCallback.accept(wrapper);
+ });
}
private ProgramMethod ensureProgramConversionMethod(
@@ -329,7 +353,6 @@
DexType wrappingType,
DexType wrappedType,
DexClass clazz,
- Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider,
SyntheticClassBuilder<?, ?> builder) {
boolean isItf = clazz.isInterface();
DexType superType = isItf ? factory.objectType : wrappingType;
@@ -341,8 +364,7 @@
.setInterfaces(interfaces)
.setSuperType(superType)
.setInstanceFields(Collections.singletonList(wrapperField))
- .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder))
- .setVirtualMethods(Arrays.asList(virtualMethodProvider.apply(wrapperField)));
+ .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder));
}
private void buildWrapperConstructor(
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 04fa965..254511e 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -98,7 +98,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- converter.createConversionMethod(param, param, vivifiedTypeFor(param)),
+ converter.ensureConversionMethod(param, param, vivifiedTypeFor(param)),
false));
newParameters[index - 1] = vivifiedTypeFor(param);
}
@@ -129,7 +129,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- converter.createConversionMethod(
+ converter.ensureConversionMethod(
returnType, vivifiedTypeFor(returnType), returnType),
false));
}
@@ -185,7 +185,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- converter.createConversionMethod(param, vivifiedTypeFor(param), param),
+ converter.ensureConversionMethod(param, vivifiedTypeFor(param), param),
false));
}
if (param == factory.longType || param == factory.doubleType) {
@@ -205,7 +205,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- converter.createConversionMethod(
+ converter.ensureConversionMethod(
returnType, returnType, vivifiedTypeFor(returnType)),
false));
returnType = vivifiedTypeFor(returnType);
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 3e68dae..f7e235f 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -564,15 +564,6 @@
}
}
- public DexType getFixedSyntheticTypeWhileMigrating(
- SyntheticKind kind, DexClass context, AppView<?> appView) {
- SynthesizingContext outerContext =
- context.isProgramClass()
- ? getSynthesizingContext(context.asProgramClass(), appView)
- : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass());
- return SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
- }
-
public ProgramMethod ensureFixedClassMethod(
DexString name,
DexProto proto,
@@ -627,8 +618,8 @@
new SyntheticClasspathClassBuilder(type, kind, outerContext, appView.dexItemFactory());
classConsumer.accept(classBuilder);
DexClasspathClass clazz = classBuilder.build();
- onCreationConsumer.accept(clazz);
addPendingDefinition(new SyntheticClasspathClassDefinition(kind, outerContext, clazz));
+ onCreationConsumer.accept(clazz);
return clazz;
}
}