Index: src/builtins-ia32.cc |
=================================================================== |
--- src/builtins-ia32.cc (revision 310) |
+++ src/builtins-ia32.cc (working copy) |
@@ -379,6 +379,135 @@ |
} |
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
+ // 1. Make sure we have at least one argument. |
+ { Label done; |
+ __ test(eax, Operand(eax)); |
+ __ j(not_zero, &done, taken); |
+ __ pop(ebx); |
+ __ push(Immediate(Factory::undefined_value())); |
+ __ push(ebx); |
+ __ inc(eax); |
+ __ bind(&done); |
+ } |
+ |
+ // 2. Get the function to call from the stack. |
+ { Label done, non_function, function; |
+ // +1 ~ return address. |
+ __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); |
+ __ test(edi, Immediate(kSmiTagMask)); |
+ __ j(zero, &non_function, not_taken); |
+ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map |
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
+ __ cmp(ecx, JS_FUNCTION_TYPE); |
+ __ j(equal, &function, taken); |
+ |
+ // Non-function called: Clear the function to force exception. |
+ __ bind(&non_function); |
+ __ xor_(edi, Operand(edi)); |
+ __ jmp(&done); |
+ |
+ // Function called: Change context eagerly to get the right global object. |
+ __ bind(&function); |
+ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
+ |
+ __ bind(&done); |
+ } |
+ |
+ // 3. Make sure first argument is an object; convert if necessary. |
+ { Label call_to_object, use_global_receiver, patch_receiver, done; |
+ __ mov(ebx, Operand(esp, eax, times_4, 0)); |
+ |
+ __ 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); |
+ |
+ __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
+ __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
+ __ j(less, &call_to_object); |
+ __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
+ __ j(less_equal, &done); |
+ |
+ __ bind(&call_to_object); |
+ __ EnterInternalFrame(); // preserves eax, ebx, edi |
+ |
+ // Store the arguments count on the stack (smi tagged). |
+ ASSERT(kSmiTag == 0); |
+ __ shl(eax, kSmiTagSize); |
+ __ push(eax); |
+ |
+ __ push(edi); // save edi across the call |
+ __ push(ebx); |
+ __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
+ __ mov(Operand(ebx), eax); |
+ __ pop(edi); // restore edi after the call |
+ |
+ // Get the arguments count and untag it. |
+ __ pop(eax); |
+ __ shr(eax, kSmiTagSize); |
+ |
+ __ ExitInternalFrame(); |
+ __ jmp(&patch_receiver); |
+ |
+ // Use the global object from the called function as the receiver. |
+ __ bind(&use_global_receiver); |
+ const int kGlobalIndex = |
+ Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
+ __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
+ |
+ __ bind(&patch_receiver); |
+ __ mov(Operand(esp, eax, times_4, 0), ebx); |
+ |
+ __ bind(&done); |
+ } |
+ |
+ // 4. Shift stuff one slot down the stack. |
+ { Label loop; |
+ __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too |
+ __ bind(&loop); |
+ __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
+ __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
+ __ dec(ecx); |
+ __ j(not_zero, &loop); |
+ } |
+ |
+ // 5. Remove TOS (copy of last arguments), but keep return address. |
+ __ pop(ebx); |
+ __ pop(ecx); |
+ __ push(ebx); |
+ __ dec(eax); |
+ |
+ // 6. Check that function really was a function and get the code to |
+ // call from the function and check that the number of expected |
+ // arguments matches what we're providing. |
+ { Label invoke; |
+ __ test(edi, Operand(edi)); |
+ __ j(not_zero, &invoke, taken); |
+ __ xor_(ebx, Operand(ebx)); |
+ __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
+ __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), code_target); |
+ |
+ __ bind(&invoke); |
+ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ mov(ebx, |
+ FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
+ __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
+ __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
+ __ cmp(eax, Operand(ebx)); |
+ __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); |
+ } |
+ |
+ // 7. Jump (tail-call) to the code in register edx without checking arguments. |
+ ParameterCount expected(0); |
+ __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); |
+} |
+ |
+ |
void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
__ EnterInternalFrame(); |
@@ -530,15 +659,14 @@ |
// -- edx : code entry to call |
// ----------------------------------- |
- Label entry, invoke, function_prototype_call; |
- __ bind(&entry); |
+ Label invoke, dont_adapt_arguments; |
__ IncrementCounter(&Counters::arguments_adaptors, 1); |
Label enough, too_few; |
__ cmp(eax, Operand(ebx)); |
__ j(less, &too_few); |
- __ cmp(ebx, -1); |
- __ j(equal, &function_prototype_call); |
+ __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
+ __ j(equal, &dont_adapt_arguments); |
{ // Enough parameters: Actual >= expected. |
__ bind(&enough); |
@@ -604,135 +732,10 @@ |
// ------------------------------------------- |
- // Function.prototype.call implementation. |
+ // Dont adapt arguments. |
// ------------------------------------------- |
- __ bind(&function_prototype_call); |
- |
- // 1. Make sure we have at least one argument. |
- { Label done; |
- __ test(eax, Operand(eax)); |
- __ j(not_zero, &done, taken); |
- __ pop(ebx); |
- __ push(Immediate(Factory::undefined_value())); |
- __ push(ebx); |
- __ inc(eax); |
- __ bind(&done); |
- } |
- |
- // 2. Get the function to call from the stack. |
- { Label done, non_function, function; |
- // +1 ~ return address. |
- __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); |
- __ test(edi, Immediate(kSmiTagMask)); |
- __ j(zero, &non_function, not_taken); |
- __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map |
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ cmp(ecx, JS_FUNCTION_TYPE); |
- __ j(equal, &function, taken); |
- |
- // Non-function called: Clear the function to force exception. |
- __ bind(&non_function); |
- __ xor_(edi, Operand(edi)); |
- __ jmp(&done); |
- |
- // Function called: Change context eagerly to get the right global object. |
- __ bind(&function); |
- __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
- |
- __ bind(&done); |
- } |
- |
- // 3. Make sure first argument is an object; convert if necessary. |
- { Label call_to_object, use_global_receiver, patch_receiver, done; |
- __ mov(ebx, Operand(esp, eax, times_4, 0)); |
- |
- __ 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); |
- |
- __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
- __ j(less, &call_to_object); |
- __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
- __ j(less_equal, &done); |
- |
- __ bind(&call_to_object); |
- __ EnterInternalFrame(); // preserves eax, ebx, edi |
- |
- // Store the arguments count on the stack (smi tagged). |
- ASSERT(kSmiTag == 0); |
- __ shl(eax, kSmiTagSize); |
- __ push(eax); |
- |
- __ push(edi); // save edi across the call |
- __ push(ebx); |
- __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
- __ mov(Operand(ebx), eax); |
- __ pop(edi); // restore edi after the call |
- |
- // Get the arguments count and untag it. |
- __ pop(eax); |
- __ shr(eax, kSmiTagSize); |
- |
- __ ExitInternalFrame(); |
- __ jmp(&patch_receiver); |
- |
- // Use the global object from the called function as the receiver. |
- __ bind(&use_global_receiver); |
- const int kGlobalIndex = |
- Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
- __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
- |
- __ bind(&patch_receiver); |
- __ mov(Operand(esp, eax, times_4, 0), ebx); |
- |
- __ bind(&done); |
- } |
- |
- // 4. Shift stuff one slot down the stack. |
- { Label loop; |
- __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too |
- __ bind(&loop); |
- __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
- __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
- __ dec(ecx); |
- __ j(not_zero, &loop); |
- } |
- |
- // 5. Remove TOS (copy of last arguments), but keep return address. |
- __ pop(ebx); |
- __ pop(ecx); |
- __ push(ebx); |
- __ dec(eax); |
- |
- // 6. Check that function really was a function and get the code to |
- // call from the function and check that the number of expected |
- // arguments matches what we're providing. |
- { Label invoke; |
- __ test(edi, Operand(edi)); |
- __ j(not_zero, &invoke, taken); |
- __ xor_(ebx, Operand(ebx)); |
- __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
- __ jmp(&enough); |
- |
- __ bind(&invoke); |
- __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
- __ mov(ebx, |
- FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
- __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
- __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
- __ cmp(eax, Operand(ebx)); |
- __ j(not_equal, &entry); |
- } |
- |
- // 7. Jump (tail-call) to the code in register edx without checking arguments. |
- ParameterCount expected(0); |
- __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); |
+ __ bind(&dont_adapt_arguments); |
+ __ jmp(Operand(edx)); |
} |