summaryrefslogtreecommitdiff
path: root/compiler/dex/mir_graph.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/mir_graph.cc')
-rw-r--r--compiler/dex/mir_graph.cc102
1 files changed, 64 insertions, 38 deletions
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 63a55707e5..baa46d61bd 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -27,6 +27,7 @@
#include "dex/quick/dex_file_method_inliner.h"
#include "leb128.h"
#include "pass_driver_me_post_opt.h"
+#include "utils/scoped_arena_containers.h"
namespace art {
@@ -1437,22 +1438,24 @@ void MIRGraph::SSATransformationEnd() {
}
void MIRGraph::ComputeTopologicalSortOrder() {
- std::queue<BasicBlock*> q;
- std::map<int, int> visited_cnt_values;
-
// Clear the nodes.
ClearAllVisitedFlags();
// Create the topological order if need be.
- if (topological_order_ != nullptr) {
- topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, 0);
+ if (topological_order_ == nullptr) {
+ topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, GetNumBlocks());
}
topological_order_->Reset();
+ ScopedArenaAllocator allocator(&cu_->arena_stack);
+ ScopedArenaQueue<BasicBlock*> q(allocator.Adapter());
+ ScopedArenaVector<size_t> visited_cnt_values(GetNumBlocks(), 0u, allocator.Adapter());
+
// 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_);
+ size_t num_blocks = 0u;
while (true) {
BasicBlock* bb = iterator.Next();
@@ -1464,7 +1467,8 @@ void MIRGraph::ComputeTopologicalSortOrder() {
continue;
}
- visited_cnt_values[bb->id] = bb->predecessors->Size();
+ num_blocks += 1u;
+ size_t unvisited_predecessor_count = bb->predecessors->Size();
GrowableArray<BasicBlockId>::Iterator pred_iterator(bb->predecessors);
// To process loops we should not wait for dominators.
@@ -1475,53 +1479,75 @@ void MIRGraph::ComputeTopologicalSortOrder() {
break;
}
- if (pred_bb->dominators == nullptr || pred_bb->hidden == true) {
- continue;
- }
-
- // Skip the backward branch.
- if (pred_bb->dominators->IsBitSet(bb->id) != 0) {
- visited_cnt_values[bb->id]--;
+ // Skip the backward branch or hidden predecessor.
+ if (pred_bb->hidden ||
+ (pred_bb->dominators != nullptr && pred_bb->dominators->IsBitSet(bb->id))) {
+ unvisited_predecessor_count -= 1u;
}
}
+ visited_cnt_values[bb->id] = unvisited_predecessor_count;
+
// Add entry block to queue.
- if (visited_cnt_values[bb->id] == 0) {
+ if (unvisited_predecessor_count == 0) {
q.push(bb);
}
}
- while (q.size() > 0) {
- // Get top.
- BasicBlock* bb = q.front();
- q.pop();
+ // We can theoretically get a cycle where none of the blocks dominates the other. Therefore
+ // don't stop when the queue is empty, continue until we've processed all the blocks.
+ // (In practice, we've seen this for a monitor-exit catch handler that erroneously tries to
+ // handle its own exceptions being broken into two blocks by a jump to to the monitor-exit
+ // from another catch hanler. http://b/15745363 .)
+ AllNodesIterator candidate_iter(this); // For the empty queue case.
+ while (num_blocks != 0u) {
+ num_blocks -= 1u;
+ BasicBlock* bb = nullptr;
+ if (!q.empty()) {
+ // Get top.
+ bb = q.front();
+ q.pop();
+ } else {
+ // Find some block we didn't visit yet that has at least one visited predecessor.
+ while (bb == nullptr) {
+ BasicBlock* candidate = candidate_iter.Next();
+ DCHECK(candidate != nullptr);
+ if (candidate->visited || candidate->hidden) {
+ continue;
+ }
+ GrowableArray<BasicBlockId>::Iterator iter(candidate->predecessors);
+ for (BasicBlock* pred_bb = GetBasicBlock(iter.Next()); pred_bb != nullptr;
+ pred_bb = GetBasicBlock(iter.Next())) {
+ if (!pred_bb->hidden && pred_bb->visited) {
+ bb = candidate;
+ break;
+ }
+ }
+ }
+ }
DCHECK_EQ(bb->hidden, false);
-
- if (bb->IsExceptionBlock() == true) {
- continue;
- }
+ DCHECK_EQ(bb->visited, false);
// We've visited all the predecessors. So, we can visit bb.
- if (bb->visited == false) {
- bb->visited = true;
+ bb->visited = true;
- // Now add the basic block.
- topological_order_->Insert(bb->id);
+ // Now add the basic block.
+ topological_order_->Insert(bb->id);
- // Reduce visitedCnt for all the successors and add into the queue ones with visitedCnt equals to zero.
- ChildBlockIterator succIter(bb, this);
- BasicBlock* successor = succIter.Next();
- while (successor != nullptr) {
- // one more predecessor was visited.
- visited_cnt_values[successor->id]--;
-
- if (visited_cnt_values[successor->id] <= 0 && successor->visited == false && successor->hidden == false) {
- q.push(successor);
- }
+ // Reduce visitedCnt for all the successors and add into the queue ones with visitedCnt equals to zero.
+ ChildBlockIterator succIter(bb, this);
+ BasicBlock* successor = succIter.Next();
+ for ( ; successor != nullptr; successor = succIter.Next()) {
+ if (successor->visited || successor->hidden) {
+ continue;
+ }
- // Take next successor.
- successor = succIter.Next();
+ // one more predecessor was visited.
+ DCHECK_NE(visited_cnt_values[successor->id], 0u);
+ visited_cnt_values[successor->id] -= 1u;
+ if (visited_cnt_values[successor->id] == 0u) {
+ q.push(successor);
}
}
}