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

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

Issue 15730003: Support inlining function containing throw in the optimizer. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: 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 | « no previous file | runtime/vm/il_printer.cc » ('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_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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698