Chromium Code Reviews| Index: runtime/vm/flow_graph_builder.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_builder.cc (revision 5781) |
| +++ runtime/vm/flow_graph_builder.cc (working copy) |
| @@ -166,6 +166,23 @@ |
| } |
| } |
| + intptr_t current_context_level = owner()->context_level(); |
| + 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)); |
| + } else { |
| + while (current_context_level-- > 0) { |
| + UnchainContext(); |
| + } |
| + } |
| + |
| + |
| AddInstruction(new ReturnInstr(return_value, node->token_index())); |
| CloseFragment(); |
| } |
| @@ -387,14 +404,15 @@ |
| // because its value is not needed. |
| // 1. Load the value. |
| - LoadLocalComp* load = new LoadLocalComp(node->local()); |
| + LoadLocalComp* load = new LoadLocalComp(node->local(), |
| + owner()->context_level()); |
| AddInstruction(new BindInstr(temp_index(), load)); |
| // 2. Increment. |
| BuildIncrOpIncrement(node->kind(), node->id(), node->token_index(), |
| temp_index() + 1); |
| // 3. Perform the store, resulting in the new value. |
| - StoreLocalComp* store = |
| - new StoreLocalComp(node->local(), new TempVal(temp_index())); |
| + StoreLocalComp* store = new StoreLocalComp( |
| + node->local(), new TempVal(temp_index()), owner()->context_level()); |
| ReturnComputation(store); |
| } |
| @@ -410,7 +428,8 @@ |
| // result. |
| // |
| // 1. Load the value. |
| - LoadLocalComp* load = new LoadLocalComp(node->local()); |
| + LoadLocalComp* load = new LoadLocalComp(node->local(), |
| + owner()->context_level()); |
| AddInstruction(new BindInstr(temp_index(), load)); |
| // 2. Duplicate it to increment. |
| AddInstruction(new PickTempInstr(temp_index() + 1, temp_index())); |
| @@ -418,8 +437,8 @@ |
| BuildIncrOpIncrement(node->kind(), node->id(), node->token_index(), |
| temp_index() + 2); |
| // 4. Perform the store and return the original value. |
| - StoreLocalComp* store = |
| - new StoreLocalComp(node->local(), new TempVal(temp_index() + 1)); |
| + StoreLocalComp* store = new StoreLocalComp( |
| + node->local(), new TempVal(temp_index() + 1), owner()->context_level()); |
| AddInstruction(new DoInstr(store)); |
| ReturnValue(new TempVal(AllocateTempIndex())); |
| } |
| @@ -725,7 +744,8 @@ |
| TargetEntryInstr* back_target_entry = new TargetEntryInstr(); |
| *for_test.true_successor_address() = back_target_entry; |
| back_target_entry->SetSuccessor(join); |
| - exit_ = *for_test.false_successor_address() = new TargetEntryInstr(); |
| + exit_ = |
| + *for_test.false_successor_address() = new TargetEntryInstr(); |
| } |
| @@ -800,9 +820,8 @@ |
| int next_index = temp_index(); |
| if (function.IsNonImplicitClosureFunction()) { |
| - const int context_level = 0; // Only because we don't handle nesting yet. |
| const ContextScope& context_scope = ContextScope::ZoneHandle( |
| - node->scope()->PreserveOuterScope(context_level)); |
| + node->scope()->PreserveOuterScope(owner()->context_level())); |
| ASSERT(!function.HasCode()); |
| ASSERT(function.context_scope() == ContextScope::null()); |
| function.set_context_scope(context_scope); |
| @@ -1156,13 +1175,17 @@ |
| return; |
| } |
| + |
| void ValueGraphVisitor::VisitLoadLocalNode(LoadLocalNode* node) { |
| - LoadLocalComp* load = new LoadLocalComp(node->local()); |
| + LoadLocalComp* load = new LoadLocalComp(node->local(), |
| + owner()->context_level()); |
| ReturnComputation(load); |
| } |
| + |
| void TestGraphVisitor::VisitLoadLocalNode(LoadLocalNode* node) { |
| - LoadLocalComp* load = new LoadLocalComp(node->local()); |
| + LoadLocalComp* load = new LoadLocalComp(node->local(), |
| + owner()->context_level()); |
| ReturnComputation(load); |
| } |
| @@ -1182,7 +1205,8 @@ |
| value = new TempVal(temp_index()); |
| } |
| - StoreLocalComp* store = new StoreLocalComp(node->local(), value); |
| + StoreLocalComp* store = |
| + new StoreLocalComp(node->local(), value, owner()->context_level()); |
| ReturnComputation(store); |
| } |
| @@ -1280,6 +1304,23 @@ |
| } |
| +bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { |
| + return (node == owner()->parsed_function().node_sequence()) && |
| + (owner()->parsed_function().saved_context_var() != NULL); |
| +} |
| + |
| + |
| +void EffectGraphVisitor::UnchainContext() { |
| + AddInstruction(new BindInstr(temp_index(), new CurrentContextComp())); |
| + TempVal* temp_ctx = new TempVal(temp_index()); |
| + NativeLoadFieldComp* load = new NativeLoadFieldComp( |
| + temp_ctx, Context::parent_offset()); |
| + AddInstruction(new BindInstr(temp_index(), load)); |
| + TempVal* parent_ctx = new TempVal(temp_index()); |
| + AddInstruction(new DoInstr(new StoreContextComp(parent_ctx))); |
| +} |
| + |
| + |
| // <Statement> ::= Sequence { scope: LocalScope |
| // nodes: <Statement>* |
| // label: SourceLabel } |
| @@ -1291,9 +1332,76 @@ |
| if (num_context_variables > 0) { |
| // The loop local scope declares variables that are captured. |
| // Allocate and chain a new context. |
| - // Allocate context computation. |
| - // Chain Context computation (maybe introduce a new variable). |
| - Bailout("Sequence needs a context. Gotta have a context."); |
| + // Allocate context computation (uses current CTX) |
| + AllocateContextComp* comp = new AllocateContextComp(node->token_index(), |
| + num_context_variables); |
| + AddInstruction(new BindInstr(temp_index(), comp)); |
| + Value* allocated_context_value = new TempVal(temp_index()); |
| + |
| + // If this node_sequence is the body of the function being compiled, and if |
| + // this function is not a closure, do not link the current context as the |
| + // parent of the newly allocated context, as it is not accessible. Instead, |
| + // save it in a pre-allocated variable and restore it on exit. |
| + if (MustSaveRestoreContext(node)) { |
| + AddInstruction(new BindInstr(temp_index() + 1, new CurrentContextComp())); |
| + StoreLocalComp* store_local = new StoreLocalComp( |
| + *owner()->parsed_function().saved_context_var(), |
| + new TempVal(temp_index() + 1), |
| + 0); |
| + AddInstruction(new DoInstr(store_local)); |
| + StoreContextComp* store_context = |
| + new StoreContextComp(new ConstantVal(Object::ZoneHandle())); |
| + AddInstruction(new DoInstr(store_context)); |
| + } |
| + |
| + ChainContextComp* chain_context = new ChainContextComp( |
| + allocated_context_value); |
| + AddInstruction(new DoInstr(chain_context)); |
| + owner()->set_context_level(scope->context_level()); |
| + |
| + // If this node_sequence is the body of the function being compiled, copy |
| + // the captured parameters from the frame into the context. |
| + if (node == owner()->parsed_function().node_sequence()) { |
| + ASSERT(scope->context_level() == 1); |
| + const Immediate raw_null = |
| + Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| + const Function& function = owner()->parsed_function().function(); |
| + const int num_params = function.NumberOfParameters(); |
| + int param_frame_index = |
| + (num_params == function.num_fixed_parameters()) ? 1 + num_params : -1; |
| + for (int pos = 0; pos < num_params; param_frame_index--, pos++) { |
| + const LocalVariable& parameter = *scope->VariableAt(pos); |
| + ASSERT(parameter.owner() == scope); |
| + if (parameter.is_captured()) { |
| + // Create a temporary local describing the original position. |
| + const String& temp_name = String::ZoneHandle(String::Concat( |
| + parameter.name(), String::Handle(String::NewSymbol("-orig")))); |
| + LocalVariable* temp_local = new LocalVariable( |
| + 0, // Token index. |
| + temp_name, |
| + Type::ZoneHandle(Type::DynamicType())); // Type. |
| + temp_local->set_index(param_frame_index); |
| + |
| + // Copy parameter from local frame to current context. |
| + LoadLocalComp* load_comp = new LoadLocalComp( |
| + *temp_local, owner()->context_level()); |
| + AddInstruction(new BindInstr(temp_index(), load_comp)); |
| + StoreLocalComp* store_local = new StoreLocalComp( |
| + parameter, |
| + new TempVal(temp_index()), |
| + owner()->context_level()); |
| + AddInstruction(new DoInstr(store_local)); |
| + // Write NULL to the source location to detect buggy accesses and |
| + // allow GC of passed value if it gets overwritten by a new value in |
| + // the function. |
| + StoreLocalComp* clear_local = new StoreLocalComp( |
| + *temp_local, |
| + new ConstantVal(Object::ZoneHandle()), |
| + owner()->context_level()); |
| + AddInstruction(new DoInstr(clear_local)); |
| + } |
| + } |
| + } |
| } |
| if (FLAG_enable_type_checks && |
| @@ -1307,6 +1415,27 @@ |
| node->NodeAt(i++)->Visit(&for_effect); |
| Append(for_effect); |
| } |
| + |
| + 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)); |
| + } else if (num_context_variables > 0) { |
| + UnchainContext(); |
| + } |
| + } |
| + |
| + // If this node sequence is labeled, a break out of the sequence will have |
| + // taken care of unchaining the context. |
| + if (node->label() != NULL) { |
| + // TODO(srdjan): Check that the break label is bound? Is this a jump? |
| + Bailout("VisitSequenceNode bind break and unchain CTX"); |
| + } |
| owner()->set_context_level(previous_context_level); |
| } |
| @@ -1474,14 +1603,15 @@ |
| void FlowGraphPrinter::VisitLoadLocal(LoadLocalComp* comp) { |
| - OS::Print("LoadLocal(%s)", comp->local().name().ToCString()); |
| + OS::Print("LoadLocal(%s lvl:%d)", |
| + comp->local().name().ToCString(), comp->context_level()); |
| } |
| void FlowGraphPrinter::VisitStoreLocal(StoreLocalComp* comp) { |
| OS::Print("StoreLocal(%s, ", comp->local().name().ToCString()); |
| comp->value()->Accept(this); |
| - OS::Print(")"); |
| + OS::Print(", lvl: %d)", comp->context_level()); |
| } |
| @@ -1622,6 +1752,25 @@ |
| } |
| +void FlowGraphPrinter::VisitAllocateContext(AllocateContextComp* comp) { |
| + OS::Print("AllocateContext(%d)", comp->num_context_variables()); |
| +} |
| + |
| + |
| +void FlowGraphPrinter::VisitChainContext(ChainContextComp* comp) { |
| + OS::Print("ChainContext("); |
| + comp->context_value()->Accept(this); |
| + OS::Print(")"); |
| +} |
| + |
| + |
| +void FlowGraphPrinter::VisitStoreContext(StoreContextComp* comp) { |
| + OS::Print("StoreContext("); |
| + comp->value()->Accept(this); |
| + OS::Print(")"); |
| +} |
| + |
| + |
| void FlowGraphPrinter::VisitJoinEntry(JoinEntryInstr* instr) { |
| OS::Print("%2d: [join]", reverse_index(instr->postorder_number())); |
| } |
| @@ -1807,7 +1956,8 @@ |
| void FlowGraphBuilder::Bailout(const char* reason) { |
| const char* kFormat = "FlowGraphBuilder Bailout: %s %s"; |
| - const char* function_name = parsed_function_.function().ToCString(); |
| + const char* function_name = |
| + parsed_function_.function().ToCString(); |
|
regis
2012/03/23 20:50:25
New line not needed.
srdjan
2012/03/23 21:22:19
Done.
|
| intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| char* chars = reinterpret_cast<char*>( |
| Isolate::Current()->current_zone()->Allocate(len)); |