Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Side by Side Diff: runtime/vm/flow_graph.cc

Issue 14682020: Optimize functions containing try-catch. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/flow_graph_allocator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.h" 5 #include "vm/flow_graph.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/flow_graph_builder.h" 8 #include "vm/flow_graph_builder.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 #include "vm/longjump.h" 10 #include "vm/longjump.h"
11 #include "vm/growable_array.h" 11 #include "vm/growable_array.h"
12 12
13 namespace dart { 13 namespace dart {
14 14
15 DECLARE_FLAG(bool, trace_optimization); 15 DECLARE_FLAG(bool, trace_optimization);
16 DECLARE_FLAG(bool, verify_compiler); 16 DECLARE_FLAG(bool, verify_compiler);
17 17
18 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
19 DEFINE_FLAG(bool, optimize_try_catch, false, "Optimization of try-catch");
20 #else
21 DEFINE_FLAG(bool, optimize_try_catch, true, "Optimization of try-catch");
22 #endif
23
18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, 24 FlowGraph::FlowGraph(const FlowGraphBuilder& builder,
19 GraphEntryInstr* graph_entry, 25 GraphEntryInstr* graph_entry,
20 intptr_t max_block_id) 26 intptr_t max_block_id)
21 : parent_(), 27 : parent_(),
22 current_ssa_temp_index_(0), 28 current_ssa_temp_index_(0),
23 max_block_id_(max_block_id), 29 max_block_id_(max_block_id),
24 parsed_function_(builder.parsed_function()), 30 parsed_function_(builder.parsed_function()),
25 num_copied_params_(builder.num_copied_params()), 31 num_copied_params_(builder.num_copied_params()),
26 num_non_copied_params_(builder.num_non_copied_params()), 32 num_non_copied_params_(builder.num_non_copied_params()),
27 num_stack_locals_(builder.num_stack_locals()), 33 num_stack_locals_(builder.num_stack_locals()),
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 // have new assigned values flowing out of that block. 327 // have new assigned values flowing out of that block.
322 const GrowableArray<BitVector*>& ComputeAssignedVars() { 328 const GrowableArray<BitVector*>& ComputeAssignedVars() {
323 // We can't directly return kill_ because it uses postorder numbering while 329 // We can't directly return kill_ because it uses postorder numbering while
324 // SSA construction uses preorder numbering internally. 330 // SSA construction uses preorder numbering internally.
325 // We have to permute postorder into preorder. 331 // We have to permute postorder into preorder.
326 assigned_vars_.Clear(); 332 assigned_vars_.Clear();
327 333
328 const intptr_t block_count = flow_graph_->preorder().length(); 334 const intptr_t block_count = flow_graph_->preorder().length();
329 for (intptr_t i = 0; i < block_count; i++) { 335 for (intptr_t i = 0; i < block_count; i++) {
330 BlockEntryInstr* block = flow_graph_->preorder()[i]; 336 BlockEntryInstr* block = flow_graph_->preorder()[i];
337 // All locals are assigned inside a try{} block.
338 // This is a safe approximation and workaround to force insertion of
339 // phis for stores that appear non-live because of the way catch-blocks
340 // are connected to the graph: They normally are dominated by the
341 // try-entry, but are direct successors of the graph entry in our flow
342 // graph.
343 // TODO(fschneider): Improve this approximation by better modeling the
344 // actual data flow to reduce the number of redundant phis.
331 BitVector* kill = GetKillSet(block); 345 BitVector* kill = GetKillSet(block);
332 kill->Intersect(GetLiveOutSet(block)); 346 if (block->InsideTryBlock()) {
347 kill->SetAll();
348 } else {
349 kill->Intersect(GetLiveOutSet(block));
350 }
333 assigned_vars_.Add(kill); 351 assigned_vars_.Add(kill);
334 } 352 }
335 353
336 return assigned_vars_; 354 return assigned_vars_;
337 } 355 }
338 356
339 // Returns true if the value set by the given store reaches any load from the 357 // Returns true if the value set by the given store reaches any load from the
340 // same local variable. 358 // same local variable.
341 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { 359 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) {
342 if (store->is_dead()) { 360 if (store->is_dead()) {
(...skipping 28 matching lines...) Expand all
371 const intptr_t block_count = postorder_.length(); 389 const intptr_t block_count = postorder_.length();
372 390
373 BitVector* last_loads = new BitVector(variable_count_); 391 BitVector* last_loads = new BitVector(variable_count_);
374 for (intptr_t i = 0; i < block_count; i++) { 392 for (intptr_t i = 0; i < block_count; i++) {
375 BlockEntryInstr* block = postorder_[i]; 393 BlockEntryInstr* block = postorder_[i];
376 394
377 BitVector* kill = kill_[i]; 395 BitVector* kill = kill_[i];
378 BitVector* live_in = live_in_[i]; 396 BitVector* live_in = live_in_[i];
379 last_loads->Clear(); 397 last_loads->Clear();
380 398
399 // There is an implicit use (load-local) of every local variable at each
400 // call inside a try{} block and every call has an implicit control-flow
401 // to the catch entry. As an approximation we mark all locals as live
402 // inside try{}.
403 // TODO(fschneider): Improve this approximation, since not all local
404 // variable stores actually reach a call.
405 if (block->InsideTryBlock()) {
406 live_in->SetAll();
407 continue;
408 }
409
381 // Iterate backwards starting at the last instruction. 410 // Iterate backwards starting at the last instruction.
382 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { 411 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) {
383 Instruction* current = it.Current(); 412 Instruction* current = it.Current();
384 413
385 LoadLocalInstr* load = current->AsLoadLocal(); 414 LoadLocalInstr* load = current->AsLoadLocal();
386 if (load != NULL) { 415 if (load != NULL) {
387 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); 416 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
388 live_in->Add(index); 417 live_in->Add(index);
389 if (!last_loads->Contains(index)) { 418 if (!last_loads->Contains(index)) {
390 last_loads->Add(index); 419 last_loads->Add(index);
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 } 639 }
611 } 640 }
612 } 641 }
613 } 642 }
614 } 643 }
615 644
616 645
617 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, 646 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
618 VariableLivenessAnalysis* variable_liveness, 647 VariableLivenessAnalysis* variable_liveness,
619 ZoneGrowableArray<Definition*>* inlining_parameters) { 648 ZoneGrowableArray<Definition*>* inlining_parameters) {
620 // TODO(fschneider): Support catch-entry. 649 if (!FLAG_optimize_try_catch && (graph_entry_->SuccessorCount() > 1)) {
621 if (graph_entry_->SuccessorCount() > 1) {
622 Bailout("Catch-entry support in SSA."); 650 Bailout("Catch-entry support in SSA.");
623 } 651 }
624 652
625 // Initial renaming environment. 653 // Initial renaming environment.
626 GrowableArray<Definition*> env(variable_count()); 654 GrowableArray<Definition*> env(variable_count());
627 655
628 // Add global constants to the initial definitions. 656 // Add global constants to the initial definitions.
629 constant_null_ = GetConstant(Object::ZoneHandle()); 657 constant_null_ = GetConstant(Object::ZoneHandle());
630 658
631 // Add parameters to the initial definitions and renaming environment. 659 // Add parameters to the initial definitions and renaming environment.
(...skipping 14 matching lines...) Expand all
646 AddToInitialDefinitions(param); 674 AddToInitialDefinitions(param);
647 env.Add(param); 675 env.Add(param);
648 } 676 }
649 } 677 }
650 678
651 // Initialize all locals with #null in the renaming environment. 679 // Initialize all locals with #null in the renaming environment.
652 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { 680 for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
653 env.Add(constant_null()); 681 env.Add(constant_null());
654 } 682 }
655 683
656 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0); 684 if (graph_entry_->SuccessorCount() > 1) {
657 ASSERT(normal_entry != NULL); // Must have entry. 685 // Functions with try-catch have a fixed area of stack slots reserved
658 RenameRecursive(normal_entry, &env, live_phis, variable_liveness); 686 // so that all local variables are stored at a known location when
687 // on entry to the catch.
688 graph_entry_->set_fixed_slot_count(
689 num_stack_locals() + num_copied_params());
690 }
691 RenameRecursive(graph_entry_, &env, live_phis, variable_liveness);
659 } 692 }
660 693
661 694
662 void FlowGraph::AttachEnvironment(Instruction* instr, 695 void FlowGraph::AttachEnvironment(Instruction* instr,
663 GrowableArray<Definition*>* env) { 696 GrowableArray<Definition*>* env) {
664 Environment* deopt_env = 697 Environment* deopt_env =
665 Environment::From(*env, 698 Environment::From(*env,
666 num_non_copied_params_, 699 num_non_copied_params_,
667 parsed_function_.function()); 700 parsed_function_.function());
668 instr->SetEnvironment(deopt_env); 701 instr->SetEnvironment(deopt_env);
(...skipping 13 matching lines...) Expand all
682 VariableLivenessAnalysis* variable_liveness) { 715 VariableLivenessAnalysis* variable_liveness) {
683 // 1. Process phis first. 716 // 1. Process phis first.
684 if (block_entry->IsJoinEntry()) { 717 if (block_entry->IsJoinEntry()) {
685 JoinEntryInstr* join = block_entry->AsJoinEntry(); 718 JoinEntryInstr* join = block_entry->AsJoinEntry();
686 if (join->phis() != NULL) { 719 if (join->phis() != NULL) {
687 for (intptr_t i = 0; i < join->phis()->length(); ++i) { 720 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
688 PhiInstr* phi = (*join->phis())[i]; 721 PhiInstr* phi = (*join->phis())[i];
689 if (phi != NULL) { 722 if (phi != NULL) {
690 (*env)[i] = phi; 723 (*env)[i] = phi;
691 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. 724 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
725 if (block_entry->InsideTryBlock()) {
726 // This is a safe approximation. Inside try{} all locals are
727 // used at every call implicitly, so we mark all phis as live
728 // from the start.
729 // TODO(fschneider): Improve this approximation to eliminate
730 // more redundant phis.
731 phi->mark_alive();
732 live_phis->Add(phi);
733 }
692 } 734 }
693 } 735 }
694 } 736 }
737 } else if (block_entry->IsCatchBlockEntry()) {
738 // Add real definitions for all locals and parameters.
739 for (intptr_t i = 0; i < env->length(); ++i) {
740 ParameterInstr* param = new ParameterInstr(i, block_entry);
741 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
742 (*env)[i] = param;
743 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param);
744 }
695 } 745 }
696 746
697 // Attach environment to the block entry. 747 // Attach environment to the block entry.
698 AttachEnvironment(block_entry, env); 748 AttachEnvironment(block_entry, env);
699 749
700 // 2. Process normal instructions. 750 // 2. Process normal instructions.
701 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { 751 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
702 Instruction* current = it.Current(); 752 Instruction* current = it.Current();
703 753
704 // Attach current environment to the instructions that need it. 754 // Attach current environment to the instructions that need it.
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after
1057 } 1107 }
1058 1108
1059 1109
1060 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, 1110 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from,
1061 BlockEntryInstr* to) const { 1111 BlockEntryInstr* to) const {
1062 return available_at_[to->postorder_number()]->Contains( 1112 return available_at_[to->postorder_number()]->Contains(
1063 from->postorder_number()); 1113 from->postorder_number());
1064 } 1114 }
1065 1115
1066 } // namespace dart 1116 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/flow_graph_allocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698