Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 3577) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -2299,12 +2299,21 @@ |
VirtualFrame::SpilledScope spilled_scope; |
ASSERT(boilerplate->IsBoilerplate()); |
- // Create a new closure. |
- frame_->EmitPush(cp); |
__ mov(r0, Operand(boilerplate)); |
- frame_->EmitPush(r0); |
- frame_->CallRuntime(Runtime::kNewClosure, 2); |
- frame_->EmitPush(r0); |
+ // Use the fast case closure allocation code that allocates in new |
+ // space for nested functions that don't need literals cloning. |
+ if (scope()->is_function_scope() && boilerplate->NumberOfLiterals() == 0) { |
+ FastNewClosureStub stub; |
+ frame_->EmitPush(r0); |
+ frame_->CallStub(&stub, 1); |
+ frame_->EmitPush(r0); |
+ } else { |
+ // Create a new closure. |
+ frame_->EmitPush(cp); |
+ frame_->EmitPush(r0); |
+ frame_->CallRuntime(Runtime::kNewClosure, 2); |
+ frame_->EmitPush(r0); |
+ } |
} |
@@ -4384,6 +4393,53 @@ |
} |
+void FastNewClosureStub::Generate(MacroAssembler* masm) { |
+ // Clone the boilerplate in new space. Set the context to the |
+ // current context in cp. |
+ Label gc; |
+ |
+ // Pop the boilerplate function from the stack. |
+ __ pop(r3); |
+ |
+ // Attempt to allocate new JSFunction in new space. |
+ __ AllocateInNewSpace(JSFunction::kSize / kPointerSize, |
+ r0, |
+ r1, |
+ r2, |
+ &gc, |
+ TAG_OBJECT); |
+ |
+ // Compute the function map in the current global context and set that |
+ // as the map of the allocated object. |
+ __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); |
+ __ ldr(r2, MemOperand(r2, Context::SlotOffset(Context::FUNCTION_MAP_INDEX))); |
+ __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); |
+ |
+ // 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) { |
+ __ str(cp, FieldMemOperand(r0, offset)); |
+ } else { |
+ __ ldr(r1, FieldMemOperand(r3, offset)); |
+ __ str(r1, FieldMemOperand(r0, offset)); |
+ } |
+ } |
+ |
+ // Return result. The argument boilerplate has been popped already. |
+ __ Ret(); |
+ |
+ // Create a new closure through the slower runtime call. |
+ __ bind(&gc); |
+ __ push(cp); |
+ __ push(r3); |
+ __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); |
+} |
+ |
+ |
// Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz |
// instruction. On pre-ARM5 hardware this routine gives the wrong answer for 0 |
// (31 instead of 32). |