Desugared lib: register wrapper field access
Still crashed on Clock tests
Bug: 148448927
Change-Id: Ieb8ce2a0f041c04cd21343a0039295e36877edbe
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index cb4baef..830479c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -27,6 +27,14 @@
return type;
}
+ public boolean isInstanceOf() {
+ return true;
+ }
+
+ public CfInstanceOf asInstanceOf() {
+ return this;
+ }
+
@Override
public void write(MethodVisitor visitor, NamingLens lens) {
visitor.visitTypeInsn(Opcodes.INSTANCEOF, lens.lookupInternalName(type));
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 833e5e1..43d209e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -95,6 +95,14 @@
return null;
}
+ public boolean isInstanceOf() {
+ return false;
+ }
+
+ public CfInstanceOf asInstanceOf() {
+ return null;
+ }
+
public boolean isStore() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
index bb21829..61d7abe 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
@@ -23,14 +23,20 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
public class DesugaredLibraryConversionWrapperAnalysis extends EnqueuerAnalysis
implements EnqueuerInvokeAnalysis {
+
+ private final AppView<?> appView;
private final DesugaredLibraryAPIConverter converter;
private boolean callbackGenerated = false;
- private boolean wrappersGenerated = false;
+ private Map<DexProgramClass, DexProgramClass> wrappersToReverseMap = null;
public DesugaredLibraryConversionWrapperAnalysis(AppView<?> appView) {
+ this.appView = appView;
this.converter =
new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
}
@@ -75,18 +81,17 @@
return converter.generateCallbackMethods();
}
- public List<DexProgramClass> generateWrappers() {
- assert !wrappersGenerated;
- wrappersGenerated = true;
- return converter.generateWrappers();
+ public Set<DexProgramClass> generateWrappers() {
+ assert wrappersToReverseMap == null;
+ wrappersToReverseMap = converter.synthesizeWrappersAndMapToReverse();
+ return wrappersToReverseMap.keySet();
}
// Generate a mock classpath class for all vivified types.
// Types will be available at runtime in the desugared library dex file.
- public List<DexClasspathClass> generateWrappersSuperTypeMock(
- List<DexProgramClass> wrappers, AppView<?> appView) {
+ public List<DexClasspathClass> generateWrappersSuperTypeMock() {
List<DexClasspathClass> classpathClasses = new ArrayList<>();
- for (DexProgramClass wrapper : wrappers) {
+ for (DexProgramClass wrapper : wrappersToReverseMap.keySet()) {
boolean mockIsInterface = wrapper.interfaces.size() == 1;
DexType mockType = mockIsInterface ? wrapper.interfaces.values[0] : wrapper.superType;
if (appView.definitionFor(mockType) == null) {
@@ -117,4 +122,38 @@
}
return classpathClasses;
}
+
+ public DesugaredLibraryConversionWrapperAnalysis registerWrite(
+ DexProgramClass wrapper, Consumer<DexEncodedMethod> registration) {
+ registration.accept(getInitializer(wrapper));
+ return this;
+ }
+
+ public DesugaredLibraryConversionWrapperAnalysis registerReads(
+ DexProgramClass wrapper, Consumer<DexEncodedMethod> registration) {
+ // The field of each wrapper is read exclusively in all virtual methods and the reverse wrapper
+ // convert method.
+ for (DexEncodedMethod virtualMethod : wrapper.virtualMethods()) {
+ registration.accept(virtualMethod);
+ }
+ DexProgramClass reverseWrapper = wrappersToReverseMap.get(wrapper);
+ if (reverseWrapper != null) {
+ registration.accept(getConvertMethod(reverseWrapper));
+ }
+ return this;
+ }
+
+ private DexEncodedMethod getInitializer(DexProgramClass wrapper) {
+ DexEncodedMethod initializer =
+ wrapper.lookupDirectMethod(DexEncodedMethod::isInstanceInitializer);
+ assert initializer != null;
+ return initializer;
+ }
+
+ private DexEncodedMethod getConvertMethod(DexProgramClass wrapper) {
+ DexEncodedMethod convertMethod = wrapper.lookupDirectMethod(DexEncodedMethod::isStatic);
+ assert convertMethod != null;
+ assert convertMethod.method.name == appView.dexItemFactory().convertMethodName;
+ return convertMethod;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index 0db6f28..5df6a03 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -299,8 +299,8 @@
return result;
}
- public List<DexProgramClass> generateWrappers() {
- return wrapperSynthesizor.generateWrappers();
+ public Map<DexProgramClass, DexProgramClass> synthesizeWrappersAndMapToReverse() {
+ return wrapperSynthesizor.synthesizeWrappersAndMapToReverse();
}
private List<DexEncodedMethod> generateCallbackMethods(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 5b3b25a..a1b217a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -36,7 +36,10 @@
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -466,40 +469,59 @@
void finalizeWrappersForD8(
DexApplication.Builder<?> builder, IRConverter irConverter, ExecutorService executorService)
throws ExecutionException {
- List<DexProgramClass> synthesizedWrappers = generateWrappers();
- registerAndProcessWrappers(builder, irConverter, executorService, synthesizedWrappers);
+ Map<DexType, DexProgramClass> synthesizedWrappers = synthesizeWrappers();
+ registerAndProcessWrappers(builder, irConverter, executorService, synthesizedWrappers.values());
}
- List<DexProgramClass> generateWrappers() {
- List<DexProgramClass> synthesizedWrappers = new ArrayList<>();
- Set<DexType> synthesizedWrapperTypes = Sets.newIdentityHashSet();
+ private Map<DexType, DexProgramClass> synthesizeWrappers() {
+ Map<DexType, DexProgramClass> synthesizedWrappers = new IdentityHashMap<>();
// Generating a wrapper may require other wrappers to be generated, iterate until fix point.
- while (synthesizedWrapperTypes.size() != typeWrappers.size() + vivifiedTypeWrappers.size()) {
+ while (synthesizedWrappers.size() != typeWrappers.size() + vivifiedTypeWrappers.size()) {
for (DexType type : typeWrappers.keySet()) {
DexType typeWrapperType = typeWrappers.get(type);
- if (!synthesizedWrapperTypes.contains(typeWrapperType)) {
- synthesizedWrappers.add(generateTypeWrapper(getValidClassToWrap(type), typeWrapperType));
- synthesizedWrapperTypes.add(typeWrapperType);
+ if (!synthesizedWrappers.containsKey(typeWrapperType)) {
+ synthesizedWrappers.put(
+ typeWrapperType, generateTypeWrapper(getValidClassToWrap(type), typeWrapperType));
}
}
for (DexType type : vivifiedTypeWrappers.keySet()) {
DexType vivifiedTypeWrapperType = vivifiedTypeWrappers.get(type);
- if (!synthesizedWrapperTypes.contains(vivifiedTypeWrapperType)) {
- synthesizedWrappers.add(
+ if (!synthesizedWrappers.containsKey(vivifiedTypeWrapperType)) {
+ synthesizedWrappers.put(
+ vivifiedTypeWrapperType,
generateVivifiedTypeWrapper(getValidClassToWrap(type), vivifiedTypeWrapperType));
- synthesizedWrapperTypes.add(vivifiedTypeWrapperType);
}
}
}
- assert synthesizedWrappers.size() == synthesizedWrapperTypes.size();
return synthesizedWrappers;
}
+ private Map<DexType, DexType> reverseWrapperMap() {
+ Map<DexType, DexType> reverseWrapperMap = new IdentityHashMap<>();
+ for (DexType type : typeWrappers.keySet()) {
+ reverseWrapperMap.put(typeWrappers.get(type), vivifiedTypeWrappers.get(type));
+ }
+ for (DexType type : vivifiedTypeWrappers.keySet()) {
+ reverseWrapperMap.put(vivifiedTypeWrappers.get(type), typeWrappers.get(type));
+ }
+ return reverseWrapperMap;
+ }
+
+ Map<DexProgramClass, DexProgramClass> synthesizeWrappersAndMapToReverse() {
+ Map<DexType, DexProgramClass> synthesizedWrappers = synthesizeWrappers();
+ Map<DexType, DexType> reverseMap = reverseWrapperMap();
+ Map<DexProgramClass, DexProgramClass> wrappersAndReverse = new IdentityHashMap<>();
+ for (DexProgramClass wrapper : synthesizedWrappers.values()) {
+ wrappersAndReverse.put(wrapper, synthesizedWrappers.get(reverseMap.get(wrapper.type)));
+ }
+ return wrappersAndReverse;
+ }
+
private void registerAndProcessWrappers(
DexApplication.Builder<?> builder,
IRConverter irConverter,
ExecutorService executorService,
- List<DexProgramClass> wrappers)
+ Collection<DexProgramClass> wrappers)
throws ExecutionException {
for (DexProgramClass wrapper : wrappers) {
builder.addSynthesizedClass(wrapper, false);
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 0a2c6a3..1782239 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2402,7 +2402,7 @@
}
// Generate the wrappers.
- List<DexProgramClass> wrappers = desugaredLibraryWrapperAnalysis.generateWrappers();
+ Set<DexProgramClass> wrappers = desugaredLibraryWrapperAnalysis.generateWrappers();
for (DexProgramClass wrapper : wrappers) {
appBuilder.addProgramClass(wrapper);
liveTypes.add(wrapper, graphReporter.fakeReportShouldNotBeUsed());
@@ -2412,12 +2412,20 @@
targetedMethods.add(method, graphReporter.fakeReportShouldNotBeUsed());
liveMethods.add(wrapper, method, graphReporter.fakeReportShouldNotBeUsed());
}
+ // Register wrapper unique field reads and unique write.
+ assert wrapper.instanceFields().size() == 1;
+ DexField field = wrapper.instanceFields().get(0).field;
+ FieldAccessInfoImpl info = new FieldAccessInfoImpl(field);
+ fieldAccessInfoCollection.extend(field, info);
+ desugaredLibraryWrapperAnalysis
+ .registerWrite(wrapper, writeContext -> info.recordWrite(field, writeContext))
+ .registerReads(wrapper, readContext -> info.recordRead(field, readContext));
}
// Add all vivified types as classpath classes.
// They will be available at runtime in the desugared library dex file.
List<DexClasspathClass> mockVivifiedClasses =
- desugaredLibraryWrapperAnalysis.generateWrappersSuperTypeMock(wrappers, appView);
+ desugaredLibraryWrapperAnalysis.generateWrappersSuperTypeMock();
appBuilder.addClasspathClasses(mockVivifiedClasses);
}