Prioritize lib method modeling in side-effect analysis of invocations.
Change-Id: I11364edfcf4396bc1b6f1c46b044e9d79f93b620
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 c1004de..ef8cae6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -402,9 +402,12 @@
public final Set<DexMethod> libraryMethodsReturningNonNull =
ImmutableSet.of(classMethods.getName, classMethods.getSimpleName, stringMethods.valueOf);
+ // We assume library methods listed here are `public`, i.e., free from visibility side effects.
+ // If not, that library method should not be added here because it literally has side effects.
public Set<DexMethod> libraryMethodsWithoutSideEffects =
ImmutableSet.<DexMethod>builder()
.add(objectMethods.constructor)
+ .addAll(classMethods.getNames)
.addAll(stringBufferMethods.constructorMethods)
.addAll(stringBuilderMethods.constructorMethods)
.build();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index bddfc6a..9be25b6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -162,6 +162,11 @@
return true;
}
+ // Check if it is a call to one of library methods that are known to be side-effect free.
+ if (appView.dexItemFactory().libraryMethodsWithoutSideEffects.contains(getInvokedMethod())) {
+ return false;
+ }
+
// Find the target and check if the invoke may have side effects.
if (appView.appInfo().hasLiveness()) {
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
@@ -176,8 +181,7 @@
return true;
}
- // Verify that the target method does not have side-effects. For program methods, we use
- // optimization info, and for library methods, we use modeling.
+ // Verify that the target method does not have side-effects.
DexClass clazz = appView.definitionFor(target.method.holder);
if (clazz == null) {
assert false : "Expected to be able to find the enclosing class of a method definition";
@@ -186,12 +190,8 @@
boolean targetMayHaveSideEffects;
if (appViewWithLiveness.appInfo().noSideEffects.containsKey(target.method)) {
targetMayHaveSideEffects = false;
- } else if (clazz.isProgramClass()) {
- targetMayHaveSideEffects = target.getOptimizationInfo().mayHaveSideEffects();
} else {
- assert clazz.isLibraryClass();
- targetMayHaveSideEffects =
- !appView.dexItemFactory().libraryMethodsWithoutSideEffects.contains(target.method);
+ targetMayHaveSideEffects = target.getOptimizationInfo().mayHaveSideEffects();
}
return targetMayHaveSideEffects;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index e659c39..93e98db 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -149,6 +149,11 @@
return true;
}
+ // Check if it is a call to one of library methods that are known to be side-effect free.
+ if (appView.dexItemFactory().libraryMethodsWithoutSideEffects.contains(getInvokedMethod())) {
+ return false;
+ }
+
// Find the target and check if the invoke may have side effects.
if (appView.appInfo().hasLiveness()) {
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 3bc7380..a2ce1bc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -137,8 +137,8 @@
return true;
}
- // Check if it is a call to one of java.lang.Class.get*Name().
- if (appView.dexItemFactory().classMethods.isReflectiveNameLookup(getInvokedMethod())) {
+ // Check if it is a call to one of library methods that are known to be side-effect free.
+ if (appView.dexItemFactory().libraryMethodsWithoutSideEffects.contains(getInvokedMethod())) {
return false;
}