Chromium Code Reviews| Index: runtime/vm/flow_graph_builder.cc |
| diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc |
| index e0e279513ee5fb8b9c5235ee4263df3145460bbe..89bcf722459aadddb4a235e0d0694463b7fa480e 100644 |
| --- a/runtime/vm/flow_graph_builder.cc |
| +++ b/runtime/vm/flow_graph_builder.cc |
| @@ -2482,7 +2482,7 @@ void EffectGraphVisitor::BuildPushTypeArguments( |
| Bind(new (Z) LoadLocalInstr(*node.type_args_var(), node.token_pos())); |
| } else { |
| const TypeArguments& type_args = node.type_arguments(); |
| - ASSERT(!type_args.IsNull() && |
| + ASSERT(!type_args.IsNull() && type_args.IsCanonical() && |
| (type_args.Length() == node.type_args_len())); |
| type_args_val = |
| BuildInstantiatedTypeArguments(node.token_pos(), type_args); |
| @@ -3896,6 +3896,78 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
| } |
| } |
| + // Load the passed-in type argument vector from the temporary stack slot, |
| + // prepend the function type arguments of the generic parent function, and |
| + // store it to the final location, possibly in the context. |
| + if (is_top_level_sequence && FLAG_reify_generic_functions && |
|
Vyacheslav Egorov (Google)
2017/06/15 14:05:44
maybe reoder condition to be more logical, moving
regis
2017/06/15 21:38:26
Will do.
|
| + function.IsGeneric()) { |
| + const ParsedFunction& parsed_function = owner()->parsed_function(); |
| + LocalVariable* type_args_var = parsed_function.function_type_arguments(); |
| + ASSERT(type_args_var->owner() == scope); |
| + LocalVariable* parent_type_args_var = |
| + parsed_function.parent_type_arguments(); |
| + if (type_args_var->is_captured() || (parent_type_args_var != NULL)) { |
| + // Create a temporary local describing the original position. |
| + const String& temp_name = Symbols::TempParam(); |
| + LocalVariable* temp_local = |
| + new (Z) LocalVariable(TokenPosition::kNoSource, // Token index. |
| + TokenPosition::kNoSource, // Token index. |
| + temp_name, |
| + Object::dynamic_type()); // Type. |
| + temp_local->set_index(parsed_function.first_stack_local_index()); |
| + |
| + // Mark this local as captured parameter so that the optimizer |
| + // correctly handles these when compiling try-catch: Captured |
| + // parameters are not in the stack environment, therefore they |
| + // must be skipped when emitting sync-code in try-blocks. |
| + temp_local->set_is_captured_parameter(true); // TODO(regis): Correct? |
| + |
| + Value* type_args_val = |
| + Bind(BuildLoadLocal(*temp_local, node->token_pos())); |
| + if (parent_type_args_var != NULL) { |
| + ASSERT(parent_type_args_var->owner() != scope); |
| + // Call the runtime to concatenate both vectors. |
| + ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| + new (Z) ZoneGrowableArray<PushArgumentInstr*>(3); |
| + arguments->Add(PushArgument(type_args_val)); |
| + Value* parent_type_args_val = |
| + Bind(BuildLoadLocal(*parent_type_args_var, node->token_pos())); |
| + arguments->Add(PushArgument(parent_type_args_val)); |
| + Value* len_const = Bind(new (Z) ConstantInstr( |
| + Smi::ZoneHandle(Z, Smi::New(function.NumTypeParameters() + |
| + function.NumParentTypeParameters())))); |
| + arguments->Add(PushArgument(len_const)); |
| + const Class& cls = |
| + Class::Handle(Z, isolate()->object_store()->object_class()); |
| + const Function& prepend_function = |
| + Function::ZoneHandle(Z, cls.LookupStaticFunctionAllowPrivate( |
| + Symbols::PrependTypeArguments())); |
| + ASSERT(!prepend_function.IsNull()); |
| + const intptr_t kTypeArgsLen = 0; |
| + type_args_val = Bind(new (Z) StaticCallInstr( |
| + node->token_pos(), prepend_function, kTypeArgsLen, |
| + Object::null_array(), // No names. |
| + arguments, owner()->ic_data_array(), owner()->GetNextDeoptId())); |
| + } |
| + Do(BuildStoreLocal(*type_args_var, type_args_val, ST(node->token_pos()))); |
| + if (type_args_var->is_captured()) { |
| + // 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. |
| + Value* null_constant = |
| + Bind(new (Z) ConstantInstr(Object::ZoneHandle(Z, Object::null()))); |
| + Do(BuildStoreLocal(*temp_local, null_constant, ST(node->token_pos()))); |
| + } else { |
| + // Do not write NULL, since the temp is also the final location. |
| + ASSERT(temp_local->index() == type_args_var->index()); |
| + } |
| + } else { |
| + // The type args slot is the final location. No copy needed. |
| + ASSERT(type_args_var->index() == |
| + parsed_function.first_stack_local_index()); |
| + } |
| + } |
| + |
| if (FLAG_causal_async_stacks && is_top_level_sequence && |
| (function.IsAsyncClosure() || function.IsAsyncGenClosure())) { |
| LocalScope* top_scope = node->scope(); |