Chromium Code Reviews| Index: runtime/vm/kernel_to_il.cc |
| diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc |
| index 1130320dcf1afbdfa98ba157d685267494722cf6..63e590a1624d7d3e10586680aec4f44247192679 100644 |
| --- a/runtime/vm/kernel_to_il.cc |
| +++ b/runtime/vm/kernel_to_il.cc |
| @@ -329,6 +329,7 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() { |
| switch (function.kind()) { |
| case RawFunction::kClosureFunction: |
| + case RawFunction::kConvertedClosureFunction: |
| case RawFunction::kRegularFunction: |
| case RawFunction::kGetterFunction: |
| case RawFunction::kSetterFunction: |
| @@ -350,6 +351,9 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() { |
| Symbols::ClosureParameter(), AbstractType::dynamic_type()); |
| variable->set_is_forced_stack(); |
| scope_->InsertParameterAt(pos++, variable); |
| + } else if (function.IsConvertedClosureFunction()) { |
| + // Do nothing. The explicit context parameter is already included into |
| + // the parameter list of the parent function. |
| } else if (!function.is_static()) { |
| // We use [is_static] instead of [IsStaticFunction] because the latter |
| // returns `false` for constructors. |
| @@ -384,10 +388,14 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() { |
| } |
| AddParameters(node, pos); |
| - // We generate a syntethic body for implicit closure functions - which |
| - // will forward the call to the real function. |
| + // We generate a syntethic body for implicit closure functions and |
| + // converted |
| + // closure functions - which will forward the call to the real function. |
| // -> see BuildGraphOfImplicitClosureFunction |
| - if (!function.IsImplicitClosureFunction()) { |
| + // -> see BuildGraphOfConvertedClosureFunction |
| + |
| + if (!function.IsImplicitClosureFunction() && |
| + !function.IsConvertedClosureFunction()) { |
| // TODO(jensj): HACK: Push the begin token to after any parameters to |
| // avoid crash when breaking on definition line of async method in |
| // debugger. It seems that another scope needs to be added |
| @@ -3201,6 +3209,7 @@ FlowGraph* FlowGraphBuilder::BuildGraph() { |
| switch (function.kind()) { |
| case RawFunction::kClosureFunction: |
| + case RawFunction::kConvertedClosureFunction: |
| case RawFunction::kRegularFunction: |
| case RawFunction::kGetterFunction: |
| case RawFunction::kSetterFunction: { |
| @@ -3209,10 +3218,13 @@ FlowGraph* FlowGraphBuilder::BuildGraph() { |
| : FunctionNode::Cast(node_); |
| ActiveFunctionScope active_function_scope(&active_class_, |
| kernel_function); |
| - return function.IsImplicitClosureFunction() |
| - ? BuildGraphOfImplicitClosureFunction(kernel_function, |
| - function) |
| - : BuildGraphOfFunction(kernel_function); |
| + if (function.IsImplicitClosureFunction()) { |
| + return BuildGraphOfImplicitClosureFunction(kernel_function, function); |
| + } else if (function.IsConvertedClosureFunction()) { |
| + return BuildGraphOfConvertedClosureFunction(kernel_function, function); |
| + } else { |
| + return BuildGraphOfFunction(kernel_function); |
| + } |
| } |
| case RawFunction::kConstructor: { |
| bool is_factory = function.IsFactory(); |
| @@ -4028,6 +4040,64 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( |
| } |
| +// This method follows the logic similar to that of |
| +// FlowGraphBuilder::BuildGraphOfImplicitClosureFunction. For additional |
| +// details on converted closure functions, please, see the comment on the method |
| +// Function::ConvertedClosureFunction. |
| +FlowGraph* FlowGraphBuilder::BuildGraphOfConvertedClosureFunction( |
| + FunctionNode* kernel_function, |
| + const Function& function) { |
| + const Function& target = Function::ZoneHandle(Z, function.parent_function()); |
| + |
| + TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| + graph_entry_ = new (Z) |
| + GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| + SetupDefaultParameterValues(kernel_function); |
| + |
| + Fragment body(normal_entry); |
| + body += CheckStackOverflowInPrologue(); |
| + |
| + // Load all the arguments. |
| + ASSERT(target.is_static()); |
| + // The first argument is the value that the target function is converted over. |
| + // It is stored in the context field of the Closure class instance. The |
| + // instance is passed as the first argument to the call. |
| + body += LoadLocal(parsed_function_->node_sequence()->scope()->VariableAt(0)); |
| + body += LoadField(Closure::context_offset()); |
| + body += PushArgument(); |
| + |
| + // The rest of the parameters are the same for the method of the Closure class |
| + // being invoked and the top-level target function. |
| + intptr_t positional_argument_count = |
| + kernel_function->positional_parameters().length(); |
| + for (intptr_t i = 1; i < positional_argument_count; i++) { |
| + body += |
| + LoadLocal(LookupVariable(kernel_function->positional_parameters()[i])); |
| + body += PushArgument(); |
| + } |
| + intptr_t named_argument_count = kernel_function->named_parameters().length(); |
| + Array& argument_names = Array::ZoneHandle(Z); |
| + if (named_argument_count > 0) { |
| + argument_names = Array::New(named_argument_count); |
| + for (intptr_t i = 0; i < named_argument_count; i++) { |
| + VariableDeclaration* variable = kernel_function->named_parameters()[i]; |
| + body += LoadLocal(LookupVariable(variable)); |
| + body += PushArgument(); |
| + argument_names.SetAt(i, H.DartSymbol(variable->name())); |
| + } |
| + } |
| + // Forward them to the target. |
| + intptr_t argument_count = positional_argument_count + named_argument_count; |
| + body += StaticCall(TokenPosition::kNoSource, target, argument_count, |
| + argument_names); |
| + |
| + // Return the result. |
| + body += Return(kernel_function->end_position()); |
| + |
| + return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| +} |
| + |
| + |
| FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( |
| const Function& function) { |
| // This function is specialized for a receiver class, a method name, and |
| @@ -4731,6 +4801,11 @@ void DartTypeTranslator::VisitVoidType(VoidType* node) { |
| } |
| +void DartTypeTranslator::VisitVectorType(VectorType* node) { |
| + result_ = Object::vector_type().raw(); |
| +} |
| + |
| + |
| void DartTypeTranslator::VisitBottomType(BottomType* node) { |
| result_ = |
| dart::Class::Handle(Z, I->object_store()->null_class()).CanonicalType(); |
| @@ -5659,6 +5734,89 @@ void FlowGraphBuilder::VisitRethrow(Rethrow* node) { |
| } |
| +void FlowGraphBuilder::VisitVectorCreation(VectorCreation* node) { |
| + ASSERT(node->value() > 0); |
|
jensj
2017/05/18 11:19:06
STREAM_EXPRESSION_IF_POSSIBLE(node); ? (the same f
Dmitry Stefantsov
2017/05/18 12:18:53
Yep, that explains why the code worked without the
|
| + Fragment instructions = AllocateContext(node->value()); |
| + fragment_ = instructions; |
| +} |
| + |
| + |
| +void FlowGraphBuilder::VisitVectorGet(VectorGet* node) { |
| + Fragment instructions; |
| + |
| + instructions += TranslateExpression(node->vector_expression()); |
| + instructions += LoadField(Context::variable_offset(node->index())); |
| + |
| + fragment_ = instructions; |
| +} |
| + |
| + |
| +void FlowGraphBuilder::VisitVectorSet(VectorSet* node) { |
| + Fragment instructions; |
| + |
| + instructions += TranslateExpression(node->vector_expression()); |
| + instructions += TranslateExpression(node->value()); |
| + LocalVariable* result = MakeTemporary(); |
| + |
| + Value* value = Pop(); |
| + StoreInstanceFieldInstr* store = new (Z) |
| + StoreInstanceFieldInstr(Context::variable_offset(node->index()), Pop(), |
| + value, kNoStoreBarrier, TokenPosition::kNoSource); |
| + instructions <<= store; |
| + |
| + // Result of a vector-set operation is its rhs. It is useful, especially for |
| + // assignment chains. |
| + instructions += LoadLocal(result); |
| + |
| + fragment_ = instructions; |
| +} |
| + |
| + |
| +void FlowGraphBuilder::VisitVectorCopy(VectorCopy* node) { |
| + Fragment instructions; |
| + |
| + instructions += TranslateExpression(node->vector_expression()); |
| + CloneContextInstr* clone_instruction = |
| + new (Z) CloneContextInstr(TokenPosition::kNoSource, Pop()); |
| + instructions <<= clone_instruction; |
| + Push(clone_instruction); |
| + |
| + fragment_ = instructions; |
| +} |
| + |
| + |
| +void FlowGraphBuilder::VisitClosureCreation(ClosureCreation* node) { |
| + Fragment instructions; |
| + |
| + Function& function = Function::ZoneHandle( |
| + Z, H.LookupStaticMethodByKernelProcedure(node->top_level_function())); |
| + function = function.ConvertedClosureFunction(); |
| + ASSERT(!function.IsNull()); |
| + |
| + const dart::Class& closure_class = |
| + dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
| + instructions += AllocateObject(closure_class, function); |
| + LocalVariable* closure = MakeTemporary(); |
| + |
| + instructions += TranslateExpression(node->context_vector()); |
| + LocalVariable* context = MakeTemporary(); |
| + |
| + instructions += LoadLocal(closure); |
| + instructions += Constant(function); |
| + instructions += |
| + StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); |
| + |
| + instructions += LoadLocal(closure); |
| + instructions += LoadLocal(context); |
| + instructions += |
| + StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); |
| + |
| + instructions += Drop(); |
| + |
| + fragment_ = instructions; |
| +} |
| + |
| + |
| Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, |
| Array* argument_names) { |
| Fragment instructions; |