Merge commit '483aabff576b08c1211b09e32c7e682eb4f59749' into dev-release
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6fea9a2..ec9955d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -160,7 +160,6 @@
assert !internal.minimalMainDex;
internal.minApiLevel = getMinApiLevel();
assert !internal.intermediate;
- internal.intermediate = true;
assert internal.readCompileTimeAnnotations;
internal.programConsumer = getProgramConsumer();
assert internal.programConsumer instanceof ClassFileConsumer;
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index f2959bb..d1e6951 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -366,11 +366,15 @@
new DexValueString(dexItemFactory.createString(kind.descriptor)));
DexAnnotationElement typeElement =
new DexAnnotationElement(dexItemFactory.valueString, new DexValueType(synthesizingContext));
+ DexAnnotationElement[] elements;
+ if (synthesizingContext == null) {
+ elements = new DexAnnotationElement[] {kindElement};
+ } else {
+ elements = new DexAnnotationElement[] {kindElement, typeElement};
+ }
return new DexAnnotation(
VISIBILITY_BUILD,
- new DexEncodedAnnotation(
- dexItemFactory.annotationSynthesizedClass,
- new DexAnnotationElement[] {kindElement, typeElement}));
+ new DexEncodedAnnotation(dexItemFactory.annotationSynthesizedClass, elements));
}
public static boolean hasSynthesizedClassAnnotation(
@@ -387,7 +391,8 @@
if (annotation.annotation.type != factory.annotationSynthesizedClass) {
return null;
}
- if (annotation.annotation.elements.length != 2) {
+ int length = annotation.annotation.elements.length;
+ if (length != 1 && length != 2) {
return null;
}
assert factory.kindString.isLessThan(factory.valueString);
@@ -404,6 +409,9 @@
if (kind == null) {
return null;
}
+ if (length != 2) {
+ return new Pair<>(kind, null);
+ }
DexAnnotationElement valueElement = annotation.annotation.elements[1];
if (valueElement.name != factory.valueString) {
return null;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 60c0ec6..04cf5cc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -61,7 +61,6 @@
import com.android.tools.r8.ir.optimize.info.UpdatableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
-import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.ir.synthetic.FieldAccessorBuilder;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
@@ -78,7 +77,6 @@
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
-import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.Ordered;
@@ -1254,27 +1252,6 @@
return builder.build();
}
- public static DexEncodedMethod toEmulateDispatchLibraryMethod(
- DexType interfaceType,
- DexMethod newMethod,
- DexMethod companionMethod,
- DexMethod libraryMethod,
- List<Pair<DexType, DexMethod>> extraDispatchCases,
- AppView<?> appView) {
- CfCode code =
- new EmulateInterfaceSyntheticCfCodeProvider(
- interfaceType, companionMethod, libraryMethod, extraDispatchCases, appView)
- .generateCfCode();
- return new DexEncodedMethod(
- newMethod,
- MethodAccessFlags.createPublicStaticSynthetic(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true);
- }
-
public ProgramMethod toStaticForwardingBridge(
DexProgramClass holder, DexMethod newMethod, DexItemFactory dexItemFactory) {
assert isPrivate()
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index cb810de..7a13785 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -275,7 +275,8 @@
group.getClassIdField(),
superMethod,
newMethodReference,
- bridgeMethodReference);
+ bridgeMethodReference,
+ appView.dexItemFactory());
DexEncodedMethod newMethod =
new DexEncodedMethod(
newMethodReference,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index 8c649b0..da12b74 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -31,7 +31,7 @@
@Override
public SourceCodeProvider getSourceCodeProvider() {
- return callerPosition ->
+ return (ignored, callerPosition) ->
new ConstructorEntryPoint(
typeConstructors, newConstructor, classIdField, callerPosition, originalMethod);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
index 3995fd8..4402a83 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
@@ -5,7 +5,9 @@
package com.android.tools.r8.horizontalclassmerging.code;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.horizontalclassmerging.VirtualMethodEntryPoint;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
@@ -15,20 +17,38 @@
public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode {
private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
+ private final DexItemFactory factory;
+
public VirtualMethodEntryPointSynthesizedCode(
Int2ReferenceSortedMap<DexMethod> mappedMethods,
DexField classIdField,
DexMethod superMethod,
DexMethod method,
- DexMethod originalMethod) {
+ DexMethod originalMethod,
+ DexItemFactory factory) {
super(
- position ->
+ (context, position) ->
new VirtualMethodEntryPoint(
- mappedMethods, classIdField, superMethod, method, position, originalMethod));
-
+ mappedMethods,
+ classIdField,
+ computeSuperMethodTarget(superMethod, context, factory),
+ method,
+ position,
+ originalMethod));
+ this.factory = factory;
this.mappedMethods = mappedMethods;
}
+ private static DexMethod computeSuperMethodTarget(
+ DexMethod superMethod, ProgramMethod method, DexItemFactory factory) {
+ // We are only using superMethod as a bit but if this is changed to generate CfCode directly,
+ // the superMethod needs to be computed by mapping through the lens.
+ if (superMethod == null) {
+ return null;
+ }
+ return method.getReference().withHolder(method.getHolder().superType, factory);
+ }
+
@Override
public Consumer<UseRegistry> getRegistryCallback() {
return this::registerReachableDefinitions;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index 4f4673a..5a96760 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
@@ -42,6 +43,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -677,13 +679,22 @@
appView
.dexItemFactory()
.createMethod(dispatchHolder, desugarMethod.proto, emulatedDispatchMethod.getName());
- return DexEncodedMethod.toEmulateDispatchLibraryMethod(
- emulatedDispatchMethod.getHolderType(),
+ CfCode code =
+ new EmulateInterfaceSyntheticCfCodeProvider(
+ emulatedDispatchMethod.getHolderType(),
+ desugarMethod,
+ itfMethod,
+ Collections.emptyList(),
+ appView)
+ .generateCfCode();
+ return new DexEncodedMethod(
newMethod,
- desugarMethod,
- itfMethod,
- Collections.emptyList(),
- appView);
+ MethodAccessFlags.createPublicStaticSynthetic(),
+ MethodTypeSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ code,
+ true);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 956cd2c..4c784f0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -765,7 +765,7 @@
DexAnnotationSet.empty(),
ParameterAnnotationsList.empty(),
new SynthesizedCode(
- callerPosition ->
+ (ignored, callerPosition) ->
new ExceptionThrowingSourceCode(clazz.type, method, callerPosition, errorType)),
true);
addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
index e8dc257..ff28c27 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
@@ -5,26 +5,28 @@
import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.emulateInterfaceLibraryMethod;
+import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
+import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
+import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,8 +42,6 @@
private final InterfaceMethodRewriter rewriter;
private final Map<DexType, DexType> emulatedInterfaces;
private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
- // All created emulated interface classes indexed by emulated interface type.
- final Map<DexProgramClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
EmulatedInterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
this.appView = appView;
@@ -136,128 +136,118 @@
return newMethods;
}
- void generateEmulateInterfaceLibrary(DexProgramClass emulatedInterface) {
+ DexProgramClass ensureEmulateInterfaceLibrary(
+ DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
assert rewriter.isEmulatedInterface(emulatedInterface.type);
- DexProgramClass theProgramInterface = emulatedInterface.asProgramClass();
- DexProgramClass synthesizedClass = synthesizeEmulateInterfaceLibraryClass(theProgramInterface);
- if (synthesizedClass != null) {
- syntheticClasses.put(emulatedInterface, synthesizedClass);
- }
- }
-
- private DexProgramClass synthesizeEmulateInterfaceLibraryClass(DexProgramClass theInterface) {
- List<DexEncodedMethod> emulationMethods = new ArrayList<>();
- theInterface.forEachProgramMethodMatching(
- DexEncodedMethod::isDefaultMethod,
- method -> {
- DexMethod libraryMethod =
- method
- .getReference()
- .withHolder(emulatedInterfaces.get(theInterface.type), appView.dexItemFactory());
- DexMethod companionMethod =
- method.getAccessFlags().isStatic()
- ? rewriter.staticAsMethodOfCompanionClass(method)
- : rewriter.defaultAsMethodOfCompanionClass(method);
- // To properly emulate the library interface call, we need to compute the interfaces
- // inheriting from the interface and manually implement the dispatch with instance of.
- // The list guarantees that an interface is always after interfaces it extends,
- // hence reverse iteration.
- List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
- List<Pair<DexType, DexMethod>> extraDispatchCases = new ArrayList<>();
- // In practice, there is usually a single case (except for tests),
- // so we do not bother to make the following loop more clever.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- if (method.getName() == methodName) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass inClass = appView.definitionFor(inType);
- if (inClass != null && implementsInterface(inClass, theInterface.type)) {
- extraDispatchCases.add(
- new Pair<>(
- inType,
- appView
- .dexItemFactory()
- .createMethod(
- retargetCoreLibMember.get(methodName).get(inType),
- appView
- .dexItemFactory()
- .protoWithDifferentFirstParameter(
- companionMethod.proto, inType),
- method.getName())));
- }
- }
- }
- }
- if (subInterfaces != null) {
- for (int i = subInterfaces.size() - 1; i >= 0; i--) {
- DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
- assert subInterfaceClass != null;
- // Else computation of subInterface would have failed.
- // if the method is implemented, extra dispatch is required.
- DexEncodedMethod result =
- subInterfaceClass.lookupVirtualMethod(method.getReference());
- if (result != null && !result.isAbstract()) {
- extraDispatchCases.add(
- new Pair<>(
- subInterfaceClass.type,
- appView
- .dexItemFactory()
- .createMethod(
- rewriter.getCompanionClassType(subInterfaceClass.type),
- appView
- .dexItemFactory()
- .protoWithDifferentFirstParameter(
- companionMethod.proto, subInterfaceClass.type),
- companionMethod.name)));
- }
- }
- }
- emulationMethods.add(
- DexEncodedMethod.toEmulateDispatchLibraryMethod(
- method.getHolderType(),
- emulateInterfaceLibraryMethod(method, rewriter.factory),
- companionMethod,
- libraryMethod,
- extraDispatchCases,
- appView));
- });
- if (emulationMethods.isEmpty()) {
- return null;
- }
DexType emulateLibraryClassType =
InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
- theInterface.type, appView.dexItemFactory());
- ClassAccessFlags emulateLibraryClassFlags = theInterface.accessFlags.copy();
- emulateLibraryClassFlags.unsetAbstract();
- emulateLibraryClassFlags.unsetInterface();
- emulateLibraryClassFlags.unsetAnnotation();
- emulateLibraryClassFlags.setFinal();
- emulateLibraryClassFlags.setSynthetic();
- emulateLibraryClassFlags.setPublic();
- DexProgramClass clazz =
- new DexProgramClass(
- emulateLibraryClassType,
- null,
- new SynthesizedOrigin("interface desugaring (libs)", getClass()),
- emulateLibraryClassFlags,
- appView.dexItemFactory().objectType,
- DexTypeList.empty(),
- theInterface.sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- // All synthesized methods are static in this case.
- emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
- DexEncodedMethod.EMPTY_ARRAY,
- appView.dexItemFactory().getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType);
- return clazz;
+ emulatedInterface.type, appView.dexItemFactory());
+ DexProgramClass emulateInterfaceClass =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClassWhileMigrating(
+ SyntheticNaming.SyntheticKind.EMULATED_INTERFACE_CLASS,
+ emulateLibraryClassType,
+ emulatedInterface,
+ appView,
+ builder ->
+ emulatedInterface.forEachProgramMethodMatching(
+ DexEncodedMethod::isDefaultMethod,
+ method ->
+ builder.addMethod(
+ methodBuilder ->
+ synthesizeEmulatedInterfaceMethod(
+ method, emulatedInterface, methodBuilder))));
+ emulateInterfaceClass.forEachProgramMethod(synthesizedMethods::add);
+ return emulateInterfaceClass;
+ }
+
+ private void synthesizeEmulatedInterfaceMethod(
+ ProgramMethod method, DexProgramClass theInterface, SyntheticMethodBuilder methodBuilder) {
+ DexMethod libraryMethod =
+ method
+ .getReference()
+ .withHolder(emulatedInterfaces.get(theInterface.type), appView.dexItemFactory());
+ DexMethod companionMethod =
+ method.getAccessFlags().isStatic()
+ ? rewriter.staticAsMethodOfCompanionClass(method)
+ : rewriter.defaultAsMethodOfCompanionClass(method);
+ List<Pair<DexType, DexMethod>> extraDispatchCases =
+ getDispatchCases(method, theInterface, companionMethod);
+ DexMethod emulatedMethod = emulateInterfaceLibraryMethod(method, appView.dexItemFactory());
+ methodBuilder
+ .setName(emulatedMethod.getName())
+ .setProto(emulatedMethod.getProto())
+ .setCode(
+ theMethod ->
+ new EmulateInterfaceSyntheticCfCodeProvider(
+ theMethod.getHolderType(),
+ companionMethod,
+ libraryMethod,
+ extraDispatchCases,
+ appView)
+ .generateCfCode())
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC, false));
+ }
+
+ private List<Pair<DexType, DexMethod>> getDispatchCases(
+ ProgramMethod method, DexProgramClass theInterface, DexMethod companionMethod) {
+ // To properly emulate the library interface call, we need to compute the interfaces
+ // inheriting from the interface and manually implement the dispatch with instance of.
+ // The list guarantees that an interface is always after interfaces it extends,
+ // hence reverse iteration.
+ List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
+ List<Pair<DexType, DexMethod>> extraDispatchCases = new ArrayList<>();
+ // In practice, there is usually a single case (except for tests),
+ // so we do not bother to make the following loop more clever.
+ Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+ appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+ for (DexString methodName : retargetCoreLibMember.keySet()) {
+ if (method.getName() == methodName) {
+ for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
+ DexClass inClass = appView.definitionFor(inType);
+ if (inClass != null && implementsInterface(inClass, theInterface.type)) {
+ extraDispatchCases.add(
+ new Pair<>(
+ inType,
+ appView
+ .dexItemFactory()
+ .createMethod(
+ retargetCoreLibMember.get(methodName).get(inType),
+ appView
+ .dexItemFactory()
+ .protoWithDifferentFirstParameter(companionMethod.proto, inType),
+ method.getName())));
+ }
+ }
+ }
+ }
+ if (subInterfaces != null) {
+ for (int i = subInterfaces.size() - 1; i >= 0; i--) {
+ DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
+ assert subInterfaceClass != null;
+ // Else computation of subInterface would have failed.
+ // if the method is implemented, extra dispatch is required.
+ DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
+ if (result != null && !result.isAbstract()) {
+ extraDispatchCases.add(
+ new Pair<>(
+ subInterfaceClass.type,
+ appView
+ .dexItemFactory()
+ .createMethod(
+ rewriter.getCompanionClassType(subInterfaceClass.type),
+ appView
+ .dexItemFactory()
+ .protoWithDifferentFirstParameter(
+ companionMethod.proto, subInterfaceClass.type),
+ companionMethod.name)));
+ }
+ }
+ }
+ return extraDispatchCases;
}
private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
@@ -282,14 +272,19 @@
|| appView.isAlreadyLibraryDesugared(emulatedInterface)) {
return;
}
- generateEmulateInterfaceLibrary(emulatedInterface);
+ if (needsEmulateInterfaceLibrary(emulatedInterface)) {
+ ensureEmulateInterfaceLibrary(emulatedInterface, synthesizedMethods);
+ }
+ }
+
+ private boolean needsEmulateInterfaceLibrary(DexProgramClass emulatedInterface) {
+ return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod);
}
@Override
public void finalizeProcessing(Builder<?> builder, ProgramMethodSet synthesizedMethods) {
warnMissingEmulatedInterfaces();
if (!appView.options().isDesugaredLibraryCompilation()) {
- assert syntheticClasses.isEmpty();
return;
}
for (DexType interfaceType : emulatedInterfaces.keySet()) {
@@ -302,12 +297,6 @@
}
}
}
- syntheticClasses.forEach(
- (interfaceClass, synthesizedClass) -> {
- builder.addSynthesizedClass(synthesizedClass);
- appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass);
- synthesizedClass.forEachProgramMethod(synthesizedMethods::add);
- });
// TODO(b/183918843): Investigate what to do for the filtering, the minimum would be to make
// the rewriting rule explicit instead of using the synthesized class prefix.
filterEmulatedInterfaceSubInterfaces(builder);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index e847977..b0df7c7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication.Builder;
@@ -28,21 +27,18 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue.DexValueInt;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodCollection;
import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
+import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
@@ -53,7 +49,6 @@
import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -76,9 +71,6 @@
private final Map<DexProgramClass, PostProcessingInterfaceInfo> postProcessingInterfaceInfos =
new ConcurrentHashMap<>();
- // All created companion classes indexed by interface type.
- final Map<DexClass, DexProgramClass> syntheticClasses = new ConcurrentHashMap<>();
-
InterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
this.appView = appView;
this.rewriter = rewriter;
@@ -91,7 +83,7 @@
}
analyzeBridges(iface);
if (needsCompanionClass(iface)) {
- synthesizeCompanionClass(iface, synthesizedMethods);
+ ensureCompanionClass(iface, synthesizedMethods);
}
}
@@ -124,72 +116,54 @@
return false;
}
- private void synthesizeCompanionClass(
+ private DexProgramClass ensureCompanionClass(
DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
- // The list of methods to be created in companion class.
- List<DexEncodedMethod> companionMethods = new ArrayList<>();
- ensureCompanionClassInitializesInterface(iface, companionMethods);
-
- // Process virtual interface methods first.
- processVirtualInterfaceMethods(iface, companionMethods);
-
- // Process static and private methods, move them into companion class as well,
- // make private instance methods public static.
- processDirectInterfaceMethods(iface, companionMethods);
-
- assert !companionMethods.isEmpty();
-
- ClassAccessFlags companionClassFlags = iface.accessFlags.copy();
- companionClassFlags.unsetAbstract();
- companionClassFlags.unsetInterface();
- companionClassFlags.unsetAnnotation();
- companionClassFlags.setFinal();
- companionClassFlags.setSynthetic();
- // Companion class must be public so moved methods can be called from anywhere.
- companionClassFlags.setPublic();
-
- // Create companion class.
- DexType companionClassType = rewriter.getCompanionClassType(iface.type);
DexProgramClass companionClass =
- new DexProgramClass(
- companionClassType,
- null,
- new SynthesizedOrigin("interface desugaring", getClass()),
- companionClassFlags,
- rewriter.factory.objectType,
- DexTypeList.empty(),
- iface.sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- companionMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
- DexEncodedMethod.EMPTY_ARRAY,
- rewriter.factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(iface));
- syntheticClasses.put(iface, companionClass);
+ appView
+ .getSyntheticItems()
+ .ensureFixedClassWhileMigrating(
+ SyntheticNaming.SyntheticKind.COMPANION_CLASS,
+ rewriter.getCompanionClassType(iface.type),
+ iface,
+ appView,
+ builder -> {
+ builder.setSourceFile(iface.sourceFile);
+ ensureCompanionClassInitializesInterface(iface, builder);
+ processVirtualInterfaceMethods(iface, builder);
+ processDirectInterfaceMethods(iface, builder);
+ });
+
+ assert companionClass.hasMethods();
+
+ // D8 and R8 don't need to optimize the methods since they are just moved from interfaces and
+ // don't need to be re-processed, besides the clinit, which has just been inserted.
if (companionClass.hasClassInitializer()) {
synthesizedMethods.add(companionClass.getProgramClassInitializer());
}
+
+ return companionClass;
}
private void ensureCompanionClassInitializesInterface(
- DexProgramClass iface, List<DexEncodedMethod> companionMethods) {
+ DexProgramClass iface, SyntheticProgramClassBuilder builder) {
if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) {
return;
}
+ DexEncodedField clinitField = ensureStaticClinitFieldToTriggerinterfaceInitialization(iface);
+ builder.addMethod(
+ methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder));
+ }
+
+ private DexEncodedField ensureStaticClinitFieldToTriggerinterfaceInitialization(
+ DexProgramClass iface) {
DexEncodedField clinitField =
findExistingStaticClinitFieldToTriggerInterfaceInitialization(iface);
if (clinitField == null) {
clinitField = createStaticClinitFieldToTriggerInterfaceInitialization(iface);
iface.appendStaticField(clinitField);
}
- companionMethods.add(createCompanionClassInitializer(iface, clinitField));
+ return clinitField;
}
private boolean hasStaticMethodThatTriggersNonTrivialClassInitializer(DexProgramClass iface) {
@@ -226,37 +200,34 @@
DexValueInt.DEFAULT);
}
- private DexEncodedMethod createCompanionClassInitializer(
- DexProgramClass iface, DexEncodedField clinitField) {
- DexType companionType = rewriter.getCompanionClassType(iface.getType());
- DexMethod clinitMethodReference = appView.dexItemFactory().createClinitMethod(companionType);
- CfCode code =
- new CfCode(
- companionType,
- clinitField.getType().isWideType() ? 2 : 1,
- 0,
- ImmutableList.of(
- new CfFieldInstruction(
- Opcodes.GETSTATIC, clinitField.getReference(), clinitField.getReference()),
- clinitField.getType().isWideType()
- ? new CfStackInstruction(Opcode.Pop2)
- : new CfStackInstruction(Opcode.Pop),
- new CfReturnVoid()),
- ImmutableList.of(),
- ImmutableList.of());
- return new DexEncodedMethod(
- clinitMethodReference,
- MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true,
- iface.getInitialClassFileVersion());
+ private void createCompanionClassInitializer(
+ DexProgramClass iface, DexEncodedField clinitField, SyntheticMethodBuilder methodBuilder) {
+ SyntheticMethodBuilder.SyntheticCodeGenerator codeGenerator =
+ method ->
+ new CfCode(
+ method.holder,
+ clinitField.getType().isWideType() ? 2 : 1,
+ 0,
+ ImmutableList.of(
+ new CfFieldInstruction(
+ Opcodes.GETSTATIC, clinitField.getReference(), clinitField.getReference()),
+ clinitField.getType().isWideType()
+ ? new CfStackInstruction(Opcode.Pop2)
+ : new CfStackInstruction(Opcode.Pop),
+ new CfReturnVoid()),
+ ImmutableList.of(),
+ ImmutableList.of());
+ methodBuilder
+ .setName(appView.dexItemFactory().classConstructorMethodName)
+ .setProto(appView.dexItemFactory().createProto(appView.dexItemFactory().voidType))
+ .setAccessFlags(
+ MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build())
+ .setCode(codeGenerator)
+ .setClassFileVersion(iface.getInitialClassFileVersion());
}
private void processVirtualInterfaceMethods(
- DexProgramClass iface, List<DexEncodedMethod> companionMethods) {
+ DexProgramClass iface, SyntheticProgramClassBuilder builder) {
for (ProgramMethod method : iface.virtualProgramMethods()) {
DexEncodedMethod virtual = method.getDefinition();
if (rewriter.isDefaultMethod(virtual)) {
@@ -282,25 +253,29 @@
newFlags.promoteToStatic();
DexEncodedMethod.setDebugInfoWithFakeThisParameter(
code, companionMethod.getArity(), appView);
- DexEncodedMethod implMethod =
- new DexEncodedMethod(
- companionMethod,
- newFlags,
- virtual.getGenericSignature(),
- virtual.annotations(),
- virtual.parameterAnnotationsList,
- code,
- true);
- implMethod.copyMetadata(virtual);
- companionMethods.add(implMethod);
- getPostProcessingInterfaceInfo(iface)
- .mapDefaultMethodToCompanionMethod(virtual, implMethod);
+
+ builder.addMethod(
+ methodBuilder ->
+ methodBuilder
+ .setName(companionMethod.getName())
+ .setProto(companionMethod.getProto())
+ .setAccessFlags(newFlags)
+ .setGenericSignature(virtual.getGenericSignature())
+ .setAnnotations(virtual.annotations())
+ .setParameterAnnotationsList(virtual.getParameterAnnotations())
+ .setCode(ignored -> virtual.getCode())
+ .setOnBuildConsumer(
+ implMethod -> {
+ implMethod.copyMetadata(virtual);
+ getPostProcessingInterfaceInfo(iface)
+ .mapDefaultMethodToCompanionMethod(virtual, implMethod);
+ }));
}
}
}
private void processDirectInterfaceMethods(
- DexProgramClass iface, List<DexEncodedMethod> companionMethods) {
+ DexProgramClass iface, SyntheticProgramClassBuilder builder) {
for (ProgramMethod method : iface.directProgramMethods()) {
DexEncodedMethod definition = method.getDefinition();
if (definition.isClassInitializer()) {
@@ -330,17 +305,22 @@
+ "either be public or private in "
+ iface.origin;
DexMethod companionMethod = rewriter.staticAsMethodOfCompanionClass(method);
- DexEncodedMethod implMethod =
- new DexEncodedMethod(
- companionMethod,
- newFlags,
- definition.getGenericSignature(),
- definition.annotations(),
- definition.parameterAnnotationsList,
- definition.getCode(),
- true);
- implMethod.copyMetadata(definition);
- companionMethods.add(implMethod);
+
+ builder.addMethod(
+ methodBuilder ->
+ methodBuilder
+ .setName(companionMethod.getName())
+ .setProto(companionMethod.getProto())
+ .setAccessFlags(newFlags)
+ .setGenericSignature(definition.getGenericSignature())
+ .setAnnotations(definition.annotations())
+ .setParameterAnnotationsList(definition.getParameterAnnotations())
+ .setCode(ignored -> definition.getCode())
+ .setOnBuildConsumer(
+ implMethod -> {
+ implMethod.copyMetadata(definition);
+ }));
+
getPostProcessingInterfaceInfo(iface).moveMethod(oldMethod, companionMethod);
continue;
}
@@ -361,19 +341,25 @@
+ oldMethod.toSourceString(),
iface.origin);
}
+
DexEncodedMethod.setDebugInfoWithFakeThisParameter(code, companionMethod.getArity(), appView);
- DexEncodedMethod implMethod =
- new DexEncodedMethod(
- companionMethod,
- newFlags,
- definition.getGenericSignature(),
- definition.annotations(),
- definition.parameterAnnotationsList,
- code,
- true);
- implMethod.copyMetadata(definition);
- companionMethods.add(implMethod);
- getPostProcessingInterfaceInfo(iface).moveMethod(oldMethod, companionMethod);
+
+ builder.addMethod(
+ methodBuilder ->
+ methodBuilder
+ .setName(companionMethod.getName())
+ .setProto(companionMethod.getProto())
+ .setAccessFlags(newFlags)
+ .setGenericSignature(definition.getGenericSignature())
+ .setAnnotations(definition.annotations())
+ .setParameterAnnotationsList(definition.getParameterAnnotations())
+ .setCode(ignored -> definition.getCode())
+ .setOnBuildConsumer(
+ implMethod -> {
+ implMethod.copyMetadata(definition);
+ getPostProcessingInterfaceInfo(iface)
+ .moveMethod(oldMethod, companionMethod);
+ }));
}
}
@@ -387,14 +373,6 @@
}
}
- private ChecksumSupplier getChecksumSupplier(DexProgramClass iface) {
- if (!appView.options().encodeChecksums) {
- return DexProgramClass::invalidChecksumRequest;
- }
- long checksum = iface.getChecksum();
- return c -> 7 * checksum;
- }
-
private boolean canMoveToCompanionClass(DexEncodedMethod method) {
Code code = method.getCode();
assert code != null;
@@ -525,13 +503,6 @@
if (appView.enableWholeProgramOptimizations() && graphLens != null) {
appView.setGraphLens(graphLens);
}
- syntheticClasses.forEach(
- (interfaceClass, synthesizedClass) -> {
- // Don't need to optimize synthesized class since all of its methods
- // are just moved from interfaces and don't need to be re-processed.
- builder.addSynthesizedClass(synthesizedClass);
- appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass.asProgramClass());
- });
new InterfaceMethodRewriterFixup(appView, graphLens).run();
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index ad43a6c..4dc56de 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -25,7 +25,7 @@
public abstract class AbstractSynthesizedCode extends Code {
public interface SourceCodeProvider {
- SourceCode get(Position callerPosition);
+ SourceCode get(ProgramMethod context, Position callerPosition);
}
public abstract SourceCodeProvider getSourceCodeProvider();
@@ -39,7 +39,7 @@
@Override
public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
- return IRBuilder.create(method, appView, getSourceCodeProvider().get(null), origin)
+ return IRBuilder.create(method, appView, getSourceCodeProvider().get(method, null), origin)
.build(method);
}
@@ -55,7 +55,7 @@
return IRBuilder.createForInlining(
method,
appView,
- getSourceCodeProvider().get(callerPosition),
+ getSourceCodeProvider().get(context, callerPosition),
origin,
methodProcessor,
valueNumberGenerator)
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index e5a79bb..9e708cc 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.Position;
@@ -86,7 +87,7 @@
return this;
}
- public ForwardMethodSourceCode build(Position callerPosition) {
+ public ForwardMethodSourceCode build(ProgramMethod context, Position callerPosition) {
return new ForwardMethodSourceCode(
receiver,
method,
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 6a611dc..3bf8883 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -67,7 +67,6 @@
static SynthesizingContext fromSyntheticInputClass(
DexProgramClass clazz, DexType synthesizingContextType, AppView<?> appView) {
- assert synthesizingContextType != null;
// A context that is itself synthetic must denote a synthesizing context from which to ensure
// hygiene. This synthesizing context type is encoded on the synthetic for intermediate builds.
FeatureSplit featureSplit =
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 126355f..c81ad1c 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -38,6 +38,7 @@
private Kind originKind;
private DexType superType;
private DexTypeList interfaces = DexTypeList.empty();
+ private DexString sourceFile = null;
private List<DexEncodedField> staticFields = new ArrayList<>();
private List<DexEncodedField> instanceFields = new ArrayList<>();
private List<DexEncodedMethod> directMethods = new ArrayList<>();
@@ -81,6 +82,11 @@
return self();
}
+ public B setSourceFile(DexString sourceFile) {
+ this.sourceFile = sourceFile;
+ return self();
+ }
+
public B setStaticFields(List<DexEncodedField> fields) {
staticFields.clear();
staticFields.addAll(fields);
@@ -117,7 +123,6 @@
ClassAccessFlags accessFlags =
ClassAccessFlags.fromSharedAccessFlags(
flag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
- DexString sourceFile = null;
NestHostClassAttribute nestHost = null;
List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
EnclosingMethodAttribute enclosingMembers = null;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index ac15138..cbdf447 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -478,7 +478,11 @@
AppView<?> appView) {
if (shouldAnnotateSynthetics(appView.options())) {
SyntheticMarker.addMarkerToClass(
- externalSyntheticClass, kind, context, appView.dexItemFactory());
+ externalSyntheticClass,
+ kind,
+ context,
+ appView.dexItemFactory(),
+ appView.options().forceAnnotateSynthetics);
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
index d68558d..1d9b5b9 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
public class SyntheticMarker {
@@ -20,21 +21,23 @@
DexProgramClass clazz,
SyntheticKind kind,
SynthesizingContext context,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ boolean dontRecordSynthesizingContext) {
clazz.setAnnotations(
clazz
.annotations()
.getWithAddedOrReplaced(
DexAnnotation.createAnnotationSynthesizedClass(
- kind, context.getSynthesizingContextType(), factory)));
+ kind,
+ dontRecordSynthesizingContext ? null : context.getSynthesizingContextType(),
+ factory)));
}
public static SyntheticMarker stripMarkerFromClass(DexProgramClass clazz, AppView<?> appView) {
SyntheticMarker marker = internalStripMarkerFromClass(clazz, appView);
assert marker != NO_MARKER
- || DexAnnotation.getSynthesizedClassAnnotationContextType(
- clazz.annotations(), appView.dexItemFactory())
- == null;
+ || !DexAnnotation.hasSynthesizedClassAnnotation(
+ clazz.annotations(), appView.dexItemFactory());
return marker;
}
@@ -67,6 +70,18 @@
}
}
clazz.setAnnotations(DexAnnotationSet.empty());
+ if (context == null) {
+ // If the class is marked as synthetic but has no synthesizing context, then we read the
+ // context type as the prefix. This happens for desugared library builds where the context of
+ // the generated
+ // synthetics becomes themselves. Using the original context could otherwise have referenced
+ // a type in the non-rewritten library and cause an non-rewritten output type.
+ String prefix = SyntheticNaming.getPrefixForExternalSyntheticType(kind, clazz.type);
+ context =
+ appView
+ .dexItemFactory()
+ .createType(DescriptorUtils.getDescriptorFromClassBinaryName(prefix));
+ }
return new SyntheticMarker(
kind, SynthesizingContext.fromSyntheticInputClass(clazz, context, appView));
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
index 487cb53..67bd52c 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import java.util.function.Consumer;
public class SyntheticMethodBuilder {
@@ -29,6 +30,10 @@
private CfVersion classFileVersion;
private SyntheticCodeGenerator codeGenerator = null;
private MethodAccessFlags accessFlags = null;
+ private MethodTypeSignature genericSignature = MethodTypeSignature.noSignature();
+ private DexAnnotationSet annotations = DexAnnotationSet.empty();
+ private ParameterAnnotationsList parameterAnnotationsList = ParameterAnnotationsList.empty();
+ private Consumer<DexEncodedMethod> onBuildConsumer = null;
SyntheticMethodBuilder(SyntheticClassBuilder<?, ?> parent) {
this.factory = parent.getFactory();
@@ -71,6 +76,27 @@
return this;
}
+ public SyntheticMethodBuilder setGenericSignature(MethodTypeSignature genericSignature) {
+ this.genericSignature = genericSignature;
+ return this;
+ }
+
+ public SyntheticMethodBuilder setAnnotations(DexAnnotationSet annotations) {
+ this.annotations = annotations;
+ return this;
+ }
+
+ public SyntheticMethodBuilder setParameterAnnotationsList(
+ ParameterAnnotationsList parameterAnnotationsList) {
+ this.parameterAnnotationsList = parameterAnnotationsList;
+ return this;
+ }
+
+ public SyntheticMethodBuilder setOnBuildConsumer(Consumer<DexEncodedMethod> onBuildConsumer) {
+ this.onBuildConsumer = onBuildConsumer;
+ return this;
+ }
+
DexEncodedMethod build() {
assert name != null;
boolean isCompilerSynthesized = true;
@@ -79,13 +105,19 @@
new DexEncodedMethod(
methodSignature,
getAccessFlags(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
+ genericSignature,
+ annotations,
+ parameterAnnotationsList,
getCodeObject(methodSignature),
isCompilerSynthesized,
classFileVersion);
- assert isValidSyntheticMethod(method);
+ // Companion class method may have different properties.
+ assert isValidSyntheticMethod(method)
+ || SyntheticNaming.isSynthetic(
+ holderType.asClassReference(), null, SyntheticNaming.SyntheticKind.COMPANION_CLASS);
+ if (onBuildConsumer != null) {
+ onBuildConsumer.accept(method);
+ }
return method;
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index cb1e91b..8b19177 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -24,7 +24,8 @@
public enum SyntheticKind {
// Class synthetics.
RECORD_TAG("", false, true, true),
- COMPANION_CLASS("CompanionClass", false),
+ COMPANION_CLASS("-CC", false, true),
+ EMULATED_INTERFACE_CLASS("-EL", false, true),
LAMBDA("Lambda", false),
INIT_TYPE_ARGUMENT("-IA", false, true),
HORIZONTAL_INIT_TYPE_ARGUMENT_1(SYNTHETIC_CLASS_SEPARATOR + "IA$1", false, true),
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 36ebfd8..a01f7dc 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -854,7 +854,7 @@
DexString.EMPTY_ARRAY);
Code code =
new SynthesizedCode(
- callerPosition -> new ReturnVoidCode(voidReturnMethod, callerPosition));
+ (ignored, callerPosition) -> new ReturnVoidCode(voidReturnMethod, callerPosition));
DexEncodedMethod method =
new DexEncodedMethod(
voidReturnMethod,
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumeNoSideEffectsRuleOnThrowingMethodTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumeNoSideEffectsRuleOnThrowingMethodTest.java
new file mode 100644
index 0000000..ba02019
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumeNoSideEffectsRuleOnThrowingMethodTest.java
@@ -0,0 +1,51 @@
+// 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.shaking.assumenosideeffects;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class AssumeNoSideEffectsRuleOnThrowingMethodTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public AssumeNoSideEffectsRuleOnThrowingMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class)
+ .addKeepMainRule(Main.class)
+ .addKeepRules("-assumenosideeffects class " + Main.class.getTypeName() + " { ouch(); }")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ ouch();
+ System.out.println("Hello world!");
+ }
+
+ static void ouch() {
+ throw new RuntimeException();
+ }
+ }
+}