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

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

Issue 12638040: Compute local variable liveness before translation to SSA. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 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
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.h" 5 #include "vm/flow_graph.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/flow_graph_builder.h" 8 #include "vm/flow_graph_builder.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 #include "vm/longjump.h" 10 #include "vm/longjump.h"
11 #include "vm/growable_array.h" 11 #include "vm/growable_array.h"
12 12
13 namespace dart { 13 namespace dart {
14 14
15 DECLARE_FLAG(bool, trace_optimization); 15 DECLARE_FLAG(bool, trace_optimization);
16 DECLARE_FLAG(bool, verify_compiler); 16 DECLARE_FLAG(bool, verify_compiler);
17 17
18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, 18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder,
19 GraphEntryInstr* graph_entry, 19 GraphEntryInstr* graph_entry,
20 intptr_t max_block_id) 20 intptr_t max_block_id)
21 : parent_(), 21 : parent_(),
22 assigned_vars_(),
23 current_ssa_temp_index_(0), 22 current_ssa_temp_index_(0),
24 max_block_id_(max_block_id), 23 max_block_id_(max_block_id),
25 parsed_function_(builder.parsed_function()), 24 parsed_function_(builder.parsed_function()),
26 num_copied_params_(builder.num_copied_params()), 25 num_copied_params_(builder.num_copied_params()),
27 num_non_copied_params_(builder.num_non_copied_params()), 26 num_non_copied_params_(builder.num_non_copied_params()),
28 num_stack_locals_(builder.num_stack_locals()), 27 num_stack_locals_(builder.num_stack_locals()),
29 graph_entry_(graph_entry), 28 graph_entry_(graph_entry),
30 preorder_(), 29 preorder_(),
31 postorder_(), 30 postorder_(),
32 reverse_postorder_(), 31 reverse_postorder_(),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 if (env != NULL) env->DeepCopyTo(instr); 80 if (env != NULL) env->DeepCopyTo(instr);
82 } 81 }
83 82
84 83
85 void FlowGraph::DiscoverBlocks() { 84 void FlowGraph::DiscoverBlocks() {
86 // Initialize state. 85 // Initialize state.
87 preorder_.Clear(); 86 preorder_.Clear();
88 postorder_.Clear(); 87 postorder_.Clear();
89 reverse_postorder_.Clear(); 88 reverse_postorder_.Clear();
90 parent_.Clear(); 89 parent_.Clear();
91 assigned_vars_.Clear();
92 // Perform a depth-first traversal of the graph to build preorder and 90 // Perform a depth-first traversal of the graph to build preorder and
93 // postorder block orders. 91 // postorder block orders.
94 graph_entry_->DiscoverBlocks(NULL, // Entry block predecessor. 92 graph_entry_->DiscoverBlocks(NULL, // Entry block predecessor.
95 &preorder_, 93 &preorder_,
96 &postorder_, 94 &postorder_,
97 &parent_, 95 &parent_,
98 &assigned_vars_,
99 variable_count(), 96 variable_count(),
100 num_non_copied_params()); 97 num_non_copied_params());
101 // Create an array of blocks in reverse postorder. 98 // Create an array of blocks in reverse postorder.
102 intptr_t block_count = postorder_.length(); 99 intptr_t block_count = postorder_.length();
103 for (intptr_t i = 0; i < block_count; ++i) { 100 for (intptr_t i = 0; i < block_count; ++i) {
104 reverse_postorder_.Add(postorder_[block_count - i - 1]); 101 reverse_postorder_.Add(postorder_[block_count - i - 1]);
105 } 102 }
106 } 103 }
107 104
108 105
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 } 195 }
199 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { 196 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
200 VerifyUseListsInInstruction(it.Current()); 197 VerifyUseListsInInstruction(it.Current());
201 } 198 }
202 } 199 }
203 return true; // Return true so we can ASSERT validation. 200 return true; // Return true so we can ASSERT validation.
204 } 201 }
205 #endif // DEBUG 202 #endif // DEBUG
206 203
207 204
205 LivenessAnalysis::LivenessAnalysis(
206 intptr_t variable_count,
207 const GrowableArray<BlockEntryInstr*>& postorder)
208 : variable_count_(variable_count),
209 postorder_(postorder),
210 live_out_(postorder.length()),
211 kill_(postorder.length()),
212 live_in_(postorder.length()) {
213 }
214
215
216 bool LivenessAnalysis::UpdateLiveOut(const BlockEntryInstr& block) {
217 BitVector* live_out = live_out_[block.postorder_number()];
218 bool changed = false;
219 Instruction* last = block.last_instruction();
220 ASSERT(last != NULL);
221 for (intptr_t i = 0; i < last->SuccessorCount(); i++) {
222 BlockEntryInstr* succ = last->SuccessorAt(i);
223 ASSERT(succ != NULL);
224 if (live_out->AddAll(live_in_[succ->postorder_number()])) {
225 changed = true;
226 }
227 }
228 return changed;
229 }
230
231
232 bool LivenessAnalysis::UpdateLiveIn(const BlockEntryInstr& block) {
233 BitVector* live_out = live_out_[block.postorder_number()];
234 BitVector* kill = kill_[block.postorder_number()];
235 BitVector* live_in = live_in_[block.postorder_number()];
236 return live_in->KillAndAdd(kill, live_out);
237 }
238
239
240 void LivenessAnalysis::ComputeLiveInAndLiveOutSets() {
241 const intptr_t block_count = postorder_.length();
242 bool changed;
243 do {
244 changed = false;
245
246 for (intptr_t i = 0; i < block_count; i++) {
247 const BlockEntryInstr& block = *postorder_[i];
248
249 // Live-in set depends only on kill set which does not
250 // change in this loop and live-out set. If live-out
251 // set does not change there is no need to recompute
252 // live-in set.
253 if (UpdateLiveOut(block) && UpdateLiveIn(block)) {
254 changed = true;
255 }
256 }
257 } while (changed);
258 }
259
260
261 void LivenessAnalysis::Analyze() {
262 const intptr_t block_count = postorder_.length();
263 for (intptr_t i = 0; i < block_count; i++) {
264 live_out_.Add(new BitVector(variable_count_));
265 kill_.Add(new BitVector(variable_count_));
266 live_in_.Add(new BitVector(variable_count_));
267 }
268
269 ComputeInitialSets();
270 ComputeLiveInAndLiveOutSets();
271 }
272
273
274 static void PrintBitVector(const char* tag, BitVector* v) {
275 OS::Print("%s:", tag);
276 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) {
277 OS::Print(" %"Pd"", it.Current());
278 }
279 OS::Print("\n");
280 }
281
282
283 void LivenessAnalysis::Dump() {
284 const intptr_t block_count = postorder_.length();
285 for (intptr_t i = 0; i < block_count; i++) {
286 BlockEntryInstr* block = postorder_[i];
287 OS::Print("block @%"Pd" -> ", block->block_id());
288
289 Instruction* last = block->last_instruction();
290 for (intptr_t j = 0; j < last->SuccessorCount(); j++) {
291 BlockEntryInstr* succ = last->SuccessorAt(j);
292 OS::Print(" @%"Pd"", succ->block_id());
293 }
294 OS::Print("\n");
295
296 PrintBitVector(" live out", live_out_[i]);
297 PrintBitVector(" kill", kill_[i]);
298 PrintBitVector(" live in", live_in_[i]);
299 }
300 }
301
302
303 class VariableLivenessAnalysis : public LivenessAnalysis {
304 public:
305 explicit VariableLivenessAnalysis(FlowGraph* flow_graph)
306 : LivenessAnalysis(flow_graph->variable_count(), flow_graph->postorder()),
307 flow_graph_(flow_graph),
308 num_non_copied_params_(flow_graph->num_non_copied_params()),
309 assigned_vars_() { }
310
311 const GrowableArray<BitVector*>& ComputeAssignedVars() {
312 assigned_vars_.Clear();
313
314 const intptr_t block_count = flow_graph_->preorder().length();
315 for (intptr_t i = 0; i < block_count; i++) {
316 BlockEntryInstr* block = flow_graph_->preorder()[i];
317 BitVector* kill = GetKillSet(block);
318 kill->Intersect(GetLiveOutSet(block));
Kevin Millikin (Google) 2013/03/22 11:57:52 It seems to me that you could either use a fresh b
Vyacheslav Egorov (Google) 2013/03/22 12:16:15 kill_ is in postorder while assigned_vars_ are in
319 assigned_vars_.Add(kill);
320 }
321
322 return assigned_vars_;
323 }
324
325 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) {
326 if (store->is_dead()) {
327 return false;
328 }
329
330 if (store->is_last()) {
331 const intptr_t index = store->local().BitIndexIn(num_non_copied_params_);
332 return GetLiveOutSet(block)->Contains(index);
333 }
334
335 return true;
336 }
337
338 bool IsLastLoad(BlockEntryInstr* block, LoadLocalInstr* load) {
339 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
340 return load->is_last() && !GetLiveOutSet(block)->Contains(index);
341 }
342
343 private:
344 virtual void ComputeInitialSets();
345
346 const FlowGraph* flow_graph_;
347 const intptr_t num_non_copied_params_;
348
349 GrowableArray<BitVector*> assigned_vars_;
350 };
351
352
353 void VariableLivenessAnalysis::ComputeInitialSets() {
354 const intptr_t block_count = postorder_.length();
355
356 BitVector* last_loads = new BitVector(variable_count_);
357 for (intptr_t i = 0; i < block_count; i++) {
358 BlockEntryInstr* block = postorder_[i];
359
360 BitVector* kill = kill_[i];
361 BitVector* live_in = live_in_[i];
362 last_loads->Clear();
363
364 // Iterate backwards starting at the last instruction.
365 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) {
366 Instruction* current = it.Current();
367
368 LoadLocalInstr* load = current->AsLoadLocal();
369 if (load != NULL) {
370 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
371 live_in->Add(index);
372
373 if (!last_loads->Contains(index)) {
374 last_loads->Add(index);
375 load->mark_last();
376 }
377
378 continue;
379 }
380
381 StoreLocalInstr* store = current->AsStoreLocal();
382 if (store != NULL) {
383 const intptr_t index =
384 store->local().BitIndexIn(num_non_copied_params_);
385 if (kill->Contains(index)) {
386 if (!live_in->Contains(index)) {
387 store->mark_dead();
388 }
389 } else {
390 if (!live_in->Contains(index)) {
391 store->mark_last();
392 }
393 kill->Add(index);
394 }
395 live_in->Remove(index);
396 continue;
397 }
398 }
399 }
400 }
401
402
208 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number, 403 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number,
209 GrowableArray<Definition*>* inlining_parameters) { 404 GrowableArray<Definition*>* inlining_parameters) {
210 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); 405 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL));
211 current_ssa_temp_index_ = next_virtual_register_number; 406 current_ssa_temp_index_ = next_virtual_register_number;
212 GrowableArray<BitVector*> dominance_frontier; 407 GrowableArray<BitVector*> dominance_frontier;
213 ComputeDominators(&dominance_frontier); 408 ComputeDominators(&dominance_frontier);
214 InsertPhis(preorder_, assigned_vars_, dominance_frontier); 409
410 VariableLivenessAnalysis variable_liveness(this);
411 variable_liveness.Analyze();
412
413 InsertPhis(preorder_,
414 variable_liveness.ComputeAssignedVars(),
415 dominance_frontier);
416
215 GrowableArray<PhiInstr*> live_phis; 417 GrowableArray<PhiInstr*> live_phis;
418
216 // Rename uses to reference inserted phis where appropriate. 419 // Rename uses to reference inserted phis where appropriate.
217 // Collect phis that reach a non-environment use. 420 // Collect phis that reach a non-environment use.
218 Rename(&live_phis, inlining_parameters); 421 Rename(&live_phis, &variable_liveness, inlining_parameters);
422
219 // Propagate alive mark transitively from alive phis and then remove 423 // Propagate alive mark transitively from alive phis and then remove
220 // non-live ones. 424 // non-live ones.
221 RemoveDeadPhis(&live_phis); 425 RemoveDeadPhis(&live_phis);
222 } 426 }
223 427
224 428
225 // Compute immediate dominators and the dominance frontier for each basic 429 // Compute immediate dominators and the dominance frontier for each basic
226 // block. As a side effect of the algorithm, sets the immediate dominator 430 // block. As a side effect of the algorithm, sets the immediate dominator
227 // of each basic block. 431 // of each basic block.
228 // 432 //
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 worklist.Add(block); 594 worklist.Add(block);
391 } 595 }
392 } 596 }
393 } 597 }
394 } 598 }
395 } 599 }
396 } 600 }
397 601
398 602
399 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, 603 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
604 VariableLivenessAnalysis* variable_liveness,
400 GrowableArray<Definition*>* inlining_parameters) { 605 GrowableArray<Definition*>* inlining_parameters) {
401 // TODO(fschneider): Support catch-entry. 606 // TODO(fschneider): Support catch-entry.
402 if (graph_entry_->SuccessorCount() > 1) { 607 if (graph_entry_->SuccessorCount() > 1) {
403 Bailout("Catch-entry support in SSA."); 608 Bailout("Catch-entry support in SSA.");
404 } 609 }
405 610
406 // Initial renaming environment. 611 // Initial renaming environment.
407 GrowableArray<Definition*> env(variable_count()); 612 GrowableArray<Definition*> env(variable_count());
408 613
409 // Add global constants to the initial definitions. 614 // Add global constants to the initial definitions.
(...skipping 20 matching lines...) Expand all
430 } 635 }
431 } 636 }
432 637
433 // Initialize all locals with #null in the renaming environment. 638 // Initialize all locals with #null in the renaming environment.
434 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { 639 for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
435 env.Add(constant_null()); 640 env.Add(constant_null());
436 } 641 }
437 642
438 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0); 643 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0);
439 ASSERT(normal_entry != NULL); // Must have entry. 644 ASSERT(normal_entry != NULL); // Must have entry.
440 RenameRecursive(normal_entry, &env, live_phis); 645 RenameRecursive(normal_entry, &env, live_phis, variable_liveness);
441 } 646 }
442 647
443 648
444 void FlowGraph::RenameRecursive(BlockEntryInstr* block_entry, 649 void FlowGraph::RenameRecursive(BlockEntryInstr* block_entry,
445 GrowableArray<Definition*>* env, 650 GrowableArray<Definition*>* env,
446 GrowableArray<PhiInstr*>* live_phis) { 651 GrowableArray<PhiInstr*>* live_phis,
652 VariableLivenessAnalysis* variable_liveness) {
447 // 1. Process phis first. 653 // 1. Process phis first.
448 if (block_entry->IsJoinEntry()) { 654 if (block_entry->IsJoinEntry()) {
449 JoinEntryInstr* join = block_entry->AsJoinEntry(); 655 JoinEntryInstr* join = block_entry->AsJoinEntry();
450 if (join->phis() != NULL) { 656 if (join->phis() != NULL) {
451 for (intptr_t i = 0; i < join->phis()->length(); ++i) { 657 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
452 PhiInstr* phi = (*join->phis())[i]; 658 PhiInstr* phi = (*join->phis())[i];
453 if (phi != NULL) { 659 if (phi != NULL) {
454 (*env)[i] = phi; 660 (*env)[i] = phi;
455 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. 661 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
456 } 662 }
457 } 663 }
458 } 664 }
459 } 665 }
460 666
461 // 2. Process normal instructions. 667 // 2. Process normal instructions.
462 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { 668 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
463 Instruction* current = it.Current(); 669 Instruction* current = it.Current();
464 // Attach current environment to the instructions that can deoptimize and 670 // Attach current environment to the instructions that can deoptimize and
465 // at goto instructions. Optimizations like LICM expect an environment at 671 // at goto instructions. Optimizations like LICM expect an environment at
466 // gotos. 672 // gotos.
467 if (current->CanDeoptimize() || current->IsGoto()) { 673 if (current->CanDeoptimize() ||
674 current->IsGoto() ||
675 (current->IsBranch() &&
Kevin Millikin (Google) 2013/03/22 11:57:52 This still seems kind of fiddly. Could we just ma
Vyacheslav Egorov (Google) 2013/03/22 12:16:15 Discussed offline. Will postpone it to another cha
676 current->AsBranch()->comparison()->IsStrictCompare())) {
468 Environment* deopt_env = 677 Environment* deopt_env =
469 Environment::From(*env, 678 Environment::From(*env,
470 num_non_copied_params_, 679 num_non_copied_params_,
471 parsed_function_.function()); 680 parsed_function_.function());
472 current->SetEnvironment(deopt_env); 681 current->SetEnvironment(deopt_env);
473 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { 682 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) {
474 Value* use = it.CurrentValue(); 683 Value* use = it.CurrentValue();
475 use->definition()->AddEnvUse(use); 684 use->definition()->AddEnvUse(use);
476 } 685 }
477 } 686 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 718
510 // 2b. Handle LoadLocal and StoreLocal. 719 // 2b. Handle LoadLocal and StoreLocal.
511 // For each LoadLocal: Remove it from the graph. 720 // For each LoadLocal: Remove it from the graph.
512 // For each StoreLocal: Remove it from the graph and update the environment. 721 // For each StoreLocal: Remove it from the graph and update the environment.
513 Definition* definition = current->AsDefinition(); 722 Definition* definition = current->AsDefinition();
514 if (definition != NULL) { 723 if (definition != NULL) {
515 LoadLocalInstr* load = definition->AsLoadLocal(); 724 LoadLocalInstr* load = definition->AsLoadLocal();
516 StoreLocalInstr* store = definition->AsStoreLocal(); 725 StoreLocalInstr* store = definition->AsStoreLocal();
517 if ((load != NULL) || (store != NULL)) { 726 if ((load != NULL) || (store != NULL)) {
518 intptr_t index; 727 intptr_t index;
728 Definition* result;
519 if (store != NULL) { 729 if (store != NULL) {
730 // Update renaming environment.
520 index = store->local().BitIndexIn(num_non_copied_params_); 731 index = store->local().BitIndexIn(num_non_copied_params_);
521 // Update renaming environment. 732 result = store->value()->definition();
522 (*env)[index] = store->value()->definition(); 733
734 if (variable_liveness->IsStoreAlive(block_entry, store)) {
735 (*env)[index] = result;
736 } else {
737 (*env)[index] = constant_null();
738 }
523 } else { 739 } else {
524 // The graph construction ensures we do not have an unused LoadLocal 740 // The graph construction ensures we do not have an unused LoadLocal
525 // computation. 741 // computation.
526 ASSERT(definition->is_used()); 742 ASSERT(definition->is_used());
527 index = load->local().BitIndexIn(num_non_copied_params_); 743 index = load->local().BitIndexIn(num_non_copied_params_);
744 result = (*env)[index];
528 745
529 PhiInstr* phi = (*env)[index]->AsPhi(); 746 PhiInstr* phi = result->AsPhi();
530 if ((phi != NULL) && !phi->is_alive()) { 747 if ((phi != NULL) && !phi->is_alive()) {
531 phi->mark_alive(); 748 phi->mark_alive();
532 live_phis->Add(phi); 749 live_phis->Add(phi);
533 } 750 }
751
752 if (variable_liveness->IsLastLoad(block_entry, load)) {
753 (*env)[index] = constant_null();
754 }
534 } 755 }
535 // Update expression stack or remove from graph. 756 // Update expression stack or remove from graph.
536 if (definition->is_used()) { 757 if (definition->is_used()) {
537 env->Add((*env)[index]); 758 env->Add(result);
538 // We remove load/store instructions when we find their use in 2a. 759 // We remove load/store instructions when we find their use in 2a.
539 } else { 760 } else {
540 it.RemoveCurrentFromGraph(); 761 it.RemoveCurrentFromGraph();
541 } 762 }
542 } else { 763 } else {
543 // Not a load or store. 764 // Not a load or store.
544 if (definition->is_used()) { 765 if (definition->is_used()) {
545 // Assign fresh SSA temporary and update expression stack. 766 // Assign fresh SSA temporary and update expression stack.
546 definition->set_ssa_temp_index(alloc_ssa_temp_index()); 767 definition->set_ssa_temp_index(alloc_ssa_temp_index());
547 env->Add(definition); 768 env->Add(definition);
548 } 769 }
549 } 770 }
550 } 771 }
551 772
552 // 2c. Handle pushed argument. 773 // 2c. Handle pushed argument.
553 PushArgumentInstr* push = current->AsPushArgument(); 774 PushArgumentInstr* push = current->AsPushArgument();
554 if (push != NULL) { 775 if (push != NULL) {
555 env->Add(push); 776 env->Add(push);
556 } 777 }
557 } 778 }
558 779
559 // 3. Process dominated blocks. 780 // 3. Process dominated blocks.
560 for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) { 781 for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) {
561 BlockEntryInstr* block = block_entry->dominated_blocks()[i]; 782 BlockEntryInstr* block = block_entry->dominated_blocks()[i];
562 GrowableArray<Definition*> new_env(env->length()); 783 GrowableArray<Definition*> new_env(env->length());
563 new_env.AddArray(*env); 784 new_env.AddArray(*env);
564 RenameRecursive(block, &new_env, live_phis); 785 RenameRecursive(block, &new_env, live_phis, variable_liveness);
565 } 786 }
566 787
567 // 4. Process successor block. We have edge-split form, so that only blocks 788 // 4. Process successor block. We have edge-split form, so that only blocks
568 // with one successor can have a join block as successor. 789 // with one successor can have a join block as successor.
569 if ((block_entry->last_instruction()->SuccessorCount() == 1) && 790 if ((block_entry->last_instruction()->SuccessorCount() == 1) &&
570 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { 791 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) {
571 JoinEntryInstr* successor = 792 JoinEntryInstr* successor =
572 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry(); 793 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry();
573 intptr_t pred_index = successor->IndexOfPredecessor(block_entry); 794 intptr_t pred_index = successor->IndexOfPredecessor(block_entry);
574 ASSERT(pred_index >= 0); 795 ASSERT(pred_index >= 0);
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 if (!found) { 946 if (!found) {
726 result->Add(field); 947 result->Add(field);
727 } 948 }
728 } 949 }
729 } 950 }
730 951
731 return result; 952 return result;
732 } 953 }
733 954
734 } // namespace dart 955 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698