| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 3577)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -2196,19 +2196,28 @@
|
|
|
|
|
| void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
|
| - // Call the runtime to instantiate the function boilerplate object.
|
| + ASSERT(boilerplate->IsBoilerplate());
|
| +
|
| // 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(rsi);
|
| - __ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
|
| - frame_->EmitPush(kScratchRegister);
|
| - Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
|
| - frame_->Push(&result);
|
| + // 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_->Push(boilerplate);
|
| + Result answer = frame_->CallStub(&stub, 1);
|
| + frame_->Push(&answer);
|
| + } else {
|
| + // Call the runtime to instantiate the function boilerplate
|
| + // object.
|
| + frame_->EmitPush(rsi);
|
| + frame_->EmitPush(boilerplate);
|
| + Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
|
| + frame_->Push(&result);
|
| + }
|
| }
|
|
|
|
|
| @@ -6066,6 +6075,49 @@
|
| }
|
|
|
|
|
| +void FastNewClosureStub::Generate(MacroAssembler* masm) {
|
| + // Clone the boilerplate in new space. Set the context to the
|
| + // current context in rsi.
|
| + Label gc;
|
| + __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT);
|
| +
|
| + // Get the boilerplate function from the stack.
|
| + __ movq(rdx, Operand(rsp, 1 * kPointerSize));
|
| +
|
| + // Compute the function map in the current global context and set that
|
| + // as the map of the allocated object.
|
| + __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| + __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
|
| + __ movq(rcx, Operand(rcx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
|
| + __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx);
|
| +
|
| + // 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) {
|
| + __ movq(FieldOperand(rax, offset), rsi);
|
| + } else {
|
| + __ movq(rbx, FieldOperand(rdx, offset));
|
| + __ movq(FieldOperand(rax, offset), rbx);
|
| + }
|
| + }
|
| +
|
| + // Return and remove the on-stack parameter.
|
| + __ ret(1 * kPointerSize);
|
| +
|
| + // Create a new closure through the slower runtime call.
|
| + __ bind(&gc);
|
| + __ pop(rcx); // Temporarily remove return address.
|
| + __ pop(rdx);
|
| + __ push(rsi);
|
| + __ push(rdx);
|
| + __ push(rcx); // Restore return address.
|
| + __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1);
|
| +}
|
| +
|
| +
|
| void ToBooleanStub::Generate(MacroAssembler* masm) {
|
| Label false_result, true_result, not_string;
|
| __ movq(rax, Operand(rsp, 1 * kPointerSize));
|
|
|