Version 2.1.7-r3
Cherry pick: Update synthesized $load method names
CL: https://r8-review.googlesource.com/c/r8/+/51402
Cherry pick: Workaround for non-determinism in service loader rewriter
CL: https://r8-review.googlesource.com/c/r8/+/51384
Cherry pick: Update ServiceLoaderRewriter to synchronize on synthetic clazz creation
CL: https://r8-review.googlesource.com/c/r8/+/50340
Cherry pick: Use AtomicInteger for increment synthesized service-loader methods
CL: https://r8-review.googlesource.com/c/r8/+/48420
Bug: 148929520
Bug: 153127674
Bug: 156054499
Bug: 162704239
Change-Id: I09a14a24d160338f20c0b7b972738d42103377cb
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 0eb833c..311ebc0 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.1.7-r2";
+ public static final String LABEL = "2.1.7-r3";
private Version() {
}
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 8cb71bb..b3e26f1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import static com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement.computeLeastUpperBoundOfInterfaces;
+import static com.android.tools.r8.ir.optimize.ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME;
import static com.google.common.base.Predicates.alwaysTrue;
import com.android.tools.r8.dex.Constants;
@@ -352,7 +353,8 @@
createStaticallyKnownType(invocationHandlerDescriptor);
public final DexType proxyType = createStaticallyKnownType(proxyDescriptor);
public final DexType serviceLoaderType = createStaticallyKnownType(serviceLoaderDescriptor);
-
+ public final DexType serviceLoaderRewrittenClassType =
+ createStaticallyKnownType("L" + SERVICE_LOADER_CLASS_NAME + ";");
public final DexType serviceLoaderConfigurationErrorType =
createStaticallyKnownType(serviceLoaderConfigurationErrorDescriptor);
public final DexType listType = createStaticallyKnownType(listDescriptor);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
index 856baa9..506b981 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -30,11 +30,14 @@
import com.android.tools.r8.ir.desugar.ServiceLoaderSourceCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.IntBox;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
/**
* ServiceLoaderRewriter will attempt to rewrite calls on the form of: ServiceLoader.load(X.class,
@@ -67,8 +70,9 @@
public static final String SERVICE_LOADER_CLASS_NAME = "$$ServiceLoaderMethods";
private static final String SERVICE_LOADER_METHOD_PREFIX_NAME = "$load";
+ private static final int SERVICE_LOADER_METHOD_HASH_LENGTH = 7;
- private DexProgramClass synthesizedClass;
+ private AtomicReference<DexProgramClass> synthesizedClass = new AtomicReference<>();
private ConcurrentHashMap<DexType, DexEncodedMethod> synthesizedServiceLoaders =
new ConcurrentHashMap<>();
@@ -79,12 +83,13 @@
}
public DexProgramClass getSynthesizedClass() {
- return synthesizedClass;
+ return synthesizedClass.get();
}
public void rewrite(IRCode code) {
DexItemFactory factory = appView.dexItemFactory();
InstructionListIterator instructionIterator = code.instructionListIterator();
+ IntBox synthesizedLoadMethodCounter = new IntBox();
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
@@ -168,7 +173,9 @@
synthesizedServiceLoaders.computeIfAbsent(
constClass.getValue(),
service -> {
- DexEncodedMethod addedMethod = createSynthesizedMethod(service, classes);
+ DexEncodedMethod addedMethod =
+ createSynthesizedMethod(
+ service, classes, code.method, synthesizedLoadMethodCounter);
if (appView.options().isGeneratingClassFiles()) {
addedMethod.upgradeClassFileVersion(code.method.getClassFileVersion());
}
@@ -180,55 +187,86 @@
}
}
- private DexEncodedMethod createSynthesizedMethod(DexType serviceType, List<DexClass> classes) {
- DexType serviceLoaderType =
- appView.dexItemFactory().createType("L" + SERVICE_LOADER_CLASS_NAME + ";");
- if (synthesizedClass == null) {
- assert !appView.options().encodeChecksums;
- ChecksumSupplier checksumSupplier = DexProgramClass::invalidChecksumRequest;
- synthesizedClass =
- new DexProgramClass(
- serviceLoaderType,
- null,
- new SynthesizedOrigin("Service Loader desugaring", getClass()),
- ClassAccessFlags.fromDexAccessFlags(
- Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
- appView.dexItemFactory().objectType,
- DexTypeList.empty(),
- appView.dexItemFactory().createString("ServiceLoader"),
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY, // Static fields.
- DexEncodedField.EMPTY_ARRAY, // Instance fields.
- DexEncodedMethod.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
- appView.dexItemFactory().getSkipNameValidationForTesting(),
- checksumSupplier);
- appView.appInfo().addSynthesizedClass(synthesizedClass);
- }
+ private DexEncodedMethod createSynthesizedMethod(
+ DexType serviceType,
+ List<DexClass> classes,
+ DexEncodedMethod context,
+ IntBox synthesizedLoadMethodCounter) {
+ DexProgramClass synthesizedClass = getOrSetSynthesizedClass();
+ String hashCode = Integer.toString(context.method.hashCode());
+ String methodNamePrefix =
+ SERVICE_LOADER_METHOD_PREFIX_NAME
+ + "$"
+ + StringUtils.replaceAll(context.method.holder.toSourceString(), ".", "$")
+ + "$"
+ + (context.isInitializer()
+ ? (context.isClassInitializer() ? "$clinit" : "$init")
+ : context.method.name.toSourceString())
+ + "$"
+ + hashCode.substring(0, Math.min(SERVICE_LOADER_METHOD_HASH_LENGTH, hashCode.length()))
+ + "$";
DexProto proto = appView.dexItemFactory().createProto(appView.dexItemFactory().iteratorType);
- DexMethod method =
- appView
- .dexItemFactory()
- .createMethod(
- serviceLoaderType,
- proto,
- SERVICE_LOADER_METHOD_PREFIX_NAME + synthesizedServiceLoaders.size());
- MethodAccessFlags methodAccess =
- MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_STATIC, false);
- DexEncodedMethod encodedMethod =
- new DexEncodedMethod(
- method,
- methodAccess,
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- ServiceLoaderSourceCode.generate(serviceType, classes, appView.dexItemFactory()),
- true);
- synthesizedClass.addDirectMethod(encodedMethod);
- return encodedMethod;
+ synchronized (synthesizedClass) {
+ DexMethod methodReference;
+ do {
+ methodReference =
+ appView
+ .dexItemFactory()
+ .createMethod(
+ appView.dexItemFactory().serviceLoaderRewrittenClassType,
+ proto,
+ methodNamePrefix + "$" + synthesizedLoadMethodCounter.getAndIncrement());
+ } while (synthesizedClass.lookupMethod(methodReference) != null);
+ DexEncodedMethod method =
+ new DexEncodedMethod(
+ methodReference,
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC, false),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ ServiceLoaderSourceCode.generate(serviceType, classes, appView.dexItemFactory()),
+ true);
+ synthesizedClass.addDirectMethod(method);
+ return method;
+ }
+ }
+
+ private DexProgramClass getOrSetSynthesizedClass() {
+ if (synthesizedClass.get() != null) {
+ return synthesizedClass.get();
+ }
+ assert !appView.options().encodeChecksums;
+ ChecksumSupplier checksumSupplier = DexProgramClass::invalidChecksumRequest;
+ DexProgramClass clazz =
+ synthesizedClass.updateAndGet(
+ existingClazz -> {
+ if (existingClazz != null) {
+ return existingClazz;
+ }
+ return new DexProgramClass(
+ appView.dexItemFactory().serviceLoaderRewrittenClassType,
+ null,
+ new SynthesizedOrigin("Service Loader desugaring", getClass()),
+ ClassAccessFlags.fromDexAccessFlags(
+ Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
+ appView.dexItemFactory().objectType,
+ DexTypeList.empty(),
+ appView.dexItemFactory().createString("ServiceLoader"),
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY, // Static fields.
+ DexEncodedField.EMPTY_ARRAY, // Instance fields.
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ checksumSupplier);
+ });
+ assert clazz != null;
+ appView.appInfo().addSynthesizedClass(clazz);
+ return clazz;
}
/**
diff --git a/src/main/java/com/android/tools/r8/utils/IntBox.java b/src/main/java/com/android/tools/r8/utils/IntBox.java
new file mode 100644
index 0000000..ebb92ca
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/IntBox.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, 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.utils;
+
+public class IntBox {
+
+ private int value;
+
+ public IntBox() {}
+
+ public IntBox(int initialValue) {
+ set(initialValue);
+ }
+
+ public int get() {
+ return value;
+ }
+
+ public int getAndIncrement() {
+ return value++;
+ }
+
+ public void increment() {
+ value++;
+ }
+
+ public void set(int value) {
+ this.value = value;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index fdf7e98..02e83de 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -11,6 +11,8 @@
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class StringUtils {
public static char[] EMPTY_CHAR_ARRAY = {};
@@ -327,4 +329,8 @@
}
return string.length();
}
+
+ public static String replaceAll(String subject, String target, String replacement) {
+ return subject.replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement));
+ }
}