Invalidate staticizing candidates whose references are not fixable.
Bug: 135172146, 119626580
Change-Id: I4d39dfaaebbf91d5c14df80dfc02c74f3a4ec717
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index d2a3838..cafc3bb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -98,6 +98,8 @@
}
private void finalEligibilityCheck() {
+ Set<Phi> visited = Sets.newIdentityHashSet();
+ Set<Phi> trivialPhis = Sets.newIdentityHashSet();
Iterator<Entry<DexType, CandidateInfo>> it =
classStaticizer.candidates.entrySet().iterator();
while (it.hasNext()) {
@@ -147,6 +149,63 @@
it.remove();
continue;
}
+
+ // CHECK: references to 'this' in instance methods are fixable.
+ boolean fixableThisPointer = true;
+ for (DexEncodedMethod method : candidateClass.methods()) {
+ if (method.isStatic() || factory().isConstructor(method.method)) {
+ continue;
+ }
+ IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
+ assert code != null;
+ Value thisValue = code.getThis();
+ assert thisValue != null;
+ visited.clear();
+ trivialPhis.clear();
+ boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfThis(
+ visited, thisValue.uniquePhiUsers(), thisValue, trivialPhis);
+ if (thisValue.numberOfPhiUsers() != 0 && !onlyHasTrivialPhis) {
+ fixableThisPointer = false;
+ break;
+ }
+ }
+ if (!fixableThisPointer) {
+ it.remove();
+ continue;
+ }
+
+ // CHECK: references to field read usages are fixable.
+ boolean fixableFieldReads = true;
+ for (DexEncodedMethod method : info.referencedFrom) {
+ IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
+ assert code != null;
+ List<StaticGet> singletonFieldReads =
+ Streams.stream(code.instructionIterator())
+ .filter(Instruction::isStaticGet)
+ .map(Instruction::asStaticGet)
+ .filter(get -> get.getField() == info.singletonField.field)
+ .collect(Collectors.toList());
+ boolean fixableFieldReadsPerUsage = true;
+ for (StaticGet read : singletonFieldReads) {
+ Value dest = read.dest();
+ visited.clear();
+ trivialPhis.clear();
+ boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfSameFieldRead(
+ visited, dest.uniquePhiUsers(), read.getField(), trivialPhis);
+ if (dest.numberOfPhiUsers() != 0 && !onlyHasTrivialPhis) {
+ fixableFieldReadsPerUsage = false;
+ break;
+ }
+ }
+ if (!fixableFieldReadsPerUsage) {
+ fixableFieldReads = false;
+ break;
+ }
+ }
+ if (!fixableFieldReads) {
+ it.remove();
+ continue;
+ }
}
}
@@ -308,7 +367,7 @@
boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfThis(
Sets.newIdentityHashSet(), thisValue.uniquePhiUsers(), thisValue, trivialPhis);
assert thisValue.numberOfPhiUsers() == 0 || onlyHasTrivialPhis;
- assert !onlyHasTrivialPhis || trivialPhis.isEmpty();
+ assert trivialPhis.isEmpty() || onlyHasTrivialPhis;
Set<Instruction> users = SetUtils.newIdentityHashSet(thisValue.uniqueUsers());
// If that is the case, method calls we want to fix up include users of those phis.
@@ -398,7 +457,7 @@
boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfSameFieldRead(
Sets.newIdentityHashSet(), dest.uniquePhiUsers(), field, trivialPhis);
assert dest.numberOfPhiUsers() == 0 || onlyHasTrivialPhis;
- assert !onlyHasTrivialPhis || trivialPhis.isEmpty();
+ assert trivialPhis.isEmpty() || onlyHasTrivialPhis;
Set<Instruction> users = SetUtils.newIdentityHashSet(dest.uniqueUsers());
// If that is the case, method calls we want to fix up include users of those phis.
diff --git a/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
index 204901f..d6c8173 100644
--- a/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
@@ -55,6 +55,8 @@
.addKeepMainRule(mainClassName)
.addKeepRules(KEEP_ANNOTATIONS)
.addKeepRules("-keep class kotlin.Metadata")
+ // TODO(119626580): Remove when resolved.
+ .addOptionsModification(options -> options.enableClassStaticizer = true)
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), mainClassName);
CodeInspector inspector = result.inspector();