// A ReferenceInfo contains additional info about a reference such as // whether it's a singleton, returned, etc. class ReferenceInfo : public DeletableArenaObject<kArenaAllocLSA> { public:
ReferenceInfo(HInstruction* reference, size_t pos)
: reference_(reference),
position_(pos),
is_singleton_(true),
is_singleton_and_not_returned_(true),
is_singleton_and_not_deopt_visible_(true),
is_singleton_and_not_read_by_invoke_(true) {
CalculateEscape(reference_,
nullptr,
&is_singleton_,
&is_singleton_and_not_returned_,
&is_singleton_and_not_deopt_visible_,
&is_singleton_and_not_read_by_invoke_);
}
// Returns true if reference_ is the only name that can refer to its value during // the lifetime of the method. So it's guaranteed to not have any alias in // the method (including its callees). bool IsSingleton() const { return is_singleton_;
}
private:
HInstruction* const reference_; // Position in which it was inserted into the ref_infos_ vector. A smaller number means that this // reference was seen before a reference with a bigger number. const size_t position_;
// Can only be referred to by a single name in the method. bool is_singleton_; // Is singleton and not returned to caller. bool is_singleton_and_not_returned_; // Is singleton and not used as an environment local of HDeoptimize. bool is_singleton_and_not_deopt_visible_; // Is singleton and no invocation is reading it. bool is_singleton_and_not_read_by_invoke_;
DISALLOW_COPY_AND_ASSIGN(ReferenceInfo);
};
// A heap location is a reference-offset/index pair that a value can be loaded from // or stored to. class HeapLocation : public ArenaObject<kArenaAllocLSA> { public: static constexpr size_t kInvalidFieldOffset = -1; // Default value for heap locations which are not vector data. static constexpr size_t kScalar = 1; // TODO: more fine-grained array types. static constexpr int16_t kDeclaringClassDefIndexForArrays = -1;
private: // Reference for instance/static field, array element or vector data.
ReferenceInfo* const ref_info_; // Type of data residing at HeapLocation (always signed for integral // data since e.g. a[i] and a[i] & 0xff are represented by differently // signed types; char vs short are disambiguated through the reference). const DataType::Type type_; // Offset of static/instance field. // Invalid when this HeapLocation is not field. const size_t offset_; // Index of an array element or starting index of vector data. // Invalid when this HeapLocation is not array.
HInstruction* const index_; // Vector length of vector data. // When this HeapLocation is not vector data, it's value is kScalar. const size_t vector_length_; // Declaring class's def's dex index. // Invalid when this HeapLocation is not field access. const int16_t declaring_class_def_index_; // Has aliased heap locations in the method, due to either the // reference is aliased or the array element is aliased via different // index names. bool has_aliased_locations_; // Whether this HeapLocation represents a vector operation. bool is_vec_op_;
DISALLOW_COPY_AND_ASSIGN(HeapLocation);
};
// A HeapLocationCollector collects all relevant heap locations and keeps // an aliasing matrix for all locations. class HeapLocationCollector final : public CRTPGraphVisitor<HeapLocationCollector> { public: static constexpr size_t kHeapLocationNotFound = -1; // Start with a single uint32_t word. That's enough bits for pair-wise // aliasing matrix of 8 heap locations. static constexpr uint32_t kInitialAliasingMatrixBitVectorSize = 32;
// Find and return the heap location index in heap_locations_. // NOTE: When heap locations are created, potentially aliasing/overlapping // accesses are given different indexes. This find function also // doesn't take aliasing/overlapping into account. For example, // this function returns three different indexes for: // - ref_info=array, index=i, vector_length=kScalar; // - ref_info=array, index=i, vector_length=2; // - ref_info=array, index=i, vector_length=4; // In later analysis, ComputeMayAlias() and MayAlias() compute and tell whether // these indexes alias.
size_t FindHeapLocationIndex(ReferenceInfo* ref_info,
DataType::Type type,
size_t offset,
HInstruction* index,
size_t vector_length,
int16_t declaring_class_def_index, bool is_vec_op) const {
DataType::Type lookup_type = DataType::ToSigned(type); for (size_t i = 0; i < heap_locations_.size(); i++) {
HeapLocation* loc = heap_locations_[i]; if (loc->GetReferenceInfo() == ref_info &&
loc->GetType() == lookup_type &&
loc->GetOffset() == offset &&
loc->GetIndex() == index &&
loc->GetVectorLength() == vector_length &&
loc->GetDeclaringClassDefIndex() == declaring_class_def_index &&
loc->IsVecOp() == is_vec_op) { return i;
}
} return kHeapLocationNotFound;
}
// Get some estimated statistics based on our analysis. void DumpReferenceStats(OptimizingCompilerStats* stats);
// Returns true if heap_locations_[index1] and heap_locations_[index2] may alias. bool MayAlias(size_t index1, size_t index2) const { if (index1 < index2) { return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index1, index2));
} elseif (index1 > index2) { return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index2, index1));
} else {
DCHECK(false) << "index1 and index2 are expected to be different"; returntrue;
}
}
void BuildAliasingMatrix() { const size_t number_of_locations = heap_locations_.size(); if (number_of_locations == 0) { return;
}
size_t pos = 0; // Compute aliasing info between every pair of different heap locations. // Save the result in a matrix represented as a BitVector. for (size_t i = 0; i < number_of_locations - 1; i++) { for (size_t j = i + 1; j < number_of_locations; j++) { if (ComputeMayAlias(i, j)) {
aliasing_matrix_.SetBit(CheckedAliasingMatrixPosition(i, j, pos));
}
pos++;
}
}
}
private: // An allocation cannot alias with a name which already exists at the point // of the allocation, such as a parameter or a load happening before the allocation. staticbool MayAliasWithPreexistenceChecking(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) { if (ref_info1->GetReference()->IsNewInstance() || ref_info1->GetReference()->IsNewArray()) { // Any reference that can alias with the allocation must appear after it in the block/in // the block's successors. In reverse post order, those instructions will be visited after // the allocation. return ref_info2->GetPosition() >= ref_info1->GetPosition();
} returntrue;
}
// `index1` and `index2` are indices in the array of collected heap locations. // Returns the position in the bit vector that tracks whether the two heap // locations may alias.
size_t AliasingMatrixPosition(size_t index1, size_t index2) const {
DCHECK(index2 > index1); const size_t number_of_locations = heap_locations_.size(); // It's (num_of_locations - 1) + ... + (num_of_locations - index1) + (index2 - index1 - 1). return (number_of_locations * index1 - (1 + index1) * index1 / 2 + (index2 - index1 - 1));
}
// An additional position is passed in to make sure the calculated position is correct.
size_t CheckedAliasingMatrixPosition(size_t index1, size_t index2, size_t position) {
size_t calculated_position = AliasingMatrixPosition(index1, index2);
DCHECK_EQ(calculated_position, position); return calculated_position;
}
// Compute if two locations may alias to each other. bool ComputeMayAlias(size_t index1, size_t index2) const {
DCHECK_NE(index1, index2);
HeapLocation* loc1 = heap_locations_[index1];
HeapLocation* loc2 = heap_locations_[index2]; if (loc1->GetOffset() != loc2->GetOffset()) { // Either two different instance fields, or one is an instance // field and the other is an array data. returnfalse;
} if (loc1->GetDeclaringClassDefIndex() != loc2->GetDeclaringClassDefIndex()) { // Different types. returnfalse;
} if (!CanReferencesAlias(loc1->GetReferenceInfo(), loc2->GetReferenceInfo())) { returnfalse;
} if (loc1->IsArray() && loc2->IsArray()) {
HInstruction* idx1 = loc1->GetIndex();
HInstruction* idx2 = loc2->GetIndex();
size_t vector_length1 = loc1->GetVectorLength();
size_t vector_length2 = loc2->GetVectorLength(); if (!CanArrayElementsAlias(idx1, vector_length1, idx2, vector_length2)) { returnfalse;
}
}
loc1->SetHasAliasedLocations(true);
loc2->SetHasAliasedLocations(true); returntrue;
}
void VisitInstruction(HInstruction* instruction) { // Any new-instance or new-array cannot alias with references that // pre-exist the new-instance/new-array. The entries of ref_infos_ keep track of the order of // creation of reference values since we visit the blocks in reverse post order. // // By default, VisitXXX() (including VisitPhi()) calls VisitInstruction(), // unless VisitXXX() is overridden. VisitInstanceFieldGet() etc. above // also call CreateReferenceInfoForReferenceType() explicitly.
CreateReferenceInfoForReferenceType(instruction);
}
ScopedArenaAllocator* allocator_; // All references used for heap accesses, accessed via instruction id.
ScopedArenaVector<ReferenceInfo*> ref_infos_; // How many non-null ReferenceInfo* are in ref_infos_.
size_t ref_infos_created_;
ScopedArenaVector<HeapLocation*> heap_locations_; // All heap locations.
ArenaBitVector aliasing_matrix_; // aliasing info between each pair of locations. bool has_heap_stores_; // If there is no heap stores, LSE acts as GVN with better // alias analysis and won't be as effective.