Restrict class inliner to maintain visible side-effects.
In the case of class inlining an object from a static field,
make sure that methods inlined do not modify the object state
as those updates could be visible to other accesses to the
object in the static field.
Bug: 160942326
Change-Id: I3088e56c8184a9b2e4a409e67284852b09ccc412
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
index 8d178a3..35eaaf5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
@@ -22,13 +22,16 @@
final OptionalBool returnsReceiver;
final boolean hasMonitorOnReceiver;
+ final boolean modifiesInstanceFields;
public ClassInlinerEligibilityInfo(
List<Pair<Invoke.Type, DexMethod>> callsReceiver,
OptionalBool returnsReceiver,
- boolean hasMonitorOnReceiver) {
+ boolean hasMonitorOnReceiver,
+ boolean modifiesInstanceFields) {
this.callsReceiver = callsReceiver;
this.returnsReceiver = returnsReceiver;
this.hasMonitorOnReceiver = hasMonitorOnReceiver;
+ this.modifiesInstanceFields = modifiesInstanceFields;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 72be050..3824962 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -1065,6 +1065,12 @@
// We will not be able to remove the monitor instruction afterwards.
return false;
}
+ if (eligibility.modifiesInstanceFields) {
+ // The static instance could be accessed from elsewhere. Therefore, we cannot
+ // allow side-effects to be removed and therefore cannot class inline method
+ // calls that modifies the instance.
+ return false;
+ }
}
// If the method returns receiver and the return value is actually
@@ -1215,8 +1221,8 @@
}
if (root.isStaticGet()) {
- // If we are class inlining a singleton instance from a static-get, then we don't the value of
- // the fields.
+ // If we are class inlining a singleton instance from a static-get, then we don't know
+ // the value of the fields.
if (parameterUsage.hasFieldRead) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 8a25765..cc24603 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -192,6 +192,7 @@
List<Pair<Invoke.Type, DexMethod>> callsReceiver = new ArrayList<>();
boolean seenSuperInitCall = false;
boolean seenMonitor = false;
+ boolean modifiesInstanceFields = false;
AliasedValueConfiguration configuration =
AssumeAndCheckCastAliasedValueConfiguration.getInstance();
@@ -220,6 +221,7 @@
if (isReceiverAlias.test(instancePutInstruction.value())) {
return;
}
+ modifiesInstanceFields = true;
}
DexField field = insn.asFieldInstruction().getField();
if (appView.appInfo().resolveField(field).isFailedOrUnknownResolution()) {
@@ -293,7 +295,8 @@
new ClassInlinerEligibilityInfo(
callsReceiver,
new ClassInlinerReceiverAnalysis(appView, definition, code).computeReturnsReceiver(),
- seenMonitor || synchronizedVirtualMethod));
+ seenMonitor || synchronizedVirtualMethod,
+ modifiesInstanceFields));
}
private void identifyParameterUsages(