Index: runtime/vm/stub_code_ia32.cc |
=================================================================== |
--- runtime/vm/stub_code_ia32.cc (revision 355) |
+++ runtime/vm/stub_code_ia32.cc (working copy) |
@@ -1240,20 +1240,37 @@ |
} |
-static void ClosureAllocationStub(Assembler* assembler, |
- const Function& func, |
- bool is_static_implicit_closure) { |
+// Called for inline allocation of closures. |
+// Input parameters: |
+// ESP + 4 : receiver (only if non-static implicit closure). |
+// ESP : points to return address. |
+// Uses EAX, EBX, ECX, EDX as temporary registers. |
+void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
+ const Function& func) { |
+ const intptr_t kReceiverOffset = 1 * kWordSize; |
const Immediate raw_null = |
Immediate(reinterpret_cast<intptr_t>(Object::null())); |
- intptr_t instance_size = Closure::InstanceSize(); |
- if (FLAG_inline_alloc && PageSpace::IsPageAllocatableSize(instance_size)) { |
+ ASSERT(func.IsClosureFunction()); |
+ const bool is_implicit_static_closure = |
+ func.IsImplicitStaticClosureFunction(); |
+ const bool is_implicit_instance_closure = |
+ func.IsImplicitInstanceClosureFunction(); |
+ const intptr_t closure_size = Closure::InstanceSize(); |
+ const intptr_t context_size = Context::InstanceSize(1); // Captured receiver. |
+ if (FLAG_inline_alloc && |
+ PageSpace::IsPageAllocatableSize(closure_size + context_size)) { |
const Class& cls = Class::ZoneHandle(func.signature_class()); |
Label slow_case; |
Heap* heap = Isolate::Current()->heap(); |
__ movl(EAX, Address::Absolute(heap->TopAddress())); |
- __ leal(EBX, Address(EAX, instance_size)); |
+ __ leal(EBX, Address(EAX, closure_size)); |
+ if (is_implicit_instance_closure) { |
+ __ movl(ECX, EBX); // ECX: new context address. |
+ __ addl(EBX, Immediate(context_size)); |
+ } |
// Check if the allocation fits into the remaining space. |
- // EAX: potential new object. |
+ // EAX: potential new closure object. |
+ // ECX: potential new context object (only if is_implicit_closure). |
// EBX: potential next object start. |
__ cmpl(EBX, Address::Absolute(heap->EndAddress())); |
__ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); |
@@ -1263,24 +1280,49 @@ |
__ movl(Address::Absolute(heap->TopAddress()), EBX); |
// Initialize the class field in the object. |
- // EAX: new object. |
- // EBX: next object start. |
- __ LoadObject(ECX, cls); // Load signature class of closure. |
- __ movl(Address(EAX, Closure::class_offset()), ECX); |
+ // EAX: new closure object. |
+ // ECX: new context object (only if is_implicit_closure). |
+ __ LoadObject(EDX, cls); // Load signature class of closure. |
+ __ movl(Address(EAX, Closure::class_offset()), EDX); |
// Initialize the function field in the object. |
- // EAX: new object. |
+ // EAX: new closure object. |
+ // ECX: new context object (only if is_implicit_closure). |
// EBX: next object start. |
- __ LoadObject(ECX, func); // Load function of closure to be allocated. |
- __ movl(Address(EAX, Closure::function_offset()), ECX); |
+ __ LoadObject(EDX, func); // Load function of closure to be allocated. |
+ __ movl(Address(EAX, Closure::function_offset()), EDX); |
// Setup the context for this closure. |
- if (is_static_implicit_closure) { |
+ if (is_implicit_static_closure) { |
ObjectStore* object_store = Isolate::Current()->object_store(); |
ASSERT(object_store != NULL); |
const Context& empty_context = |
Context::ZoneHandle(object_store->empty_context()); |
- __ LoadObject(ECX, empty_context); |
+ __ LoadObject(EDX, empty_context); |
+ __ movl(Address(EAX, Closure::context_offset()), EDX); |
+ } else if (is_implicit_instance_closure) { |
+ // Initialize the new context capturing the receiver. |
+ |
+ // Set the class field to the Context class. |
+ __ LoadObject(EBX, Class::ZoneHandle(Object::context_class())); |
+ __ movl(Address(ECX, Context::class_offset()), EBX); |
+ |
+ // Set number of variables field to 1 (for captured receiver). |
+ __ movl(Address(ECX, Context::num_variables_offset()), Immediate(1)); |
+ |
+ // Set isolate field to isolate of current context. |
+ __ movl(EDX, FieldAddress(CTX, Context::isolate_offset())); |
+ __ movl(Address(ECX, Context::isolate_offset()), EDX); |
+ |
+ // Set the parent field to null. |
+ __ movl(Address(ECX, Context::parent_offset()), raw_null); |
+ |
+ // Initialize the context variable to the receiver. |
+ __ movl(EDX, Address(ESP, kReceiverOffset)); |
+ __ movl(Address(ECX, Context::variable_offset(0)), EDX); |
+ |
+ // Set the newly allocated context in the newly allocated closure. |
+ __ addl(ECX, Immediate(kHeapObjectTag)); |
__ movl(Address(EAX, Closure::context_offset()), ECX); |
} else { |
__ movl(Address(EAX, Closure::context_offset()), CTX); |
@@ -1297,14 +1339,22 @@ |
__ Bind(&slow_case); |
} |
+ if (is_implicit_instance_closure) { |
+ __ movl(EAX, Address(ESP, kReceiverOffset)); |
+ } |
// Create a stub frame. |
__ EnterFrame(0); |
const Closure& new_closure = Closure::ZoneHandle(); |
__ PushObject(new_closure); // Push Null closure for return value. |
__ PushObject(func); |
- if (is_static_implicit_closure) { |
- __ CallRuntimeFromStub(kAllocateStaticImplicitClosureRuntimeEntry); |
+ if (is_implicit_static_closure) { |
+ __ CallRuntimeFromStub(kAllocateImplicitStaticClosureRuntimeEntry); |
+ } else if (is_implicit_instance_closure) { |
+ __ pushl(EAX); // Receiver. |
+ __ CallRuntimeFromStub(kAllocateImplicitInstanceClosureRuntimeEntry); |
+ __ popl(EAX); // Pop receiver. |
} else { |
+ ASSERT(func.IsNonImplicitClosureFunction()); |
__ CallRuntimeFromStub(kAllocateClosureRuntimeEntry); |
} |
__ popl(EAX); // Pop function object. |
@@ -1316,26 +1366,6 @@ |
} |
-// Called for inline allocation of closures. |
-// Input parameters: |
-// Uses EAX, EBX, ECX as temporary registers. |
-void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
- const Function& func) { |
- static const bool kIsNotStaticImplicitClosure = false; |
- ClosureAllocationStub(assembler, func, kIsNotStaticImplicitClosure); |
-} |
- |
- |
-// Called for inline allocation of implicit closures. |
-// Input parameters: |
-// Uses EAX, EBX, ECX as temporary registers. |
-void StubCode::GenerateAllocationStubForStaticImplicitClosure( |
- Assembler* assembler, const Function& func) { |
- static const bool kIsStaticImplicitClosure = true; |
- ClosureAllocationStub(assembler, func, kIsStaticImplicitClosure); |
-} |
- |
- |
// Called for invoking noSuchMethod function from the entry code of a dart |
// function after an error in passed named arguments is detected. |
// Input parameters: |