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:
parent
b21987203e
commit
d88dbf27f5
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user