Bypass clinit for inlining of newBuilder() methods in proto lite
Change-Id: Idb92e59886bb0b63c5a7ec1275640f1475a43e0a
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 988bf75..0acef70 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -560,6 +560,11 @@
return lookupTarget(directMethods, method);
}
+ /** Find direct method in this class matching {@param predicate}. */
+ public DexEncodedMethod lookupDirectMethod(Predicate<DexEncodedMethod> predicate) {
+ return PredicateUtils.findFirst(directMethods, predicate);
+ }
+
/** Find virtual method in this class matching {@param method}. */
public DexEncodedMethod lookupVirtualMethod(DexMethod method) {
return lookupTarget(virtualMethods, method);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 3a866ef..0e8da38 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -36,8 +36,9 @@
public static void addInliningHeuristicsForBuilderInlining(
AppView<? extends AppInfoWithSubtyping> appView,
Set<DexMethod> alwaysInline,
- Set<DexMethod> neverInline) {
- new RootSetExtension(appView, alwaysInline, neverInline).extend();
+ Set<DexMethod> neverInline,
+ Set<DexMethod> bypassClinitforInlining) {
+ new RootSetExtension(appView, alwaysInline, neverInline, bypassClinitforInlining).extend();
}
private static class RootSetExtension {
@@ -47,15 +48,18 @@
private final Set<DexMethod> alwaysInline;
private final Set<DexMethod> neverInline;
+ private final Set<DexMethod> bypassClinitforInlining;
RootSetExtension(
AppView<? extends AppInfoWithSubtyping> appView,
Set<DexMethod> alwaysInline,
- Set<DexMethod> neverInline) {
+ Set<DexMethod> neverInline,
+ Set<DexMethod> bypassClinitforInlining) {
this.appView = appView;
this.references = appView.protoShrinker().references;
this.alwaysInline = alwaysInline;
this.neverInline = neverInline;
+ this.bypassClinitforInlining = bypassClinitforInlining;
}
void extend() {
@@ -64,12 +68,27 @@
neverInlineIsInitializedFromGeneratedMessageLite();
// * extends GeneratedMessageLite heuristics.
+ bypassClinitforInliningNewBuilderMethods();
alwaysInlineDynamicMethodFromGeneratedMessageLiteImplementations();
// GeneratedMessageLite$Builder heuristics.
alwaysInlineBuildPartialFromGeneratedMessageLiteBuilder();
}
+ private void bypassClinitforInliningNewBuilderMethods() {
+ for (DexType type : appView.appInfo().subtypes(references.generatedMessageLiteType)) {
+ DexProgramClass clazz = appView.definitionFor(type).asProgramClass();
+ if (clazz != null) {
+ DexEncodedMethod newBuilderMethod =
+ clazz.lookupDirectMethod(
+ method -> method.method.name == references.newBuilderMethodName);
+ if (newBuilderMethod != null) {
+ bypassClinitforInlining.add(newBuilderMethod.method);
+ }
+ }
+ }
+ }
+
private void alwaysInlineBuildPartialFromGeneratedMessageLiteBuilder() {
alwaysInline.add(references.generatedMessageLiteBuilderMethods.buildPartialMethod);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
index 0b26a38..e8967b4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -30,6 +30,7 @@
public final DexString dynamicMethodName;
public final DexString findLiteExtensionByNumberName;
+ public final DexString newBuilderMethodName;
public final DexProto dynamicMethodProto;
public final DexProto findLiteExtensionByNumberProto;
@@ -62,6 +63,7 @@
// Names.
dynamicMethodName = factory.createString("dynamicMethod");
findLiteExtensionByNumberName = factory.createString("findLiteExtensionByNumber");
+ newBuilderMethodName = factory.createString("newBuilder");
// Protos.
dynamicMethodProto =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index b43a294..6b7c389 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -185,6 +185,10 @@
return true;
}
+ if (appView.rootSet().bypassClinitForInlining.contains(target.method)) {
+ return true;
+ }
+
whyAreYouNotInliningReporter.reportMustTriggerClassInitialization();
return false;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 4cacde6..d16033f 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import static com.android.tools.r8.graph.GraphLense.rewriteReferenceKeys;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
@@ -57,7 +56,6 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
-import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -74,6 +72,7 @@
private final Set<DexMethod> alwaysInline = Sets.newIdentityHashSet();
private final Set<DexMethod> forceInline = Sets.newIdentityHashSet();
private final Set<DexMethod> neverInline = Sets.newIdentityHashSet();
+ private final Set<DexMethod> bypassClinitforInlining = Sets.newIdentityHashSet();
private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet();
private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet();
private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet();
@@ -283,7 +282,7 @@
}
if (appView.options().protoShrinking().enableGeneratedMessageLiteBuilderShrinking) {
GeneratedMessageLiteBuilderShrinker.addInliningHeuristicsForBuilderInlining(
- appView, alwaysInline, neverInline);
+ appView, alwaysInline, neverInline, bypassClinitforInlining);
}
assert Sets.intersection(neverInline, alwaysInline).isEmpty()
&& Sets.intersection(neverInline, forceInline).isEmpty()
@@ -297,6 +296,7 @@
alwaysInline,
forceInline,
neverInline,
+ bypassClinitforInlining,
whyAreYouNotInlining,
keepParametersWithConstantValue,
keepUnusedArguments,
@@ -1058,6 +1058,7 @@
public final Set<DexMethod> alwaysInline;
public final Set<DexMethod> forceInline;
public final Set<DexMethod> neverInline;
+ public final Set<DexMethod> bypassClinitForInlining;
public final Set<DexMethod> whyAreYouNotInlining;
public final Set<DexMethod> keepConstantArguments;
public final Set<DexMethod> keepUnusedArguments;
@@ -1082,6 +1083,7 @@
Set<DexMethod> alwaysInline,
Set<DexMethod> forceInline,
Set<DexMethod> neverInline,
+ Set<DexMethod> bypassClinitForInlining,
Set<DexMethod> whyAreYouNotInlining,
Set<DexMethod> keepConstantArguments,
Set<DexMethod> keepUnusedArguments,
@@ -1103,6 +1105,7 @@
this.alwaysInline = Collections.unmodifiableSet(alwaysInline);
this.forceInline = Collections.unmodifiableSet(forceInline);
this.neverInline = neverInline;
+ this.bypassClinitForInlining = bypassClinitForInlining;
this.whyAreYouNotInlining = whyAreYouNotInlining;
this.keepConstantArguments = keepConstantArguments;
this.keepUnusedArguments = keepUnusedArguments;
@@ -1137,15 +1140,6 @@
}
}
- private static <T extends DexReference, S> Map<T, Map<T, S>> rewriteDependentReferenceKeys(
- Map<T, Map<T, S>> original, Function<T, T> rewrite) {
- Map<T, Map<T, S>> result = new IdentityHashMap<>();
- for (T item : original.keySet()) {
- result.put(rewrite.apply(item), rewriteReferenceKeys(original.get(item), rewrite));
- }
- return result;
- }
-
void addConsequentRootSet(ConsequentRootSet consequentRootSet) {
neverInline.addAll(consequentRootSet.neverInline);
neverClassInline.addAll(consequentRootSet.neverClassInline);