bool SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle<SavedFrame*> frame) { if (iter.done()) { frame.set(nullptr); return true; } ScriptFrameIter thisFrame(iter); Rooted<SavedFrame*> parentFrame(cx); if (!insertFrames(cx, ++iter, &parentFrame)) return false; RootedScript script(cx, thisFrame.script()); RootedFunction callee(cx, thisFrame.maybeCallee()); const char *filename = script->filename(); RootedAtom source(cx, Atomize(cx, filename, strlen(filename))); if (!source) return false; uint32_t column; uint32_t line = PCToLineNumber(script, thisFrame.pc(), &column); SavedFrame::Lookup lookup(source, line, column, callee ? callee->displayAtom() : nullptr, parentFrame, thisFrame.compartment()->principals); frame.set(getOrCreateSavedFrame(cx, lookup)); return frame.address() != nullptr; }
bool SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame, unsigned maxFrameCount) { // In order to lookup a cached SavedFrame object, we need to have its parent // SavedFrame, which means we need to walk the stack from oldest frame to // youngest. However, FrameIter walks the stack from youngest frame to // oldest. The solution is to append stack frames to a vector as we walk the // stack with FrameIter, and then do a second pass through that vector in // reverse order after the traversal has completed and get or create the // SavedFrame objects at that time. // // To avoid making many copies of FrameIter (whose copy constructor is // relatively slow), we save the subset of FrameIter's data that is relevant // to our needs in a FrameState object, and maintain a vector of FrameState // objects instead of a vector of FrameIter objects. // Accumulate the vector of FrameState objects in |stackState|. AutoFrameStateVector stackState(cx); while (!iter.done()) { AutoLocationValueRooter location(cx); { AutoCompartment ac(cx, iter.compartment()); if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location)) return false; } { FrameState frameState(iter); frameState.location = location.get(); if (!stackState->append(frameState)) return false; } ++iter; if (maxFrameCount == 0) { // If maxFrameCount is zero, then there's no limit on the number of // frames. continue; } else if (maxFrameCount == 1) { // Since we were only asked to save one frame, do not continue // walking the stack and saving frame state. break; } else { maxFrameCount--; } } // Iterate through |stackState| in reverse order and get or create the // actual SavedFrame instances. RootedSavedFrame parentFrame(cx, nullptr); for (size_t i = stackState->length(); i != 0; i--) { SavedFrame::AutoLookupRooter lookup(cx, stackState[i-1].location.source, stackState[i-1].location.line, stackState[i-1].location.column, stackState[i-1].name, parentFrame, stackState[i-1].principals); parentFrame.set(getOrCreateSavedFrame(cx, lookup)); if (!parentFrame) return false; } frame.set(parentFrame); return true; }