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; |