📄 builtins-arm.cc.svn-base
字号:
__ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function __ push(r0); __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array __ push(r0); __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); // Eagerly check for stack-overflow before starting to push the arguments. // r0: number of arguments Label okay; ExternalReference stack_guard_limit_address = ExternalReference::address_of_stack_guard_limit(); __ mov(r2, Operand(stack_guard_limit_address)); __ ldr(r2, MemOperand(r2)); __ sub(r2, sp, r2); __ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); __ b(hi, &okay); // Out of stack space. __ ldr(r1, MemOperand(fp, kFunctionOffset)); __ push(r1); __ push(r0); __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS); // Push current limit and index. __ bind(&okay); __ push(r0); // limit __ mov(r1, Operand(0)); // initial index __ push(r1); // Change context eagerly to get the right global object if necessary. __ ldr(r0, MemOperand(fp, kFunctionOffset)); __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); // Compute the receiver. Label call_to_object, use_global_receiver, push_receiver; __ ldr(r0, MemOperand(fp, kRecvOffset)); __ tst(r0, Operand(kSmiTagMask)); __ b(eq, &call_to_object); __ mov(r1, Operand(Factory::null_value())); __ cmp(r0, r1); __ b(eq, &use_global_receiver); __ mov(r1, Operand(Factory::undefined_value())); __ cmp(r0, r1); __ b(eq, &use_global_receiver); // Check if the receiver is already a JavaScript object. // r0: receiver __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); __ b(lt, &call_to_object); __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); __ b(le, &push_receiver); // Convert the receiver to a regular object. // r0: receiver __ bind(&call_to_object); __ push(r0); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); __ b(&push_receiver); // Use the current global object as the receiver. __ bind(&use_global_receiver); __ ldr(r0, FieldMemOperand(cp, Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize)); // Push the receiver. // r0: receiver __ bind(&push_receiver); __ push(r0); // Copy all arguments from the array to the stack. Label entry, loop; __ ldr(r0, MemOperand(fp, kIndexOffset)); __ b(&entry); // Load the current argument from the arguments array and push it to the // stack. // r0: current argument index __ bind(&loop); __ ldr(r1, MemOperand(fp, kArgsOffset)); __ push(r1); __ push(r0); // Call the runtime to access the property in the arguments array. __ CallRuntime(Runtime::kGetProperty, 2); __ push(r0); // Use inline caching to access the arguments. __ ldr(r0, MemOperand(fp, kIndexOffset)); __ add(r0, r0, Operand(1 << kSmiTagSize)); __ str(r0, MemOperand(fp, kIndexOffset)); // Test if the copy loop has finished copying all the elements from the // arguments object. __ bind(&entry); __ ldr(r1, MemOperand(fp, kLimitOffset)); __ cmp(r0, r1); __ b(ne, &loop); // Invoke the function. ParameterCount actual(r0); __ mov(r0, Operand(r0, ASR, kSmiTagSize)); __ ldr(r1, MemOperand(fp, kFunctionOffset)); __ InvokeFunction(r1, actual, CALL_FUNCTION); // Tear down the internal frame and remove function, receiver and args. __ LeaveInternalFrame(); __ add(sp, sp, Operand(3 * kPointerSize)); __ mov(pc, lr);}static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { __ mov(r0, Operand(r0, LSL, kSmiTagSize)); __ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL)); __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); __ add(fp, sp, Operand(3 * kPointerSize));}static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : result being passed through // ----------------------------------- // Get the number of arguments passed (as a smi), tear down the frame and // then tear down the parameters. __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); __ mov(sp, fp); __ ldm(ia_w, sp, fp.bit() | lr.bit()); __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver}void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : actual number of arguments // -- r1 : function (passed through to callee) // -- r2 : expected number of arguments // -- r3 : code entry to call // ----------------------------------- Label invoke, dont_adapt_arguments; Label enough, too_few; __ cmp(r0, Operand(r2)); __ b(lt, &too_few); __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); __ b(eq, &dont_adapt_arguments); { // Enough parameters: actual >= excpected __ bind(&enough); EnterArgumentsAdaptorFrame(masm); // Calculate copy start address into r0 and copy end address into r2. // r0: actual number of arguments as a smi // r1: function // r2: expected number of arguments // r3: code entry to call __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); // adjust for return address and receiver __ add(r0, r0, Operand(2 * kPointerSize)); __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); // Copy the arguments (including the receiver) to the new stack frame. // r0: copy start address // r1: function // r2: copy end address // r3: code entry to call Label copy; __ bind(©); __ ldr(ip, MemOperand(r0, 0)); __ push(ip); __ cmp(r0, r2); // Compare before moving to next argument. __ sub(r0, r0, Operand(kPointerSize)); __ b(ne, ©); __ b(&invoke); } { // Too few parameters: Actual < expected __ bind(&too_few); EnterArgumentsAdaptorFrame(masm); // Calculate copy start address into r0 and copy end address is fp. // r0: actual number of arguments as a smi // r1: function // r2: expected number of arguments // r3: code entry to call __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); // Copy the arguments (including the receiver) to the new stack frame. // r0: copy start address // r1: function // r2: expected number of arguments // r3: code entry to call Label copy; __ bind(©); // Adjust load for return address and receiver. __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); __ push(ip); __ cmp(r0, fp); // Compare before moving to next argument. __ sub(r0, r0, Operand(kPointerSize)); __ b(ne, ©); // Fill the remaining expected arguments with undefined. // r1: function // r2: expected number of arguments // r3: code entry to call __ mov(ip, Operand(Factory::undefined_value())); __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. Label fill; __ bind(&fill); __ push(ip); __ cmp(sp, r2); __ b(ne, &fill); } // Call the entry point. Label return_site; __ bind(&invoke); __ Call(r3); __ bind(&return_site); ExitArgumentsAdaptorFrame(masm); __ mov(pc, lr); // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline // builtin code object to the return address after the call. ASSERT(return_site.is_bound()); arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; // ------------------------------------------- // Dont adapt arguments. // ------------------------------------------- __ bind(&dont_adapt_arguments); __ mov(pc, r3);}static void Generate_DebugBreakCallHelper(MacroAssembler* masm, RegList pointer_regs) { // Save the content of all general purpose registers in memory. This copy in // memory is later pushed onto the JS expression stack for the fake JS frame // generated and also to the C frame generated on top of that. In the JS // frame ONLY the registers containing pointers will be pushed on the // expression stack. This causes the GC to update these pointers so that // they will have the correct value when returning from the debugger. __ SaveRegistersToMemory(kJSCallerSaved); // This is a direct call from a debug breakpoint. To build a fake JS frame // with no parameters push a function and a receiver, keep the current // return address in lr, and set r0 to zero. __ mov(ip, Operand(ExternalReference::the_hole_value_location())); __ ldr(r3, MemOperand(ip)); __ mov(r0, Operand(0)); // Null receiver and zero arguments. __ stm(db_w, sp, r0.bit() | r3.bit()); // push function and receiver // r0: number of arguments. // What follows is an inlined version of EnterJSFrame(0, 0). // It needs to be kept in sync if any calling conventions are changed. // Compute parameter pointer before making changes // ip = sp + kPointerSize*(args_len+1); // +1 for receiver, args_len == 0 __ add(ip, sp, Operand(kPointerSize)); __ mov(r3, Operand(0)); // args_len to be saved __ mov(r2, Operand(cp)); // context to be saved // push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp, // sp_on_exit (ip == pp), return address __ stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() | ip.bit() | lr.bit()); // Setup new frame pointer. __ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset)); __ mov(pp, Operand(ip)); // setup new parameter pointer // r0 is already set to 0 as spare slot to store caller code object during GC __ push(r0); // code pointer // Inlined EnterJSFrame ends here. // Store the registers containing object pointers on the expression stack to // make sure that these are correctly updated during GC. // Use sp as base to push. __ CopyRegistersFromMemoryToStack(sp, pointer_regs);#ifdef DEBUG __ RecordComment("// Calling from debug break to runtime - come in - over");#endif // r0 is already 0, no arguments __ mov(r1, Operand(ExternalReference::debug_break())); CEntryDebugBreakStub ceb; __ CallStub(&ceb); // Restore the register values containing object pointers from the expression // stack in the reverse order as they where pushed. // Use sp as base to pop. __ CopyRegistersFromStackToMemory(sp, r3, pointer_regs); // What follows is an inlined version of ExitJSFrame(0). // It needs to be kept in sync if any calling conventions are changed. // NOTE: loading the return address to lr and discarding the (fake) function // is an addition to this inlined copy. __ mov(sp, Operand(fp)); // respect ABI stack constraint __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | lr.bit()); __ pop(); // discard fake function // Inlined ExitJSFrame ends here. // Finally restore all registers. __ RestoreRegistersFromMemory(kJSCallerSaved); // Now that the break point has been handled, resume normal execution by // jumping to the target address intended by the caller and that was // overwritten by the address of DebugBreakXXX. __ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget()))); __ ldr(ip, MemOperand(ip)); __ Jump(ip);}void Builtins::Generate_LoadIC_DebugBreak(MacroAssembler* masm) { // Calling convention for IC load (from ic-arm.cc). // ----------- S t a t e ------------- // -- r0 : receiver // -- r2 : name // -- lr : return address // -- [sp] : receiver // ----------------------------------- // Registers r0 and r2 contain objects that needs to be pushed on the // expression stack of the fake JS frame. Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());}void Builtins::Generate_StoreIC_DebugBreak(MacroAssembler* masm) { // Calling convention for IC store (from ic-arm.cc). // ----------- S t a t e ------------- // -- r0 : receiver // -- r2 : name // -- lr : return address // -- [sp] : receiver // ----------------------------------- // Registers r0 and r2 contain objects that needs to be pushed on the // expression stack of the fake JS frame. Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());}void Builtins::Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) { // Keyed load IC not implemented on ARM.}void Builtins::Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) { // Keyed store IC not implemented on ARM.}void Builtins::Generate_CallIC_DebugBreak(MacroAssembler* masm) { // Calling convention for IC call (from ic-arm.cc) // ----------- S t a t e ------------- // -- r0: number of arguments // -- r1: receiver // -- lr: return address // ----------------------------------- // Register r1 contains an object that needs to be pushed on the expression // stack of the fake JS frame. r0 is the actual number of arguments not // encoded as a smi, therefore it cannot be on the expression stack of the // fake JS frame as it can easily be an invalid pointer (e.g. 1). r0 will be // pushed on the stack of the C frame and restored from there. Generate_DebugBreakCallHelper(masm, r1.bit());}void Builtins::Generate_ConstructCall_DebugBreak(MacroAssembler* masm) { // In places other than IC call sites it is expected that r0 is TOS which // is an object - this is not generally the case so this should be used with // care. Generate_DebugBreakCallHelper(masm, r0.bit());}void Builtins::Generate_Return_DebugBreak(MacroAssembler* masm) { // In places other than IC call sites it is expected that r0 is TOS which // is an object - this is not generally the case so this should be used with // care. Generate_DebugBreakCallHelper(masm, r0.bit());}void Builtins::Generate_Return_DebugBreakEntry(MacroAssembler* masm) { // Generate nothing as this handling of debug break return is not done this // way on ARM - yet.}void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { // Generate nothing as CodeStub CallFunction is not used on ARM.}#undef __} } // namespace v8::internal
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -