Support generating array conversion during wrapper generation
- Extend the UniqueContext design to support
creating Unique context outside the main
parallel processing loop on methods
Bug:222647019
Change-Id: Ibcdbbe5b50595f57b579456743afc6d5c2afd9f6
diff --git a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
index a34811c..b936f91 100644
--- a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
+++ b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.structural.HasherWrapper;
import java.util.Map;
@@ -96,6 +97,20 @@
return methodProcessingContext;
}
+ public MainThreadContext createMainThreadContext() {
+ MainThreadContext singleThreadContext = new MainThreadContext(this, parent.mainThread);
+ assert verifyContext(singleThreadContext);
+ return singleThreadContext;
+ }
+
+ public ClassSynthesisDesugaringContext createClassSynthesisDesugaringContext(
+ CfClassSynthesizerDesugaring desugaring) {
+ ClassSynthesisDesugaringContext classSynthesisDesugaringContext =
+ new ClassSynthesisDesugaringContext(this, desugaring);
+ assert verifyContext(classSynthesisDesugaringContext);
+ return classSynthesisDesugaringContext;
+ }
+
private StringBuilder buildSuffix(StringBuilder builder) {
return builder.append('$').append(processorId);
}
@@ -111,14 +126,91 @@
}
}
- /** Description of the method context from which to synthesize. */
- public static class MethodProcessingContext extends ContextDescriptorProvider {
+ /** The processor context is responsible in creating a task context per thread. */
+ public abstract static class ThreadTaskContext extends ContextDescriptorProvider {
private final ProcessorContext parent;
- private final ProgramMethod method;
private int nextId = 0;
- private MethodProcessingContext(ProcessorContext parent, ProgramMethod method) {
+ private ThreadTaskContext(ProcessorContext parent) {
this.parent = parent;
+ }
+
+ public ProcessorContext getParent() {
+ return parent;
+ }
+
+ int incrementAndGetNextId() {
+ return nextId++;
+ }
+ }
+
+ /**
+ * If no threading is used, the MainThreadContext allows one to generate UniqueContext instances
+ * without a thread specific identifier.
+ */
+ public static class MainThreadContext extends ThreadTaskContext {
+
+ private static final String IDENTIFIER = "main";
+
+ private final Thread mainThread;
+
+ private MainThreadContext(ProcessorContext parent, Thread mainThread) {
+ super(parent);
+ this.mainThread = mainThread;
+ }
+
+ @Override
+ StringBuilder buildContextDescriptorForTesting(StringBuilder builder) {
+ return getParent().buildContextDescriptorForTesting(builder).append(IDENTIFIER);
+ }
+
+ @Override
+ StringBuilder buildSyntheticSuffix(StringBuilder builder) {
+ return getParent().buildSyntheticSuffix(builder).append(IDENTIFIER);
+ }
+
+ public UniqueContext createUniqueContext(DexProgramClass context) {
+ assert mainThread == Thread.currentThread() : "Invoked on another thread than main";
+ UniqueContext uniqueContext = new UniqueContext(this, context, incrementAndGetNextId());
+ assert getParent().verifyContext(uniqueContext);
+ return uniqueContext;
+ }
+ }
+
+ public static class ClassSynthesisDesugaringContext extends ThreadTaskContext {
+ private final CfClassSynthesizerDesugaring desugaring;
+
+ private ClassSynthesisDesugaringContext(
+ ProcessorContext parent, CfClassSynthesizerDesugaring desugaring) {
+ super(parent);
+ this.desugaring = desugaring;
+ }
+
+ @Override
+ StringBuilder buildContextDescriptorForTesting(StringBuilder builder) {
+ return getParent()
+ .buildContextDescriptorForTesting(builder)
+ .append(desugaring.uniqueIdentifier());
+ }
+
+ @Override
+ StringBuilder buildSyntheticSuffix(StringBuilder builder) {
+ return getParent().buildSyntheticSuffix(builder).append(desugaring.uniqueIdentifier());
+ }
+
+ public UniqueContext createUniqueContext(DexProgramClass context) {
+ UniqueContext uniqueContext = new UniqueContext(this, context, incrementAndGetNextId());
+ assert getParent().verifyContext(uniqueContext);
+ return uniqueContext;
+ }
+ }
+
+ /** Description of the method context from which to synthesize. */
+ public static class MethodProcessingContext extends ThreadTaskContext {
+ private final ProgramMethod method;
+
+ private MethodProcessingContext(ProcessorContext parent, ProgramMethod method) {
+ super(parent);
this.method = method;
}
@@ -130,12 +222,13 @@
* deterministic order, eg, by the processing of method instructions being single threaded.
*/
public UniqueContext createUniqueContext() {
- UniqueContext uniqueContext = new UniqueContext(this, nextId++);
- assert parent.verifyContext(uniqueContext);
+ UniqueContext uniqueContext =
+ new UniqueContext(this, getClassContext(), incrementAndGetNextId());
+ assert getParent().verifyContext(uniqueContext);
return uniqueContext;
}
- DexProgramClass getClassContext() {
+ private DexProgramClass getClassContext() {
return method.getHolder();
}
@@ -154,21 +247,26 @@
StringBuilder buildContextDescriptorForTesting(StringBuilder builder) {
// Put the type first in the context descriptor.
builder.append(getClassContext().getType().toDescriptorString());
- return buildSuffix(parent.buildContextDescriptorForTesting(builder));
+ return buildSuffix(getParent().buildContextDescriptorForTesting(builder));
}
@Override
StringBuilder buildSyntheticSuffix(StringBuilder builder) {
- return buildSuffix(parent.buildSyntheticSuffix(builder));
+ return buildSuffix(getParent().buildSyntheticSuffix(builder));
}
}
public static class UniqueContext extends ContextDescriptorProvider {
- private final MethodProcessingContext parent;
+ private final ThreadTaskContext parent;
+ // The class context is required to:
+ // - determine in which feature the method should be put (feature split),
+ // - put the synthetic in the correct package.
+ private final DexProgramClass classContext;
private final int positionId;
- private UniqueContext(MethodProcessingContext parent, int positionId) {
+ private UniqueContext(ThreadTaskContext parent, DexProgramClass classContext, int positionId) {
this.parent = parent;
+ this.classContext = classContext;
this.positionId = positionId;
}
@@ -187,7 +285,7 @@
}
public DexProgramClass getClassContext() {
- return parent.getClassContext();
+ return classContext;
}
public String getSyntheticSuffix() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaring.java
index 38fa09a..bfe03a9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaring.java
@@ -4,7 +4,13 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
+
public interface CfClassSynthesizerDesugaring {
- void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer);
+ String uniqueIdentifier();
+
+ void synthesizeClasses(
+ ClassSynthesisDesugaringContext processingContext,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
index 02c87a6..2e95917 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
+import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterL8Synthesizer;
@@ -13,6 +15,7 @@
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
public abstract class CfClassSynthesizerDesugaringCollection {
@@ -38,7 +41,7 @@
if (synthesizers.isEmpty()) {
return new EmptyCfClassSynthesizerCollection();
}
- return new NonEmptyCfClassSynthesizerCollection(synthesizers);
+ return new NonEmptyCfClassSynthesizerCollection(appView, synthesizers);
}
public abstract void synthesizeClasses(
@@ -47,11 +50,13 @@
static class NonEmptyCfClassSynthesizerCollection extends CfClassSynthesizerDesugaringCollection {
+ private final AppView<?> appView;
private final Collection<CfClassSynthesizerDesugaring> synthesizers;
public NonEmptyCfClassSynthesizerCollection(
- Collection<CfClassSynthesizerDesugaring> synthesizers) {
+ AppView<?> appView, Collection<CfClassSynthesizerDesugaring> synthesizers) {
assert !synthesizers.isEmpty();
+ this.appView = appView;
this.synthesizers = synthesizers;
}
@@ -59,9 +64,19 @@
public void synthesizeClasses(
ExecutorService executorService, CfClassSynthesizerDesugaringEventConsumer eventConsumer)
throws ExecutionException {
+ assert synthesizers.stream()
+ .map(CfClassSynthesizerDesugaring::uniqueIdentifier)
+ .collect(Collectors.toSet())
+ .size()
+ == synthesizers.size();
+ ProcessorContext processorContext = appView.createProcessorContext();
ThreadUtils.processItems(
synthesizers,
- synthesizer -> synthesizer.synthesizeClasses(eventConsumer),
+ synthesizer -> {
+ ClassSynthesisDesugaringContext classSynthesisDesugaringContext =
+ processorContext.createClassSynthesisDesugaringContext(synthesizer);
+ synthesizer.synthesizeClasses(classSynthesisDesugaringContext, eventConsumer);
+ },
executorService);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
index 8a9a016..354a323 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.L8ProgramEmulatedInterfaceSynthesizerEventConsumer;
@@ -48,4 +49,9 @@
public Set<DexProgramClass> getSynthesizedClasses() {
return synthesizedClasses;
}
+
+ @Override
+ public void acceptArrayConversion(ProgramMethod arrayConversion) {
+ synthesizedClasses.add(arrayConversion.getHolder());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index 30fe9d8..450cdb5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -8,7 +8,7 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.isAPIConversionSyntheticType;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
-import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.contexts.CompilationContext.MainThreadContext;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -57,8 +57,9 @@
Collection<DexProgramClass> programClasses,
CfPostProcessingDesugaringEventConsumer eventConsumer,
ExecutorService executorService) {
- assert noPendingWrappersOrConversions();
ProcessorContext processorContext = appView.createProcessorContext();
+ MainThreadContext mainThreadContext = processorContext.createMainThreadContext();
+ assert noPendingWrappersOrConversions();
for (DexProgramClass clazz : programClasses) {
if (!appView.isAlreadyLibraryDesugared(clazz)) {
ArrayList<DexEncodedMethod> callbacks = new ArrayList<>();
@@ -74,7 +75,7 @@
virtualProgramMethod.getDefinition(),
virtualProgramMethod.getHolder(),
eventConsumer,
- processorContext.createMethodProcessingContext(virtualProgramMethod));
+ mainThreadContext);
callbacks.add(callback.getDefinition());
}
}
@@ -195,7 +196,7 @@
DexEncodedMethod originalMethod,
DexProgramClass clazz,
DesugaredLibraryAPICallbackSynthesizorEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
+ MainThreadContext context) {
DexMethod methodToInstall =
methodWithVivifiedTypeInSignature(originalMethod.getReference(), clazz.type, appView);
CfCode cfCode =
@@ -205,7 +206,7 @@
wrapperSynthesizor,
clazz.isInterface(),
eventConsumer,
- methodProcessingContext)
+ () -> context.createUniqueContext(clazz))
.generateCfCode();
DexEncodedMethod newMethod = wrapperSynthesizor.newSynthesizedMethod(methodToInstall, cfCode);
newMethod.setCode(cfCode, appView);
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 684f9bc..520b5ea 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
@@ -296,7 +296,11 @@
if (wrapperSynthesizor.shouldConvert(returnType, invokedMethod, context)) {
DexType newReturnType = DesugaredLibraryAPIConverter.vivifiedTypeFor(returnType, appView);
return wrapperSynthesizor.ensureConversionMethod(
- returnType, newReturnType, returnType, eventConsumer, methodProcessingContext);
+ returnType,
+ newReturnType,
+ returnType,
+ eventConsumer,
+ methodProcessingContext::createUniqueContext);
}
return null;
}
@@ -314,7 +318,11 @@
DexType argVivifiedType = vivifiedTypeFor(argType, appView);
parameterConversions[i] =
wrapperSynthesizor.ensureConversionMethod(
- argType, argType, argVivifiedType, eventConsumer, methodProcessingContext);
+ argType,
+ argType,
+ argVivifiedType,
+ eventConsumer,
+ methodProcessingContext::createUniqueContext);
}
}
return parameterConversions;
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 1bd5ba8..e1fbb96 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
@@ -5,7 +5,8 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
import com.android.tools.r8.androidapi.ComputedApiLevel;
-import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
+import com.android.tools.r8.contexts.CompilationContext.UniqueContext;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -49,6 +50,7 @@
import java.util.List;
import java.util.Map;
import java.util.function.Function;
+import java.util.function.Supplier;
// I am responsible for the generation of wrappers used to call library APIs when desugaring
// libraries. Wrappers can be both ways, wrapping the desugarType as a type, or the type as
@@ -133,10 +135,9 @@
DexType srcType,
DexType destType,
DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
+ Supplier<UniqueContext> contextSupplier) {
if (type.isArrayType()) {
- return ensureArrayConversionMethod(
- type, srcType, destType, eventConsumer, methodProcessingContext);
+ return ensureArrayConversionMethod(type, srcType, destType, eventConsumer, contextSupplier);
}
DexMethod customConversion = getCustomConversion(type, srcType, destType);
if (customConversion != null) {
@@ -162,20 +163,47 @@
DexType srcType,
DexType destType,
DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
+ Supplier<UniqueContext> contextSupplier) {
DexMethod conversion =
ensureConversionMethod(
type.toDimensionMinusOneType(factory),
srcType.toDimensionMinusOneType(factory),
destType.toDimensionMinusOneType(factory),
eventConsumer,
- methodProcessingContext);
+ contextSupplier);
+ return ensureArrayConversionMethod(
+ srcType, destType, eventConsumer, contextSupplier, conversion);
+ }
+
+ private DexMethod ensureArrayConversionMethodFromExistingBaseConversion(
+ DexType type,
+ DexType srcType,
+ DexType destType,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
+ DexMethod conversion =
+ getExistingProgramConversionMethod(
+ type.toDimensionMinusOneType(factory),
+ srcType.toDimensionMinusOneType(factory),
+ destType.toDimensionMinusOneType(factory),
+ eventConsumer,
+ contextSupplier);
+ return ensureArrayConversionMethod(
+ srcType, destType, eventConsumer, contextSupplier, conversion);
+ }
+
+ private DexMethod ensureArrayConversionMethod(
+ DexType srcType,
+ DexType destType,
+ DesugaredLibraryWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier,
+ DexMethod conversion) {
ProgramMethod arrayConversion =
appView
.getSyntheticItems()
.createMethod(
SyntheticKind.ARRAY_CONVERSION,
- methodProcessingContext.createUniqueContext(),
+ contextSupplier.get(),
appView,
builder ->
builder
@@ -195,8 +223,15 @@
}
public DexMethod getExistingProgramConversionMethod(
- DexType type, DexType srcType, DexType destType) {
- assert !type.isArrayType();
+ DexType type,
+ DexType srcType,
+ DexType destType,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
+ if (type.isArrayType()) {
+ return ensureArrayConversionMethodFromExistingBaseConversion(
+ type, srcType, destType, eventConsumer, contextSupplier);
+ }
DexMethod customConversion = getCustomConversion(type, srcType, destType);
if (customConversion != null) {
return customConversion;
@@ -321,7 +356,11 @@
type,
classpathOrLibraryContext,
eventConsumer,
- wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, methods, wrapperField));
+ wrapperField ->
+ synthesizeVirtualMethodsForTypeWrapper(
+ methods,
+ wrapperField,
+ DesugaredLibraryWrapperSynthesizer::codeForClasspathMethod));
DexClass vivifiedWrapper =
ensureClasspathWrapper(
SyntheticKind.VIVIFIED_WRAPPER,
@@ -330,7 +369,10 @@
classpathOrLibraryContext,
eventConsumer,
wrapperField ->
- synthesizeVirtualMethodsForVivifiedTypeWrapper(context, methods, wrapperField));
+ synthesizeVirtualMethodsForVivifiedTypeWrapper(
+ methods,
+ wrapperField,
+ DesugaredLibraryWrapperSynthesizer::codeForClasspathMethod));
return new WrapperConversions(
getConversion(wrapper, vivifiedType, type),
getConversion(vivifiedWrapper, type, vivifiedType));
@@ -494,82 +536,75 @@
.generateCfCode());
}
+ private static CfCode codeForClasspathMethod(DexMethod ignore) {
+ return null;
+ }
+
private Collection<DexEncodedMethod> synthesizeVirtualMethodsForVivifiedTypeWrapper(
- DexClass dexClass, Iterable<DexMethod> allImplementedMethods, DexEncodedField wrapperField) {
+ Iterable<DexMethod> allImplementedMethods,
+ DexEncodedField wrapperField,
+ Function<DexMethod, CfCode> cfCodeProvider) {
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
- // Each method should use only types in their signature, but each method the wrapper forwards
- // to should used only vivified types.
- // Generated method looks like:
- // long foo (type, int)
- // v0 <- arg0;
- // v1 <- arg1;
- // v2 <- convertTypeToVivifiedType(v0);
- // v3 <- wrappedValue.foo(v2,v1);
- // return v3;
for (DexMethod method : allImplementedMethods) {
- DexClass holderClass = appView.definitionFor(method.getHolderType());
- boolean isInterface;
- if (holderClass == null) {
- assert appView
- .options()
- .machineDesugaredLibrarySpecification
- .isEmulatedInterfaceRewrittenType(method.getHolderType());
- isInterface = true;
- } else {
- isInterface = holderClass.isInterface();
- }
DexMethod methodToInstall =
factory.createMethod(wrapperField.getHolderType(), method.proto, method.name);
- CfCode cfCode;
- if (dexClass.isProgramClass()) {
- cfCode =
- new APIConverterVivifiedWrapperCfCodeProvider(
- appView, methodToInstall, wrapperField.getReference(), this, isInterface)
- .generateCfCode();
- } else {
- cfCode = null;
- }
+ CfCode cfCode = cfCodeProvider.apply(method);
DexEncodedMethod newDexEncodedMethod = newSynthesizedMethod(methodToInstall, cfCode);
generatedMethods.add(newDexEncodedMethod);
}
return generatedMethods;
}
+ private CfCode synthesizeCfCodeForVivifiedTypeWrapper(
+ DexMethod method,
+ DexField wrapperField,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
+ DexClass holderClass = appView.definitionFor(method.getHolderType());
+ boolean isInterface;
+ if (holderClass == null) {
+ assert appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .isEmulatedInterfaceRewrittenType(method.getHolderType());
+ isInterface = true;
+ } else {
+ isInterface = holderClass.isInterface();
+ }
+ return new APIConverterVivifiedWrapperCfCodeProvider(
+ appView, method, wrapperField, this, isInterface, eventConsumer, contextSupplier)
+ .generateCfCode();
+ }
+
private Collection<DexEncodedMethod> synthesizeVirtualMethodsForTypeWrapper(
- DexClass dexClass, Iterable<DexMethod> dexMethods, DexEncodedField wrapperField) {
+ Iterable<DexMethod> dexMethods,
+ DexEncodedField wrapperField,
+ Function<DexMethod, CfCode> cfCodeProvider) {
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
- // Each method should use only vivified types in their signature, but each method the wrapper
- // forwards
- // to should used only types.
- // Generated method looks like:
- // long foo (type, int)
- // v0 <- arg0;
- // v1 <- arg1;
- // v2 <- convertVivifiedTypeToType(v0);
- // v3 <- wrappedValue.foo(v2,v1);
- // return v3;
for (DexMethod method : dexMethods) {
- DexClass holderClass = appView.definitionFor(method.getHolderType());
- assert holderClass != null || appView.options().isDesugaredLibraryCompilation();
- boolean isInterface = holderClass == null || holderClass.isInterface();
DexMethod methodToInstall =
DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature(
method, wrapperField.getHolderType(), appView);
- CfCode cfCode;
- if (dexClass.isProgramClass()) {
- cfCode =
- new APIConverterWrapperCfCodeProvider(
- appView, method, wrapperField.getReference(), this, isInterface)
- .generateCfCode();
- } else {
- cfCode = null;
- }
+ CfCode cfCode = cfCodeProvider.apply(method);
DexEncodedMethod newDexEncodedMethod = newSynthesizedMethod(methodToInstall, cfCode);
generatedMethods.add(newDexEncodedMethod);
}
return generatedMethods;
}
+ private CfCode synthesizeCfCodeForTypeWrapper(
+ DexMethod method,
+ DexField wrapperField,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
+ DexClass holderClass = appView.definitionFor(method.getHolderType());
+ assert holderClass != null || appView.options().isDesugaredLibraryCompilation();
+ boolean isInterface = holderClass == null || holderClass.isInterface();
+ return new APIConverterWrapperCfCodeProvider(
+ appView, method, wrapperField, this, isInterface, eventConsumer, contextSupplier)
+ .generateCfCode();
+ }
+
DexEncodedMethod newSynthesizedMethod(DexMethod methodToInstall, Code code) {
MethodAccessFlags newFlags =
MethodAccessFlags.fromSharedAccessFlags(
@@ -609,12 +644,19 @@
.build();
}
+ @Override
+ public String uniqueIdentifier() {
+ return "$wrapper$";
+ }
+
// Program wrappers are harder to deal with than classpath wrapper because generating a method's
// code may require other wrappers. To keep it simple (This is L8 specific), we generate first
// the wrappers with the conversion methods only, then the virtual methods assuming the
// conversion methods are present.
@Override
- public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+ public void synthesizeClasses(
+ ClassSynthesisDesugaringContext processingContext,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
MachineDesugaredLibrarySpecification librarySpecification =
appView.options().machineDesugaredLibrarySpecification;
Map<DexProgramClass, Iterable<DexMethod>> validClassesToWrap = new IdentityHashMap<>();
@@ -636,7 +678,9 @@
}
}
});
- validClassesToWrap.forEach(this::ensureProgramWrappersVirtualMethods);
+ validClassesToWrap.forEach(
+ (clazz, methods) ->
+ ensureProgramWrappersVirtualMethods(clazz, methods, eventConsumer, processingContext));
}
// We generate first the two wrappers with the constructor method and the fields, then we
@@ -664,16 +708,35 @@
SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapper, wrapper);
}
- private void ensureProgramWrappersVirtualMethods(DexClass context, Iterable<DexMethod> methods) {
- assert context.isProgramClass();
+ private void ensureProgramWrappersVirtualMethods(
+ DexProgramClass context,
+ Iterable<DexMethod> methods,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer,
+ ClassSynthesisDesugaringContext processingContext) {
DexProgramClass wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER);
+ DexEncodedField wrapperField = getWrapperUniqueEncodedField(wrapper);
wrapper.addVirtualMethods(
synthesizeVirtualMethodsForTypeWrapper(
- context, methods, getWrapperUniqueEncodedField(wrapper)));
+ methods,
+ wrapperField,
+ m ->
+ synthesizeCfCodeForTypeWrapper(
+ m,
+ wrapperField.getReference(),
+ eventConsumer,
+ () -> processingContext.createUniqueContext(wrapper))));
DexProgramClass vivifiedWrapper =
getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER);
+ DexEncodedField vivifiedWrapperField = getWrapperUniqueEncodedField(vivifiedWrapper);
vivifiedWrapper.addVirtualMethods(
synthesizeVirtualMethodsForVivifiedTypeWrapper(
- context, methods, getWrapperUniqueEncodedField(vivifiedWrapper)));
+ methods,
+ vivifiedWrapperField,
+ m ->
+ synthesizeCfCodeForVivifiedTypeWrapper(
+ m,
+ vivifiedWrapperField.getReference(),
+ eventConsumer,
+ () -> processingContext.createUniqueContext(vivifiedWrapper))));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
index 562c5ac..cf803cb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
@@ -10,20 +10,22 @@
public interface DesugaredLibraryWrapperSynthesizerEventConsumer {
- interface DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer {
+ void acceptArrayConversion(ProgramMethod arrayConversion);
+
+ interface DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer
+ extends DesugaredLibraryWrapperSynthesizerEventConsumer {
void acceptWrapperProgramClass(DexProgramClass clazz);
void acceptEnumConversionProgramClass(DexProgramClass clazz);
}
- interface DesugaredLibraryClasspathWrapperSynthesizeEventConsumer {
+ interface DesugaredLibraryClasspathWrapperSynthesizeEventConsumer
+ extends DesugaredLibraryWrapperSynthesizerEventConsumer {
void acceptWrapperClasspathClass(DexClasspathClass clazz);
void acceptEnumConversionClasspathClass(DexClasspathClass clazz);
-
- void acceptArrayConversion(ProgramMethod arrayConversion);
}
interface DesugaredLibraryAPIConverterEventConsumer
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index 60086f8..6a32412 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
@@ -33,7 +34,14 @@
}
@Override
- public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+ public String uniqueIdentifier() {
+ return "$retargeter$";
+ }
+
+ @Override
+ public void synthesizeClasses(
+ ClassSynthesisDesugaringContext processingContext,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
appView.options().machineDesugaredLibrarySpecification.getEmulatedVirtualRetarget();
for (EmulatedDispatchMethodDescriptor emulatedDispatchMethod :
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index 7e8a2cc..8d14980 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -3,24 +3,22 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.desugar.itf;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
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.desugar.CfClassSynthesizerDesugaring;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedInterfaceDescriptor;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.L8ProgramEmulatedInterfaceSynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.EmulateDispatchSyntheticCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
import com.android.tools.r8.utils.StringDiagnostic;
import java.util.LinkedHashMap;
@@ -75,17 +73,6 @@
methodBuilder)));
}
- private DexMethod emulatedMethod(DerivedMethod method, DexType holder) {
- assert method.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
- DexProto newProto = appView.dexItemFactory().prependHolderToProto(method.getMethod());
- return appView.dexItemFactory().createMethod(holder, newProto, method.getName());
- }
-
- private DexMethod interfaceMethod(DerivedMethod method) {
- assert method.getHolderKind() == null;
- return method.getMethod();
- }
-
private void synthesizeEmulatedInterfaceMethod(
ProgramMethod method,
EmulatedDispatchMethodDescriptor descriptor,
@@ -127,7 +114,14 @@
}
@Override
- public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+ public String uniqueIdentifier() {
+ return "$emulatedInterface$";
+ }
+
+ @Override
+ public void synthesizeClasses(
+ ClassSynthesisDesugaringContext processingContext,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
assert appView.options().isDesugaredLibraryCompilation();
appView
.options()
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index 9a7c53c..a6fcf97 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.cf.code.CfInvokeDynamic;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfTypeInstruction;
+import com.android.tools.r8.contexts.CompilationContext.ClassSynthesisDesugaringContext;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
@@ -476,7 +477,14 @@
}
@Override
- public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+ public String uniqueIdentifier() {
+ return "$record$";
+ }
+
+ @Override
+ public void synthesizeClasses(
+ ClassSynthesisDesugaringContext processingContext,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
if (appView.appInfo().app().getFlags().hasReadRecordReferenceFromProgramClass()) {
ensureRecordClass(eventConsumer);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
index 1b5b27c..476859a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
@@ -62,7 +62,7 @@
return null;
}
if (isTwrCloseResourceInvoke(instruction)) {
- return rewriteTwrCloseResourceInvoke(eventConsumer, context, methodProcessingContext);
+ return rewriteTwrCloseResourceInvoke(eventConsumer, methodProcessingContext);
}
if (!appView.options().canUseSuppressedExceptions()) {
if (isTwrSuppressedInvoke(instruction, addSuppressed)) {
@@ -108,7 +108,6 @@
private ImmutableList<CfInstruction> rewriteTwrCloseResourceInvoke(
CfInstructionDesugaringEventConsumer eventConsumer,
- ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
// Synthesize a new method.
return createAndCallSyntheticMethod(
@@ -117,7 +116,7 @@
BackportedMethods::CloseResourceMethod_closeResourceImpl,
methodProcessingContext,
eventConsumer::acceptTwrCloseResourceMethod,
- context);
+ methodProcessingContext.getMethodContext());
}
private ImmutableList<CfInstruction> createAndCallSyntheticMethod(
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 399648b..9402a62 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
@@ -33,7 +33,7 @@
import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.contexts.CompilationContext.UniqueContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexEncodedField;
@@ -50,12 +50,14 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.collections.ImmutableDeque;
import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Supplier;
import org.objectweb.asm.Opcodes;
public abstract class DesugaredLibraryAPIConversionCfCodeProvider extends SyntheticCfCodeProvider {
@@ -75,18 +77,24 @@
private final DexMethod forwardMethod;
private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizer;
private final boolean itfCall;
+ private final DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer;
+ private final Supplier<UniqueContext> contextSupplier;
public APIConverterVivifiedWrapperCfCodeProvider(
AppView<?> appView,
DexMethod forwardMethod,
DexField wrapperField,
DesugaredLibraryWrapperSynthesizer wrapperSynthesizer,
- boolean itfCall) {
+ boolean itfCall,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
super(appView, wrapperField.holder);
this.forwardMethod = forwardMethod;
this.wrapperField = wrapperField;
this.wrapperSynthesizer = wrapperSynthesizer;
this.itfCall = itfCall;
+ this.eventConsumer = eventConsumer;
+ this.contextSupplier = contextSupplier;
}
@Override
@@ -107,8 +115,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizer.getExistingProgramConversionMethod(
- param, param, vivifiedTypeFor(param)),
+ conversionMethod(param, param, vivifiedTypeFor(param)),
false));
newParameters[index - 1] = vivifiedTypeFor(param);
}
@@ -139,8 +146,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizer.getExistingProgramConversionMethod(
- returnType, vivifiedTypeFor(returnType), returnType),
+ conversionMethod(returnType, vivifiedTypeFor(returnType), returnType),
false));
}
if (returnType == factory.voidType) {
@@ -150,6 +156,11 @@
}
return standardCfCodeFromInstructions(instructions);
}
+
+ private DexMethod conversionMethod(DexType type, DexType srcType, DexType destType) {
+ return wrapperSynthesizer.getExistingProgramConversionMethod(
+ type, srcType, destType, eventConsumer, contextSupplier);
+ }
}
public abstract static class AbstractAPIConverterWrapperCfCodeProvider
@@ -227,7 +238,7 @@
extends AbstractAPIConverterWrapperCfCodeProvider {
private final DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer;
- private final MethodProcessingContext methodProcessingContext;
+ private final Supplier<UniqueContext> contextSupplier;
public APICallbackWrapperCfCodeProvider(
AppView<?> appView,
@@ -235,10 +246,10 @@
DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
boolean itfCall,
DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
+ Supplier<UniqueContext> contextSupplier) {
super(appView, forwardMethod.holder, forwardMethod, wrapperSynthesizor, itfCall);
this.eventConsumer = eventConsumer;
- this.methodProcessingContext = methodProcessingContext;
+ this.contextSupplier = contextSupplier;
}
@Override
@@ -249,7 +260,7 @@
@Override
DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
return wrapperSynthesizor.ensureConversionMethod(
- type, srcType, destType, eventConsumer, methodProcessingContext);
+ type, srcType, destType, eventConsumer, contextSupplier);
}
}
@@ -257,15 +268,21 @@
extends AbstractAPIConverterWrapperCfCodeProvider {
private final DexField wrapperField;
+ private final DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer;
+ private final Supplier<UniqueContext> contextSupplier;
public APIConverterWrapperCfCodeProvider(
AppView<?> appView,
DexMethod forwardMethod,
DexField wrapperField,
DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
- boolean itfCall) {
+ boolean itfCall,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
+ Supplier<UniqueContext> contextSupplier) {
super(appView, wrapperField.holder, forwardMethod, wrapperSynthesizor, itfCall);
this.wrapperField = wrapperField;
+ this.eventConsumer = eventConsumer;
+ this.contextSupplier = contextSupplier;
}
@Override
@@ -276,7 +293,8 @@
@Override
DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
- return wrapperSynthesizor.getExistingProgramConversionMethod(type, srcType, destType);
+ return wrapperSynthesizor.getExistingProgramConversionMethod(
+ type, srcType, destType, eventConsumer, contextSupplier);
}
}