Index: runtime/vm/code_generator_ia32.cc |
=================================================================== |
--- runtime/vm/code_generator_ia32.cc (revision 415) |
+++ runtime/vm/code_generator_ia32.cc (working copy) |
@@ -845,6 +845,7 @@ |
} |
+// TODO(regis): Consider merging all 3 closure node flavors into a single one. |
void CodeGenerator::VisitClosureNode(ClosureNode* node) { |
const int current_context_level = state()->context_level(); |
const ContextScope& context_scope = ContextScope::ZoneHandle( |
@@ -854,10 +855,21 @@ |
ASSERT(!function.HasCode()); |
ASSERT(function.context_scope() == ContextScope::null()); |
function.set_context_scope(context_scope); |
+ // The function type of a closure may be parameterized. In that case, pass |
+ // the type arguments of the instantiator. |
+ const Class& cls = Class::Handle(function.signature_class()); |
+ ASSERT(!cls.IsNull()); |
+ const bool is_cls_parameterized = cls.IsParameterized(); |
+ if (is_cls_parameterized) { |
+ GenerateInstantiatorTypeArguments(); |
+ } |
const Code& stub = Code::Handle( |
StubCode::GetAllocationStubForClosure(function)); |
const ExternalLabel label(function.ToCString(), stub.EntryPoint()); |
GenerateCall(node->token_index(), &label); |
+ if (is_cls_parameterized) { |
+ __ popl(ECX); // Pop type arguments. |
+ } |
if (IsResultNeeded(node)) { |
__ pushl(EAX); |
} |
@@ -885,10 +897,21 @@ |
ASSERT(function.IsImplicitInstanceClosureFunction()); |
ASSERT(function.context_scope() != ContextScope::null()); |
node->receiver()->Visit(this); |
+ // The function type of a closure may be parameterized. In that case, pass |
+ // the type arguments of the instantiator. |
+ const Class& cls = Class::Handle(function.signature_class()); |
+ ASSERT(!cls.IsNull()); |
+ const bool is_cls_parameterized = cls.IsParameterized(); |
+ if (is_cls_parameterized) { |
+ GenerateInstantiatorTypeArguments(); |
+ } |
const Code& stub = Code::Handle( |
StubCode::GetAllocationStubForClosure(function)); |
const ExternalLabel label(function.ToCString(), stub.EntryPoint()); |
GenerateCall(node->token_index(), &label); |
+ if (is_cls_parameterized) { |
+ __ popl(ECX); // Pop type arguments. |
+ } |
__ popl(ECX); // Pop receiver. |
if (IsResultNeeded(node)) { |
__ pushl(EAX); |
@@ -1436,24 +1459,9 @@ |
__ pushl(EAX); // Push the instance. |
__ PushObject(type); // Push the type. |
if (!type.IsInstantiated()) { |
- ASSERT(parsed_function().instantiator() != NULL); |
- parsed_function().instantiator()->Visit(this); // Instantiator on stack. |
- if (!parsed_function().function().IsInFactoryScope()) { |
- __ popl(EAX); // Pop instantiator. |
- const Class& instantiator_class = |
- Class::Handle(parsed_function().function().owner()); |
- // The instantiator is the receiver of the caller, which is not a factory. |
- // The receiver cannot be null; extract its TypeArguments object. |
- // Note that in the factory case, the instantiator is the first parameter |
- // of the factory, i.e. already a TypeArguments object. |
- intptr_t type_arguments_instance_field_offset = |
- instantiator_class.type_arguments_instance_field_offset(); |
- ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); |
- __ movl(EAX, FieldAddress(EAX, type_arguments_instance_field_offset)); |
- __ pushl(EAX); // Push instantiator. |
- } |
+ GenerateInstantiatorTypeArguments(); |
} else { |
- __ PushObject(TypeArguments::ZoneHandle()); // Null instantiator. |
+ __ pushl(raw_null); // Null instantiator. |
} |
GenerateCallRuntime(token_index, kInstanceofRuntimeEntry); |
// Pop the two parameters supplied to the runtime entry. The result of the |
@@ -1608,24 +1616,9 @@ |
__ pushl(EAX); // Push the source object. |
__ PushObject(dst_type); // Push the type of the destination. |
if (!dst_type.IsInstantiated()) { |
- ASSERT(parsed_function().instantiator() != NULL); |
- parsed_function().instantiator()->Visit(this); // Instantiator on stack. |
- if (!parsed_function().function().IsInFactoryScope()) { |
- __ popl(EAX); // Pop instantiator. |
- const Class& instantiator_class = |
- Class::Handle(parsed_function().function().owner()); |
- // The instantiator is the receiver of the caller, which is not a factory. |
- // The receiver cannot be null; extract its TypeArguments object. |
- // Note that in the factory case, the instantiator is the first parameter |
- // of the factory, i.e. already a TypeArguments object. |
- intptr_t type_arguments_instance_field_offset = |
- instantiator_class.type_arguments_instance_field_offset(); |
- ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); |
- __ movl(EAX, FieldAddress(EAX, type_arguments_instance_field_offset)); |
- __ pushl(EAX); // Push instantiator. |
- } |
+ GenerateInstantiatorTypeArguments(); |
} else { |
- __ PushObject(TypeArguments::ZoneHandle()); // Null instantiator. |
+ __ pushl(raw_null); // Null instantiator. |
} |
__ PushObject(dst_name); // Push the name of the destination. |
GenerateCallRuntime(token_index, kTypeCheckRuntimeEntry); |
@@ -2205,6 +2198,27 @@ |
} |
+// Pushes the type arguments of the instantiator on the stack. |
+void CodeGenerator::GenerateInstantiatorTypeArguments() { |
+ ASSERT(parsed_function().instantiator() != NULL); |
+ parsed_function().instantiator()->Visit(this); |
+ if (!parsed_function().function().IsInFactoryScope()) { |
+ __ popl(EAX); // Pop instantiator. |
+ const Class& instantiator_class = |
+ Class::Handle(parsed_function().function().owner()); |
+ // The instantiator is the receiver of the caller, which is not a factory. |
+ // The receiver cannot be null; extract its TypeArguments object. |
+ // Note that in the factory case, the instantiator is the first parameter |
+ // of the factory, i.e. already a TypeArguments object. |
+ intptr_t type_arguments_instance_field_offset = |
+ instantiator_class.type_arguments_instance_field_offset(); |
+ ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); |
+ __ movl(EAX, FieldAddress(EAX, type_arguments_instance_field_offset)); |
+ __ pushl(EAX); |
+ } |
+} |
+ |
+ |
// Pushes the type arguments on the stack in preparation of a constructor or |
// factory call. |
// For a factory call, instantiates (possibly requiring an additional run time |
@@ -2219,6 +2233,8 @@ |
// e.g. class A extends Array<int>. |
void CodeGenerator::GenerateTypeArguments(ConstructorCallNode* node, |
bool is_cls_parameterized) { |
+ const Immediate raw_null = |
+ Immediate(reinterpret_cast<intptr_t>(Object::null())); |
// Instantiate the type arguments if necessary. |
if (node->type_arguments().IsNull() || |
node->type_arguments().IsInstantiated()) { |
@@ -2227,33 +2243,18 @@ |
__ PushObject(node->type_arguments()); |
if (!node->constructor().IsFactory()) { |
// The allocator additionally requires the instantiator type arguments. |
- __ PushObject(TypeArguments::ZoneHandle()); // Null instantiator. |
+ __ pushl(raw_null); // Null instantiator. |
} |
} |
} else { |
// The type arguments are uninstantiated. |
- ASSERT(parsed_function().instantiator() != NULL); |
ASSERT(node->constructor().IsFactory() || is_cls_parameterized); |
- parsed_function().instantiator()->Visit(this); |
+ GenerateInstantiatorTypeArguments(); |
__ popl(EAX); // Pop instantiator. |
- if (!parsed_function().function().IsInFactoryScope()) { |
- const Class& instantiator_class = |
- Class::Handle(parsed_function().function().owner()); |
- // The instantiator is the receiver of the caller, which is not a factory. |
- // The receiver cannot be null; extract its TypeArguments object. |
- // Note that in the factory case, the instantiator is the first parameter |
- // of the factory, i.e. already a TypeArguments object. |
- intptr_t type_arguments_instance_field_offset = |
- instantiator_class.type_arguments_instance_field_offset(); |
- ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); |
- __ movl(EAX, FieldAddress(EAX, type_arguments_instance_field_offset)); |
- } |
// EAX is the instantiator TypeArguments object (or null). |
// If EAX is null, no need to instantiate the type arguments, use null, and |
// allocate an object of a raw type. |
Label type_arguments_instantiated, type_arguments_uninstantiated; |
- const Immediate raw_null = |
- Immediate(reinterpret_cast<intptr_t>(Object::null())); |
__ cmpl(EAX, raw_null); |
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
@@ -2294,7 +2295,7 @@ |
__ Bind(&type_arguments_instantiated); |
__ pushl(EAX); // Instantiated type arguments. |
- __ PushObject(TypeArguments::ZoneHandle()); // Null instantiator. |
+ __ pushl(raw_null); // Null instantiator. |
__ Bind(&type_arguments_pushed); |
} |
} |