Migrate getClass-to-ConstClass conversion.
This is a mechanical migration to place related code together.
Change-Id: Id49dadda7bd92af5b4656569b5296f41dd48297b
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 38842da..bdee0ac 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -56,6 +56,7 @@
import com.android.tools.r8.ir.optimize.Outliner;
import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
import com.android.tools.r8.ir.optimize.RedundantFieldLoadElimination;
+import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
@@ -904,7 +905,7 @@
if (appInfo.hasLiveness()) {
// Reflection optimization 1. getClass() -> const-class
- codeRewriter.rewriteGetClass(code);
+ ReflectionOptimizer.rewriteGetClass(appInfo.withLiveness(), code);
}
if (!isDebugMode) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 785041c..18c31ed 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -47,7 +47,6 @@
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.Cmp;
import com.android.tools.r8.ir.code.Cmp.Bias;
-import com.android.tools.r8.ir.code.ConstClass;
import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
@@ -1948,67 +1947,6 @@
return converter.definitionFor(type);
}
- // Rewrite getClass() call to const-class if the type of the given instance is effectively final.
- public void rewriteGetClass(IRCode code) {
- InstructionIterator it = code.instructionIterator();
- while (it.hasNext()) {
- Instruction current = it.next();
- // Conservatively bail out if the containing block has catch handlers.
- // TODO(b/118509730): unless join of all catch types is ClassNotFoundException ?
- if (current.getBlock().hasCatchHandlers()) {
- continue;
- }
- if (!current.isInvokeVirtual()) {
- continue;
- }
- InvokeVirtual invoke = current.asInvokeVirtual();
- DexMethod invokedMethod = invoke.getInvokedMethod();
- // Class<?> Object#getClass() is final and cannot be overridden.
- if (invokedMethod != appInfo.dexItemFactory.objectMethods.getClass) {
- continue;
- }
- Value in = invoke.getReceiver();
- if (in.hasLocalInfo()) {
- continue;
- }
- TypeLatticeElement inType = in.getTypeLattice();
- // Check the receiver is either class type or array type. Also make sure it is not nullable.
- if (!(inType.isClassType() || inType.isArrayType())
- || inType.isNullable()) {
- continue;
- }
- DexType type = inType.isClassType()
- ? inType.asClassTypeLatticeElement().getClassType()
- : inType.asArrayTypeLatticeElement().getArrayType(appInfo.dexItemFactory);
- DexType baseType = type.toBaseType(appInfo.dexItemFactory);
- // Make sure base type is a class type.
- if (!baseType.isClassType()) {
- continue;
- }
- // Only consider program class, e.g., platform can introduce sub types in different versions.
- DexClass clazz = appInfo.definitionFor(baseType);
- if (clazz == null || !clazz.isProgramClass()) {
- continue;
- }
- // Only consider effectively final class. Exception: new Base().getClass().
- if (!baseType.hasSubtypes()
- || !appInfo.withLiveness().isInstantiatedIndirectly(baseType)
- || (!in.isPhi() && in.definition.isCreatingInstanceOrArray())) {
- // Make sure the target (base) type is visible.
- ConstraintWithTarget constraints =
- ConstraintWithTarget.classIsVisible(code.method.method.getHolder(), baseType, appInfo);
- if (constraints == ConstraintWithTarget.NEVER) {
- continue;
- }
- TypeLatticeElement typeLattice = TypeLatticeElement.classClassType(appInfo);
- Value value = code.createValue(typeLattice, invoke.getLocalInfo());
- ConstClass constClass = new ConstClass(value, type);
- it.replaceCurrentInstruction(constClass);
- }
- }
- assert code.isConsistentSSA();
- }
-
public void removeTrivialCheckCastAndInstanceOfInstructions(
IRCode code, boolean enableWholeProgramOptimizations) {
if (!enableWholeProgramOptimizations) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index ecd3a7a..496e113 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -9,8 +9,19 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.code.ConstClass;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption;
+import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.google.common.base.Strings;
public class ReflectionOptimizer {
@@ -57,6 +68,67 @@
}
}
+ // Rewrite getClass() call to const-class if the type of the given instance is effectively final.
+ public static void rewriteGetClass(AppInfoWithLiveness appInfo, IRCode code) {
+ InstructionIterator it = code.instructionIterator();
+ while (it.hasNext()) {
+ Instruction current = it.next();
+ // Conservatively bail out if the containing block has catch handlers.
+ // TODO(b/118509730): unless join of all catch types is ClassNotFoundException ?
+ if (current.getBlock().hasCatchHandlers()) {
+ continue;
+ }
+ if (!current.isInvokeVirtual()) {
+ continue;
+ }
+ InvokeVirtual invoke = current.asInvokeVirtual();
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ // Class<?> Object#getClass() is final and cannot be overridden.
+ if (invokedMethod != appInfo.dexItemFactory.objectMethods.getClass) {
+ continue;
+ }
+ Value in = invoke.getReceiver();
+ if (in.hasLocalInfo()) {
+ continue;
+ }
+ TypeLatticeElement inType = in.getTypeLattice();
+ // Check the receiver is either class type or array type. Also make sure it is not nullable.
+ if (!(inType.isClassType() || inType.isArrayType())
+ || inType.isNullable()) {
+ continue;
+ }
+ DexType type = inType.isClassType()
+ ? inType.asClassTypeLatticeElement().getClassType()
+ : inType.asArrayTypeLatticeElement().getArrayType(appInfo.dexItemFactory);
+ DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+ // Make sure base type is a class type.
+ if (!baseType.isClassType()) {
+ continue;
+ }
+ // Only consider program class, e.g., platform can introduce sub types in different versions.
+ DexClass clazz = appInfo.definitionFor(baseType);
+ if (clazz == null || !clazz.isProgramClass()) {
+ continue;
+ }
+ // Only consider effectively final class. Exception: new Base().getClass().
+ if (!baseType.hasSubtypes()
+ || !appInfo.isInstantiatedIndirectly(baseType)
+ || (!in.isPhi() && in.definition.isCreatingInstanceOrArray())) {
+ // Make sure the target (base) type is visible.
+ ConstraintWithTarget constraints =
+ ConstraintWithTarget.classIsVisible(code.method.method.getHolder(), baseType, appInfo);
+ if (constraints == ConstraintWithTarget.NEVER) {
+ continue;
+ }
+ TypeLatticeElement typeLattice = TypeLatticeElement.classClassType(appInfo);
+ Value value = code.createValue(typeLattice, invoke.getLocalInfo());
+ ConstClass constClass = new ConstClass(value, type);
+ it.replaceCurrentInstruction(constClass);
+ }
+ }
+ assert code.isConsistentSSA();
+ }
+
public static String computeClassName(
DexString descriptor, DexClass holder, ClassNameComputationInfo classNameComputationInfo) {
return computeClassName(