Reduce further Nest Desugaring memory footprint
- Remove deferredBridgeToAdd Map which is now redundant
- clean-up: refactor extractNest
- clean-up: remove duplicate lookupGet/PutFieldForMethod
which are now redundant
Bug:132411997
Change-Id: I0c65bcdb2c4c5e875b2eae91121f83dc12290139
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index fc24fd2..16dab7e 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -458,19 +458,11 @@
public abstract DexField lookupField(DexField field);
- public DexMethod lookupStaticGetFieldForMethod(DexField field, DexMethod context) {
+ public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
return null;
}
- public DexMethod lookupStaticPutFieldForMethod(DexField field, DexMethod context) {
- return null;
- }
-
- public DexMethod lookupInstanceGetFieldForMethod(DexField field, DexMethod context) {
- return null;
- }
-
- public DexMethod lookupInstancePutFieldForMethod(DexField field, DexMethod context) {
+ public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
return null;
}
@@ -971,23 +963,13 @@
}
@Override
- public DexMethod lookupStaticGetFieldForMethod(DexField field, DexMethod context) {
- return previousLense.lookupStaticGetFieldForMethod(field, context);
+ public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
+ return previousLense.lookupGetFieldForMethod(field, context);
}
@Override
- public DexMethod lookupStaticPutFieldForMethod(DexField field, DexMethod context) {
- return previousLense.lookupStaticPutFieldForMethod(field, context);
- }
-
- @Override
- public DexMethod lookupInstanceGetFieldForMethod(DexField field, DexMethod context) {
- return previousLense.lookupInstanceGetFieldForMethod(field, context);
- }
-
- @Override
- public DexMethod lookupInstancePutFieldForMethod(DexField field, DexMethod context) {
- return previousLense.lookupInstancePutFieldForMethod(field, context);
+ public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
+ return previousLense.lookupPutFieldForMethod(field, context);
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index d5c65ec..2559faa 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -786,7 +786,15 @@
public void optimizeSynthesizedMethodsConcurrently(
Collection<DexEncodedMethod> methods, ExecutorService executorService)
throws ExecutionException {
- List<Future<?>> futures = new ArrayList<>();
+ List<Future<?>> futures = new ArrayList<>(methods.size());
+ optimizeSynthesizedMethodsConcurrently(methods, executorService, futures);
+ ThreadUtils.awaitFutures(futures);
+ }
+
+ public void optimizeSynthesizedMethodsConcurrently(
+ Collection<DexEncodedMethod> methods,
+ ExecutorService executorService,
+ List<Future<?>> futures) {
for (DexEncodedMethod method : methods) {
futures.add(
executorService.submit(
@@ -800,7 +808,6 @@
return null; // we want a Callable not a Runnable to be able to throw
}));
}
- ThreadUtils.awaitFutures(futures);
}
private String logCode(InternalOptions options, DexEncodedMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index cb56a09..959e9b7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -278,7 +278,7 @@
DexField field = instanceGet.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupInstanceGetFieldForMethod(actualField, method.method);
+ graphLense.lookupGetFieldForMethod(actualField, method.method);
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, current.outValue(), current.inValues()));
@@ -295,7 +295,7 @@
DexField field = instancePut.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupInstancePutFieldForMethod(actualField, method.method);
+ graphLense.lookupPutFieldForMethod(actualField, method.method);
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, current.outValue(), current.inValues()));
@@ -309,7 +309,7 @@
DexField field = staticGet.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupStaticGetFieldForMethod(actualField, method.method);
+ graphLense.lookupGetFieldForMethod(actualField, method.method);
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, current.outValue(), current.inValues()));
@@ -323,7 +323,7 @@
DexField field = staticPut.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupStaticPutFieldForMethod(actualField, method.method);
+ graphLense.lookupPutFieldForMethod(actualField, method.method);
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, current.outValue(), current.inValues()));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index 6f7bd72..3b0a46b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -43,8 +43,7 @@
private List<DexType> getNestFor(DexClass clazz) {
DexType nestHostType = clazz.getNestHost();
- DexClass nestHost = clazz.isNestHost() ? clazz : appView.definitionFor(nestHostType);
- return metNests.computeIfAbsent(nestHostType, host -> extractNest(nestHost, clazz));
+ return metNests.computeIfAbsent(nestHostType, host -> extractNest(clazz));
}
public void rewriteNestBasedAccesses(
@@ -121,8 +120,7 @@
processNestsConcurrently(metNests, executorService);
addDeferredBridges();
synthetizeNestConstructor(builder);
- converter.optimizeSynthesizedMethodsConcurrently(
- deferredBridgesToAdd.keySet(), executorService);
+ optimizeDeferredBridgesConcurrently(executorService, converter);
}
// In D8, programClass are processed on the fly so they do not need to be processed again here.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 0265d20..865049c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -18,14 +18,18 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.ThreadUtils;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@@ -48,14 +52,11 @@
private static final String FULL_NEST_CONTRUCTOR_NAME = "L" + NEST_CONSTRUCTOR_NAME + ";";
protected final AppView<?> appView;
- // Following maps are there to avoid creating the bridges multiple times.
- private final Map<DexEncodedMethod, DexMethod> bridges = new ConcurrentHashMap<>();
- private final Map<DexEncodedField, DexMethod> getFieldBridges = new ConcurrentHashMap<>();
- private final Map<DexEncodedField, DexMethod> putFieldBridges = new ConcurrentHashMap<>();
- // The following map records the bridges to add in the program.
- // It may differ from the values of the previous maps
- // if some classes are on the classpath and not the program path.
- final Map<DexEncodedMethod, DexProgramClass> deferredBridgesToAdd = new ConcurrentHashMap<>();
+ // Following maps are there to avoid creating the bridges multiple times
+ // and remember the bridges to add once the nests are processed.
+ private final Map<DexEncodedMethod, DexEncodedMethod> bridges = new ConcurrentHashMap<>();
+ private final Map<DexEncodedField, DexEncodedMethod> getFieldBridges = new ConcurrentHashMap<>();
+ private final Map<DexEncodedField, DexEncodedMethod> putFieldBridges = new ConcurrentHashMap<>();
// Common single empty class for nest based private constructors
private final DexProgramClass nestConstructor;
private boolean nestConstructorUsed = false;
@@ -70,8 +71,9 @@
}
// Extract the list of types in the programClass' nest, of host hostClass
- List<DexType> extractNest(DexClass hostClass, DexClass clazz) {
+ List<DexType> extractNest(DexClass clazz) {
assert clazz != null;
+ DexClass hostClass = clazz.isNestHost() ? clazz : appView.definitionFor(clazz.getNestHost());
if (hostClass == null) {
throw abortCompilationDueToMissingNestHost(clazz);
}
@@ -112,11 +114,31 @@
protected abstract boolean shouldProcessClassInNest(DexClass clazz, List<DexType> nest);
void addDeferredBridges() {
- for (Map.Entry<DexEncodedMethod, DexProgramClass> entry : deferredBridgesToAdd.entrySet()) {
- entry.getValue().addMethod(entry.getKey());
+ addDeferredBridges(bridges.values());
+ addDeferredBridges(getFieldBridges.values());
+ addDeferredBridges(putFieldBridges.values());
+ }
+
+ private void addDeferredBridges(Collection<DexEncodedMethod> bridges) {
+ for (DexEncodedMethod bridge : bridges) {
+ DexClass holder = appView.definitionFor(bridge.method.holder);
+ assert holder != null && holder.isProgramClass();
+ holder.asProgramClass().addMethod(bridge);
}
}
+ void optimizeDeferredBridgesConcurrently(ExecutorService executorService, IRConverter converter)
+ throws ExecutionException {
+ List<Future<?>> futures =
+ new ArrayList<>(bridges.size() + getFieldBridges.size() + putFieldBridges.size());
+ converter.optimizeSynthesizedMethodsConcurrently(bridges.values(), executorService, futures);
+ converter.optimizeSynthesizedMethodsConcurrently(
+ getFieldBridges.values(), executorService, futures);
+ converter.optimizeSynthesizedMethodsConcurrently(
+ putFieldBridges.values(), executorService, futures);
+ ThreadUtils.awaitFutures(futures);
+ }
+
private RuntimeException abortCompilationDueToIncompleteNest(List<DexType> nest) {
List<String> programClassesFromNest = new ArrayList<>();
List<String> unavailableClasses = new ArrayList<>();
@@ -288,8 +310,7 @@
return true;
}
assert holder.isLibraryClass();
- DexClass host = appView.definitionFor(holder.getNestHost());
- throw abortCompilationDueToIncompleteNest(extractNest(host, holder));
+ throw abortCompilationDueToIncompleteNest(extractNest(holder));
}
DexMethod ensureFieldAccessBridge(DexEncodedField field, boolean isGet) {
@@ -299,17 +320,15 @@
if (holderRequiresBridge(holder)) {
return bridgeMethod;
}
- // The map is used to avoid creating multiple times the bridge.
- Map<DexEncodedField, DexMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
- return fieldMap.computeIfAbsent(
+ // The map is used to avoid creating multiple times the bridge
+ // and remembers the bridges to add.
+ Map<DexEncodedField, DexEncodedMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
+ fieldMap.computeIfAbsent(
field,
- k -> {
- DexEncodedMethod localBridge =
- DexEncodedMethod.createFieldAccessorBridge(
- new DexFieldWithAccess(field, isGet), holder, bridgeMethod);
- deferredBridgesToAdd.put(localBridge, holder.asProgramClass());
- return bridgeMethod;
- });
+ k ->
+ DexEncodedMethod.createFieldAccessorBridge(
+ new DexFieldWithAccess(field, isGet), holder, bridgeMethod));
+ return bridgeMethod;
}
DexMethod ensureInvokeBridge(DexEncodedMethod method) {
@@ -326,17 +345,15 @@
if (holderRequiresBridge(holder)) {
return bridgeMethod;
}
- // The map is used to avoid creating multiple times the bridge.
- return bridges.computeIfAbsent(
+ // The map is used to avoid creating multiple times the bridge
+ // and remembers the bridges to add.
+ bridges.computeIfAbsent(
method,
- k -> {
- DexEncodedMethod localBridge =
- method.isInstanceInitializer()
- ? method.toInitializerForwardingBridge(holder, bridgeMethod)
- : method.toStaticForwardingBridge(holder, computeMethodBridge(method, appView));
- deferredBridgesToAdd.put(localBridge, holder.asProgramClass());
- return bridgeMethod;
- });
+ k ->
+ method.isInstanceInitializer()
+ ? method.toInitializerForwardingBridge(holder, bridgeMethod)
+ : method.toStaticForwardingBridge(holder, computeMethodBridge(method, appView)));
+ return bridgeMethod;
}
protected class NestBasedAccessDesugaringUseRegistry extends UseRegistry {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
index 19c4f33..a37b8ac 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
@@ -59,22 +59,12 @@
}
@Override
- public DexMethod lookupStaticGetFieldForMethod(DexField field, DexMethod context) {
+ public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
return lookupFieldForMethod(field, context, true);
}
@Override
- public DexMethod lookupStaticPutFieldForMethod(DexField field, DexMethod context) {
- return lookupFieldForMethod(field, context, false);
- }
-
- @Override
- public DexMethod lookupInstanceGetFieldForMethod(DexField field, DexMethod context) {
- return lookupFieldForMethod(field, context, true);
- }
-
- @Override
- public DexMethod lookupInstancePutFieldForMethod(DexField field, DexMethod context) {
+ public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
return lookupFieldForMethod(field, context, false);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
index 1c96f03..e3e14a3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
@@ -50,8 +50,7 @@
if (clazz.isInANest()) {
DexType hostType = clazz.getNestHost();
if (!nestMap.containsKey(hostType)) {
- DexClass host = clazz.isNestHost() ? clazz : appView.definitionFor(clazz.getNestHost());
- List<DexType> nest = extractNest(host, clazz);
+ List<DexType> nest = extractNest(clazz);
nestMap.put(hostType, nest);
futures.add(asyncProcessNest(nest, executorService));
}