Remove startup base feature split
Change-Id: I829137591c70444695fbfed86f6d02297cf20f8b
diff --git a/src/main/java/com/android/tools/r8/FeatureSplit.java b/src/main/java/com/android/tools/r8/FeatureSplit.java
index 08b1657..03f99fa 100644
--- a/src/main/java/com/android/tools/r8/FeatureSplit.java
+++ b/src/main/java/com/android/tools/r8/FeatureSplit.java
@@ -39,19 +39,6 @@
}
};
- public static final FeatureSplit BASE_STARTUP =
- new FeatureSplit(null, null, null, null) {
- @Override
- public boolean isBase() {
- return true;
- }
-
- @Override
- public boolean isStartupBase() {
- return true;
- }
- };
-
private ProgramConsumer programConsumer;
private final List<ProgramResourceProvider> programResourceProviders;
private final AndroidResourceProvider androidResourceProvider;
@@ -72,10 +59,6 @@
return false;
}
- public boolean isStartupBase() {
- return false;
- }
-
void internalSetProgramConsumer(ProgramConsumer consumer) {
this.programConsumer = consumer;
}
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
index 6d0b3e6..0e79887 100644
--- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -14,10 +14,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramDefinition;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
@@ -106,18 +104,15 @@
public Map<FeatureSplit, Set<DexProgramClass>> getFeatureSplitClasses(
Set<DexProgramClass> classes, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return getFeatureSplitClasses(
- classes, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
+ return getFeatureSplitClasses(classes, appView.getSyntheticItems());
}
public Map<FeatureSplit, Set<DexProgramClass>> getFeatureSplitClasses(
Set<DexProgramClass> classes,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
Map<FeatureSplit, Set<DexProgramClass>> result = new IdentityHashMap<>();
for (DexProgramClass clazz : classes) {
- FeatureSplit featureSplit = getFeatureSplit(clazz, options, startupProfile, syntheticItems);
+ FeatureSplit featureSplit = getFeatureSplit(clazz, syntheticItems);
if (featureSplit != null && !featureSplit.isBase()) {
result.computeIfAbsent(featureSplit, ignore -> Sets.newIdentityHashSet()).add(clazz);
}
@@ -127,46 +122,32 @@
public FeatureSplit getFeatureSplit(
ProgramDefinition definition, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return getFeatureSplit(
- definition, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
+ return getFeatureSplit(definition, appView.getSyntheticItems());
}
public FeatureSplit getFeatureSplit(
ProgramDefinition definition,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- return getFeatureSplit(definition.getContextType(), options, startupProfile, syntheticItems);
+ return getFeatureSplit(definition.getContextType(), syntheticItems);
}
public FeatureSplit getFeatureSplit(
DexType type, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return getFeatureSplit(
- type, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
+ return getFeatureSplit(type, appView.getSyntheticItems());
}
public FeatureSplit getFeatureSplit(
DexType type,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
if (syntheticItems == null) {
// Called from AndroidApp.dumpProgramResources().
- assert startupProfile.isEmpty();
return classToFeatureSplitMap.getOrDefault(type, FeatureSplit.BASE);
}
FeatureSplit feature;
boolean isSynthetic = syntheticItems.isSyntheticClass(type);
if (isSynthetic) {
if (syntheticItems.isSyntheticOfKind(type, k -> k.ENUM_UNBOXING_SHARED_UTILITY_CLASS)) {
- // Use the startup base if there is one, such that we don't merge non-startup classes with
- // the shared utility class in case it is used during startup. The use of base startup
- // allows for merging startup classes with the shared utility class, however, which could be
- // bad for startup if the shared utility class is not used during startup.
- return startupProfile.isEmpty()
- || options.getStartupOptions().isStartupBoundaryOptimizationsEnabled()
- ? FeatureSplit.BASE
- : FeatureSplit.BASE_STARTUP;
+ return FeatureSplit.BASE;
}
feature = syntheticItems.getContextualFeatureSplitOrDefault(type, FeatureSplit.BASE);
// Verify the synthetic is not in the class to feature split map or the synthetic has the same
@@ -176,10 +157,7 @@
feature = classToFeatureSplitMap.getOrDefault(type, FeatureSplit.BASE);
}
if (feature.isBase()) {
- return !startupProfile.isStartupClass(type)
- || options.getStartupOptions().isStartupBoundaryOptimizationsEnabled()
- ? FeatureSplit.BASE
- : FeatureSplit.BASE_STARTUP;
+ return FeatureSplit.BASE;
}
return feature;
}
@@ -192,17 +170,9 @@
}
public boolean isInBase(
- DexProgramClass clazz, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return isInBase(
- clazz, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
- }
-
- public boolean isInBase(
DexProgramClass clazz,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- return getFeatureSplit(clazz, options, startupProfile, syntheticItems).isBase();
+ return getFeatureSplit(clazz, syntheticItems).isBase();
}
public boolean isInBaseOrSameFeatureAs(
@@ -212,19 +182,14 @@
return isInBaseOrSameFeatureAs(
clazz,
context,
- appView.options(),
- appView.getStartupProfile(),
appView.getSyntheticItems());
}
public boolean isInBaseOrSameFeatureAs(
ProgramDefinition clazz,
ProgramDefinition context,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- return isInBaseOrSameFeatureAs(
- clazz.getContextType(), context, options, startupProfile, syntheticItems);
+ return isInBaseOrSameFeatureAs(clazz.getContextType(), context, syntheticItems);
}
public boolean isInBaseOrSameFeatureAs(
@@ -234,60 +199,21 @@
return isInBaseOrSameFeatureAs(
clazz,
context,
- appView.options(),
- appView.getStartupProfile(),
appView.getSyntheticItems());
}
public boolean isInBaseOrSameFeatureAs(
DexType clazz,
ProgramDefinition context,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- FeatureSplit split = getFeatureSplit(clazz, options, startupProfile, syntheticItems);
- return split.isBase()
- || split == getFeatureSplit(context, options, startupProfile, syntheticItems);
+ FeatureSplit split = getFeatureSplit(clazz, syntheticItems);
+ return split.isBase() || split == getFeatureSplit(context, syntheticItems);
}
public boolean isInFeature(
DexProgramClass clazz,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- return !isInBase(clazz, options, startupProfile, syntheticItems);
- }
-
- public boolean isInSameFeatureOrBothInSameBase(
- ProgramMethod a, ProgramMethod b, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return isInSameFeatureOrBothInSameBase(
- a, b, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
- }
-
- public boolean isInSameFeatureOrBothInSameBase(
- ProgramMethod a,
- ProgramMethod b,
- InternalOptions options,
- StartupProfile startupProfile,
- SyntheticItems syntheticItems) {
- return isInSameFeatureOrBothInSameBase(
- a.getHolder(), b.getHolder(), options, startupProfile, syntheticItems);
- }
-
- public boolean isInSameFeatureOrBothInSameBase(
- DexProgramClass a, DexProgramClass b, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return isInSameFeatureOrBothInSameBase(
- a, b, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
- }
-
- public boolean isInSameFeatureOrBothInSameBase(
- DexProgramClass a,
- DexProgramClass b,
- InternalOptions options,
- StartupProfile startupProfile,
- SyntheticItems syntheticItems) {
- return getFeatureSplit(a, options, startupProfile, syntheticItems)
- == getFeatureSplit(b, options, startupProfile, syntheticItems);
+ return !isInBase(clazz, syntheticItems);
}
public ClassToFeatureSplitMap rewrittenWithLens(GraphLens lens, Timing timing) {
@@ -298,7 +224,7 @@
Map<DexType, FeatureSplit> rewrittenClassToFeatureSplitMap = new IdentityHashMap<>();
classToFeatureSplitMap.forEach(
(type, featureSplit) -> {
- DexType rewrittenType = lens.lookupType(type);
+ DexType rewrittenType = lens.lookupType(type, GraphLens.getIdentityLens());
if (rewrittenType.isIntType()) {
// The type was removed by enum unboxing.
return;
@@ -332,8 +258,6 @@
public static boolean isInFeature(
DexProgramClass clazz, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return getMap(appView)
- .isInFeature(
- clazz, appView.options(), appView.getStartupProfile(), appView.getSyntheticItems());
+ return getMap(appView).isInFeature(clazz, appView.getSyntheticItems());
}
}
diff --git a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
index 542c1ab..81d3fe6 100644
--- a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
+++ b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
@@ -12,10 +12,7 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
import com.android.tools.r8.synthesis.SyntheticItems;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.OptionalBool;
public class FeatureSplitBoundaryOptimizationUtils {
@@ -43,11 +40,8 @@
DexProgramClass accessedClass,
ProgramDefinition accessor,
ClassToFeatureSplitMap classToFeatureSplitMap,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
- return classToFeatureSplitMap.isInBaseOrSameFeatureAs(
- accessedClass, accessor, options, startupProfile, syntheticItems);
+ return classToFeatureSplitMap.isInBaseOrSameFeatureAs(accessedClass, accessor, syntheticItems);
}
public static boolean isSafeForInlining(
@@ -60,42 +54,11 @@
// First guarantee that we don't cross any actual feature split boundaries.
if (!calleeFeatureSplit.isBase()) {
- if (calleeFeatureSplit != callerFeatureSplit) {
- return false;
- }
- }
-
- // Next perform startup checks.
- if (!callee.getOptimizationInfo().forceInline()) {
- StartupProfile startupProfile = appView.getStartupProfile();
- OptionalBool callerIsStartupMethod = isStartupMethod(caller, startupProfile);
- if (callerIsStartupMethod.isTrue()) {
- // If the caller is a startup method, then only allow inlining if the callee is also a
- // startup method.
- if (isStartupMethod(callee, startupProfile).isFalse()) {
- return false;
- }
- } else if (callerIsStartupMethod.isFalse()) {
- // If the caller is not a startup method, then only allow inlining if the caller is not a
- // startup class or the callee is a startup class.
- if (startupProfile.isStartupClass(caller.getHolderType())
- && !startupProfile.isStartupClass(callee.getHolderType())) {
- return false;
- }
- }
+ return calleeFeatureSplit == callerFeatureSplit;
}
return true;
}
- private static OptionalBool isStartupMethod(ProgramMethod method, StartupProfile startupProfile) {
- if (method.getDefinition().isD8R8Synthesized()) {
- // Due to inadequate rewriting of the startup list during desugaring, we do not give an
- // accurate result in this case.
- return OptionalBool.unknown();
- }
- return OptionalBool.of(startupProfile.containsMethodRule(method.getReference()));
- }
-
public static boolean isSafeForVerticalClassMerging(
DexProgramClass sourceClass,
DexProgramClass targetClass,
@@ -107,19 +70,9 @@
// First guarantee that we don't cross any actual feature split boundaries.
if (targetFeatureSplit.isBase()) {
assert sourceFeatureSplit.isBase() : "Unexpected class in base that inherits from feature";
+ return true;
} else {
- if (sourceFeatureSplit != targetFeatureSplit) {
- return false;
- }
+ return sourceFeatureSplit == targetFeatureSplit;
}
-
- // If the source class is a startup class then require that the target class is also a startup
- // class.
- StartupProfile startupProfile = appView.getStartupProfile();
- if (startupProfile.isStartupClass(sourceClass.getType())
- && !startupProfile.isStartupClass(targetClass.getType())) {
- return false;
- }
- return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AccessControl.java b/src/main/java/com/android/tools/r8/graph/AccessControl.java
index 3819be8..2d5b68a 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessControl.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessControl.java
@@ -5,9 +5,7 @@
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.features.FeatureSplitBoundaryOptimizationUtils;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
import com.android.tools.r8.synthesis.SyntheticItems;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
/**
@@ -26,8 +24,6 @@
clazz,
context,
appView.appInfo().getClassToFeatureSplitMap(),
- appView.options(),
- appView.getStartupProfile(),
appView.getSyntheticItems());
}
@@ -35,8 +31,6 @@
DexClass clazz,
Definition context,
ClassToFeatureSplitMap classToFeatureSplitMap,
- InternalOptions options,
- StartupProfile startupProfile,
SyntheticItems syntheticItems) {
if (!clazz.isPublic() && !clazz.getType().isSamePackage(context.getContextType())) {
return OptionalBool.FALSE;
@@ -47,8 +41,6 @@
clazz.asProgramClass(),
context.asProgramDefinition(),
classToFeatureSplitMap,
- options,
- startupProfile,
syntheticItems)) {
return OptionalBool.UNKNOWN;
}
@@ -59,13 +51,11 @@
static OptionalBool isMemberAccessible(
SuccessfulMemberResolutionResult<?, ?> resolutionResult,
Definition context,
- AppView<?> appView,
AppInfoWithClassHierarchy appInfo) {
return isMemberAccessible(
resolutionResult.getResolutionPair(),
resolutionResult.getInitialResolutionHolder(),
context,
- appView,
appInfo);
}
@@ -74,15 +64,13 @@
Definition initialResolutionContext,
Definition context,
AppView<? extends AppInfoWithClassHierarchy> appView) {
- return isMemberAccessible(
- member, initialResolutionContext, context, appView, appView.appInfo());
+ return isMemberAccessible(member, initialResolutionContext, context, appView.appInfo());
}
static OptionalBool isMemberAccessible(
DexClassAndMember<?, ?> member,
Definition initialResolutionContext,
Definition context,
- AppView<?> appView,
AppInfoWithClassHierarchy appInfo) {
AccessFlags<?> memberFlags = member.getDefinition().getAccessFlags();
OptionalBool classAccessibility =
@@ -90,8 +78,6 @@
initialResolutionContext.getContextClass(),
context,
appInfo.getClassToFeatureSplitMap(),
- appInfo.options(),
- appView.getStartupProfile(),
appInfo.getSyntheticItems());
if (classAccessibility.isFalse()) {
return OptionalBool.FALSE;
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
index a383253..6bae976 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -203,7 +203,7 @@
@Override
public OptionalBool isAccessibleFrom(
ProgramDefinition context, AppView<?> appView, AppInfoWithClassHierarchy appInfo) {
- return AccessControl.isMemberAccessible(this, context, appView, appInfo);
+ return AccessControl.isMemberAccessible(this, context, appInfo);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 710666b..03b3932 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -501,7 +501,7 @@
@Override
public OptionalBool isAccessibleFrom(
ProgramDefinition context, AppView<?> appView, AppInfoWithClassHierarchy appInfo) {
- return AccessControl.isMemberAccessible(this, context, appView, appInfo);
+ return AccessControl.isMemberAccessible(this, context, appInfo);
}
@Override
@@ -1484,8 +1484,6 @@
clazz,
context,
appInfo.getClassToFeatureSplitMap(),
- appView.options(),
- appView.getStartupProfile(),
appView.getSyntheticItems())
.isPossiblyFalse())),
method -> {
@@ -1493,7 +1491,7 @@
DexClassAndMethod classAndMethod = DexClassAndMethod.create(holder, method);
seenNoAccess.or(
AccessControl.isMemberAccessible(
- classAndMethod, initialResolutionHolder, context, appView, appInfo)
+ classAndMethod, initialResolutionHolder, context, appInfo)
.isPossiblyFalse());
});
return seenNoAccess.get();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index 8d63fb1..da96bcf 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -60,6 +60,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.SameNestHost;
import com.android.tools.r8.horizontalclassmerging.policies.SamePackageForNonGlobalMergeSynthetic;
import com.android.tools.r8.horizontalclassmerging.policies.SameParentClass;
+import com.android.tools.r8.horizontalclassmerging.policies.SameStartupPartition;
import com.android.tools.r8.horizontalclassmerging.policies.SyntheticItemsPolicy;
import com.android.tools.r8.horizontalclassmerging.policies.VerifyMultiClassPolicyAlwaysSatisfied;
import com.android.tools.r8.horizontalclassmerging.policies.VerifySingleClassPolicyAlwaysSatisfied;
@@ -289,6 +290,7 @@
new CheckAbstractClasses(appView),
new NoClassAnnotationCollisions(),
new SameFeatureSplit(appView),
+ new SameStartupPartition(appView),
new SameInstanceFields(appView, mode),
new SameMainDexGroup(appView),
new SameNestHost(appView),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameStartupPartition.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameStartupPartition.java
new file mode 100644
index 0000000..b04ed19
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameStartupPartition.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2023, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy;
+import com.android.tools.r8.horizontalclassmerging.policies.SameStartupPartition.StartupPartition;
+import com.android.tools.r8.profile.startup.StartupOptions;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+
+public class SameStartupPartition extends MultiClassSameReferencePolicy<StartupPartition> {
+
+ public enum StartupPartition {
+ STARTUP,
+ POST_STARTUP
+ }
+
+ private final StartupOptions startupOptions;
+ private final StartupProfile startupProfile;
+
+ public SameStartupPartition(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ this.startupOptions = appView.options().getStartupOptions();
+ this.startupProfile = appView.getStartupProfile();
+ }
+
+ @Override
+ public StartupPartition getMergeKey(DexProgramClass clazz) {
+ return startupProfile.isStartupClass(clazz.getType())
+ ? StartupPartition.STARTUP
+ : StartupPartition.POST_STARTUP;
+ }
+
+ @Override
+ public boolean shouldSkipPolicy() {
+ return startupProfile.isEmpty() || startupOptions.isStartupBoundaryOptimizationsEnabled();
+ }
+
+ @Override
+ public String getName() {
+ return "SameStartupPartition";
+ }
+}
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 603bcc6..1ed5f9a 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
@@ -48,6 +48,7 @@
import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
import com.android.tools.r8.ir.optimize.inliner.InliningReasonStrategy;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
+import com.android.tools.r8.profile.startup.optimization.StartupBoundaryOptimizationUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.AssumeInfoCollection;
import com.android.tools.r8.shaking.MainDexInfo;
@@ -176,6 +177,11 @@
return false;
}
+ if (!StartupBoundaryOptimizationUtils.isSafeForInlining(method, singleTarget, appView)) {
+ whyAreYouNotInliningReporter.reportInliningAcrossStartupBoundary();
+ return false;
+ }
+
// Abort inlining attempt if method -> target access is not right.
if (resolutionResult.isAccessibleFrom(method, appView).isPossiblyFalse()) {
whyAreYouNotInliningReporter.reportInaccessible();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
index d3d3735..1f116b4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
@@ -69,6 +69,9 @@
public void reportInliningAcrossFeatureSplit() {}
@Override
+ public void reportInliningAcrossStartupBoundary() {}
+
+ @Override
public void reportInstructionBudgetIsExceeded() {}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
index 4bf931b..159128c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
@@ -76,6 +76,8 @@
public abstract void reportInliningAcrossFeatureSplit();
+ public abstract void reportInliningAcrossStartupBoundary();
+
public abstract void reportInstructionBudgetIsExceeded();
public abstract void reportInvalidDoubleInliningCandidate();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
index 05e2cb1..23391b7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -153,6 +153,11 @@
}
@Override
+ public void reportInliningAcrossStartupBoundary() {
+ report("cannot inline across startup/non-startup boundary.");
+ }
+
+ @Override
public void reportInstructionBudgetIsExceeded() {
report("caller's instruction budget is exceeded.");
}
diff --git a/src/main/java/com/android/tools/r8/profile/startup/optimization/StartupBoundaryOptimizationUtils.java b/src/main/java/com/android/tools/r8/profile/startup/optimization/StartupBoundaryOptimizationUtils.java
new file mode 100644
index 0000000..194f1dd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/startup/optimization/StartupBoundaryOptimizationUtils.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2023, 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.profile.startup.optimization;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+
+public class StartupBoundaryOptimizationUtils {
+
+ public static boolean isSafeForInlining(
+ ProgramMethod caller,
+ ProgramMethod callee,
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ StartupProfile startupProfile = appView.getStartupProfile();
+ if (startupProfile.isEmpty()
+ || appView.options().getStartupOptions().isStartupBoundaryOptimizationsEnabled()
+ || callee.getOptimizationInfo().forceInline()) {
+ return true;
+ }
+ // It is always OK to inline into a non-startup class.
+ if (!startupProfile.isStartupClass(caller.getHolderType())) {
+ return true;
+ }
+ // Otherwise the caller is a startup method or a post-startup method on a non-startup class. In
+ // either case, only allow inlining if the callee is defined on a startup class.
+ return startupProfile.isStartupClass(callee.getHolderType());
+ }
+
+ public static boolean isSafeForVerticalClassMerging(
+ DexProgramClass sourceClass,
+ DexProgramClass targetClass,
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ StartupProfile startupProfile = appView.getStartupProfile();
+ if (startupProfile.isEmpty()
+ || appView.options().getStartupOptions().isStartupBoundaryOptimizationsEnabled()) {
+ return true;
+ }
+ return !startupProfile.isStartupClass(sourceClass.getType())
+ || startupProfile.isStartupClass(targetClass.getType());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 41c19f5..8222389 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -39,7 +39,6 @@
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.SyntheticFinalization.Result;
@@ -609,25 +608,17 @@
private SynthesizingContext getSynthesizingContext(
ProgramDefinition context, AppView<?> appView) {
- InternalOptions options = appView.options();
if (appView.hasClassHierarchy()) {
AppInfoWithClassHierarchy appInfo = appView.appInfoWithClassHierarchy();
- return getSynthesizingContext(
- context, appInfo.getClassToFeatureSplitMap(), options, appView.getStartupProfile());
+ return getSynthesizingContext(context, appInfo.getClassToFeatureSplitMap());
}
return getSynthesizingContext(
- context,
- ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
- options,
- StartupProfile.empty());
+ context, ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap());
}
/** Used to find the synthesizing context for a new synthetic that is about to be created. */
private SynthesizingContext getSynthesizingContext(
- ProgramDefinition context,
- ClassToFeatureSplitMap featureSplits,
- InternalOptions options,
- StartupProfile startupProfile) {
+ ProgramDefinition context, ClassToFeatureSplitMap featureSplits) {
DexType contextType = context.getContextType();
SyntheticDefinition<?, ?, ?> existingDefinition = pending.definitions.get(contextType);
if (existingDefinition != null) {
@@ -643,8 +634,7 @@
.getContext();
}
// This context is not nested in an existing synthetic context so create a new "leaf" context.
- FeatureSplit featureSplit =
- featureSplits.getFeatureSplit(context, options, startupProfile, this);
+ FeatureSplit featureSplit = featureSplits.getFeatureSplit(context, this);
return SynthesizingContext.fromNonSyntheticInputContext(context, featureSplit);
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 8bbf801..adb0992 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -46,7 +46,6 @@
import com.android.tools.r8.profile.art.ArtProfileProvider;
import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.synthesis.SyntheticItems;
@@ -717,8 +716,7 @@
DexType type = options.dexItemFactory().createType(classDescriptor);
SyntheticItems syntheticItems = null;
FeatureSplit featureSplit =
- classToFeatureSplitMap.getFeatureSplit(
- type, options, StartupProfile.empty(), syntheticItems);
+ classToFeatureSplitMap.getFeatureSplit(type, syntheticItems);
if (featureSplit != null && !featureSplit.isBase()) {
return featureSplitArchiveOutputStreams.get(featureSplit);
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
index 983077e..e2bfb17 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.profile.startup.optimization.StartupBoundaryOptimizationUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.utils.Box;
@@ -105,6 +106,10 @@
sourceClass, targetClass, appView)) {
return false;
}
+ if (!StartupBoundaryOptimizationUtils.isSafeForVerticalClassMerging(
+ sourceClass, targetClass, appView)) {
+ return false;
+ }
if (appView.appServices().allServiceTypes().contains(sourceClass.getType())
&& appView.getKeepInfo(targetClass).isPinned(options)) {
return false;
diff --git a/src/test/java/com/android/tools/r8/startup/SingleCallerBridgeStartupTest.java b/src/test/java/com/android/tools/r8/startup/SingleCallerBridgeStartupTest.java
index 1cb68de..88d5f71 100644
--- a/src/test/java/com/android/tools/r8/startup/SingleCallerBridgeStartupTest.java
+++ b/src/test/java/com/android/tools/r8/startup/SingleCallerBridgeStartupTest.java
@@ -63,12 +63,12 @@
.inspect(
inspector -> {
// Assert that foo is not inlined.
- ClassSubject A = inspector.clazz(A.class);
- assertThat(A, isPresent());
- assertThat(A.uniqueMethodWithOriginalName("foo"), isPresent());
+ ClassSubject B = inspector.clazz(B.class);
+ assertThat(B, isPresent());
+ assertThat(B.uniqueMethodWithOriginalName("foo"), isPresent());
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A::foo", "A::foo");
+ .assertSuccessWithOutputLines("B::foo", "B::foo");
}
static class Main {
@@ -81,12 +81,8 @@
public static class A {
- private static void foo() {
- System.out.println("A::foo");
- }
-
private static void bar() {
- foo();
+ B.foo();
}
public static void callBarInStartup() {
@@ -97,4 +93,11 @@
bar();
}
}
+
+ public static class B {
+
+ static void foo() {
+ System.out.println("B::foo");
+ }
+ }
}