[ApiModel] Outline instance-of instructions to new library classes
Bug: b/258270051
Change-Id: If11f3309062fe74cfd78a46f5183bc45c2bf9607
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index 82ada16..4c3fc63 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
@@ -36,6 +37,7 @@
import com.android.tools.r8.ir.synthetic.CheckCastSourceCode;
import com.android.tools.r8.ir.synthetic.FieldAccessorBuilder;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
+import com.android.tools.r8.ir.synthetic.InstanceOfSourceCode;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.TraversalContinuation;
@@ -108,6 +110,8 @@
reference = instruction.asFieldInstruction().getField();
} else if (instruction.isCheckCast()) {
reference = instruction.asCheckCast().getType();
+ } else if (instruction.isInstanceOf()) {
+ reference = instruction.asInstanceOf().getType();
} else {
return appView.computedMinApiLevel();
}
@@ -126,7 +130,7 @@
return appView.computedMinApiLevel();
}
// Check for protected or package private access flags before outlining.
- if (holder.isInterface() || instruction.isCheckCast()) {
+ if (holder.isInterface() || instruction.isCheckCast() || instruction.isInstanceOf()) {
return referenceApiLevel;
} else {
DexEncodedMember<?, ?> definition =
@@ -174,7 +178,10 @@
DexItemFactory factory,
ApiInvokeOutlinerDesugaringEventConsumer eventConsumer,
ProgramMethod context) {
- assert instruction.isInvoke() || instruction.isFieldInstruction() || instruction.isCheckCast();
+ assert instruction.isInvoke()
+ || instruction.isFieldInstruction()
+ || instruction.isCheckCast()
+ || instruction.isInstanceOf();
ProgramMethod outlinedMethod =
ensureOutlineMethod(uniqueContext, instruction, computedApiLevel, factory, context);
eventConsumer.acceptOutlinedMethod(outlinedMethod, context);
@@ -208,6 +215,8 @@
setCodeForInvoke(syntheticMethodBuilder, instruction.asInvoke(), factory);
} else if (instruction.isCheckCast()) {
setCodeForCheckCast(syntheticMethodBuilder, instruction.asCheckCast(), factory);
+ } else if (instruction.isInstanceOf()) {
+ setCodeForInstanceOf(syntheticMethodBuilder, instruction.asInstanceOf(), factory);
} else {
assert instruction.isCfInstruction();
setCodeForFieldInstruction(
@@ -294,6 +303,18 @@
.generateCfCode());
}
+ private void setCodeForInstanceOf(
+ SyntheticMethodBuilder methodBuilder, CfInstanceOf instruction, DexItemFactory factory) {
+ DexClass target = appView.definitionFor(instruction.getType());
+ assert target != null;
+ methodBuilder
+ .setProto(factory.createProto(factory.booleanType, objectParams))
+ .setCode(
+ m ->
+ InstanceOfSourceCode.create(appView, m.getHolderType(), target.getType())
+ .generateCfCode());
+ }
+
private boolean verifyLibraryHolderAndInvoke(
DexClass libraryHolder, DexMethod apiMethod, boolean isVirtualInvoke) {
DexEncodedMethod libraryApiMethodDefinition = libraryHolder.lookupMethod(apiMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/InstanceOfSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/InstanceOfSourceCode.java
new file mode 100644
index 0000000..57257ff
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/InstanceOfSourceCode.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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.synthetic;
+
+import com.android.tools.r8.cf.code.CfInstanceOf;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.ValueType;
+import java.util.ArrayList;
+import java.util.List;
+
+// Source code representing a simple call to CheckCast.
+public final class InstanceOfSourceCode extends SyntheticCfCodeProvider {
+
+ private final DexType instanceOfType;
+
+ private InstanceOfSourceCode(AppView<?> appView, DexType holder, DexType instanceOfType) {
+ super(appView, holder);
+ this.instanceOfType = instanceOfType;
+ }
+
+ public static InstanceOfSourceCode create(
+ AppView<?> appView, DexType holder, DexType checkCastType) {
+ return new InstanceOfSourceCode(appView, holder, checkCastType);
+ }
+
+ @Override
+ public CfCode generateCfCode() {
+ List<CfInstruction> instructions = new ArrayList<>();
+ instructions.add(new CfLoad(ValueType.OBJECT, 0));
+ instructions.add(new CfInstanceOf(instanceOfType));
+ instructions.add(new CfReturn(ValueType.INT));
+ return standardCfCodeFromInstructions(instructions);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
index e9857a0..662f9f4 100644
--- a/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
@@ -133,7 +133,7 @@
@Override
public void registerInstanceOf(DexType type) {
- // InstanceOf are not causing soft verification issues
+ setMaxApiReferenceLevel(type);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
index ad6b725..63e03a6 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
@@ -126,8 +126,8 @@
private void inspect(CodeInspector inspector) throws Exception {
verifyThat(inspector, parameters, LibraryClass.class)
- // TODO(b/258270051): We should outline the call on lower api levels.
- .hasNotInstanceOfOutlinedFrom(Main.class.getMethod("main", String[].class));
+ .hasInstanceOfOutlinedFromUntil(
+ Main.class.getMethod("main", String[].class), classApiLevel);
}
private void checkOutput(SingleTestRunResult<?> runResult) {