Chromium Code Reviews| Index: runtime/vm/flow_graph_builder.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_builder.cc (revision 33044) |
| +++ runtime/vm/flow_graph_builder.cc (working copy) |
| @@ -2225,133 +2225,135 @@ |
| ReturnDefinition(new ConstantInstr(closure)); |
| return; |
| } |
| - if (function.IsNonImplicitClosureFunction()) { |
| - // The context scope may have already been set by the non-optimizing |
| - // compiler. If it was not, set it here. |
| - if (function.context_scope() == ContextScope::null()) { |
| - const ContextScope& context_scope = ContextScope::ZoneHandle( |
| - node->scope()->PreserveOuterScope(owner()->context_level())); |
| - ASSERT(!function.HasCode()); |
| - ASSERT(function.context_scope() == ContextScope::null()); |
| - function.set_context_scope(context_scope); |
| - const Class& cls = Class::Handle( |
| - owner()->parsed_function()->function().Owner()); |
| - // The closure is now properly setup, add it to the lookup table. |
| + const bool is_implicit = function.IsImplicitInstanceClosureFunction(); |
| + ASSERT(is_implicit || function.IsNonImplicitClosureFunction()); |
| + // The context scope may have already been set by the non-optimizing |
| + // compiler. If it was not, set it here. |
| + if (function.context_scope() == ContextScope::null()) { |
| + ASSERT(!is_implicit); |
| + const ContextScope& context_scope = ContextScope::ZoneHandle( |
| + node->scope()->PreserveOuterScope(owner()->context_level())); |
| + ASSERT(!function.HasCode()); |
| + ASSERT(function.context_scope() == ContextScope::null()); |
| + function.set_context_scope(context_scope); |
| + const Class& cls = Class::Handle( |
| + owner()->parsed_function()->function().Owner()); |
| + // The closure is now properly setup, add it to the lookup table. |
| #if DEBUG |
| - const Function& found_func = Function::Handle( |
| - cls.LookupClosureFunction(function.token_pos())); |
| - ASSERT(found_func.IsNull() || |
| - (found_func.token_pos() != function.token_pos()) || |
| - // TODO(hausner): The following check should not be necessary. |
| - // Since we only lookup based on the token_pos we can get |
| - // duplicate entries due to closurized and non-closurized parent |
| - // functions (see Parser::ParseFunctionStatement). |
| - // We need two ways to lookup in this cache: One way to cache the |
| - // appropriate closure function and one way to find the functions |
| - // while debugging (we might need to set breakpoints in multiple |
| - // different function for a single token index.) |
| - (found_func.parent_function() != function.parent_function())); |
| + const Function& found_func = Function::Handle( |
| + cls.LookupClosureFunction(function.token_pos())); |
| + ASSERT(found_func.IsNull() || |
| + (found_func.token_pos() != function.token_pos()) || |
| + // TODO(hausner): The following check should not be necessary. |
| + // Since we only lookup based on the token_pos we can get |
| + // duplicate entries due to closurized and non-closurized parent |
| + // functions (see Parser::ParseFunctionStatement). |
| + // We need two ways to lookup in this cache: One way to cache the |
| + // appropriate closure function and one way to find the functions |
| + // while debugging (we might need to set breakpoints in multiple |
| + // different function for a single token index.) |
| + (found_func.parent_function() != function.parent_function())); |
| #endif // DEBUG |
| - cls.AddClosureFunction(function); |
| - } |
| - ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| - new ZoneGrowableArray<PushArgumentInstr*>(2); |
| - ASSERT(function.context_scope() != ContextScope::null()); |
| + cls.AddClosureFunction(function); |
| + } |
| + ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| + new ZoneGrowableArray<PushArgumentInstr*>(1); |
| + ASSERT(function.context_scope() != ContextScope::null()); |
| - // The function type of a closure may have type arguments. In that case, |
| - // pass the type arguments of the instantiator. |
| - const Class& cls = Class::ZoneHandle(function.signature_class()); |
| - ASSERT(!cls.IsNull()); |
| - const bool requires_type_arguments = cls.NumTypeArguments() > 0; |
| - Value* type_arguments = NULL; |
| - if (requires_type_arguments) { |
| - ASSERT(cls.type_arguments_field_offset() == |
| - Closure::type_arguments_offset()); |
| - const Class& instantiator_class = Class::Handle( |
| - owner()->parsed_function()->function().Owner()); |
| - type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), |
| - instantiator_class, |
| - NULL); |
| - arguments->Add(PushArgument(type_arguments)); |
| - } |
| - AllocateObjectInstr* alloc = new AllocateObjectInstr(node->token_pos(), |
| - cls, |
| - arguments); |
| - alloc->set_closure_function(function); |
| + // The function type of a closure may have type arguments. In that case, |
| + // pass the type arguments of the instantiator. |
| + const Class& cls = Class::ZoneHandle(function.signature_class()); |
| + ASSERT(!cls.IsNull()); |
| + const bool requires_type_arguments = cls.NumTypeArguments() > 0; |
| + Value* type_arguments = NULL; |
| + if (requires_type_arguments) { |
| + ASSERT(cls.type_arguments_field_offset() == |
| + Closure::type_arguments_offset()); |
| + ASSERT(cls.instance_size() == Closure::InstanceSize()); |
| + const Class& instantiator_class = Class::Handle( |
| + owner()->parsed_function()->function().Owner()); |
| + type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), |
| + instantiator_class, |
| + NULL); |
| + arguments->Add(PushArgument(type_arguments)); |
| + } |
| + AllocateObjectInstr* alloc = new AllocateObjectInstr(node->token_pos(), |
| + cls, |
| + arguments); |
| + alloc->set_closure_function(function); |
| - // Create fake fields for function and context. Only the context field is |
| - // stored at the allocation to be used later when inlining a closure call. |
| - const Field& function_field = |
| - Field::ZoneHandle( |
| - Field::New(Symbols::ClosureFunctionField(), |
| - false, // !static |
| - false, // !final |
| - false, // !const |
| - alloc->cls(), |
| - 0)); // No token position. |
| - function_field.SetOffset(Closure::function_offset()); |
| - const Field& context_field = |
| - Field::ZoneHandle(Field::New( |
| - Symbols::ClosureContextField(), |
| - false, // !static |
| - false, // !final |
| - false, // !const |
| - alloc->cls(), |
| - 0)); // No token position. |
| - context_field.SetOffset(Closure::context_offset()); |
| - alloc->set_context_field(context_field); |
| + // Create fake fields for function and context. Only the context field is |
| + // stored at the allocation to be used later when inlining a closure call. |
| + const Field& function_field = |
|
Ivan Posva
2014/02/26 05:16:02
In a separate CL we should make these singletons i
Florian Schneider
2014/02/26 11:46:07
I would just allocate one instance per compilation
Ivan Posva
2014/02/27 18:12:34
Florian, the code below is technically wrong. The
|
| + Field::ZoneHandle( |
| + Field::New(Symbols::ClosureFunctionField(), |
| + false, // !static |
| + false, // !final |
| + false, // !const |
| + alloc->cls(), |
| + 0)); // No token position. |
| + function_field.SetOffset(Closure::function_offset()); |
| + const Field& context_field = |
| + Field::ZoneHandle(Field::New( |
| + Symbols::ClosureContextField(), |
| + false, // !static |
| + false, // !final |
| + false, // !const |
| + alloc->cls(), |
| + 0)); // No token position. |
| + context_field.SetOffset(Closure::context_offset()); |
| + alloc->set_context_field(context_field); |
| - Value* closure_val = Bind(alloc); |
| - { LocalVariable* tmp_var = EnterTempLocalScope(closure_val); |
| - // Store function. |
| - Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); |
| - Value* func_val = |
| - Bind(new ConstantInstr(Function::ZoneHandle(function.raw()))); |
| - Do(new StoreInstanceFieldInstr(function_field, |
| - tmp_val, |
| - func_val, |
| - kEmitStoreBarrier)); |
| - // Store current context. |
| - tmp_val = Bind(new LoadLocalInstr(*tmp_var)); |
| + Value* closure_val = Bind(alloc); |
| + { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val); |
| + // Store function. |
| + Value* closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); |
| + Value* func_val = |
| + Bind(new ConstantInstr(Function::ZoneHandle(function.raw()))); |
| + Do(new StoreInstanceFieldInstr(function_field, |
| + closure_tmp_val, |
| + func_val, |
| + kEmitStoreBarrier)); |
| + if (is_implicit) { |
| + // Create new context containing the receiver. |
| + const intptr_t kNumContextVariables = 1; // The receiver. |
| + Value* allocated_context = |
| + Bind(new AllocateContextInstr(node->token_pos(), |
| + kNumContextVariables)); |
| + { LocalVariable* context_tmp_var = EnterTempLocalScope(allocated_context); |
| + // First operand (receiver). |
| + ValueGraphVisitor for_receiver(owner()); |
| + node->receiver()->Visit(&for_receiver); |
| + Append(for_receiver); |
| + Value* receiver = for_receiver.value(); |
| + |
| + // Second operand (context). |
| + Value* context_tmp_val = Bind(new LoadLocalInstr(*context_tmp_var)); |
| + |
| + // Store receiver in context. |
| + Do(new StoreVMFieldInstr(context_tmp_val, |
| + Context::variable_offset(0), |
| + receiver, |
| + Type::ZoneHandle())); |
| + // Store new context in closure. |
| + closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); |
| + context_tmp_val = Bind(new LoadLocalInstr(*context_tmp_var)); |
| + Do(new StoreInstanceFieldInstr(context_field, |
| + closure_tmp_val, |
| + context_tmp_val, |
| + kEmitStoreBarrier)); |
| + Do(ExitTempLocalScope(context_tmp_var)); |
| + } |
| + } else { |
| + // Store current context in closure. |
| + closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); |
| Value* context = Bind(new CurrentContextInstr()); |
| Do(new StoreInstanceFieldInstr(context_field, |
| - tmp_val, |
| + closure_tmp_val, |
| context, |
| kEmitStoreBarrier)); |
| - ReturnDefinition(ExitTempLocalScope(tmp_var)); |
| } |
| - } else { |
| - ASSERT(function.IsImplicitInstanceClosureFunction()); |
| - ValueGraphVisitor for_receiver(owner()); |
| - node->receiver()->Visit(&for_receiver); |
| - Append(for_receiver); |
| - Value* receiver = for_receiver.value(); |
| - |
| - PushArgumentInstr* push_receiver = PushArgument(receiver); |
| - ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| - new ZoneGrowableArray<PushArgumentInstr*>(2); |
| - arguments->Add(push_receiver); |
| - ASSERT(function.context_scope() != ContextScope::null()); |
| - |
| - // The function type of a closure may have type arguments. In that case, |
| - // pass the type arguments of the instantiator. Otherwise, pass null object. |
| - const Class& cls = Class::Handle(function.signature_class()); |
| - ASSERT(!cls.IsNull()); |
| - const bool requires_type_arguments = cls.NumTypeArguments() > 0; |
| - Value* type_arguments = NULL; |
| - if (requires_type_arguments) { |
| - const Class& instantiator_class = Class::Handle( |
| - owner()->parsed_function()->function().Owner()); |
| - type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), |
| - instantiator_class, |
| - NULL); |
| - } else { |
| - type_arguments = BuildNullValue(); |
| - } |
| - PushArgumentInstr* push_type_arguments = PushArgument(type_arguments); |
| - arguments->Add(push_type_arguments); |
| - ReturnDefinition( |
| - new CreateClosureInstr(node->function(), arguments, node->token_pos())); |
| + ReturnDefinition(ExitTempLocalScope(closure_tmp_var)); |
| } |
| } |