Avoid calling ToObject on JSFunction receiver arguments for Function.call and Function.apply.

BUG=
TEST=

Review URL: http://codereview.chromium.org/7062007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8000 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
whesse@chromium.org 2011-05-23 15:17:10 +00:00
parent b21987203e
commit d88dbf27f5
4 changed files with 35 additions and 38 deletions

View File

@ -1264,10 +1264,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ cmp(r2, r3); __ cmp(r2, r3);
__ b(eq, &use_global_receiver); __ b(eq, &use_global_receiver);
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE); __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE);
__ b(lt, &convert_to_object); __ b(ge, &shift_arguments);
__ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
__ b(le, &shift_arguments);
__ bind(&convert_to_object); __ bind(&convert_to_object);
__ EnterInternalFrame(); // In order to preserve argument count. __ EnterInternalFrame(); // In order to preserve argument count.
@ -1443,10 +1443,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// Check if the receiver is already a JavaScript object. // Check if the receiver is already a JavaScript object.
// r0: receiver // r0: receiver
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
__ b(lt, &call_to_object); __ b(ge, &push_receiver);
__ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
__ b(le, &push_receiver);
// Convert the receiver to a regular object. // Convert the receiver to a regular object.
// r0: receiver // r0: receiver

View File

@ -606,20 +606,19 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// Compute the receiver in non-strict mode. // Compute the receiver in non-strict mode.
__ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
// Call ToObject on the receiver if it is not an object, or use the
// global object if it is null or undefined.
__ test(ebx, Immediate(kSmiTagMask)); __ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &convert_to_object); __ j(zero, &convert_to_object);
__ cmp(ebx, factory->null_value()); __ cmp(ebx, factory->null_value());
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
__ cmp(ebx, factory->undefined_value()); __ cmp(ebx, factory->undefined_value());
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
// We don't use IsObjectJSObjectType here because we jump on success. STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); __ CmpObjectType(ebx, FIRST_JS_OBJECT_TYPE, ecx);
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); __ j(above_equal, &shift_arguments);
__ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
__ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
__ j(below_equal, &shift_arguments);
__ bind(&convert_to_object); __ bind(&convert_to_object);
__ EnterInternalFrame(); // In order to preserve argument count. __ EnterInternalFrame(); // In order to preserve argument count.
@ -768,23 +767,19 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ j(not_equal, &push_receiver); __ j(not_equal, &push_receiver);
// Compute the receiver in non-strict mode. // Compute the receiver in non-strict mode.
// Call ToObject on the receiver if it is not an object, or use the
// global object if it is null or undefined.
__ test(ebx, Immediate(kSmiTagMask)); __ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object); __ j(zero, &call_to_object);
__ cmp(ebx, factory->null_value()); __ cmp(ebx, factory->null_value());
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
__ cmp(ebx, factory->undefined_value()); __ cmp(ebx, factory->undefined_value());
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ CmpObjectType(ebx, FIRST_JS_OBJECT_TYPE, ecx);
__ j(above_equal, &push_receiver);
// If given receiver is already a JavaScript object then there's no
// reason for converting it.
// We don't use IsObjectJSObjectType here because we jump on success.
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ sub(Operand(ecx), Immediate(FIRST_JS_OBJECT_TYPE));
__ cmp(ecx, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE);
__ j(below_equal, &push_receiver);
// Convert the receiver to an object.
__ bind(&call_to_object); __ bind(&call_to_object);
__ push(ebx); __ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);

View File

@ -1222,9 +1222,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ LoadRoot(a3, Heap::kNullValueRootIndex); __ LoadRoot(a3, Heap::kNullValueRootIndex);
__ Branch(&use_global_receiver, eq, a2, Operand(a3)); __ Branch(&use_global_receiver, eq, a2, Operand(a3));
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ GetObjectType(a2, a3, a3); __ GetObjectType(a2, a3, a3);
__ Branch(&convert_to_object, lt, a3, Operand(FIRST_JS_OBJECT_TYPE)); __ Branch(&shift_arguments, ge, a3, Operand(FIRST_JS_OBJECT_TYPE));
__ Branch(&shift_arguments, le, a3, Operand(LAST_JS_OBJECT_TYPE));
__ bind(&convert_to_object); __ bind(&convert_to_object);
__ EnterInternalFrame(); // In order to preserve argument count. __ EnterInternalFrame(); // In order to preserve argument count.
@ -1401,9 +1402,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// Check if the receiver is already a JavaScript object. // Check if the receiver is already a JavaScript object.
// a0: receiver // a0: receiver
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ GetObjectType(a0, a1, a1); __ GetObjectType(a0, a1, a1);
__ Branch(&call_to_object, lt, a1, Operand(FIRST_JS_OBJECT_TYPE)); __ Branch(&push_receiver, ge, a1, Operand(FIRST_JS_OBJECT_TYPE));
__ Branch(&push_receiver, le, a1, Operand(LAST_JS_OBJECT_TYPE));
// Convert the receiver to a regular object. // Convert the receiver to a regular object.
// a0: receiver // a0: receiver

View File

@ -666,17 +666,17 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// Compute the receiver in non-strict mode. // Compute the receiver in non-strict mode.
__ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
__ JumpIfSmi(rbx, &convert_to_object); __ JumpIfSmi(rbx, &convert_to_object, Label::kNear);
__ CompareRoot(rbx, Heap::kNullValueRootIndex); __ CompareRoot(rbx, Heap::kNullValueRootIndex);
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
__ j(below, &convert_to_object); __ j(above_equal, &shift_arguments);
__ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
__ j(below_equal, &shift_arguments);
__ bind(&convert_to_object); __ bind(&convert_to_object);
__ EnterInternalFrame(); // In order to preserve argument count. __ EnterInternalFrame(); // In order to preserve argument count.
@ -692,7 +692,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ LeaveInternalFrame(); __ LeaveInternalFrame();
// Restore the function to rdi. // Restore the function to rdi.
__ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize)); __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
__ jmp(&patch_receiver); __ jmp(&patch_receiver, Label::kNear);
// Use the global receiver object from the called function as the // Use the global receiver object from the called function as the
// receiver. // receiver.
@ -834,7 +834,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ j(not_zero, &push_receiver); __ j(not_zero, &push_receiver);
// Compute the receiver in non-strict mode. // Compute the receiver in non-strict mode.
__ JumpIfSmi(rbx, &call_to_object); __ JumpIfSmi(rbx, &call_to_object, Label::kNear);
__ CompareRoot(rbx, Heap::kNullValueRootIndex); __ CompareRoot(rbx, Heap::kNullValueRootIndex);
__ j(equal, &use_global_receiver); __ j(equal, &use_global_receiver);
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
@ -842,17 +842,17 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// If given receiver is already a JavaScript object then there's no // If given receiver is already a JavaScript object then there's no
// reason for converting it. // reason for converting it.
STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE);
STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
__ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
__ j(below, &call_to_object); __ j(above_equal, &push_receiver);
__ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
__ j(below_equal, &push_receiver);
// Convert the receiver to an object. // Convert the receiver to an object.
__ bind(&call_to_object); __ bind(&call_to_object);
__ push(rbx); __ push(rbx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ movq(rbx, rax); __ movq(rbx, rax);
__ jmp(&push_receiver); __ jmp(&push_receiver, Label::kNear);
// Use the current global receiver object as the receiver. // Use the current global receiver object as the receiver.
__ bind(&use_global_receiver); __ bind(&use_global_receiver);