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..aed1f6bb3b1d931840592d9edee0d83488cf30aa 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); |
@@ -2551,6 +2551,7 @@ void ValueGraphVisitor::VisitInstanceCallNode(InstanceCallNode* node) { |
void EffectGraphVisitor::VisitInstanceCallNode(InstanceCallNode* node) { |
if (node->is_conditional()) { |
+ ASSERT(node->arguments()->type_args_len() == 0); |
ValueGraphVisitor for_receiver(owner()); |
node->receiver()->Visit(&for_receiver); |
Append(for_receiver); |
@@ -2600,7 +2601,6 @@ void EffectGraphVisitor::BuildClosureCall(ClosureCallNode* node, |
ZoneGrowableArray<PushArgumentInstr*>* arguments = |
new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
node->arguments()->LengthWithTypeArgs() + 1); |
- BuildPushTypeArguments(*node->arguments(), arguments); |
ValueGraphVisitor for_closure(owner()); |
node->closure()->Visit(&for_closure); |
@@ -2608,6 +2608,7 @@ void EffectGraphVisitor::BuildClosureCall(ClosureCallNode* node, |
Value* closure_value = for_closure.value(); |
LocalVariable* tmp_var = EnterTempLocalScope(closure_value); |
+ BuildPushTypeArguments(*node->arguments(), arguments); |
Value* closure_val = |
Bind(new (Z) LoadLocalInstr(*tmp_var, node->token_pos())); |
PushArgumentInstr* push_closure = PushArgument(closure_val); |
@@ -3896,6 +3897,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 (FLAG_reify_generic_functions && is_top_level_sequence && |
+ 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 Library& dart_internal = |
+ Library::Handle(Z, Library::InternalLibrary()); |
+ const Function& prepend_function = |
+ Function::ZoneHandle(Z, dart_internal.LookupFunctionAllowPrivate( |
+ 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(); |