Simplify the way constructors are called and avoid pushing

a dummy receiver that we end up ignoring anyway.
Review URL: http://codereview.chromium.org/3136032

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5335 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2010-08-25 07:18:32 +00:00
parent 99ce72bd8a
commit 02a842daae
11 changed files with 41 additions and 67 deletions

View File

@ -505,10 +505,6 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// r0: number of arguments
// r1: called object
__ bind(&non_function_call);
// CALL_NON_FUNCTION expects the non-function constructor as receiver
// (instead of the original receiver from the call site). The receiver is
// stack element argc.
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
// Set expected number of arguments to zero (not changing r0).
__ mov(r2, Operand(0));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);

View File

@ -4179,11 +4179,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// actual function to call is resolved after the arguments have been
// evaluated.
// Compute function to call and use the global object as the
// receiver. There is no need to use the global proxy here because
// it will always be replaced with a newly allocated object.
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
Load(node->expression());
LoadGlobal();
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = node->arguments();
@ -4192,21 +4191,21 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
Load(args->at(i));
}
// Spill everything from here to simplify the implementation.
VirtualFrame::SpilledScope spilled_scope(frame_);
// r0: the number of arguments.
// Load the argument count into r0 and the function into r1 as per
// calling convention.
__ mov(r0, Operand(arg_count));
// Load the function into r1 as per calling convention.
__ ldr(r1, frame_->ElementAt(arg_count + 1));
__ ldr(r1, frame_->ElementAt(arg_count));
// Call the construct call builtin that handles allocation and
// constructor invocation.
CodeForSourcePosition(node->position());
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1);
frame_->EmitPush(r0);
// Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
__ str(r0, frame_->Top());
ASSERT_EQ(original_height + 1, frame_->height());
}

View File

@ -1700,12 +1700,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// According to ECMA-262, section 11.2.2, page 44, the function
// expression in new calls must be evaluated before the
// arguments.
// Push function on the stack.
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
VisitForValue(expr->expression(), kStack);
// Push global object (receiver).
__ ldr(r0, CodeGenerator::GlobalObject());
__ push(r0);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
@ -1717,16 +1717,13 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// constructor invocation.
SetSourcePosition(expr->position());
// Load function, arg_count into r1 and r0.
// Load function and argument count into r1 and r0.
__ mov(r0, Operand(arg_count));
// Function is in sp[arg_count + 1].
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in r0, or pop it.
DropAndApply(1, context_, r0);
Apply(context_, r0);
}

View File

@ -95,10 +95,6 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// edi: called object
// eax: number of arguments
__ bind(&non_function_call);
// CALL_NON_FUNCTION expects the non-function constructor as receiver
// (instead of the original receiver from the call site). The receiver is
// stack element argc+1.
__ mov(Operand(esp, eax, times_4, kPointerSize), edi);
// Set expected number of arguments to zero (not changing eax).
__ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);

View File

@ -6390,11 +6390,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// actual function to call is resolved after the arguments have been
// evaluated.
// Compute function to call and use the global object as the
// receiver. There is no need to use the global proxy here because
// it will always be replaced with a newly allocated object.
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
Load(node->expression());
LoadGlobal();
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = node->arguments();
@ -6407,8 +6406,7 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// constructor invocation.
CodeForSourcePosition(node->position());
Result result = frame_->CallConstructor(arg_count);
// Replace the function on the stack with the result.
frame_->SetElementAt(0, &result);
frame_->Push(&result);
}

View File

@ -1700,11 +1700,11 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// According to ECMA-262, section 11.2.2, page 44, the function
// expression in new calls must be evaluated before the
// arguments.
// Push function on the stack.
VisitForValue(expr->expression(), kStack);
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
VisitForValue(expr->expression(), kStack);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
@ -1717,16 +1717,13 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// constructor invocation.
SetSourcePosition(expr->position());
// Load function, arg_count into edi and eax.
// Load function and argument count into edi and eax.
__ Set(eax, Immediate(arg_count));
// Function is in esp[arg_count + 1].
__ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
__ mov(edi, Operand(esp, arg_count * kPointerSize));
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in eax, or pop it.
DropAndApply(1, context_, eax);
Apply(context_, eax);
}

View File

@ -1143,9 +1143,9 @@ Result VirtualFrame::CallConstructor(int arg_count) {
// and receiver on the stack.
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
// Duplicate the function before preparing the frame.
PushElementAt(arg_count + 1);
PushElementAt(arg_count);
Result function = Pop();
PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver.
PrepareForCall(arg_count + 1, arg_count + 1); // Spill function and args.
function.ToRegister(edi);
// Constructors are called with the number of arguments in register

View File

@ -897,10 +897,6 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// rdi: called object
// rax: number of arguments
__ bind(&non_function_call);
// CALL_NON_FUNCTION expects the non-function constructor as receiver
// (instead of the original receiver from the call site). The receiver is
// stack element argc+1.
__ movq(Operand(rsp, rax, times_pointer_size, kPointerSize), rdi);
// Set expected number of arguments to zero (not changing rax).
__ movq(rbx, Immediate(0));
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);

View File

@ -5656,11 +5656,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// actual function to call is resolved after the arguments have been
// evaluated.
// Compute function to call and use the global object as the
// receiver. There is no need to use the global proxy here because
// it will always be replaced with a newly allocated object.
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
Load(node->expression());
LoadGlobal();
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = node->arguments();
@ -5673,8 +5672,7 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// constructor invocation.
CodeForSourcePosition(node->position());
Result result = frame_->CallConstructor(arg_count);
// Replace the function on the stack with the result.
frame_->SetElementAt(0, &result);
frame_->Push(&result);
}

View File

@ -1709,11 +1709,11 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// According to ECMA-262, section 11.2.2, page 44, the function
// expression in new calls must be evaluated before the
// arguments.
// Push function on the stack.
VisitForValue(expr->expression(), kStack);
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
// Push constructor on the stack. If it's not a function it's used as
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
// ignored.
VisitForValue(expr->expression(), kStack);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
@ -1726,16 +1726,13 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// constructor invocation.
SetSourcePosition(expr->position());
// Load function, arg_count into rdi and rax.
// Load function and argument count into rdi and rax.
__ Set(rax, arg_count);
// Function is in rsp[arg_count + 1].
__ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ movq(rdi, Operand(rsp, arg_count * kPointerSize));
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in rax, or pop it.
DropAndApply(1, context_, rax);
Apply(context_, rax);
}

View File

@ -1230,9 +1230,9 @@ Result VirtualFrame::CallConstructor(int arg_count) {
// and receiver on the stack.
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
// Duplicate the function before preparing the frame.
PushElementAt(arg_count + 1);
PushElementAt(arg_count);
Result function = Pop();
PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver.
PrepareForCall(arg_count + 1, arg_count + 1); // Spill function and args.
function.ToRegister(rdi);
// Constructors are called with the number of arguments in register