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 "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
| 9 #include "vm/code_descriptors.h" | 9 #include "vm/code_descriptors.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 exits_.Sort(LowestBlockIdFirst); | 122 exits_.Sort(LowestBlockIdFirst); |
| 123 } | 123 } |
| 124 | 124 |
| 125 | 125 |
| 126 Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, | 126 Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, |
| 127 Instruction** last_instruction) { | 127 Instruction** last_instruction) { |
| 128 // First sort the list of exits by block id (caching return instruction | 128 // First sort the list of exits by block id (caching return instruction |
| 129 // block entries as a side effect). | 129 // block entries as a side effect). |
| 130 SortExits(); | 130 SortExits(); |
| 131 intptr_t num_exits = exits_.length(); | 131 intptr_t num_exits = exits_.length(); |
| 132 if (num_exits == 0) { | 132 if (num_exits == 1) { |
| 133 // TODO(zerny): Add support for non-local exits, such as throw. | |
| 134 UNREACHABLE(); | |
| 135 return NULL; | |
| 136 } else if (num_exits == 1) { | |
| 137 ReturnAt(0)->UnuseAllInputs(); | 133 ReturnAt(0)->UnuseAllInputs(); |
| 138 *exit_block = ExitBlockAt(0); | 134 *exit_block = ExitBlockAt(0); |
| 139 *last_instruction = LastInstructionAt(0); | 135 *last_instruction = LastInstructionAt(0); |
| 140 return call_->HasUses() ? ValueAt(0)->definition() : NULL; | 136 return call_->HasUses() ? ValueAt(0)->definition() : NULL; |
| 141 } else { | 137 } else { |
| 138 ASSERT(num_exits > 1); | |
| 142 // Create a join of the returns. | 139 // Create a join of the returns. |
| 143 intptr_t join_id = caller_graph_->max_block_id() + 1; | 140 intptr_t join_id = caller_graph_->max_block_id() + 1; |
| 144 caller_graph_->set_max_block_id(join_id); | 141 caller_graph_->set_max_block_id(join_id); |
| 145 JoinEntryInstr* join = | 142 JoinEntryInstr* join = |
| 146 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex); | 143 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex); |
| 147 join->InheritDeoptTargetAfter(call_); | 144 join->InheritDeoptTargetAfter(call_); |
| 148 | 145 |
| 149 // The dominator set of the join is the intersection of the dominator | 146 // The dominator set of the join is the intersection of the dominator |
| 150 // sets of all the predecessors. If we keep the dominator sets ordered | 147 // sets of all the predecessors. If we keep the dominator sets ordered |
| 151 // by height in the dominator tree, we can also get the immediate | 148 // by height in the dominator tree, we can also get the immediate |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 | 227 |
| 231 | 228 |
| 232 void InlineExitCollector::ReplaceCall(TargetEntryInstr* callee_entry) { | 229 void InlineExitCollector::ReplaceCall(TargetEntryInstr* callee_entry) { |
| 233 ASSERT(call_->previous() != NULL); | 230 ASSERT(call_->previous() != NULL); |
| 234 ASSERT(call_->next() != NULL); | 231 ASSERT(call_->next() != NULL); |
| 235 BlockEntryInstr* call_block = call_->GetBlock(); | 232 BlockEntryInstr* call_block = call_->GetBlock(); |
| 236 | 233 |
| 237 // Insert the callee graph into the caller graph. | 234 // Insert the callee graph into the caller graph. |
| 238 BlockEntryInstr* callee_exit = NULL; | 235 BlockEntryInstr* callee_exit = NULL; |
| 239 Instruction* callee_last_instruction = NULL; | 236 Instruction* callee_last_instruction = NULL; |
| 240 Definition* callee_result = JoinReturns(&callee_exit, | 237 |
| 241 &callee_last_instruction); | 238 if (exits_.length() == 0) { |
| 242 if (callee_result != NULL) { | 239 // Handle the case when there are no normal return exits from the callee |
| 243 call_->ReplaceUsesWith(callee_result); | 240 // (i.e. the callee unconditionally throws) by inserting an artificial |
| 241 // branch (true === true). | |
| 242 // The true successor is the inlined body, the false successor | |
| 243 // goes to the rest of the caller graph. It is removed as unreachable code | |
| 244 // by the constant propagation. | |
| 245 TargetEntryInstr* false_block = | |
| 246 new TargetEntryInstr(caller_graph_->allocate_block_id(), | |
| 247 call_block->try_index()); | |
| 248 false_block->LinkTo(call_->next()); | |
|
Kevin Millikin (Google)
2013/05/22 12:05:11
I guess it's safe that false_block does not have a
Florian Schneider
2013/05/24 12:51:56
Done.
| |
| 249 call_block->ReplaceAsPredecessorWith(false_block); | |
| 250 | |
| 251 ConstantInstr* true_const = caller_graph_->GetConstant(Bool::True()); | |
| 252 Value* left = new Value(true_const); | |
| 253 Value* right = new Value(true_const); | |
| 254 true_const->AddInputUse(left); | |
| 255 true_const->AddInputUse(right); | |
| 256 BranchInstr* branch = | |
| 257 new BranchInstr(new StrictCompareInstr(Token::kEQ_STRICT, left, right)); | |
| 258 branch->InheritDeoptTarget(call_); | |
| 259 | |
| 260 call_->previous()->LinkTo(branch); | |
|
Kevin Millikin (Google)
2013/05/22 12:05:11
You can call
AppendInstruction(call_->previous(),
Florian Schneider
2013/05/24 12:51:56
Done. Added AppendInstruction helper to the Instru
| |
| 261 call_block->set_last_instruction(branch); | |
| 262 | |
| 263 *branch->true_successor_address() = callee_entry; | |
| 264 *branch->false_successor_address() = false_block; | |
| 265 | |
| 266 // Update dominator tree. | |
| 267 call_block->AddDominatedBlock(callee_entry); | |
| 268 call_block->AddDominatedBlock(false_block); | |
| 269 | |
| 270 // The graph entry (if present) is not in the graph anymore. | |
|
Kevin Millikin (Google)
2013/05/22 12:05:11
This is the same as the last code in the else bloc
Florian Schneider
2013/05/24 12:51:56
Done.
| |
| 271 // Remove it and the original call from use lists. | |
| 272 if (callee_entry->PredecessorCount() > 0) { | |
| 273 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs(); | |
| 274 } | |
| 275 call_->UnuseAllInputs(); | |
| 276 } else { | |
|
Florian Schneider
2013/05/22 11:40:40
The diff is confused here. This part of the if-sta
| |
| 277 Definition* callee_result = JoinReturns(&callee_exit, | |
| 278 &callee_last_instruction); | |
| 279 if (callee_result != NULL) { | |
| 280 call_->ReplaceUsesWith(callee_result); | |
| 281 } | |
| 282 if (callee_last_instruction == callee_entry) { | |
| 283 // There are no instructions in the inlined function (e.g., it might be | |
| 284 // a return of a parameter or a return of a constant defined in the | |
| 285 // initial definitions). | |
| 286 call_->previous()->LinkTo(call_->next()); | |
| 287 } else { | |
| 288 call_->previous()->LinkTo(callee_entry->next()); | |
| 289 callee_last_instruction->LinkTo(call_->next()); | |
| 290 } | |
| 291 if (callee_exit != callee_entry) { | |
| 292 // In case of control flow, locally update the predecessors, phis and | |
| 293 // dominator tree. | |
| 294 // | |
| 295 // Pictorially, the graph structure is: | |
| 296 // | |
| 297 // Bc : call_block Bi : callee_entry | |
| 298 // before_call inlined_head | |
| 299 // call ... other blocks ... | |
| 300 // after_call Be : callee_exit | |
| 301 // inlined_foot | |
| 302 // And becomes: | |
| 303 // | |
| 304 // Bc : call_block | |
| 305 // before_call | |
| 306 // inlined_head | |
| 307 // ... other blocks ... | |
| 308 // Be : callee_exit | |
| 309 // inlined_foot | |
| 310 // after_call | |
| 311 // | |
| 312 // For successors of 'after_call', the call block (Bc) is replaced as a | |
| 313 // predecessor by the callee exit (Be). | |
| 314 call_block->ReplaceAsPredecessorWith(callee_exit); | |
| 315 // For successors of 'inlined_head', the callee entry (Bi) is replaced | |
| 316 // as a predecessor by the call block (Bc). | |
| 317 callee_entry->ReplaceAsPredecessorWith(call_block); | |
| 318 | |
| 319 // The callee exit is now the immediate dominator of blocks whose | |
| 320 // immediate dominator was the call block. | |
| 321 ASSERT(callee_exit->dominated_blocks().is_empty()); | |
| 322 for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) { | |
| 323 BlockEntryInstr* block = call_block->dominated_blocks()[i]; | |
| 324 callee_exit->AddDominatedBlock(block); | |
| 325 } | |
| 326 // The call block is now the immediate dominator of blocks whose | |
| 327 // immediate dominator was the callee entry. | |
| 328 call_block->ClearDominatedBlocks(); | |
| 329 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { | |
| 330 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; | |
| 331 call_block->AddDominatedBlock(block); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 // Neither call nor callee entry nor the graph entry (if present) are in the | |
| 336 // graph at this point. Remove them from use lists. | |
| 337 callee_entry->UnuseAllInputs(); | |
| 338 if (callee_entry->PredecessorCount() > 0) { | |
| 339 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs(); | |
| 340 } | |
| 341 call_->UnuseAllInputs(); | |
| 244 } | 342 } |
| 245 if (callee_last_instruction == callee_entry) { | |
| 246 // There are no instructions in the inlined function (e.g., it might be | |
| 247 // a return of a parameter or a return of a constant defined in the | |
| 248 // initial definitions). | |
| 249 call_->previous()->LinkTo(call_->next()); | |
| 250 } else { | |
| 251 call_->previous()->LinkTo(callee_entry->next()); | |
| 252 callee_last_instruction->LinkTo(call_->next()); | |
| 253 } | |
| 254 if (callee_exit != callee_entry) { | |
| 255 // In case of control flow, locally update the predecessors, phis and | |
| 256 // dominator tree. | |
| 257 // | |
| 258 // Pictorially, the graph structure is: | |
| 259 // | |
| 260 // Bc : call_block Bi : callee_entry | |
| 261 // before_call inlined_head | |
| 262 // call ... other blocks ... | |
| 263 // after_call Be : callee_exit | |
| 264 // inlined_foot | |
| 265 // And becomes: | |
| 266 // | |
| 267 // Bc : call_block | |
| 268 // before_call | |
| 269 // inlined_head | |
| 270 // ... other blocks ... | |
| 271 // Be : callee_exit | |
| 272 // inlined_foot | |
| 273 // after_call | |
| 274 // | |
| 275 // For successors of 'after_call', the call block (Bc) is replaced as a | |
| 276 // predecessor by the callee exit (Be). | |
| 277 call_block->ReplaceAsPredecessorWith(callee_exit); | |
| 278 // For successors of 'inlined_head', the callee entry (Bi) is replaced | |
| 279 // as a predecessor by the call block (Bc). | |
| 280 callee_entry->ReplaceAsPredecessorWith(call_block); | |
| 281 | |
| 282 // The callee exit is now the immediate dominator of blocks whose | |
| 283 // immediate dominator was the call block. | |
| 284 ASSERT(callee_exit->dominated_blocks().is_empty()); | |
| 285 for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) { | |
| 286 BlockEntryInstr* block = call_block->dominated_blocks()[i]; | |
| 287 callee_exit->AddDominatedBlock(block); | |
| 288 } | |
| 289 // The call block is now the immediate dominator of blocks whose | |
| 290 // immediate dominator was the callee entry. | |
| 291 call_block->ClearDominatedBlocks(); | |
| 292 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) { | |
| 293 BlockEntryInstr* block = callee_entry->dominated_blocks()[i]; | |
| 294 call_block->AddDominatedBlock(block); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 // Neither call nor callee entry nor the graph entry (if present) are in the | |
| 299 // graph at this point. Remove them from use lists. | |
| 300 callee_entry->UnuseAllInputs(); | |
| 301 if (callee_entry->PredecessorCount() > 0) { | |
| 302 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs(); | |
| 303 } | |
| 304 call_->UnuseAllInputs(); | |
| 305 } | 343 } |
| 306 | 344 |
| 307 | 345 |
| 308 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { | 346 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| 309 ASSERT(is_open()); | 347 ASSERT(is_open()); |
| 310 if (other_fragment.is_empty()) return; | 348 if (other_fragment.is_empty()) return; |
| 311 if (is_empty()) { | 349 if (is_empty()) { |
| 312 entry_ = other_fragment.entry(); | 350 entry_ = other_fragment.entry(); |
| 313 exit_ = other_fragment.exit(); | 351 exit_ = other_fragment.exit(); |
| 314 } else { | 352 } else { |
| (...skipping 2971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3286 Resolver::kIsQualified)); | 3324 Resolver::kIsQualified)); |
| 3287 ASSERT(!func.IsNull()); | 3325 ASSERT(!func.IsNull()); |
| 3288 return new StaticCallInstr(token_pos, | 3326 return new StaticCallInstr(token_pos, |
| 3289 func, | 3327 func, |
| 3290 Array::ZoneHandle(), // No names. | 3328 Array::ZoneHandle(), // No names. |
| 3291 arguments); | 3329 arguments); |
| 3292 } | 3330 } |
| 3293 | 3331 |
| 3294 | 3332 |
| 3295 void EffectGraphVisitor::BuildThrowNode(ThrowNode* node) { | 3333 void EffectGraphVisitor::BuildThrowNode(ThrowNode* node) { |
| 3296 // TODO(kmillikin) non-local control flow is not handled correctly | |
| 3297 // by the inliner. | |
| 3298 InlineBailout("EffectGraphVisitor::BuildThrowNode (exception)"); | |
| 3299 ValueGraphVisitor for_exception(owner(), temp_index()); | 3334 ValueGraphVisitor for_exception(owner(), temp_index()); |
| 3300 node->exception()->Visit(&for_exception); | 3335 node->exception()->Visit(&for_exception); |
| 3301 Append(for_exception); | 3336 Append(for_exception); |
| 3302 PushArgument(for_exception.value()); | 3337 PushArgument(for_exception.value()); |
| 3303 Instruction* instr = NULL; | 3338 Instruction* instr = NULL; |
| 3304 if (node->stacktrace() == NULL) { | 3339 if (node->stacktrace() == NULL) { |
| 3305 instr = new ThrowInstr(node->token_pos()); | 3340 instr = new ThrowInstr(node->token_pos()); |
| 3306 } else { | 3341 } else { |
| 3307 ValueGraphVisitor for_stack_trace(owner(), temp_index()); | 3342 ValueGraphVisitor for_stack_trace(owner(), temp_index()); |
| 3308 node->stacktrace()->Visit(&for_stack_trace); | 3343 node->stacktrace()->Visit(&for_stack_trace); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3395 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3430 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3396 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3431 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3397 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3432 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3398 const Error& error = Error::Handle( | 3433 const Error& error = Error::Handle( |
| 3399 LanguageError::New(String::Handle(String::New(chars)))); | 3434 LanguageError::New(String::Handle(String::New(chars)))); |
| 3400 Isolate::Current()->long_jump_base()->Jump(1, error); | 3435 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3401 } | 3436 } |
| 3402 | 3437 |
| 3403 | 3438 |
| 3404 } // namespace dart | 3439 } // namespace dart |
| OLD | NEW |