blob: 1a46480687c325977b4b73bc6bd051013bbb3bcb [file] [log] [blame]
// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// 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.dex.Constants;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.EmulateDispatchSyntheticCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticClassBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.DescriptorUtils;
import java.util.Collections;
public class DesugaredLibraryRetargeterSyntheticHelper {
private final AppView<?> appView;
public DesugaredLibraryRetargeterSyntheticHelper(AppView<?> appView) {
this.appView = appView;
}
public DexClass ensureEmulatedHolderDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
assert eventConsumer != null;
if (appView.options().isDesugaredLibraryCompilation()) {
return appView
.getSyntheticItems()
.getExistingFixedClass(
SyntheticKind.RETARGET_CLASS, emulatedDispatchMethod.getHolder(), appView);
}
DexClass interfaceClass =
ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
DexMethod itfMethod =
interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
ClasspathOrLibraryClass context =
emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
assert context != null;
return appView
.getSyntheticItems()
.ensureFixedClasspathClass(
SyntheticKind.RETARGET_CLASS,
context,
appView,
classBuilder ->
buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
clazz -> {
eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
rewriteType(clazz.type);
});
}
public void ensureProgramEmulatedHolderDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
assert eventConsumer != null;
assert appView.options().isDesugaredLibraryCompilation();
DexClass interfaceClass =
ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
DexMethod itfMethod =
interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
appView
.getSyntheticItems()
.ensureFixedClass(
SyntheticKind.RETARGET_CLASS,
emulatedDispatchMethod.getHolder(),
appView,
classBuilder ->
buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
clazz -> {
eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
rewriteType(clazz.type);
});
}
public DexClass ensureEmulatedInterfaceDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
assert eventConsumer != null;
if (appView.options().isDesugaredLibraryCompilation()) {
return appView
.getSyntheticItems()
.getExistingFixedClass(
SyntheticKind.RETARGET_INTERFACE, emulatedDispatchMethod.getHolder(), appView);
}
ClasspathOrLibraryClass context =
emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
assert context != null;
return appView
.getSyntheticItems()
.ensureFixedClasspathClass(
SyntheticKind.RETARGET_INTERFACE,
context,
appView,
classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
clazz -> {
eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
rewriteType(clazz.type);
});
}
public DexClass ensureEmulatedInterfaceDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
assert appView.options().isDesugaredLibraryCompilation();
assert eventConsumer != null;
return appView
.getSyntheticItems()
.ensureFixedClass(
SyntheticKind.RETARGET_INTERFACE,
emulatedDispatchMethod.getHolder(),
appView,
classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
clazz -> {
eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
rewriteType(clazz.type);
});
}
private void buildInterfaceDispatchMethod(
SyntheticClassBuilder<?, ?> classBuilder, DexClassAndMethod emulatedDispatchMethod) {
classBuilder
.setInterface()
.addMethod(
methodBuilder -> {
MethodAccessFlags flags =
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | Constants.ACC_SYNTHETIC,
false);
methodBuilder
.setName(emulatedDispatchMethod.getName())
.setProto(emulatedDispatchMethod.getProto())
// Will be traced by the enqueuer.
.disableAndroidApiLevelCheck()
.setAccessFlags(flags);
});
}
private <SCB extends SyntheticClassBuilder<?, ?>> void buildHolderDispatchMethod(
SCB classBuilder, DexClassAndMethod emulatedDispatchMethod, DexMethod itfMethod) {
classBuilder.addMethod(
methodBuilder -> {
DexMethod desugarMethod =
appView
.options()
.desugaredLibrarySpecification
.retargetMethod(emulatedDispatchMethod, appView);
assert desugarMethod
!= null; // This method is reached only for retarget core lib members.
methodBuilder
.setName(emulatedDispatchMethod.getName())
.setProto(desugarMethod.proto)
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
// Will be traced by the enqueuer.
.disableAndroidApiLevelCheck()
.setCode(
methodSig ->
appView.options().isDesugaredLibraryCompilation()
? new EmulateDispatchSyntheticCfCodeProvider(
methodSig.getHolderType(),
desugarMethod,
itfMethod,
Collections.emptyList(),
appView)
.generateCfCode()
: null);
});
}
private void rewriteType(DexType type) {
String newName =
appView.options().desugaredLibrarySpecification.convertJavaNameToDesugaredLibrary(type);
DexType newType =
appView.dexItemFactory().createType(DescriptorUtils.javaTypeToDescriptor(newName));
appView.rewritePrefix.rewriteType(type, newType);
}
}