Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "vm/ast_printer.h" | 7 #include "vm/ast_printer.h" |
| 8 #include "vm/bit_vector.h" | |
| 8 #include "vm/code_descriptors.h" | 9 #include "vm/code_descriptors.h" |
| 9 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 10 #include "vm/flags.h" | 11 #include "vm/flags.h" |
| 11 #include "vm/intermediate_language.h" | 12 #include "vm/intermediate_language.h" |
| 12 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 13 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 14 #include "vm/os.h" | 15 #include "vm/os.h" |
| 15 #include "vm/parser.h" | 16 #include "vm/parser.h" |
| 16 #include "vm/resolver.h" | 17 #include "vm/resolver.h" |
| 17 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 18 | 19 |
| 19 namespace dart { | 20 namespace dart { |
| 20 | 21 |
| 21 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 22 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 22 DECLARE_FLAG(bool, enable_type_checks); | 23 DECLARE_FLAG(bool, enable_type_checks); |
| 23 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 24 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
| 24 | 25 |
| 25 | 26 |
| 26 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) | 27 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) |
| 27 : parsed_function_(parsed_function), | 28 : parsed_function_(parsed_function), |
| 28 preorder_block_entries_(), | 29 preorder_block_entries_(), |
| 29 postorder_block_entries_(), | 30 postorder_block_entries_(), |
| 30 context_level_(0), | 31 context_level_(0), |
| 31 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), | 32 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 32 try_index_(CatchClauseNode::kInvalidTryIndex), | 33 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 33 catch_entries_() {} | 34 catch_entries_() { } |
| 34 | 35 |
| 35 | 36 |
| 36 void FlowGraphBuilder::AddCatchEntry(intptr_t try_index, Instruction* entry) { | 37 void FlowGraphBuilder::AddCatchEntry(intptr_t try_index, Instruction* entry) { |
| 37 catch_entries_.Add(entry); | 38 catch_entries_.Add(entry); |
| 38 } | 39 } |
| 39 | 40 |
| 40 | 41 |
| 41 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { | 42 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| 42 ASSERT(is_open()); | 43 ASSERT(is_open()); |
| 43 if (other_fragment.is_empty()) return; | 44 if (other_fragment.is_empty()) return; |
| (...skipping 2440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2484 Isolate* isolate = Isolate::Current(); | 2485 Isolate* isolate = Isolate::Current(); |
| 2485 const intptr_t prev_cid = isolate->computation_id(); | 2486 const intptr_t prev_cid = isolate->computation_id(); |
| 2486 isolate->set_computation_id(0); | 2487 isolate->set_computation_id(0); |
| 2487 const Function& function = parsed_function().function(); | 2488 const Function& function = parsed_function().function(); |
| 2488 EffectGraphVisitor for_effect(this, 0); | 2489 EffectGraphVisitor for_effect(this, 0); |
| 2489 for_effect.AddInstruction(new TargetEntryInstr()); | 2490 for_effect.AddInstruction(new TargetEntryInstr()); |
| 2490 parsed_function().node_sequence()->Visit(&for_effect); | 2491 parsed_function().node_sequence()->Visit(&for_effect); |
| 2491 // Check that the graph is properly terminated. | 2492 // Check that the graph is properly terminated. |
| 2492 ASSERT(!for_effect.is_open()); | 2493 ASSERT(!for_effect.is_open()); |
| 2493 GrowableArray<intptr_t> parent; | 2494 GrowableArray<intptr_t> parent; |
| 2495 GrowableArray<BitVector*> assigned_vars; | |
| 2496 intptr_t variable_count = parsed_function_.function().num_fixed_parameters() + | |
| 2497 parsed_function_.copied_parameter_count() + | |
| 2498 parsed_function_.stack_local_count(); | |
| 2499 GrowableArray<BitVector*> dominance_frontier; | |
| 2494 for (intptr_t i = 0; i < catch_entries_.length(); i++) { | 2500 for (intptr_t i = 0; i < catch_entries_.length(); i++) { |
| 2495 Instruction* entry = catch_entries_[i]; | 2501 Instruction* entry = catch_entries_[i]; |
| 2496 entry->DiscoverBlocks(NULL, // Entry block predecessor. | 2502 entry->DiscoverBlocks(NULL, // Entry block predecessor. |
| 2497 &preorder_block_entries_, | 2503 &preorder_block_entries_, |
| 2498 &postorder_block_entries_, | 2504 &postorder_block_entries_, |
| 2499 &parent); | 2505 &parent, |
| 2506 &assigned_vars, | |
| 2507 variable_count); | |
| 2500 if (for_optimized) { | 2508 if (for_optimized) { |
| 2501 ComputeDominators(&preorder_block_entries_, &parent); | 2509 ComputeDominators(&preorder_block_entries_, &parent, &dominance_frontier); |
| 2502 } | 2510 } |
| 2503 } | 2511 } |
| 2504 if (for_effect.entry() != NULL) { | 2512 if (for_effect.entry() != NULL) { |
| 2505 // Perform a depth-first traversal of the graph to build preorder and | 2513 // Perform a depth-first traversal of the graph to build preorder and |
| 2506 // postorder block orders. | 2514 // postorder block orders. |
| 2507 for_effect.entry()->DiscoverBlocks(NULL, // Entry block predecessor. | 2515 for_effect.entry()->DiscoverBlocks(NULL, // Entry block predecessor. |
| 2508 &preorder_block_entries_, | 2516 &preorder_block_entries_, |
| 2509 &postorder_block_entries_, | 2517 &postorder_block_entries_, |
| 2510 &parent); | 2518 &parent, |
| 2519 &assigned_vars, | |
| 2520 variable_count); | |
| 2511 if (for_optimized) { | 2521 if (for_optimized) { |
| 2512 ComputeDominators(&preorder_block_entries_, &parent); | 2522 ComputeDominators(&preorder_block_entries_, &parent, &dominance_frontier); |
| 2513 } | 2523 } |
| 2514 } | 2524 } |
| 2515 isolate->set_computation_id(prev_cid); | 2525 isolate->set_computation_id(prev_cid); |
| 2516 if (FLAG_print_flow_graph) { | 2526 if (FLAG_print_flow_graph) { |
| 2517 intptr_t length = postorder_block_entries_.length(); | 2527 intptr_t length = postorder_block_entries_.length(); |
| 2518 GrowableArray<BlockEntryInstr*> reverse_postorder(length); | 2528 GrowableArray<BlockEntryInstr*> reverse_postorder(length); |
| 2519 for (intptr_t i = length - 1; i >= 0; --i) { | 2529 for (intptr_t i = length - 1; i >= 0; --i) { |
| 2520 reverse_postorder.Add(postorder_block_entries_[i]); | 2530 reverse_postorder.Add(postorder_block_entries_[i]); |
| 2521 } | 2531 } |
| 2522 FlowGraphPrinter printer(function, reverse_postorder); | 2532 FlowGraphPrinter printer(function, reverse_postorder); |
| 2523 printer.VisitBlocks(); | 2533 printer.VisitBlocks(); |
| 2524 } | 2534 } |
| 2525 } | 2535 } |
| 2526 | 2536 |
| 2527 | 2537 |
| 2528 void FlowGraphBuilder::ComputeDominators( | 2538 void FlowGraphBuilder::ComputeDominators( |
| 2529 GrowableArray<BlockEntryInstr*>* preorder, | 2539 GrowableArray<BlockEntryInstr*>* preorder, |
| 2530 GrowableArray<intptr_t>* parent) { | 2540 GrowableArray<intptr_t>* parent, |
| 2541 GrowableArray<BitVector*>* dominance_frontier) { | |
|
srdjan
2012/05/12 00:00:55
Maybe add in comment what is the content of parent
Kevin Millikin (Google)
2012/05/15 11:51:44
Done.
| |
| 2531 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass | 2542 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass |
| 2532 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) | 2543 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) |
| 2533 // that eliminates a pass by using nearest-common ancestor (NCA) to | 2544 // that eliminates a pass by using nearest-common ancestor (NCA) to |
| 2534 // compute immediate dominators from semidominators. It also removes a | 2545 // compute immediate dominators from semidominators. It also removes a |
| 2535 // level of indirection in the link-eval forest data structure. | 2546 // level of indirection in the link-eval forest data structure. |
| 2536 // | 2547 // |
| 2537 // The algorithm is described in Georgiadis, Tarjan, and Werneck's | 2548 // The algorithm is described in Georgiadis, Tarjan, and Werneck's |
| 2538 // "Finding Dominators in Practice". | 2549 // "Finding Dominators in Practice". |
| 2539 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . | 2550 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . |
| 2540 | 2551 |
| 2541 // All arrays are maps between preorder basic-block numbers. | 2552 // All arrays are maps between preorder basic-block numbers. |
| 2542 intptr_t size = parent->length(); | 2553 intptr_t size = parent->length(); |
| 2543 GrowableArray<intptr_t> idom(size); // Immediate dominator. | 2554 GrowableArray<intptr_t> idom(size); // Immediate dominator. |
| 2544 GrowableArray<intptr_t> semi(size); // Semidominator. | 2555 GrowableArray<intptr_t> semi(size); // Semidominator. |
| 2545 GrowableArray<intptr_t> label(size); // Label for link-eval forest. | 2556 GrowableArray<intptr_t> label(size); // Label for link-eval forest. |
| 2546 | 2557 |
| 2547 // 1. First pass: compute semidominators as in Lengauer-Tarjan. | 2558 // 1. First pass: compute semidominators as in Lengauer-Tarjan. |
| 2548 // Semidominators are computed from a depth-first spanning tree and are an | 2559 // Semidominators are computed from a depth-first spanning tree and are an |
| 2549 // approximation of immediate dominators. | 2560 // approximation of immediate dominators. |
| 2550 | 2561 |
| 2551 // Use a link-eval data structure with path compression. Implement path | 2562 // Use a link-eval data structure with path compression. Implement path |
| 2552 // compression in place by mutating the parent array. Each block has a | 2563 // compression in place by mutating the parent array. Each block has a |
| 2553 // label, which is the minimum block number on the compressed path. | 2564 // label, which is the minimum block number on the compressed path. |
| 2554 | 2565 |
| 2555 // Initialize idom, semi, and label. | 2566 // Initialize idom, semi, and label used by SEMI-NCA. Initialize the |
| 2567 // dominance frontier output array. | |
| 2556 for (intptr_t i = 0; i < size; ++i) { | 2568 for (intptr_t i = 0; i < size; ++i) { |
| 2557 idom.Add((*parent)[i]); | 2569 idom.Add((*parent)[i]); |
| 2558 semi.Add(i); | 2570 semi.Add(i); |
| 2559 label.Add(i); | 2571 label.Add(i); |
| 2572 dominance_frontier->Add(new BitVector(size, | |
| 2573 Isolate::Current()->current_zone())); | |
|
Florian Schneider
2012/05/11 13:19:37
Maybe it would be useful to have a Zone* zone_ sto
srdjan
2012/05/12 00:00:55
That would premature optimization, IMHO. At some p
Kevin Millikin (Google)
2012/05/15 11:51:44
I've eliminated the parameter, but I disagree that
srdjan
2012/05/15 22:05:32
In the VM we do not pass isolates/zones for perfor
| |
| 2560 } | 2574 } |
| 2561 | 2575 |
| 2562 // Loop over the blocks in reverse preorder (not including the graph | 2576 // Loop over the blocks in reverse preorder (not including the graph |
| 2563 // entry). | 2577 // entry). |
| 2564 for (intptr_t block_index = size - 1; block_index >= 1; --block_index) { | 2578 for (intptr_t block_index = size - 1; block_index >= 1; --block_index) { |
| 2565 // Loop over the predecessors. | 2579 // Loop over the predecessors. |
| 2566 BlockEntryInstr* block = (*preorder)[block_index]; | 2580 BlockEntryInstr* block = (*preorder)[block_index]; |
| 2567 for (intptr_t i = 0; i < block->PredecessorCount(); ++i) { | 2581 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { |
| 2568 BlockEntryInstr* pred = block->PredecessorAt(i); | 2582 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 2569 ASSERT(pred != NULL); | 2583 ASSERT(pred != NULL); |
| 2570 | 2584 |
| 2571 // Look for the semidominator by ascending the semidominator path | 2585 // Look for the semidominator by ascending the semidominator path |
| 2572 // starting from pred. | 2586 // starting from pred. |
| 2573 intptr_t pred_index = pred->preorder_number(); | 2587 intptr_t pred_index = pred->preorder_number(); |
| 2574 intptr_t best = pred_index; | 2588 intptr_t best = pred_index; |
| 2575 if (pred_index > block_index) { | 2589 if (pred_index > block_index) { |
| 2576 CompressPath(block_index, pred_index, parent, &label); | 2590 CompressPath(block_index, pred_index, parent, &label); |
| 2577 best = label[pred_index]; | 2591 best = label[pred_index]; |
| 2578 } | 2592 } |
| 2579 | 2593 |
| 2580 // Update the semidominator if we've found a better one. | 2594 // Update the semidominator if we've found a better one. |
| 2581 semi[block_index] = Utils::Minimum(semi[block_index], semi[best]); | 2595 semi[block_index] = Utils::Minimum(semi[block_index], semi[best]); |
| 2582 } | 2596 } |
| 2583 | 2597 |
| 2584 // Now use label for the semidominator. | 2598 // Now use label for the semidominator. |
| 2585 label[block_index] = semi[block_index]; | 2599 label[block_index] = semi[block_index]; |
| 2586 } | 2600 } |
| 2587 | 2601 |
| 2588 // 2. Compute the immediate dominators as the nearest common ancestor of | 2602 // 2. Compute the immediate dominators as the nearest common ancestor of |
| 2589 // spanning tree parent and semidominator, for all nodes except the entry. | 2603 // spanning tree parent and semidominator, for all blocks except the entry. |
| 2590 for (intptr_t block_index = 1; block_index < size; ++block_index) { | 2604 for (intptr_t block_index = 1; block_index < size; ++block_index) { |
| 2591 intptr_t dom_index = idom[block_index]; | 2605 intptr_t dom_index = idom[block_index]; |
| 2592 while (dom_index > semi[block_index]) { | 2606 while (dom_index > semi[block_index]) { |
| 2593 dom_index = idom[dom_index]; | 2607 dom_index = idom[dom_index]; |
| 2594 } | 2608 } |
| 2595 idom[block_index] = dom_index; | 2609 idom[block_index] = dom_index; |
| 2596 (*preorder)[block_index]->set_dominator((*preorder)[dom_index]); | 2610 (*preorder)[block_index]->set_dominator((*preorder)[dom_index]); |
| 2597 } | 2611 } |
| 2612 | |
| 2613 // 3. Compute the dominance frontier for all blocks. This is algorithm in | |
| 2614 // "A Simple, Fast Dominance Algorithm" (Figure 5), which is attributed to | |
| 2615 // a paper by Ferrante et al. There is no bookkeeping required to avoid | |
| 2616 // adding a block twice to the same block's dominance frontier because we | |
| 2617 // use a set to represent the dominance frontier. | |
| 2618 for (intptr_t block_index = 0; block_index < size; ++block_index) { | |
| 2619 BlockEntryInstr* block = (*preorder)[block_index]; | |
| 2620 intptr_t count = block->PredecessorCount(); | |
| 2621 if (count <= 1) continue; | |
| 2622 for (intptr_t i = 0; i < count; ++i) { | |
| 2623 BlockEntryInstr* runner = block->PredecessorAt(i); | |
| 2624 while (runner != block->dominator()) { | |
| 2625 (*dominance_frontier)[runner->preorder_number()]->Add(block_index); | |
| 2626 runner = runner->dominator(); | |
| 2627 } | |
| 2628 } | |
| 2629 } | |
| 2598 } | 2630 } |
| 2599 | 2631 |
| 2600 | 2632 |
| 2601 void FlowGraphBuilder::CompressPath(intptr_t start_index, | 2633 void FlowGraphBuilder::CompressPath(intptr_t start_index, |
| 2602 intptr_t current_index, | 2634 intptr_t current_index, |
| 2603 GrowableArray<intptr_t>* parent, | 2635 GrowableArray<intptr_t>* parent, |
| 2604 GrowableArray<intptr_t>* label) { | 2636 GrowableArray<intptr_t>* label) { |
| 2605 intptr_t next_index = (*parent)[current_index]; | 2637 intptr_t next_index = (*parent)[current_index]; |
| 2606 if (next_index > start_index) { | 2638 if (next_index > start_index) { |
| 2607 CompressPath(start_index, next_index, parent, label); | 2639 CompressPath(start_index, next_index, parent, label); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2619 char* chars = reinterpret_cast<char*>( | 2651 char* chars = reinterpret_cast<char*>( |
| 2620 Isolate::Current()->current_zone()->Allocate(len)); | 2652 Isolate::Current()->current_zone()->Allocate(len)); |
| 2621 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2653 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2622 const Error& error = Error::Handle( | 2654 const Error& error = Error::Handle( |
| 2623 LanguageError::New(String::Handle(String::New(chars)))); | 2655 LanguageError::New(String::Handle(String::New(chars)))); |
| 2624 Isolate::Current()->long_jump_base()->Jump(1, error); | 2656 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2625 } | 2657 } |
| 2626 | 2658 |
| 2627 | 2659 |
| 2628 } // namespace dart | 2660 } // namespace dart |
| OLD | NEW |