Index: bleeding_edge/src/ia32/codegen-ia32.cc |
=================================================================== |
--- bleeding_edge/src/ia32/codegen-ia32.cc (revision 3473) |
+++ bleeding_edge/src/ia32/codegen-ia32.cc (working copy) |
@@ -3593,18 +3593,28 @@ |
void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
- // Call the runtime to instantiate the function boilerplate object. |
- // The inevitable call will sync frame elements to memory anyway, so |
- // we do it eagerly to allow us to push the arguments directly into |
- // place. |
ASSERT(boilerplate->IsBoilerplate()); |
- frame_->SyncRange(0, frame_->element_count() - 1); |
- // Create a new closure. |
- frame_->EmitPush(esi); |
- frame_->EmitPush(Immediate(boilerplate)); |
- Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); |
- frame_->Push(&result); |
+ // Use the fast case closure allocation code that allocated in new |
Mads Ager (chromium)
2009/12/16 16:13:24
allocated -> allocates
|
+ // space when for nested functions that don't need literals cloning. |
bakster
2009/12/16 15:40:38
remove when
|
+ if (scope()->is_function_scope() && boilerplate->NumberOfLiterals() == 0) { |
+ FastNewClosureStub stub; |
+ frame_->Push(boilerplate); |
+ Result answer = frame_->CallStub(&stub, 1); |
+ frame_->Push(&answer); |
+ } else { |
+ // Call the runtime to instantiate the function boilerplate |
+ // object. The inevitable call will sync frame elements to memory |
+ // anyway, so we do it eagerly to allow us to push the arguments |
+ // directly into place. |
+ frame_->SyncRange(0, frame_->element_count() - 1); |
+ |
+ // Create a new closure. |
+ frame_->EmitPush(esi); |
+ frame_->EmitPush(Immediate(boilerplate)); |
+ Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); |
+ frame_->Push(&result); |
+ } |
} |
@@ -6537,6 +6547,49 @@ |
} |
+void FastNewClosureStub::Generate(MacroAssembler* masm) { |
+ // Clone the boilerplate in new space. Set the context to the |
+ // current context in esi. |
+ Label gc; |
+ __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT); |
+ |
+ // Get the boilerplate function from the stack. |
+ __ mov(edx, Operand(esp, 1 * kPointerSize)); |
+ |
+ // Compute the function map in the current global context and set that |
+ // as the map of the allocated object. |
+ __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
+ __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
+ __ mov(ecx, Operand(ecx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX))); |
+ __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); |
+ |
+ // Clone the rest of the boilerplate fields. We don't have to update |
+ // the write barrier because the allocated object is in new space. |
+ for (int offset = kPointerSize; |
+ offset < JSFunction::kSize; |
+ offset += kPointerSize) { |
+ if (offset == JSFunction::kContextOffset) { |
+ __ mov(FieldOperand(eax, offset), esi); |
+ } else { |
+ __ mov(ebx, FieldOperand(edx, offset)); |
+ __ mov(FieldOperand(eax, offset), ebx); |
+ } |
+ } |
+ |
+ // Return and remove the on-stack parameter. |
+ __ ret(1 * kPointerSize); |
+ |
+ // Create a new closure through the slower runtime call. |
+ __ bind(&gc); |
+ __ pop(ecx); // Temporarily remove return address. |
+ __ pop(edx); |
+ __ push(esi); |
+ __ push(edx); |
+ __ push(ecx); // Restore return address. |
+ __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); |
+} |
+ |
+ |
// NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). |
void ToBooleanStub::Generate(MacroAssembler* masm) { |
Label false_result, true_result, not_string; |