Avoid staticizer lense creation if no method/field mappings found.
Bug: 122846041
Change-Id: I346e54e7711858ff5d2205a2cde2aee8500478d5
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 50c91eb..9cef6b6 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -840,9 +840,11 @@
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) {
- builder.append(entry.getKey().toSourceString()).append(" -> ");
- builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
+ if (typeMap != null) {
+ for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) {
+ builder.append(entry.getKey().toSourceString()).append(" -> ");
+ builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
+ }
}
for (Map.Entry<DexMethod, DexMethod> entry : methodMap.entrySet()) {
builder.append(entry.getKey().toSourceString()).append(" -> ");
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 59d8717..f8ddcb6 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
@@ -291,7 +291,7 @@
// invoke-virtual { s1, ... } mtd1
// goto Exit
// b2:
- // s2 <- static-get singleoton
+ // s2 <- static-get singleton
// ...
// invoke-virtual { s2, ... } mtd1
// goto Exit
@@ -503,7 +503,7 @@
}
}
- if (!methodMapping.isEmpty() || fieldMapping.isEmpty()) {
+ if (!methodMapping.isEmpty() || !fieldMapping.isEmpty()) {
classStaticizer.converter.appView.setGraphLense(
new ClassStaticizerGraphLense(
classStaticizer.converter.graphLense(),
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index df797ad..7b3ed4a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -29,11 +29,14 @@
import com.android.tools.r8.ir.optimize.staticizer.movetohost.CandidateConflictField;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.CandidateConflictMethod;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.CandidateOk;
+import com.android.tools.r8.ir.optimize.staticizer.movetohost.CandidateOkFieldOnly;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.CandidateOkSideEffects;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.HostConflictField;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.HostConflictMethod;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.HostOk;
+import com.android.tools.r8.ir.optimize.staticizer.movetohost.HostOkFieldOnly;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.HostOkSideEffects;
+import com.android.tools.r8.ir.optimize.staticizer.movetohost.MoveToHostFieldOnlyTestClass;
import com.android.tools.r8.ir.optimize.staticizer.movetohost.MoveToHostTestClass;
import com.android.tools.r8.ir.optimize.staticizer.trivial.Simple;
import com.android.tools.r8.ir.optimize.staticizer.trivial.SimpleWithGetter;
@@ -150,6 +153,36 @@
}
@Test
+ public void testMoveToHost_fieldOnly() throws Exception {
+ assumeTrue("b/112831361", backend == Backend.DEX);
+ Class<?> main = MoveToHostFieldOnlyTestClass.class;
+ Class<?>[] classes = {
+ NeverInline.class,
+ MoveToHostFieldOnlyTestClass.class,
+ HostOkFieldOnly.class,
+ CandidateOkFieldOnly.class
+ };
+ TestRunResult result = testForR8(backend)
+ .addProgramClasses(classes)
+ .enableProguardTestOptions()
+ .enableInliningAnnotations()
+ .addKeepMainRule(main)
+ .noMinification()
+ .addKeepRules("-allowaccessmodification")
+ .addOptionsModification(this::configure)
+ .run(main);
+
+ CodeInspector inspector = result.inspector();
+ ClassSubject clazz = inspector.clazz(main);
+
+ assertEquals(
+ Lists.newArrayList(),
+ references(clazz, "testOk_fieldOnly", "void"));
+
+ assertFalse(inspector.clazz(CandidateOkFieldOnly.class).isPresent());
+ }
+
+ @Test
public void testMoveToHost() throws Exception {
assumeTrue("b/112831361", backend == Backend.DEX);
Class<?> main = MoveToHostTestClass.class;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/CandidateOkFieldOnly.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/CandidateOkFieldOnly.java
new file mode 100644
index 0000000..48963f4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/CandidateOkFieldOnly.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, 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.ir.optimize.staticizer.movetohost;
+
+public class CandidateOkFieldOnly {
+ // No instance methods.
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/HostOkFieldOnly.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/HostOkFieldOnly.java
new file mode 100644
index 0000000..e132627
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/HostOkFieldOnly.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, 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.ir.optimize.staticizer.movetohost;
+
+public class HostOkFieldOnly {
+ static CandidateOkFieldOnly INSTANCE = new CandidateOkFieldOnly();
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/MoveToHostFieldOnlyTestClass.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/MoveToHostFieldOnlyTestClass.java
new file mode 100644
index 0000000..f725d21
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/movetohost/MoveToHostFieldOnlyTestClass.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, 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.ir.optimize.staticizer.movetohost;
+
+import com.android.tools.r8.NeverInline;
+
+public class MoveToHostFieldOnlyTestClass {
+
+ public static void main(String[] args) {
+ MoveToHostFieldOnlyTestClass test = new MoveToHostFieldOnlyTestClass();
+ test.testOk_fieldOnly();
+ }
+
+ @NeverInline
+ private void testOk_fieldOnly() {
+ // Any instance method call whose target holder is not the candidate will invalidate candidacy,
+ // for example, toString() without overriding, getClass(), etc.
+ // Note that having instance methods in the candidate class guarantees that method mappings will
+ // exist when field mappings do so.
+ // Any other uses other than invoke-virtual or invoke-direct (to either <init> or private) are
+ // not allowed, e.g., System.out.println(INSTANCE), null check, or static-put to somewhere else.
+ // Therefore, it's merely dead code, and thus it has not been harmful to forget to create a
+ // staticizer lense when there is no method mapping (for instance methods to staticized ones)
+ // while there are field mappings as shown in this example.
+ Object x = HostOkFieldOnly.INSTANCE;
+ }
+}
+