Chromium Code Reviews| Index: runtime/vm/flow_graph_builder.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_builder.cc (revision 6367) |
| +++ runtime/vm/flow_graph_builder.cc (working copy) |
| @@ -5,6 +5,7 @@ |
| #include "vm/flow_graph_builder.h" |
| #include "vm/ast_printer.h" |
| +#include "vm/code_descriptors.h" |
| #include "vm/dart_entry.h" |
| #include "vm/flags.h" |
| #include "vm/intermediate_language.h" |
| @@ -21,6 +22,22 @@ |
| DECLARE_FLAG(bool, enable_type_checks); |
| DECLARE_FLAG(bool, print_ast); |
| + |
| +FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) |
| + : parsed_function_(parsed_function), |
| + preorder_block_entries_(), |
| + postorder_block_entries_(), |
| + context_level_(0), |
| + last_used_try_index_(CatchClauseNode::kInvalidTryIndex), |
| + try_index_(CatchClauseNode::kInvalidTryIndex), |
| + catch_entries_() {} |
| + |
| + |
| +void FlowGraphBuilder::AddCatchEntry(intptr_t try_index, Instruction* entry) { |
| + catch_entries_.Add(entry); |
| +} |
| + |
| + |
| void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| ASSERT(is_open()); |
| if (other_fragment.is_empty()) return; |
| @@ -117,6 +134,31 @@ |
| } |
| +// Stores current context into the 'variable' |
| +void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable, |
| + intptr_t start_index) { |
| + AddInstruction(new BindInstr(start_index, new CurrentContextComp())); |
| + StoreLocalComp* store_context = new StoreLocalComp( |
| + variable, |
| + new TempVal(start_index), |
| + owner()->context_level()); |
| + AddInstruction(new DoInstr(store_context)); |
| +} |
| + |
| + |
| +// Loads context saved in 'context_variable' into the current context. |
| +void EffectGraphVisitor::BuildLoadContext( |
| + const LocalVariable& context_variable, intptr_t start_index) { |
|
regis
2012/04/10 22:58:24
Should you also call the variable in BuildStoreCon
srdjan
2012/04/10 23:11:58
-> variable
|
| + LoadLocalComp* load_saved_context = |
| + new LoadLocalComp(context_variable, owner()->context_level()); |
| + AddInstruction(new BindInstr(start_index, load_saved_context)); |
| + StoreContextComp* store_context = |
| + new StoreContextComp(new TempVal(start_index)); |
| + AddInstruction(new DoInstr(store_context)); |
| +} |
| + |
| + |
| + |
| void TestGraphVisitor::ReturnValue(Value* value) { |
| BranchInstr* branch = new BranchInstr(value); |
| AddInstruction(branch); |
| @@ -178,12 +220,7 @@ |
| ASSERT(current_context_level >= 0); |
| if (owner()->parsed_function().saved_context_var() != NULL) { |
| // CTX on entry was saved, but not linked as context parent. |
| - LoadLocalComp* load_comp = |
| - new LoadLocalComp(*owner()->parsed_function().saved_context_var(), 0); |
| - AddInstruction(new BindInstr(temp_index(), load_comp)); |
| - TempVal* local_value = new TempVal(temp_index()); |
| - StoreContextComp* store_context = new StoreContextComp(local_value); |
| - AddInstruction(new DoInstr(store_context)); |
| + BuildLoadContext(*owner()->parsed_function().saved_context_var(), 0); |
| } else { |
| while (current_context_level-- > 0) { |
| UnchainContext(); |
| @@ -258,9 +295,13 @@ |
| arguments->Add(for_left_value.value()); |
| arguments->Add(for_right_value.value()); |
| const String& name = String::ZoneHandle(String::NewSymbol(node->Name())); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 2); |
| + InstanceCallComp* call = new InstanceCallComp(node->id(), |
| + node->token_index(), |
| + owner()->try_index(), |
| + name, |
| + arguments, |
| + Array::ZoneHandle(), |
| + 2); |
| ReturnComputation(call); |
| } |
| @@ -377,6 +418,7 @@ |
| TranslateArgumentList(*interpol_arg, temp_index(), values); |
| StaticCallComp* call = |
| new StaticCallComp(node->token_index(), |
| + owner()->try_index(), |
| interpol_func, |
| interpol_arg->names(), |
| values); |
| @@ -395,6 +437,7 @@ |
| InstanceOfComp* instance_of = new InstanceOfComp( |
| node->id(), |
| node->token_index(), |
| + owner()->try_index(), |
| for_left_value.value(), |
| node->right()->AsTypeNode()->type(), |
| (node->kind() == Token::kISNOT)); |
| @@ -428,9 +471,9 @@ |
| // Boolean negation '!' cannot be overloaded neither. |
| if (node->kind() == Token::kNE) { |
| const String& name = String::ZoneHandle(String::NewSymbol("==")); |
| - InstanceCallComp* call_equal = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 2); |
| + InstanceCallComp* call_equal = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), name, |
| + arguments, Array::ZoneHandle(), 2); |
| AddInstruction(new BindInstr(temp_index(), call_equal)); |
| Value* eq_result = new TempVal(temp_index()); |
| if (FLAG_enable_type_checks) { |
| @@ -440,9 +483,9 @@ |
| ReturnComputation(negate); |
| } else { |
| const String& name = String::ZoneHandle(String::NewSymbol(node->Name())); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 2); |
| + InstanceCallComp* call = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), name, |
| + arguments, Array::ZoneHandle(), 2); |
| ReturnComputation(call); |
| } |
| } |
| @@ -470,9 +513,9 @@ |
| String::ZoneHandle(String::NewSymbol((node->kind() == Token::kSUB) |
| ? Token::Str(Token::kNEGATE) |
| : node->Name())); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* call = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), name, |
| + arguments, Array::ZoneHandle(), 1); |
| ReturnComputation(call); |
| } |
| @@ -541,9 +584,9 @@ |
| String::ZoneHandle(Field::GetterSymbol(node->field_name())); |
| ZoneGrowableArray<Value*>* arguments = new ZoneGrowableArray<Value*>(1); |
| arguments->Add(new TempVal(next_index)); |
| - InstanceCallComp* load = |
| - new InstanceCallComp(node->getter_id(), node->token_index(), getter_name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* load = new InstanceCallComp( |
| + node->getter_id(), node->token_index(), owner()->try_index(), |
| + getter_name, arguments, Array::ZoneHandle(), 1); |
| AddInstruction(new BindInstr(next_index, load)); |
| return next_index; |
| @@ -565,9 +608,9 @@ |
| arguments->Add(new TempVal(start_index)); |
| const String& op_name = |
| String::ZoneHandle(String::NewSymbol((kind == Token::kINCR) ? "+" : "-")); |
| - InstanceCallComp* add = |
| - new InstanceCallComp(node_id, token_index, op_name, |
| - arguments, Array::ZoneHandle(), 2); |
| + InstanceCallComp* add = new InstanceCallComp( |
| + node_id, token_index, owner()->try_index(), op_name, |
| + arguments, Array::ZoneHandle(), 2); |
| AddInstruction(new BindInstr(start_index - 1, add)); |
| } |
| @@ -585,7 +628,9 @@ |
| value_index + 1); |
| // 3. Perform the store, returning the stored value. |
| InstanceSetterComp* store = |
| - new InstanceSetterComp(node->setter_id(), node->token_index(), |
| + new InstanceSetterComp(node->setter_id(), |
| + node->token_index(), |
| + owner()->try_index(), |
| node->field_name(), |
| new TempVal(value_index - 1), |
| new TempVal(value_index)); |
| @@ -620,9 +665,9 @@ |
| ZoneGrowableArray<Value*>* arguments = new ZoneGrowableArray<Value*>(2); |
| arguments->Add(new TempVal(value_index - 1)); |
| arguments->Add(new TempVal(value_index)); |
| - InstanceCallComp* store = |
| - new InstanceCallComp(node->setter_id(), node->token_index(), |
| - setter_name, arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* store = new InstanceCallComp( |
| + node->setter_id(), node->token_index(), owner()->try_index(), |
| + setter_name, arguments, Array::ZoneHandle(), 1); |
| AddInstruction(new DoInstr(store)); |
| ReturnValue(new TempVal(AllocateTempIndex())); |
| } |
| @@ -654,9 +699,9 @@ |
| arguments->Add(new TempVal(next_index + 1)); |
| const String& load_name = |
| String::ZoneHandle(String::NewSymbol(Token::Str(Token::kINDEX))); |
| - InstanceCallComp* load = |
| - new InstanceCallComp(node->load_id(), node->token_index(), load_name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* load = new InstanceCallComp( |
| + node->load_id(), node->token_index(), owner()->try_index(), |
| + load_name, arguments, Array::ZoneHandle(), 1); |
| AddInstruction(new BindInstr(next_index, load)); |
| return next_index; |
| } |
| @@ -675,6 +720,7 @@ |
| // 3. Perform the store, returning the stored value. |
| StoreIndexedComp* store = new StoreIndexedComp(node->store_id(), |
| node->token_index(), |
| + owner()->try_index(), |
| new TempVal(value_index - 2), |
| new TempVal(value_index - 1), |
| new TempVal(value_index)); |
| @@ -709,9 +755,9 @@ |
| arguments->Add(new TempVal(value_index - 2)); |
| arguments->Add(new TempVal(value_index - 1)); |
| arguments->Add(new TempVal(value_index)); |
| - InstanceCallComp* store = |
| - new InstanceCallComp(node->store_id(), node->token_index(), store_name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* store = new InstanceCallComp( |
| + node->store_id(), node->token_index(), owner()->try_index(), |
| + store_name, arguments, Array::ZoneHandle(), 1); |
| AddInstruction(new DoInstr(store)); |
| ReturnValue(new TempVal(AllocateTempIndex())); |
| } |
| @@ -1156,7 +1202,9 @@ |
| values->Add(for_value.value()); |
| index = for_value.temp_index(); |
| } |
| - CreateArrayComp* create = new CreateArrayComp(node, values); |
| + CreateArrayComp* create = new CreateArrayComp(node, |
| + owner()->try_index(), |
| + values); |
| ReturnComputation(create); |
| } |
| @@ -1194,7 +1242,8 @@ |
| BuildInstantiatorTypeArguments(node->token_index(), temp_index()); |
| } |
| - CreateClosureComp* create = new CreateClosureComp(node, type_arguments); |
| + CreateClosureComp* create = |
| + new CreateClosureComp(node, owner()->try_index(), type_arguments); |
| ReturnComputation(create); |
| } |
| @@ -1223,9 +1272,9 @@ |
| values->Add(for_receiver.value()); |
| TranslateArgumentList(*arguments, for_receiver.temp_index(), values); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), |
| - node->function_name(), values, |
| + InstanceCallComp* call = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), |
| + node->function_name(), values, |
| arguments->names(), 1); |
| ReturnComputation(call); |
| } |
| @@ -1239,6 +1288,7 @@ |
| TranslateArgumentList(*node->arguments(), temp_index(), values); |
| StaticCallComp* call = |
| new StaticCallComp(node->token_index(), |
| + owner()->try_index(), |
| node->function(), |
| node->arguments()->names(), |
| values); |
| @@ -1260,8 +1310,10 @@ |
| arguments->Add(for_closure.value()); |
| TranslateArgumentList(*node->arguments(), temp_index() + 2, arguments); |
| // First operand is the saved context, consumed by the call. |
| - ClosureCallComp* call = |
| - new ClosureCallComp(node, new TempVal(temp_index()), arguments); |
| + ClosureCallComp* call = new ClosureCallComp(node, |
| + owner()->try_index(), |
| + new TempVal(temp_index()), |
| + arguments); |
| ReturnComputation(call); |
| } |
| @@ -1270,7 +1322,10 @@ |
| AddInstruction(new BindInstr(temp_index(), new CurrentContextComp())); |
| TempVal* ctx = new TempVal(temp_index()); |
| AddInstruction(new BindInstr(temp_index(), |
| - new CloneContextComp(node->id(), node->token_index(), ctx))); |
| + new CloneContextComp(node->id(), |
| + node->token_index(), |
| + owner()->try_index(), |
| + ctx))); |
| TempVal* cloned_ctx = new TempVal(temp_index()); |
| ReturnComputation(new StoreContextComp(cloned_ctx)); |
| } |
| @@ -1287,7 +1342,9 @@ |
| BuildConstructorTypeArguments(node, start_index, allocate_arguments); |
| } |
| AllocateObjectComp* alloc_comp = |
| - new AllocateObjectComp(node, allocate_arguments); |
| + new AllocateObjectComp(node, |
| + owner()->try_index(), |
| + allocate_arguments); |
| AddInstruction(new BindInstr(start_index, alloc_comp)); |
| return new TempVal(start_index); |
| } |
| @@ -1306,6 +1363,7 @@ |
| TranslateArgumentList(*node->arguments(), start_index + 1, values); |
| StaticCallComp* call = |
| new StaticCallComp(node->token_index(), |
| + owner()->try_index(), |
| node->constructor(), |
| node->arguments()->names(), |
| values); |
| @@ -1324,6 +1382,7 @@ |
| factory_arguments); |
| StaticCallComp* call = |
| new StaticCallComp(node->token_index(), |
| + owner()->try_index(), |
| node->constructor(), |
| node->arguments()->names(), |
| factory_arguments); |
| @@ -1399,7 +1458,9 @@ |
| Value* instantiator_value = |
| BuildInstantiatorTypeArguments(node->token_index(), start_index); |
| ExtractFactoryTypeArgumentsComp* extract = |
| - new ExtractFactoryTypeArgumentsComp(node, instantiator_value); |
| + new ExtractFactoryTypeArgumentsComp(node, |
| + owner()->try_index(), |
| + instantiator_value); |
| AddInstruction(new BindInstr(start_index, extract)); |
| return new TempVal(start_index); |
| } |
| @@ -1482,9 +1543,9 @@ |
| arguments->Add(for_receiver.value()); |
| const String& name = |
| String::ZoneHandle(Field::GetterSymbol(node->field_name())); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* call = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), name, |
| + arguments, Array::ZoneHandle(), 1); |
| ReturnComputation(call); |
| } |
| @@ -1496,11 +1557,13 @@ |
| ArgumentGraphVisitor for_value(owner(), for_receiver.temp_index()); |
| node->value()->Visit(&for_value); |
| Append(for_value); |
| - InstanceSetterComp* setter = new InstanceSetterComp(node->id(), |
| - node->token_index(), |
| - node->field_name(), |
| - for_receiver.value(), |
| - for_value.value()); |
| + InstanceSetterComp* setter = |
| + new InstanceSetterComp(node->id(), |
| + node->token_index(), |
| + owner()->try_index(), |
| + node->field_name(), |
| + for_receiver.value(), |
| + for_value.value()); |
| ReturnComputation(setter); |
| } |
| @@ -1513,6 +1576,7 @@ |
| ASSERT(!getter_function.IsNull()); |
| ZoneGrowableArray<Value*>* values = new ZoneGrowableArray<Value*>(); |
| StaticCallComp* call = new StaticCallComp(node->token_index(), |
| + owner()->try_index(), |
| getter_function, |
| Array::ZoneHandle(), // No names. |
| values); |
| @@ -1530,6 +1594,7 @@ |
| node->value()->Visit(&for_value); |
| Append(for_value); |
| StaticSetterComp* call = new StaticSetterComp(node->token_index(), |
| + owner()->try_index(), |
| setter_function, |
| for_value.value()); |
| ReturnComputation(call); |
| @@ -1537,7 +1602,8 @@ |
| void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { |
| - NativeCallComp* native_call = new NativeCallComp(node); |
| + NativeCallComp* native_call = |
| + new NativeCallComp(node, owner()->try_index()); |
| ReturnComputation(native_call); |
| } |
| @@ -1656,9 +1722,9 @@ |
| arguments->Add(for_index.value()); |
| const String& name = |
| String::ZoneHandle(String::NewSymbol(Token::Str(Token::kINDEX))); |
| - InstanceCallComp* call = |
| - new InstanceCallComp(node->id(), node->token_index(), name, |
| - arguments, Array::ZoneHandle(), 1); |
| + InstanceCallComp* call = new InstanceCallComp( |
| + node->id(), node->token_index(), owner()->try_index(), name, |
| + arguments, Array::ZoneHandle(), 1); |
| ReturnComputation(call); |
| } |
| @@ -1675,6 +1741,7 @@ |
| Append(for_value); |
| StoreIndexedComp* store = new StoreIndexedComp(node->id(), |
| node->token_index(), |
| + owner()->try_index(), |
| for_array.value(), |
| for_index.value(), |
| for_value.value()); |
| @@ -1711,8 +1778,10 @@ |
| // The loop local scope declares variables that are captured. |
| // Allocate and chain a new context. |
| // Allocate context computation (uses current CTX) |
| - AllocateContextComp* comp = new AllocateContextComp(node->token_index(), |
| - num_context_variables); |
| + AllocateContextComp* comp = new AllocateContextComp( |
| + node->token_index(), |
| + owner()->try_index(), |
| + num_context_variables); |
| AddInstruction(new BindInstr(temp_index(), comp)); |
| Value* allocated_context_value = new TempVal(temp_index()); |
| @@ -1801,12 +1870,7 @@ |
| if (is_open()) { |
| if (MustSaveRestoreContext(node)) { |
| ASSERT(num_context_variables > 0); |
| - LoadLocalComp* load_comp = |
| - new LoadLocalComp(*owner()->parsed_function().saved_context_var(), 0); |
| - AddInstruction(new BindInstr(temp_index(), load_comp)); |
| - TempVal* local_value = new TempVal(temp_index()); |
| - StoreContextComp* store_context = new StoreContextComp(local_value); |
| - AddInstruction(new DoInstr(store_context)); |
| + BuildLoadContext(*owner()->parsed_function().saved_context_var(), 0); |
| } else if (num_context_variables > 0) { |
| UnchainContext(); |
| } |
| @@ -1834,12 +1898,59 @@ |
| void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { |
| - Bailout("EffectGraphVisitor::VisitCatchClauseNode"); |
| + // NOTE: The implicit variables ':saved_context', ':exception_var' |
| + // and ':stacktrace_var' can never be captured variables. |
| + // Restores CTX from local variable ':saved_context'. |
| + CatchEntryComp* catch_entry = new CatchEntryComp(node->exception_var(), |
| + node->stacktrace_var()); |
| + AddInstruction(new DoInstr(catch_entry)); |
| + BuildLoadContext(node->context_var(), temp_index()); |
| + |
| + EffectGraphVisitor for_catch(owner(), temp_index()); |
| + node->VisitChildren(&for_catch); |
| + Append(for_catch); |
| } |
| void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { |
| - Bailout("EffectGraphVisitor::VisitTryCatchNode"); |
| + intptr_t old_try_index = owner()->try_index(); |
| + intptr_t try_index = owner()->allocate_try_index(); |
| + owner()->set_try_index(try_index); |
| + |
| + // Preserve CTX into local variable '%saved_context'. |
| + BuildStoreContext(node->context_var(), temp_index()); |
| + |
| + EffectGraphVisitor for_try_block(owner(), temp_index()); |
| + node->try_block()->Visit(&for_try_block); |
| + Append(for_try_block); |
| + |
| + // We are done generating code for the try block. |
| + owner()->set_try_index(old_try_index); |
| + |
| + CatchClauseNode* catch_block = node->catch_block(); |
| + if (catch_block != NULL) { |
| + // Set the corresponding try index for this catch block so |
| + // that we can set the appropriate handler pc when we generate |
| + // code for this catch block. |
| + catch_block->set_try_index(try_index); |
| + EffectGraphVisitor for_catch_block(owner(), temp_index()); |
| + for_catch_block.AddInstruction(new TargetEntryInstr(try_index)); |
| + catch_block->Visit(&for_catch_block); |
| + owner()->AddCatchEntry(try_index, for_catch_block.entry()); |
| + ASSERT(!for_catch_block.is_open()); |
| + if ((node->end_catch_label() != NULL) && |
| + (node->end_catch_label()->join_for_continue() != NULL)) { |
| + if (is_open()) { |
| + AddInstruction(node->end_catch_label()->join_for_continue()); |
| + } else { |
| + exit_ = node->end_catch_label()->join_for_continue(); |
| + } |
| + } |
| + } |
| + |
| + if (node->finally_block() != NULL) { |
| + Bailout("EffectGraphVisitor::VisitTryCatchNode finally"); |
| + } |
| } |
| @@ -1849,14 +1960,17 @@ |
| Append(for_exception); |
| Instruction* instr = NULL; |
| if (node->stacktrace() == NULL) { |
| - instr = new ThrowInstr( |
| - node->id(), node->token_index(), for_exception.value()); |
| + instr = new ThrowInstr(node->id(), |
| + node->token_index(), |
| + owner()->try_index(), |
| + for_exception.value()); |
| } else { |
| ValueGraphVisitor for_stack_trace(owner(), temp_index() + 1); |
| node->stacktrace()->Visit(&for_stack_trace); |
| Append(for_stack_trace); |
| instr = new ReThrowInstr(node->id(), |
| node->token_index(), |
| + owner()->try_index(), |
| for_exception.value(), |
| for_stack_trace.value()); |
| } |
| @@ -2183,6 +2297,12 @@ |
| } |
| +void FlowGraphPrinter::VisitCatchEntry(CatchEntryComp* comp) { |
| + OS::Print("CatchEntry(%s, %s)", comp->exception_var().name().ToCString(), |
| + comp->stacktrace_var().name().ToCString()); |
| +} |
| + |
| + |
| void FlowGraphPrinter::VisitStoreContext(StoreContextComp* comp) { |
| OS::Print("StoreContext("); |
| comp->value()->Accept(this); |
| @@ -2196,7 +2316,12 @@ |
| void FlowGraphPrinter::VisitTargetEntry(TargetEntryInstr* instr) { |
| - OS::Print("%2d: [target]", reverse_index(instr->postorder_number())); |
| + OS::Print("%2d: [target", reverse_index(instr->postorder_number())); |
| + if (instr->HasTryIndex()) { |
| + OS::Print(" catch %d]", instr->try_index()); |
| + } else { |
| + OS::Print("]"); |
| + } |
| } |
| @@ -2264,10 +2389,18 @@ |
| parsed_function().node_sequence()->Visit(&for_effect); |
| // Check that the graph is properly terminated. |
| ASSERT(!for_effect.is_open()); |
| + GrowableArray<intptr_t> parent; |
| + for (intptr_t i = 0; i < catch_entries_.length(); i++) { |
| + Instruction* entry = catch_entries_[i]; |
| + entry->DiscoverBlocks(NULL, // Entry block predecessor. |
| + &preorder_block_entries_, |
| + &postorder_block_entries_, |
| + &parent); |
| + ComputeDominators(&preorder_block_entries_, &parent); |
| + } |
| if (for_effect.entry() != NULL) { |
| // Perform a depth-first traversal of the graph to build preorder and |
| // postorder block orders. |
| - GrowableArray<intptr_t> parent; |
| for_effect.entry()->DiscoverBlocks(NULL, // Entry block predecessor. |
| &preorder_block_entries_, |
| &postorder_block_entries_, |