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

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/intermediate_language.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_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->InheritDeoptTargetAfter(call_);
249 false_block->LinkTo(call_->next());
250 call_block->ReplaceAsPredecessorWith(false_block);
251
252 ConstantInstr* true_const = caller_graph_->GetConstant(Bool::True());
253 BranchInstr* branch =
254 new BranchInstr(new StrictCompareInstr(Token::kEQ_STRICT,
255 new Value(true_const),
256 new Value(true_const)));
257 branch->InheritDeoptTarget(call_);
258 *branch->true_successor_address() = callee_entry;
259 *branch->false_successor_address() = false_block;
260
261 call_->previous()->AppendInstruction(branch);
262 call_block->set_last_instruction(branch);
263
264 // Update dominator tree.
265 call_block->AddDominatedBlock(callee_entry);
266 call_block->AddDominatedBlock(false_block);
267
268 } else {
269 Definition* callee_result = JoinReturns(&callee_exit,
270 &callee_last_instruction);
271 if (callee_result != NULL) {
272 call_->ReplaceUsesWith(callee_result);
273 }
274 if (callee_last_instruction == callee_entry) {
275 // There are no instructions in the inlined function (e.g., it might be
276 // a return of a parameter or a return of a constant defined in the
277 // initial definitions).
278 call_->previous()->LinkTo(call_->next());
279 } else {
280 call_->previous()->LinkTo(callee_entry->next());
281 callee_last_instruction->LinkTo(call_->next());
282 }
283 if (callee_exit != callee_entry) {
284 // In case of control flow, locally update the predecessors, phis and
285 // dominator tree.
286 //
287 // Pictorially, the graph structure is:
288 //
289 // Bc : call_block Bi : callee_entry
290 // before_call inlined_head
291 // call ... other blocks ...
292 // after_call Be : callee_exit
293 // inlined_foot
294 // And becomes:
295 //
296 // Bc : call_block
297 // before_call
298 // inlined_head
299 // ... other blocks ...
300 // Be : callee_exit
301 // inlined_foot
302 // after_call
303 //
304 // For successors of 'after_call', the call block (Bc) is replaced as a
305 // predecessor by the callee exit (Be).
306 call_block->ReplaceAsPredecessorWith(callee_exit);
307 // For successors of 'inlined_head', the callee entry (Bi) is replaced
308 // as a predecessor by the call block (Bc).
309 callee_entry->ReplaceAsPredecessorWith(call_block);
310
311 // The callee exit is now the immediate dominator of blocks whose
312 // immediate dominator was the call block.
313 ASSERT(callee_exit->dominated_blocks().is_empty());
314 for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) {
315 BlockEntryInstr* block = call_block->dominated_blocks()[i];
316 callee_exit->AddDominatedBlock(block);
317 }
318 // The call block is now the immediate dominator of blocks whose
319 // immediate dominator was the callee entry.
320 call_block->ClearDominatedBlocks();
321 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
322 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
323 call_block->AddDominatedBlock(block);
324 }
325 }
326
327 // Callee entry in not in the graph anymore. Remove it from use lists.
328 callee_entry->UnuseAllInputs();
244 } 329 }
245 if (callee_last_instruction == callee_entry) { 330 // Neither call nor the graph entry (if present) are in the
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. 331 // graph at this point. Remove them from use lists.
300 callee_entry->UnuseAllInputs();
301 if (callee_entry->PredecessorCount() > 0) { 332 if (callee_entry->PredecessorCount() > 0) {
302 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs(); 333 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs();
303 } 334 }
304 call_->UnuseAllInputs(); 335 call_->UnuseAllInputs();
305 } 336 }
306 337
307 338
308 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { 339 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) {
309 ASSERT(is_open()); 340 ASSERT(is_open());
310 if (other_fragment.is_empty()) return; 341 if (other_fragment.is_empty()) return;
(...skipping 2975 matching lines...) Expand 10 before | Expand all | Expand 10 after
3286 Resolver::kIsQualified)); 3317 Resolver::kIsQualified));
3287 ASSERT(!func.IsNull()); 3318 ASSERT(!func.IsNull());
3288 return new StaticCallInstr(token_pos, 3319 return new StaticCallInstr(token_pos,
3289 func, 3320 func,
3290 Array::ZoneHandle(), // No names. 3321 Array::ZoneHandle(), // No names.
3291 arguments); 3322 arguments);
3292 } 3323 }
3293 3324
3294 3325
3295 void EffectGraphVisitor::BuildThrowNode(ThrowNode* node) { 3326 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()); 3327 ValueGraphVisitor for_exception(owner(), temp_index());
3300 node->exception()->Visit(&for_exception); 3328 node->exception()->Visit(&for_exception);
3301 Append(for_exception); 3329 Append(for_exception);
3302 PushArgument(for_exception.value()); 3330 PushArgument(for_exception.value());
3303 Instruction* instr = NULL; 3331 Instruction* instr = NULL;
3304 if (node->stacktrace() == NULL) { 3332 if (node->stacktrace() == NULL) {
3305 instr = new ThrowInstr(node->token_pos()); 3333 instr = new ThrowInstr(node->token_pos());
3306 } else { 3334 } else {
3307 ValueGraphVisitor for_stack_trace(owner(), temp_index()); 3335 ValueGraphVisitor for_stack_trace(owner(), temp_index());
3308 node->stacktrace()->Visit(&for_stack_trace); 3336 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; 3423 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
3396 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 3424 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
3397 OS::SNPrint(chars, len, kFormat, function_name, reason); 3425 OS::SNPrint(chars, len, kFormat, function_name, reason);
3398 const Error& error = Error::Handle( 3426 const Error& error = Error::Handle(
3399 LanguageError::New(String::Handle(String::New(chars)))); 3427 LanguageError::New(String::Handle(String::New(chars))));
3400 Isolate::Current()->long_jump_base()->Jump(1, error); 3428 Isolate::Current()->long_jump_base()->Jump(1, error);
3401 } 3429 }
3402 3430
3403 3431
3404 } // namespace dart 3432 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698