void MIRGraph::SSATransformationStart() {
DCHECK(temp_scoped_alloc_.get() == nullptr);
temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
- temp_bit_vector_size_ = cu_->num_dalvik_registers;
+ temp_bit_vector_size_ = GetNumOfCodeAndTempVRs();
temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapRegisterV);
-
- // Update the maximum number of reachable blocks.
- max_num_reachable_blocks_ = num_reachable_blocks_;
}
void MIRGraph::SSATransformationEnd() {
temp_bit_vector_ = nullptr;
DCHECK(temp_scoped_alloc_.get() != nullptr);
temp_scoped_alloc_.reset();
+
+ // Update the maximum number of reachable blocks.
+ max_num_reachable_blocks_ = num_reachable_blocks_;
}
-void MIRGraph::ComputeTopologicalSortOrder() {
- std::queue<BasicBlock*> q;
- std::map<int, int> visited_cnt_values;
-
- // Clear the nodes.
- ClearAllVisitedFlags();
+size_t MIRGraph::GetNumDalvikInsns() const {
+ size_t cumulative_size = 0u;
+ bool counted_current_item = false;
+ const uint8_t size_for_null_code_item = 2u;
+
+ for (auto it : m_units_) {
+ const DexFile::CodeItem* code_item = it->GetCodeItem();
+ // Even if the code item is null, we still count non-zero value so that
+ // each m_unit is counted as having impact.
+ cumulative_size += (code_item == nullptr ?
+ size_for_null_code_item : code_item->insns_size_in_code_units_);
+ if (code_item == current_code_item_) {
+ counted_current_item = true;
+ }
+ }
- // Create the topological order if need be.
- if (topological_order_ != nullptr) {
- topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, 0);
+ // If the current code item was not counted yet, count it now.
+ // This can happen for example in unit tests where some fields like m_units_
+ // are not initialized.
+ if (counted_current_item == false) {
+ cumulative_size += (current_code_item_ == nullptr ?
+ size_for_null_code_item : current_code_item_->insns_size_in_code_units_);
}
- topological_order_->Reset();
- // Set up visitedCntValues map for all BB. The default value for this counters in the map is zero.
- // also fill initial queue.
- GrowableArray<BasicBlock*>::Iterator iterator(&block_list_);
+ return cumulative_size;
+}
- while (true) {
- BasicBlock* bb = iterator.Next();
+static BasicBlock* SelectTopologicalSortOrderFallBack(
+ MIRGraph* mir_graph, const ArenaBitVector* current_loop,
+ const ScopedArenaVector<size_t>* visited_cnt_values, ScopedArenaAllocator* allocator,
+ ScopedArenaVector<BasicBlockId>* tmp_stack) {
+ // No true loop head has been found but there may be true loop heads after the mess we need
+ // to resolve. To avoid taking one of those, pick the candidate with the highest number of
+ // reachable unvisited nodes. That candidate will surely be a part of a loop.
+ BasicBlock* fall_back = nullptr;
+ size_t fall_back_num_reachable = 0u;
+ // Reuse the same bit vector for each candidate to mark reachable unvisited blocks.
+ ArenaBitVector candidate_reachable(allocator, mir_graph->GetNumBlocks(), false, kBitMapMisc);
+ AllNodesIterator iter(mir_graph);
+ for (BasicBlock* candidate = iter.Next(); candidate != nullptr; candidate = iter.Next()) {
+ if (candidate->hidden || // Hidden, or
+ candidate->visited || // already processed, or
+ (*visited_cnt_values)[candidate->id] == 0u || // no processed predecessors, or
+ (current_loop != nullptr && // outside current loop.
+ !current_loop->IsBitSet(candidate->id))) {
+ continue;
+ }
+ DCHECK(tmp_stack->empty());
+ tmp_stack->push_back(candidate->id);
+ candidate_reachable.ClearAllBits();
+ size_t num_reachable = 0u;
+ while (!tmp_stack->empty()) {
+ BasicBlockId current_id = tmp_stack->back();
+ tmp_stack->pop_back();
+ BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id);
+ DCHECK(current_bb != nullptr);
+ ChildBlockIterator child_iter(current_bb, mir_graph);
+ BasicBlock* child_bb = child_iter.Next();
+ for ( ; child_bb != nullptr; child_bb = child_iter.Next()) {
+ DCHECK(!child_bb->hidden);
+ if (child_bb->visited || // Already processed, or
+ (current_loop != nullptr && // outside current loop.
+ !current_loop->IsBitSet(child_bb->id))) {
+ continue;
+ }
+ if (!candidate_reachable.IsBitSet(child_bb->id)) {
+ candidate_reachable.SetBit(child_bb->id);
+ tmp_stack->push_back(child_bb->id);
+ num_reachable += 1u;
+ }
+ }
+ }
+ if (fall_back_num_reachable < num_reachable) {
+ fall_back_num_reachable = num_reachable;
+ fall_back = candidate;
+ }
+ }
+ return fall_back;
+}
- if (bb == nullptr) {
- break;
+// Compute from which unvisited blocks is bb_id reachable through unvisited blocks.
+static void ComputeUnvisitedReachableFrom(MIRGraph* mir_graph, BasicBlockId bb_id,
+ ArenaBitVector* reachable,
+ ScopedArenaVector<BasicBlockId>* tmp_stack) {
+ // NOTE: Loop heads indicated by the "visited" flag.
+ DCHECK(tmp_stack->empty());
+ reachable->ClearAllBits();
+ tmp_stack->push_back(bb_id);
+ while (!tmp_stack->empty()) {
+ BasicBlockId current_id = tmp_stack->back();
+ tmp_stack->pop_back();
+ BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id);
+ DCHECK(current_bb != nullptr);
+ for (BasicBlockId pred_id : current_bb->predecessors) {
+ BasicBlock* pred_bb = mir_graph->GetBasicBlock(pred_id);
+ DCHECK(pred_bb != nullptr);
+ if (!pred_bb->visited && !reachable->IsBitSet(pred_bb->id)) {
+ reachable->SetBit(pred_bb->id);
+ tmp_stack->push_back(pred_bb->id);
+ }
}
+ }
+}
+void MIRGraph::ComputeTopologicalSortOrder() {
+ ScopedArenaAllocator allocator(&cu_->arena_stack);
+ unsigned int num_blocks = GetNumBlocks();
+
+ ScopedArenaQueue<BasicBlock*> q(allocator.Adapter());
+ ScopedArenaVector<size_t> visited_cnt_values(num_blocks, 0u, allocator.Adapter());
+ ScopedArenaVector<BasicBlockId> loop_head_stack(allocator.Adapter());
+ size_t max_nested_loops = 0u;
+ ArenaBitVector loop_exit_blocks(&allocator, num_blocks, false, kBitMapMisc);
+ loop_exit_blocks.ClearAllBits();
+
+ // Count the number of blocks to process and add the entry block(s).
+ unsigned int num_blocks_to_process = 0u;
+ for (BasicBlock* bb : block_list_) {
if (bb->hidden == true) {
continue;
}