| Index: runtime/vm/flow_graph_builder.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_builder.cc (revision 5792)
|
| +++ 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()));
|
| }
|
| @@ -800,9 +819,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 +1174,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 +1204,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 +1303,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 +1331,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 +1414,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 +1602,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 +1751,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()));
|
| }
|
|
|