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/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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), | 53 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 54 try_index_(CatchClauseNode::kInvalidTryIndex), | 54 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 55 graph_entry_(NULL) { } | 55 graph_entry_(NULL) { } |
| 56 | 56 |
| 57 | 57 |
| 58 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) { | 58 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) { |
| 59 graph_entry_->AddCatchEntry(entry); | 59 graph_entry_->AddCatchEntry(entry); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 InliningContext* InliningContext::Create(Definition* call) { | |
|
srdjan
2013/01/24 18:09:51
Why the argument call?
| |
| 64 return new ValueInliningContext(); | |
| 65 } | |
| 66 | |
| 67 | |
| 68 void InliningContext::PrepareGraphs(FlowGraph* caller_graph, | |
| 69 Definition* call, | |
| 70 FlowGraph* callee_graph) { | |
| 71 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | |
| 72 ASSERT(callee_graph->max_block_id() > caller_graph->max_block_id()); | |
| 73 ASSERT(callee_graph->max_virtual_register_number() > | |
| 74 caller_graph->max_virtual_register_number()); | |
| 75 | |
| 76 // Adjust the caller's maximum block id and current SSA temp index. | |
| 77 caller_graph->set_max_block_id(callee_graph->max_block_id()); | |
| 78 caller_graph->set_current_ssa_temp_index( | |
| 79 callee_graph->max_virtual_register_number()); | |
| 80 | |
| 81 // Attach the outer environment on each instruction in the callee graph. | |
| 82 for (BlockIterator block_it = callee_graph->postorder_iterator(); | |
| 83 !block_it.Done(); | |
| 84 block_it.Advance()) { | |
| 85 for (ForwardInstructionIterator it(block_it.Current()); | |
| 86 !it.Done(); | |
| 87 it.Advance()) { | |
| 88 Instruction* instr = it.Current(); | |
| 89 // TODO(zerny): Avoid creating unnecessary environments. Note that some | |
| 90 // optimizations need deoptimization info for non-deoptable instructions, | |
| 91 // eg, LICM on GOTOs. | |
| 92 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr); | |
| 93 } | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 | |
| 63 void ValueInliningContext::AddExit(ReturnInstr* exit) { | 98 void ValueInliningContext::AddExit(ReturnInstr* exit) { |
| 64 Data data = { NULL, exit }; | 99 Data data = { NULL, exit }; |
| 65 exits_.Add(data); | 100 exits_.Add(data); |
| 66 } | 101 } |
| 67 | 102 |
| 68 | 103 |
| 69 int ValueInliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { | 104 int ValueInliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { |
| 70 return (a->exit_block->block_id() - b->exit_block->block_id()); | 105 return (a->exit_block->block_id() - b->exit_block->block_id()); |
| 71 } | 106 } |
| 72 | 107 |
| 73 | 108 |
| 74 void ValueInliningContext::SortExits() { | 109 void ValueInliningContext::SortExits() { |
| 75 // Assign block entries here because we did not necessarily know them when | 110 // Assign block entries here because we did not necessarily know them when |
| 76 // the return exit was added to the array. | 111 // the return exit was added to the array. |
| 77 for (int i = 0; i < exits_.length(); ++i) { | 112 for (int i = 0; i < exits_.length(); ++i) { |
| 78 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); | 113 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); |
| 79 } | 114 } |
| 80 exits_.Sort(LowestBlockIdFirst); | 115 exits_.Sort(LowestBlockIdFirst); |
| 81 } | 116 } |
| 82 | 117 |
| 83 | 118 |
| 119 void ValueInliningContext::ReplaceCall(FlowGraph* caller_graph, | |
| 120 Definition* call, | |
| 121 FlowGraph* callee_graph) { | |
| 122 ASSERT(call->previous() != NULL); | |
| 123 ASSERT(call->next() != NULL); | |
| 124 PrepareGraphs(caller_graph, call, callee_graph); | |
| 125 | |
| 126 BlockEntryInstr* caller_entry = call->GetBlock(); | |
| 127 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); | |
| 128 | |
| 129 // Insert the callee graph into the caller graph. First sort the list of | |
| 130 // exits by block id (recording block entries as a side effect). | |
| 131 SortExits(); | |
| 132 intptr_t num_exits = exits_.length(); | |
| 133 if (num_exits == 0) { | |
| 134 // TODO(zerny): Add support for non-local exits, such as throw. | |
| 135 UNREACHABLE(); | |
| 136 } else if (num_exits == 1) { | |
| 137 // For just one exit, replace the uses and remove the call from the graph. | |
| 138 call->ReplaceUsesWith(ValueAt(0)->definition()); | |
| 139 call->previous()->LinkTo(callee_entry->next()); | |
| 140 LastInstructionAt(0)->LinkTo(call->next()); | |
| 141 // In case of control flow, locally update the predecessors, phis and | |
| 142 // dominator tree. | |
| 143 // TODO(zerny): should we leave the dominator tree since we recompute it | |
| 144 // after a full inlining pass? | |
| 145 if (callee_graph->preorder().length() > 2) { | |
| 146 BlockEntryInstr* exit_block = ExitBlockAt(0); | |
| 147 // Pictorially, the graph structure is: | |
| 148 // | |
| 149 // Bc : caller_entry Bi : callee_entry | |
| 150 // before_call inlined_head | |
| 151 // call ... other blocks ... | |
| 152 // after_call Be : exit_block | |
| 153 // inlined_foot | |
| 154 // And becomes: | |
| 155 // | |
| 156 // Bc : caller_entry | |
| 157 // before_call | |
| 158 // inlined_head | |
| 159 // ... other blocks ... | |
| 160 // Be : exit_block | |
| 161 // inlined_foot | |
| 162 // after_call | |
| 163 // | |
| 164 // For 'after_call', caller entry (Bc) is replaced by callee exit (Be). | |
| 165 caller_entry->ReplaceAsPredecessorWith(exit_block); | |
| 166 // For 'inlined_head', callee entry (Bi) is replaced by caller entry (Bc). | |
| 167 callee_entry->ReplaceAsPredecessorWith(caller_entry); | |
| 168 // The callee exit is now the immediate dominator of blocks whose | |
| 169 // immediate dominator was the caller entry. | |
| 170 ASSERT(exit_block->dominated_blocks().is_empty()); | |
| 171 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) { | |
| 172 BlockEntryInstr* block = caller_entry->dominated_blocks()[i]; | |
| 173 block->set_dominator(exit_block); | |
| 174 exit_block->AddDominatedBlock(block); | |
| 175 } | |
| 176 // The caller entry is now the immediate dominator of blocks whose | |
| 177 // immediate dominator was the callee entry. | |
| 178 caller_entry->ClearDominatedBlocks(); | |
| 179 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { | |
| 180 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; | |
| 181 block->set_dominator(caller_entry); | |
| 182 caller_entry->AddDominatedBlock(block); | |
| 183 } | |
| 184 } | |
| 185 } else { | |
| 186 // Create a join of the returns. | |
| 187 intptr_t join_id = caller_graph->max_block_id() + 1; | |
| 188 caller_graph->set_max_block_id(join_id); | |
| 189 JoinEntryInstr* join = | |
| 190 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex); | |
| 191 for (intptr_t i = 0; i < num_exits; ++i) { | |
| 192 LastInstructionAt(i)->Goto(join); | |
| 193 // Directly add the predecessors of the join in ascending block id order. | |
| 194 join->predecessors_.Add(ExitBlockAt(i)); | |
| 195 } | |
| 196 // If the call has uses, create a phi of the returns. | |
| 197 if (call->HasUses()) { | |
| 198 // Environment count: length before call - argument count (+ return) | |
| 199 intptr_t env_count = call->env()->Length() - call->ArgumentCount(); | |
| 200 // Add a phi of the return values. | |
| 201 join->InsertPhi(env_count, env_count + 1); | |
| 202 PhiInstr* phi = join->phis()->Last(); | |
| 203 phi->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index()); | |
| 204 phi->mark_alive(); | |
| 205 for (intptr_t i = 0; i < num_exits; ++i) { | |
| 206 Value* value = ValueAt(i); | |
| 207 phi->SetInputAt(i, value); | |
| 208 value->set_instruction(phi); | |
| 209 value->set_use_index(i); | |
| 210 } | |
| 211 // Replace uses of the call with the phi. | |
| 212 call->ReplaceUsesWith(phi); | |
| 213 } | |
| 214 // Remove the call from the graph. | |
| 215 call->previous()->LinkTo(callee_entry->next()); | |
| 216 join->LinkTo(call->next()); | |
| 217 // Replace the blocks after splitting (see comment in the len=1 case above). | |
| 218 caller_entry->ReplaceAsPredecessorWith(join); | |
| 219 callee_entry->ReplaceAsPredecessorWith(caller_entry); | |
| 220 // Update the last instruction pointers on each exit block to the new goto. | |
| 221 for (intptr_t i = 0; i < num_exits; ++i) { | |
| 222 ExitBlockAt(i)->set_last_instruction(LastInstructionAt(i)->next()); | |
| 223 } | |
| 224 // Mark that the dominator tree is invalid. | |
| 225 // TODO(zerny): Compute the dominator frontier locally. | |
| 226 caller_graph->InvalidateDominatorTree(); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 | |
| 84 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { | 231 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| 85 ASSERT(is_open()); | 232 ASSERT(is_open()); |
| 86 if (other_fragment.is_empty()) return; | 233 if (other_fragment.is_empty()) return; |
| 87 if (is_empty()) { | 234 if (is_empty()) { |
| 88 entry_ = other_fragment.entry(); | 235 entry_ = other_fragment.entry(); |
| 89 exit_ = other_fragment.exit(); | 236 exit_ = other_fragment.exit(); |
| 90 } else { | 237 } else { |
| 91 exit()->LinkTo(other_fragment.entry()); | 238 exit()->LinkTo(other_fragment.entry()); |
| 92 exit_ = other_fragment.exit(); | 239 exit_ = other_fragment.exit(); |
| 93 } | 240 } |
| (...skipping 2956 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3050 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3197 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3051 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3198 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3052 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3199 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3053 const Error& error = Error::Handle( | 3200 const Error& error = Error::Handle( |
| 3054 LanguageError::New(String::Handle(String::New(chars)))); | 3201 LanguageError::New(String::Handle(String::New(chars)))); |
| 3055 Isolate::Current()->long_jump_base()->Jump(1, error); | 3202 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3056 } | 3203 } |
| 3057 | 3204 |
| 3058 | 3205 |
| 3059 } // namespace dart | 3206 } // namespace dart |
| OLD | NEW |