diff options
Diffstat (limited to 'compiler/optimizing')
53 files changed, 776 insertions, 548 deletions
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc index fe7ecd1ae1..d7def774fd 100644 --- a/compiler/optimizing/block_builder.cc +++ b/compiler/optimizing/block_builder.cc @@ -29,7 +29,7 @@ HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t semantic_dex_pc, uint32_t store_dex_pc) { HBasicBlock* block = branch_targets_[store_dex_pc]; if (block == nullptr) { - block = new (arena_) HBasicBlock(graph_, semantic_dex_pc); + block = new (allocator_) HBasicBlock(graph_, semantic_dex_pc); branch_targets_[store_dex_pc] = block; } DCHECK_EQ(block->GetDexPc(), semantic_dex_pc); @@ -200,7 +200,7 @@ void HBasicBlockBuilder::ConnectBasicBlocks() { // Returns the TryItem stored for `block` or nullptr if there is no info for it. static const DexFile::TryItem* GetTryItem( HBasicBlock* block, - const ArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) { + const ScopedArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) { auto iterator = try_block_info.find(block->GetBlockId()); return (iterator == try_block_info.end()) ? nullptr : iterator->second; } @@ -212,7 +212,7 @@ static const DexFile::TryItem* GetTryItem( static void LinkToCatchBlocks(HTryBoundary* try_boundary, const DexFile::CodeItem& code_item, const DexFile::TryItem* try_item, - const ArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) { + const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) { for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) { try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress())); } @@ -253,8 +253,8 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // Keep a map of all try blocks and their respective TryItems. We do not use // the block's pointer but rather its id to ensure deterministic iteration. - ArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info( - std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info( + std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder)); // Obtain TryItem information for blocks with throwing instructions, and split // blocks which are both try & catch to simplify the graph. @@ -278,8 +278,8 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { } // Map from a handler dex_pc to the corresponding catch block. - ArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks( - std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaSafeMap<uint32_t, HBasicBlock*> catch_blocks( + std::less<uint32_t>(), local_allocator_->Adapter(kArenaAllocGraphBuilder)); // Iterate over catch blocks, create artifical landing pads if necessary to // simplify the CFG, and set metadata. @@ -302,8 +302,8 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { HBasicBlock* catch_block = GetBlockAt(address); bool is_try_block = (try_block_info.find(catch_block->GetBlockId()) != try_block_info.end()); if (is_try_block || MightHaveLiveNormalPredecessors(catch_block)) { - HBasicBlock* new_catch_block = new (arena_) HBasicBlock(graph_, address); - new_catch_block->AddInstruction(new (arena_) HGoto(address)); + HBasicBlock* new_catch_block = new (allocator_) HBasicBlock(graph_, address); + new_catch_block->AddInstruction(new (allocator_) HGoto(address)); new_catch_block->AddSuccessor(catch_block); graph_->AddBlock(new_catch_block); catch_block = new_catch_block; @@ -311,7 +311,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { catch_blocks.Put(address, catch_block); catch_block->SetTryCatchInformation( - new (arena_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_)); + new (allocator_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_)); } handlers_ptr = iterator.EndDataPointer(); } @@ -328,8 +328,8 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { if (GetTryItem(predecessor, try_block_info) != try_item) { // Found a predecessor not covered by the same TryItem. Insert entering // boundary block. - HTryBoundary* try_entry = - new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc()); + HTryBoundary* try_entry = new (allocator_) HTryBoundary( + HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc()); try_block->CreateImmediateDominator()->AddInstruction(try_entry); LinkToCatchBlocks(try_entry, code_item_, try_item, catch_blocks); break; @@ -357,7 +357,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // Insert TryBoundary and link to catch blocks. HTryBoundary* try_exit = - new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc()); + new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc()); graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); LinkToCatchBlocks(try_exit, code_item_, try_item, catch_blocks); } @@ -367,8 +367,8 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { bool HBasicBlockBuilder::Build() { DCHECK(graph_->GetBlocks().empty()); - graph_->SetEntryBlock(new (arena_) HBasicBlock(graph_, kNoDexPc)); - graph_->SetExitBlock(new (arena_) HBasicBlock(graph_, kNoDexPc)); + graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc)); + graph_->SetExitBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc)); // TODO(dbrazdil): Do CreateBranchTargets and ConnectBasicBlocks in one pass. if (!CreateBranchTargets()) { diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h index 4a0f78ce3d..79f7a7bc81 100644 --- a/compiler/optimizing/block_builder.h +++ b/compiler/optimizing/block_builder.h @@ -17,8 +17,8 @@ #ifndef ART_COMPILER_OPTIMIZING_BLOCK_BUILDER_H_ #define ART_COMPILER_OPTIMIZING_BLOCK_BUILDER_H_ -#include "base/arena_containers.h" -#include "base/arena_object.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "dex_file.h" #include "nodes.h" @@ -28,17 +28,21 @@ class HBasicBlockBuilder : public ValueObject { public: HBasicBlockBuilder(HGraph* graph, const DexFile* const dex_file, - const DexFile::CodeItem& code_item) - : arena_(graph->GetAllocator()), + const DexFile::CodeItem& code_item, + ScopedArenaAllocator* local_allocator) + : allocator_(graph->GetAllocator()), graph_(graph), dex_file_(dex_file), code_item_(code_item), + local_allocator_(local_allocator), branch_targets_(code_item.insns_size_in_code_units_, nullptr, - arena_->Adapter(kArenaAllocGraphBuilder)), - throwing_blocks_(kDefaultNumberOfThrowingBlocks, arena_->Adapter(kArenaAllocGraphBuilder)), + local_allocator->Adapter(kArenaAllocGraphBuilder)), + throwing_blocks_(kDefaultNumberOfThrowingBlocks, + local_allocator->Adapter(kArenaAllocGraphBuilder)), number_of_branches_(0u), - quicken_index_for_dex_pc_(std::less<uint32_t>(), arena_->Adapter()) {} + quicken_index_for_dex_pc_(std::less<uint32_t>(), + local_allocator->Adapter(kArenaAllocGraphBuilder)) {} // Creates basic blocks in `graph_` at branch target dex_pc positions of the // `code_item_`. Blocks are connected but left unpopulated with instructions. @@ -71,18 +75,19 @@ class HBasicBlockBuilder : public ValueObject { // handler dex_pcs. bool MightHaveLiveNormalPredecessors(HBasicBlock* catch_block); - ArenaAllocator* const arena_; + ArenaAllocator* const allocator_; HGraph* const graph_; const DexFile* const dex_file_; const DexFile::CodeItem& code_item_; - ArenaVector<HBasicBlock*> branch_targets_; - ArenaVector<HBasicBlock*> throwing_blocks_; + ScopedArenaAllocator* const local_allocator_; + ScopedArenaVector<HBasicBlock*> branch_targets_; + ScopedArenaVector<HBasicBlock*> throwing_blocks_; size_t number_of_branches_; // A table to quickly find the quicken index for the first instruction of a basic block. - ArenaSafeMap<uint32_t, uint32_t> quicken_index_for_dex_pc_; + ScopedArenaSafeMap<uint32_t, uint32_t> quicken_index_for_dex_pc_; static constexpr size_t kDefaultNumberOfThrowingBlocks = 2u; diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index 0255e7302c..9c2068ec5e 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -18,7 +18,8 @@ #include <limits> -#include "base/arena_containers.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "induction_var_range.h" #include "nodes.h" #include "side_effects_analysis.h" @@ -287,7 +288,7 @@ class ValueBound : public ValueObject { */ class ValueRange : public ArenaObject<kArenaAllocBoundsCheckElimination> { public: - ValueRange(ArenaAllocator* allocator, ValueBound lower, ValueBound upper) + ValueRange(ScopedArenaAllocator* allocator, ValueBound lower, ValueBound upper) : allocator_(allocator), lower_(lower), upper_(upper) {} virtual ~ValueRange() {} @@ -297,7 +298,7 @@ class ValueRange : public ArenaObject<kArenaAllocBoundsCheckElimination> { return AsMonotonicValueRange() != nullptr; } - ArenaAllocator* GetAllocator() const { return allocator_; } + ScopedArenaAllocator* GetAllocator() const { return allocator_; } ValueBound GetLower() const { return lower_; } ValueBound GetUpper() const { return upper_; } @@ -350,7 +351,7 @@ class ValueRange : public ArenaObject<kArenaAllocBoundsCheckElimination> { } private: - ArenaAllocator* const allocator_; + ScopedArenaAllocator* const allocator_; const ValueBound lower_; // inclusive const ValueBound upper_; // inclusive @@ -365,7 +366,7 @@ class ValueRange : public ArenaObject<kArenaAllocBoundsCheckElimination> { */ class MonotonicValueRange : public ValueRange { public: - MonotonicValueRange(ArenaAllocator* allocator, + MonotonicValueRange(ScopedArenaAllocator* allocator, HPhi* induction_variable, HInstruction* initial, int32_t increment, @@ -510,21 +511,19 @@ class BCEVisitor : public HGraphVisitor { const SideEffectsAnalysis& side_effects, HInductionVarAnalysis* induction_analysis) : HGraphVisitor(graph), + allocator_(graph->GetArenaStack()), maps_(graph->GetBlocks().size(), - ArenaSafeMap<int, ValueRange*>( + ScopedArenaSafeMap<int, ValueRange*>( std::less<int>(), - graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), - graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), - first_index_bounds_check_map_( - std::less<int>(), - graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), - early_exit_loop_( - std::less<uint32_t>(), - graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), - taken_test_loop_( - std::less<uint32_t>(), - graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), - finite_loop_(graph->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)), + allocator_.Adapter(kArenaAllocBoundsCheckElimination)), + allocator_.Adapter(kArenaAllocBoundsCheckElimination)), + first_index_bounds_check_map_(std::less<int>(), + allocator_.Adapter(kArenaAllocBoundsCheckElimination)), + early_exit_loop_(std::less<uint32_t>(), + allocator_.Adapter(kArenaAllocBoundsCheckElimination)), + taken_test_loop_(std::less<uint32_t>(), + allocator_.Adapter(kArenaAllocBoundsCheckElimination)), + finite_loop_(allocator_.Adapter(kArenaAllocBoundsCheckElimination)), has_dom_based_dynamic_bce_(false), initial_block_size_(graph->GetBlocks().size()), side_effects_(side_effects), @@ -569,7 +568,7 @@ class BCEVisitor : public HGraphVisitor { private: // Return the map of proven value ranges at the beginning of a basic block. - ArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) { + ScopedArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) { if (IsAddedBlock(basic_block)) { // Added blocks don't keep value ranges. return nullptr; @@ -580,7 +579,7 @@ class BCEVisitor : public HGraphVisitor { // Traverse up the dominator tree to look for value range info. ValueRange* LookupValueRange(HInstruction* instruction, HBasicBlock* basic_block) { while (basic_block != nullptr) { - ArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block); + ScopedArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block); if (map != nullptr) { if (map->find(instruction->GetId()) != map->end()) { return map->Get(instruction->GetId()); @@ -668,8 +667,8 @@ class BCEVisitor : public HGraphVisitor { if (successor != nullptr) { bool overflow; bool underflow; - ValueRange* new_left_range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* new_left_range = new (&allocator_) ValueRange( + &allocator_, left_range->GetBound(), right_range->GetBound().Add(left_compensation, &overflow, &underflow)); if (!overflow && !underflow) { @@ -677,8 +676,8 @@ class BCEVisitor : public HGraphVisitor { new_left_range); } - ValueRange* new_right_range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* new_right_range = new (&allocator_) ValueRange( + &allocator_, left_range->GetBound().Add(right_compensation, &overflow, &underflow), right_range->GetBound()); if (!overflow && !underflow) { @@ -750,8 +749,8 @@ class BCEVisitor : public HGraphVisitor { if (overflow || underflow) { return; } - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), ValueBound::Min(), new_upper); + ValueRange* new_range = new (&allocator_) ValueRange( + &allocator_, ValueBound::Min(), new_upper); ApplyRangeFromComparison(left, block, true_successor, new_range); } @@ -762,8 +761,8 @@ class BCEVisitor : public HGraphVisitor { if (overflow || underflow) { return; } - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), new_lower, ValueBound::Max()); + ValueRange* new_range = new (&allocator_) ValueRange( + &allocator_, new_lower, ValueBound::Max()); ApplyRangeFromComparison(left, block, false_successor, new_range); } } else if (cond == kCondGT || cond == kCondGE) { @@ -774,8 +773,8 @@ class BCEVisitor : public HGraphVisitor { if (overflow || underflow) { return; } - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), new_lower, ValueBound::Max()); + ValueRange* new_range = new (&allocator_) ValueRange( + &allocator_, new_lower, ValueBound::Max()); ApplyRangeFromComparison(left, block, true_successor, new_range); } @@ -785,8 +784,8 @@ class BCEVisitor : public HGraphVisitor { if (overflow || underflow) { return; } - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), ValueBound::Min(), new_upper); + ValueRange* new_range = new (&allocator_) ValueRange( + &allocator_, ValueBound::Min(), new_upper); ApplyRangeFromComparison(left, block, false_successor, new_range); } } else if (cond == kCondNE || cond == kCondEQ) { @@ -795,8 +794,7 @@ class BCEVisitor : public HGraphVisitor { // length == [c,d] yields [c, d] along true // length != [c,d] yields [c, d] along false if (!lower.Equals(ValueBound::Min()) || !upper.Equals(ValueBound::Max())) { - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), lower, upper); + ValueRange* new_range = new (&allocator_) ValueRange(&allocator_, lower, upper); ApplyRangeFromComparison( left, block, cond == kCondEQ ? true_successor : false_successor, new_range); } @@ -804,8 +802,8 @@ class BCEVisitor : public HGraphVisitor { // length == 0 yields [1, max] along false // length != 0 yields [1, max] along true if (lower.GetConstant() == 0 && upper.GetConstant() == 0) { - ValueRange* new_range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), ValueBound(nullptr, 1), ValueBound::Max()); + ValueRange* new_range = new (&allocator_) ValueRange( + &allocator_, ValueBound(nullptr, 1), ValueBound::Max()); ApplyRangeFromComparison( left, block, cond == kCondEQ ? false_successor : true_successor, new_range); } @@ -826,7 +824,7 @@ class BCEVisitor : public HGraphVisitor { // Non-constant index. ValueBound lower = ValueBound(nullptr, 0); // constant 0 ValueBound upper = ValueBound(array_length, -1); // array_length - 1 - ValueRange array_range(GetGraph()->GetAllocator(), lower, upper); + ValueRange array_range(&allocator_, lower, upper); // Try index range obtained by dominator-based analysis. ValueRange* index_range = LookupValueRange(index, block); if (index_range != nullptr && index_range->FitsIn(&array_range)) { @@ -875,8 +873,7 @@ class BCEVisitor : public HGraphVisitor { } else { ValueBound lower = ValueBound(nullptr, constant + 1); ValueBound upper = ValueBound::Max(); - ValueRange* range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), lower, upper); + ValueRange* range = new (&allocator_) ValueRange(&allocator_, lower, upper); AssignRange(block, array_length, range); } } @@ -938,8 +935,8 @@ class BCEVisitor : public HGraphVisitor { ValueRange* range = nullptr; if (increment == 0) { // Add constant 0. It's really a fixed value. - range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + range = new (&allocator_) ValueRange( + &allocator_, ValueBound(initial_value, 0), ValueBound(initial_value, 0)); } else { @@ -959,8 +956,8 @@ class BCEVisitor : public HGraphVisitor { bound = increment > 0 ? ValueBound::Min() : ValueBound::Max(); } } - range = new (GetGraph()->GetAllocator()) MonotonicValueRange( - GetGraph()->GetAllocator(), + range = new (&allocator_) MonotonicValueRange( + &allocator_, phi, initial_value, increment, @@ -1039,8 +1036,8 @@ class BCEVisitor : public HGraphVisitor { !ValueBound::WouldAddOverflowOrUnderflow(c0, -c1)) { if ((c0 - c1) <= 0) { // array.length + (c0 - c1) won't overflow/underflow. - ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* range = new (&allocator_) ValueRange( + &allocator_, ValueBound(nullptr, right_const - upper.GetConstant()), ValueBound(array_length, right_const - lower.GetConstant())); AssignRange(sub->GetBlock(), sub, range); @@ -1087,8 +1084,8 @@ class BCEVisitor : public HGraphVisitor { // than array_length. return; } - ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* range = new (&allocator_) ValueRange( + &allocator_, ValueBound(nullptr, std::numeric_limits<int32_t>::min()), ValueBound(left, 0)); AssignRange(instruction->GetBlock(), instruction, range); @@ -1113,8 +1110,8 @@ class BCEVisitor : public HGraphVisitor { if (constant > 0) { // constant serves as a mask so any number masked with it // gets a [0, constant] value range. - ValueRange* range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* range = new (&allocator_) ValueRange( + &allocator_, ValueBound(nullptr, 0), ValueBound(nullptr, constant)); AssignRange(instruction->GetBlock(), instruction, range); @@ -1139,8 +1136,8 @@ class BCEVisitor : public HGraphVisitor { // array[i % 10]; // index value range [0, 9] // array[i % -10]; // index value range [0, 9] // } - ValueRange* right_range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* right_range = new (&allocator_) ValueRange( + &allocator_, ValueBound(nullptr, 1 - right_const), ValueBound(nullptr, right_const - 1)); @@ -1169,8 +1166,8 @@ class BCEVisitor : public HGraphVisitor { if (right->IsArrayLength()) { ValueBound lower = ValueBound::Min(); // ideally, lower should be '1-array_length'. ValueBound upper = ValueBound(right, -1); // array_length - 1 - ValueRange* right_range = new (GetGraph()->GetAllocator()) ValueRange( - GetGraph()->GetAllocator(), + ValueRange* right_range = new (&allocator_) ValueRange( + &allocator_, lower, upper); ValueRange* left_range = LookupValueRange(left, instruction->GetBlock()); @@ -1195,8 +1192,7 @@ class BCEVisitor : public HGraphVisitor { // which isn't available as an instruction yet. new_array will // be treated the same as new_array.length when it's used in a ValueBound. ValueBound upper = ValueBound(new_array, -right_const); - ValueRange* range = new (GetGraph()->GetAllocator()) - ValueRange(GetGraph()->GetAllocator(), lower, upper); + ValueRange* range = new (&allocator_) ValueRange(&allocator_, lower, upper); ValueRange* existing_range = LookupValueRange(left, new_array->GetBlock()); if (existing_range != nullptr) { range = existing_range->Narrow(range); @@ -1291,10 +1287,10 @@ class BCEVisitor : public HGraphVisitor { HInstruction* base = value.GetInstruction(); int32_t min_c = base == nullptr ? 0 : value.GetConstant(); int32_t max_c = value.GetConstant(); - ArenaVector<HBoundsCheck*> candidates( - GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)); - ArenaVector<HBoundsCheck*> standby( - GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)); + ScopedArenaVector<HBoundsCheck*> candidates( + allocator_.Adapter(kArenaAllocBoundsCheckElimination)); + ScopedArenaVector<HBoundsCheck*> standby( + allocator_.Adapter(kArenaAllocBoundsCheckElimination)); for (const HUseListNode<HInstruction*>& use : array_length->GetUses()) { // Another bounds check in same or dominated block? HInstruction* user = use.GetUser(); @@ -1378,7 +1374,7 @@ class BCEVisitor : public HGraphVisitor { v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) { DCHECK(v1.a_constant == 1 || v1.instruction == nullptr); DCHECK(v2.a_constant == 1 || v2.instruction == nullptr); - ValueRange index_range(GetGraph()->GetAllocator(), + ValueRange index_range(&allocator_, ValueBound(v1.instruction, v1.b_constant), ValueBound(v2.instruction, v2.b_constant)); // If analysis reveals a certain OOB, disable dynamic BCE. Otherwise, @@ -1410,10 +1406,10 @@ class BCEVisitor : public HGraphVisitor { HInstruction* base = value.GetInstruction(); int32_t min_c = base == nullptr ? 0 : value.GetConstant(); int32_t max_c = value.GetConstant(); - ArenaVector<HBoundsCheck*> candidates( - GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)); - ArenaVector<HBoundsCheck*> standby( - GetGraph()->GetAllocator()->Adapter(kArenaAllocBoundsCheckElimination)); + ScopedArenaVector<HBoundsCheck*> candidates( + allocator_.Adapter(kArenaAllocBoundsCheckElimination)); + ScopedArenaVector<HBoundsCheck*> standby( + allocator_.Adapter(kArenaAllocBoundsCheckElimination)); for (const HUseListNode<HInstruction*>& use : array_length->GetUses()) { HInstruction* user = use.GetUser(); if (user->IsBoundsCheck() && loop == user->GetBlock()->GetLoopInformation()) { @@ -1882,21 +1878,24 @@ class BCEVisitor : public HGraphVisitor { instruction->GetBlock()->RemoveInstruction(instruction); } + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator_; + // A set of maps, one per basic block, from instruction to range. - ArenaVector<ArenaSafeMap<int, ValueRange*>> maps_; + ScopedArenaVector<ScopedArenaSafeMap<int, ValueRange*>> maps_; // Map an HArrayLength instruction's id to the first HBoundsCheck instruction // in a block that checks an index against that HArrayLength. - ArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_; + ScopedArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_; // Early-exit loop bookkeeping. - ArenaSafeMap<uint32_t, bool> early_exit_loop_; + ScopedArenaSafeMap<uint32_t, bool> early_exit_loop_; // Taken-test loop bookkeeping. - ArenaSafeMap<uint32_t, HBasicBlock*> taken_test_loop_; + ScopedArenaSafeMap<uint32_t, HBasicBlock*> taken_test_loop_; // Finite loop bookkeeping. - ArenaSet<uint32_t> finite_loop_; + ScopedArenaSet<uint32_t> finite_loop_; // Flag that denotes whether dominator-based dynamic elimination has occurred. bool has_dom_based_dynamic_bce_; diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 76350a6d55..4ed1612220 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -20,12 +20,16 @@ #include "base/arena_bit_vector.h" #include "base/bit_vector-inl.h" #include "base/logging.h" +#include "block_builder.h" #include "data_type-inl.h" #include "dex/verified_method.h" #include "driver/compiler_options.h" +#include "instruction_builder.h" #include "mirror/class_loader.h" #include "mirror/dex_cache.h" #include "nodes.h" +#include "optimizing_compiler_stats.h" +#include "ssa_builder.h" #include "thread.h" #include "utils/dex_cache_arrays_layout-inl.h" @@ -43,27 +47,13 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, dex_file_(&graph->GetDexFile()), code_item_(*dex_compilation_unit->GetCodeItem()), dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(outer_compilation_unit), compiler_driver_(driver), + code_generator_(code_generator), compilation_stats_(compiler_stats), - block_builder_(graph, dex_file_, code_item_), - ssa_builder_(graph, - dex_compilation_unit->GetClassLoader(), - dex_compilation_unit->GetDexCache(), - handles), - instruction_builder_(graph, - &block_builder_, - &ssa_builder_, - dex_file_, - code_item_, - DataType::FromShorty(dex_compilation_unit_->GetShorty()[0]), - dex_compilation_unit, - outer_compilation_unit, - driver, - code_generator, - interpreter_metadata, - compiler_stats, - dex_compilation_unit->GetDexCache(), - handles) {} + interpreter_metadata_(interpreter_metadata), + handles_(handles), + return_type_(DataType::FromShorty(dex_compilation_unit_->GetShorty()[0])) {} bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { if (compiler_driver_ == nullptr) { @@ -108,15 +98,38 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { graph_->SetMaximumNumberOfOutVRegs(code_item_.outs_size_); graph_->SetHasTryCatch(code_item_.tries_size_ != 0); + // Use ScopedArenaAllocator for all local allocations. + ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); + HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_, &local_allocator); + SsaBuilder ssa_builder(graph_, + dex_compilation_unit_->GetClassLoader(), + dex_compilation_unit_->GetDexCache(), + handles_, + &local_allocator); + HInstructionBuilder instruction_builder(graph_, + &block_builder, + &ssa_builder, + dex_file_, + code_item_, + return_type_, + dex_compilation_unit_, + outer_compilation_unit_, + compiler_driver_, + code_generator_, + interpreter_metadata_, + compilation_stats_, + handles_, + &local_allocator); + // 1) Create basic blocks and link them together. Basic blocks are left // unpopulated with the exception of synthetic blocks, e.g. HTryBoundaries. - if (!block_builder_.Build()) { + if (!block_builder.Build()) { return kAnalysisInvalidBytecode; } // 2) Decide whether to skip this method based on its code size and number // of branches. - if (SkipCompilation(block_builder_.GetNumberOfBranches())) { + if (SkipCompilation(block_builder.GetNumberOfBranches())) { return kAnalysisSkipped; } @@ -127,12 +140,12 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { } // 4) Populate basic blocks with instructions. - if (!instruction_builder_.Build()) { + if (!instruction_builder.Build()) { return kAnalysisInvalidBytecode; } // 5) Type the graph and eliminate dead/redundant phis. - return ssa_builder_.BuildSsa(); + return ssa_builder.BuildSsa(); } } // namespace art diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 6c5985a3de..5a860f1e43 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -17,21 +17,17 @@ #ifndef ART_COMPILER_OPTIMIZING_BUILDER_H_ #define ART_COMPILER_OPTIMIZING_BUILDER_H_ -#include "base/arena_containers.h" #include "base/arena_object.h" -#include "block_builder.h" #include "dex_file-inl.h" #include "dex_file.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" -#include "instruction_builder.h" #include "nodes.h" -#include "optimizing_compiler_stats.h" -#include "ssa_builder.h" namespace art { class CodeGenerator; +class OptimizingCompilerStats; class HGraphBuilder : public ValueObject { public: @@ -46,34 +42,21 @@ class HGraphBuilder : public ValueObject { // Only for unit testing. HGraphBuilder(HGraph* graph, + const DexCompilationUnit* dex_compilation_unit, const DexFile::CodeItem& code_item, VariableSizedHandleScope* handles, DataType::Type return_type = DataType::Type::kInt32) : graph_(graph), - dex_file_(nullptr), + dex_file_(dex_compilation_unit->GetDexFile()), code_item_(code_item), - dex_compilation_unit_(nullptr), + dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(nullptr), compiler_driver_(nullptr), + code_generator_(nullptr), compilation_stats_(nullptr), - block_builder_(graph, nullptr, code_item), - ssa_builder_(graph, - handles->NewHandle<mirror::ClassLoader>(nullptr), - handles->NewHandle<mirror::DexCache>(nullptr), - handles), - instruction_builder_(graph, - &block_builder_, - &ssa_builder_, - /* dex_file */ nullptr, - code_item_, - return_type, - /* dex_compilation_unit */ nullptr, - /* outer_compilation_unit */ nullptr, - /* compiler_driver */ nullptr, - /* code_generator */ nullptr, - /* interpreter_metadata */ nullptr, - /* compiler_stats */ nullptr, - handles->NewHandle<mirror::DexCache>(nullptr), - handles) {} + interpreter_metadata_(nullptr), + handles_(handles), + return_type_(return_type) {} GraphAnalysisResult BuildGraph(); @@ -90,13 +73,16 @@ class HGraphBuilder : public ValueObject { // it can be an inlined method. const DexCompilationUnit* const dex_compilation_unit_; - CompilerDriver* const compiler_driver_; + // The compilation unit of the enclosing method being compiled. + const DexCompilationUnit* const outer_compilation_unit_; - OptimizingCompilerStats* compilation_stats_; + CompilerDriver* const compiler_driver_; + CodeGenerator* const code_generator_; - HBasicBlockBuilder block_builder_; - SsaBuilder ssa_builder_; - HInstructionBuilder instruction_builder_; + OptimizingCompilerStats* const compilation_stats_; + const uint8_t* const interpreter_metadata_; + VariableSizedHandleScope* const handles_; + const DataType::Type return_type_; DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); }; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index dd8e3d240f..84f01828b2 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -935,7 +935,7 @@ void CodeGenerator::RecordCatchBlockInfo() { if (current_phi == nullptr || current_phi->AsPhi()->GetRegNumber() != vreg) { stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0); } else { - Location location = current_phi->GetLiveInterval()->ToLocation(); + Location location = current_phi->GetLocations()->Out(); switch (location.GetKind()) { case Location::kStackSlot: { stack_map_stream_.AddDexRegisterEntry( @@ -1202,22 +1202,21 @@ void CodeGenerator::GenerateNullCheck(HNullCheck* instruction) { } } -void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const { +void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check, + HParallelMove* spills) const { LocationSummary* locations = suspend_check->GetLocations(); HBasicBlock* block = suspend_check->GetBlock(); DCHECK(block->GetLoopInformation()->GetSuspendCheck() == suspend_check); DCHECK(block->IsLoopHeader()); - - for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { - HInstruction* current = it.Current(); - LiveInterval* interval = current->GetLiveInterval(); - // We only need to clear bits of loop phis containing objects and allocated in register. - // Loop phis allocated on stack already have the object in the stack. - if (current->GetType() == DataType::Type::kReference - && interval->HasRegister() - && interval->HasSpillSlot()) { - locations->ClearStackBit(interval->GetSpillSlot() / kVRegSize); - } + DCHECK(block->GetFirstInstruction() == spills); + + for (size_t i = 0, num_moves = spills->NumMoves(); i != num_moves; ++i) { + Location dest = spills->MoveOperandsAt(i)->GetDestination(); + // All parallel moves in loop headers are spills. + DCHECK(dest.IsStackSlot() || dest.IsDoubleStackSlot() || dest.IsSIMDStackSlot()) << dest; + // Clear the stack bit marking a reference. Do not bother to check if the spill is + // actually a reference spill, clearing bits that are already zero is harmless. + locations->ClearStackBit(dest.GetStackIndex() / kVRegSize); } } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 2c3cf262b1..2904b71991 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -380,7 +380,8 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { // for the suspend check at the back edge (instead of where the suspend check // is, which is the loop entry). At this point, the spill slots for the phis // have not been written to. - void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const; + void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check, + HParallelMove* spills) const; bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; } bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 9be9117967..e6e69846e4 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2209,7 +2209,6 @@ void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruct codegen_->AddSlowPath(slow_path); if (successor != nullptr) { DCHECK(successor->IsLoopHeader()); - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); } } else { DCHECK_EQ(slow_path->GetSuccessor(), successor); @@ -3560,7 +3559,6 @@ void InstructionCodeGeneratorARM64::HandleGoto(HInstruction* got, HBasicBlock* s HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -5420,6 +5418,13 @@ void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBU } void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index d7137a3b28..251f390ce3 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -2858,7 +2858,6 @@ void InstructionCodeGeneratorARMVIXL::HandleGoto(HInstruction* got, HBasicBlock* HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -6741,6 +6740,13 @@ void LocationsBuilderARMVIXL::VisitParallelMove(HParallelMove* instruction ATTRI } void InstructionCodeGeneratorARMVIXL::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } @@ -6776,7 +6782,6 @@ void InstructionCodeGeneratorARMVIXL::GenerateSuspendCheck(HSuspendCheck* instru codegen_->AddSlowPath(slow_path); if (successor != nullptr) { DCHECK(successor->IsLoopHeader()); - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); } } else { DCHECK_EQ(slow_path->GetSuccessor(), successor); diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 7ea7b9cee2..e58f43e1bb 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -3967,7 +3967,6 @@ void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* su HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -8359,6 +8358,13 @@ void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUT } void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index fad0fe74e5..11120cf07a 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3488,7 +3488,6 @@ void InstructionCodeGeneratorMIPS64::HandleGoto(HInstruction* got, HBasicBlock* HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -6490,6 +6489,13 @@ void LocationsBuilderMIPS64::VisitParallelMove(HParallelMove* instruction ATTRIB } void InstructionCodeGeneratorMIPS64::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } diff --git a/compiler/optimizing/code_generator_vector_arm_vixl.cc b/compiler/optimizing/code_generator_vector_arm_vixl.cc index f84408da49..cc470ddb2e 100644 --- a/compiler/optimizing/code_generator_vector_arm_vixl.cc +++ b/compiler/optimizing/code_generator_vector_arm_vixl.cc @@ -28,6 +28,7 @@ using helpers::Int64ConstantFrom; using helpers::InputDRegisterAt; using helpers::InputRegisterAt; using helpers::OutputDRegister; +using helpers::OutputRegister; using helpers::RegisterFrom; #define __ GetVIXLAssembler()-> @@ -76,11 +77,30 @@ void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScala } void LocationsBuilderARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } void InstructionCodeGeneratorARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = instruction->GetLocations(); + vixl32::DRegister src = DRegisterFrom(locations->InAt(0)); + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: + DCHECK_EQ(2u, instruction->GetVectorLength()); + __ Vmov(OutputRegister(instruction), DRegisterLane(src, 0)); + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } // Helper to set up locations for vector unary operations. @@ -112,7 +132,28 @@ void LocationsBuilderARMVIXL::VisitVecReduce(HVecReduce* instruction) { } void InstructionCodeGeneratorARMVIXL::VisitVecReduce(HVecReduce* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = instruction->GetLocations(); + vixl32::DRegister src = DRegisterFrom(locations->InAt(0)); + vixl32::DRegister dst = DRegisterFrom(locations->Out()); + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: + DCHECK_EQ(2u, instruction->GetVectorLength()); + switch (instruction->GetKind()) { + case HVecReduce::kSum: + __ Vpadd(DataTypeValue::I32, dst, src, src); + break; + case HVecReduce::kMin: + __ Vpmin(DataTypeValue::S32, dst, src, src); + break; + case HVecReduce::kMax: + __ Vpmax(DataTypeValue::S32, dst, src, src); + break; + } + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } void LocationsBuilderARMVIXL::VisitVecCnv(HVecCnv* instruction) { @@ -635,11 +676,49 @@ void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) { } void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); + + DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented + + HInstruction* input = instruction->InputAt(0); + bool is_zero = IsZeroBitPattern(input); + + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: + locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant()) + : Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = instruction->GetLocations(); + vixl32::DRegister dst = DRegisterFrom(locations->Out()); + + DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented + + // Zero out all other elements first. + __ Vmov(I32, dst, 0); + + // Shorthand for any type of zero. + if (IsZeroBitPattern(instruction->InputAt(0))) { + return; + } + + // Set required elements. + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: + DCHECK_EQ(2u, instruction->GetVectorLength()); + __ Vmov(Untyped32, DRegisterLane(dst, 0), InputRegisterAt(instruction, 0)); + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } // Helper to set up locations for vector accumulations. @@ -676,7 +755,39 @@ void LocationsBuilderARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instructi } void InstructionCodeGeneratorARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) { - LOG(FATAL) << "No SIMD for " << instruction->GetId(); + LocationSummary* locations = instruction->GetLocations(); + vixl32::DRegister acc = DRegisterFrom(locations->InAt(0)); + vixl32::DRegister left = DRegisterFrom(locations->InAt(1)); + vixl32::DRegister right = DRegisterFrom(locations->InAt(2)); + + DCHECK(locations->InAt(0).Equals(locations->Out())); + + // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S). + HVecOperation* a = instruction->InputAt(1)->AsVecOperation(); + HVecOperation* b = instruction->InputAt(2)->AsVecOperation(); + DCHECK_EQ(a->GetPackedType(), b->GetPackedType()); + switch (a->GetPackedType()) { + case DataType::Type::kInt32: + DCHECK_EQ(2u, a->GetVectorLength()); + switch (instruction->GetPackedType()) { + case DataType::Type::kInt32: { + DCHECK_EQ(2u, instruction->GetVectorLength()); + UseScratchRegisterScope temps(GetVIXLAssembler()); + vixl32::DRegister tmp = temps.AcquireD(); + __ Vsub(DataTypeValue::I32, tmp, left, right); + __ Vabs(DataTypeValue::S32, tmp, tmp); + __ Vadd(DataTypeValue::I32, acc, acc, tmp); + break; + } + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } + break; + default: + LOG(FATAL) << "Unsupported SIMD type"; + UNREACHABLE(); + } } // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index d8a47fa1ea..39a07b82d1 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -5680,6 +5680,13 @@ void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE } void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } @@ -5717,7 +5724,6 @@ void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instructio codegen_->AddSlowPath(slow_path); if (successor != nullptr) { DCHECK(successor->IsLoopHeader()); - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); } } else { DCHECK_EQ(slow_path->GetSuccessor(), successor); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index b6aa110f2d..c8032c25df 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5125,6 +5125,13 @@ void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIB } void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) { + if (instruction->GetNext()->IsSuspendCheck() && + instruction->GetBlock()->GetLoopInformation() != nullptr) { + HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck(); + // The back edge will generate the suspend check. + codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction); + } + codegen_->GetMoveResolver()->EmitNativeCode(instruction); } @@ -5162,7 +5169,6 @@ void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruc codegen_->AddSlowPath(slow_path); if (successor != nullptr) { DCHECK(successor->IsLoopHeader()); - codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); } } else { DCHECK_EQ(slow_path->GetSuccessor(), successor); diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index 5117e07a12..3cc7b0e78d 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -18,13 +18,18 @@ #include "base/array_ref.h" #include "base/bit_vector-inl.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "base/stl_util.h" #include "ssa_phi_elimination.h" namespace art { static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) { - ArenaVector<HBasicBlock*> worklist(graph->GetAllocator()->Adapter(kArenaAllocDCE)); + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator(graph->GetArenaStack()); + + ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocDCE)); constexpr size_t kDefaultWorlistSize = 8; worklist.reserve(kDefaultWorlistSize); visited->SetBit(graph->GetEntryBlock()->GetBlockId()); @@ -305,9 +310,12 @@ void HDeadCodeElimination::ConnectSuccessiveBlocks() { } bool HDeadCodeElimination::RemoveDeadBlocks() { + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator(graph_->GetArenaStack()); + // Classify blocks as reachable/unreachable. - ArenaAllocator* allocator = graph_->GetAllocator(); - ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE); + ArenaBitVector live_blocks(&allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE); + live_blocks.ClearAllBits(); MarkReachableBlocks(graph_, &live_blocks); bool removed_one_or_more_blocks = false; diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 1c7d1a0b69..b1ac027a68 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -22,8 +22,9 @@ #include "android-base/stringprintf.h" -#include "base/arena_containers.h" #include "base/bit_vector-inl.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" namespace art { @@ -47,10 +48,13 @@ static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) { void GraphChecker::VisitBasicBlock(HBasicBlock* block) { current_block_ = block; + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator(GetGraph()->GetArenaStack()); + // Check consistency with respect to predecessors of `block`. // Note: Counting duplicates with a sorted vector uses up to 6x less memory // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse. - ArenaVector<HBasicBlock*>& sorted_predecessors = blocks_storage_; + ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker)); sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end()); std::sort(sorted_predecessors.begin(), sorted_predecessors.end()); for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) { @@ -73,7 +77,7 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { // Check consistency with respect to successors of `block`. // Note: Counting duplicates with a sorted vector uses up to 6x less memory // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse. - ArenaVector<HBasicBlock*>& sorted_successors = blocks_storage_; + ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker)); sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end()); std::sort(sorted_successors.begin(), sorted_successors.end()); for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) { @@ -829,10 +833,14 @@ void GraphChecker::VisitPhi(HPhi* phi) { phi->GetRegNumber(), type_str.str().c_str())); } else { + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator(GetGraph()->GetArenaStack()); // If we get here, make sure we allocate all the necessary storage at once // because the BitVector reallocation strategy has very bad worst-case behavior. - ArenaBitVector& visited = visited_storage_; - visited.SetBit(GetGraph()->GetCurrentInstructionId()); + ArenaBitVector visited(&allocator, + GetGraph()->GetCurrentInstructionId(), + /* expandable */ false, + kArenaAllocGraphChecker); visited.ClearAllBits(); if (!IsConstantEquivalent(phi, other_phi, &visited)) { AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they " diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h index 6af7b429f7..0f0b49d240 100644 --- a/compiler/optimizing/graph_checker.h +++ b/compiler/optimizing/graph_checker.h @@ -17,10 +17,13 @@ #ifndef ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_ #define ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_ -#include "nodes.h" - #include <ostream> +#include "base/arena_bit_vector.h" +#include "base/bit_vector-inl.h" +#include "base/scoped_arena_allocator.h" +#include "nodes.h" + namespace art { // A control-flow graph visitor performing various checks. @@ -30,12 +33,10 @@ class GraphChecker : public HGraphDelegateVisitor { : HGraphDelegateVisitor(graph), errors_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)), dump_prefix_(dump_prefix), - seen_ids_(graph->GetAllocator(), - graph->GetCurrentInstructionId(), - false, - kArenaAllocGraphChecker), - blocks_storage_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)), - visited_storage_(graph->GetAllocator(), 0u, true, kArenaAllocGraphChecker) {} + allocator_(graph->GetArenaStack()), + seen_ids_(&allocator_, graph->GetCurrentInstructionId(), false, kArenaAllocGraphChecker) { + seen_ids_.ClearAllBits(); + } // Check the whole graph (in reverse post-order). void Run() { @@ -104,12 +105,9 @@ class GraphChecker : public HGraphDelegateVisitor { private: // String displayed before dumped errors. const char* const dump_prefix_; + ScopedArenaAllocator allocator_; ArenaBitVector seen_ids_; - // To reduce the total arena memory allocation, we reuse the same storage. - ArenaVector<HBasicBlock*> blocks_storage_; - ArenaBitVector visited_storage_; - DISALLOW_COPY_AND_ASSIGN(GraphChecker); }; diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index eccdccf186..3851877ae5 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -21,6 +21,7 @@ #include <cctype> #include <sstream> +#include "art_method.h" #include "bounds_check_elimination.h" #include "builder.h" #include "code_generator.h" @@ -33,6 +34,7 @@ #include "optimization.h" #include "reference_type_propagation.h" #include "register_allocator_linear_scan.h" +#include "scoped_thread_state_change-inl.h" #include "ssa_liveness_analysis.h" #include "utils/assembler.h" #include "utils/intrusive_forward_list.h" diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc index c09e5df1c0..813772e9af 100644 --- a/compiler/optimizing/gvn.cc +++ b/compiler/optimizing/gvn.cc @@ -17,7 +17,8 @@ #include "gvn.h" #include "base/arena_bit_vector.h" -#include "base/arena_containers.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "base/bit_vector-inl.h" #include "side_effects_analysis.h" #include "utils.h" @@ -36,7 +37,7 @@ namespace art { class ValueSet : public ArenaObject<kArenaAllocGvn> { public: // Constructs an empty ValueSet which owns all its buckets. - explicit ValueSet(ArenaAllocator* allocator) + explicit ValueSet(ScopedArenaAllocator* allocator) : allocator_(allocator), num_buckets_(kMinimumNumberOfBuckets), buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)), @@ -44,12 +45,13 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { num_entries_(0u) { // ArenaAllocator returns zeroed memory, so no need to set buckets to null. DCHECK(IsPowerOfTwo(num_buckets_)); + std::fill_n(buckets_, num_buckets_, nullptr); buckets_owned_.SetInitialBits(num_buckets_); } // Copy constructor. Depending on the load factor, it will either make a deep // copy (all buckets owned) or a shallow one (buckets pointing to the parent). - ValueSet(ArenaAllocator* allocator, const ValueSet& other) + ValueSet(ScopedArenaAllocator* allocator, const ValueSet& other) : allocator_(allocator), num_buckets_(other.IdealBucketCount()), buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)), @@ -58,7 +60,7 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { // ArenaAllocator returns zeroed memory, so entries of buckets_ and // buckets_owned_ are initialized to null and false, respectively. DCHECK(IsPowerOfTwo(num_buckets_)); - PopulateFromInternal(other, /* is_dirty */ false); + PopulateFromInternal(other); } // Erases all values in this set and populates it with values from `other`. @@ -66,7 +68,7 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { if (this == &other) { return; } - PopulateFromInternal(other, /* is_dirty */ true); + PopulateFromInternal(other); } // Returns true if `this` has enough buckets so that if `other` is copied into @@ -159,33 +161,19 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { private: // Copies all entries from `other` to `this`. - // If `is_dirty` is set to true, existing data will be wiped first. It is - // assumed that `buckets_` and `buckets_owned_` are zero-allocated otherwise. - void PopulateFromInternal(const ValueSet& other, bool is_dirty) { + void PopulateFromInternal(const ValueSet& other) { DCHECK_NE(this, &other); DCHECK_GE(num_buckets_, other.IdealBucketCount()); if (num_buckets_ == other.num_buckets_) { // Hash table remains the same size. We copy the bucket pointers and leave // all buckets_owned_ bits false. - if (is_dirty) { - buckets_owned_.ClearAllBits(); - } else { - DCHECK_EQ(buckets_owned_.NumSetBits(), 0u); - } + buckets_owned_.ClearAllBits(); memcpy(buckets_, other.buckets_, num_buckets_ * sizeof(Node*)); } else { // Hash table size changes. We copy and rehash all entries, and set all // buckets_owned_ bits to true. - if (is_dirty) { - memset(buckets_, 0, num_buckets_ * sizeof(Node*)); - } else { - if (kIsDebugBuild) { - for (size_t i = 0; i < num_buckets_; ++i) { - DCHECK(buckets_[i] == nullptr) << i; - } - } - } + std::fill_n(buckets_, num_buckets_, nullptr); for (size_t i = 0; i < other.num_buckets_; ++i) { for (Node* node = other.buckets_[i]; node != nullptr; node = node->GetNext()) { size_t new_index = BucketIndex(node->GetHashCode()); @@ -208,7 +196,7 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { Node* GetNext() const { return next_; } void SetNext(Node* node) { next_ = node; } - Node* Dup(ArenaAllocator* allocator, Node* new_next = nullptr) { + Node* Dup(ScopedArenaAllocator* allocator, Node* new_next = nullptr) { return new (allocator) Node(instruction_, hash_code_, new_next); } @@ -326,7 +314,7 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { return hash_code & (num_buckets_ - 1); } - ArenaAllocator* const allocator_; + ScopedArenaAllocator* const allocator_; // The internal bucket implementation of the set. size_t const num_buckets_; @@ -350,15 +338,16 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> { */ class GlobalValueNumberer : public ValueObject { public: - GlobalValueNumberer(ArenaAllocator* allocator, - HGraph* graph, + GlobalValueNumberer(HGraph* graph, const SideEffectsAnalysis& side_effects) : graph_(graph), - allocator_(allocator), + allocator_(graph->GetArenaStack()), side_effects_(side_effects), - sets_(graph->GetBlocks().size(), nullptr, allocator->Adapter(kArenaAllocGvn)), + sets_(graph->GetBlocks().size(), nullptr, allocator_.Adapter(kArenaAllocGvn)), visited_blocks_( - allocator, graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGvn) {} + &allocator_, graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGvn) { + visited_blocks_.ClearAllBits(); + } void Run(); @@ -368,7 +357,7 @@ class GlobalValueNumberer : public ValueObject { void VisitBasicBlock(HBasicBlock* block); HGraph* graph_; - ArenaAllocator* const allocator_; + ScopedArenaAllocator allocator_; const SideEffectsAnalysis& side_effects_; ValueSet* FindSetFor(HBasicBlock* block) const { @@ -396,7 +385,7 @@ class GlobalValueNumberer : public ValueObject { // ValueSet for blocks. Initially null, but for an individual block they // are allocated and populated by the dominator, and updated by all blocks // in the path from the dominator to the block. - ArenaVector<ValueSet*> sets_; + ScopedArenaVector<ValueSet*> sets_; // BitVector which serves as a fast-access map from block id to // visited/unvisited Boolean. @@ -407,7 +396,7 @@ class GlobalValueNumberer : public ValueObject { void GlobalValueNumberer::Run() { DCHECK(side_effects_.HasRun()); - sets_[graph_->GetEntryBlock()->GetBlockId()] = new (allocator_) ValueSet(allocator_); + sets_[graph_->GetEntryBlock()->GetBlockId()] = new (&allocator_) ValueSet(&allocator_); // Use the reverse post order to ensure the non back-edge predecessors of a block are // visited before the block itself. @@ -424,7 +413,7 @@ void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) { // The entry block should only accumulate constant instructions, and // the builder puts constants only in the entry block. // Therefore, there is no need to propagate the value set to the next block. - set = new (allocator_) ValueSet(allocator_); + set = new (&allocator_) ValueSet(&allocator_); } else { HBasicBlock* dominator = block->GetDominator(); ValueSet* dominator_set = FindSetFor(dominator); @@ -443,7 +432,7 @@ void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) { if (recyclable == nullptr) { // No block with a suitable ValueSet found. Allocate a new one and // copy `dominator_set` into it. - set = new (allocator_) ValueSet(allocator_, *dominator_set); + set = new (&allocator_) ValueSet(&allocator_, *dominator_set); } else { // Block with a recyclable ValueSet found. Clone `dominator_set` into it. set = FindSetFor(recyclable); @@ -566,7 +555,7 @@ HBasicBlock* GlobalValueNumberer::FindVisitedBlockWithRecyclableSet( } void GVNOptimization::Run() { - GlobalValueNumberer gvn(graph_->GetAllocator(), graph_, side_effects_); + GlobalValueNumberer gvn(graph_, side_effects_); gvn.Run(); } diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index b06d91c823..902985e4ee 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -17,15 +17,23 @@ #include "instruction_builder.h" #include "art_method-inl.h" +#include "base/arena_bit_vector.h" +#include "base/bit_vector-inl.h" +#include "block_builder.h" #include "bytecode_utils.h" #include "class_linker.h" #include "data_type-inl.h" #include "dex_instruction-inl.h" +#include "driver/compiler_driver-inl.h" +#include "driver/dex_compilation_unit.h" #include "driver/compiler_options.h" #include "imtable-inl.h" +#include "mirror/dex_cache.h" +#include "optimizing_compiler_stats.h" #include "quicken_info.h" #include "scoped_thread_state_change-inl.h" #include "sharpening.h" +#include "ssa_builder.h" #include "well_known_classes.h" namespace art { @@ -34,8 +42,8 @@ HBasicBlock* HInstructionBuilder::FindBlockStartingAt(uint32_t dex_pc) const { return block_builder_->GetBlockAt(dex_pc); } -inline ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsFor(HBasicBlock* block) { - ArenaVector<HInstruction*>* locals = &locals_for_[block->GetBlockId()]; +inline ScopedArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsFor(HBasicBlock* block) { + ScopedArenaVector<HInstruction*>* locals = &locals_for_[block->GetBlockId()]; const size_t vregs = graph_->GetNumberOfVRegs(); if (locals->size() == vregs) { return locals; @@ -43,9 +51,9 @@ inline ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsFor(HBasicBlock return GetLocalsForWithAllocation(block, locals, vregs); } -ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsForWithAllocation( +ScopedArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsForWithAllocation( HBasicBlock* block, - ArenaVector<HInstruction*>* locals, + ScopedArenaVector<HInstruction*>* locals, const size_t vregs) { DCHECK_NE(locals->size(), vregs); locals->resize(vregs, nullptr); @@ -73,7 +81,7 @@ ArenaVector<HInstruction*>* HInstructionBuilder::GetLocalsForWithAllocation( } inline HInstruction* HInstructionBuilder::ValueOfLocalAt(HBasicBlock* block, size_t local) { - ArenaVector<HInstruction*>* locals = GetLocalsFor(block); + ScopedArenaVector<HInstruction*>* locals = GetLocalsFor(block); return (*locals)[local]; } @@ -168,7 +176,7 @@ void HInstructionBuilder::InitializeBlockLocals() { void HInstructionBuilder::PropagateLocalsToCatchBlocks() { const HTryBoundary& try_entry = current_block_->GetTryCatchInformation()->GetTryEntry(); for (HBasicBlock* catch_block : try_entry.GetExceptionHandlers()) { - ArenaVector<HInstruction*>* handler_locals = GetLocalsFor(catch_block); + ScopedArenaVector<HInstruction*>* handler_locals = GetLocalsFor(catch_block); DCHECK_EQ(handler_locals->size(), current_locals_->size()); for (size_t vreg = 0, e = current_locals_->size(); vreg < e; ++vreg) { HInstruction* handler_value = (*handler_locals)[vreg]; @@ -216,7 +224,7 @@ void HInstructionBuilder::InitializeInstruction(HInstruction* instruction) { graph_->GetArtMethod(), instruction->GetDexPc(), instruction); - environment->CopyFrom(*current_locals_); + environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals_)); instruction->SetRawEnvironment(environment); } } @@ -264,8 +272,9 @@ static bool IsBlockPopulated(HBasicBlock* block) { } bool HInstructionBuilder::Build() { - locals_for_.resize(graph_->GetBlocks().size(), - ArenaVector<HInstruction*>(allocator_->Adapter(kArenaAllocGraphBuilder))); + locals_for_.resize( + graph_->GetBlocks().size(), + ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder))); // Find locations where we want to generate extra stackmaps for native debugging. // This allows us to generate the info only at interesting points (for example, @@ -274,10 +283,7 @@ bool HInstructionBuilder::Build() { compiler_driver_->GetCompilerOptions().GetNativeDebuggable(); ArenaBitVector* native_debug_info_locations = nullptr; if (native_debuggable) { - const uint32_t num_instructions = code_item_.insns_size_in_code_units_; - native_debug_info_locations = - new (allocator_) ArenaBitVector (allocator_, num_instructions, false); - FindNativeDebugInfoLocations(native_debug_info_locations); + native_debug_info_locations = FindNativeDebugInfoLocations(); } for (HBasicBlock* block : graph_->GetReversePostOrder()) { @@ -358,7 +364,7 @@ bool HInstructionBuilder::Build() { return true; } -void HInstructionBuilder::FindNativeDebugInfoLocations(ArenaBitVector* locations) { +ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() { // The callback gets called when the line number changes. // In other words, it marks the start of new java statement. struct Callback { @@ -367,6 +373,12 @@ void HInstructionBuilder::FindNativeDebugInfoLocations(ArenaBitVector* locations return false; } }; + const uint32_t num_instructions = code_item_.insns_size_in_code_units_; + ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_, + num_instructions, + /* expandable */ false, + kArenaAllocGraphBuilder); + locations->ClearAllBits(); dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations); // Instruction-specific tweaks. IterationRange<DexInstructionIterator> instructions = code_item_.Instructions(); @@ -387,6 +399,7 @@ void HInstructionBuilder::FindNativeDebugInfoLocations(ArenaBitVector* locations break; } } + return locations; } HInstruction* HInstructionBuilder::LoadLocal(uint32_t reg_number, DataType::Type type) const { @@ -439,8 +452,8 @@ void HInstructionBuilder::UpdateLocal(uint32_t reg_number, HInstruction* stored_ void HInstructionBuilder::InitializeParameters() { DCHECK(current_block_->IsEntryBlock()); - // dex_compilation_unit_ is null only when unit testing. - if (dex_compilation_unit_ == nullptr) { + // outer_compilation_unit_ is null only when unit testing. + if (outer_compilation_unit_ == nullptr) { return; } diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 79d6ddc87d..058b711687 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -17,23 +17,32 @@ #ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_ #define ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_ -#include "base/arena_containers.h" -#include "base/arena_object.h" -#include "block_builder.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" +#include "data_type.h" +#include "dex_file.h" #include "dex_file_types.h" -#include "driver/compiler_driver-inl.h" -#include "driver/compiler_driver.h" -#include "driver/dex_compilation_unit.h" -#include "mirror/dex_cache.h" +#include "handle.h" #include "nodes.h" -#include "optimizing_compiler_stats.h" #include "quicken_info.h" -#include "ssa_builder.h" namespace art { +class ArenaBitVector; +class ArtField; +class ArtMethod; class CodeGenerator; +class CompilerDriver; +class DexCompilationUnit; +class HBasicBlockBuilder; class Instruction; +class OptimizingCompilerStats; +class SsaBuilder; +class VariableSizedHandleScope; + +namespace mirror { +class Class; +} // namespace mirror class HInstructionBuilder : public ValueObject { public: @@ -45,12 +54,12 @@ class HInstructionBuilder : public ValueObject { DataType::Type return_type, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, - CompilerDriver* driver, + CompilerDriver* compiler_driver, CodeGenerator* code_generator, const uint8_t* interpreter_metadata, OptimizingCompilerStats* compiler_stats, - Handle<mirror::DexCache> dex_cache, - VariableSizedHandleScope* handles) + VariableSizedHandleScope* handles, + ScopedArenaAllocator* local_allocator) : allocator_(graph->GetAllocator()), graph_(graph), handles_(handles), @@ -59,19 +68,19 @@ class HInstructionBuilder : public ValueObject { return_type_(return_type), block_builder_(block_builder), ssa_builder_(ssa_builder), - locals_for_(allocator_->Adapter(kArenaAllocGraphBuilder)), - current_block_(nullptr), - current_locals_(nullptr), - latest_result_(nullptr), - current_this_parameter_(nullptr), - compiler_driver_(driver), + compiler_driver_(compiler_driver), code_generator_(code_generator), dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), quicken_info_(interpreter_metadata), compilation_stats_(compiler_stats), - dex_cache_(dex_cache), - loop_headers_(allocator_->Adapter(kArenaAllocGraphBuilder)) { + local_allocator_(local_allocator), + locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)), + current_block_(nullptr), + current_locals_(nullptr), + latest_result_(nullptr), + current_this_parameter_(nullptr), + loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { loop_headers_.reserve(kDefaultNumberOfLoops); } @@ -83,18 +92,18 @@ class HInstructionBuilder : public ValueObject { void SetLoopHeaderPhiInputs(); bool ProcessDexInstruction(const Instruction& instruction, uint32_t dex_pc, size_t quicken_index); - void FindNativeDebugInfoLocations(ArenaBitVector* locations); + ArenaBitVector* FindNativeDebugInfoLocations(); bool CanDecodeQuickenedInfo() const; uint16_t LookupQuickenedInfo(uint32_t quicken_index); HBasicBlock* FindBlockStartingAt(uint32_t dex_pc) const; - ArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block); + ScopedArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block); // Out of line version of GetLocalsFor(), which has a fast path that is // beneficial to get inlined by callers. - ArenaVector<HInstruction*>* GetLocalsForWithAllocation( - HBasicBlock* block, ArenaVector<HInstruction*>* locals, const size_t vregs); + ScopedArenaVector<HInstruction*>* GetLocalsForWithAllocation( + HBasicBlock* block, ScopedArenaVector<HInstruction*>* locals, const size_t vregs); HInstruction* ValueOfLocalAt(HBasicBlock* block, size_t local); HInstruction* LoadLocal(uint32_t register_index, DataType::Type type) const; HInstruction* LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc); @@ -314,7 +323,7 @@ class HInstructionBuilder : public ValueObject { ArenaAllocator* const allocator_; HGraph* const graph_; - VariableSizedHandleScope* handles_; + VariableSizedHandleScope* const handles_; // The dex file where the method being compiled is, and the bytecode data. const DexFile* const dex_file_; @@ -323,18 +332,8 @@ class HInstructionBuilder : public ValueObject { // The return type of the method being compiled. const DataType::Type return_type_; - HBasicBlockBuilder* block_builder_; - SsaBuilder* ssa_builder_; - - ArenaVector<ArenaVector<HInstruction*>> locals_for_; - HBasicBlock* current_block_; - ArenaVector<HInstruction*>* current_locals_; - HInstruction* latest_result_; - // Current "this" parameter. - // Valid only after InitializeParameters() finishes. - // * Null for static methods. - // * Non-null for instance methods. - HParameterValue* current_this_parameter_; + HBasicBlockBuilder* const block_builder_; + SsaBuilder* const ssa_builder_; CompilerDriver* const compiler_driver_; @@ -352,10 +351,20 @@ class HInstructionBuilder : public ValueObject { // Original values kept after instruction quickening. QuickenInfoTable quicken_info_; - OptimizingCompilerStats* compilation_stats_; - Handle<mirror::DexCache> dex_cache_; + OptimizingCompilerStats* const compilation_stats_; + + ScopedArenaAllocator* const local_allocator_; + ScopedArenaVector<ScopedArenaVector<HInstruction*>> locals_for_; + HBasicBlock* current_block_; + ScopedArenaVector<HInstruction*>* current_locals_; + HInstruction* latest_result_; + // Current "this" parameter. + // Valid only after InitializeParameters() finishes. + // * Null for static methods. + // * Non-null for instance methods. + HParameterValue* current_this_parameter_; - ArenaVector<HBasicBlock*> loop_headers_; + ScopedArenaVector<HBasicBlock*> loop_headers_; static constexpr int kDefaultNumberOfLoops = 2; diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index f39acab3d7..afe748458e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -1284,9 +1284,9 @@ void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) { DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above. // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24". HUShr* ushr = new (GetGraph()->GetAllocator()) HUShr(instruction->GetType(), - input_other->InputAt(0), - input_other->InputAt(1), - input_other->GetDexPc()); + input_other->InputAt(0), + input_other->InputAt(1), + input_other->GetDexPc()); instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr); input_other->GetBlock()->RemoveInstruction(input_other); RecordSimplification(); diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h index 3533c88c67..033a644f34 100644 --- a/compiler/optimizing/intrinsics_arm64.h +++ b/compiler/optimizing/intrinsics_arm64.h @@ -57,8 +57,8 @@ class IntrinsicLocationsBuilderARM64 FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - ArenaAllocator* allocator_; - CodeGeneratorARM64* codegen_; + ArenaAllocator* const allocator_; + CodeGeneratorARM64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderARM64); }; @@ -81,7 +81,7 @@ class IntrinsicCodeGeneratorARM64 FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); - CodeGeneratorARM64* codegen_; + CodeGeneratorARM64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorARM64); }; diff --git a/compiler/optimizing/intrinsics_arm_vixl.h b/compiler/optimizing/intrinsics_arm_vixl.h index 4f18ca3fc1..9c02d0a4ad 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.h +++ b/compiler/optimizing/intrinsics_arm_vixl.h @@ -46,9 +46,9 @@ class IntrinsicLocationsBuilderARMVIXL FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - ArenaAllocator* allocator_; - CodeGenerator* codegen_; - ArmVIXLAssembler* assembler_; + ArenaAllocator* const allocator_; + CodeGenerator* const codegen_; + ArmVIXLAssembler* const assembler_; const ArmInstructionSetFeatures& features_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderARMVIXL); @@ -71,7 +71,7 @@ class IntrinsicCodeGeneratorARMVIXL FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); ArmVIXLAssembler* GetAssembler(); - CodeGeneratorARMVIXL* codegen_; + CodeGeneratorARMVIXL* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorARMVIXL); }; diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h index afd9548a60..13397f11d4 100644 --- a/compiler/optimizing/intrinsics_mips.h +++ b/compiler/optimizing/intrinsics_mips.h @@ -49,8 +49,8 @@ class IntrinsicLocationsBuilderMIPS FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - CodeGeneratorMIPS* codegen_; - ArenaAllocator* allocator_; + CodeGeneratorMIPS* const codegen_; + ArenaAllocator* const allocator_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderMIPS); }; @@ -77,7 +77,7 @@ class IntrinsicCodeGeneratorMIPS FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); - CodeGeneratorMIPS* codegen_; + CodeGeneratorMIPS* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorMIPS); }; diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h index 6085c7b29c..6f40d90ddb 100644 --- a/compiler/optimizing/intrinsics_mips64.h +++ b/compiler/optimizing/intrinsics_mips64.h @@ -49,8 +49,8 @@ class IntrinsicLocationsBuilderMIPS64 FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - CodeGeneratorMIPS64* codegen_; - ArenaAllocator* allocator_; + CodeGeneratorMIPS64* const codegen_; + ArenaAllocator* const allocator_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderMIPS64); }; @@ -73,7 +73,7 @@ class IntrinsicCodeGeneratorMIPS64 FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); - CodeGeneratorMIPS64* codegen_; + CodeGeneratorMIPS64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorMIPS64); }; diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h index ba3ca0a410..e3555e78fc 100644 --- a/compiler/optimizing/intrinsics_x86.h +++ b/compiler/optimizing/intrinsics_x86.h @@ -49,8 +49,8 @@ class IntrinsicLocationsBuilderX86 FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - ArenaAllocator* allocator_; - CodeGeneratorX86* codegen_; + ArenaAllocator* const allocator_; + CodeGeneratorX86* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderX86); }; @@ -73,7 +73,7 @@ class IntrinsicCodeGeneratorX86 FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); - CodeGeneratorX86* codegen_; + CodeGeneratorX86* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorX86); }; diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h index b0fbe91a75..5cb601edfe 100644 --- a/compiler/optimizing/intrinsics_x86_64.h +++ b/compiler/optimizing/intrinsics_x86_64.h @@ -49,8 +49,8 @@ class IntrinsicLocationsBuilderX86_64 FINAL : public IntrinsicVisitor { bool TryDispatch(HInvoke* invoke); private: - ArenaAllocator* allocator_; - CodeGeneratorX86_64* codegen_; + ArenaAllocator* const allocator_; + CodeGeneratorX86_64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderX86_64); }; @@ -73,7 +73,7 @@ class IntrinsicCodeGeneratorX86_64 FINAL : public IntrinsicVisitor { ArenaAllocator* GetAllocator(); - CodeGeneratorX86_64* codegen_; + CodeGeneratorX86_64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorX86_64); }; diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h index 6a25da3cfd..5940ee755f 100644 --- a/compiler/optimizing/load_store_analysis.h +++ b/compiler/optimizing/load_store_analysis.h @@ -25,7 +25,7 @@ namespace art { // A ReferenceInfo contains additional info about a reference such as // whether it's a singleton, returned, etc. -class ReferenceInfo : public ArenaObject<kArenaAllocMisc> { +class ReferenceInfo : public ArenaObject<kArenaAllocLSA> { public: ReferenceInfo(HInstruction* reference, size_t pos) : reference_(reference), @@ -99,7 +99,7 @@ class ReferenceInfo : public ArenaObject<kArenaAllocMisc> { // A heap location is a reference-offset/index pair that a value can be loaded from // or stored to. -class HeapLocation : public ArenaObject<kArenaAllocMisc> { +class HeapLocation : public ArenaObject<kArenaAllocLSA> { public: static constexpr size_t kInvalidFieldOffset = -1; @@ -172,12 +172,12 @@ class HeapLocationCollector : public HGraphVisitor { explicit HeapLocationCollector(HGraph* graph) : HGraphVisitor(graph), - ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), - heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), + ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSA)), + heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSA)), aliasing_matrix_(graph->GetAllocator(), kInitialAliasingMatrixBitVectorSize, true, - kArenaAllocLSE), + kArenaAllocLSA), has_heap_stores_(false), has_volatile_(false), has_monitor_operations_(false) {} diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 39bfc86432..af5585ec92 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -16,6 +16,9 @@ #include "load_store_elimination.h" +#include "base/array_ref.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "escape.h" #include "load_store_analysis.h" #include "side_effects_analysis.h" @@ -45,17 +48,18 @@ class LSEVisitor : public HGraphVisitor { : HGraphVisitor(graph, stats), heap_location_collector_(heap_locations_collector), side_effects_(side_effects), + allocator_(graph->GetArenaStack()), heap_values_for_(graph->GetBlocks().size(), - ArenaVector<HInstruction*>(heap_locations_collector. - GetNumberOfHeapLocations(), - kUnknownHeapValue, - graph->GetAllocator()->Adapter(kArenaAllocLSE)), - graph->GetAllocator()->Adapter(kArenaAllocLSE)), - removed_loads_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), - substitute_instructions_for_loads_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), - possibly_removed_stores_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), - singleton_new_instances_(graph->GetAllocator()->Adapter(kArenaAllocLSE)), - singleton_new_arrays_(graph->GetAllocator()->Adapter(kArenaAllocLSE)) { + ScopedArenaVector<HInstruction*>(heap_locations_collector. + GetNumberOfHeapLocations(), + kUnknownHeapValue, + allocator_.Adapter(kArenaAllocLSE)), + allocator_.Adapter(kArenaAllocLSE)), + removed_loads_(allocator_.Adapter(kArenaAllocLSE)), + substitute_instructions_for_loads_(allocator_.Adapter(kArenaAllocLSE)), + possibly_removed_stores_(allocator_.Adapter(kArenaAllocLSE)), + singleton_new_instances_(allocator_.Adapter(kArenaAllocLSE)), + singleton_new_arrays_(allocator_.Adapter(kArenaAllocLSE)) { } void VisitBasicBlock(HBasicBlock* block) OVERRIDE { @@ -146,7 +150,7 @@ class LSEVisitor : public HGraphVisitor { void HandleLoopSideEffects(HBasicBlock* block) { DCHECK(block->IsLoopHeader()); int block_id = block->GetBlockId(); - ArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id]; + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id]; // Don't eliminate loads in irreducible loops. This is safe for singletons, because // they are always used by the non-eliminated loop-phi. @@ -160,7 +164,7 @@ class LSEVisitor : public HGraphVisitor { } HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader(); - ArenaVector<HInstruction*>& pre_header_heap_values = + ScopedArenaVector<HInstruction*>& pre_header_heap_values = heap_values_for_[pre_header->GetBlockId()]; // Inherit the values from pre-header. @@ -191,12 +195,12 @@ class LSEVisitor : public HGraphVisitor { } void MergePredecessorValues(HBasicBlock* block) { - const ArenaVector<HBasicBlock*>& predecessors = block->GetPredecessors(); + ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors()); if (predecessors.size() == 0) { return; } - ArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()]; + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()]; for (size_t i = 0; i < heap_values.size(); i++) { HInstruction* merged_value = nullptr; // Whether merged_value is a result that's merged from all predecessors. @@ -234,7 +238,8 @@ class LSEVisitor : public HGraphVisitor { // or the heap value may be needed after method return or deoptimization. // Keep the last store in each predecessor since future loads cannot be eliminated. for (HBasicBlock* predecessor : predecessors) { - ArenaVector<HInstruction*>& pred_values = heap_values_for_[predecessor->GetBlockId()]; + ScopedArenaVector<HInstruction*>& pred_values = + heap_values_for_[predecessor->GetBlockId()]; KeepIfIsStore(pred_values[i]); } } @@ -303,7 +308,7 @@ class LSEVisitor : public HGraphVisitor { size_t idx = heap_location_collector_.FindHeapLocationIndex( ref_info, offset, index, declaring_class_def_index); DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound); - ArenaVector<HInstruction*>& heap_values = + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; HInstruction* heap_value = heap_values[idx]; if (heap_value == kDefaultHeapValue) { @@ -369,7 +374,7 @@ class LSEVisitor : public HGraphVisitor { size_t idx = heap_location_collector_.FindHeapLocationIndex( ref_info, offset, index, declaring_class_def_index); DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound); - ArenaVector<HInstruction*>& heap_values = + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; HInstruction* heap_value = heap_values[idx]; bool same_value = false; @@ -496,7 +501,7 @@ class LSEVisitor : public HGraphVisitor { } void VisitDeoptimize(HDeoptimize* instruction) { - const ArenaVector<HInstruction*>& heap_values = + const ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; for (HInstruction* heap_value : heap_values) { // Filter out fake instructions before checking instruction kind below. @@ -523,7 +528,7 @@ class LSEVisitor : public HGraphVisitor { } void HandleInvoke(HInstruction* invoke) { - ArenaVector<HInstruction*>& heap_values = + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[invoke->GetBlock()->GetBlockId()]; for (size_t i = 0; i < heap_values.size(); i++) { ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo(); @@ -590,7 +595,7 @@ class LSEVisitor : public HGraphVisitor { !new_instance->NeedsChecks()) { singleton_new_instances_.push_back(new_instance); } - ArenaVector<HInstruction*>& heap_values = + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[new_instance->GetBlock()->GetBlockId()]; for (size_t i = 0; i < heap_values.size(); i++) { HInstruction* ref = @@ -612,7 +617,7 @@ class LSEVisitor : public HGraphVisitor { if (ref_info->IsSingletonAndRemovable()) { singleton_new_arrays_.push_back(new_array); } - ArenaVector<HInstruction*>& heap_values = + ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[new_array->GetBlock()->GetBlockId()]; for (size_t i = 0; i < heap_values.size(); i++) { HeapLocation* location = heap_location_collector_.GetHeapLocation(i); @@ -639,20 +644,23 @@ class LSEVisitor : public HGraphVisitor { const HeapLocationCollector& heap_location_collector_; const SideEffectsAnalysis& side_effects_; + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator_; + // One array of heap values for each block. - ArenaVector<ArenaVector<HInstruction*>> heap_values_for_; + ScopedArenaVector<ScopedArenaVector<HInstruction*>> heap_values_for_; // We record the instructions that should be eliminated but may be // used by heap locations. They'll be removed in the end. - ArenaVector<HInstruction*> removed_loads_; - ArenaVector<HInstruction*> substitute_instructions_for_loads_; + ScopedArenaVector<HInstruction*> removed_loads_; + ScopedArenaVector<HInstruction*> substitute_instructions_for_loads_; // Stores in this list may be removed from the list later when it's // found that the store cannot be eliminated. - ArenaVector<HInstruction*> possibly_removed_stores_; + ScopedArenaVector<HInstruction*> possibly_removed_stores_; - ArenaVector<HInstruction*> singleton_new_instances_; - ArenaVector<HInstruction*> singleton_new_arrays_; + ScopedArenaVector<HInstruction*> singleton_new_instances_; + ScopedArenaVector<HInstruction*> singleton_new_arrays_; DISALLOW_COPY_AND_ASSIGN(LSEVisitor); }; diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index d87861bde0..645915e2f8 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -1359,7 +1359,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction; return TrySetVectorLength(4); case DataType::Type::kInt32: - *restrictions |= kNoDiv | kNoReduction; + *restrictions |= kNoDiv | kNoWideSAD; return TrySetVectorLength(2); default: break; @@ -1968,7 +1968,9 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node, return false; } // Try same/narrower type and deal with vector restrictions. - if (!TrySetVectorType(sub_type, &restrictions) || HasVectorRestrictions(restrictions, kNoSAD)) { + if (!TrySetVectorType(sub_type, &restrictions) || + HasVectorRestrictions(restrictions, kNoSAD) || + (reduction_type != sub_type && HasVectorRestrictions(restrictions, kNoWideSAD))) { return false; } // Accept SAD idiom for vectorizable operands. Vectorized code uses the shorthand diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h index b1b3d110bc..768fe554e3 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -78,6 +78,7 @@ class HLoopOptimization : public HOptimization { kNoStringCharAt = 1 << 9, // no StringCharAt kNoReduction = 1 << 10, // no reduction kNoSAD = 1 << 11, // no sum of absolute differences (SAD) + kNoWideSAD = 1 << 12, // no sum of absolute differences (SAD) with operand widening }; /* diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 1a537ca47e..f4f6434678 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -55,14 +55,18 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) { // "visited" must be empty on entry, it's an output argument for all visited (i.e. live) blocks. DCHECK_EQ(visited->GetHighestBitSet(), -1); + // Allocate memory from local ScopedArenaAllocator. + ScopedArenaAllocator allocator(GetArenaStack()); // Nodes that we're currently visiting, indexed by block id. - ArenaBitVector visiting(allocator_, blocks_.size(), false, kArenaAllocGraphBuilder); + ArenaBitVector visiting( + &allocator, blocks_.size(), /* expandable */ false, kArenaAllocGraphBuilder); + visiting.ClearAllBits(); // Number of successors visited from a given node, indexed by block id. - ArenaVector<size_t> successors_visited(blocks_.size(), - 0u, - allocator_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<size_t> successors_visited(blocks_.size(), + 0u, + allocator.Adapter(kArenaAllocGraphBuilder)); // Stack of nodes that we're currently visiting (same as marked in "visiting" above). - ArenaVector<HBasicBlock*> worklist(allocator_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder)); constexpr size_t kDefaultWorklistSize = 8; worklist.reserve(kDefaultWorklistSize); visited->SetBit(entry_block_->GetBlockId()); @@ -173,7 +177,11 @@ void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) { } GraphAnalysisResult HGraph::BuildDominatorTree() { - ArenaBitVector visited(allocator_, blocks_.size(), false, kArenaAllocGraphBuilder); + // Allocate memory from local ScopedArenaAllocator. + ScopedArenaAllocator allocator(GetArenaStack()); + + ArenaBitVector visited(&allocator, blocks_.size(), false, kArenaAllocGraphBuilder); + visited.ClearAllBits(); // (1) Find the back edges in the graph doing a DFS traversal. FindBackEdges(&visited); @@ -258,14 +266,16 @@ void HGraph::ComputeDominanceInformation() { reverse_post_order_.reserve(blocks_.size()); reverse_post_order_.push_back(entry_block_); + // Allocate memory from local ScopedArenaAllocator. + ScopedArenaAllocator allocator(GetArenaStack()); // Number of visits of a given node, indexed by block id. - ArenaVector<size_t> visits(blocks_.size(), 0u, allocator_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<size_t> visits(blocks_.size(), 0u, allocator.Adapter(kArenaAllocGraphBuilder)); // Number of successors visited from a given node, indexed by block id. - ArenaVector<size_t> successors_visited(blocks_.size(), - 0u, - allocator_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<size_t> successors_visited(blocks_.size(), + 0u, + allocator.Adapter(kArenaAllocGraphBuilder)); // Nodes for which we need to visit successors. - ArenaVector<HBasicBlock*> worklist(allocator_->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder)); constexpr size_t kDefaultWorklistSize = 8; worklist.reserve(kDefaultWorklistSize); worklist.push_back(entry_block_); @@ -710,10 +720,13 @@ void HLoopInformation::Populate() { bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader(); if (is_irreducible_loop) { - ArenaBitVector visited(graph->GetAllocator(), + // Allocate memory from local ScopedArenaAllocator. + ScopedArenaAllocator allocator(graph->GetArenaStack()); + ArenaBitVector visited(&allocator, graph->GetBlocks().size(), /* expandable */ false, kArenaAllocGraphBuilder); + visited.ClearAllBits(); // Stop marking blocks at the loop header. visited.SetBit(header_->GetBlockId()); @@ -942,7 +955,7 @@ void HBasicBlock::RemoveInstructionOrPhi(HInstruction* instruction, bool ensure_ } } -void HEnvironment::CopyFrom(const ArenaVector<HInstruction*>& locals) { +void HEnvironment::CopyFrom(ArrayRef<HInstruction* const> locals) { for (size_t i = 0; i < locals.size(); i++) { HInstruction* instruction = locals[i]; SetRawEnvAt(i, instruction); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 99fde755da..75cdb3ee5e 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1839,7 +1839,7 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { } } - void CopyFrom(const ArenaVector<HInstruction*>& locals); + void CopyFrom(ArrayRef<HInstruction* const> locals); void CopyFrom(HEnvironment* environment); // Copy from `env`. If it's a loop phi for `loop_header`, copy the first diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc index b2180d9f98..9bfd250ea4 100644 --- a/compiler/optimizing/nodes_test.cc +++ b/compiler/optimizing/nodes_test.cc @@ -129,10 +129,9 @@ TEST_F(NodeTest, ParentEnvironment) { HEnvironment* environment = new (GetAllocator()) HEnvironment( GetAllocator(), 1, graph->GetArtMethod(), 0, with_environment); - ArenaVector<HInstruction*> array(GetAllocator()->Adapter()); - array.push_back(parameter1); + HInstruction* const array[] = { parameter1 }; - environment->CopyFrom(array); + environment->CopyFrom(ArrayRef<HInstruction* const>(array)); with_environment->SetRawEnvironment(environment); ASSERT_TRUE(parameter1->HasEnvironmentUses()); @@ -140,13 +139,13 @@ TEST_F(NodeTest, ParentEnvironment) { HEnvironment* parent1 = new (GetAllocator()) HEnvironment( GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr); - parent1->CopyFrom(array); + parent1->CopyFrom(ArrayRef<HInstruction* const>(array)); ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u); HEnvironment* parent2 = new (GetAllocator()) HEnvironment( GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr); - parent2->CopyFrom(array); + parent2->CopyFrom(ArrayRef<HInstruction* const>(array)); parent1->SetAndCopyParentChain(GetAllocator(), parent2); // One use for parent2, and one other use for the new parent of parent1. diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 9bfb7a5c50..42f32b7866 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1146,7 +1146,8 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, if (total_allocated > kArenaAllocatorMemoryReportThreshold) { MemStats mem_stats(allocator.GetMemStats()); MemStats peak_stats(arena_stack.GetPeakStats()); - LOG(INFO) << dex_file.PrettyMethod(method_idx) + LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling " + << dex_file.PrettyMethod(method_idx) << "\n" << Dumpable<MemStats>(mem_stats) << "\n" << Dumpable<MemStats>(peak_stats); } @@ -1256,7 +1257,8 @@ bool OptimizingCompiler::JitCompile(Thread* self, if (total_allocated > kArenaAllocatorMemoryReportThreshold) { MemStats mem_stats(allocator.GetMemStats()); MemStats peak_stats(arena_stack.GetPeakStats()); - LOG(INFO) << dex_file->PrettyMethod(method_idx) + LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling " + << dex_file->PrettyMethod(method_idx) << "\n" << Dumpable<MemStats>(mem_stats) << "\n" << Dumpable<MemStats>(peak_stats); } diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index 5632f9a453..9aba91205c 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -22,7 +22,9 @@ #include "common_compiler_test.h" #include "dex_file.h" #include "dex_instruction.h" -#include "handle_scope.h" +#include "handle_scope-inl.h" +#include "mirror/class_loader.h" +#include "mirror/dex_cache.h" #include "nodes.h" #include "scoped_thread_state_change.h" #include "ssa_builder.h" @@ -123,8 +125,7 @@ class OptimizingUnitTest : public CommonCompilerTest { // Create a control-flow graph from Dex instructions. HGraph* CreateCFG(const uint16_t* data, DataType::Type return_type = DataType::Type::kInt32) { - const DexFile::CodeItem* item = - reinterpret_cast<const DexFile::CodeItem*>(data); + const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(data); HGraph* graph = CreateGraph(); { @@ -132,7 +133,19 @@ class OptimizingUnitTest : public CommonCompilerTest { if (handles_ == nullptr) { handles_.reset(new VariableSizedHandleScope(soa.Self())); } - HGraphBuilder builder(graph, *item, handles_.get(), return_type); + const DexFile* dex_file = graph->GetAllocator()->Alloc<DexFile>(); + const DexCompilationUnit* dex_compilation_unit = + new (graph->GetAllocator()) DexCompilationUnit( + handles_->NewHandle<mirror::ClassLoader>(nullptr), + /* class_linker */ nullptr, + *dex_file, + code_item, + /* class_def_index */ DexFile::kDexNoIndex16, + /* method_idx */ dex::kDexNoIndex, + /* access_flags */ 0u, + /* verified_method */ nullptr, + handles_->NewHandle<mirror::DexCache>(nullptr)); + HGraphBuilder builder(graph, dex_compilation_unit, *code_item, handles_.get(), return_type); bool graph_built = (builder.BuildGraph() == kAnalysisSuccess); return graph_built ? graph : nullptr; } diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 6d9ebc8d91..cb9dc42572 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -18,8 +18,11 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "handle_scope-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" #include "scoped_thread_state_change-inl.h" @@ -70,14 +73,16 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, HandleCache* handle_cache, - ArenaVector<HInstruction*>* worklist, bool is_first_run) : HGraphDelegateVisitor(graph), class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handle_cache), - worklist_(worklist), - is_first_run_(is_first_run) {} + allocator_(graph->GetArenaStack()), + worklist_(allocator_.Adapter(kArenaAllocReferenceTypePropagation)), + is_first_run_(is_first_run) { + worklist_.reserve(kDefaultWorklistSize); + } void VisitDeoptimize(HDeoptimize* deopt) OVERRIDE; void VisitNewInstance(HNewInstance* new_instance) OVERRIDE; @@ -87,9 +92,6 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { void VisitLoadException(HLoadException* instr) OVERRIDE; void VisitNewArray(HNewArray* instr) OVERRIDE; void VisitParameterValue(HParameterValue* instr) OVERRIDE; - void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info); - void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact) - REQUIRES_SHARED(Locks::mutator_lock_); void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE; void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE; void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE; @@ -99,16 +101,39 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { void VisitCheckCast(HCheckCast* instr) OVERRIDE; void VisitBoundType(HBoundType* instr) OVERRIDE; void VisitNullCheck(HNullCheck* instr) OVERRIDE; + void VisitPhi(HPhi* phi); + + void VisitBasicBlock(HBasicBlock* block); + void ProcessWorklist(); + + private: + void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info); + void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact) + REQUIRES_SHARED(Locks::mutator_lock_); + void BoundTypeForIfNotNull(HBasicBlock* block); + static void BoundTypeForIfInstanceOf(HBasicBlock* block); + static bool UpdateNullability(HInstruction* instr); + static void UpdateBoundType(HBoundType* bound_type) REQUIRES_SHARED(Locks::mutator_lock_); + void UpdateArrayGet(HArrayGet* instr) REQUIRES_SHARED(Locks::mutator_lock_); + void UpdatePhi(HPhi* phi) REQUIRES_SHARED(Locks::mutator_lock_); + bool UpdateReferenceTypeInfo(HInstruction* instr); void UpdateReferenceTypeInfo(HInstruction* instr, dex::TypeIndex type_idx, const DexFile& dex_file, bool is_exact); - private: + void AddToWorklist(HInstruction* instruction); + void AddDependentInstructionsToWorklist(HInstruction* instruction); + + static constexpr size_t kDefaultWorklistSize = 8; + Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> hint_dex_cache_; - HandleCache* handle_cache_; - ArenaVector<HInstruction*>* worklist_; + HandleCache* const handle_cache_; + + // Use local allocator for allocating memory. + ScopedArenaAllocator allocator_; + ScopedArenaVector<HInstruction*> worklist_; const bool is_first_run_; }; @@ -122,7 +147,6 @@ ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph, class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handles), - worklist_(graph->GetAllocator()->Adapter(kArenaAllocReferenceTypePropagation)), is_first_run_(is_first_run) { } @@ -158,7 +182,6 @@ void ReferenceTypePropagation::Visit(HInstruction* instruction) { class_loader_, hint_dex_cache_, &handle_cache_, - &worklist_, is_first_run_); instruction->Accept(&visitor); } @@ -319,26 +342,20 @@ static void BoundTypeForClassCheck(HInstruction* check) { } void ReferenceTypePropagation::Run() { - worklist_.reserve(kDefaultWorklistSize); + RTPVisitor visitor(graph_, class_loader_, hint_dex_cache_, &handle_cache_, is_first_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. // We take advantage of this order in `VisitBasicBlock`. for (HBasicBlock* block : graph_->GetReversePostOrder()) { - VisitBasicBlock(block); + visitor.VisitBasicBlock(block); } - ProcessWorklist(); + visitor.ProcessWorklist(); ValidateTypes(); } -void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { - RTPVisitor visitor(graph_, - class_loader_, - hint_dex_cache_, - &handle_cache_, - &worklist_, - is_first_run_); +void ReferenceTypePropagation::RTPVisitor::VisitBasicBlock(HBasicBlock* block) { // 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()); @@ -348,7 +365,7 @@ void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { // last visited instruction, use `HInstructionIteratorHandleChanges` iterator. for (HInstructionIteratorHandleChanges it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* instr = it.Current(); - instr->Accept(&visitor); + instr->Accept(this); } // Add extra nodes to bound types. @@ -357,7 +374,7 @@ void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { BoundTypeForClassCheck(block->GetLastInstruction()); } -void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) { +void ReferenceTypePropagation::RTPVisitor::BoundTypeForIfNotNull(HBasicBlock* block) { HIf* ifInstruction = block->GetLastInstruction()->AsIf(); if (ifInstruction == nullptr) { return; @@ -391,7 +408,7 @@ void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) { : ifInstruction->IfFalseSuccessor(); ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create( - handle_cache_.GetObjectClassHandle(), /* is_exact */ false); + handle_cache_->GetObjectClassHandle(), /* is_exact */ false); BoundTypeIn(obj, notNullBlock, /* start_instruction */ nullptr, object_rti); } @@ -469,7 +486,7 @@ static bool MatchIfInstanceOf(HIf* ifInstruction, // `if (x instanceof ClassX) { }` // If that's the case insert an HBoundType instruction to bound the type of `x` // to `ClassX` in the scope of the dominated blocks. -void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) { +void ReferenceTypePropagation::RTPVisitor::BoundTypeForIfInstanceOf(HBasicBlock* block) { HIf* ifInstruction = block->GetLastInstruction()->AsIf(); if (ifInstruction == nullptr) { return; @@ -728,7 +745,7 @@ void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast } } -void ReferenceTypePropagation::VisitPhi(HPhi* phi) { +void ReferenceTypePropagation::RTPVisitor::VisitPhi(HPhi* phi) { if (phi->IsDead() || phi->GetType() != DataType::Type::kReference) { return; } @@ -812,7 +829,7 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& return ReferenceTypeInfo::Create(result_type_handle, is_exact); } -void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) { +void ReferenceTypePropagation::RTPVisitor::UpdateArrayGet(HArrayGet* instr) { DCHECK_EQ(DataType::Type::kReference, instr->GetType()); ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo(); @@ -823,7 +840,7 @@ void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* han Handle<mirror::Class> handle = parent_rti.GetTypeHandle(); if (handle->IsObjectArrayClass() && IsAdmissible(handle->GetComponentType())) { ReferenceTypeInfo::TypeHandle component_handle = - handle_cache->NewHandle(handle->GetComponentType()); + handle_cache_->NewHandle(handle->GetComponentType()); bool is_exact = component_handle->CannotBeAssignedFromOtherTypes(); instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact)); } else { @@ -832,7 +849,7 @@ void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* han } } -bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) { +bool ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr) { ScopedObjectAccess soa(Thread::Current()); ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo(); @@ -848,7 +865,7 @@ bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) { } else if (instr->IsArrayGet()) { // TODO: consider if it's worth "looking back" and binding the input object // to an array type. - UpdateArrayGet(instr->AsArrayGet(), &handle_cache_); + UpdateArrayGet(instr->AsArrayGet()); } else { LOG(FATAL) << "Invalid instruction (should not get here)"; } @@ -873,13 +890,13 @@ void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) { } ScopedObjectAccess soa(Thread::Current()); - UpdateArrayGet(instr, handle_cache_); + UpdateArrayGet(instr); if (!instr->GetReferenceTypeInfo().IsValid()) { - worklist_->push_back(instr); + worklist_.push_back(instr); } } -void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) { +void ReferenceTypePropagation::RTPVisitor::UpdateBoundType(HBoundType* instr) { ReferenceTypeInfo input_rti = instr->InputAt(0)->GetReferenceTypeInfo(); if (!input_rti.IsValid()) { return; // No new info yet. @@ -903,7 +920,7 @@ void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) { // NullConstant inputs are ignored during merging as they do not provide any useful information. // If all the inputs are NullConstants then the type of the phi will be set to Object. -void ReferenceTypePropagation::UpdatePhi(HPhi* instr) { +void ReferenceTypePropagation::RTPVisitor::UpdatePhi(HPhi* instr) { DCHECK(instr->IsLive()); HInputsRef inputs = instr->GetInputs(); @@ -931,7 +948,7 @@ void ReferenceTypePropagation::UpdatePhi(HPhi* instr) { if (inputs[i]->IsNullConstant()) { continue; } - new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), &handle_cache_); + new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), handle_cache_); if (new_rti.IsValid() && new_rti.IsObjectClass()) { if (!new_rti.IsExact()) { break; @@ -948,7 +965,7 @@ void ReferenceTypePropagation::UpdatePhi(HPhi* instr) { // Re-computes and updates the nullability of the instruction. Returns whether or // not the nullability was changed. -bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) { +bool ReferenceTypePropagation::RTPVisitor::UpdateNullability(HInstruction* instr) { DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive()) || instr->IsBoundType() || instr->IsNullCheck() @@ -976,7 +993,7 @@ bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) { return existing_can_be_null != instr->CanBeNull(); } -void ReferenceTypePropagation::ProcessWorklist() { +void ReferenceTypePropagation::RTPVisitor::ProcessWorklist() { while (!worklist_.empty()) { HInstruction* instruction = worklist_.back(); worklist_.pop_back(); @@ -988,13 +1005,14 @@ void ReferenceTypePropagation::ProcessWorklist() { } } -void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) { +void ReferenceTypePropagation::RTPVisitor::AddToWorklist(HInstruction* instruction) { DCHECK_EQ(instruction->GetType(), DataType::Type::kReference) << instruction->DebugName() << ":" << instruction->GetType(); worklist_.push_back(instruction); } -void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) { +void ReferenceTypePropagation::RTPVisitor::AddDependentInstructionsToWorklist( + HInstruction* instruction) { for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) { HInstruction* user = use.GetUser(); if ((user->IsPhi() && user->AsPhi()->IsLive()) diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index c221282b9b..fd4dad2b45 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -18,12 +18,10 @@ #define ART_COMPILER_OPTIMIZING_REFERENCE_TYPE_PROPAGATION_H_ #include "base/arena_containers.h" -#include "driver/dex_compilation_unit.h" -#include "handle_scope-inl.h" +#include "mirror/class-inl.h" #include "nodes.h" #include "obj_ptr.h" #include "optimization.h" -#include "optimizing_compiler_stats.h" namespace art { @@ -91,22 +89,6 @@ class ReferenceTypePropagation : public HOptimization { class RTPVisitor; - void VisitPhi(HPhi* phi); - void VisitBasicBlock(HBasicBlock* block); - void UpdateBoundType(HBoundType* bound_type) REQUIRES_SHARED(Locks::mutator_lock_); - void UpdatePhi(HPhi* phi) REQUIRES_SHARED(Locks::mutator_lock_); - void BoundTypeForIfNotNull(HBasicBlock* block); - void BoundTypeForIfInstanceOf(HBasicBlock* block); - void ProcessWorklist(); - void AddToWorklist(HInstruction* instr); - void AddDependentInstructionsToWorklist(HInstruction* instr); - - bool UpdateNullability(HInstruction* instr); - bool UpdateReferenceTypeInfo(HInstruction* instr); - - static void UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) - REQUIRES_SHARED(Locks::mutator_lock_); - static ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b, HandleCache* handle_cache) @@ -122,13 +104,9 @@ class ReferenceTypePropagation : public HOptimization { Handle<mirror::DexCache> hint_dex_cache_; HandleCache handle_cache_; - ArenaVector<HInstruction*> worklist_; - // Whether this reference type propagation is the first run we are doing. const bool is_first_run_; - static constexpr size_t kDefaultWorklistSize = 8; - friend class ReferenceTypePropagationTest; DISALLOW_COPY_AND_ASSIGN(ReferenceTypePropagation); diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index ece9904426..86e971353f 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -53,6 +53,21 @@ std::unique_ptr<RegisterAllocator> RegisterAllocator::Create(ScopedArenaAllocato } } +RegisterAllocator::~RegisterAllocator() { + if (kIsDebugBuild) { + // Poison live interval pointers with "Error: BAD 71ve1nt3rval." + LiveInterval* bad_live_interval = reinterpret_cast<LiveInterval*>(0xebad7113u); + for (HBasicBlock* block : codegen_->GetGraph()->GetLinearOrder()) { + for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { + it.Current()->SetLiveInterval(bad_live_interval); + } + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + it.Current()->SetLiveInterval(bad_live_interval); + } + } + } +} + bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph ATTRIBUTE_UNUSED, InstructionSet instruction_set) { return instruction_set == kArm diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index eaeec3b261..18ef69fcab 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -50,7 +50,7 @@ class RegisterAllocator : public DeletableArenaObject<kArenaAllocRegisterAllocat const SsaLivenessAnalysis& analysis, Strategy strategy = kRegisterAllocatorDefault); - virtual ~RegisterAllocator() = default; + virtual ~RegisterAllocator(); // Main entry point for the register allocator. Given the liveness analysis, // allocates registers to live intervals. @@ -87,7 +87,7 @@ class RegisterAllocator : public DeletableArenaObject<kArenaAllocRegisterAllocat // to find an optimal split position. LiveInterval* SplitBetween(LiveInterval* interval, size_t from, size_t to); - ScopedArenaAllocator* allocator_; + ScopedArenaAllocator* const allocator_; CodeGenerator* const codegen_; const SsaLivenessAnalysis& liveness_; }; diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc index c673d54458..57eb7623b1 100644 --- a/compiler/optimizing/scheduler.cc +++ b/compiler/optimizing/scheduler.cc @@ -781,7 +781,7 @@ void HInstructionScheduling::Run(bool only_optimize_loop_blocks, #if defined(ART_ENABLE_CODEGEN_arm64) || defined(ART_ENABLE_CODEGEN_arm) // Phase-local allocator that allocates scheduler internal data structures like // scheduling nodes, internel nodes map, dependencies, etc. - ScopedArenaAllocator arena_allocator(graph_->GetArenaStack()); + ScopedArenaAllocator allocator(graph_->GetArenaStack()); CriticalPathSchedulingNodeSelector critical_path_selector; RandomSchedulingNodeSelector random_selector; SchedulingNodeSelector* selector = schedule_randomly @@ -797,7 +797,7 @@ void HInstructionScheduling::Run(bool only_optimize_loop_blocks, switch (instruction_set_) { #ifdef ART_ENABLE_CODEGEN_arm64 case kArm64: { - arm64::HSchedulerARM64 scheduler(&arena_allocator, selector); + arm64::HSchedulerARM64 scheduler(&allocator, selector); scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks); scheduler.Schedule(graph_); break; @@ -807,7 +807,7 @@ void HInstructionScheduling::Run(bool only_optimize_loop_blocks, case kThumb2: case kArm: { arm::SchedulingLatencyVisitorARM arm_latency_visitor(codegen_); - arm::HSchedulerARM scheduler(&arena_allocator, selector, &arm_latency_visitor); + arm::HSchedulerARM scheduler(&allocator, selector, &arm_latency_visitor); scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks); scheduler.Schedule(graph_); break; diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h index 3efd26af9b..afdf6f1474 100644 --- a/compiler/optimizing/scheduler.h +++ b/compiler/optimizing/scheduler.h @@ -253,14 +253,14 @@ class SchedulingGraph : public ValueObject { public: SchedulingGraph(const HScheduler* scheduler, ScopedArenaAllocator* allocator) : scheduler_(scheduler), - arena_(allocator), + allocator_(allocator), contains_scheduling_barrier_(false), - nodes_map_(arena_->Adapter(kArenaAllocScheduler)), + nodes_map_(allocator_->Adapter(kArenaAllocScheduler)), heap_location_collector_(nullptr) {} SchedulingNode* AddNode(HInstruction* instr, bool is_scheduling_barrier = false) { std::unique_ptr<SchedulingNode> node( - new (arena_) SchedulingNode(instr, arena_, is_scheduling_barrier)); + new (allocator_) SchedulingNode(instr, allocator_, is_scheduling_barrier)); SchedulingNode* result = node.get(); nodes_map_.Insert(std::make_pair(instr, std::move(node))); contains_scheduling_barrier_ |= is_scheduling_barrier; @@ -323,7 +323,7 @@ class SchedulingGraph : public ValueObject { const HScheduler* const scheduler_; - ScopedArenaAllocator* const arena_; + ScopedArenaAllocator* const allocator_; bool contains_scheduling_barrier_; diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc index 0e46aeca37..77ec9a6285 100644 --- a/compiler/optimizing/select_generator.cc +++ b/compiler/optimizing/select_generator.cc @@ -16,6 +16,8 @@ #include "select_generator.h" +#include "reference_type_propagation.h" + namespace art { static constexpr size_t kMaxInstructionsInBranch = 1u; diff --git a/compiler/optimizing/select_generator.h b/compiler/optimizing/select_generator.h index c060146478..f8cf00e35a 100644 --- a/compiler/optimizing/select_generator.h +++ b/compiler/optimizing/select_generator.h @@ -58,7 +58,6 @@ #define ART_COMPILER_OPTIMIZING_SELECT_GENERATOR_H_ #include "optimization.h" -#include "reference_type_propagation.h" namespace art { diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index f4a8a17131..e4edbfdc24 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -105,7 +105,7 @@ void SsaBuilder::FixEnvironmentPhis() { } static void AddDependentInstructionsToWorklist(HInstruction* instruction, - ArenaVector<HPhi*>* worklist) { + ScopedArenaVector<HPhi*>* worklist) { // If `instruction` is a dead phi, type conflict was just identified. All its // live phi users, and transitively users of those users, therefore need to be // marked dead/conflicting too, so we add them to the worklist. Otherwise we @@ -167,7 +167,7 @@ static bool TypePhiFromInputs(HPhi* phi) { } // Replace inputs of `phi` to match its type. Return false if conflict is identified. -bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist) { +bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) { DataType::Type common_type = phi->GetType(); if (DataType::IsIntegralType(common_type)) { // We do not need to retype ambiguous inputs because they are always constructed @@ -213,7 +213,7 @@ bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist) { // Attempt to set the primitive type of `phi` to match its inputs. Return whether // it was changed by the algorithm or not. -bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist) { +bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) { DCHECK(phi->IsLive()); DataType::Type original_type = phi->GetType(); @@ -233,7 +233,7 @@ bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist) { } void SsaBuilder::RunPrimitiveTypePropagation() { - ArenaVector<HPhi*> worklist(graph_->GetAllocator()->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder)); for (HBasicBlock* block : graph_->GetReversePostOrder()) { if (block->IsLoopHeader()) { @@ -262,7 +262,7 @@ void SsaBuilder::RunPrimitiveTypePropagation() { EquivalentPhisCleanup(); } -void SsaBuilder::ProcessPrimitiveTypePropagationWorklist(ArenaVector<HPhi*>* worklist) { +void SsaBuilder::ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist) { // Process worklist while (!worklist->empty()) { HPhi* phi = worklist->back(); @@ -319,7 +319,7 @@ bool SsaBuilder::FixAmbiguousArrayOps() { // uses (because they are untyped) and environment uses (if --debuggable). // After resolving all ambiguous ArrayGets, we will re-run primitive type // propagation on the Phis which need to be updated. - ArenaVector<HPhi*> worklist(graph_->GetAllocator()->Adapter(kArenaAllocGraphBuilder)); + ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder)); { ScopedObjectAccess soa(Thread::Current()); @@ -623,8 +623,7 @@ HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, DataType:: || (next->GetType() != type)) { ArenaAllocator* allocator = graph_->GetAllocator(); HInputsRef inputs = phi->GetInputs(); - HPhi* new_phi = - new (allocator) HPhi(allocator, phi->GetRegNumber(), inputs.size(), type); + HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), inputs.size(), type); // Copy the inputs. Note that the graph may not be correctly typed // by doing this copy, but the type propagation phase will fix it. ArrayRef<HUserRecord<HInstruction*>> new_input_records = new_phi->GetInputRecords(); diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h index 509cdc1252..60831a9e6a 100644 --- a/compiler/optimizing/ssa_builder.h +++ b/compiler/optimizing/ssa_builder.h @@ -17,7 +17,8 @@ #ifndef ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_ #define ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_ -#include "base/arena_containers.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "nodes.h" #include "optimization.h" @@ -50,15 +51,17 @@ class SsaBuilder : public ValueObject { SsaBuilder(HGraph* graph, Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> dex_cache, - VariableSizedHandleScope* handles) + VariableSizedHandleScope* handles, + ScopedArenaAllocator* local_allocator) : graph_(graph), class_loader_(class_loader), dex_cache_(dex_cache), handles_(handles), agets_fixed_(false), - ambiguous_agets_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)), - ambiguous_asets_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)), - uninitialized_strings_(graph->GetAllocator()->Adapter(kArenaAllocGraphBuilder)) { + local_allocator_(local_allocator), + ambiguous_agets_(local_allocator->Adapter(kArenaAllocGraphBuilder)), + ambiguous_asets_(local_allocator->Adapter(kArenaAllocGraphBuilder)), + uninitialized_strings_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { graph_->InitializeInexactObjectRTI(handles); } @@ -105,9 +108,9 @@ class SsaBuilder : public ValueObject { // input. Returns false if the type of an array is unknown. bool FixAmbiguousArrayOps(); - bool TypeInputsOfPhi(HPhi* phi, ArenaVector<HPhi*>* worklist); - bool UpdatePrimitiveType(HPhi* phi, ArenaVector<HPhi*>* worklist); - void ProcessPrimitiveTypePropagationWorklist(ArenaVector<HPhi*>* worklist); + bool TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist); + bool UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist); + void ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist); HFloatConstant* GetFloatEquivalent(HIntConstant* constant); HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant); @@ -116,7 +119,7 @@ class SsaBuilder : public ValueObject { void RemoveRedundantUninitializedStrings(); - HGraph* graph_; + HGraph* const graph_; Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> dex_cache_; VariableSizedHandleScope* const handles_; @@ -124,9 +127,10 @@ class SsaBuilder : public ValueObject { // True if types of ambiguous ArrayGets have been resolved. bool agets_fixed_; - ArenaVector<HArrayGet*> ambiguous_agets_; - ArenaVector<HArraySet*> ambiguous_asets_; - ArenaVector<HNewInstance*> uninitialized_strings_; + ScopedArenaAllocator* const local_allocator_; + ScopedArenaVector<HArrayGet*> ambiguous_agets_; + ScopedArenaVector<HArraySet*> ambiguous_asets_; + ScopedArenaVector<HNewInstance*> uninitialized_strings_; DISALLOW_COPY_AND_ASSIGN(SsaBuilder); }; diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index 9800af76f8..f83bb52b69 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -1292,7 +1292,7 @@ class SsaLivenessAnalysis : public ValueObject { // Use a local ScopedArenaAllocator for allocating memory. // This allocator must remain alive while doing register allocation. - ScopedArenaAllocator* allocator_; + ScopedArenaAllocator* const allocator_; ScopedArenaVector<BlockInfo*> block_infos_; diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc index 9b78e0ee6c..b9bfbaa173 100644 --- a/compiler/optimizing/ssa_liveness_analysis_test.cc +++ b/compiler/optimizing/ssa_liveness_analysis_test.cc @@ -95,8 +95,7 @@ TEST_F(SsaLivenessAnalysisTest, TestAput) { graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32); HInstruction* extra_arg2 = new (GetAllocator()) HParameterValue( graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference); - ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 }, - GetAllocator()->Adapter()); + HInstruction* const args[] = { array, index, value, extra_arg1, extra_arg2 }; for (HInstruction* insn : args) { entry_->AddInstruction(insn); } @@ -109,7 +108,7 @@ TEST_F(SsaLivenessAnalysisTest, TestAput) { /* method */ nullptr, /* dex_pc */ 0u, null_check); - null_check_env->CopyFrom(args); + null_check_env->CopyFrom(ArrayRef<HInstruction* const>(args)); null_check->SetRawEnvironment(null_check_env); HInstruction* length = new (GetAllocator()) HArrayLength(array, 0); block->AddInstruction(length); @@ -120,7 +119,7 @@ TEST_F(SsaLivenessAnalysisTest, TestAput) { /* method */ nullptr, /* dex_pc */ 0u, bounds_check); - bounds_check_env->CopyFrom(args); + bounds_check_env->CopyFrom(ArrayRef<HInstruction* const>(args)); bounds_check->SetRawEnvironment(bounds_check_env); HInstruction* array_set = new (GetAllocator()) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0); @@ -144,7 +143,7 @@ TEST_F(SsaLivenessAnalysisTest, TestAput) { // Environment uses keep the reference argument alive. "ranges: { [10,19) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0", }; - ASSERT_EQ(arraysize(expected), args.size()); + static_assert(arraysize(expected) == arraysize(args), "Array size check."); size_t arg_index = 0u; for (HInstruction* arg : args) { std::ostringstream arg_dump; @@ -165,8 +164,7 @@ TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) { graph_->GetDexFile(), dex::TypeIndex(3), 3, DataType::Type::kInt32); HInstruction* extra_arg2 = new (GetAllocator()) HParameterValue( graph_->GetDexFile(), dex::TypeIndex(4), 4, DataType::Type::kReference); - ArenaVector<HInstruction*> args({ array, index, value, extra_arg1, extra_arg2 }, - GetAllocator()->Adapter()); + HInstruction* const args[] = { array, index, value, extra_arg1, extra_arg2 }; for (HInstruction* insn : args) { entry_->AddInstruction(insn); } @@ -179,7 +177,7 @@ TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) { /* method */ nullptr, /* dex_pc */ 0u, null_check); - null_check_env->CopyFrom(args); + null_check_env->CopyFrom(ArrayRef<HInstruction* const>(args)); null_check->SetRawEnvironment(null_check_env); HInstruction* length = new (GetAllocator()) HArrayLength(array, 0); block->AddInstruction(length); @@ -194,7 +192,7 @@ TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) { /* method */ nullptr, /* dex_pc */ 0u, deoptimize); - deoptimize_env->CopyFrom(args); + deoptimize_env->CopyFrom(ArrayRef<HInstruction* const>(args)); deoptimize->SetRawEnvironment(deoptimize_env); HInstruction* array_set = new (GetAllocator()) HArraySet(array, index, value, DataType::Type::kInt32, /* dex_pc */ 0); @@ -217,7 +215,7 @@ TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) { // Environment uses keep the reference argument alive. "ranges: { [10,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0", }; - ASSERT_EQ(arraysize(expected), args.size()); + static_assert(arraysize(expected) == arraysize(args), "Array size check."); size_t arg_index = 0u; for (HInstruction* arg : args) { std::ostringstream arg_dump; diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc index 3b95b86268..cb27ded17a 100644 --- a/compiler/optimizing/ssa_phi_elimination.cc +++ b/compiler/optimizing/ssa_phi_elimination.cc @@ -17,7 +17,8 @@ #include "ssa_phi_elimination.h" #include "base/arena_bit_vector.h" -#include "base/arena_containers.h" +#include "base/scoped_arena_allocator.h" +#include "base/scoped_arena_containers.h" #include "base/bit_vector-inl.h" namespace art { @@ -28,10 +29,17 @@ void SsaDeadPhiElimination::Run() { } void SsaDeadPhiElimination::MarkDeadPhis() { + // Use local allocator for allocating memory used by this optimization. + ScopedArenaAllocator allocator(graph_->GetArenaStack()); + + static constexpr size_t kDefaultWorklistSize = 8; + ScopedArenaVector<HPhi*> worklist(allocator.Adapter(kArenaAllocSsaPhiElimination)); + worklist.reserve(kDefaultWorklistSize); + // Phis are constructed live and should not be revived if previously marked // dead. This algorithm temporarily breaks that invariant but we DCHECK that // only phis which were initially live are revived. - ArenaSet<HPhi*> initially_live(graph_->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)); + ScopedArenaSet<HPhi*> initially_live(allocator.Adapter(kArenaAllocSsaPhiElimination)); // Add to the worklist phis referenced by non-phi instructions. for (HBasicBlock* block : graph_->GetReversePostOrder()) { @@ -52,7 +60,7 @@ void SsaDeadPhiElimination::MarkDeadPhis() { } if (keep_alive) { - worklist_.push_back(phi); + worklist.push_back(phi); } else { phi->SetDead(); if (kIsDebugBuild) { @@ -63,9 +71,9 @@ void SsaDeadPhiElimination::MarkDeadPhis() { } // Process the worklist by propagating liveness to phi inputs. - while (!worklist_.empty()) { - HPhi* phi = worklist_.back(); - worklist_.pop_back(); + while (!worklist.empty()) { + HPhi* phi = worklist.back(); + worklist.pop_back(); for (HInstruction* raw_input : phi->GetInputs()) { HPhi* input = raw_input->AsPhi(); if (input != nullptr && input->IsDead()) { @@ -73,7 +81,7 @@ void SsaDeadPhiElimination::MarkDeadPhis() { // that the phi was not dead initially (see definition of `initially_live`). DCHECK(ContainsElement(initially_live, input)); input->SetLive(); - worklist_.push_back(input); + worklist.push_back(input); } } } @@ -115,23 +123,31 @@ void SsaDeadPhiElimination::EliminateDeadPhis() { } void SsaRedundantPhiElimination::Run() { + // Use local allocator for allocating memory used by this optimization. + ScopedArenaAllocator allocator(graph_->GetArenaStack()); + + static constexpr size_t kDefaultWorklistSize = 8; + ScopedArenaVector<HPhi*> worklist(allocator.Adapter(kArenaAllocSsaPhiElimination)); + worklist.reserve(kDefaultWorklistSize); + // Add all phis in the worklist. Order does not matter for correctness, and // neither will necessarily converge faster. for (HBasicBlock* block : graph_->GetReversePostOrder()) { for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) { - worklist_.push_back(inst_it.Current()->AsPhi()); + worklist.push_back(inst_it.Current()->AsPhi()); } } - ArenaBitVector visited_phis_in_cycle(graph_->GetAllocator(), + ArenaBitVector visited_phis_in_cycle(&allocator, graph_->GetCurrentInstructionId(), /* expandable */ false, kArenaAllocSsaPhiElimination); - ArenaVector<HPhi*> cycle_worklist(graph_->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)); + visited_phis_in_cycle.ClearAllBits(); + ScopedArenaVector<HPhi*> cycle_worklist(allocator.Adapter(kArenaAllocSsaPhiElimination)); - while (!worklist_.empty()) { - HPhi* phi = worklist_.back(); - worklist_.pop_back(); + while (!worklist.empty()) { + HPhi* phi = worklist.back(); + worklist.pop_back(); // If the phi has already been processed, continue. if (!phi->IsInBlock()) { @@ -231,7 +247,7 @@ void SsaRedundantPhiElimination::Run() { for (const HUseListNode<HInstruction*>& use : current->GetUses()) { HInstruction* user = use.GetUser(); if (user->IsPhi() && !visited_phis_in_cycle.IsBitSet(user->GetId())) { - worklist_.push_back(user->AsPhi()); + worklist.push_back(user->AsPhi()); } } DCHECK(candidate->StrictlyDominates(current)); diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h index e0cde074d6..11d5837eb5 100644 --- a/compiler/optimizing/ssa_phi_elimination.h +++ b/compiler/optimizing/ssa_phi_elimination.h @@ -17,7 +17,6 @@ #ifndef ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_ #define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_ -#include "base/arena_containers.h" #include "nodes.h" #include "optimization.h" @@ -30,10 +29,7 @@ namespace art { class SsaDeadPhiElimination : public HOptimization { public: explicit SsaDeadPhiElimination(HGraph* graph) - : HOptimization(graph, kSsaDeadPhiEliminationPassName), - worklist_(graph->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)) { - worklist_.reserve(kDefaultWorklistSize); - } + : HOptimization(graph, kSsaDeadPhiEliminationPassName) {} void Run() OVERRIDE; @@ -43,10 +39,6 @@ class SsaDeadPhiElimination : public HOptimization { static constexpr const char* kSsaDeadPhiEliminationPassName = "dead_phi_elimination"; private: - ArenaVector<HPhi*> worklist_; - - static constexpr size_t kDefaultWorklistSize = 8; - DISALLOW_COPY_AND_ASSIGN(SsaDeadPhiElimination); }; @@ -59,20 +51,13 @@ class SsaDeadPhiElimination : public HOptimization { class SsaRedundantPhiElimination : public HOptimization { public: explicit SsaRedundantPhiElimination(HGraph* graph) - : HOptimization(graph, kSsaRedundantPhiEliminationPassName), - worklist_(graph->GetAllocator()->Adapter(kArenaAllocSsaPhiElimination)) { - worklist_.reserve(kDefaultWorklistSize); - } + : HOptimization(graph, kSsaRedundantPhiEliminationPassName) {} void Run() OVERRIDE; static constexpr const char* kSsaRedundantPhiEliminationPassName = "redundant_phi_elimination"; private: - ArenaVector<HPhi*> worklist_; - - static constexpr size_t kDefaultWorklistSize = 8; - DISALLOW_COPY_AND_ASSIGN(SsaRedundantPhiElimination); }; diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index a574566e33..62ed7ee0e5 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -223,7 +223,7 @@ class StackMapStream : public ValueObject { size_t dex_register_locations_index) const; void CheckCodeInfo(MemoryRegion region) const; - ArenaAllocator* allocator_; + ArenaAllocator* const allocator_; const InstructionSet instruction_set_; ArenaVector<StackMapEntry> stack_maps_; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index a842c6e452..96ac368ac3 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -47,10 +47,10 @@ using Kind = DexRegisterLocation::Kind; TEST(StackMapTest, Test1) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector sp_mask(&allocator, 0, false); size_t number_of_dex_registers = 2; stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. @@ -58,7 +58,7 @@ TEST(StackMapTest, Test1) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -128,11 +128,11 @@ TEST(StackMapTest, Test1) { TEST(StackMapTest, Test2) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); ArtMethod art_method; - ArenaBitVector sp_mask1(&arena, 0, true); + ArenaBitVector sp_mask1(&allocator, 0, true); sp_mask1.SetBit(2); sp_mask1.SetBit(4); size_t number_of_dex_registers = 2; @@ -146,7 +146,7 @@ TEST(StackMapTest, Test2) { stream.EndInlineInfoEntry(); stream.EndStackMapEntry(); - ArenaBitVector sp_mask2(&arena, 0, true); + ArenaBitVector sp_mask2(&allocator, 0, true); sp_mask2.SetBit(3); sp_mask2.SetBit(8); stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0); @@ -154,7 +154,7 @@ TEST(StackMapTest, Test2) { stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location. stream.EndStackMapEntry(); - ArenaBitVector sp_mask3(&arena, 0, true); + ArenaBitVector sp_mask3(&allocator, 0, true); sp_mask3.SetBit(1); sp_mask3.SetBit(5); stream.BeginStackMapEntry(2, 192, 0xAB, &sp_mask3, number_of_dex_registers, 0); @@ -162,7 +162,7 @@ TEST(StackMapTest, Test2) { stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8); // Short location. stream.EndStackMapEntry(); - ArenaBitVector sp_mask4(&arena, 0, true); + ArenaBitVector sp_mask4(&allocator, 0, true); sp_mask4.SetBit(6); sp_mask4.SetBit(7); stream.BeginStackMapEntry(3, 256, 0xCD, &sp_mask4, number_of_dex_registers, 0); @@ -171,7 +171,7 @@ TEST(StackMapTest, Test2) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -412,11 +412,11 @@ TEST(StackMapTest, Test2) { TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); ArtMethod art_method; - ArenaBitVector sp_mask1(&arena, 0, true); + ArenaBitVector sp_mask1(&allocator, 0, true); sp_mask1.SetBit(2); sp_mask1.SetBit(4); const size_t number_of_dex_registers = 2; @@ -431,7 +431,7 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -506,10 +506,10 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { TEST(StackMapTest, TestNonLiveDexRegisters) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kNone, 0); // No location. @@ -517,7 +517,7 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -585,10 +585,10 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { // not treat it as kNoDexRegisterMap. TEST(StackMapTest, DexRegisterMapOffsetOverflow) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 1024; // Create the first stack map (and its Dex register map). stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); @@ -609,7 +609,7 @@ TEST(StackMapTest, DexRegisterMapOffsetOverflow) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -648,10 +648,10 @@ TEST(StackMapTest, DexRegisterMapOffsetOverflow) { TEST(StackMapTest, TestShareDexRegisterMap) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; // First stack map. stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); @@ -670,7 +670,7 @@ TEST(StackMapTest, TestShareDexRegisterMap) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -706,10 +706,10 @@ TEST(StackMapTest, TestShareDexRegisterMap) { TEST(StackMapTest, TestNoDexRegisterMap) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 0; stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); stream.EndStackMapEntry(); @@ -719,7 +719,7 @@ TEST(StackMapTest, TestNoDexRegisterMap) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -755,11 +755,11 @@ TEST(StackMapTest, TestNoDexRegisterMap) { TEST(StackMapTest, InlineTest) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); ArtMethod art_method; - ArenaBitVector sp_mask1(&arena, 0, true); + ArenaBitVector sp_mask1(&allocator, 0, true); sp_mask1.SetBit(2); sp_mask1.SetBit(4); @@ -821,7 +821,7 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -936,10 +936,10 @@ TEST(StackMapTest, CodeOffsetTest) { TEST(StackMapTest, TestDeduplicateStackMask) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, true); + ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); sp_mask.SetBit(4); stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0); @@ -948,7 +948,7 @@ TEST(StackMapTest, TestDeduplicateStackMask) { stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); - void* memory = arena.Alloc(size, kArenaAllocMisc); + void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); stream.FillInCodeInfo(region); @@ -964,10 +964,10 @@ TEST(StackMapTest, TestDeduplicateStackMask) { TEST(StackMapTest, TestInvokeInfo) { ArenaPool pool; - ArenaAllocator arena(&pool); - StackMapStream stream(&arena, kRuntimeISA); + ArenaAllocator allocator(&pool); + StackMapStream stream(&allocator, kRuntimeISA); - ArenaBitVector sp_mask(&arena, 0, true); + ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0); stream.AddInvoke(kSuper, 1); @@ -980,11 +980,12 @@ TEST(StackMapTest, TestInvokeInfo) { stream.EndStackMapEntry(); const size_t code_info_size = stream.PrepareForFillIn(); - MemoryRegion code_info_region(arena.Alloc(code_info_size, kArenaAllocMisc), code_info_size); + MemoryRegion code_info_region(allocator.Alloc(code_info_size, kArenaAllocMisc), code_info_size); stream.FillInCodeInfo(code_info_region); const size_t method_info_size = stream.ComputeMethodInfoSize(); - MemoryRegion method_info_region(arena.Alloc(method_info_size, kArenaAllocMisc), method_info_size); + MemoryRegion method_info_region(allocator.Alloc(method_info_size, kArenaAllocMisc), + method_info_size); stream.FillInMethodInfo(method_info_region); CodeInfo code_info(code_info_region); |