📄 codegen-arm.cc.svn-base
字号:
masm->StubReturn(argc_);}void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { // r0 holds exception ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); __ ldr(sp, MemOperand(r3)); __ pop(r2); // pop next in chain __ str(r2, MemOperand(r3)); // restore parameter- and frame-pointer and pop state. __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit()); // Before returning we restore the context from the frame pointer if not NULL. // The frame pointer is NULL in the exception handler of a JS entry frame. __ cmp(fp, Operand(0)); // Set cp to NULL if fp is NULL. __ mov(cp, Operand(0), LeaveCC, eq); // Restore cp otherwise. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); __ pop(pc);}void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) { // Fetch top stack handler. __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); __ ldr(r3, MemOperand(r3)); // Unwind the handlers until the ENTRY handler is found. Label loop, done; __ bind(&loop); // Load the type of the current stack handler. const int kStateOffset = StackHandlerConstants::kAddressDisplacement + StackHandlerConstants::kStateOffset; __ ldr(r2, MemOperand(r3, kStateOffset)); __ cmp(r2, Operand(StackHandler::ENTRY)); __ b(eq, &done); // Fetch the next handler in the list. const int kNextOffset = StackHandlerConstants::kAddressDisplacement + StackHandlerConstants::kNextOffset; __ ldr(r3, MemOperand(r3, kNextOffset)); __ jmp(&loop); __ bind(&done); // Set the top handler address to next handler past the current ENTRY handler. __ ldr(r0, MemOperand(r3, kNextOffset)); __ mov(r2, Operand(ExternalReference(Top::k_handler_address))); __ str(r0, MemOperand(r2)); // Set external caught exception to false. __ mov(r0, Operand(false)); ExternalReference external_caught(Top::k_external_caught_exception_address); __ mov(r2, Operand(external_caught)); __ str(r0, MemOperand(r2)); // Set pending exception and r0 to out of memory exception. Failure* out_of_memory = Failure::OutOfMemoryException(); __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); __ str(r0, MemOperand(r2)); // Restore the stack to the address of the ENTRY handler __ mov(sp, Operand(r3)); // restore parameter- and frame-pointer and pop state. __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit()); // Before returning we restore the context from the frame pointer if not NULL. // The frame pointer is NULL in the exception handler of a JS entry frame. __ cmp(fp, Operand(0)); // Set cp to NULL if fp is NULL. __ mov(cp, Operand(0), LeaveCC, eq); // Restore cp otherwise. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); __ pop(pc);}void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_out_of_memory_exception, StackFrame::Type frame_type, bool do_gc) { // r0: result parameter for PerformGC, if any // r4: number of arguments including receiver (C callee-saved) // r5: pointer to builtin function (C callee-saved) // r6: pointer to the first argument (C callee-saved) if (do_gc) { // Passing r0. __ Call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); } // Call C built-in. // r0 = argc, r1 = argv __ mov(r0, Operand(r4)); __ mov(r1, Operand(r6)); // TODO(1242173): To let the GC traverse the return address of the exit // frames, we need to know where the return address is. Right now, // we push it on the stack to be able to find it again, but we never // restore from it in case of changes, which makes it impossible to // support moving the C entry code stub. This should be fixed, but currently // this is OK because the CEntryStub gets generated so early in the V8 boot // sequence that it is not moving ever. __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4 __ push(lr);#if !defined(__arm__) // Notify the simulator of the transition to C code. __ swi(assembler::arm::call_rt_r5);#else /* !defined(__arm__) */ __ mov(pc, Operand(r5));#endif /* !defined(__arm__) */ // result is in r0 or r0:r1 - do not destroy these registers! // check for failure result Label failure_returned; ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); // Lower 2 bits of r2 are 0 iff r0 has failure tag. __ add(r2, r0, Operand(1)); __ tst(r2, Operand(kFailureTagMask)); __ b(eq, &failure_returned); // Exit C frame and return. // r0:r1: result // sp: stack pointer // fp: frame pointer // pp: caller's parameter pointer pp (restored as C callee-saved) __ LeaveExitFrame(frame_type); // check if we should retry or throw exception Label retry; __ bind(&failure_returned); ASSERT(Failure::RETRY_AFTER_GC == 0); __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); __ b(eq, &retry); Label continue_exception; // If the returned failure is EXCEPTION then promote Top::pending_exception(). __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception()))); __ b(ne, &continue_exception); // Retrieve the pending exception and clear the variable. __ mov(ip, Operand(Factory::the_hole_value().location())); __ ldr(r3, MemOperand(ip)); __ mov(ip, Operand(Top::pending_exception_address())); __ ldr(r0, MemOperand(ip)); __ str(r3, MemOperand(ip)); __ bind(&continue_exception); // Special handling of out of memory exception. Failure* out_of_memory = Failure::OutOfMemoryException(); __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); __ b(eq, throw_out_of_memory_exception); // Handle normal exception. __ jmp(throw_normal_exception); __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying}void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { // Called from JavaScript; parameters are on stack as if calling JS function // r0: number of arguments including receiver // r1: pointer to builtin function // fp: frame pointer (restored after C call) // sp: stack pointer (restored as callee's pp after C call) // cp: current context (C callee-saved) // pp: caller's parameter pointer pp (C callee-saved) // NOTE: Invocations of builtins may return failure objects // instead of a proper result. The builtin entry handles // this by performing a garbage collection and retrying the // builtin once. StackFrame::Type frame_type = is_debug_break ? StackFrame::EXIT_DEBUG : StackFrame::EXIT; // Enter the exit frame that transitions from JavaScript to C++. __ EnterExitFrame(frame_type); // r4: number of arguments (C callee-saved) // r5: pointer to builtin function (C callee-saved) // r6: pointer to first argument (C callee-saved) Label throw_out_of_memory_exception; Label throw_normal_exception;#ifdef DEBUG if (FLAG_gc_greedy) { Failure* failure = Failure::RetryAfterGC(0, NEW_SPACE); __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure))); } GenerateCore(masm, &throw_normal_exception, &throw_out_of_memory_exception, frame_type, FLAG_gc_greedy);#else GenerateCore(masm, &throw_normal_exception, &throw_out_of_memory_exception, frame_type, false);#endif GenerateCore(masm, &throw_normal_exception, &throw_out_of_memory_exception, frame_type, true); __ bind(&throw_out_of_memory_exception); GenerateThrowOutOfMemory(masm); // control flow for generated will not return. __ bind(&throw_normal_exception); GenerateThrowTOS(masm);}void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // r0: code entry // r1: function // r2: receiver // r3: argc // [sp+0]: argv Label invoke, exit; // Called from C, so do not pop argc and args on exit (preserve sp) // No need to save register-passed args // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr __ stm(db_w, sp, kCalleeSaved | lr.bit()); // Get address of argv, see stm above. // r0: code entry // r1: function // r2: receiver // r3: argc __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize)); __ ldr(r4, MemOperand(r4)); // argv // Push a frame with special values setup to mark it as an entry frame. // r0: code entry // r1: function // r2: receiver // r3: argc // r4: argv int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL)); __ mov(r6, Operand(Smi::FromInt(marker))); __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address))); __ ldr(r5, MemOperand(r5)); __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit()); // Setup frame pointer for the frame to be pushed. __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); // Call a faked try-block that does the invoke. __ bl(&invoke); // Caught exception: Store result (exception) in the pending // exception field in the JSEnv and return a failure sentinel. // Coming in here the fp will be invalid because the PushTryHandler below // sets it to 0 to signal the existence of the JSEntry frame. __ mov(ip, Operand(Top::pending_exception_address())); __ str(r0, MemOperand(ip)); __ mov(r0, Operand(Handle<Failure>(Failure::Exception()))); __ b(&exit); // Invoke: Link this frame into the handler chain. __ bind(&invoke); // Must preserve r0-r4, r5-r7 are available. __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); // If an exception not caught by another handler occurs, this handler returns // control to the code after the bl(&invoke) above, which restores all // kCalleeSaved registers (including cp, pp and fp) to their saved values // before returning a failure to C. // Clear any pending exceptions. __ mov(ip, Operand(ExternalReference::the_hole_value_location())); __ ldr(r5, MemOperand(ip)); __ mov(ip, Operand(Top::pending_exception_address())); __ str(r5, MemOperand(ip)); // Invoke the function by calling through JS entry trampoline builtin. // Notice that we cannot store a reference to the trampoline code directly in // this stub, because runtime stubs are not traversed when doing GC. // Expected registers by Builtins::JSEntryTrampoline // r0: code entry // r1: function // r2: receiver // r3: argc // r4: argv if (is_construct) { ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline); __ mov(ip, Operand(construct_entry)); } else { ExternalReference entry(Builtins::JSEntryTrampoline); __ mov(ip, Operand(entry)); } __ ldr(ip, MemOperand(ip)); // deref address // Branch and link to JSEntryTrampoline __ mov(lr, Operand(pc)); __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); // Unlink this frame from the handler chain. When reading the // address of the next handler, there is no need to use the address // displacement since the current stack pointer (sp) points directly // to the stack handler. __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset)); __ mov(ip, Operand(ExternalReference(Top::k_handler_address))); __ str(r3, MemOperand(ip)); // No need to restore registers __ add(sp, sp, Operand(StackHandlerConstants::kSize)); __ bind(&exit); // r0 holds result // Restore the top frame descriptors from the stack. __ pop(r3); __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); __ str(r3, MemOperand(ip)); // Reset the stack to the callee saved registers. __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); // Restore callee-saved registers and return.#ifdef DEBUG if (FLAG_debug_code) __ mov(lr, Operand(pc));#endif __ ldm(ia_w, sp, kCalleeSaved | pc.bit());}class ArgumentsAccessStub: public CodeStub { public: explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { } private: bool is_length_; Major MajorKey() { return ArgumentsAccess; } int MinorKey() { return is_length_ ? 1 : 0; } void Generate(MacroAssembler* masm); const char* GetName() { return "ArgumentsAccessStub"; }#ifdef DEBUG void Print() { PrintF("ArgumentsAccessStub (is_length %s)\n", is_length_ ? "true" : "false"); }#endif};void ArgumentsAccessStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0: formal number of parameters for the calling function // -- r1: key (if value access) // -- lr: return address // ----------------------------------- // Check that the key is a smi for non-length accesses. Label slow; if (!is_length_) { __ tst(r1, Operand(kSmiTagMask)); __ b(ne, &slow); } // Check if the calling frame is an arguments adaptor frame. // r0: formal number of parameters // r1: key (if access) Label adaptor; __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL)); __ b(eq, &adaptor); static const int kParamDisplace
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -