void AsmJSProfilingFrameIterator::initFromFP(const AsmJSActivation &activation) { uint8_t *fp = activation.fp(); // If a signal was handled while entering an activation, the frame will // still be null. if (!fp) { JS_ASSERT(done()); return; } // Since we don't have the pc for fp, start unwinding at the caller of fp, // whose pc we do have via fp->returnAddress. This means that the innermost // frame is skipped but this is fine because: // - for FFI calls, the innermost frame is a thunk, so the first frame that // shows up is the function calling the FFI; // - for Math and other builtin calls, when profiling is activated, we // patch all call sites to instead call through a thunk; and // - for interrupts, we just accept that we'll lose the innermost frame. void *pc = ReturnAddressFromFP(fp); const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(pc); JS_ASSERT(codeRange); codeRange_ = codeRange; stackAddress_ = fp; switch (codeRange->kind()) { case AsmJSModule::CodeRange::Entry: callerPC_ = nullptr; callerFP_ = nullptr; break; case AsmJSModule::CodeRange::Function: fp = CallerFPFromFP(fp); callerPC_ = ReturnAddressFromFP(fp); callerFP_ = CallerFPFromFP(fp); AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, fp); break; case AsmJSModule::CodeRange::IonFFI: case AsmJSModule::CodeRange::SlowFFI: case AsmJSModule::CodeRange::Interrupt: case AsmJSModule::CodeRange::Inline: case AsmJSModule::CodeRange::Thunk: MOZ_CRASH("Unexpected CodeRange kind"); } // Since, despite the above reasoning for skipping a frame, we do want FFI // trampolines and interrupts to show up in the profile (so they can // accumulate self time and explain performance faults), an "exit reason" is // stored on all the paths leaving asm.js and the iterator logic treats this // reason as its own frame. If we have exited asm.js code without setting an // exit reason, the reason will be None and this means the code was // asynchronously interrupted. exitReason_ = activation.exitReason(); if (exitReason_ == AsmJSExit::None) exitReason_ = AsmJSExit::Interrupt; JS_ASSERT(!done()); }