Merge "Minor refactoring of class initialization analysis"
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index a0fbb59..a19d070 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -4,16 +4,31 @@
package com.android.tools.r8.ir.analysis;
+import com.android.tools.r8.graph.AppInfo.ResolutionResult;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CatchHandlers.CatchHandler;
import com.android.tools.r8.ir.code.DominatorTree;
import com.android.tools.r8.ir.code.DominatorTree.Assumption;
import com.android.tools.r8.ir.code.DominatorTree.Inclusive;
+import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InstanceGet;
+import com.android.tools.r8.ir.code.InstancePut;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.InvokeSuper;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.StaticPut;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.google.common.collect.Streams;
import java.util.Iterator;
@@ -229,4 +244,188 @@
markingColor = -1;
}
}
+
+ public static class InstructionUtils {
+
+ public static boolean forInstanceGet(
+ InstanceGet instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ return forInstanceGetOrPut(instruction, type, appView, mode, assumption);
+ }
+
+ public static boolean forInstancePut(
+ InstancePut instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ return forInstanceGetOrPut(instruction, type, appView, mode, assumption);
+ }
+
+ private static boolean forInstanceGetOrPut(
+ FieldInstruction instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ assert instruction.isInstanceGet() || instruction.isInstancePut();
+ if (assumption == AnalysisAssumption.NONE) {
+ Value object =
+ instruction.isInstanceGet()
+ ? instruction.asInstanceGet().object()
+ : instruction.asInstancePut().object();
+ if (object.getTypeLattice().isNullable()) {
+ // If the receiver is null we cannot be sure that the holder has been initialized.
+ return false;
+ }
+ }
+ return isTypeInitializedBy(type, instruction.getField().clazz, appView, mode);
+ }
+
+ public static boolean forInvokeDirect(
+ InvokeDirect instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ if (assumption == AnalysisAssumption.NONE) {
+ if (instruction.getReceiver().getTypeLattice().isNullable()) {
+ // If the receiver is null we cannot be sure that the holder has been initialized.
+ return false;
+ }
+ }
+ return isTypeInitializedBy(type, instruction.getInvokedMethod().holder, appView, mode);
+ }
+
+ public static boolean forInvokeStatic(
+ InvokeStatic instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ if (assumption == AnalysisAssumption.NONE) {
+ // Class initialization may fail with ExceptionInInitializerError.
+ return false;
+ }
+ return isTypeInitializedBy(type, instruction.getInvokedMethod().holder, appView, mode);
+ }
+
+ public static boolean forInvokeSuper(
+ InvokeSuper instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ if (assumption == AnalysisAssumption.NONE) {
+ if (instruction.getReceiver().getTypeLattice().isNullable()) {
+ // If the receiver is null we cannot be sure that the holder has been initialized.
+ return false;
+ }
+ }
+ if (mode == Query.DIRECTLY) {
+ // We cannot ensure exactly which class is being loaded because it depends on the runtime
+ // type of the receiver.
+ // TODO(christofferqa): We can do better if there is a unique target.
+ return false;
+ }
+ DexMethod method = instruction.getInvokedMethod();
+ DexClass enclosingClass = appView.appInfo().definitionFor(method.holder);
+ if (enclosingClass == null) {
+ return false;
+ }
+ DexType superType = enclosingClass.superType;
+ if (superType == null) {
+ return false;
+ }
+ ResolutionResult resolutionResult = appView.appInfo().resolveMethod(superType, method);
+ if (!resolutionResult.hasSingleTarget()) {
+ return false;
+ }
+ DexType holder = resolutionResult.asSingleTarget().method.holder;
+ return holder.isSubtypeOf(type, appView.appInfo());
+ }
+
+ public static boolean forInvokeVirtual(
+ InvokeVirtual instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ if (assumption == AnalysisAssumption.NONE) {
+ if (instruction.getReceiver().getTypeLattice().isNullable()) {
+ // If the receiver is null we cannot be sure that the holder has been initialized.
+ return false;
+ }
+ }
+ if (mode == Query.DIRECTLY) {
+ // We cannot ensure exactly which class is being loaded because it depends on the runtime
+ // type of the receiver.
+ // TODO(christofferqa): We can do better if there is a unique target.
+ return false;
+ }
+ DexMethod method = instruction.getInvokedMethod();
+ ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method);
+ if (!resolutionResult.hasSingleTarget()) {
+ return false;
+ }
+ DexType holder = resolutionResult.asSingleTarget().method.holder;
+ return holder.isSubtypeOf(type, appView.appInfo());
+ }
+
+ public static boolean forNewInstance(
+ NewInstance instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ return isTypeInitializedBy(type, instruction.clazz, appView, mode);
+ }
+
+ public static boolean forStaticGet(
+ StaticGet instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ return forStaticGetOrPut(instruction, type, appView, mode, assumption);
+ }
+
+ public static boolean forStaticPut(
+ StaticPut instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ return forStaticGetOrPut(instruction, type, appView, mode, assumption);
+ }
+
+ private static boolean forStaticGetOrPut(
+ FieldInstruction instruction,
+ DexType type,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode,
+ AnalysisAssumption assumption) {
+ assert instruction.isStaticGet() || instruction.isStaticPut();
+ if (assumption == AnalysisAssumption.NONE) {
+ // Class initialization may fail with ExceptionInInitializerError.
+ return false;
+ }
+ return isTypeInitializedBy(type, instruction.getField().clazz, appView, mode);
+ }
+
+ private static boolean isTypeInitializedBy(
+ DexType typeToBeInitialized,
+ DexType typeKnownToBeInitialized,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ Query mode) {
+ if (mode == Query.DIRECTLY) {
+ return typeKnownToBeInitialized == typeToBeInitialized;
+ } else {
+ return typeKnownToBeInitialized.isSubtypeOf(typeToBeInitialized, appView.appInfo());
+ }
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index acc122b..40756ae 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -169,17 +170,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- if (object().getTypeLattice().isNullable()) {
- // If the receiver is null we cannot be sure that the holder has been initialized.
- return false;
- }
- }
- DexType holder = getField().clazz;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forInstanceGet(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 48bc0c0..57fe121 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -152,17 +153,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- if (object().getTypeLattice().isNullable()) {
- // If the receiver is null we cannot be sure that the holder has been initialized.
- return false;
- }
- }
- DexType holder = getField().clazz;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forInstancePut(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index ca1180f..301f710 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -130,17 +131,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- if (getReceiver().getTypeLattice().isNullable()) {
- // If the receiver is null we cannot be sure that the holder has been initialized.
- return false;
- }
- }
- DexType holder = getInvokedMethod().holder;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forInvokeDirect(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index e203cc6..b90d23e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -127,15 +127,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- // Class initialization may fail with ExceptionInInitializerError.
- return false;
- }
- DexType holder = getInvokedMethod().holder;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forInvokeStatic(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index b02ca94..bc3d982 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -5,13 +5,12 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.code.InvokeSuperRange;
-import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -119,32 +118,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- if (getReceiver().getTypeLattice().isNullable()) {
- // If the receiver is null we cannot be sure that the holder has been initialized.
- return false;
- }
- }
- if (mode == Query.DIRECTLY) {
- // We cannot ensure exactly which class is being loaded because it depends on the runtime
- // type of the receiver.
- // TODO(christofferqa): We can do better if there is a unique target.
- return false;
- }
- DexMethod method = getInvokedMethod();
- DexClass enclosingClass = appView.appInfo().definitionFor(method.holder);
- if (enclosingClass == null) {
- return false;
- }
- DexType superType = enclosingClass.superType;
- if (superType == null) {
- return false;
- }
- ResolutionResult resolutionResult = appView.appInfo().resolveMethod(superType, method);
- if (!resolutionResult.hasSingleTarget()) {
- return false;
- }
- DexType holder = resolutionResult.asSingleTarget().method.holder;
- return holder.isSubtypeOf(clazz, appView.appInfo());
+ return ClassInitializationAnalysis.InstructionUtils.forInvokeSuper(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 4c2327f..7246ff1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -5,12 +5,12 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.code.InvokeVirtualRange;
-import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -109,24 +109,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- if (getReceiver().getTypeLattice().isNullable()) {
- // If the receiver is null we cannot be sure that the holder has been initialized.
- return false;
- }
- }
- if (mode == Query.DIRECTLY) {
- // We cannot ensure exactly which class is being loaded because it depends on the runtime
- // type of the receiver.
- // TODO(christofferqa): We can do better if there is a unique target.
- return false;
- }
- DexMethod method = getInvokedMethod();
- ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method);
- if (!resolutionResult.hasSingleTarget()) {
- return false;
- }
- DexType holder = resolutionResult.asSingleTarget().method.holder;
- return holder.isSubtypeOf(clazz, appView.appInfo());
+ return ClassInitializationAnalysis.InstructionUtils.forInvokeVirtual(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 93b1042..4de219e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -116,12 +117,8 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- DexType holder = this.clazz;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forNewInstance(
+ this, clazz, appView, mode, assumption);
}
public void markNoSpilling() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index db3838c..b79d076 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -156,15 +157,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- // Class initialization may fail with ExceptionInInitializerError.
- return false;
- }
- DexType holder = getField().clazz;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forStaticGet(
+ this, clazz, appView, mode, assumption);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index 4f63a1b..29ce40c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -139,15 +140,7 @@
AppView<? extends AppInfoWithSubtyping> appView,
Query mode,
AnalysisAssumption assumption) {
- if (assumption == AnalysisAssumption.NONE) {
- // Class initialization may fail with ExceptionInInitializerError.
- return false;
- }
- DexType holder = getField().clazz;
- if (mode == Query.DIRECTLY) {
- return holder == clazz;
- } else {
- return holder.isSubtypeOf(clazz, appView.appInfo());
- }
+ return ClassInitializationAnalysis.InstructionUtils.forStaticPut(
+ this, clazz, appView, mode, assumption);
}
}