| 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/code_descriptors.h" | 8 #include "vm/code_descriptors.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 "Eliminate type checks when allowed by static type analysis."); | 24 "Eliminate type checks when allowed by static type analysis."); |
| 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
| 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 27 DEFINE_FLAG(bool, print_flow_graph_optimized, false, | 27 DEFINE_FLAG(bool, print_flow_graph_optimized, false, |
| 28 "Print the IR flow graph when optimizing."); | 28 "Print the IR flow graph when optimizing."); |
| 29 DEFINE_FLAG(bool, trace_type_check_elimination, false, | 29 DEFINE_FLAG(bool, trace_type_check_elimination, false, |
| 30 "Trace type check elimination at compile time."); | 30 "Trace type check elimination at compile time."); |
| 31 DECLARE_FLAG(bool, enable_type_checks); | 31 DECLARE_FLAG(bool, enable_type_checks); |
| 32 | 32 |
| 33 | 33 |
| 34 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) | 34 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function, |
| 35 InliningContext* inlining_context) |
| 35 : parsed_function_(parsed_function), | 36 : parsed_function_(parsed_function), |
| 36 num_copied_params_(parsed_function.num_copied_params()), | 37 num_copied_params_(parsed_function.num_copied_params()), |
| 37 // All parameters are copied if any parameter is. | 38 // All parameters are copied if any parameter is. |
| 38 num_non_copied_params_((num_copied_params_ == 0) | 39 num_non_copied_params_((num_copied_params_ == 0) |
| 39 ? parsed_function.function().num_fixed_parameters() | 40 ? parsed_function.function().num_fixed_parameters() |
| 40 : 0), | 41 : 0), |
| 41 num_stack_locals_(parsed_function.num_stack_locals()), | 42 num_stack_locals_(parsed_function.num_stack_locals()), |
| 43 inlining_context_(inlining_context), |
| 42 last_used_block_id_(0), // 0 is used for the graph entry. | 44 last_used_block_id_(0), // 0 is used for the graph entry. |
| 43 context_level_(0), | 45 context_level_(0), |
| 44 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), | 46 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 45 try_index_(CatchClauseNode::kInvalidTryIndex), | 47 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 46 graph_entry_(NULL), | 48 graph_entry_(NULL) { } |
| 47 inlining_context_(kNotInlining), | |
| 48 exits_(NULL) { } | |
| 49 | 49 |
| 50 | 50 |
| 51 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) { | 51 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) { |
| 52 graph_entry_->AddCatchEntry(entry); | 52 graph_entry_->AddCatchEntry(entry); |
| 53 } | 53 } |
| 54 | 54 |
| 55 | 55 |
| 56 void ValueInliningContext::AddExit(ReturnInstr* exit) { |
| 57 Data data = { NULL, exit }; |
| 58 exits_.Add(data); |
| 59 } |
| 60 |
| 61 |
| 62 int ValueInliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { |
| 63 return (a->exit_block->block_id() - b->exit_block->block_id()); |
| 64 } |
| 65 |
| 66 |
| 67 void ValueInliningContext::SortExits() { |
| 68 // Assign block entries here because we did not necessarily know them when |
| 69 // the return exit was added to the array. |
| 70 for (int i = 0; i < exits_.length(); ++i) { |
| 71 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); |
| 72 } |
| 73 exits_.Sort(LowestBlockIdFirst); |
| 74 } |
| 75 |
| 76 |
| 56 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { | 77 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| 57 ASSERT(is_open()); | 78 ASSERT(is_open()); |
| 58 if (other_fragment.is_empty()) return; | 79 if (other_fragment.is_empty()) return; |
| 59 if (is_empty()) { | 80 if (is_empty()) { |
| 60 entry_ = other_fragment.entry(); | 81 entry_ = other_fragment.entry(); |
| 61 exit_ = other_fragment.exit(); | 82 exit_ = other_fragment.exit(); |
| 62 } else { | 83 } else { |
| 63 exit()->LinkTo(other_fragment.entry()); | 84 exit()->LinkTo(other_fragment.entry()); |
| 64 exit_ = other_fragment.exit(); | 85 exit_ = other_fragment.exit(); |
| 65 } | 86 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 DeallocateTempIndex(instruction->InputCount()); | 123 DeallocateTempIndex(instruction->InputCount()); |
| 103 if (is_empty()) { | 124 if (is_empty()) { |
| 104 entry_ = exit_ = instruction; | 125 entry_ = exit_ = instruction; |
| 105 } else { | 126 } else { |
| 106 exit()->LinkTo(instruction); | 127 exit()->LinkTo(instruction); |
| 107 exit_ = instruction; | 128 exit_ = instruction; |
| 108 } | 129 } |
| 109 } | 130 } |
| 110 | 131 |
| 111 | 132 |
| 133 void EffectGraphVisitor::AddReturnExit(intptr_t token_pos, Value* value) { |
| 134 ASSERT(is_open()); |
| 135 ReturnInstr* return_instr = new ReturnInstr(token_pos, value); |
| 136 AddInstruction(return_instr); |
| 137 InliningContext* inlining_context = owner()->inlining_context(); |
| 138 if (inlining_context != NULL) { |
| 139 inlining_context->AddExit(return_instr); |
| 140 } |
| 141 CloseFragment(); |
| 142 } |
| 143 |
| 144 |
| 112 void EffectGraphVisitor::Goto(JoinEntryInstr* join) { | 145 void EffectGraphVisitor::Goto(JoinEntryInstr* join) { |
| 113 ASSERT(is_open()); | 146 ASSERT(is_open()); |
| 114 if (is_empty()) { | 147 if (is_empty()) { |
| 115 entry_ = new GotoInstr(join); | 148 entry_ = new GotoInstr(join); |
| 116 } else { | 149 } else { |
| 117 exit()->Goto(join); | 150 exit()->Goto(join); |
| 118 } | 151 } |
| 119 exit_ = NULL; | 152 exit_ = NULL; |
| 120 } | 153 } |
| 121 | 154 |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 ASSERT(current_context_level >= 0); | 552 ASSERT(current_context_level >= 0); |
| 520 if (owner()->parsed_function().saved_context_var() != NULL) { | 553 if (owner()->parsed_function().saved_context_var() != NULL) { |
| 521 // CTX on entry was saved, but not linked as context parent. | 554 // CTX on entry was saved, but not linked as context parent. |
| 522 BuildLoadContext(*owner()->parsed_function().saved_context_var()); | 555 BuildLoadContext(*owner()->parsed_function().saved_context_var()); |
| 523 } else { | 556 } else { |
| 524 while (current_context_level-- > 0) { | 557 while (current_context_level-- > 0) { |
| 525 UnchainContext(); | 558 UnchainContext(); |
| 526 } | 559 } |
| 527 } | 560 } |
| 528 | 561 |
| 529 ReturnInstr* return_instr = new ReturnInstr(node->token_pos(), return_value); | 562 AddReturnExit(node->token_pos(), return_value); |
| 530 AddReturnExit(return_instr); | |
| 531 AddInstruction(return_instr); | |
| 532 CloseFragment(); | |
| 533 } | 563 } |
| 534 | 564 |
| 535 | 565 |
| 536 // <Expression> ::= Literal { literal: Instance } | 566 // <Expression> ::= Literal { literal: Instance } |
| 537 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) { | 567 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) { |
| 538 return; | 568 return; |
| 539 } | 569 } |
| 540 | 570 |
| 541 | 571 |
| 542 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { | 572 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { |
| (...skipping 2480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3023 for_finally_block.Goto(after_finally); | 3053 for_finally_block.Goto(after_finally); |
| 3024 for_finally_block.exit_ = after_finally; | 3054 for_finally_block.exit_ = after_finally; |
| 3025 } | 3055 } |
| 3026 | 3056 |
| 3027 Goto(finally_entry); | 3057 Goto(finally_entry); |
| 3028 AppendFragment(finally_entry, for_finally_block); | 3058 AppendFragment(finally_entry, for_finally_block); |
| 3029 exit_ = for_finally_block.exit_; | 3059 exit_ = for_finally_block.exit_; |
| 3030 } | 3060 } |
| 3031 | 3061 |
| 3032 | 3062 |
| 3033 FlowGraph* FlowGraphBuilder::BuildGraph(InliningContext context, | 3063 FlowGraph* FlowGraphBuilder::BuildGraph(intptr_t initial_loop_depth) { |
| 3034 intptr_t initial_loop_depth) { | |
| 3035 if (FLAG_print_ast) { | 3064 if (FLAG_print_ast) { |
| 3036 // Print the function ast before IL generation. | 3065 // Print the function ast before IL generation. |
| 3037 AstPrinter::PrintFunctionNodes(parsed_function()); | 3066 AstPrinter::PrintFunctionNodes(parsed_function()); |
| 3038 } | 3067 } |
| 3039 // Set the inlining context. | |
| 3040 ASSERT(inlining_context_ == kNotInlining); | |
| 3041 inlining_context_ = context; | |
| 3042 if (InInliningContext()) exits_ = new ZoneGrowableArray<ReturnInstr*>(); | |
| 3043 // Compilation can be nested, preserve the computation-id. | 3068 // Compilation can be nested, preserve the computation-id. |
| 3044 const Function& function = parsed_function().function(); | 3069 const Function& function = parsed_function().function(); |
| 3045 TargetEntryInstr* normal_entry = | 3070 TargetEntryInstr* normal_entry = |
| 3046 new TargetEntryInstr(AllocateBlockId(), | 3071 new TargetEntryInstr(AllocateBlockId(), |
| 3047 CatchClauseNode::kInvalidTryIndex, | 3072 CatchClauseNode::kInvalidTryIndex, |
| 3048 initial_loop_depth); | 3073 initial_loop_depth); |
| 3049 graph_entry_ = new GraphEntryInstr(normal_entry); | 3074 graph_entry_ = new GraphEntryInstr(normal_entry); |
| 3050 EffectGraphVisitor for_effect(this, 0, initial_loop_depth); | 3075 EffectGraphVisitor for_effect(this, 0, initial_loop_depth); |
| 3051 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the | 3076 // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the |
| 3052 // stack check on entry for leaf routines). | 3077 // stack check on entry for leaf routines). |
| 3053 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); | 3078 Instruction* check = new CheckStackOverflowInstr(function.token_pos()); |
| 3054 // If we are inlining don't actually attach the stack check. We must still | 3079 // If we are inlining don't actually attach the stack check. We must still |
| 3055 // create the stack check inorder to allocate a deopt id. | 3080 // create the stack check inorder to allocate a deopt id. |
| 3056 if (!InInliningContext()) for_effect.AddInstruction(check); | 3081 if (!InInliningContext()) for_effect.AddInstruction(check); |
| 3057 parsed_function().node_sequence()->Visit(&for_effect); | 3082 parsed_function().node_sequence()->Visit(&for_effect); |
| 3058 AppendFragment(normal_entry, for_effect); | 3083 AppendFragment(normal_entry, for_effect); |
| 3059 // Check that the graph is properly terminated. | 3084 // Check that the graph is properly terminated. |
| 3060 ASSERT(!for_effect.is_open()); | 3085 ASSERT(!for_effect.is_open()); |
| 3061 FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_); | 3086 FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_); |
| 3062 if (InInliningContext()) graph->set_exits(exits_); | |
| 3063 return graph; | 3087 return graph; |
| 3064 } | 3088 } |
| 3065 | 3089 |
| 3066 | 3090 |
| 3067 void FlowGraphBuilder::Bailout(const char* reason) { | 3091 void FlowGraphBuilder::Bailout(const char* reason) { |
| 3068 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; | 3092 const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; |
| 3069 const char* function_name = parsed_function_.function().ToCString(); | 3093 const char* function_name = parsed_function_.function().ToCString(); |
| 3070 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3094 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3071 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3095 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3072 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3096 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3073 const Error& error = Error::Handle( | 3097 const Error& error = Error::Handle( |
| 3074 LanguageError::New(String::Handle(String::New(chars)))); | 3098 LanguageError::New(String::Handle(String::New(chars)))); |
| 3075 Isolate::Current()->long_jump_base()->Jump(1, error); | 3099 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3076 } | 3100 } |
| 3077 | 3101 |
| 3078 | 3102 |
| 3079 } // namespace dart | 3103 } // namespace dart |
| OLD | NEW |