Adding a black list of methods which are never supposed to be inlined.
Bug:
Change-Id: Idc52e433c02d338d38ca670f0741e30baf5c0ce3
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 d674ccb..61881a8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -194,6 +194,7 @@
public final LongMethods longMethods = new LongMethods();
public final ThrowableMethods throwableMethods = new ThrowableMethods();
public final ClassMethods classMethods = new ClassMethods();
+ public final Kotlin kotlin = new Kotlin();
// Dex system annotations.
// See https://source.android.com/devices/tech/dalvik/dex-format.html#system-annotation
@@ -334,6 +335,23 @@
}
}
+ public class Kotlin {
+ private Kotlin() {
+ }
+
+ public final Intrinsics intrinsics = new Intrinsics();
+
+ // kotlin.jvm.internal.Intrinsics class
+ public class Intrinsics {
+ private Intrinsics() {
+ }
+
+ public final DexType type = createType(createString("Lkotlin/jvm/internal/Intrinsics;"));
+ public final DexMethod throwParameterIsNullException =
+ createMethod(type, createProto(voidType, stringType), "throwParameterIsNullException");
+ }
+ }
+
private static <T extends DexItem> T canonicalize(ConcurrentHashMap<T, T> map, T item) {
assert item != null;
assert !DexItemFactory.isInternalSentinel(item);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 2a8f7b0..4bb10d3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -53,10 +53,21 @@
private final Set<DexEncodedMethod> doubleInlineSelectedTargets = Sets.newIdentityHashSet();
private final Map<DexEncodedMethod, DexEncodedMethod> doubleInlineeCandidates = new HashMap<>();
+ private final Set<DexMethod> blackList = Sets.newIdentityHashSet();
+
public Inliner(AppInfoWithLiveness appInfo, GraphLense graphLense, InternalOptions options) {
this.appInfo = appInfo;
this.graphLense = graphLense;
this.options = options;
+ fillInBlackList(appInfo);
+ }
+
+ private void fillInBlackList(AppInfoWithLiveness appInfo) {
+ blackList.add(appInfo.dexItemFactory.kotlin.intrinsics.throwParameterIsNullException);
+ }
+
+ public boolean isBlackListed(DexMethod method) {
+ return blackList.contains(method);
}
private Constraint instructionAllowedForInlining(
@@ -191,6 +202,14 @@
public static Constraint classIsVisible(DexType context, DexType clazz,
AppInfoWithSubtyping appInfo) {
+ if (clazz.isArrayType()) {
+ return classIsVisible(context, clazz.toArrayElementType(appInfo.dexItemFactory), appInfo);
+ }
+
+ if (clazz.isPrimitiveType()) {
+ return ALWAYS;
+ }
+
DexClass definition = appInfo.definitionFor(clazz);
return definition == null ? NEVER
: deriveConstraint(context, clazz, definition.accessFlags, appInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 2f4ac93..0da6c30 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -206,7 +206,7 @@
public InlineAction computeForInvokeWithReceiver(
InvokeMethodWithReceiver invoke, DexType invocationContext) {
DexEncodedMethod candidate = validateCandidate(invoke, invocationContext);
- if (candidate == null) {
+ if (candidate == null || inliner.isBlackListed(candidate.method)) {
return null;
}
@@ -246,7 +246,7 @@
public InlineAction computeForInvokeStatic(InvokeStatic invoke, DexType invocationContext) {
DexEncodedMethod candidate = validateCandidate(invoke, invocationContext);
- if (candidate == null) {
+ if (candidate == null || inliner.isBlackListed(candidate.method)) {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 4bd61e1..343fe9c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -14,6 +14,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -173,6 +174,7 @@
}
@Test
+ @Ignore("See b/72871423")
public void test_dataclass_copyDefault() throws Exception {
final String mainClassName = "dataclass.MainCopyWithDefaultKt";
final MethodSignature testMethodSignature =
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
new file mode 100644
index 0000000..fc2a7bb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2018, 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.kotlin;
+
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import java.util.Collection;
+import java.util.Collections;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class R8KotlinIntrinsicsTest extends AbstractR8KotlinTestBase {
+
+ private static final KotlinDataClass KOTLIN_INTRINSICS_CLASS =
+ new KotlinDataClass("kotlin.jvm.internal.Intrinsics");
+
+ @Parameters(name = "{0}")
+ public static Collection<Object> data() {
+ return ImmutableList.of(Boolean.TRUE, Boolean.FALSE);
+ }
+
+ public R8KotlinIntrinsicsTest(boolean allowAccessModification) {
+ super(allowAccessModification);
+ }
+
+ @Test
+ public void testParameterNullCheckIsInlined() throws Exception {
+ final String extraRules = keepClassMethod("intrinsics.IntrinsicsKt",
+ new MethodSignature("expectsNonNullParameters",
+ "java.lang.String", Lists.newArrayList("java.lang.String", "java.lang.String")));
+
+ runTest("intrinsics", "intrinsics.IntrinsicsKt", extraRules, (app) -> {
+ DexInspector dexInspector = new DexInspector(app);
+ ClassSubject intrinsicsClass = checkClassExists(
+ dexInspector, KOTLIN_INTRINSICS_CLASS.getClassName());
+
+ checkMethodsPresence(intrinsicsClass,
+ ImmutableMap.<MethodSignature, Boolean>builder()
+ .put(new MethodSignature("throwParameterIsNullException",
+ "void", Collections.singletonList("java.lang.String")),
+ true)
+ .put(new MethodSignature("checkParameterIsNotNull",
+ "void", Lists.newArrayList("java.lang.Object", "java.lang.String")),
+ allowAccessModification ? false /* should be inlined*/ : true)
+ .build());
+ });
+ }
+}
diff --git a/src/test/kotlinR8TestResources/intrinsics/Intrinsics.kt b/src/test/kotlinR8TestResources/intrinsics/Intrinsics.kt
new file mode 100644
index 0000000..90d26bf
--- /dev/null
+++ b/src/test/kotlinR8TestResources/intrinsics/Intrinsics.kt
@@ -0,0 +1,32 @@
+// Copyright (c) 2018, 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 intrinsics
+
+import java.lang.reflect.InvocationTargetException
+
+fun main(args: Array<String>) {
+ testParameterNullCheck()
+}
+
+fun expectsNonNullParameters(a: String, b: String): String = a + b
+
+fun testParameterNullCheck() {
+ println("> ${expectsNonNullParameters("pre", "post")} <")
+
+ val intrinsics = Class.forName("intrinsics.IntrinsicsKt")
+ val method = intrinsics.getMethod(
+ "expectsNonNullParameters", String::class.java, String::class.java)
+
+ println("> ${method.invoke(null, "pre", "post")} <")
+
+ try {
+ println("> ${method.invoke(null, "pre", null)} <")
+ } catch (e: InvocationTargetException) {
+ println("> exception: ${e.targetException::javaClass} <")
+ return
+ }
+ throw AssertionError()
+}
+