Version 1.4.38
Cherry pick: Reland: Fix bug making us not inline when a simple class without clinit had static fields with nothing setting them
CL: https://r8-review.googlesource.com/c/r8/+/33843
Bug: 122683370, 123358657
Change-Id: If6631a44765a449d2e7b7a5e2f56609324a29002
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index b64a3c7..f8b366e 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.37";
+ public static final String LABEL = "1.4.38";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index d9940f3..b229074 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -474,7 +474,7 @@
public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
return Arrays.stream(staticFields())
- .anyMatch(field -> !field.getStaticValue().mayTriggerAllocation());
+ .anyMatch(field -> field.getStaticValue().mayTriggerAllocation());
}
public List<InnerClassAttribute> getInnerClasses() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
index e0b57f1..64740ba 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
public class ConstMethodHandle extends ConstInstruction {
@@ -68,6 +70,12 @@
}
@Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, DexType invocationContext) {
+ return inliningConstraints.forConstMethodHandle();
+ }
+
+ @Override
public int maxOutValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 3292704..873eb20 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -259,6 +259,10 @@
return ConstraintWithTarget.ALWAYS;
}
+ public ConstraintWithTarget forConstMethodHandle() {
+ return ConstraintWithTarget.NEVER;
+ }
+
private ConstraintWithTarget forFieldInstruction(
DexField field, DexEncodedField target, DexType invocationContext) {
// Resolve the field if possible and decide whether the instruction can inlined.
diff --git a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
index 18998c8..4bfb5ce 100644
--- a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -116,6 +117,8 @@
if (cst instanceof Type && ((Type) cst).getSort() != Type.METHOD) {
DexType type = application.getType((Type) cst);
updateConstraint(inliningConstraints.forConstClass(type, invocationContext));
+ } else if (cst instanceof Handle) {
+ updateConstraint(inliningConstraints.forConstMethodHandle());
} else {
updateConstraint(inliningConstraints.forConstInstruction());
}
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index 46ed96b..da70125 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ByteDataView;
import com.android.tools.r8.ClassFileConsumer;
@@ -23,10 +24,14 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -133,6 +138,16 @@
ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName(), expected);
assertEquals(runCf.stderr, 0, runCf.exitCode);
assertEquals(runInput.toString(), runCf.toString());
+ // Ensure that we did not inline the const method handle
+ ensureConstHandleNotInlined(outCf);
+ }
+
+ private void ensureConstHandleNotInlined(Path file) throws IOException, ExecutionException {
+ CodeInspector inspector = new CodeInspector(file);
+ MethodSubject subject = inspector.clazz(MethodHandleTest.D.class).method(
+ "java.lang.MethodHandle", "vcviSpecialMethod");
+ assertTrue(inspector.clazz(MethodHandleTest.D.class)
+ .method("java.lang.invoke.MethodHandle", "vcviSpecialMethod").isPresent());
}
private void runDex() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineWithSimpleFieldNoValue.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineWithSimpleFieldNoValue.java
new file mode 100644
index 0000000..eac5881
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineWithSimpleFieldNoValue.java
@@ -0,0 +1,43 @@
+// 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.inliner;
+
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+
+class TestClass {
+ public static void main(String[] args) {
+ System.out.println(InlineFrom.getValue());
+ InlineFrom.value = 43;
+ System.out.println(InlineFrom.value);
+ }
+}
+
+// Simple class, with no clinit and no static field initialization.
+// We should always inline getValue()
+// We ensure that we use value.
+class InlineFrom {
+ public static int value;
+
+ public static int getValue() {
+ return 42;
+ }
+}
+
+public class InlineWithSimpleFieldNoValue extends TestBase {
+ @Test
+ public void test() throws Exception {
+ R8TestRunResult result = testForR8(Backend.DEX)
+ .addKeepMainRule(TestClass.class)
+ .addProgramClasses(TestClass.class, InlineFrom.class)
+ .run(TestClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("42", "43"));
+ assertTrue(result.inspector().clazz(InlineFrom.class).allMethods().isEmpty());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index ac75230..bc23757 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -910,11 +910,10 @@
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
- // Field is public and getter is small so we expect to always inline it.
+ // Field is public and getter/setter is only called from one place so we expect to always
+ // inline it.
checkMethodIsRemoved(objectClass, getter);
-
- // Setter has null check of new value, thus may not be inlined.
- checkMethodIsKept(objectClass, setter);
+ checkMethodIsRemoved(objectClass, setter);
});
}
@@ -934,7 +933,7 @@
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
checkMethodIsRemoved(objectClass, getter);
- checkMethodIsKept(objectClass, setter);
+ checkMethodIsRemoved(objectClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/C.java b/src/test/java/com/android/tools/r8/shaking/testrules/C.java
index 79370a4..7a30a65 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/C.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/C.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.shaking.testrules;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NeverMerge;
@NeverMerge
@@ -11,6 +12,7 @@
private static int i;
+ @NeverInline
public static int x() {
return i;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
index 432711f..4bf8c92 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
@@ -69,6 +69,7 @@
ImmutableList.of(
"-keep class **.Main { *; }",
"-nevermerge @com.android.tools.r8.NeverMerge class *",
+ "-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
ClassSubject classA = inspector.clazz(A.class);
@@ -99,6 +100,7 @@
"-neverinline class **.B { method(); }",
"-keep class **.Main { *; }",
"-nevermerge @com.android.tools.r8.NeverMerge class *",
+ "-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
ClassSubject classA = inspector.clazz(A.class);
@@ -126,6 +128,7 @@
"-forceinline class **.B { int m(int, int); }",
"-keep class **.Main { *; }",
"-nevermerge @com.android.tools.r8.NeverMerge class *",
+ "-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
ClassSubject classA = inspector.clazz(A.class);