Merge "Revert "Use the object class as top in reference type propagation""
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index d6b5636..694b68c 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -469,14 +469,19 @@
if (instruction->IsLoadClass()) {
ReferenceTypeInfo info = instruction->AsLoadClass()->GetLoadedClassRTI();
ScopedObjectAccess soa(Thread::Current());
- DCHECK(info.IsValid()) << "Invalid RTI for " << instruction->DebugName();
- StartAttributeStream("klass") << PrettyDescriptor(info.GetTypeHandle().Get());
- StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha;
+ if (info.GetTypeHandle().GetReference() != nullptr) {
+ StartAttributeStream("klass") << PrettyDescriptor(info.GetTypeHandle().Get());
+ } else {
+ StartAttributeStream("klass") << "unresolved";
+ }
} else {
ReferenceTypeInfo info = instruction->GetReferenceTypeInfo();
- ScopedObjectAccess soa(Thread::Current());
- DCHECK(info.IsValid()) << "Invalid RTI for " << instruction->DebugName();
- StartAttributeStream("klass") << PrettyDescriptor(info.GetTypeHandle().Get());
+ if (info.IsTop()) {
+ StartAttributeStream("klass") << "java.lang.Object";
+ } else {
+ ScopedObjectAccess soa(Thread::Current());
+ StartAttributeStream("klass") << PrettyDescriptor(info.GetTypeHandle().Get());
+ }
StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha;
}
}
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 1551c15..cea7dd9 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -109,8 +109,10 @@
receiver = receiver->InputAt(0);
}
ReferenceTypeInfo info = receiver->GetReferenceTypeInfo();
- DCHECK(info.IsValid()) << "Invalid RTI for " << receiver->DebugName();
- if (!info.IsExact()) {
+ if (info.IsTop()) {
+ // We have no information on the receiver.
+ return nullptr;
+ } else if (!info.IsExact()) {
// We currently only support inlining with known receivers.
// TODO: Remove this check, we should be able to inline final methods
// on unknown receivers.
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 1089812..b30b6c7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -195,16 +195,16 @@
// Returns whether doing a type test between the class of `object` against `klass` has
// a statically known outcome. The result of the test is stored in `outcome`.
static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bool* outcome) {
- ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
- ScopedObjectAccess soa(Thread::Current());
- if (!obj_rti.IsValid()) {
- // We run the simplifier before the reference type propagation so type info might not be
- // available.
+ if (!klass->IsResolved()) {
+ // If the class couldn't be resolve it's not safe to compare against it. It's
+ // default type would be Top which might be wider that the actual class type
+ // and thus producing wrong results.
return false;
}
+ ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI();
- DCHECK(class_rti.IsValid() && class_rti.IsExact());
+ ScopedObjectAccess soa(Thread::Current());
if (class_rti.IsSupertypeOf(obj_rti)) {
*outcome = true;
return true;
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 296c1b0..519fa00 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1757,39 +1757,11 @@
}
}
-void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) {
- if (kIsDebugBuild) {
- DCHECK_EQ(GetType(), Primitive::kPrimNot);
- ScopedObjectAccess soa(Thread::Current());
- DCHECK(rti.IsValid()) << "Invalid RTI for " << DebugName();
- if (IsBoundType()) {
- // Having the test here spares us from making the method virtual just for
- // the sake of a DCHECK.
- ReferenceTypeInfo upper_bound_rti = AsBoundType()->GetUpperBound();
- DCHECK(upper_bound_rti.IsSupertypeOf(rti))
- << " upper_bound_rti: " << upper_bound_rti
- << " rti: " << rti;
- DCHECK(!upper_bound_rti.GetTypeHandle()->IsFinal() || rti.IsExact());
- }
- }
- reference_type_info_ = rti;
-}
-
-ReferenceTypeInfo::ReferenceTypeInfo() : type_handle_(TypeHandle()), is_exact_(false) {}
-
-ReferenceTypeInfo::ReferenceTypeInfo(TypeHandle type_handle, bool is_exact)
- : type_handle_(type_handle), is_exact_(is_exact) {
- if (kIsDebugBuild) {
- ScopedObjectAccess soa(Thread::Current());
- DCHECK(IsValidHandle(type_handle));
- }
-}
-
std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs) {
ScopedObjectAccess soa(Thread::Current());
os << "["
- << " is_valid=" << rhs.IsValid()
- << " type=" << (!rhs.IsValid() ? "?" : PrettyClass(rhs.GetTypeHandle().Get()))
+ << " is_top=" << rhs.IsTop()
+ << " type=" << (rhs.IsTop() ? "?" : PrettyClass(rhs.GetTypeHandle().Get()))
<< " is_exact=" << rhs.IsExact()
<< " ]";
return os;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index d9cdfea..903e02e 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1460,63 +1460,79 @@
public:
typedef Handle<mirror::Class> TypeHandle;
- static ReferenceTypeInfo Create(TypeHandle type_handle, bool is_exact) {
- // The constructor will check that the type_handle is valid.
- return ReferenceTypeInfo(type_handle, is_exact);
+ 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 CreateInvalid() { return ReferenceTypeInfo(); }
-
- static bool IsValidHandle(TypeHandle handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return handle.GetReference() != nullptr;
+ static ReferenceTypeInfo CreateTop(bool is_exact) {
+ return ReferenceTypeInfo(TypeHandle(), is_exact, true);
}
- bool IsValid() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return IsValidHandle(type_handle_);
- }
bool IsExact() const { return is_exact_; }
- bool IsObjectClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(IsValid());
- return GetTypeHandle()->IsObjectClass();
- }
+ bool IsTop() const { return is_top_; }
bool IsInterface() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(IsValid());
- return GetTypeHandle()->IsInterface();
+ return !IsTop() && GetTypeHandle()->IsInterface();
}
Handle<mirror::Class> GetTypeHandle() const { return type_handle_; }
bool IsSupertypeOf(ReferenceTypeInfo rti) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(IsValid());
- DCHECK(rti.IsValid());
+ if (IsTop()) {
+ // Top (equivalent for java.lang.Object) is supertype of anything.
+ return true;
+ }
+ if (rti.IsTop()) {
+ // If we get here `this` is not Top() so it can't be a supertype.
+ return false;
+ }
return GetTypeHandle()->IsAssignableFrom(rti.GetTypeHandle().Get());
}
// Returns true if the type information provide the same amount of details.
// Note that it does not mean that the instructions have the same actual type
- // (because the type can be the result of a merge).
+ // (e.g. tops are equal but they can be the result of a merge).
bool IsEqual(ReferenceTypeInfo rti) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (!IsValid() && !rti.IsValid()) {
- // Invalid types are equal.
- return true;
- }
- if (!IsValid() || !rti.IsValid()) {
- // One is valid, the other not.
+ if (IsExact() != rti.IsExact()) {
return false;
}
- return IsExact() == rti.IsExact()
- && GetTypeHandle().Get() == rti.GetTypeHandle().Get();
+ if (IsTop() && rti.IsTop()) {
+ // `Top` means java.lang.Object, so the types are equivalent.
+ return true;
+ }
+ if (IsTop() || rti.IsTop()) {
+ // If only one is top or object than they are not equivalent.
+ // NB: We need this extra check because the type_handle of `Top` is invalid
+ // and we cannot inspect its reference.
+ return false;
+ }
+
+ // Finally check the types.
+ return GetTypeHandle().Get() == rti.GetTypeHandle().Get();
}
private:
- ReferenceTypeInfo();
- ReferenceTypeInfo(TypeHandle type_handle, bool is_exact);
+ 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.
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
+ // flag acts as a substitute. When true, the TypeHandle refers to a null
+ // pointer and should not be used.
+ bool is_top_;
};
std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs);
@@ -1534,7 +1550,7 @@
live_interval_(nullptr),
lifetime_position_(kNoLifetime),
side_effects_(side_effects),
- reference_type_info_(ReferenceTypeInfo::CreateInvalid()) {}
+ reference_type_info_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {}
virtual ~HInstruction() {}
@@ -1591,7 +1607,10 @@
return false;
}
- void SetReferenceTypeInfo(ReferenceTypeInfo rti);
+ void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) {
+ DCHECK_EQ(GetType(), Primitive::kPrimNot);
+ reference_type_info_ = reference_type_info;
+ }
ReferenceTypeInfo GetReferenceTypeInfo() const {
DCHECK_EQ(GetType(), Primitive::kPrimNot);
@@ -3886,7 +3905,7 @@
is_referrers_class_(is_referrers_class),
dex_pc_(dex_pc),
generate_clinit_check_(false),
- loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) {
+ loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {
SetRawInputAt(0, current_method);
}
@@ -3937,6 +3956,10 @@
loaded_class_rti_ = rti;
}
+ bool IsResolved() {
+ return loaded_class_rti_.IsExact();
+ }
+
const DexFile& GetDexFile() { return dex_file_; }
bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; }
@@ -4179,15 +4202,12 @@
class HBoundType : public HExpression<1> {
public:
- // Constructs an HBoundType with the given upper_bound.
- // Ensures that the upper_bound is valid.
HBoundType(HInstruction* input, ReferenceTypeInfo upper_bound, bool upper_can_be_null)
: HExpression(Primitive::kPrimNot, SideEffects::None()),
upper_bound_(upper_bound),
upper_can_be_null_(upper_can_be_null) {
DCHECK_EQ(input->GetType(), Primitive::kPrimNot);
SetRawInputAt(0, input);
- SetReferenceTypeInfo(upper_bound_);
}
// GetUpper* should only be used in reference type propagation.
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d11a441..84db62b 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -25,26 +25,13 @@
class RTPVisitor : public HGraphDelegateVisitor {
public:
- RTPVisitor(HGraph* graph,
- StackHandleScopeCollection* handles,
- GrowableArray<HInstruction*>* worklist,
- ReferenceTypeInfo::TypeHandle object_class_handle,
- ReferenceTypeInfo::TypeHandle class_class_handle,
- ReferenceTypeInfo::TypeHandle string_class_handle)
+ RTPVisitor(HGraph* graph, StackHandleScopeCollection* handles)
: HGraphDelegateVisitor(graph),
- handles_(handles),
- object_class_handle_(object_class_handle),
- class_class_handle_(class_class_handle),
- string_class_handle_(string_class_handle),
- worklist_(worklist) {}
+ handles_(handles) {}
- void VisitNullConstant(HNullConstant* null_constant) OVERRIDE;
void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
- void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
- void VisitLoadString(HLoadString* instr) OVERRIDE;
void VisitNewArray(HNewArray* instr) OVERRIDE;
- void VisitParameterValue(HParameterValue* instr) OVERRIDE;
void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
@@ -52,8 +39,6 @@
void VisitInvoke(HInvoke* instr) OVERRIDE;
void VisitArrayGet(HArrayGet* instr) OVERRIDE;
void VisitCheckCast(HCheckCast* instr) OVERRIDE;
- void VisitNullCheck(HNullCheck* instr) OVERRIDE;
- void VisitFakeString(HFakeString* instr) OVERRIDE;
void UpdateReferenceTypeInfo(HInstruction* instr,
uint16_t type_idx,
const DexFile& dex_file,
@@ -61,33 +46,8 @@
private:
StackHandleScopeCollection* handles_;
- ReferenceTypeInfo::TypeHandle object_class_handle_;
- ReferenceTypeInfo::TypeHandle class_class_handle_;
- ReferenceTypeInfo::TypeHandle string_class_handle_;
- GrowableArray<HInstruction*>* worklist_;
-
- static constexpr size_t kDefaultWorklistSize = 8;
};
-ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
- StackHandleScopeCollection* handles,
- const char* name)
- : HOptimization(graph, name),
- handles_(handles),
- worklist_(graph->GetArena(), kDefaultWorklistSize) {
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
- string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
- class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
-
- if (kIsDebugBuild) {
- ScopedObjectAccess soa(Thread::Current());
- DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
- DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
- DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
- }
-}
-
void ReferenceTypePropagation::Run() {
// To properly propagate type info we need to visit in the dominator-based order.
// Reverse post order guarantees a node's dominators are visited first.
@@ -96,51 +56,24 @@
VisitBasicBlock(it.Current());
}
ProcessWorklist();
-
- if (kIsDebugBuild) {
- // TODO: move this to the graph checker.
- ScopedObjectAccess soa(Thread::Current());
- for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
- HBasicBlock* block = it.Current();
- for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
- HInstruction* instr = iti.Current();
- if (instr->GetType() == Primitive::kPrimNot) {
- DCHECK(instr->GetReferenceTypeInfo().IsValid())
- << "Invalid RTI for instruction: " << instr->DebugName();
- if (instr->IsBoundType()) {
- DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
- } else if (instr->IsLoadClass()) {
- DCHECK(instr->AsLoadClass()->GetReferenceTypeInfo().IsExact());
- DCHECK(instr->AsLoadClass()->GetLoadedClassRTI().IsValid());
- } else if (instr->IsNullCheck()) {
- DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
- << "NullCheck " << instr->GetReferenceTypeInfo()
- << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
- }
- }
- }
- }
- }
}
void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
- RTPVisitor visitor(graph_,
- handles_,
- &worklist_,
- object_class_handle_,
- class_class_handle_,
- string_class_handle_);
- // Handle Phis first as there might be instructions in the same block who depend on them.
- for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
- VisitPhi(it.Current()->AsPhi());
- }
+ // TODO: handle other instructions that give type info
+ // (array accesses)
- // Handle instructions.
+ RTPVisitor visitor(graph_, handles_);
+ // Initialize exact types first for faster convergence.
for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* instr = it.Current();
instr->Accept(&visitor);
}
+ // Handle Phis.
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ VisitPhi(it.Current()->AsPhi());
+ }
+
// Add extra nodes to bound types.
BoundTypeForIfNotNull(block);
BoundTypeForIfInstanceOf(block);
@@ -158,10 +91,10 @@
ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
// Narrow the type as much as possible.
- if (class_rti.GetTypeHandle()->IsFinal()) {
+ if (load_class->IsResolved() && class_rti.GetTypeHandle()->IsFinal()) {
bound_type->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
- } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
+ } else if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
bound_type->SetReferenceTypeInfo(obj_rti);
} else {
bound_type->SetReferenceTypeInfo(
@@ -252,14 +185,10 @@
if (bound_type == nullptr) {
ScopedObjectAccess soa(Thread::Current());
HInstruction* insert_point = notNullBlock->GetFirstInstruction();
- ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
- object_class_handle_, /* is_exact */ true);
+ ReferenceTypeInfo object_rti = ReferenceTypeInfo::CreateTop(false);
if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
bound_type = new (graph_->GetArena()) HBoundType(
obj, object_rti, /* bound_can_be_null */ false);
- if (obj->GetReferenceTypeInfo().IsValid()) {
- bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
- }
notNullBlock->InsertInstructionBefore(bound_type, insert_point);
} else {
// We already have a bound type on the position we would need to insert
@@ -346,32 +275,11 @@
void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
mirror::Class* klass,
bool is_exact) {
- if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
- // Calls to String.<init> are replaced with a StringFactory.
- if (kIsDebugBuild) {
- ScopedObjectAccess soa(Thread::Current());
- ClassLinker* cl = Runtime::Current()->GetClassLinker();
- mirror::DexCache* dex_cache = cl->FindDexCache(instr->AsInvoke()->GetDexFile());
- ArtMethod* method = dex_cache->GetResolvedMethod(
- instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
- DCHECK(method != nullptr);
- mirror::Class* declaring_class = method->GetDeclaringClass();
- DCHECK(declaring_class != nullptr);
- DCHECK(declaring_class->IsStringClass())
- << "Expected String class: " << PrettyDescriptor(declaring_class);
- DCHECK(method->IsConstructor())
- << "Expected String.<init>: " << PrettyMethod(method);
- }
- instr->SetReferenceTypeInfo(
- ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
- } else if (klass != nullptr) {
+ if (klass != nullptr) {
ScopedObjectAccess soa(Thread::Current());
- ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
+ MutableHandle<mirror::Class> handle = handles_->NewHandle(klass);
is_exact = is_exact || klass->IsFinal();
instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
- } else {
- instr->SetReferenceTypeInfo(
- ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
}
}
@@ -387,11 +295,6 @@
SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
}
-void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
- instr->SetReferenceTypeInfo(
- ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
-}
-
void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
}
@@ -400,13 +303,6 @@
UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
}
-void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
- if (instr->GetType() == Primitive::kPrimNot) {
- // TODO: parse the signature and add precise types for the parameters.
- SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
- }
-}
-
void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
const FieldInfo& info) {
// The field index is unknown only during tests.
@@ -418,10 +314,10 @@
ClassLinker* cl = Runtime::Current()->GetClassLinker();
mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
- // TODO: There are certain cases where we can't resolve the field.
- // b/21914925 is open to keep track of a repro case for this issue.
- mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
- SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+ if (field != nullptr) {
+ mirror::Class* klass = field->GetType<false>();
+ SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+ }
}
void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
@@ -438,29 +334,12 @@
Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
// Get type from dex cache assuming it was populated by the verifier.
mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
- DCHECK(resolved_class != nullptr);
- ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(resolved_class);
- instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
- instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
-}
-
-void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
- instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
-}
-
-void RTPVisitor::VisitLoadString(HLoadString* instr) {
- instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
-}
-
-void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
- ScopedObjectAccess soa(Thread::Current());
- ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
- DCHECK(parent_rti.IsValid());
- instr->SetReferenceTypeInfo(parent_rti);
-}
-
-void RTPVisitor::VisitFakeString(HFakeString* instr) {
- instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
+ if (resolved_class != nullptr) {
+ Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
+ instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
+ }
+ Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_handle, /* is_exact */ true));
}
void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
@@ -516,54 +395,29 @@
ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
const ReferenceTypeInfo& b) {
- if (!b.IsValid()) {
- return a;
- }
- if (!a.IsValid()) {
- return b;
- }
-
bool is_exact = a.IsExact() && b.IsExact();
+ bool is_top = a.IsTop() || b.IsTop();
Handle<mirror::Class> type_handle;
- if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
- type_handle = a.GetTypeHandle();
- } else if (a.IsSupertypeOf(b)) {
- type_handle = a.GetTypeHandle();
- is_exact = false;
- } else if (b.IsSupertypeOf(a)) {
- type_handle = b.GetTypeHandle();
- is_exact = false;
- } else {
- // TODO: Find the first common super class.
- type_handle = object_class_handle_;
- is_exact = false;
+ if (!is_top) {
+ if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
+ type_handle = a.GetTypeHandle();
+ } else if (a.IsSupertypeOf(b)) {
+ type_handle = a.GetTypeHandle();
+ is_exact = false;
+ } else if (b.IsSupertypeOf(a)) {
+ type_handle = b.GetTypeHandle();
+ is_exact = false;
+ } else {
+ // TODO: Find a common super class.
+ is_top = true;
+ is_exact = false;
+ }
}
- return ReferenceTypeInfo::Create(type_handle, is_exact);
-}
-
-static void UpdateArrayGet(HArrayGet* instr,
- StackHandleScopeCollection* handles,
- ReferenceTypeInfo::TypeHandle object_class_handle)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
-
- ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
- DCHECK(parent_rti.IsValid());
-
- Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
- if (handle->IsObjectArrayClass()) {
- ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
- instr->SetReferenceTypeInfo(
- ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
- } else {
- // We don't know what the parent actually is, so we fallback to object.
- instr->SetReferenceTypeInfo(
- ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
- }
-
- return;
+ return is_top
+ ? ReferenceTypeInfo::CreateTop(is_exact)
+ : ReferenceTypeInfo::Create(type_handle, is_exact);
}
bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
@@ -574,15 +428,6 @@
UpdateBoundType(instr->AsBoundType());
} else if (instr->IsPhi()) {
UpdatePhi(instr->AsPhi());
- } else if (instr->IsNullCheck()) {
- ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
- if (parent_rti.IsValid()) {
- instr->SetReferenceTypeInfo(parent_rti);
- }
- } else if (instr->IsArrayGet()) {
- // TODO: consider if it's worth "looking back" and bounding the input object
- // to an array type.
- UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
} else {
LOG(FATAL) << "Invalid instruction (should not get here)";
}
@@ -600,28 +445,28 @@
mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
ArtMethod* method = dex_cache->GetResolvedMethod(
instr->GetDexMethodIndex(), cl->GetImagePointerSize());
- mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false);
- SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+ if (method != nullptr) {
+ mirror::Class* klass = method->GetReturnType(false);
+ SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+ }
}
void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
if (instr->GetType() != Primitive::kPrimNot) {
return;
}
+
+ HInstruction* parent = instr->InputAt(0);
ScopedObjectAccess soa(Thread::Current());
- UpdateArrayGet(instr, handles_, object_class_handle_);
- if (!instr->GetReferenceTypeInfo().IsValid()) {
- worklist_->Add(instr);
+ Handle<mirror::Class> handle = parent->GetReferenceTypeInfo().GetTypeHandle();
+ if (handle.GetReference() != nullptr && handle->IsObjectArrayClass()) {
+ SetClassAsTypeInfo(instr, handle->GetComponentType(), /* is_exact */ false);
}
}
void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
- if (!new_rti.IsValid()) {
- return; // No new info yet.
- }
-
- // Make sure that we don't go over the bounded type.
+ // Be sure that we don't go over the bounded type.
ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
new_rti = upper_bound_rti;
@@ -631,14 +476,14 @@
void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
- if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
- // Early return if we are Object and inexact.
+ if (new_rti.IsTop() && !new_rti.IsExact()) {
+ // Early return if we are Top and inexact.
instr->SetReferenceTypeInfo(new_rti);
return;
}
for (size_t i = 1; i < instr->InputCount(); i++) {
new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
- if (new_rti.IsValid() && new_rti.IsObjectClass()) {
+ if (new_rti.IsTop()) {
if (!new_rti.IsExact()) {
break;
} else {
@@ -652,14 +497,7 @@
// Re-computes and updates the nullability of the instruction. Returns whether or
// not the nullability was changed.
bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
- DCHECK(instr->IsPhi()
- || instr->IsBoundType()
- || instr->IsNullCheck()
- || instr->IsArrayGet());
-
- if (!instr->IsPhi() && !instr->IsBoundType()) {
- return false;
- }
+ DCHECK(instr->IsPhi() || instr->IsBoundType());
bool existing_can_be_null = instr->CanBeNull();
if (instr->IsPhi()) {
@@ -689,18 +527,14 @@
}
void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
- DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
- << instruction->DebugName() << ":" << instruction->GetType();
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) << instruction->GetType();
worklist_.Add(instruction);
}
void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
HInstruction* user = it.Current()->GetUser();
- if (user->IsPhi()
- || user->IsBoundType()
- || user->IsNullCheck()
- || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
+ if (user->IsPhi() || user->IsBoundType()) {
AddToWorklist(user);
}
}
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 9196b56..e8680ea 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -32,7 +32,10 @@
public:
ReferenceTypePropagation(HGraph* graph,
StackHandleScopeCollection* handles,
- const char* name = kReferenceTypePropagationPassName);
+ const char* name = kReferenceTypePropagationPassName)
+ : HOptimization(graph, name),
+ handles_(handles),
+ worklist_(graph->GetArena(), kDefaultWorklistSize) {}
void Run() OVERRIDE;
@@ -59,10 +62,6 @@
GrowableArray<HInstruction*> worklist_;
- ReferenceTypeInfo::TypeHandle object_class_handle_;
- ReferenceTypeInfo::TypeHandle class_class_handle_;
- ReferenceTypeInfo::TypeHandle string_class_handle_;
-
static constexpr size_t kDefaultWorklistSize = 8;
DISALLOW_COPY_AND_ASSIGN(ReferenceTypePropagation);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 73a194d..fc27315 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -909,33 +909,6 @@
DCHECK_EQ(pointer_size, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
-inline Class* Class::GetComponentType() {
- return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(ComponentTypeOffset());
-}
-
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
-inline bool Class::IsArrayClass() {
- return GetComponentType<kVerifyFlags, kReadBarrierOption>() != nullptr;
-}
-
-inline bool Class::IsAssignableFrom(Class* src) {
- DCHECK(src != nullptr);
- if (this == src) {
- // Can always assign to things of the same type.
- return true;
- } else if (IsObjectClass()) {
- // Can assign any reference to java.lang.Object.
- return !src->IsPrimitive();
- } else if (IsInterface()) {
- return src->Implements(this);
- } else if (src->IsArrayClass()) {
- return IsAssignableFromArray(src);
- } else {
- return !src->IsInterface() && src->IsSubClass(this);
- }
-}
-
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index cc63dec..ba0a9fc 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -403,7 +403,9 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return GetComponentType<kVerifyFlags, kReadBarrierOption>() != nullptr;
+ }
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
@@ -420,7 +422,9 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(ComponentTypeOffset());
+ }
void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(GetComponentType() == nullptr);
@@ -612,7 +616,22 @@
// downcast would be necessary. Similarly for interfaces, a class that implements (or an interface
// that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign
// to themselves. Classes for primitive types may not assign to each other.
- ALWAYS_INLINE bool IsAssignableFrom(Class* src) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ALWAYS_INLINE bool IsAssignableFrom(Class* src) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(src != nullptr);
+ if (this == src) {
+ // Can always assign to things of the same type.
+ return true;
+ } else if (IsObjectClass()) {
+ // Can assign any reference to java.lang.Object.
+ return !src->IsPrimitive();
+ } else if (IsInterface()) {
+ return src->Implements(this);
+ } else if (src->IsArrayClass()) {
+ return IsAssignableFromArray(src);
+ } else {
+ return !src->IsInterface() && src->IsSubClass(this);
+ }
+ }
ALWAYS_INLINE Class* GetSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index 530a05e..67060d9 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -415,11 +415,11 @@
}
/// CHECK-START: SubclassC Main.inlineGenerics() reference_type_propagation (after)
- /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:SubclassC exact:false
+ /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:SubclassC
/// CHECK-NEXT: Return [<<Invoke>>]
/// CHECK-START: SubclassC Main.inlineGenerics() reference_type_propagation_after_inlining (after)
- /// CHECK: <<BoundType:l\d+>> BoundType klass:SubclassC exact:false
+ /// CHECK: <<BoundType:l\d+>> BoundType klass:SubclassC
/// CHECK: Return [<<BoundType>>]
private SubclassC inlineGenerics() {
SubclassC c = get();
@@ -464,25 +464,6 @@
return f;
}
- private Super getSuper() {
- return new SubclassA();
- }
-
- /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) reference_type_propagation (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:Super
- /// CHECK: NullCheck [<<Phi>>] klass:Super
-
- /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) reference_type_propagation_after_inlining (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:SubclassA
- /// CHECK: NullCheck [<<Phi>>] klass:SubclassA
- private void updateNodesInTheSameBlockAsPhi(boolean cond) {
- Super s = getSuper();
- if (cond) {
- s = new SubclassA();
- }
- s.$noinline$f();
- }
-
public static void main(String[] args) {
}
}