| 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).
|
|
|