📄 builtins-ia32.cc.svn-base
字号:
// Restore the arguments count and exit the internal frame. __ bind(&exit); __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count __ LeaveInternalFrame(); // Remove caller arguments from the stack and return. ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ pop(ecx); __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ push(ecx); __ ret(0); // Compute the offset from the beginning of the JSConstructCall // builtin code object to the return address after the call. ASSERT(return_site.is_bound()); construct_call_pc_offset_ = return_site.pos() + Code::kHeaderSize;}static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, bool is_construct) { // Clear the context before we push it when entering the JS frame. __ xor_(esi, Operand(esi)); // clear esi // Enter an internal frame. __ EnterInternalFrame(); // Load the previous frame pointer (ebx) to access C arguments __ mov(ebx, Operand(ebp, 0)); // Get the function from the frame and setup the context. __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset)); // Push the function and the receiver onto the stack. __ push(ecx); __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); // Load the number of arguments and setup pointer to the arguments. __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); // Copy arguments to the stack in a loop. Label loop, entry; __ xor_(ecx, Operand(ecx)); // clear ecx __ jmp(&entry); __ bind(&loop); __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv __ push(Operand(edx, 0)); // dereference handle __ inc(Operand(ecx)); __ bind(&entry); __ cmp(ecx, Operand(eax)); __ j(not_equal, &loop); // Get the function from the stack and call it. __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver // Invoke the code. if (is_construct) { __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), RelocInfo::CODE_TARGET); } else { ParameterCount actual(eax); __ InvokeFunction(edi, actual, CALL_FUNCTION); } // Exit the JS frame. Notice that this also removes the empty // context and the function left on the stack by the code // invocation. __ LeaveInternalFrame(); __ ret(1 * kPointerSize); // remove receiver}void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { Generate_JSEntryTrampolineHelper(masm, false);}void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { Generate_JSEntryTrampolineHelper(masm, true);}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); __ LeaveInternalFrame(); __ 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)), RelocInfo::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(); __ push(Operand(ebp, 4 * kPointerSize)); // push this __ push(Operand(ebp, 2 * kPointerSize)); // push arguments __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); // Eagerly check for stack-overflow before pushing all the arguments // to the stack. Label okay; __ lea(ecx, Operand(esp, -3 * kPointerSize)); // receiver, limit, index __ mov(edx, Operand(eax)); __ shl(edx, kPointerSizeLog2 - kSmiTagSize); __ sub(ecx, Operand(edx)); ExternalReference stack_guard_limit_address = ExternalReference::address_of_stack_guard_limit(); __ cmp(ecx, Operand::StaticVariable(stack_guard_limit_address)); __ j(greater, &okay, taken); // Too bad: Out of stack space. __ push(Operand(ebp, 4 * kPointerSize)); // push this __ push(eax); __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); __ bind(&okay); // Push current index and limit. const int kLimitOffset = StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; const int kIndexOffset = kLimitOffset - 1 * kPointerSize; __ push(eax); // limit __ push(Immediate(0)); // index // Change context eagerly to get the right global object if // necessary. __ mov(edi, Operand(ebp, 4 * kPointerSize)); __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); // Compute the receiver. Label call_to_object, use_global_receiver, push_receiver; __ mov(ebx, Operand(ebp, 3 * kPointerSize)); __ 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); // If given receiver is already a JavaScript object then there's no // reason for converting it. __ 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, &push_receiver); // Convert the receiver to an object. __ bind(&call_to_object); __ push(ebx); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); __ mov(ebx, Operand(eax)); __ jmp(&push_receiver); // Use the current global object as the receiver. __ bind(&use_global_receiver); const int kGlobalOffset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; __ mov(ebx, FieldOperand(esi, kGlobalOffset)); // Push the receiver. __ bind(&push_receiver); __ push(ebx); // Copy all arguments from the array to the stack. Label entry, loop; __ mov(eax, Operand(ebp, kIndexOffset)); __ jmp(&entry); __ bind(&loop); __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments __ push(ecx); __ push(eax);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -