// parse the heap to find valid objects and initialize metadata, then // add edges for every known root pointer and every known obj->obj ptr. HeapGraph makeHeapGraph(bool include_free) { HeapGraph g; PtrMap blocks; // parse the heap once to create a PtrMap for pointer filtering. Create // one node for every parsed block, including NativeData and AsyncFuncFrame // blocks. Only include free blocks if requested. MM().forEachHeader([&](Header* h) { if (h->kind() != HeaderKind::Free || include_free) { blocks.insert(h); // adds interval [h, h+h->size[ } }); blocks.prepare(); // initialize nodes by iterating over PtrMap's regions g.nodes.reserve(blocks.size()); blocks.iterate([&](const Header* h, size_t size) { g.nodes.push_back(HeapGraph::Node{h, -1, -1}); }); // find roots PtrFilter<RootMarker> rmark(g, blocks); scanRoots(rmark); // find heap->heap pointers for (size_t i = 0, n = g.nodes.size(); i < n; i++) { auto h = g.nodes[i].h; PtrFilter<ObjMarker> omark(g, blocks, h); scanHeader(h, omark); } g.nodes.shrink_to_fit(); g.ptrs.shrink_to_fit(); g.roots.shrink_to_fit(); return g; }
// parse the heap to find valid objects and initialize metadata, then // add edges for every known root pointer and every known obj->obj ptr. HeapGraph makeHeapGraph(bool include_free) { HeapGraph g; PtrMap blocks; // parse the heap once to create a PtrMap for pointer filtering. Create // one node for every parsed block, including NativeData and AsyncFuncFrame // blocks. Only include free blocks if requested. MM().forEachHeader([&](Header* h, size_t alloc_size) { if (h->kind() != HeaderKind::Free || include_free) { blocks.insert(h, alloc_size); // adds interval [h, h+alloc_size[ } }); blocks.prepare(); // initialize nodes by iterating over PtrMap's regions g.nodes.reserve(blocks.size()); blocks.iterate([&](const Header* h, size_t size) { type_scan::Index ty; switch (h->kind()) { case HeaderKind::NativeData: ty = h->native_.typeIndex(); break; case HeaderKind::Resource: ty = h->res_.typeIndex(); break; case HeaderKind::SmallMalloc: case HeaderKind::BigMalloc: ty = h->malloc_.typeIndex(); break; default: ty = type_scan::kIndexUnknown; break; } g.nodes.push_back( HeapGraph::Node{h, size, false, ty, -1, -1} ); }); // find root nodes type_scan::Scanner scanner; iterateRoots([&](const void* h, size_t size, type_scan::Index tyindex) { // it's important that we actually scan each root node before // returning, since at least one will be the C++ stack, and some // nodes will only exist for the duration of the call to this lambda, // for example EphemeralPtrWrapper<T>. addRootNode(g, blocks, scanner, h, size, tyindex); }); // find heap->heap pointers for (size_t i = 0, n = g.nodes.size(); i < n; i++) { if (g.nodes[i].is_root) continue; auto h = g.nodes[i].h; scanHeader(h, scanner); auto from = blocks.index(h); assert(from == i); scanner.finish( [&](const void* p) { // definitely a ptr, but maybe interior, and maybe not counted if (auto r = blocks.region(p)) { addPtr(g, from, blocks.index(r), HeapGraph::Implicit, UnknownOffset); } }, [&](const void* p, std::size_t size) { conservativeScan(p, size, [&](const void** addr, const void* ptr) { if (auto r = blocks.region(ptr)) { auto to = blocks.index(r); auto offset = uintptr_t(addr) - uintptr_t(h); addPtr(g, from, to, HeapGraph::Ambiguous, offset); } }); }, [&](const void** addr) { if (auto r = blocks.region(*addr)) { auto to = blocks.index(r); auto offset = uintptr_t(addr) - uintptr_t(h); addPtr(g, from, to, HeapGraph::Counted, offset); } } ); } g.nodes.shrink_to_fit(); g.ptrs.shrink_to_fit(); g.root_ptrs.shrink_to_fit(); g.root_nodes.shrink_to_fit(); return g; }