From: ager@chromium.org Date: Tue, 12 Jan 2010 07:16:49 +0000 (+0000) Subject: Port FastNewClosureStub introduced for ia32 in r3477 to x64 and arm. X-Git-Tag: upstream/4.7.83~22722 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c1cafb7cf16c05c89a70bd3abcfbaba46ecd0351;p=platform%2Fupstream%2Fv8.git Port FastNewClosureStub introduced for ia32 in r3477 to x64 and arm. BUG=552 Review URL: http://codereview.chromium.org/543010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3578 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 7ad1598e5..f77366428 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -2299,12 +2299,21 @@ void CodeGenerator::InstantiateBoilerplate(Handle boilerplate) { 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 Reference::SetValue(InitState init_state) { } +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). diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index ccea82b1d..ff2695656 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -3910,21 +3910,21 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { void CodeGenerator::InstantiateBoilerplate(Handle boilerplate) { 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. + frame_->SyncRange(0, frame_->element_count() - 1); + // 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); + frame_->EmitPush(Immediate(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. + // object. frame_->EmitPush(esi); frame_->EmitPush(Immediate(boilerplate)); Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc index eb743f81f..b889e2e20 100644 --- a/src/mksnapshot.cc +++ b/src/mksnapshot.cc @@ -151,6 +151,7 @@ int main(int argc, char** argv) { } i::Serializer::Enable(); Persistent context = v8::Context::New(); + ASSERT(!context.IsEmpty()); // Make sure all builtin scripts are cached. { HandleScope scope; for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) { diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 2e961af94..73ebc30ea 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -2196,19 +2196,28 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { void CodeGenerator::InstantiateBoilerplate(Handle 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 Reference::SetValue(InitState init_state) { } +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));