From d88dbf27f55791fff4b7e426afa0ffceda43c6a4 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Mon, 23 May 2011 15:17:10 +0000 Subject: [PATCH] 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 --- src/arm/builtins-arm.cc | 12 ++++++------ src/ia32/builtins-ia32.cc | 31 +++++++++++++------------------ src/mips/builtins-mips.cc | 10 ++++++---- src/x64/builtins-x64.cc | 20 ++++++++++---------- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 1b2b919305..931c6bbd19 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -1264,10 +1264,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ cmp(r2, r3); __ 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); - __ b(lt, &convert_to_object); - __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); - __ b(le, &shift_arguments); + __ b(ge, &shift_arguments); __ bind(&convert_to_object); __ 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. // 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); - __ b(lt, &call_to_object); - __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); - __ b(le, &push_receiver); + __ b(ge, &push_receiver); // Convert the receiver to a regular object. // r0: receiver diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 44f0a977dc..b140b576b6 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -606,20 +606,19 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { // Compute the receiver in non-strict mode. __ 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)); __ j(zero, &convert_to_object); - __ cmp(ebx, factory->null_value()); __ j(equal, &use_global_receiver); __ cmp(ebx, factory->undefined_value()); __ j(equal, &use_global_receiver); - - // 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, &shift_arguments); + 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, &shift_arguments); __ bind(&convert_to_object); __ EnterInternalFrame(); // In order to preserve argument count. @@ -768,23 +767,19 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ j(not_equal, &push_receiver); // 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)); __ j(zero, &call_to_object); __ cmp(ebx, factory->null_value()); __ j(equal, &use_global_receiver); __ cmp(ebx, factory->undefined_value()); __ 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); __ push(ebx); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index fdcb7c73c0..732915f013 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc @@ -1222,9 +1222,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ LoadRoot(a3, Heap::kNullValueRootIndex); __ 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); - __ Branch(&convert_to_object, lt, a3, Operand(FIRST_JS_OBJECT_TYPE)); - __ Branch(&shift_arguments, le, a3, Operand(LAST_JS_OBJECT_TYPE)); + __ Branch(&shift_arguments, ge, a3, Operand(FIRST_JS_OBJECT_TYPE)); __ bind(&convert_to_object); __ 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. // a0: receiver + STATIC_ASSERT(LAST_JS_OBJECT_TYPE + 1 == LAST_TYPE); + STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); __ GetObjectType(a0, a1, a1); - __ Branch(&call_to_object, lt, a1, Operand(FIRST_JS_OBJECT_TYPE)); - __ Branch(&push_receiver, le, a1, Operand(LAST_JS_OBJECT_TYPE)); + __ Branch(&push_receiver, ge, a1, Operand(FIRST_JS_OBJECT_TYPE)); // Convert the receiver to a regular object. // a0: receiver diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 57cde65206..a5e392ff9c 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -666,17 +666,17 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { // Compute the receiver in non-strict mode. __ 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); __ j(equal, &use_global_receiver); __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); __ 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); - __ j(below, &convert_to_object); - __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); - __ j(below_equal, &shift_arguments); + __ j(above_equal, &shift_arguments); __ bind(&convert_to_object); __ EnterInternalFrame(); // In order to preserve argument count. @@ -692,7 +692,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ LeaveInternalFrame(); // Restore the function to rdi. __ 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 // receiver. @@ -834,7 +834,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ j(not_zero, &push_receiver); // Compute the receiver in non-strict mode. - __ JumpIfSmi(rbx, &call_to_object); + __ JumpIfSmi(rbx, &call_to_object, Label::kNear); __ CompareRoot(rbx, Heap::kNullValueRootIndex); __ j(equal, &use_global_receiver); __ 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 // 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); - __ j(below, &call_to_object); - __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); - __ j(below_equal, &push_receiver); + __ j(above_equal, &push_receiver); // Convert the receiver to an object. __ bind(&call_to_object); __ push(rbx); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); __ movq(rbx, rax); - __ jmp(&push_receiver); + __ jmp(&push_receiver, Label::kNear); // Use the current global receiver object as the receiver. __ bind(&use_global_receiver);