bool HeapSnapshot::saveNode(const protobuf::Node& node) { if (!node.has_id()) return false; NodeId id = node.id(); if (!node.has_typename_()) return false; const auto* duplicatedTypeName = reinterpret_cast<const char16_t*>( node.typename_().c_str()); const char16_t* typeName = borrowUniqueString( duplicatedTypeName, node.typename_().length() / sizeof(char16_t)); if (!typeName) return false; if (!node.has_size()) return false; uint64_t size = node.size(); auto edgesLength = node.edges_size(); DeserializedNode::EdgeVector edges; if (!edges.reserve(edgesLength)) return false; for (decltype(edgesLength) i = 0; i < edgesLength; i++) { DeserializedEdge edge; if (!edge.init(node.edges(i), *this)) return false; edges.infallibleAppend(Move(edge)); } DeserializedNode dn(id, typeName, size, Move(edges), *this); return nodes.putNew(id, Move(dn)); }
bool HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame, StackFrameId& outFrameId) { if (frame.has_ref()) { // We should only get a reference to the previous frame if we have already // seen the previous frame. if (!frames.has(frame.ref())) return false; outFrameId = frame.ref(); return true; } // Incomplete message. if (!frame.has_data()) return false; auto data = frame.data(); if (!data.has_id()) return false; StackFrameId id = data.id(); // This should be the first and only time we see this frame. if (frames.has(id)) return false; Maybe<StackFrameId> parent; if (data.has_parent()) { StackFrameId parentId = 0; if (!saveStackFrame(data.parent(), parentId)) return false; parent = Some(parentId); } if (!data.has_line()) return false; uint32_t line = data.line(); if (!data.has_column()) return false; uint32_t column = data.column(); auto duplicatedSource = reinterpret_cast<const char16_t*>( data.source().data()); size_t sourceLength = data.source().length() / sizeof(char16_t); const char16_t* source = borrowUniqueString(duplicatedSource, sourceLength); if (!source) return false; const char16_t* functionDisplayName = nullptr; if (data.has_functiondisplayname() && data.functiondisplayname().length() > 0) { auto duplicatedName = reinterpret_cast<const char16_t*>( data.functiondisplayname().data()); size_t nameLength = data.functiondisplayname().length() / sizeof(char16_t); functionDisplayName = borrowUniqueString(duplicatedName, nameLength); if (!functionDisplayName) return false; } MOZ_ASSERT(!!functionDisplayName == (data.has_functiondisplayname() && data.functiondisplayname().length() > 0)); if (!data.has_issystem()) return false; bool isSystem = data.issystem(); if (!data.has_isselfhosted()) return false; bool isSelfHosted = data.isselfhosted(); if (!frames.putNew(id, DeserializedStackFrame(id, parent, line, column, source, functionDisplayName, isSystem, isSelfHosted, *this))) { return false; } outFrameId = id; return true; }
bool HeapSnapshot::saveNode(const protobuf::Node& node) { if (!node.has_id()) return false; NodeId id = node.id(); // Should only deserialize each node once. if (nodes.has(id)) return false; if (!JS::ubi::Uint32IsValidCoarseType(node.coarsetype())) return false; auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype()); if (!node.has_typename_()) return false; auto duplicatedTypeName = reinterpret_cast<const char16_t*>( node.typename_().data()); auto length = node.typename_().length() / sizeof(char16_t); auto typeName = borrowUniqueString(duplicatedTypeName, length); if (!typeName) return false; if (!node.has_size()) return false; uint64_t size = node.size(); auto edgesLength = node.edges_size(); DeserializedNode::EdgeVector edges; if (!edges.reserve(edgesLength)) return false; for (decltype(edgesLength) i = 0; i < edgesLength; i++) { DeserializedEdge edge; if (!edge.init(node.edges(i), *this)) return false; edges.infallibleAppend(Move(edge)); } Maybe<StackFrameId> allocationStack; if (node.has_allocationstack()) { StackFrameId id = 0; if (!saveStackFrame(node.allocationstack(), id)) return false; allocationStack.emplace(id); } MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack()); UniquePtr<char[]> jsObjectClassName; if (node.has_jsobjectclassname()) { auto length = node.jsobjectclassname().length(); jsObjectClassName.reset(static_cast<char*>(malloc(length + 1))); if (!jsObjectClassName) return false; strncpy(jsObjectClassName.get(), node.jsobjectclassname().data(), length); jsObjectClassName.get()[length] = '\0'; } return nodes.putNew(id, DeserializedNode(id, coarseType, typeName, size, Move(edges), allocationStack, Move(jsObjectClassName), *this)); }