Commit created dex items after each enqueuer wave
Bug: b/422947619
Change-Id: Ida3ab1f30c3b4cd71df6ecf4acd0aa16e2b9a86e
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index ca1c308..60cdebb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -92,12 +92,24 @@
private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
private Map<DexString, DexString> markers = new ConcurrentHashMap<>();
- private Map<DexString, DexString> strings = new ConcurrentHashMap<>();
- private Map<DexString, DexType> types = new ConcurrentHashMap<>();
- private Map<DexField, DexField> fields = new ConcurrentHashMap<>();
- private Map<DexProto, DexProto> protos = new ConcurrentHashMap<>();
- private Map<DexMethod, DexMethod> methods = new ConcurrentHashMap<>();
+
private Map<DexMethodHandle, DexMethodHandle> methodHandles = new ConcurrentHashMap<>();
+ private Map<DexMethodHandle, DexMethodHandle> committedMethodHandles = new HashMap<>();
+
+ private Map<DexString, DexString> strings = new ConcurrentHashMap<>();
+ private Map<DexString, DexString> committedStrings = new HashMap<>();
+
+ private Map<DexString, DexType> types = new ConcurrentHashMap<>();
+ private Map<DexString, DexType> committedTypes = new HashMap<>();
+
+ private Map<DexField, DexField> fields = new ConcurrentHashMap<>();
+ private Map<DexField, DexField> committedFields = new HashMap<>();
+
+ private Map<DexProto, DexProto> protos = new ConcurrentHashMap<>();
+ private Map<DexProto, DexProto> committedProtos = new HashMap<>();
+
+ private Map<DexMethod, DexMethod> methods = new ConcurrentHashMap<>();
+ private Map<DexMethod, DexMethod> committedMethods = new HashMap<>();
// DexDebugEvent Canonicalization.
private final Int2ReferenceMap<AdvanceLine> advanceLines = new Int2ReferenceOpenHashMap<>();
@@ -1887,8 +1899,12 @@
createString("addSuppressed"), voidDescriptor, new DexString[]{throwableDescriptor});
getSuppressed = createMethod(throwableDescriptor,
createString("getSuppressed"), throwableArrayDescriptor, DexString.EMPTY_ARRAY);
- initCause = createMethod(throwableDescriptor, createString("initCause"), throwableDescriptor,
- new DexString[] { throwableDescriptor });
+ initCause =
+ createMethod(
+ throwableDescriptor,
+ createString("initCause"),
+ throwableDescriptor,
+ new DexString[] {throwableDescriptor});
getMessage =
createMethod(
throwableDescriptor,
@@ -2222,14 +2238,27 @@
getDeclaredConstructorName,
constructorDescriptor,
new DexString[] {classArrayDescriptor});
- getField = createMethod(classDescriptor, getFieldName, fieldDescriptor,
- new DexString[] {stringDescriptor});
- getDeclaredField = createMethod(classDescriptor, getDeclaredFieldName, fieldDescriptor,
- new DexString[] {stringDescriptor});
- getMethod = createMethod(classDescriptor, getMethodName, methodDescriptor,
- new DexString[] {stringDescriptor, classArrayDescriptor});
- getDeclaredMethod = createMethod(classDescriptor, getDeclaredMethodName, methodDescriptor,
- new DexString[] {stringDescriptor, classArrayDescriptor});
+ getField =
+ createMethod(
+ classDescriptor, getFieldName, fieldDescriptor, new DexString[] {stringDescriptor});
+ getDeclaredField =
+ createMethod(
+ classDescriptor,
+ getDeclaredFieldName,
+ fieldDescriptor,
+ new DexString[] {stringDescriptor});
+ getMethod =
+ createMethod(
+ classDescriptor,
+ getMethodName,
+ methodDescriptor,
+ new DexString[] {stringDescriptor, classArrayDescriptor});
+ getDeclaredMethod =
+ createMethod(
+ classDescriptor,
+ getDeclaredMethodName,
+ methodDescriptor,
+ new DexString[] {stringDescriptor, classArrayDescriptor});
newInstance =
createMethod(classDescriptor, newInstanceName, objectDescriptor, DexString.EMPTY_ARRAY);
getMembers = ImmutableSet.of(getField, getDeclaredField, getMethod, getDeclaredMethod);
@@ -2429,6 +2458,7 @@
&& accessFlags.isFinal();
}
}
+
public class NullPointerExceptionMethods {
public final DexMethod init =
@@ -2454,7 +2484,7 @@
* All boxed types (Boolean, Byte, ...) have a field named TYPE which contains the Class object
* for the primitive type.
*
- * E.g. for Boolean https://docs.oracle.com/javase/8/docs/api/java/lang/Boolean.html#TYPE.
+ * <p>E.g. for Boolean https://docs.oracle.com/javase/8/docs/api/java/lang/Boolean.html#TYPE.
*/
public class PrimitiveTypesBoxedTypeFields {
@@ -2808,7 +2838,7 @@
return !strValue.getType().isNullable();
}
- assert false : "Unexpected invoke targeting `" + invokedMethod.toSourceString() + "`";
+ assert false : "Unexpected invoke targeting `" + invokedMethod.toSourceString() + "`";
return false;
}
@@ -2962,11 +2992,20 @@
createMethod(javaUtilIteratorType, createProto(objectType), nextName);
}
- private static <T extends DexItem> T canonicalize(Map<T, T> map, T item) {
+ private static <T extends DexItem> T canonicalize(
+ Map<T, T> committedMap, Map<T, T> pendingMap, T item) {
assert item != null;
assert !DexItemFactory.isInternalSentinel(item);
- T previous = map.putIfAbsent(item, item);
- return previous == null ? item : previous;
+ // Avoid synchronization for committed items.
+ T committed = committedMap.get(item);
+ if (committed != null) {
+ return committed;
+ }
+ T previous = pendingMap.putIfAbsent(item, item);
+ if (previous != null) {
+ return previous;
+ }
+ return item;
}
public DexString createMarkerString(int size, byte[] content) {
@@ -2986,11 +3025,11 @@
}
public DexString createString(int size, byte[] content) {
- return canonicalize(strings, new DexString(size, content));
+ return canonicalize(committedStrings, strings, new DexString(size, content));
}
public DexString createString(String source) {
- return canonicalize(strings, new DexString(source));
+ return canonicalize(committedStrings, strings, new DexString(source));
}
public static String escapeMemberString(String str) {
@@ -3294,12 +3333,13 @@
}
}
- public DexString lookupString(int size, byte[] content) {
- return strings.get(new DexString(size, content));
- }
-
public DexString lookupString(String source) {
- return strings.get(new DexString(source));
+ DexString key = new DexString(source);
+ DexString committed = committedStrings.get(key);
+ if (committed != null) {
+ return committed;
+ }
+ return strings.get(key);
}
// Debugging support to extract marking string.
@@ -3315,23 +3355,6 @@
return markers;
}
- // Non-synchronized internal create.
- private DexType internalCreateType(DexString descriptor) {
- assert descriptor != null;
- DexType result = types.get(descriptor);
- if (result == null) {
- result = new DexType(descriptor);
- assert result.isArrayType()
- || result.isClassType()
- || result.isPrimitiveType()
- || result.isVoidType()
- : descriptor.toString();
- assert !isInternalSentinel(result);
- types.put(descriptor, result);
- }
- return result;
- }
-
private DexType createStaticallyKnownType(String descriptor) {
return createStaticallyKnownType(createString(descriptor));
}
@@ -3344,7 +3367,7 @@
}
private DexType createStaticallyKnownType(DexString descriptor) {
- DexType type = internalCreateType(descriptor);
+ DexType type = createType(descriptor);
// Conservatively add all statically known types to "compiler synthesized types set".
addPossiblySynthesizedType(type);
return type;
@@ -3352,8 +3375,8 @@
// Safe synchronized external create. May be used for statically known types in synthetic code.
// See the generated BackportedMethods.java for reference.
- public synchronized DexType createSynthesizedType(String descriptor) {
- DexType type = internalCreateType(createString(descriptor));
+ public DexType createSynthesizedType(String descriptor) {
+ DexType type = createType(createString(descriptor));
addPossiblySynthesizedType(type);
return type;
}
@@ -3381,9 +3404,13 @@
possibleCompilerSynthesizedTypes.forEach(fn);
}
- // Safe synchronized external create. Should never be used to create a statically known type!
- public synchronized DexType createType(DexString descriptor) {
- return internalCreateType(descriptor);
+ public DexType createType(DexString descriptor) {
+ assert descriptor != null;
+ DexType committed = committedTypes.get(descriptor);
+ if (committed != null) {
+ return committed;
+ }
+ return types.computeIfAbsent(descriptor, DexType::new);
}
public DexType createType(String descriptor) {
@@ -3395,6 +3422,10 @@
}
public DexType lookupType(DexString descriptor) {
+ DexType committed = committedTypes.get(descriptor);
+ if (committed != null) {
+ return committed;
+ }
return types.get(descriptor);
}
@@ -3405,7 +3436,7 @@
public DexField createField(DexType clazz, DexType type, DexString name) {
DexField field = new DexField(clazz, type, name, skipNameValidationForTesting);
- return canonicalize(fields, field);
+ return canonicalize(committedFields, fields, field);
}
public DexField createField(DexType clazz, DexType type, String name) {
@@ -3421,7 +3452,7 @@
public DexProto createProto(DexType returnType, DexTypeList parameters) {
DexProto proto = new DexProto(returnType, parameters);
- return canonicalize(protos, proto);
+ return canonicalize(committedProtos, protos, proto);
}
public DexProto createProto(DexType returnType, DexType... parameters) {
@@ -3493,7 +3524,7 @@
public DexMethod createMethod(DexType holder, DexProto proto, DexString name) {
DexMethod method = new DexMethod(holder, proto, name, skipNameValidationForTesting);
- return canonicalize(methods, method);
+ return canonicalize(committedMethods, methods, method);
}
public DexMethod createMethod(DexType holder, DexProto proto, String name) {
@@ -3530,7 +3561,7 @@
DexMethod rewrittenTarget) {
DexMethodHandle methodHandle =
new DexMethodHandle(type, fieldOrMethod, isInterface, rewrittenTarget);
- return canonicalize(methodHandles, methodHandle);
+ return canonicalize(committedMethodHandles, methodHandles, methodHandle);
}
public DexCallSite createCallSite(
@@ -3629,25 +3660,53 @@
@Deprecated
synchronized public void forAllTypes(Consumer<DexType> f) {
- new ArrayList<>(types.values()).forEach(f);
+ List<DexType> allTypes = new ArrayList<>(committedTypes.values());
+ allTypes.addAll(types.values());
+ allTypes.forEach(f);
}
public void gc() {
markers = new WeakHashMap<>(markers);
+ methodHandles = new WeakHashMap<>(methodHandles);
strings = new WeakHashMap<>(strings);
types = new WeakHashMap<>(types);
fields = new WeakHashMap<>(fields);
protos = new WeakHashMap<>(protos);
methods = new WeakHashMap<>(methods);
- methodHandles = new WeakHashMap<>(methodHandles);
+ committedMethodHandles = new WeakHashMap<>(committedMethodHandles);
+ committedStrings = new WeakHashMap<>(committedStrings);
+ committedTypes = new WeakHashMap<>(committedTypes);
+ committedFields = new WeakHashMap<>(committedFields);
+ committedProtos = new WeakHashMap<>(committedProtos);
+ committedMethods = new WeakHashMap<>(committedMethods);
System.gc();
System.gc();
markers = new ConcurrentHashMap<>(markers);
+ methodHandles = new ConcurrentHashMap<>(methodHandles);
strings = new ConcurrentHashMap<>(strings);
types = new ConcurrentHashMap<>(types);
fields = new ConcurrentHashMap<>(fields);
protos = new ConcurrentHashMap<>(protos);
methods = new ConcurrentHashMap<>(methods);
- methodHandles = new ConcurrentHashMap<>(methodHandles);
+ committedMethodHandles = new HashMap<>(committedMethodHandles);
+ committedStrings = new HashMap<>(committedStrings);
+ committedTypes = new HashMap<>(committedTypes);
+ committedFields = new HashMap<>(committedFields);
+ committedProtos = new HashMap<>(committedProtos);
+ committedMethods = new HashMap<>(committedMethods);
+ }
+
+ public void commitPendingItems() {
+ commitPendingItems(committedMethodHandles, methodHandles);
+ commitPendingItems(committedStrings, strings);
+ commitPendingItems(committedTypes, types);
+ commitPendingItems(committedFields, fields);
+ commitPendingItems(committedProtos, protos);
+ commitPendingItems(committedMethods, methods);
+ }
+
+ private static <K, V> void commitPendingItems(Map<K, V> committed, Map<K, V> pending) {
+ committed.putAll(pending);
+ pending.clear();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index ba87f0c..234295e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -481,21 +481,6 @@
return dexItemFactory.createType(newDesc);
}
- // Similar to the method above, but performs a lookup only, allowing to use
- // this method also after strings are sorted in the ApplicationWriter.
- public DexType lookupBaseType(DexItemFactory dexItemFactory) {
- int leadingSquareBrackets = getNumberOfLeadingSquareBrackets();
- if (leadingSquareBrackets == 0) {
- return this;
- }
- DexString newDesc =
- dexItemFactory.lookupString(
- descriptor.length() - leadingSquareBrackets,
- Arrays.copyOfRange(
- descriptor.content, leadingSquareBrackets, descriptor.content.length));
- return dexItemFactory.lookupType(newDesc);
- }
-
public DexType replaceBaseType(DexType newBase, DexItemFactory dexItemFactory) {
assert this.isArrayType();
assert !newBase.isArrayType();
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 85403b4..869e6ac 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4863,6 +4863,14 @@
timing.begin("Compute fixpoint #" + round++);
long numberOfLiveItems = getNumberOfLiveItems();
+ // During the initial round of tree shaking we concurrently parse the code objects. Commit
+ // dex items before every wave to minimize synchronization overhead.
+ if (mode.isInitialTreeShaking()) {
+ timing.begin("Commit pending dex items");
+ appView.dexItemFactory().commitPendingItems();
+ timing.end();
+ }
+
timing.begin("Process worklist");
worklist.process(timing);
timing.end();