// The takeCensus function works in three phases: // // 1) We examine the 'breakdown' property of our 'options' argument, and // use that to build a CountType tree. // // 2) We create a count node for the root of our CountType tree, and then walk // the heap, counting each node we find, expanding our tree of counts as we // go. // // 3) We walk the tree of counts and produce JavaScript objects reporting the // accumulated results. bool DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGGER_MEMORY(cx, argc, vp, "Debugger.Memory.prototype.census", args, memory); Census census(cx); if (!census.init()) return false; CountTypePtr rootType; RootedObject options(cx); if (args.get(0).isObject()) options = &args[0].toObject(); if (!JS::ubi::ParseCensusOptions(cx, census, options, rootType)) return false; JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); if (!rootCount) return false; JS::ubi::CensusHandler handler(census, rootCount, cx->runtime()->debuggerMallocSizeOf); Debugger* dbg = memory->getDebugger(); RootedObject dbgObj(cx, dbg->object); // Populate our target set of debuggee zones. for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { if (!census.targetZones.put(r.front()->zone())) return false; } { Maybe<JS::AutoCheckCannotGC> maybeNoGC; JS::ubi::RootList rootList(cx->runtime(), maybeNoGC); if (!rootList.init(dbgObj)) { ReportOutOfMemory(cx); return false; } JS::ubi::CensusTraversal traversal(cx->runtime(), handler, maybeNoGC.ref()); if (!traversal.init()) { ReportOutOfMemory(cx); return false; } traversal.wantNames = false; if (!traversal.addStart(JS::ubi::Node(&rootList)) || !traversal.traverse()) { ReportOutOfMemory(cx); return false; } } return handler.report(cx, args.rval()); }