Improve type propagation with if-contexts
This works by adding a new instruction (HBoundType) after each `if (a
instanceof ClassA) {}` to bound the type that `a` can take in the True-
dominated blocks.
Change-Id: Iae6a150b353486d4509b0d9b092164675732b90c
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index c7b8343..4baea66 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -583,6 +583,7 @@
M(ArrayLength, Instruction) \
M(ArraySet, Instruction) \
M(BoundsCheck, Instruction) \
+ M(BoundType, Instruction) \
M(CheckCast, Instruction) \
M(ClinitCheck, Instruction) \
M(Compare, BinaryOperation) \
@@ -876,9 +877,22 @@
class ReferenceTypeInfo : ValueObject {
public:
- ReferenceTypeInfo() : is_exact_(false), is_top_(true) {}
- ReferenceTypeInfo(Handle<mirror::Class> type_handle, bool is_exact) {
- SetTypeHandle(type_handle, is_exact);
+ typedef Handle<mirror::Class> TypeHandle;
+
+ static ReferenceTypeInfo Create(TypeHandle type_handle, bool is_exact)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (type_handle->IsObjectClass()) {
+ // Override the type handle to be consistent with the case when we get to
+ // Top but don't have the Object class available. It avoids having to guess
+ // what value the type_handle has when it's Top.
+ return ReferenceTypeInfo(TypeHandle(), is_exact, true);
+ } else {
+ return ReferenceTypeInfo(type_handle, is_exact, false);
+ }
+ }
+
+ static ReferenceTypeInfo CreateTop(bool is_exact) {
+ return ReferenceTypeInfo(TypeHandle(), is_exact, true);
}
bool IsExact() const { return is_exact_; }
@@ -886,29 +900,7 @@
Handle<mirror::Class> GetTypeHandle() const { return type_handle_; }
- void SetTop() {
- is_top_ = true;
- type_handle_ = Handle<mirror::Class>();
- }
-
- void SetInexact() { is_exact_ = false; }
-
- void SetTypeHandle(Handle<mirror::Class> type_handle, bool is_exact)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- is_exact_ = is_exact;
- if (type_handle->IsObjectClass()) {
- is_top_ = true;
- // Override the type handle to be consistent with the case when we get to
- // Top but don't have the Object class available. It avoids having to guess
- // what value the type_handle has when it's Top.
- type_handle_ = Handle<mirror::Class>();
- } else {
- is_top_ = false;
- type_handle_ = type_handle;
- }
- }
-
- bool IsSupertypeOf(ReferenceTypeInfo rti) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ bool IsSupertypeOf(ReferenceTypeInfo rti) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (IsTop()) {
// Top (equivalent for java.lang.Object) is supertype of anything.
return true;
@@ -943,9 +935,14 @@
}
private:
+ ReferenceTypeInfo() : ReferenceTypeInfo(TypeHandle(), false, true) {}
+ ReferenceTypeInfo(TypeHandle type_handle, bool is_exact, bool is_top)
+ : type_handle_(type_handle), is_exact_(is_exact), is_top_(is_top) {}
+
// The class of the object.
- Handle<mirror::Class> type_handle_;
+ TypeHandle type_handle_;
// Whether or not the type is exact or a superclass of the actual type.
+ // Whether or not we have any information about this type.
bool is_exact_;
// A true value here means that the object type should be java.lang.Object.
// We don't have access to the corresponding mirror object every time so this
@@ -968,7 +965,8 @@
locations_(nullptr),
live_interval_(nullptr),
lifetime_position_(kNoLifetime),
- side_effects_(side_effects) {}
+ side_effects_(side_effects),
+ reference_type_info_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {}
virtual ~HInstruction() {}
@@ -2740,7 +2738,8 @@
type_index_(type_index),
is_referrers_class_(is_referrers_class),
dex_pc_(dex_pc),
- generate_clinit_check_(false) {}
+ generate_clinit_check_(false),
+ loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {}
bool CanBeMoved() const OVERRIDE { return true; }
@@ -3006,6 +3005,32 @@
DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
};
+class HBoundType : public HExpression<1> {
+ public:
+ HBoundType(HInstruction* input, ReferenceTypeInfo bound_type)
+ : HExpression(Primitive::kPrimNot, SideEffects::None()),
+ bound_type_(bound_type) {
+ SetRawInputAt(0, input);
+ }
+
+ const ReferenceTypeInfo& GetBoundType() const { return bound_type_; }
+
+ bool CanBeNull() const OVERRIDE {
+ // `null instanceof ClassX` always return false so we can't be null.
+ return false;
+ }
+
+ DECLARE_INSTRUCTION(BoundType);
+
+ private:
+ // Encodes the most upper class that this instruction can have. In other words
+ // it is always the case that GetBoundType().IsSupertypeOf(GetReferenceType()).
+ // It is used to bound the type in cases like `if (x instanceof ClassX) {}`
+ const ReferenceTypeInfo bound_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(HBoundType);
+};
+
class HCheckCast : public HTemplateInstruction<2> {
public:
HCheckCast(HInstruction* object,