| 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));
|
| }
|
|
|
|
|
|
|