diff options
Diffstat (limited to 'devtools/shared')
138 files changed, 0 insertions, 18073 deletions
diff --git a/devtools/shared/heapsnapshot/.gitattributes b/devtools/shared/heapsnapshot/.gitattributes deleted file mode 100644 index 44e248a8d..000000000 --- a/devtools/shared/heapsnapshot/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -CoreDump.pb.* binary diff --git a/devtools/shared/heapsnapshot/AutoMemMap.cpp b/devtools/shared/heapsnapshot/AutoMemMap.cpp deleted file mode 100644 index e725a99c6..000000000 --- a/devtools/shared/heapsnapshot/AutoMemMap.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/AutoMemMap.h" - -#include "mozilla/Unused.h" -#include "nsDebug.h" - -namespace mozilla { -namespace devtools { - -AutoMemMap::~AutoMemMap() -{ - if (addr) { - Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS); - addr = nullptr; - } - - if (fileMap) { - Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS); - fileMap = nullptr; - } - - if (fd) { - Unused << NS_WARN_IF(PR_Close(fd) != PR_SUCCESS); - fd = nullptr; - } -} - -nsresult -AutoMemMap::init(const char* filePath, int flags, int mode, PRFileMapProtect prot) -{ - MOZ_ASSERT(!fd); - MOZ_ASSERT(!fileMap); - MOZ_ASSERT(!addr); - - if (PR_GetFileInfo64(filePath, &fileInfo) != PR_SUCCESS) - return NS_ERROR_FILE_NOT_FOUND; - - // Check if the file is too big to memmap. - if (fileInfo.size > int64_t(UINT32_MAX)) - return NS_ERROR_INVALID_ARG; - auto length = uint32_t(fileInfo.size); - - fd = PR_Open(filePath, flags, flags); - if (!fd) - return NS_ERROR_UNEXPECTED; - - fileMap = PR_CreateFileMap(fd, fileInfo.size, prot); - if (!fileMap) - return NS_ERROR_UNEXPECTED; - - addr = PR_MemMap(fileMap, 0, length); - if (!addr) - return NS_ERROR_UNEXPECTED; - - return NS_OK; -} - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/AutoMemMap.h b/devtools/shared/heapsnapshot/AutoMemMap.h deleted file mode 100644 index 537d68004..000000000 --- a/devtools/shared/heapsnapshot/AutoMemMap.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_AutoMemMap_h -#define mozilla_devtools_AutoMemMap_h - -#include <prio.h> -#include "mozilla/GuardObjects.h" - -namespace mozilla { -namespace devtools { - -// # AutoMemMap -// -// AutoMemMap is an RAII class to manage mapping a file to memory. It is a -// wrapper aorund managing opening and closing a file and calling PR_MemMap and -// PR_MemUnmap. -// -// Example usage: -// -// { -// AutoMemMap mm; -// if (NS_FAILED(mm.init("/path/to/desired/file"))) { -// // Handle the error however you see fit. -// return false; -// } -// -// doStuffWithMappedMemory(mm.address()); -// } -// // The memory is automatically unmapped when the AutoMemMap leaves scope. -class MOZ_RAII AutoMemMap -{ - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER; - - PRFileInfo64 fileInfo; - PRFileDesc* fd; - PRFileMap* fileMap; - void* addr; - - AutoMemMap(const AutoMemMap& aOther) = delete; - void operator=(const AutoMemMap& aOther) = delete; - -public: - explicit AutoMemMap(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : fd(nullptr) - , fileMap(nullptr) - , addr(nullptr) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - }; - ~AutoMemMap(); - - // Initialize this AutoMemMap. - nsresult init(const char* filePath, int flags = PR_RDONLY, int mode = 0, - PRFileMapProtect prot = PR_PROT_READONLY); - - // Get the size of the memory mapped file. - uint32_t size() const { - MOZ_ASSERT(fileInfo.size <= UINT32_MAX, - "Should only call size() if init() succeeded."); - return uint32_t(fileInfo.size); - } - - // Get the mapped memory. - void* address() { MOZ_ASSERT(addr); return addr; } - const void* address() const { MOZ_ASSERT(addr); return addr; } -}; - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_AutoMemMap_h diff --git a/devtools/shared/heapsnapshot/CensusUtils.js b/devtools/shared/heapsnapshot/CensusUtils.js deleted file mode 100644 index 36bdd2d82..000000000 --- a/devtools/shared/heapsnapshot/CensusUtils.js +++ /dev/null @@ -1,489 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { flatten } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js"); - -/** * Visitor ****************************************************************/ - -/** - * A Visitor visits each node and edge of a census report tree as the census - * report is being traversed by `walk`. - */ -function Visitor() { } -exports.Visitor = Visitor; - -/** - * The `enter` method is called when a new sub-report is entered in traversal. - * - * @param {Object} breakdown - * The breakdown for the sub-report that is being entered by traversal. - * - * @param {Object} report - * The report generated by the given breakdown. - * - * @param {any} edge - * The edge leading to this sub-report. The edge is null if (but not iff! - * eg, null allocation stack edges) we are entering the root report. - */ -Visitor.prototype.enter = function (breakdown, report, edge) { }; - -/** - * The `exit` method is called when traversal of a sub-report has finished. - * - * @param {Object} breakdown - * The breakdown for the sub-report whose traversal has finished. - * - * @param {Object} report - * The report generated by the given breakdown. - * - * @param {any} edge - * The edge leading to this sub-report. The edge is null if (but not iff! - * eg, null allocation stack edges) we are entering the root report. - */ -Visitor.prototype.exit = function (breakdown, report, edge) { }; - -/** - * The `count` method is called when leaf nodes (reports whose breakdown is - * by: "count") in the report tree are encountered. - * - * @param {Object} breakdown - * The count breakdown for this report. - * - * @param {Object} report - * The report generated by a breakdown by "count". - * - * @param {any|null} edge - * The edge leading to this count report. The edge is null if we are - * entering the root report. - */ -Visitor.prototype.count = function (breakdown, report, edge) { }; - -/** * getReportEdges *********************************************************/ - -const EDGES = Object.create(null); - -EDGES.count = function (breakdown, report) { - return []; -}; - -EDGES.bucket = function (breakdown, report) { - return []; -}; - -EDGES.internalType = function (breakdown, report) { - return Object.keys(report).map(key => ({ - edge: key, - referent: report[key], - breakdown: breakdown.then - })); -}; - -EDGES.objectClass = function (breakdown, report) { - return Object.keys(report).map(key => ({ - edge: key, - referent: report[key], - breakdown: key === "other" ? breakdown.other : breakdown.then - })); -}; - -EDGES.coarseType = function (breakdown, report) { - return [ - { edge: "objects", referent: report.objects, breakdown: breakdown.objects }, - { edge: "scripts", referent: report.scripts, breakdown: breakdown.scripts }, - { edge: "strings", referent: report.strings, breakdown: breakdown.strings }, - { edge: "other", referent: report.other, breakdown: breakdown.other }, - ]; -}; - -EDGES.allocationStack = function (breakdown, report) { - const edges = []; - report.forEach((value, key) => { - edges.push({ - edge: key, - referent: value, - breakdown: key === "noStack" ? breakdown.noStack : breakdown.then - }); - }); - return edges; -}; - -EDGES.filename = function (breakdown, report) { - return Object.keys(report).map(key => ({ - edge: key, - referent: report[key], - breakdown: key === "noFilename" ? breakdown.noFilename : breakdown.then - })); -}; - -/** - * Get the set of outgoing edges from `report` as specified by the given - * breakdown. - * - * @param {Object} breakdown - * The census breakdown. - * - * @param {Object} report - * The census report. - */ -function getReportEdges(breakdown, report) { - return EDGES[breakdown.by](breakdown, report); -} -exports.getReportEdges = getReportEdges; - -/** * walk *******************************************************************/ - -function recursiveWalk(breakdown, edge, report, visitor) { - if (breakdown.by === "count") { - visitor.enter(breakdown, report, edge); - visitor.count(breakdown, report, edge); - visitor.exit(breakdown, report, edge); - } else { - visitor.enter(breakdown, report, edge); - for (let { edge, referent, breakdown: subBreakdown } of getReportEdges(breakdown, report)) { - recursiveWalk(subBreakdown, edge, referent, visitor); - } - visitor.exit(breakdown, report, edge); - } -} - -/** - * Walk the given `report` that was generated by taking a census with the - * specified `breakdown`. - * - * @param {Object} breakdown - * The census breakdown. - * - * @param {Object} report - * The census report. - * - * @param {Visitor} visitor - * The Visitor instance to call into while traversing. - */ -function walk(breakdown, report, visitor) { - recursiveWalk(breakdown, null, report, visitor); -} -exports.walk = walk; - -/** * diff *******************************************************************/ - -/** - * Return true if the object is a Map, false otherwise. Works with Map objects - * from other globals, unlike `instanceof`. - * - * @returns {Boolean} - */ -function isMap(obj) { - return Object.prototype.toString.call(obj) === "[object Map]"; -} - -/** - * A Visitor for computing the difference between the census report being - * traversed and the given other census. - * - * @param {Object} otherCensus - * The other census report. - */ -function DiffVisitor(otherCensus) { - // The other census we are comparing against. - this._otherCensus = otherCensus; - - // The total bytes and count of the basis census we are traversing. - this._totalBytes = 0; - this._totalCount = 0; - - // Stack maintaining the current corresponding sub-report for the other - // census we are comparing against. - this._otherCensusStack = []; - - // Stack maintaining the set of edges visited at each sub-report. - this._edgesVisited = [new Set()]; - - // The final delta census. Valid only after traversal. - this._results = null; - - // Stack maintaining the results corresponding to each sub-report we are - // currently traversing. - this._resultsStack = []; -} - -DiffVisitor.prototype = Object.create(Visitor.prototype); - -/** - * Given a report and an outgoing edge, get the edge's referent. - */ -DiffVisitor.prototype._get = function (report, edge) { - if (!report) { - return undefined; - } - return isMap(report) ? report.get(edge) : report[edge]; -}; - -/** - * Given a report, an outgoing edge, and a value, set the edge's referent to - * the given value. - */ -DiffVisitor.prototype._set = function (report, edge, val) { - if (isMap(report)) { - report.set(edge, val); - } else { - report[edge] = val; - } -}; - -/** - * @overrides Visitor.prototype.enter - */ -DiffVisitor.prototype.enter = function (breakdown, report, edge) { - const isFirstTimeEntering = this._results === null; - - const newResults = breakdown.by === "allocationStack" ? new Map() : {}; - let newOther; - - if (!this._results) { - // This is the first time we have entered a sub-report. - this._results = newResults; - newOther = this._otherCensus; - } else { - const topResults = this._resultsStack[this._resultsStack.length - 1]; - this._set(topResults, edge, newResults); - - const topOther = this._otherCensusStack[this._otherCensusStack.length - 1]; - newOther = this._get(topOther, edge); - } - - this._resultsStack.push(newResults); - this._otherCensusStack.push(newOther); - - const visited = this._edgesVisited[this._edgesVisited.length - 1]; - visited.add(edge); - this._edgesVisited.push(new Set()); -}; - -/** - * @overrides Visitor.prototype.exit - */ -DiffVisitor.prototype.exit = function (breakdown, report, edge) { - // Find all the edges in the other census report that were not traversed and - // add them to the results directly. - const other = this._otherCensusStack[this._otherCensusStack.length - 1]; - if (other) { - const visited = this._edgesVisited[this._edgesVisited.length - 1]; - const unvisited = getReportEdges(breakdown, other) - .map(e => e.edge) - .filter(e => !visited.has(e)); - const results = this._resultsStack[this._resultsStack.length - 1]; - for (let edge of unvisited) { - this._set(results, edge, this._get(other, edge)); - } - } - - this._otherCensusStack.pop(); - this._resultsStack.pop(); - this._edgesVisited.pop(); -}; - -/** - * @overrides Visitor.prototype.count - */ -DiffVisitor.prototype.count = function (breakdown, report, edge) { - const other = this._otherCensusStack[this._otherCensusStack.length - 1]; - const results = this._resultsStack[this._resultsStack.length - 1]; - - if (breakdown.count) { - this._totalCount += report.count; - } - if (breakdown.bytes) { - this._totalBytes += report.bytes; - } - - if (other) { - if (breakdown.count) { - results.count = other.count - report.count; - } - if (breakdown.bytes) { - results.bytes = other.bytes - report.bytes; - } - } else { - if (breakdown.count) { - results.count = -report.count; - } - if (breakdown.bytes) { - results.bytes = -report.bytes; - } - } -}; - -const basisTotalBytes = exports.basisTotalBytes = Symbol("basisTotalBytes"); -const basisTotalCount = exports.basisTotalCount = Symbol("basisTotalCount"); - -/** - * Get the resulting report of the difference between the traversed census - * report and the other census report. - * - * @returns {Object} - * The delta census report. - */ -DiffVisitor.prototype.results = function () { - if (!this._results) { - throw new Error("Attempt to get results before computing diff!"); - } - - if (this._resultsStack.length) { - throw new Error("Attempt to get results while still computing diff!"); - } - - this._results[basisTotalBytes] = this._totalBytes; - this._results[basisTotalCount] = this._totalCount; - - return this._results; -}; - -/** - * Take the difference between two censuses. The resulting delta report - * contains the number/size of things that are in the `endCensus` that are not - * in the `startCensus`. - * - * @param {Object} breakdown - * The breakdown used to generate both census reports. - * - * @param {Object} startCensus - * The first census report. - * - * @param {Object} endCensus - * The second census report. - * - * @returns {Object} - * A delta report mirroring the structure of the two census reports (as - * specified by the given breakdown). Has two additional properties: - * - {Number} basisTotalBytes: the total number of bytes in the start - * census. - * - {Number} basisTotalCount: the total count in the start census. - */ -function diff(breakdown, startCensus, endCensus) { - const visitor = new DiffVisitor(endCensus); - walk(breakdown, startCensus, visitor); - return visitor.results(); -} -exports.diff = diff; - -/** - * Creates a hash map mapping node IDs to its parent node. - * - * @param {CensusTreeNode} node - * @param {Object<number, TreeNode>} aggregator - * - * @return {Object<number, TreeNode>} - */ -const createParentMap = exports.createParentMap = function (node, - getId = node => node.id, - aggregator = Object.create(null)) { - if (node.children) { - for (let i = 0, length = node.children.length; i < length; i++) { - const child = node.children[i]; - aggregator[getId(child)] = node; - createParentMap(child, getId, aggregator); - } - } - - return aggregator; -}; - -const BUCKET = Object.freeze({ by: "bucket" }); - -/** - * Convert a breakdown whose leaves are { by: "count" } to an identical - * breakdown, except with { by: "bucket" } leaves. - * - * @param {Object} breakdown - * @returns {Object} - */ -exports.countToBucketBreakdown = function (breakdown) { - if (typeof breakdown !== "object" || !breakdown) { - return breakdown; - } - - if (breakdown.by === "count") { - return BUCKET; - } - - const keys = Object.keys(breakdown); - const vals = keys.reduce((vs, k) => { - vs.push(exports.countToBucketBreakdown(breakdown[k])); - return vs; - }, []); - - const result = {}; - for (let i = 0, length = keys.length; i < length; i++) { - result[keys[i]] = vals[i]; - } - - return Object.freeze(result); -}; - -/** - * A Visitor for finding report leaves by their DFS index. - */ -function GetLeavesVisitor(targetIndices) { - this._index = -1; - this._targetIndices = targetIndices; - this._leaves = []; -} - -GetLeavesVisitor.prototype = Object.create(Visitor.prototype); - -/** - * @overrides Visitor.prototype.enter - */ -GetLeavesVisitor.prototype.enter = function (breakdown, report, edge) { - this._index++; - if (this._targetIndices.has(this._index)) { - this._leaves.push(report); - } -}; - -/** - * Get the accumulated report leaves after traversal. - */ -GetLeavesVisitor.prototype.leaves = function () { - if (this._index === -1) { - throw new Error("Attempt to call `leaves` before traversing report!"); - } - return this._leaves; -}; - -/** - * Given a set of indices of leaves in a pre-order depth-first traversal of the - * given census report, return the leaves. - * - * @param {Set<Number>} indices - * @param {Object} breakdown - * @param {Object} report - * - * @returns {Array<Object>} - */ -exports.getReportLeaves = function (indices, breakdown, report) { - const visitor = new GetLeavesVisitor(indices); - walk(breakdown, report, visitor); - return visitor.leaves(); -}; - -/** - * Get a list of the individual node IDs that belong to the census report leaves - * of the given indices. - * - * @param {Set<Number>} indices - * @param {Object} breakdown - * @param {HeapSnapshot} snapshot - * - * @returns {Array<NodeId>} - */ -exports.getCensusIndividuals = function (indices, countBreakdown, snapshot) { - const bucketBreakdown = exports.countToBucketBreakdown(countBreakdown); - const bucketReport = snapshot.takeCensus({ breakdown: bucketBreakdown }); - const buckets = exports.getReportLeaves(indices, - bucketBreakdown, - bucketReport); - return flatten(buckets); -}; diff --git a/devtools/shared/heapsnapshot/CoreDump.pb.cc b/devtools/shared/heapsnapshot/CoreDump.pb.cc deleted file mode 100644 index 6c7c0e8a4..000000000 --- a/devtools/shared/heapsnapshot/CoreDump.pb.cc +++ /dev/null @@ -1,2542 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: CoreDump.proto - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "CoreDump.pb.h" - -#include <algorithm> - -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/once.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format_lite_inl.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/generated_message_reflection.h> -#include <google/protobuf/reflection_ops.h> -#include <google/protobuf/wire_format.h> -// @@protoc_insertion_point(includes) - -namespace mozilla { -namespace devtools { -namespace protobuf { - -namespace { - -const ::google::protobuf::Descriptor* Metadata_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Metadata_reflection_ = NULL; -const ::google::protobuf::Descriptor* StackFrame_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - StackFrame_reflection_ = NULL; -struct StackFrameOneofInstance { - const ::mozilla::devtools::protobuf::StackFrame_Data* data_; - ::google::protobuf::uint64 ref_; -}* StackFrame_default_oneof_instance_ = NULL; -const ::google::protobuf::Descriptor* StackFrame_Data_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - StackFrame_Data_reflection_ = NULL; -struct StackFrame_DataOneofInstance { - const ::std::string* source_; - ::google::protobuf::uint64 sourceref_; - const ::std::string* functiondisplayname_; - ::google::protobuf::uint64 functiondisplaynameref_; -}* StackFrame_Data_default_oneof_instance_ = NULL; -const ::google::protobuf::Descriptor* Node_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Node_reflection_ = NULL; -struct NodeOneofInstance { - const ::std::string* typename__; - ::google::protobuf::uint64 typenameref_; - const ::std::string* jsobjectclassname_; - ::google::protobuf::uint64 jsobjectclassnameref_; - const ::std::string* scriptfilename_; - ::google::protobuf::uint64 scriptfilenameref_; -}* Node_default_oneof_instance_ = NULL; -const ::google::protobuf::Descriptor* Edge_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Edge_reflection_ = NULL; -struct EdgeOneofInstance { - const ::std::string* name_; - ::google::protobuf::uint64 nameref_; -}* Edge_default_oneof_instance_ = NULL; - -} // namespace - - -void protobuf_AssignDesc_CoreDump_2eproto() { - protobuf_AddDesc_CoreDump_2eproto(); - const ::google::protobuf::FileDescriptor* file = - ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( - "CoreDump.proto"); - GOOGLE_CHECK(file != NULL); - Metadata_descriptor_ = file->message_type(0); - static const int Metadata_offsets_[1] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, timestamp_), - }; - Metadata_reflection_ = - new ::google::protobuf::internal::GeneratedMessageReflection( - Metadata_descriptor_, - Metadata::default_instance_, - Metadata_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _unknown_fields_), - -1, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), - sizeof(Metadata)); - StackFrame_descriptor_ = file->message_type(1); - static const int StackFrame_offsets_[3] = { - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_default_oneof_instance_, data_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_default_oneof_instance_, ref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, StackFrameType_), - }; - StackFrame_reflection_ = - new ::google::protobuf::internal::GeneratedMessageReflection( - StackFrame_descriptor_, - StackFrame::default_instance_, - StackFrame_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _unknown_fields_), - -1, - StackFrame_default_oneof_instance_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _oneof_case_[0]), - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), - sizeof(StackFrame)); - StackFrame_Data_descriptor_ = StackFrame_descriptor_->nested_type(0); - static const int StackFrame_Data_offsets_[12] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, id_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, parent_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, line_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, column_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, source_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, sourceref_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplayname_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplaynameref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, issystem_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, isselfhosted_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, SourceOrRef_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, FunctionDisplayNameOrRef_), - }; - StackFrame_Data_reflection_ = - new ::google::protobuf::internal::GeneratedMessageReflection( - StackFrame_Data_descriptor_, - StackFrame_Data::default_instance_, - StackFrame_Data_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _unknown_fields_), - -1, - StackFrame_Data_default_oneof_instance_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _oneof_case_[0]), - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), - sizeof(StackFrame_Data)); - Node_descriptor_ = file->message_type(2); - static const int Node_offsets_[14] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, id_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typename__), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typenameref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, size_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, edges_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, allocationstack_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassname_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassnameref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, coarsetype_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, scriptfilename_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, scriptfilenameref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, TypeNameOrRef_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, JSObjectClassNameOrRef_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, ScriptFilenameOrRef_), - }; - Node_reflection_ = - new ::google::protobuf::internal::GeneratedMessageReflection( - Node_descriptor_, - Node::default_instance_, - Node_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _unknown_fields_), - -1, - Node_default_oneof_instance_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _oneof_case_[0]), - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), - sizeof(Node)); - Edge_descriptor_ = file->message_type(3); - static const int Edge_offsets_[4] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, referent_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, name_), - PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, nameref_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, EdgeNameOrRef_), - }; - Edge_reflection_ = - new ::google::protobuf::internal::GeneratedMessageReflection( - Edge_descriptor_, - Edge::default_instance_, - Edge_offsets_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _unknown_fields_), - -1, - Edge_default_oneof_instance_, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _oneof_case_[0]), - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), - sizeof(Edge)); -} - -namespace { - -GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { - ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, - &protobuf_AssignDesc_CoreDump_2eproto); -} - -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Metadata_descriptor_, &Metadata::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - StackFrame_descriptor_, &StackFrame::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - StackFrame_Data_descriptor_, &StackFrame_Data::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Node_descriptor_, &Node::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Edge_descriptor_, &Edge::default_instance()); -} - -} // namespace - -void protobuf_ShutdownFile_CoreDump_2eproto() { - delete Metadata::default_instance_; - delete Metadata_reflection_; - delete StackFrame::default_instance_; - delete StackFrame_default_oneof_instance_; - delete StackFrame_reflection_; - delete StackFrame_Data::default_instance_; - delete StackFrame_Data_default_oneof_instance_; - delete StackFrame_Data_reflection_; - delete Node::default_instance_; - delete Node_default_oneof_instance_; - delete Node_reflection_; - delete Edge::default_instance_; - delete Edge_default_oneof_instance_; - delete Edge_reflection_; -} - -void protobuf_AddDesc_CoreDump_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - "\n\016CoreDump.proto\022\031mozilla.devtools.proto" - "buf\"\035\n\010Metadata\022\021\n\ttimeStamp\030\001 \001(\004\"\216\003\n\nS" - "tackFrame\022:\n\004data\030\001 \001(\0132*.mozilla.devtoo" - "ls.protobuf.StackFrame.DataH\000\022\r\n\003ref\030\002 \001" - "(\004H\000\032\242\002\n\004Data\022\n\n\002id\030\001 \001(\004\0225\n\006parent\030\002 \001(" - "\0132%.mozilla.devtools.protobuf.StackFrame" - "\022\014\n\004line\030\003 \001(\r\022\016\n\006column\030\004 \001(\r\022\020\n\006source" - "\030\005 \001(\014H\000\022\023\n\tsourceRef\030\006 \001(\004H\000\022\035\n\023functio" - "nDisplayName\030\007 \001(\014H\001\022 \n\026functionDisplayN" - "ameRef\030\010 \001(\004H\001\022\020\n\010isSystem\030\t \001(\010\022\024\n\014isSe" - "lfHosted\030\n \001(\010B\r\n\013SourceOrRefB\032\n\030Functio" - "nDisplayNameOrRefB\020\n\016StackFrameType\"\210\003\n\004" - "Node\022\n\n\002id\030\001 \001(\004\022\022\n\010typeName\030\002 \001(\014H\000\022\025\n\013" - "typeNameRef\030\003 \001(\004H\000\022\014\n\004size\030\004 \001(\004\022.\n\005edg" - "es\030\005 \003(\0132\037.mozilla.devtools.protobuf.Edg" - "e\022>\n\017allocationStack\030\006 \001(\0132%.mozilla.dev" - "tools.protobuf.StackFrame\022\033\n\021jsObjectCla" - "ssName\030\007 \001(\014H\001\022\036\n\024jsObjectClassNameRef\030\010" - " \001(\004H\001\022\025\n\ncoarseType\030\t \001(\r:\0010\022\030\n\016scriptF" - "ilename\030\n \001(\014H\002\022\033\n\021scriptFilenameRef\030\013 \001" - "(\004H\002B\017\n\rTypeNameOrRefB\030\n\026JSObjectClassNa" - "meOrRefB\025\n\023ScriptFilenameOrRef\"L\n\004Edge\022\020" - "\n\010referent\030\001 \001(\004\022\016\n\004name\030\002 \001(\014H\000\022\021\n\007name" - "Ref\030\003 \001(\004H\000B\017\n\rEdgeNameOrRef", 948); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "CoreDump.proto", &protobuf_RegisterTypes); - Metadata::default_instance_ = new Metadata(); - StackFrame::default_instance_ = new StackFrame(); - StackFrame_default_oneof_instance_ = new StackFrameOneofInstance; - StackFrame_Data::default_instance_ = new StackFrame_Data(); - StackFrame_Data_default_oneof_instance_ = new StackFrame_DataOneofInstance; - Node::default_instance_ = new Node(); - Node_default_oneof_instance_ = new NodeOneofInstance; - Edge::default_instance_ = new Edge(); - Edge_default_oneof_instance_ = new EdgeOneofInstance; - Metadata::default_instance_->InitAsDefaultInstance(); - StackFrame::default_instance_->InitAsDefaultInstance(); - StackFrame_Data::default_instance_->InitAsDefaultInstance(); - Node::default_instance_->InitAsDefaultInstance(); - Edge::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_CoreDump_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_CoreDump_2eproto { - StaticDescriptorInitializer_CoreDump_2eproto() { - protobuf_AddDesc_CoreDump_2eproto(); - } -} static_descriptor_initializer_CoreDump_2eproto_; - -// =================================================================== - -#ifndef _MSC_VER -const int Metadata::kTimeStampFieldNumber; -#endif // !_MSC_VER - -Metadata::Metadata() - : ::google::protobuf::Message() { - SharedCtor(); - // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Metadata) -} - -void Metadata::InitAsDefaultInstance() { -} - -Metadata::Metadata(const Metadata& from) - : ::google::protobuf::Message() { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Metadata) -} - -void Metadata::SharedCtor() { - _cached_size_ = 0; - timestamp_ = GOOGLE_ULONGLONG(0); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -Metadata::~Metadata() { - // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Metadata) - SharedDtor(); -} - -void Metadata::SharedDtor() { - if (this != default_instance_) { - } -} - -void Metadata::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Metadata::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Metadata_descriptor_; -} - -const Metadata& Metadata::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto(); - return *default_instance_; -} - -Metadata* Metadata::default_instance_ = NULL; - -Metadata* Metadata::New() const { - return new Metadata; -} - -void Metadata::Clear() { - timestamp_ = GOOGLE_ULONGLONG(0); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); -} - -bool Metadata::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Metadata) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 timeStamp = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, ×tamp_))); - set_has_timestamp(); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Metadata) - return true; -failure: - // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Metadata) - return false; -#undef DO_ -} - -void Metadata::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Metadata) - // optional uint64 timeStamp = 1; - if (has_timestamp()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->timestamp(), output); - } - - if (!unknown_fields().empty()) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output); - } - // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Metadata) -} - -::google::protobuf::uint8* Metadata::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Metadata) - // optional uint64 timeStamp = 1; - if (has_timestamp()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->timestamp(), target); - } - - if (!unknown_fields().empty()) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - unknown_fields(), target); - } - // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Metadata) - return target; -} - -int Metadata::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional uint64 timeStamp = 1; - if (has_timestamp()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->timestamp()); - } - - } - if (!unknown_fields().empty()) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - unknown_fields()); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Metadata::MergeFrom(const ::google::protobuf::Message& from) { - GOOGLE_CHECK_NE(&from, this); - const Metadata* source = - ::google::protobuf::internal::dynamic_cast_if_available<const Metadata*>( - &from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - -void Metadata::MergeFrom(const Metadata& from) { - GOOGLE_CHECK_NE(&from, this); - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from.has_timestamp()) { - set_timestamp(from.timestamp()); - } - } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); -} - -void Metadata::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Metadata::CopyFrom(const Metadata& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Metadata::IsInitialized() const { - - return true; -} - -void Metadata::Swap(Metadata* other) { - if (other != this) { - std::swap(timestamp_, other->timestamp_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::google::protobuf::Metadata Metadata::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Metadata_descriptor_; - metadata.reflection = Metadata_reflection_; - return metadata; -} - - -// =================================================================== - -#ifndef _MSC_VER -const int StackFrame_Data::kIdFieldNumber; -const int StackFrame_Data::kParentFieldNumber; -const int StackFrame_Data::kLineFieldNumber; -const int StackFrame_Data::kColumnFieldNumber; -const int StackFrame_Data::kSourceFieldNumber; -const int StackFrame_Data::kSourceRefFieldNumber; -const int StackFrame_Data::kFunctionDisplayNameFieldNumber; -const int StackFrame_Data::kFunctionDisplayNameRefFieldNumber; -const int StackFrame_Data::kIsSystemFieldNumber; -const int StackFrame_Data::kIsSelfHostedFieldNumber; -#endif // !_MSC_VER - -StackFrame_Data::StackFrame_Data() - : ::google::protobuf::Message() { - SharedCtor(); - // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame.Data) -} - -void StackFrame_Data::InitAsDefaultInstance() { - parent_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance()); - StackFrame_Data_default_oneof_instance_->source_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - StackFrame_Data_default_oneof_instance_->sourceref_ = GOOGLE_ULONGLONG(0); - StackFrame_Data_default_oneof_instance_->functiondisplayname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - StackFrame_Data_default_oneof_instance_->functiondisplaynameref_ = GOOGLE_ULONGLONG(0); -} - -StackFrame_Data::StackFrame_Data(const StackFrame_Data& from) - : ::google::protobuf::Message() { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.StackFrame.Data) -} - -void StackFrame_Data::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - id_ = GOOGLE_ULONGLONG(0); - parent_ = NULL; - line_ = 0u; - column_ = 0u; - issystem_ = false; - isselfhosted_ = false; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - clear_has_SourceOrRef(); - clear_has_FunctionDisplayNameOrRef(); -} - -StackFrame_Data::~StackFrame_Data() { - // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.StackFrame.Data) - SharedDtor(); -} - -void StackFrame_Data::SharedDtor() { - if (has_SourceOrRef()) { - clear_SourceOrRef(); - } - if (has_FunctionDisplayNameOrRef()) { - clear_FunctionDisplayNameOrRef(); - } - if (this != default_instance_) { - delete parent_; - } -} - -void StackFrame_Data::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* StackFrame_Data::descriptor() { - protobuf_AssignDescriptorsOnce(); - return StackFrame_Data_descriptor_; -} - -const StackFrame_Data& StackFrame_Data::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto(); - return *default_instance_; -} - -StackFrame_Data* StackFrame_Data::default_instance_ = NULL; - -StackFrame_Data* StackFrame_Data::New() const { - return new StackFrame_Data; -} - -void StackFrame_Data::clear_SourceOrRef() { - switch(SourceOrRef_case()) { - case kSource: { - delete SourceOrRef_.source_; - break; - } - case kSourceRef: { - // No need to clear - break; - } - case SOURCEORREF_NOT_SET: { - break; - } - } - _oneof_case_[0] = SOURCEORREF_NOT_SET; -} - -void StackFrame_Data::clear_FunctionDisplayNameOrRef() { - switch(FunctionDisplayNameOrRef_case()) { - case kFunctionDisplayName: { - delete FunctionDisplayNameOrRef_.functiondisplayname_; - break; - } - case kFunctionDisplayNameRef: { - // No need to clear - break; - } - case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { - break; - } - } - _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET; -} - - -void StackFrame_Data::Clear() { -#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \ - &reinterpret_cast<StackFrame_Data*>(16)->f) - \ - reinterpret_cast<char*>(16)) - -#define ZR_(first, last) do { \ - size_t f = OFFSET_OF_FIELD_(first); \ - size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \ - ::memset(&first, 0, n); \ - } while (0) - - if (_has_bits_[0 / 32] & 15) { - ZR_(line_, column_); - id_ = GOOGLE_ULONGLONG(0); - if (has_parent()) { - if (parent_ != NULL) parent_->::mozilla::devtools::protobuf::StackFrame::Clear(); - } - } - ZR_(issystem_, isselfhosted_); - -#undef OFFSET_OF_FIELD_ -#undef ZR_ - - clear_SourceOrRef(); - clear_FunctionDisplayNameOrRef(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); -} - -bool StackFrame_Data::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame.Data) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 id = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &id_))); - set_has_id(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_parent; - break; - } - - // optional .mozilla.devtools.protobuf.StackFrame parent = 2; - case 2: { - if (tag == 18) { - parse_parent: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_parent())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_line; - break; - } - - // optional uint32 line = 3; - case 3: { - if (tag == 24) { - parse_line: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( - input, &line_))); - set_has_line(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(32)) goto parse_column; - break; - } - - // optional uint32 column = 4; - case 4: { - if (tag == 32) { - parse_column: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( - input, &column_))); - set_has_column(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(42)) goto parse_source; - break; - } - - // optional bytes source = 5; - case 5: { - if (tag == 42) { - parse_source: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_source())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(48)) goto parse_sourceRef; - break; - } - - // optional uint64 sourceRef = 6; - case 6: { - if (tag == 48) { - parse_sourceRef: - clear_SourceOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &SourceOrRef_.sourceref_))); - set_has_sourceref(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(58)) goto parse_functionDisplayName; - break; - } - - // optional bytes functionDisplayName = 7; - case 7: { - if (tag == 58) { - parse_functionDisplayName: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_functiondisplayname())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(64)) goto parse_functionDisplayNameRef; - break; - } - - // optional uint64 functionDisplayNameRef = 8; - case 8: { - if (tag == 64) { - parse_functionDisplayNameRef: - clear_FunctionDisplayNameOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &FunctionDisplayNameOrRef_.functiondisplaynameref_))); - set_has_functiondisplaynameref(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(72)) goto parse_isSystem; - break; - } - - // optional bool isSystem = 9; - case 9: { - if (tag == 72) { - parse_isSystem: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &issystem_))); - set_has_issystem(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(80)) goto parse_isSelfHosted; - break; - } - - // optional bool isSelfHosted = 10; - case 10: { - if (tag == 80) { - parse_isSelfHosted: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &isselfhosted_))); - set_has_isselfhosted(); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame.Data) - return true; -failure: - // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.StackFrame.Data) - return false; -#undef DO_ -} - -void StackFrame_Data::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.StackFrame.Data) - // optional uint64 id = 1; - if (has_id()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->id(), output); - } - - // optional .mozilla.devtools.protobuf.StackFrame parent = 2; - if (has_parent()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 2, this->parent(), output); - } - - // optional uint32 line = 3; - if (has_line()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->line(), output); - } - - // optional uint32 column = 4; - if (has_column()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->column(), output); - } - - // optional bytes source = 5; - if (has_source()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 5, this->source(), output); - } - - // optional uint64 sourceRef = 6; - if (has_sourceref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->sourceref(), output); - } - - // optional bytes functionDisplayName = 7; - if (has_functiondisplayname()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 7, this->functiondisplayname(), output); - } - - // optional uint64 functionDisplayNameRef = 8; - if (has_functiondisplaynameref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->functiondisplaynameref(), output); - } - - // optional bool isSystem = 9; - if (has_issystem()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->issystem(), output); - } - - // optional bool isSelfHosted = 10; - if (has_isselfhosted()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->isselfhosted(), output); - } - - if (!unknown_fields().empty()) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output); - } - // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame.Data) -} - -::google::protobuf::uint8* StackFrame_Data::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame.Data) - // optional uint64 id = 1; - if (has_id()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target); - } - - // optional .mozilla.devtools.protobuf.StackFrame parent = 2; - if (has_parent()) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteMessageNoVirtualToArray( - 2, this->parent(), target); - } - - // optional uint32 line = 3; - if (has_line()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->line(), target); - } - - // optional uint32 column = 4; - if (has_column()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->column(), target); - } - - // optional bytes source = 5; - if (has_source()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 5, this->source(), target); - } - - // optional uint64 sourceRef = 6; - if (has_sourceref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(6, this->sourceref(), target); - } - - // optional bytes functionDisplayName = 7; - if (has_functiondisplayname()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 7, this->functiondisplayname(), target); - } - - // optional uint64 functionDisplayNameRef = 8; - if (has_functiondisplaynameref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->functiondisplaynameref(), target); - } - - // optional bool isSystem = 9; - if (has_issystem()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->issystem(), target); - } - - // optional bool isSelfHosted = 10; - if (has_isselfhosted()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->isselfhosted(), target); - } - - if (!unknown_fields().empty()) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - unknown_fields(), target); - } - // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame.Data) - return target; -} - -int StackFrame_Data::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional uint64 id = 1; - if (has_id()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->id()); - } - - // optional .mozilla.devtools.protobuf.StackFrame parent = 2; - if (has_parent()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->parent()); - } - - // optional uint32 line = 3; - if (has_line()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt32Size( - this->line()); - } - - // optional uint32 column = 4; - if (has_column()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt32Size( - this->column()); - } - - } - if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { - // optional bool isSystem = 9; - if (has_issystem()) { - total_size += 1 + 1; - } - - // optional bool isSelfHosted = 10; - if (has_isselfhosted()) { - total_size += 1 + 1; - } - - } - switch (SourceOrRef_case()) { - // optional bytes source = 5; - case kSource: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->source()); - break; - } - // optional uint64 sourceRef = 6; - case kSourceRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->sourceref()); - break; - } - case SOURCEORREF_NOT_SET: { - break; - } - } - switch (FunctionDisplayNameOrRef_case()) { - // optional bytes functionDisplayName = 7; - case kFunctionDisplayName: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->functiondisplayname()); - break; - } - // optional uint64 functionDisplayNameRef = 8; - case kFunctionDisplayNameRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->functiondisplaynameref()); - break; - } - case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { - break; - } - } - if (!unknown_fields().empty()) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - unknown_fields()); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void StackFrame_Data::MergeFrom(const ::google::protobuf::Message& from) { - GOOGLE_CHECK_NE(&from, this); - const StackFrame_Data* source = - ::google::protobuf::internal::dynamic_cast_if_available<const StackFrame_Data*>( - &from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - -void StackFrame_Data::MergeFrom(const StackFrame_Data& from) { - GOOGLE_CHECK_NE(&from, this); - switch (from.SourceOrRef_case()) { - case kSource: { - set_source(from.source()); - break; - } - case kSourceRef: { - set_sourceref(from.sourceref()); - break; - } - case SOURCEORREF_NOT_SET: { - break; - } - } - switch (from.FunctionDisplayNameOrRef_case()) { - case kFunctionDisplayName: { - set_functiondisplayname(from.functiondisplayname()); - break; - } - case kFunctionDisplayNameRef: { - set_functiondisplaynameref(from.functiondisplaynameref()); - break; - } - case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { - break; - } - } - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from.has_id()) { - set_id(from.id()); - } - if (from.has_parent()) { - mutable_parent()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.parent()); - } - if (from.has_line()) { - set_line(from.line()); - } - if (from.has_column()) { - set_column(from.column()); - } - } - if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { - if (from.has_issystem()) { - set_issystem(from.issystem()); - } - if (from.has_isselfhosted()) { - set_isselfhosted(from.isselfhosted()); - } - } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); -} - -void StackFrame_Data::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void StackFrame_Data::CopyFrom(const StackFrame_Data& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool StackFrame_Data::IsInitialized() const { - - return true; -} - -void StackFrame_Data::Swap(StackFrame_Data* other) { - if (other != this) { - std::swap(id_, other->id_); - std::swap(parent_, other->parent_); - std::swap(line_, other->line_); - std::swap(column_, other->column_); - std::swap(issystem_, other->issystem_); - std::swap(isselfhosted_, other->isselfhosted_); - std::swap(SourceOrRef_, other->SourceOrRef_); - std::swap(_oneof_case_[0], other->_oneof_case_[0]); - std::swap(FunctionDisplayNameOrRef_, other->FunctionDisplayNameOrRef_); - std::swap(_oneof_case_[1], other->_oneof_case_[1]); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::google::protobuf::Metadata StackFrame_Data::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = StackFrame_Data_descriptor_; - metadata.reflection = StackFrame_Data_reflection_; - return metadata; -} - - -// ------------------------------------------------------------------- - -#ifndef _MSC_VER -const int StackFrame::kDataFieldNumber; -const int StackFrame::kRefFieldNumber; -#endif // !_MSC_VER - -StackFrame::StackFrame() - : ::google::protobuf::Message() { - SharedCtor(); - // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame) -} - -void StackFrame::InitAsDefaultInstance() { - StackFrame_default_oneof_instance_->data_ = const_cast< ::mozilla::devtools::protobuf::StackFrame_Data*>(&::mozilla::devtools::protobuf::StackFrame_Data::default_instance()); - StackFrame_default_oneof_instance_->ref_ = GOOGLE_ULONGLONG(0); -} - -StackFrame::StackFrame(const StackFrame& from) - : ::google::protobuf::Message() { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.StackFrame) -} - -void StackFrame::SharedCtor() { - _cached_size_ = 0; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - clear_has_StackFrameType(); -} - -StackFrame::~StackFrame() { - // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.StackFrame) - SharedDtor(); -} - -void StackFrame::SharedDtor() { - if (has_StackFrameType()) { - clear_StackFrameType(); - } - if (this != default_instance_) { - } -} - -void StackFrame::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* StackFrame::descriptor() { - protobuf_AssignDescriptorsOnce(); - return StackFrame_descriptor_; -} - -const StackFrame& StackFrame::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto(); - return *default_instance_; -} - -StackFrame* StackFrame::default_instance_ = NULL; - -StackFrame* StackFrame::New() const { - return new StackFrame; -} - -void StackFrame::clear_StackFrameType() { - switch(StackFrameType_case()) { - case kData: { - delete StackFrameType_.data_; - break; - } - case kRef: { - // No need to clear - break; - } - case STACKFRAMETYPE_NOT_SET: { - break; - } - } - _oneof_case_[0] = STACKFRAMETYPE_NOT_SET; -} - - -void StackFrame::Clear() { - clear_StackFrameType(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); -} - -bool StackFrame::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_data())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(16)) goto parse_ref; - break; - } - - // optional uint64 ref = 2; - case 2: { - if (tag == 16) { - parse_ref: - clear_StackFrameType(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &StackFrameType_.ref_))); - set_has_ref(); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame) - return true; -failure: - // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.StackFrame) - return false; -#undef DO_ -} - -void StackFrame::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.StackFrame) - // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; - if (has_data()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->data(), output); - } - - // optional uint64 ref = 2; - if (has_ref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->ref(), output); - } - - if (!unknown_fields().empty()) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output); - } - // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame) -} - -::google::protobuf::uint8* StackFrame::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame) - // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; - if (has_data()) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteMessageNoVirtualToArray( - 1, this->data(), target); - } - - // optional uint64 ref = 2; - if (has_ref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->ref(), target); - } - - if (!unknown_fields().empty()) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - unknown_fields(), target); - } - // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame) - return target; -} - -int StackFrame::ByteSize() const { - int total_size = 0; - - switch (StackFrameType_case()) { - // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; - case kData: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->data()); - break; - } - // optional uint64 ref = 2; - case kRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->ref()); - break; - } - case STACKFRAMETYPE_NOT_SET: { - break; - } - } - if (!unknown_fields().empty()) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - unknown_fields()); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void StackFrame::MergeFrom(const ::google::protobuf::Message& from) { - GOOGLE_CHECK_NE(&from, this); - const StackFrame* source = - ::google::protobuf::internal::dynamic_cast_if_available<const StackFrame*>( - &from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - -void StackFrame::MergeFrom(const StackFrame& from) { - GOOGLE_CHECK_NE(&from, this); - switch (from.StackFrameType_case()) { - case kData: { - mutable_data()->::mozilla::devtools::protobuf::StackFrame_Data::MergeFrom(from.data()); - break; - } - case kRef: { - set_ref(from.ref()); - break; - } - case STACKFRAMETYPE_NOT_SET: { - break; - } - } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); -} - -void StackFrame::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void StackFrame::CopyFrom(const StackFrame& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool StackFrame::IsInitialized() const { - - return true; -} - -void StackFrame::Swap(StackFrame* other) { - if (other != this) { - std::swap(StackFrameType_, other->StackFrameType_); - std::swap(_oneof_case_[0], other->_oneof_case_[0]); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::google::protobuf::Metadata StackFrame::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = StackFrame_descriptor_; - metadata.reflection = StackFrame_reflection_; - return metadata; -} - - -// =================================================================== - -#ifndef _MSC_VER -const int Node::kIdFieldNumber; -const int Node::kTypeNameFieldNumber; -const int Node::kTypeNameRefFieldNumber; -const int Node::kSizeFieldNumber; -const int Node::kEdgesFieldNumber; -const int Node::kAllocationStackFieldNumber; -const int Node::kJsObjectClassNameFieldNumber; -const int Node::kJsObjectClassNameRefFieldNumber; -const int Node::kCoarseTypeFieldNumber; -const int Node::kScriptFilenameFieldNumber; -const int Node::kScriptFilenameRefFieldNumber; -#endif // !_MSC_VER - -Node::Node() - : ::google::protobuf::Message() { - SharedCtor(); - // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Node) -} - -void Node::InitAsDefaultInstance() { - Node_default_oneof_instance_->typename__ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - Node_default_oneof_instance_->typenameref_ = GOOGLE_ULONGLONG(0); - allocationstack_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance()); - Node_default_oneof_instance_->jsobjectclassname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - Node_default_oneof_instance_->jsobjectclassnameref_ = GOOGLE_ULONGLONG(0); - Node_default_oneof_instance_->scriptfilename_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - Node_default_oneof_instance_->scriptfilenameref_ = GOOGLE_ULONGLONG(0); -} - -Node::Node(const Node& from) - : ::google::protobuf::Message() { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Node) -} - -void Node::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - id_ = GOOGLE_ULONGLONG(0); - size_ = GOOGLE_ULONGLONG(0); - allocationstack_ = NULL; - coarsetype_ = 0u; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - clear_has_TypeNameOrRef(); - clear_has_JSObjectClassNameOrRef(); - clear_has_ScriptFilenameOrRef(); -} - -Node::~Node() { - // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Node) - SharedDtor(); -} - -void Node::SharedDtor() { - if (has_TypeNameOrRef()) { - clear_TypeNameOrRef(); - } - if (has_JSObjectClassNameOrRef()) { - clear_JSObjectClassNameOrRef(); - } - if (has_ScriptFilenameOrRef()) { - clear_ScriptFilenameOrRef(); - } - if (this != default_instance_) { - delete allocationstack_; - } -} - -void Node::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Node::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Node_descriptor_; -} - -const Node& Node::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto(); - return *default_instance_; -} - -Node* Node::default_instance_ = NULL; - -Node* Node::New() const { - return new Node; -} - -void Node::clear_TypeNameOrRef() { - switch(TypeNameOrRef_case()) { - case kTypeName: { - delete TypeNameOrRef_.typename__; - break; - } - case kTypeNameRef: { - // No need to clear - break; - } - case TYPENAMEORREF_NOT_SET: { - break; - } - } - _oneof_case_[0] = TYPENAMEORREF_NOT_SET; -} - -void Node::clear_JSObjectClassNameOrRef() { - switch(JSObjectClassNameOrRef_case()) { - case kJsObjectClassName: { - delete JSObjectClassNameOrRef_.jsobjectclassname_; - break; - } - case kJsObjectClassNameRef: { - // No need to clear - break; - } - case JSOBJECTCLASSNAMEORREF_NOT_SET: { - break; - } - } - _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET; -} - -void Node::clear_ScriptFilenameOrRef() { - switch(ScriptFilenameOrRef_case()) { - case kScriptFilename: { - delete ScriptFilenameOrRef_.scriptfilename_; - break; - } - case kScriptFilenameRef: { - // No need to clear - break; - } - case SCRIPTFILENAMEORREF_NOT_SET: { - break; - } - } - _oneof_case_[2] = SCRIPTFILENAMEORREF_NOT_SET; -} - - -void Node::Clear() { -#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \ - &reinterpret_cast<Node*>(16)->f) - \ - reinterpret_cast<char*>(16)) - -#define ZR_(first, last) do { \ - size_t f = OFFSET_OF_FIELD_(first); \ - size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \ - ::memset(&first, 0, n); \ - } while (0) - - if (_has_bits_[0 / 32] & 41) { - ZR_(id_, size_); - if (has_allocationstack()) { - if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear(); - } - } - coarsetype_ = 0u; - -#undef OFFSET_OF_FIELD_ -#undef ZR_ - - edges_.Clear(); - clear_TypeNameOrRef(); - clear_JSObjectClassNameOrRef(); - clear_ScriptFilenameOrRef(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); -} - -bool Node::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Node) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 id = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &id_))); - set_has_id(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_typeName; - break; - } - - // optional bytes typeName = 2; - case 2: { - if (tag == 18) { - parse_typeName: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_typename_())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_typeNameRef; - break; - } - - // optional uint64 typeNameRef = 3; - case 3: { - if (tag == 24) { - parse_typeNameRef: - clear_TypeNameOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &TypeNameOrRef_.typenameref_))); - set_has_typenameref(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(32)) goto parse_size; - break; - } - - // optional uint64 size = 4; - case 4: { - if (tag == 32) { - parse_size: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &size_))); - set_has_size(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(42)) goto parse_edges; - break; - } - - // repeated .mozilla.devtools.protobuf.Edge edges = 5; - case 5: { - if (tag == 42) { - parse_edges: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_edges())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(42)) goto parse_edges; - if (input->ExpectTag(50)) goto parse_allocationStack; - break; - } - - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; - case 6: { - if (tag == 50) { - parse_allocationStack: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_allocationstack())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(58)) goto parse_jsObjectClassName; - break; - } - - // optional bytes jsObjectClassName = 7; - case 7: { - if (tag == 58) { - parse_jsObjectClassName: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_jsobjectclassname())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(64)) goto parse_jsObjectClassNameRef; - break; - } - - // optional uint64 jsObjectClassNameRef = 8; - case 8: { - if (tag == 64) { - parse_jsObjectClassNameRef: - clear_JSObjectClassNameOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &JSObjectClassNameOrRef_.jsobjectclassnameref_))); - set_has_jsobjectclassnameref(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(72)) goto parse_coarseType; - break; - } - - // optional uint32 coarseType = 9 [default = 0]; - case 9: { - if (tag == 72) { - parse_coarseType: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( - input, &coarsetype_))); - set_has_coarsetype(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(82)) goto parse_scriptFilename; - break; - } - - // optional bytes scriptFilename = 10; - case 10: { - if (tag == 82) { - parse_scriptFilename: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_scriptfilename())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(88)) goto parse_scriptFilenameRef; - break; - } - - // optional uint64 scriptFilenameRef = 11; - case 11: { - if (tag == 88) { - parse_scriptFilenameRef: - clear_ScriptFilenameOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &ScriptFilenameOrRef_.scriptfilenameref_))); - set_has_scriptfilenameref(); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Node) - return true; -failure: - // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Node) - return false; -#undef DO_ -} - -void Node::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Node) - // optional uint64 id = 1; - if (has_id()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->id(), output); - } - - // optional bytes typeName = 2; - if (has_typename_()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 2, this->typename_(), output); - } - - // optional uint64 typeNameRef = 3; - if (has_typenameref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->typenameref(), output); - } - - // optional uint64 size = 4; - if (has_size()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->size(), output); - } - - // repeated .mozilla.devtools.protobuf.Edge edges = 5; - for (int i = 0; i < this->edges_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 5, this->edges(i), output); - } - - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; - if (has_allocationstack()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 6, this->allocationstack(), output); - } - - // optional bytes jsObjectClassName = 7; - if (has_jsobjectclassname()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 7, this->jsobjectclassname(), output); - } - - // optional uint64 jsObjectClassNameRef = 8; - if (has_jsobjectclassnameref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->jsobjectclassnameref(), output); - } - - // optional uint32 coarseType = 9 [default = 0]; - if (has_coarsetype()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->coarsetype(), output); - } - - // optional bytes scriptFilename = 10; - if (has_scriptfilename()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 10, this->scriptfilename(), output); - } - - // optional uint64 scriptFilenameRef = 11; - if (has_scriptfilenameref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(11, this->scriptfilenameref(), output); - } - - if (!unknown_fields().empty()) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output); - } - // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Node) -} - -::google::protobuf::uint8* Node::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Node) - // optional uint64 id = 1; - if (has_id()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target); - } - - // optional bytes typeName = 2; - if (has_typename_()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 2, this->typename_(), target); - } - - // optional uint64 typeNameRef = 3; - if (has_typenameref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->typenameref(), target); - } - - // optional uint64 size = 4; - if (has_size()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->size(), target); - } - - // repeated .mozilla.devtools.protobuf.Edge edges = 5; - for (int i = 0; i < this->edges_size(); i++) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteMessageNoVirtualToArray( - 5, this->edges(i), target); - } - - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; - if (has_allocationstack()) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteMessageNoVirtualToArray( - 6, this->allocationstack(), target); - } - - // optional bytes jsObjectClassName = 7; - if (has_jsobjectclassname()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 7, this->jsobjectclassname(), target); - } - - // optional uint64 jsObjectClassNameRef = 8; - if (has_jsobjectclassnameref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->jsobjectclassnameref(), target); - } - - // optional uint32 coarseType = 9 [default = 0]; - if (has_coarsetype()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->coarsetype(), target); - } - - // optional bytes scriptFilename = 10; - if (has_scriptfilename()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 10, this->scriptfilename(), target); - } - - // optional uint64 scriptFilenameRef = 11; - if (has_scriptfilenameref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(11, this->scriptfilenameref(), target); - } - - if (!unknown_fields().empty()) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - unknown_fields(), target); - } - // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Node) - return target; -} - -int Node::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional uint64 id = 1; - if (has_id()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->id()); - } - - // optional uint64 size = 4; - if (has_size()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->size()); - } - - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; - if (has_allocationstack()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->allocationstack()); - } - - } - if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { - // optional uint32 coarseType = 9 [default = 0]; - if (has_coarsetype()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt32Size( - this->coarsetype()); - } - - } - // repeated .mozilla.devtools.protobuf.Edge edges = 5; - total_size += 1 * this->edges_size(); - for (int i = 0; i < this->edges_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->edges(i)); - } - - switch (TypeNameOrRef_case()) { - // optional bytes typeName = 2; - case kTypeName: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->typename_()); - break; - } - // optional uint64 typeNameRef = 3; - case kTypeNameRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->typenameref()); - break; - } - case TYPENAMEORREF_NOT_SET: { - break; - } - } - switch (JSObjectClassNameOrRef_case()) { - // optional bytes jsObjectClassName = 7; - case kJsObjectClassName: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->jsobjectclassname()); - break; - } - // optional uint64 jsObjectClassNameRef = 8; - case kJsObjectClassNameRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->jsobjectclassnameref()); - break; - } - case JSOBJECTCLASSNAMEORREF_NOT_SET: { - break; - } - } - switch (ScriptFilenameOrRef_case()) { - // optional bytes scriptFilename = 10; - case kScriptFilename: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->scriptfilename()); - break; - } - // optional uint64 scriptFilenameRef = 11; - case kScriptFilenameRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->scriptfilenameref()); - break; - } - case SCRIPTFILENAMEORREF_NOT_SET: { - break; - } - } - if (!unknown_fields().empty()) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - unknown_fields()); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Node::MergeFrom(const ::google::protobuf::Message& from) { - GOOGLE_CHECK_NE(&from, this); - const Node* source = - ::google::protobuf::internal::dynamic_cast_if_available<const Node*>( - &from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - -void Node::MergeFrom(const Node& from) { - GOOGLE_CHECK_NE(&from, this); - edges_.MergeFrom(from.edges_); - switch (from.TypeNameOrRef_case()) { - case kTypeName: { - set_typename_(from.typename_()); - break; - } - case kTypeNameRef: { - set_typenameref(from.typenameref()); - break; - } - case TYPENAMEORREF_NOT_SET: { - break; - } - } - switch (from.JSObjectClassNameOrRef_case()) { - case kJsObjectClassName: { - set_jsobjectclassname(from.jsobjectclassname()); - break; - } - case kJsObjectClassNameRef: { - set_jsobjectclassnameref(from.jsobjectclassnameref()); - break; - } - case JSOBJECTCLASSNAMEORREF_NOT_SET: { - break; - } - } - switch (from.ScriptFilenameOrRef_case()) { - case kScriptFilename: { - set_scriptfilename(from.scriptfilename()); - break; - } - case kScriptFilenameRef: { - set_scriptfilenameref(from.scriptfilenameref()); - break; - } - case SCRIPTFILENAMEORREF_NOT_SET: { - break; - } - } - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from.has_id()) { - set_id(from.id()); - } - if (from.has_size()) { - set_size(from.size()); - } - if (from.has_allocationstack()) { - mutable_allocationstack()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.allocationstack()); - } - } - if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { - if (from.has_coarsetype()) { - set_coarsetype(from.coarsetype()); - } - } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); -} - -void Node::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Node::CopyFrom(const Node& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Node::IsInitialized() const { - - return true; -} - -void Node::Swap(Node* other) { - if (other != this) { - std::swap(id_, other->id_); - std::swap(size_, other->size_); - edges_.Swap(&other->edges_); - std::swap(allocationstack_, other->allocationstack_); - std::swap(coarsetype_, other->coarsetype_); - std::swap(TypeNameOrRef_, other->TypeNameOrRef_); - std::swap(_oneof_case_[0], other->_oneof_case_[0]); - std::swap(JSObjectClassNameOrRef_, other->JSObjectClassNameOrRef_); - std::swap(_oneof_case_[1], other->_oneof_case_[1]); - std::swap(ScriptFilenameOrRef_, other->ScriptFilenameOrRef_); - std::swap(_oneof_case_[2], other->_oneof_case_[2]); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::google::protobuf::Metadata Node::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Node_descriptor_; - metadata.reflection = Node_reflection_; - return metadata; -} - - -// =================================================================== - -#ifndef _MSC_VER -const int Edge::kReferentFieldNumber; -const int Edge::kNameFieldNumber; -const int Edge::kNameRefFieldNumber; -#endif // !_MSC_VER - -Edge::Edge() - : ::google::protobuf::Message() { - SharedCtor(); - // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Edge) -} - -void Edge::InitAsDefaultInstance() { - Edge_default_oneof_instance_->name_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); - Edge_default_oneof_instance_->nameref_ = GOOGLE_ULONGLONG(0); -} - -Edge::Edge(const Edge& from) - : ::google::protobuf::Message() { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Edge) -} - -void Edge::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - referent_ = GOOGLE_ULONGLONG(0); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - clear_has_EdgeNameOrRef(); -} - -Edge::~Edge() { - // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Edge) - SharedDtor(); -} - -void Edge::SharedDtor() { - if (has_EdgeNameOrRef()) { - clear_EdgeNameOrRef(); - } - if (this != default_instance_) { - } -} - -void Edge::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Edge::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Edge_descriptor_; -} - -const Edge& Edge::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto(); - return *default_instance_; -} - -Edge* Edge::default_instance_ = NULL; - -Edge* Edge::New() const { - return new Edge; -} - -void Edge::clear_EdgeNameOrRef() { - switch(EdgeNameOrRef_case()) { - case kName: { - delete EdgeNameOrRef_.name_; - break; - } - case kNameRef: { - // No need to clear - break; - } - case EDGENAMEORREF_NOT_SET: { - break; - } - } - _oneof_case_[0] = EDGENAMEORREF_NOT_SET; -} - - -void Edge::Clear() { - referent_ = GOOGLE_ULONGLONG(0); - clear_EdgeNameOrRef(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); -} - -bool Edge::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Edge) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 referent = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &referent_))); - set_has_referent(); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_name; - break; - } - - // optional bytes name = 2; - case 2: { - if (tag == 18) { - parse_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_name())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_nameRef; - break; - } - - // optional uint64 nameRef = 3; - case 3: { - if (tag == 24) { - parse_nameRef: - clear_EdgeNameOrRef(); - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &EdgeNameOrRef_.nameref_))); - set_has_nameref(); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Edge) - return true; -failure: - // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Edge) - return false; -#undef DO_ -} - -void Edge::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Edge) - // optional uint64 referent = 1; - if (has_referent()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->referent(), output); - } - - // optional bytes name = 2; - if (has_name()) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 2, this->name(), output); - } - - // optional uint64 nameRef = 3; - if (has_nameref()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->nameref(), output); - } - - if (!unknown_fields().empty()) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output); - } - // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Edge) -} - -::google::protobuf::uint8* Edge::SerializeWithCachedSizesToArray( - ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Edge) - // optional uint64 referent = 1; - if (has_referent()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->referent(), target); - } - - // optional bytes name = 2; - if (has_name()) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 2, this->name(), target); - } - - // optional uint64 nameRef = 3; - if (has_nameref()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->nameref(), target); - } - - if (!unknown_fields().empty()) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - unknown_fields(), target); - } - // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Edge) - return target; -} - -int Edge::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional uint64 referent = 1; - if (has_referent()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->referent()); - } - - } - switch (EdgeNameOrRef_case()) { - // optional bytes name = 2; - case kName: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->name()); - break; - } - // optional uint64 nameRef = 3; - case kNameRef: { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->nameref()); - break; - } - case EDGENAMEORREF_NOT_SET: { - break; - } - } - if (!unknown_fields().empty()) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - unknown_fields()); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Edge::MergeFrom(const ::google::protobuf::Message& from) { - GOOGLE_CHECK_NE(&from, this); - const Edge* source = - ::google::protobuf::internal::dynamic_cast_if_available<const Edge*>( - &from); - if (source == NULL) { - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - MergeFrom(*source); - } -} - -void Edge::MergeFrom(const Edge& from) { - GOOGLE_CHECK_NE(&from, this); - switch (from.EdgeNameOrRef_case()) { - case kName: { - set_name(from.name()); - break; - } - case kNameRef: { - set_nameref(from.nameref()); - break; - } - case EDGENAMEORREF_NOT_SET: { - break; - } - } - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from.has_referent()) { - set_referent(from.referent()); - } - } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); -} - -void Edge::CopyFrom(const ::google::protobuf::Message& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Edge::CopyFrom(const Edge& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Edge::IsInitialized() const { - - return true; -} - -void Edge::Swap(Edge* other) { - if (other != this) { - std::swap(referent_, other->referent_); - std::swap(EdgeNameOrRef_, other->EdgeNameOrRef_); - std::swap(_oneof_case_[0], other->_oneof_case_[0]); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::google::protobuf::Metadata Edge::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Edge_descriptor_; - metadata.reflection = Edge_reflection_; - return metadata; -} - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace protobuf -} // namespace devtools -} // namespace mozilla - -// @@protoc_insertion_point(global_scope) diff --git a/devtools/shared/heapsnapshot/CoreDump.pb.h b/devtools/shared/heapsnapshot/CoreDump.pb.h deleted file mode 100644 index 584c2e379..000000000 --- a/devtools/shared/heapsnapshot/CoreDump.pb.h +++ /dev/null @@ -1,1893 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: CoreDump.proto - -#ifndef PROTOBUF_CoreDump_2eproto__INCLUDED -#define PROTOBUF_CoreDump_2eproto__INCLUDED - -#include <string> - -#include <google/protobuf/stubs/common.h> - -#if GOOGLE_PROTOBUF_VERSION < 2006000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include <google/protobuf/generated_message_util.h> -#include <google/protobuf/message.h> -#include <google/protobuf/repeated_field.h> -#include <google/protobuf/extension_set.h> -#include <google/protobuf/unknown_field_set.h> -// @@protoc_insertion_point(includes) - -namespace mozilla { -namespace devtools { -namespace protobuf { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_CoreDump_2eproto(); -void protobuf_AssignDesc_CoreDump_2eproto(); -void protobuf_ShutdownFile_CoreDump_2eproto(); - -class Metadata; -class StackFrame; -class StackFrame_Data; -class Node; -class Edge; - -// =================================================================== - -class Metadata : public ::google::protobuf::Message { - public: - Metadata(); - virtual ~Metadata(); - - Metadata(const Metadata& from); - - inline Metadata& operator=(const Metadata& from) { - CopyFrom(from); - return *this; - } - - inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; - } - - inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Metadata& default_instance(); - - void Swap(Metadata* other); - - // implements Message ---------------------------------------------- - - Metadata* New() const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Metadata& from); - void MergeFrom(const Metadata& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 timeStamp = 1; - inline bool has_timestamp() const; - inline void clear_timestamp(); - static const int kTimeStampFieldNumber = 1; - inline ::google::protobuf::uint64 timestamp() const; - inline void set_timestamp(::google::protobuf::uint64 value); - - // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Metadata) - private: - inline void set_has_timestamp(); - inline void clear_has_timestamp(); - - ::google::protobuf::UnknownFieldSet _unknown_fields_; - - ::google::protobuf::uint32 _has_bits_[1]; - mutable int _cached_size_; - ::google::protobuf::uint64 timestamp_; - friend void protobuf_AddDesc_CoreDump_2eproto(); - friend void protobuf_AssignDesc_CoreDump_2eproto(); - friend void protobuf_ShutdownFile_CoreDump_2eproto(); - - void InitAsDefaultInstance(); - static Metadata* default_instance_; -}; -// ------------------------------------------------------------------- - -class StackFrame_Data : public ::google::protobuf::Message { - public: - StackFrame_Data(); - virtual ~StackFrame_Data(); - - StackFrame_Data(const StackFrame_Data& from); - - inline StackFrame_Data& operator=(const StackFrame_Data& from) { - CopyFrom(from); - return *this; - } - - inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; - } - - inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const StackFrame_Data& default_instance(); - - enum SourceOrRefCase { - kSource = 5, - kSourceRef = 6, - SOURCEORREF_NOT_SET = 0, - }; - - enum FunctionDisplayNameOrRefCase { - kFunctionDisplayName = 7, - kFunctionDisplayNameRef = 8, - FUNCTIONDISPLAYNAMEORREF_NOT_SET = 0, - }; - - void Swap(StackFrame_Data* other); - - // implements Message ---------------------------------------------- - - StackFrame_Data* New() const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const StackFrame_Data& from); - void MergeFrom(const StackFrame_Data& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 id = 1; - inline bool has_id() const; - inline void clear_id(); - static const int kIdFieldNumber = 1; - inline ::google::protobuf::uint64 id() const; - inline void set_id(::google::protobuf::uint64 value); - - // optional .mozilla.devtools.protobuf.StackFrame parent = 2; - inline bool has_parent() const; - inline void clear_parent(); - static const int kParentFieldNumber = 2; - inline const ::mozilla::devtools::protobuf::StackFrame& parent() const; - inline ::mozilla::devtools::protobuf::StackFrame* mutable_parent(); - inline ::mozilla::devtools::protobuf::StackFrame* release_parent(); - inline void set_allocated_parent(::mozilla::devtools::protobuf::StackFrame* parent); - - // optional uint32 line = 3; - inline bool has_line() const; - inline void clear_line(); - static const int kLineFieldNumber = 3; - inline ::google::protobuf::uint32 line() const; - inline void set_line(::google::protobuf::uint32 value); - - // optional uint32 column = 4; - inline bool has_column() const; - inline void clear_column(); - static const int kColumnFieldNumber = 4; - inline ::google::protobuf::uint32 column() const; - inline void set_column(::google::protobuf::uint32 value); - - // optional bytes source = 5; - inline bool has_source() const; - inline void clear_source(); - static const int kSourceFieldNumber = 5; - inline const ::std::string& source() const; - inline void set_source(const ::std::string& value); - inline void set_source(const char* value); - inline void set_source(const void* value, size_t size); - inline ::std::string* mutable_source(); - inline ::std::string* release_source(); - inline void set_allocated_source(::std::string* source); - - // optional uint64 sourceRef = 6; - inline bool has_sourceref() const; - inline void clear_sourceref(); - static const int kSourceRefFieldNumber = 6; - inline ::google::protobuf::uint64 sourceref() const; - inline void set_sourceref(::google::protobuf::uint64 value); - - // optional bytes functionDisplayName = 7; - inline bool has_functiondisplayname() const; - inline void clear_functiondisplayname(); - static const int kFunctionDisplayNameFieldNumber = 7; - inline const ::std::string& functiondisplayname() const; - inline void set_functiondisplayname(const ::std::string& value); - inline void set_functiondisplayname(const char* value); - inline void set_functiondisplayname(const void* value, size_t size); - inline ::std::string* mutable_functiondisplayname(); - inline ::std::string* release_functiondisplayname(); - inline void set_allocated_functiondisplayname(::std::string* functiondisplayname); - - // optional uint64 functionDisplayNameRef = 8; - inline bool has_functiondisplaynameref() const; - inline void clear_functiondisplaynameref(); - static const int kFunctionDisplayNameRefFieldNumber = 8; - inline ::google::protobuf::uint64 functiondisplaynameref() const; - inline void set_functiondisplaynameref(::google::protobuf::uint64 value); - - // optional bool isSystem = 9; - inline bool has_issystem() const; - inline void clear_issystem(); - static const int kIsSystemFieldNumber = 9; - inline bool issystem() const; - inline void set_issystem(bool value); - - // optional bool isSelfHosted = 10; - inline bool has_isselfhosted() const; - inline void clear_isselfhosted(); - static const int kIsSelfHostedFieldNumber = 10; - inline bool isselfhosted() const; - inline void set_isselfhosted(bool value); - - inline SourceOrRefCase SourceOrRef_case() const; - inline FunctionDisplayNameOrRefCase FunctionDisplayNameOrRef_case() const; - // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.StackFrame.Data) - private: - inline void set_has_id(); - inline void clear_has_id(); - inline void set_has_parent(); - inline void clear_has_parent(); - inline void set_has_line(); - inline void clear_has_line(); - inline void set_has_column(); - inline void clear_has_column(); - inline void set_has_source(); - inline void set_has_sourceref(); - inline void set_has_functiondisplayname(); - inline void set_has_functiondisplaynameref(); - inline void set_has_issystem(); - inline void clear_has_issystem(); - inline void set_has_isselfhosted(); - inline void clear_has_isselfhosted(); - - inline bool has_SourceOrRef(); - void clear_SourceOrRef(); - inline void clear_has_SourceOrRef(); - - inline bool has_FunctionDisplayNameOrRef(); - void clear_FunctionDisplayNameOrRef(); - inline void clear_has_FunctionDisplayNameOrRef(); - - ::google::protobuf::UnknownFieldSet _unknown_fields_; - - ::google::protobuf::uint32 _has_bits_[1]; - mutable int _cached_size_; - ::google::protobuf::uint64 id_; - ::mozilla::devtools::protobuf::StackFrame* parent_; - ::google::protobuf::uint32 line_; - ::google::protobuf::uint32 column_; - bool issystem_; - bool isselfhosted_; - union SourceOrRefUnion { - ::std::string* source_; - ::google::protobuf::uint64 sourceref_; - } SourceOrRef_; - union FunctionDisplayNameOrRefUnion { - ::std::string* functiondisplayname_; - ::google::protobuf::uint64 functiondisplaynameref_; - } FunctionDisplayNameOrRef_; - ::google::protobuf::uint32 _oneof_case_[2]; - - friend void protobuf_AddDesc_CoreDump_2eproto(); - friend void protobuf_AssignDesc_CoreDump_2eproto(); - friend void protobuf_ShutdownFile_CoreDump_2eproto(); - - void InitAsDefaultInstance(); - static StackFrame_Data* default_instance_; -}; -// ------------------------------------------------------------------- - -class StackFrame : public ::google::protobuf::Message { - public: - StackFrame(); - virtual ~StackFrame(); - - StackFrame(const StackFrame& from); - - inline StackFrame& operator=(const StackFrame& from) { - CopyFrom(from); - return *this; - } - - inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; - } - - inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const StackFrame& default_instance(); - - enum StackFrameTypeCase { - kData = 1, - kRef = 2, - STACKFRAMETYPE_NOT_SET = 0, - }; - - void Swap(StackFrame* other); - - // implements Message ---------------------------------------------- - - StackFrame* New() const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const StackFrame& from); - void MergeFrom(const StackFrame& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - typedef StackFrame_Data Data; - - // accessors ------------------------------------------------------- - - // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; - inline bool has_data() const; - inline void clear_data(); - static const int kDataFieldNumber = 1; - inline const ::mozilla::devtools::protobuf::StackFrame_Data& data() const; - inline ::mozilla::devtools::protobuf::StackFrame_Data* mutable_data(); - inline ::mozilla::devtools::protobuf::StackFrame_Data* release_data(); - inline void set_allocated_data(::mozilla::devtools::protobuf::StackFrame_Data* data); - - // optional uint64 ref = 2; - inline bool has_ref() const; - inline void clear_ref(); - static const int kRefFieldNumber = 2; - inline ::google::protobuf::uint64 ref() const; - inline void set_ref(::google::protobuf::uint64 value); - - inline StackFrameTypeCase StackFrameType_case() const; - // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.StackFrame) - private: - inline void set_has_data(); - inline void set_has_ref(); - - inline bool has_StackFrameType(); - void clear_StackFrameType(); - inline void clear_has_StackFrameType(); - - ::google::protobuf::UnknownFieldSet _unknown_fields_; - - ::google::protobuf::uint32 _has_bits_[1]; - mutable int _cached_size_; - union StackFrameTypeUnion { - ::mozilla::devtools::protobuf::StackFrame_Data* data_; - ::google::protobuf::uint64 ref_; - } StackFrameType_; - ::google::protobuf::uint32 _oneof_case_[1]; - - friend void protobuf_AddDesc_CoreDump_2eproto(); - friend void protobuf_AssignDesc_CoreDump_2eproto(); - friend void protobuf_ShutdownFile_CoreDump_2eproto(); - - void InitAsDefaultInstance(); - static StackFrame* default_instance_; -}; -// ------------------------------------------------------------------- - -class Node : public ::google::protobuf::Message { - public: - Node(); - virtual ~Node(); - - Node(const Node& from); - - inline Node& operator=(const Node& from) { - CopyFrom(from); - return *this; - } - - inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; - } - - inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Node& default_instance(); - - enum TypeNameOrRefCase { - kTypeName = 2, - kTypeNameRef = 3, - TYPENAMEORREF_NOT_SET = 0, - }; - - enum JSObjectClassNameOrRefCase { - kJsObjectClassName = 7, - kJsObjectClassNameRef = 8, - JSOBJECTCLASSNAMEORREF_NOT_SET = 0, - }; - - enum ScriptFilenameOrRefCase { - kScriptFilename = 10, - kScriptFilenameRef = 11, - SCRIPTFILENAMEORREF_NOT_SET = 0, - }; - - void Swap(Node* other); - - // implements Message ---------------------------------------------- - - Node* New() const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Node& from); - void MergeFrom(const Node& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 id = 1; - inline bool has_id() const; - inline void clear_id(); - static const int kIdFieldNumber = 1; - inline ::google::protobuf::uint64 id() const; - inline void set_id(::google::protobuf::uint64 value); - - // optional bytes typeName = 2; - inline bool has_typename_() const; - inline void clear_typename_(); - static const int kTypeNameFieldNumber = 2; - inline const ::std::string& typename_() const; - inline void set_typename_(const ::std::string& value); - inline void set_typename_(const char* value); - inline void set_typename_(const void* value, size_t size); - inline ::std::string* mutable_typename_(); - inline ::std::string* release_typename_(); - inline void set_allocated_typename_(::std::string* typename_); - - // optional uint64 typeNameRef = 3; - inline bool has_typenameref() const; - inline void clear_typenameref(); - static const int kTypeNameRefFieldNumber = 3; - inline ::google::protobuf::uint64 typenameref() const; - inline void set_typenameref(::google::protobuf::uint64 value); - - // optional uint64 size = 4; - inline bool has_size() const; - inline void clear_size(); - static const int kSizeFieldNumber = 4; - inline ::google::protobuf::uint64 size() const; - inline void set_size(::google::protobuf::uint64 value); - - // repeated .mozilla.devtools.protobuf.Edge edges = 5; - inline int edges_size() const; - inline void clear_edges(); - static const int kEdgesFieldNumber = 5; - inline const ::mozilla::devtools::protobuf::Edge& edges(int index) const; - inline ::mozilla::devtools::protobuf::Edge* mutable_edges(int index); - inline ::mozilla::devtools::protobuf::Edge* add_edges(); - inline const ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >& - edges() const; - inline ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >* - mutable_edges(); - - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; - inline bool has_allocationstack() const; - inline void clear_allocationstack(); - static const int kAllocationStackFieldNumber = 6; - inline const ::mozilla::devtools::protobuf::StackFrame& allocationstack() const; - inline ::mozilla::devtools::protobuf::StackFrame* mutable_allocationstack(); - inline ::mozilla::devtools::protobuf::StackFrame* release_allocationstack(); - inline void set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack); - - // optional bytes jsObjectClassName = 7; - inline bool has_jsobjectclassname() const; - inline void clear_jsobjectclassname(); - static const int kJsObjectClassNameFieldNumber = 7; - inline const ::std::string& jsobjectclassname() const; - inline void set_jsobjectclassname(const ::std::string& value); - inline void set_jsobjectclassname(const char* value); - inline void set_jsobjectclassname(const void* value, size_t size); - inline ::std::string* mutable_jsobjectclassname(); - inline ::std::string* release_jsobjectclassname(); - inline void set_allocated_jsobjectclassname(::std::string* jsobjectclassname); - - // optional uint64 jsObjectClassNameRef = 8; - inline bool has_jsobjectclassnameref() const; - inline void clear_jsobjectclassnameref(); - static const int kJsObjectClassNameRefFieldNumber = 8; - inline ::google::protobuf::uint64 jsobjectclassnameref() const; - inline void set_jsobjectclassnameref(::google::protobuf::uint64 value); - - // optional uint32 coarseType = 9 [default = 0]; - inline bool has_coarsetype() const; - inline void clear_coarsetype(); - static const int kCoarseTypeFieldNumber = 9; - inline ::google::protobuf::uint32 coarsetype() const; - inline void set_coarsetype(::google::protobuf::uint32 value); - - // optional bytes scriptFilename = 10; - inline bool has_scriptfilename() const; - inline void clear_scriptfilename(); - static const int kScriptFilenameFieldNumber = 10; - inline const ::std::string& scriptfilename() const; - inline void set_scriptfilename(const ::std::string& value); - inline void set_scriptfilename(const char* value); - inline void set_scriptfilename(const void* value, size_t size); - inline ::std::string* mutable_scriptfilename(); - inline ::std::string* release_scriptfilename(); - inline void set_allocated_scriptfilename(::std::string* scriptfilename); - - // optional uint64 scriptFilenameRef = 11; - inline bool has_scriptfilenameref() const; - inline void clear_scriptfilenameref(); - static const int kScriptFilenameRefFieldNumber = 11; - inline ::google::protobuf::uint64 scriptfilenameref() const; - inline void set_scriptfilenameref(::google::protobuf::uint64 value); - - inline TypeNameOrRefCase TypeNameOrRef_case() const; - inline JSObjectClassNameOrRefCase JSObjectClassNameOrRef_case() const; - inline ScriptFilenameOrRefCase ScriptFilenameOrRef_case() const; - // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Node) - private: - inline void set_has_id(); - inline void clear_has_id(); - inline void set_has_typename_(); - inline void set_has_typenameref(); - inline void set_has_size(); - inline void clear_has_size(); - inline void set_has_allocationstack(); - inline void clear_has_allocationstack(); - inline void set_has_jsobjectclassname(); - inline void set_has_jsobjectclassnameref(); - inline void set_has_coarsetype(); - inline void clear_has_coarsetype(); - inline void set_has_scriptfilename(); - inline void set_has_scriptfilenameref(); - - inline bool has_TypeNameOrRef(); - void clear_TypeNameOrRef(); - inline void clear_has_TypeNameOrRef(); - - inline bool has_JSObjectClassNameOrRef(); - void clear_JSObjectClassNameOrRef(); - inline void clear_has_JSObjectClassNameOrRef(); - - inline bool has_ScriptFilenameOrRef(); - void clear_ScriptFilenameOrRef(); - inline void clear_has_ScriptFilenameOrRef(); - - ::google::protobuf::UnknownFieldSet _unknown_fields_; - - ::google::protobuf::uint32 _has_bits_[1]; - mutable int _cached_size_; - ::google::protobuf::uint64 id_; - ::google::protobuf::uint64 size_; - ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge > edges_; - ::mozilla::devtools::protobuf::StackFrame* allocationstack_; - ::google::protobuf::uint32 coarsetype_; - union TypeNameOrRefUnion { - ::std::string* typename__; - ::google::protobuf::uint64 typenameref_; - } TypeNameOrRef_; - union JSObjectClassNameOrRefUnion { - ::std::string* jsobjectclassname_; - ::google::protobuf::uint64 jsobjectclassnameref_; - } JSObjectClassNameOrRef_; - union ScriptFilenameOrRefUnion { - ::std::string* scriptfilename_; - ::google::protobuf::uint64 scriptfilenameref_; - } ScriptFilenameOrRef_; - ::google::protobuf::uint32 _oneof_case_[3]; - - friend void protobuf_AddDesc_CoreDump_2eproto(); - friend void protobuf_AssignDesc_CoreDump_2eproto(); - friend void protobuf_ShutdownFile_CoreDump_2eproto(); - - void InitAsDefaultInstance(); - static Node* default_instance_; -}; -// ------------------------------------------------------------------- - -class Edge : public ::google::protobuf::Message { - public: - Edge(); - virtual ~Edge(); - - Edge(const Edge& from); - - inline Edge& operator=(const Edge& from) { - CopyFrom(from); - return *this; - } - - inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; - } - - inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Edge& default_instance(); - - enum EdgeNameOrRefCase { - kName = 2, - kNameRef = 3, - EDGENAMEORREF_NOT_SET = 0, - }; - - void Swap(Edge* other); - - // implements Message ---------------------------------------------- - - Edge* New() const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Edge& from); - void MergeFrom(const Edge& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 referent = 1; - inline bool has_referent() const; - inline void clear_referent(); - static const int kReferentFieldNumber = 1; - inline ::google::protobuf::uint64 referent() const; - inline void set_referent(::google::protobuf::uint64 value); - - // optional bytes name = 2; - inline bool has_name() const; - inline void clear_name(); - static const int kNameFieldNumber = 2; - inline const ::std::string& name() const; - inline void set_name(const ::std::string& value); - inline void set_name(const char* value); - inline void set_name(const void* value, size_t size); - inline ::std::string* mutable_name(); - inline ::std::string* release_name(); - inline void set_allocated_name(::std::string* name); - - // optional uint64 nameRef = 3; - inline bool has_nameref() const; - inline void clear_nameref(); - static const int kNameRefFieldNumber = 3; - inline ::google::protobuf::uint64 nameref() const; - inline void set_nameref(::google::protobuf::uint64 value); - - inline EdgeNameOrRefCase EdgeNameOrRef_case() const; - // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Edge) - private: - inline void set_has_referent(); - inline void clear_has_referent(); - inline void set_has_name(); - inline void set_has_nameref(); - - inline bool has_EdgeNameOrRef(); - void clear_EdgeNameOrRef(); - inline void clear_has_EdgeNameOrRef(); - - ::google::protobuf::UnknownFieldSet _unknown_fields_; - - ::google::protobuf::uint32 _has_bits_[1]; - mutable int _cached_size_; - ::google::protobuf::uint64 referent_; - union EdgeNameOrRefUnion { - ::std::string* name_; - ::google::protobuf::uint64 nameref_; - } EdgeNameOrRef_; - ::google::protobuf::uint32 _oneof_case_[1]; - - friend void protobuf_AddDesc_CoreDump_2eproto(); - friend void protobuf_AssignDesc_CoreDump_2eproto(); - friend void protobuf_ShutdownFile_CoreDump_2eproto(); - - void InitAsDefaultInstance(); - static Edge* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -// Metadata - -// optional uint64 timeStamp = 1; -inline bool Metadata::has_timestamp() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -inline void Metadata::set_has_timestamp() { - _has_bits_[0] |= 0x00000001u; -} -inline void Metadata::clear_has_timestamp() { - _has_bits_[0] &= ~0x00000001u; -} -inline void Metadata::clear_timestamp() { - timestamp_ = GOOGLE_ULONGLONG(0); - clear_has_timestamp(); -} -inline ::google::protobuf::uint64 Metadata::timestamp() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Metadata.timeStamp) - return timestamp_; -} -inline void Metadata::set_timestamp(::google::protobuf::uint64 value) { - set_has_timestamp(); - timestamp_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Metadata.timeStamp) -} - -// ------------------------------------------------------------------- - -// StackFrame_Data - -// optional uint64 id = 1; -inline bool StackFrame_Data::has_id() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -inline void StackFrame_Data::set_has_id() { - _has_bits_[0] |= 0x00000001u; -} -inline void StackFrame_Data::clear_has_id() { - _has_bits_[0] &= ~0x00000001u; -} -inline void StackFrame_Data::clear_id() { - id_ = GOOGLE_ULONGLONG(0); - clear_has_id(); -} -inline ::google::protobuf::uint64 StackFrame_Data::id() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.id) - return id_; -} -inline void StackFrame_Data::set_id(::google::protobuf::uint64 value) { - set_has_id(); - id_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.id) -} - -// optional .mozilla.devtools.protobuf.StackFrame parent = 2; -inline bool StackFrame_Data::has_parent() const { - return (_has_bits_[0] & 0x00000002u) != 0; -} -inline void StackFrame_Data::set_has_parent() { - _has_bits_[0] |= 0x00000002u; -} -inline void StackFrame_Data::clear_has_parent() { - _has_bits_[0] &= ~0x00000002u; -} -inline void StackFrame_Data::clear_parent() { - if (parent_ != NULL) parent_->::mozilla::devtools::protobuf::StackFrame::Clear(); - clear_has_parent(); -} -inline const ::mozilla::devtools::protobuf::StackFrame& StackFrame_Data::parent() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.parent) - return parent_ != NULL ? *parent_ : *default_instance_->parent_; -} -inline ::mozilla::devtools::protobuf::StackFrame* StackFrame_Data::mutable_parent() { - set_has_parent(); - if (parent_ == NULL) parent_ = new ::mozilla::devtools::protobuf::StackFrame; - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.StackFrame.Data.parent) - return parent_; -} -inline ::mozilla::devtools::protobuf::StackFrame* StackFrame_Data::release_parent() { - clear_has_parent(); - ::mozilla::devtools::protobuf::StackFrame* temp = parent_; - parent_ = NULL; - return temp; -} -inline void StackFrame_Data::set_allocated_parent(::mozilla::devtools::protobuf::StackFrame* parent) { - delete parent_; - parent_ = parent; - if (parent) { - set_has_parent(); - } else { - clear_has_parent(); - } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.StackFrame.Data.parent) -} - -// optional uint32 line = 3; -inline bool StackFrame_Data::has_line() const { - return (_has_bits_[0] & 0x00000004u) != 0; -} -inline void StackFrame_Data::set_has_line() { - _has_bits_[0] |= 0x00000004u; -} -inline void StackFrame_Data::clear_has_line() { - _has_bits_[0] &= ~0x00000004u; -} -inline void StackFrame_Data::clear_line() { - line_ = 0u; - clear_has_line(); -} -inline ::google::protobuf::uint32 StackFrame_Data::line() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.line) - return line_; -} -inline void StackFrame_Data::set_line(::google::protobuf::uint32 value) { - set_has_line(); - line_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.line) -} - -// optional uint32 column = 4; -inline bool StackFrame_Data::has_column() const { - return (_has_bits_[0] & 0x00000008u) != 0; -} -inline void StackFrame_Data::set_has_column() { - _has_bits_[0] |= 0x00000008u; -} -inline void StackFrame_Data::clear_has_column() { - _has_bits_[0] &= ~0x00000008u; -} -inline void StackFrame_Data::clear_column() { - column_ = 0u; - clear_has_column(); -} -inline ::google::protobuf::uint32 StackFrame_Data::column() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.column) - return column_; -} -inline void StackFrame_Data::set_column(::google::protobuf::uint32 value) { - set_has_column(); - column_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.column) -} - -// optional bytes source = 5; -inline bool StackFrame_Data::has_source() const { - return SourceOrRef_case() == kSource; -} -inline void StackFrame_Data::set_has_source() { - _oneof_case_[0] = kSource; -} -inline void StackFrame_Data::clear_source() { - if (has_source()) { - delete SourceOrRef_.source_; - clear_has_SourceOrRef(); - } -} -inline const ::std::string& StackFrame_Data::source() const { - if (has_source()) { - return *SourceOrRef_.source_; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void StackFrame_Data::set_source(const ::std::string& value) { - if (!has_source()) { - clear_SourceOrRef(); - set_has_source(); - SourceOrRef_.source_ = new ::std::string; - } - SourceOrRef_.source_->assign(value); -} -inline void StackFrame_Data::set_source(const char* value) { - if (!has_source()) { - clear_SourceOrRef(); - set_has_source(); - SourceOrRef_.source_ = new ::std::string; - } - SourceOrRef_.source_->assign(value); -} -inline void StackFrame_Data::set_source(const void* value, size_t size) { - if (!has_source()) { - clear_SourceOrRef(); - set_has_source(); - SourceOrRef_.source_ = new ::std::string; - } - SourceOrRef_.source_->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* StackFrame_Data::mutable_source() { - if (!has_source()) { - clear_SourceOrRef(); - set_has_source(); - SourceOrRef_.source_ = new ::std::string; - } - return SourceOrRef_.source_; -} -inline ::std::string* StackFrame_Data::release_source() { - if (has_source()) { - clear_has_SourceOrRef(); - ::std::string* temp = SourceOrRef_.source_; - SourceOrRef_.source_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void StackFrame_Data::set_allocated_source(::std::string* source) { - clear_SourceOrRef(); - if (source) { - set_has_source(); - SourceOrRef_.source_ = source; - } -} - -// optional uint64 sourceRef = 6; -inline bool StackFrame_Data::has_sourceref() const { - return SourceOrRef_case() == kSourceRef; -} -inline void StackFrame_Data::set_has_sourceref() { - _oneof_case_[0] = kSourceRef; -} -inline void StackFrame_Data::clear_sourceref() { - if (has_sourceref()) { - SourceOrRef_.sourceref_ = GOOGLE_ULONGLONG(0); - clear_has_SourceOrRef(); - } -} -inline ::google::protobuf::uint64 StackFrame_Data::sourceref() const { - if (has_sourceref()) { - return SourceOrRef_.sourceref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void StackFrame_Data::set_sourceref(::google::protobuf::uint64 value) { - if (!has_sourceref()) { - clear_SourceOrRef(); - set_has_sourceref(); - } - SourceOrRef_.sourceref_ = value; -} - -// optional bytes functionDisplayName = 7; -inline bool StackFrame_Data::has_functiondisplayname() const { - return FunctionDisplayNameOrRef_case() == kFunctionDisplayName; -} -inline void StackFrame_Data::set_has_functiondisplayname() { - _oneof_case_[1] = kFunctionDisplayName; -} -inline void StackFrame_Data::clear_functiondisplayname() { - if (has_functiondisplayname()) { - delete FunctionDisplayNameOrRef_.functiondisplayname_; - clear_has_FunctionDisplayNameOrRef(); - } -} -inline const ::std::string& StackFrame_Data::functiondisplayname() const { - if (has_functiondisplayname()) { - return *FunctionDisplayNameOrRef_.functiondisplayname_; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void StackFrame_Data::set_functiondisplayname(const ::std::string& value) { - if (!has_functiondisplayname()) { - clear_FunctionDisplayNameOrRef(); - set_has_functiondisplayname(); - FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; - } - FunctionDisplayNameOrRef_.functiondisplayname_->assign(value); -} -inline void StackFrame_Data::set_functiondisplayname(const char* value) { - if (!has_functiondisplayname()) { - clear_FunctionDisplayNameOrRef(); - set_has_functiondisplayname(); - FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; - } - FunctionDisplayNameOrRef_.functiondisplayname_->assign(value); -} -inline void StackFrame_Data::set_functiondisplayname(const void* value, size_t size) { - if (!has_functiondisplayname()) { - clear_FunctionDisplayNameOrRef(); - set_has_functiondisplayname(); - FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; - } - FunctionDisplayNameOrRef_.functiondisplayname_->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* StackFrame_Data::mutable_functiondisplayname() { - if (!has_functiondisplayname()) { - clear_FunctionDisplayNameOrRef(); - set_has_functiondisplayname(); - FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; - } - return FunctionDisplayNameOrRef_.functiondisplayname_; -} -inline ::std::string* StackFrame_Data::release_functiondisplayname() { - if (has_functiondisplayname()) { - clear_has_FunctionDisplayNameOrRef(); - ::std::string* temp = FunctionDisplayNameOrRef_.functiondisplayname_; - FunctionDisplayNameOrRef_.functiondisplayname_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void StackFrame_Data::set_allocated_functiondisplayname(::std::string* functiondisplayname) { - clear_FunctionDisplayNameOrRef(); - if (functiondisplayname) { - set_has_functiondisplayname(); - FunctionDisplayNameOrRef_.functiondisplayname_ = functiondisplayname; - } -} - -// optional uint64 functionDisplayNameRef = 8; -inline bool StackFrame_Data::has_functiondisplaynameref() const { - return FunctionDisplayNameOrRef_case() == kFunctionDisplayNameRef; -} -inline void StackFrame_Data::set_has_functiondisplaynameref() { - _oneof_case_[1] = kFunctionDisplayNameRef; -} -inline void StackFrame_Data::clear_functiondisplaynameref() { - if (has_functiondisplaynameref()) { - FunctionDisplayNameOrRef_.functiondisplaynameref_ = GOOGLE_ULONGLONG(0); - clear_has_FunctionDisplayNameOrRef(); - } -} -inline ::google::protobuf::uint64 StackFrame_Data::functiondisplaynameref() const { - if (has_functiondisplaynameref()) { - return FunctionDisplayNameOrRef_.functiondisplaynameref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void StackFrame_Data::set_functiondisplaynameref(::google::protobuf::uint64 value) { - if (!has_functiondisplaynameref()) { - clear_FunctionDisplayNameOrRef(); - set_has_functiondisplaynameref(); - } - FunctionDisplayNameOrRef_.functiondisplaynameref_ = value; -} - -// optional bool isSystem = 9; -inline bool StackFrame_Data::has_issystem() const { - return (_has_bits_[0] & 0x00000100u) != 0; -} -inline void StackFrame_Data::set_has_issystem() { - _has_bits_[0] |= 0x00000100u; -} -inline void StackFrame_Data::clear_has_issystem() { - _has_bits_[0] &= ~0x00000100u; -} -inline void StackFrame_Data::clear_issystem() { - issystem_ = false; - clear_has_issystem(); -} -inline bool StackFrame_Data::issystem() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.isSystem) - return issystem_; -} -inline void StackFrame_Data::set_issystem(bool value) { - set_has_issystem(); - issystem_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSystem) -} - -// optional bool isSelfHosted = 10; -inline bool StackFrame_Data::has_isselfhosted() const { - return (_has_bits_[0] & 0x00000200u) != 0; -} -inline void StackFrame_Data::set_has_isselfhosted() { - _has_bits_[0] |= 0x00000200u; -} -inline void StackFrame_Data::clear_has_isselfhosted() { - _has_bits_[0] &= ~0x00000200u; -} -inline void StackFrame_Data::clear_isselfhosted() { - isselfhosted_ = false; - clear_has_isselfhosted(); -} -inline bool StackFrame_Data::isselfhosted() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.isSelfHosted) - return isselfhosted_; -} -inline void StackFrame_Data::set_isselfhosted(bool value) { - set_has_isselfhosted(); - isselfhosted_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSelfHosted) -} - -inline bool StackFrame_Data::has_SourceOrRef() { - return SourceOrRef_case() != SOURCEORREF_NOT_SET; -} -inline void StackFrame_Data::clear_has_SourceOrRef() { - _oneof_case_[0] = SOURCEORREF_NOT_SET; -} -inline bool StackFrame_Data::has_FunctionDisplayNameOrRef() { - return FunctionDisplayNameOrRef_case() != FUNCTIONDISPLAYNAMEORREF_NOT_SET; -} -inline void StackFrame_Data::clear_has_FunctionDisplayNameOrRef() { - _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET; -} -inline StackFrame_Data::SourceOrRefCase StackFrame_Data::SourceOrRef_case() const { - return StackFrame_Data::SourceOrRefCase(_oneof_case_[0]); -} -inline StackFrame_Data::FunctionDisplayNameOrRefCase StackFrame_Data::FunctionDisplayNameOrRef_case() const { - return StackFrame_Data::FunctionDisplayNameOrRefCase(_oneof_case_[1]); -} -// ------------------------------------------------------------------- - -// StackFrame - -// optional .mozilla.devtools.protobuf.StackFrame.Data data = 1; -inline bool StackFrame::has_data() const { - return StackFrameType_case() == kData; -} -inline void StackFrame::set_has_data() { - _oneof_case_[0] = kData; -} -inline void StackFrame::clear_data() { - if (has_data()) { - delete StackFrameType_.data_; - clear_has_StackFrameType(); - } -} -inline const ::mozilla::devtools::protobuf::StackFrame_Data& StackFrame::data() const { - return has_data() ? *StackFrameType_.data_ - : ::mozilla::devtools::protobuf::StackFrame_Data::default_instance(); -} -inline ::mozilla::devtools::protobuf::StackFrame_Data* StackFrame::mutable_data() { - if (!has_data()) { - clear_StackFrameType(); - set_has_data(); - StackFrameType_.data_ = new ::mozilla::devtools::protobuf::StackFrame_Data; - } - return StackFrameType_.data_; -} -inline ::mozilla::devtools::protobuf::StackFrame_Data* StackFrame::release_data() { - if (has_data()) { - clear_has_StackFrameType(); - ::mozilla::devtools::protobuf::StackFrame_Data* temp = StackFrameType_.data_; - StackFrameType_.data_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void StackFrame::set_allocated_data(::mozilla::devtools::protobuf::StackFrame_Data* data) { - clear_StackFrameType(); - if (data) { - set_has_data(); - StackFrameType_.data_ = data; - } -} - -// optional uint64 ref = 2; -inline bool StackFrame::has_ref() const { - return StackFrameType_case() == kRef; -} -inline void StackFrame::set_has_ref() { - _oneof_case_[0] = kRef; -} -inline void StackFrame::clear_ref() { - if (has_ref()) { - StackFrameType_.ref_ = GOOGLE_ULONGLONG(0); - clear_has_StackFrameType(); - } -} -inline ::google::protobuf::uint64 StackFrame::ref() const { - if (has_ref()) { - return StackFrameType_.ref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void StackFrame::set_ref(::google::protobuf::uint64 value) { - if (!has_ref()) { - clear_StackFrameType(); - set_has_ref(); - } - StackFrameType_.ref_ = value; -} - -inline bool StackFrame::has_StackFrameType() { - return StackFrameType_case() != STACKFRAMETYPE_NOT_SET; -} -inline void StackFrame::clear_has_StackFrameType() { - _oneof_case_[0] = STACKFRAMETYPE_NOT_SET; -} -inline StackFrame::StackFrameTypeCase StackFrame::StackFrameType_case() const { - return StackFrame::StackFrameTypeCase(_oneof_case_[0]); -} -// ------------------------------------------------------------------- - -// Node - -// optional uint64 id = 1; -inline bool Node::has_id() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -inline void Node::set_has_id() { - _has_bits_[0] |= 0x00000001u; -} -inline void Node::clear_has_id() { - _has_bits_[0] &= ~0x00000001u; -} -inline void Node::clear_id() { - id_ = GOOGLE_ULONGLONG(0); - clear_has_id(); -} -inline ::google::protobuf::uint64 Node::id() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.id) - return id_; -} -inline void Node::set_id(::google::protobuf::uint64 value) { - set_has_id(); - id_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.id) -} - -// optional bytes typeName = 2; -inline bool Node::has_typename_() const { - return TypeNameOrRef_case() == kTypeName; -} -inline void Node::set_has_typename_() { - _oneof_case_[0] = kTypeName; -} -inline void Node::clear_typename_() { - if (has_typename_()) { - delete TypeNameOrRef_.typename__; - clear_has_TypeNameOrRef(); - } -} -inline const ::std::string& Node::typename_() const { - if (has_typename_()) { - return *TypeNameOrRef_.typename__; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void Node::set_typename_(const ::std::string& value) { - if (!has_typename_()) { - clear_TypeNameOrRef(); - set_has_typename_(); - TypeNameOrRef_.typename__ = new ::std::string; - } - TypeNameOrRef_.typename__->assign(value); -} -inline void Node::set_typename_(const char* value) { - if (!has_typename_()) { - clear_TypeNameOrRef(); - set_has_typename_(); - TypeNameOrRef_.typename__ = new ::std::string; - } - TypeNameOrRef_.typename__->assign(value); -} -inline void Node::set_typename_(const void* value, size_t size) { - if (!has_typename_()) { - clear_TypeNameOrRef(); - set_has_typename_(); - TypeNameOrRef_.typename__ = new ::std::string; - } - TypeNameOrRef_.typename__->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* Node::mutable_typename_() { - if (!has_typename_()) { - clear_TypeNameOrRef(); - set_has_typename_(); - TypeNameOrRef_.typename__ = new ::std::string; - } - return TypeNameOrRef_.typename__; -} -inline ::std::string* Node::release_typename_() { - if (has_typename_()) { - clear_has_TypeNameOrRef(); - ::std::string* temp = TypeNameOrRef_.typename__; - TypeNameOrRef_.typename__ = NULL; - return temp; - } else { - return NULL; - } -} -inline void Node::set_allocated_typename_(::std::string* typename_) { - clear_TypeNameOrRef(); - if (typename_) { - set_has_typename_(); - TypeNameOrRef_.typename__ = typename_; - } -} - -// optional uint64 typeNameRef = 3; -inline bool Node::has_typenameref() const { - return TypeNameOrRef_case() == kTypeNameRef; -} -inline void Node::set_has_typenameref() { - _oneof_case_[0] = kTypeNameRef; -} -inline void Node::clear_typenameref() { - if (has_typenameref()) { - TypeNameOrRef_.typenameref_ = GOOGLE_ULONGLONG(0); - clear_has_TypeNameOrRef(); - } -} -inline ::google::protobuf::uint64 Node::typenameref() const { - if (has_typenameref()) { - return TypeNameOrRef_.typenameref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void Node::set_typenameref(::google::protobuf::uint64 value) { - if (!has_typenameref()) { - clear_TypeNameOrRef(); - set_has_typenameref(); - } - TypeNameOrRef_.typenameref_ = value; -} - -// optional uint64 size = 4; -inline bool Node::has_size() const { - return (_has_bits_[0] & 0x00000008u) != 0; -} -inline void Node::set_has_size() { - _has_bits_[0] |= 0x00000008u; -} -inline void Node::clear_has_size() { - _has_bits_[0] &= ~0x00000008u; -} -inline void Node::clear_size() { - size_ = GOOGLE_ULONGLONG(0); - clear_has_size(); -} -inline ::google::protobuf::uint64 Node::size() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.size) - return size_; -} -inline void Node::set_size(::google::protobuf::uint64 value) { - set_has_size(); - size_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.size) -} - -// repeated .mozilla.devtools.protobuf.Edge edges = 5; -inline int Node::edges_size() const { - return edges_.size(); -} -inline void Node::clear_edges() { - edges_.Clear(); -} -inline const ::mozilla::devtools::protobuf::Edge& Node::edges(int index) const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.edges) - return edges_.Get(index); -} -inline ::mozilla::devtools::protobuf::Edge* Node::mutable_edges(int index) { - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.edges) - return edges_.Mutable(index); -} -inline ::mozilla::devtools::protobuf::Edge* Node::add_edges() { - // @@protoc_insertion_point(field_add:mozilla.devtools.protobuf.Node.edges) - return edges_.Add(); -} -inline const ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >& -Node::edges() const { - // @@protoc_insertion_point(field_list:mozilla.devtools.protobuf.Node.edges) - return edges_; -} -inline ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >* -Node::mutable_edges() { - // @@protoc_insertion_point(field_mutable_list:mozilla.devtools.protobuf.Node.edges) - return &edges_; -} - -// optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; -inline bool Node::has_allocationstack() const { - return (_has_bits_[0] & 0x00000020u) != 0; -} -inline void Node::set_has_allocationstack() { - _has_bits_[0] |= 0x00000020u; -} -inline void Node::clear_has_allocationstack() { - _has_bits_[0] &= ~0x00000020u; -} -inline void Node::clear_allocationstack() { - if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear(); - clear_has_allocationstack(); -} -inline const ::mozilla::devtools::protobuf::StackFrame& Node::allocationstack() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.allocationStack) - return allocationstack_ != NULL ? *allocationstack_ : *default_instance_->allocationstack_; -} -inline ::mozilla::devtools::protobuf::StackFrame* Node::mutable_allocationstack() { - set_has_allocationstack(); - if (allocationstack_ == NULL) allocationstack_ = new ::mozilla::devtools::protobuf::StackFrame; - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.allocationStack) - return allocationstack_; -} -inline ::mozilla::devtools::protobuf::StackFrame* Node::release_allocationstack() { - clear_has_allocationstack(); - ::mozilla::devtools::protobuf::StackFrame* temp = allocationstack_; - allocationstack_ = NULL; - return temp; -} -inline void Node::set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack) { - delete allocationstack_; - allocationstack_ = allocationstack; - if (allocationstack) { - set_has_allocationstack(); - } else { - clear_has_allocationstack(); - } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.allocationStack) -} - -// optional bytes jsObjectClassName = 7; -inline bool Node::has_jsobjectclassname() const { - return JSObjectClassNameOrRef_case() == kJsObjectClassName; -} -inline void Node::set_has_jsobjectclassname() { - _oneof_case_[1] = kJsObjectClassName; -} -inline void Node::clear_jsobjectclassname() { - if (has_jsobjectclassname()) { - delete JSObjectClassNameOrRef_.jsobjectclassname_; - clear_has_JSObjectClassNameOrRef(); - } -} -inline const ::std::string& Node::jsobjectclassname() const { - if (has_jsobjectclassname()) { - return *JSObjectClassNameOrRef_.jsobjectclassname_; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void Node::set_jsobjectclassname(const ::std::string& value) { - if (!has_jsobjectclassname()) { - clear_JSObjectClassNameOrRef(); - set_has_jsobjectclassname(); - JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; - } - JSObjectClassNameOrRef_.jsobjectclassname_->assign(value); -} -inline void Node::set_jsobjectclassname(const char* value) { - if (!has_jsobjectclassname()) { - clear_JSObjectClassNameOrRef(); - set_has_jsobjectclassname(); - JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; - } - JSObjectClassNameOrRef_.jsobjectclassname_->assign(value); -} -inline void Node::set_jsobjectclassname(const void* value, size_t size) { - if (!has_jsobjectclassname()) { - clear_JSObjectClassNameOrRef(); - set_has_jsobjectclassname(); - JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; - } - JSObjectClassNameOrRef_.jsobjectclassname_->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* Node::mutable_jsobjectclassname() { - if (!has_jsobjectclassname()) { - clear_JSObjectClassNameOrRef(); - set_has_jsobjectclassname(); - JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; - } - return JSObjectClassNameOrRef_.jsobjectclassname_; -} -inline ::std::string* Node::release_jsobjectclassname() { - if (has_jsobjectclassname()) { - clear_has_JSObjectClassNameOrRef(); - ::std::string* temp = JSObjectClassNameOrRef_.jsobjectclassname_; - JSObjectClassNameOrRef_.jsobjectclassname_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void Node::set_allocated_jsobjectclassname(::std::string* jsobjectclassname) { - clear_JSObjectClassNameOrRef(); - if (jsobjectclassname) { - set_has_jsobjectclassname(); - JSObjectClassNameOrRef_.jsobjectclassname_ = jsobjectclassname; - } -} - -// optional uint64 jsObjectClassNameRef = 8; -inline bool Node::has_jsobjectclassnameref() const { - return JSObjectClassNameOrRef_case() == kJsObjectClassNameRef; -} -inline void Node::set_has_jsobjectclassnameref() { - _oneof_case_[1] = kJsObjectClassNameRef; -} -inline void Node::clear_jsobjectclassnameref() { - if (has_jsobjectclassnameref()) { - JSObjectClassNameOrRef_.jsobjectclassnameref_ = GOOGLE_ULONGLONG(0); - clear_has_JSObjectClassNameOrRef(); - } -} -inline ::google::protobuf::uint64 Node::jsobjectclassnameref() const { - if (has_jsobjectclassnameref()) { - return JSObjectClassNameOrRef_.jsobjectclassnameref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void Node::set_jsobjectclassnameref(::google::protobuf::uint64 value) { - if (!has_jsobjectclassnameref()) { - clear_JSObjectClassNameOrRef(); - set_has_jsobjectclassnameref(); - } - JSObjectClassNameOrRef_.jsobjectclassnameref_ = value; -} - -// optional uint32 coarseType = 9 [default = 0]; -inline bool Node::has_coarsetype() const { - return (_has_bits_[0] & 0x00000100u) != 0; -} -inline void Node::set_has_coarsetype() { - _has_bits_[0] |= 0x00000100u; -} -inline void Node::clear_has_coarsetype() { - _has_bits_[0] &= ~0x00000100u; -} -inline void Node::clear_coarsetype() { - coarsetype_ = 0u; - clear_has_coarsetype(); -} -inline ::google::protobuf::uint32 Node::coarsetype() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.coarseType) - return coarsetype_; -} -inline void Node::set_coarsetype(::google::protobuf::uint32 value) { - set_has_coarsetype(); - coarsetype_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.coarseType) -} - -// optional bytes scriptFilename = 10; -inline bool Node::has_scriptfilename() const { - return ScriptFilenameOrRef_case() == kScriptFilename; -} -inline void Node::set_has_scriptfilename() { - _oneof_case_[2] = kScriptFilename; -} -inline void Node::clear_scriptfilename() { - if (has_scriptfilename()) { - delete ScriptFilenameOrRef_.scriptfilename_; - clear_has_ScriptFilenameOrRef(); - } -} -inline const ::std::string& Node::scriptfilename() const { - if (has_scriptfilename()) { - return *ScriptFilenameOrRef_.scriptfilename_; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void Node::set_scriptfilename(const ::std::string& value) { - if (!has_scriptfilename()) { - clear_ScriptFilenameOrRef(); - set_has_scriptfilename(); - ScriptFilenameOrRef_.scriptfilename_ = new ::std::string; - } - ScriptFilenameOrRef_.scriptfilename_->assign(value); -} -inline void Node::set_scriptfilename(const char* value) { - if (!has_scriptfilename()) { - clear_ScriptFilenameOrRef(); - set_has_scriptfilename(); - ScriptFilenameOrRef_.scriptfilename_ = new ::std::string; - } - ScriptFilenameOrRef_.scriptfilename_->assign(value); -} -inline void Node::set_scriptfilename(const void* value, size_t size) { - if (!has_scriptfilename()) { - clear_ScriptFilenameOrRef(); - set_has_scriptfilename(); - ScriptFilenameOrRef_.scriptfilename_ = new ::std::string; - } - ScriptFilenameOrRef_.scriptfilename_->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* Node::mutable_scriptfilename() { - if (!has_scriptfilename()) { - clear_ScriptFilenameOrRef(); - set_has_scriptfilename(); - ScriptFilenameOrRef_.scriptfilename_ = new ::std::string; - } - return ScriptFilenameOrRef_.scriptfilename_; -} -inline ::std::string* Node::release_scriptfilename() { - if (has_scriptfilename()) { - clear_has_ScriptFilenameOrRef(); - ::std::string* temp = ScriptFilenameOrRef_.scriptfilename_; - ScriptFilenameOrRef_.scriptfilename_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void Node::set_allocated_scriptfilename(::std::string* scriptfilename) { - clear_ScriptFilenameOrRef(); - if (scriptfilename) { - set_has_scriptfilename(); - ScriptFilenameOrRef_.scriptfilename_ = scriptfilename; - } -} - -// optional uint64 scriptFilenameRef = 11; -inline bool Node::has_scriptfilenameref() const { - return ScriptFilenameOrRef_case() == kScriptFilenameRef; -} -inline void Node::set_has_scriptfilenameref() { - _oneof_case_[2] = kScriptFilenameRef; -} -inline void Node::clear_scriptfilenameref() { - if (has_scriptfilenameref()) { - ScriptFilenameOrRef_.scriptfilenameref_ = GOOGLE_ULONGLONG(0); - clear_has_ScriptFilenameOrRef(); - } -} -inline ::google::protobuf::uint64 Node::scriptfilenameref() const { - if (has_scriptfilenameref()) { - return ScriptFilenameOrRef_.scriptfilenameref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void Node::set_scriptfilenameref(::google::protobuf::uint64 value) { - if (!has_scriptfilenameref()) { - clear_ScriptFilenameOrRef(); - set_has_scriptfilenameref(); - } - ScriptFilenameOrRef_.scriptfilenameref_ = value; -} - -inline bool Node::has_TypeNameOrRef() { - return TypeNameOrRef_case() != TYPENAMEORREF_NOT_SET; -} -inline void Node::clear_has_TypeNameOrRef() { - _oneof_case_[0] = TYPENAMEORREF_NOT_SET; -} -inline bool Node::has_JSObjectClassNameOrRef() { - return JSObjectClassNameOrRef_case() != JSOBJECTCLASSNAMEORREF_NOT_SET; -} -inline void Node::clear_has_JSObjectClassNameOrRef() { - _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET; -} -inline bool Node::has_ScriptFilenameOrRef() { - return ScriptFilenameOrRef_case() != SCRIPTFILENAMEORREF_NOT_SET; -} -inline void Node::clear_has_ScriptFilenameOrRef() { - _oneof_case_[2] = SCRIPTFILENAMEORREF_NOT_SET; -} -inline Node::TypeNameOrRefCase Node::TypeNameOrRef_case() const { - return Node::TypeNameOrRefCase(_oneof_case_[0]); -} -inline Node::JSObjectClassNameOrRefCase Node::JSObjectClassNameOrRef_case() const { - return Node::JSObjectClassNameOrRefCase(_oneof_case_[1]); -} -inline Node::ScriptFilenameOrRefCase Node::ScriptFilenameOrRef_case() const { - return Node::ScriptFilenameOrRefCase(_oneof_case_[2]); -} -// ------------------------------------------------------------------- - -// Edge - -// optional uint64 referent = 1; -inline bool Edge::has_referent() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -inline void Edge::set_has_referent() { - _has_bits_[0] |= 0x00000001u; -} -inline void Edge::clear_has_referent() { - _has_bits_[0] &= ~0x00000001u; -} -inline void Edge::clear_referent() { - referent_ = GOOGLE_ULONGLONG(0); - clear_has_referent(); -} -inline ::google::protobuf::uint64 Edge::referent() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Edge.referent) - return referent_; -} -inline void Edge::set_referent(::google::protobuf::uint64 value) { - set_has_referent(); - referent_ = value; - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Edge.referent) -} - -// optional bytes name = 2; -inline bool Edge::has_name() const { - return EdgeNameOrRef_case() == kName; -} -inline void Edge::set_has_name() { - _oneof_case_[0] = kName; -} -inline void Edge::clear_name() { - if (has_name()) { - delete EdgeNameOrRef_.name_; - clear_has_EdgeNameOrRef(); - } -} -inline const ::std::string& Edge::name() const { - if (has_name()) { - return *EdgeNameOrRef_.name_; - } - return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); -} -inline void Edge::set_name(const ::std::string& value) { - if (!has_name()) { - clear_EdgeNameOrRef(); - set_has_name(); - EdgeNameOrRef_.name_ = new ::std::string; - } - EdgeNameOrRef_.name_->assign(value); -} -inline void Edge::set_name(const char* value) { - if (!has_name()) { - clear_EdgeNameOrRef(); - set_has_name(); - EdgeNameOrRef_.name_ = new ::std::string; - } - EdgeNameOrRef_.name_->assign(value); -} -inline void Edge::set_name(const void* value, size_t size) { - if (!has_name()) { - clear_EdgeNameOrRef(); - set_has_name(); - EdgeNameOrRef_.name_ = new ::std::string; - } - EdgeNameOrRef_.name_->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* Edge::mutable_name() { - if (!has_name()) { - clear_EdgeNameOrRef(); - set_has_name(); - EdgeNameOrRef_.name_ = new ::std::string; - } - return EdgeNameOrRef_.name_; -} -inline ::std::string* Edge::release_name() { - if (has_name()) { - clear_has_EdgeNameOrRef(); - ::std::string* temp = EdgeNameOrRef_.name_; - EdgeNameOrRef_.name_ = NULL; - return temp; - } else { - return NULL; - } -} -inline void Edge::set_allocated_name(::std::string* name) { - clear_EdgeNameOrRef(); - if (name) { - set_has_name(); - EdgeNameOrRef_.name_ = name; - } -} - -// optional uint64 nameRef = 3; -inline bool Edge::has_nameref() const { - return EdgeNameOrRef_case() == kNameRef; -} -inline void Edge::set_has_nameref() { - _oneof_case_[0] = kNameRef; -} -inline void Edge::clear_nameref() { - if (has_nameref()) { - EdgeNameOrRef_.nameref_ = GOOGLE_ULONGLONG(0); - clear_has_EdgeNameOrRef(); - } -} -inline ::google::protobuf::uint64 Edge::nameref() const { - if (has_nameref()) { - return EdgeNameOrRef_.nameref_; - } - return GOOGLE_ULONGLONG(0); -} -inline void Edge::set_nameref(::google::protobuf::uint64 value) { - if (!has_nameref()) { - clear_EdgeNameOrRef(); - set_has_nameref(); - } - EdgeNameOrRef_.nameref_ = value; -} - -inline bool Edge::has_EdgeNameOrRef() { - return EdgeNameOrRef_case() != EDGENAMEORREF_NOT_SET; -} -inline void Edge::clear_has_EdgeNameOrRef() { - _oneof_case_[0] = EDGENAMEORREF_NOT_SET; -} -inline Edge::EdgeNameOrRefCase Edge::EdgeNameOrRef_case() const { - return Edge::EdgeNameOrRefCase(_oneof_case_[0]); -} - -// @@protoc_insertion_point(namespace_scope) - -} // namespace protobuf -} // namespace devtools -} // namespace mozilla - -#ifndef SWIG -namespace google { -namespace protobuf { - - -} // namespace google -} // namespace protobuf -#endif // SWIG - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_CoreDump_2eproto__INCLUDED diff --git a/devtools/shared/heapsnapshot/CoreDump.proto b/devtools/shared/heapsnapshot/CoreDump.proto deleted file mode 100644 index 24a223e11..000000000 --- a/devtools/shared/heapsnapshot/CoreDump.proto +++ /dev/null @@ -1,143 +0,0 @@ -/* -*- Mode: protobuf; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// # Core Dumps -// -// A core dump is a serialized snapshot of the heap graph. We serialize the heap -// as a series of protobuf messages with each message prefixed by its Varint32 -// byte size so we can delimit individual protobuf messages (protobuf parsers -// cannot determine where a message ends on their own). -// -// The first protobuf message is an instance of the `Metadata` message. All -// subsequent messages will be instances of the `Node` message. The first of -// these `Node` messages is the root node of the serialized heap graph. Here is -// a diagram of our core dump format: -// -// +-----------------------------------------------------------------------+ -// | Varint32: The size of following `Metadata` message. | -// +-----------------------------------------------------------------------+ -// | message: The core dump `Metadata` message. | -// +-----------------------------------------------------------------------+ -// | Varint32: The size of the following `Node` message. | -// +-----------------------------------------------------------------------+ -// | message: The first `Node` message. This is the root node. | -// +-----------------------------------------------------------------------+ -// | Varint32: The size of the following `Node` message. | -// +-----------------------------------------------------------------------+ -// | message: A `Node` message. | -// +-----------------------------------------------------------------------+ -// | Varint32: The size of the following `Node` message. | -// +-----------------------------------------------------------------------+ -// | message: A `Node` message. | -// +-----------------------------------------------------------------------+ -// | . | -// | . | -// | . | -// +-----------------------------------------------------------------------+ -// -// Core dumps should always be written with a -// `google::protobuf::io::GzipOutputStream` and read from a -// `google::protobuf::io::GzipInputStream`. -// -// Note that all strings are de-duplicated. The first time the N^th unique -// string is encountered, the full string is serialized. Subsequent times that -// same string is encountered, it is referenced by N. This de-duplication -// happens across string properties, not on a per-property basis. For example, -// if the same K^th unique string is first used as an Edge::EdgeNameOrRef and -// then as a StackFrame::Data::FunctionDisplayNameOrRef, the first will be the -// actual string as the functionDisplayName oneof property, and the second will -// be a reference to the first as the edgeNameRef oneof property whose value is -// K. -// -// We would ordinarily abstract these de-duplicated strings with messages of -// their own, but unfortunately, the protobuf compiler does not have a way to -// inline a messsage within another message and the child message must be -// referenced by pointer. This leads to extra mallocs that we wish to avoid. - - -package mozilla.devtools.protobuf; - -// A collection of metadata about this core dump. -message Metadata { - // Number of microseconds since midnight (00:00:00) 1 January 1970 UTC. - optional uint64 timeStamp = 1; -} - -// A serialized version of `JS::ubi::StackFrame`. Older parent frame tails are -// de-duplicated to cut down on [de]serialization and size costs. -message StackFrame { - oneof StackFrameType { - // This is the first time this stack frame has been serialized, and so - // here is all of its data. - Data data = 1; - // A reference to a stack frame that has already been serialized and has - // the given number as its id. - uint64 ref = 2; - } - - message Data { - optional uint64 id = 1; - optional StackFrame parent = 2; - optional uint32 line = 3; - optional uint32 column = 4; - - // De-duplicated two-byte string. - oneof SourceOrRef { - bytes source = 5; - uint64 sourceRef = 6; - } - - // De-duplicated two-byte string. - oneof FunctionDisplayNameOrRef { - bytes functionDisplayName = 7; - uint64 functionDisplayNameRef = 8; - } - - optional bool isSystem = 9; - optional bool isSelfHosted = 10; - } -} - -// A serialized version of `JS::ubi::Node` and its outgoing edges. -message Node { - optional uint64 id = 1; - - // De-duplicated two-byte string. - oneof TypeNameOrRef { - bytes typeName = 2; - uint64 typeNameRef = 3; - } - - optional uint64 size = 4; - repeated Edge edges = 5; - optional StackFrame allocationStack = 6; - - // De-duplicated one-byte string. - oneof JSObjectClassNameOrRef { - bytes jsObjectClassName = 7; - uint64 jsObjectClassNameRef = 8; - } - - // JS::ubi::CoarseType. Defaults to Other. - optional uint32 coarseType = 9 [default = 0]; - - // De-duplicated one-byte string. - oneof ScriptFilenameOrRef { - bytes scriptFilename = 10; - uint64 scriptFilenameRef = 11; - } -} - -// A serialized edge from the heap graph. -message Edge { - optional uint64 referent = 1; - - // De-duplicated two-byte string. - oneof EdgeNameOrRef { - bytes name = 2; - uint64 nameRef = 3; - } -} diff --git a/devtools/shared/heapsnapshot/DeserializedNode.cpp b/devtools/shared/heapsnapshot/DeserializedNode.cpp deleted file mode 100644 index fac4cccb9..000000000 --- a/devtools/shared/heapsnapshot/DeserializedNode.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/DeserializedNode.h" -#include "mozilla/devtools/HeapSnapshot.h" -#include "nsCRTGlue.h" - -namespace mozilla { -namespace devtools { - -DeserializedEdge::DeserializedEdge(DeserializedEdge&& rhs) -{ - referent = rhs.referent; - name = rhs.name; -} - -DeserializedEdge& DeserializedEdge::operator=(DeserializedEdge&& rhs) -{ - MOZ_ASSERT(&rhs != this); - this->~DeserializedEdge(); - new(this) DeserializedEdge(Move(rhs)); - return *this; -} - -JS::ubi::Node -DeserializedNode::getEdgeReferent(const DeserializedEdge& edge) -{ - auto ptr = owner->nodes.lookup(edge.referent); - MOZ_ASSERT(ptr); - - // `HashSets` only provide const access to their values, because mutating a - // value might change its hash, rendering it unfindable in the set. - // Unfortunately, the `ubi::Node` constructor requires a non-const pointer to - // its referent. However, the only aspect of a `DeserializedNode` we hash on - // is its id, which can't be changed via `ubi::Node`, so this cast can't cause - // the trouble `HashSet` is concerned a non-const reference would cause. - return JS::ubi::Node(const_cast<DeserializedNode*>(&*ptr)); -} - -JS::ubi::StackFrame -DeserializedStackFrame::getParentStackFrame() const -{ - MOZ_ASSERT(parent.isSome()); - auto ptr = owner->frames.lookup(parent.ref()); - MOZ_ASSERT(ptr); - // See above comment in DeserializedNode::getEdgeReferent about why this - // const_cast is needed and safe. - return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); -} - -} // namespace devtools -} // namespace mozilla - -namespace JS { -namespace ubi { - -using mozilla::devtools::DeserializedEdge; - -const char16_t Concrete<DeserializedNode>::concreteTypeName[] = - u"mozilla::devtools::DeserializedNode"; - -const char16_t* -Concrete<DeserializedNode>::typeName() const -{ - return get().typeName; -} - -Node::Size -Concrete<DeserializedNode>::size(mozilla::MallocSizeOf mallocSizeof) const -{ - return get().size; -} - -class DeserializedEdgeRange : public EdgeRange -{ - DeserializedNode* node; - Edge currentEdge; - size_t i; - - void settle() { - if (i >= node->edges.length()) { - front_ = nullptr; - return; - } - - auto& edge = node->edges[i]; - auto referent = node->getEdgeReferent(edge); - currentEdge = mozilla::Move(Edge(edge.name ? NS_strdup(edge.name) : nullptr, - referent)); - front_ = ¤tEdge; - } - -public: - explicit DeserializedEdgeRange(DeserializedNode& node) - : node(&node) - , i(0) - { - settle(); - } - - void popFront() override - { - i++; - settle(); - } -}; - -StackFrame -Concrete<DeserializedNode>::allocationStack() const -{ - MOZ_ASSERT(hasAllocationStack()); - auto id = get().allocationStack.ref(); - auto ptr = get().owner->frames.lookup(id); - MOZ_ASSERT(ptr); - // See above comment in DeserializedNode::getEdgeReferent about why this - // const_cast is needed and safe. - return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); -} - - -js::UniquePtr<EdgeRange> -Concrete<DeserializedNode>::edges(JSContext* cx, bool) const -{ - js::UniquePtr<DeserializedEdgeRange> range(js_new<DeserializedEdgeRange>(get())); - - if (!range) - return nullptr; - - return js::UniquePtr<EdgeRange>(range.release()); -} - -StackFrame -ConcreteStackFrame<DeserializedStackFrame>::parent() const -{ - return get().parent.isNothing() ? StackFrame() : get().getParentStackFrame(); -} - -bool -ConcreteStackFrame<DeserializedStackFrame>::constructSavedFrameStack( - JSContext* cx, - MutableHandleObject outSavedFrameStack) const -{ - StackFrame f(&get()); - return ConstructSavedFrameStackSlow(cx, f, outSavedFrameStack); -} - -} // namespace ubi -} // namespace JS diff --git a/devtools/shared/heapsnapshot/DeserializedNode.h b/devtools/shared/heapsnapshot/DeserializedNode.h deleted file mode 100644 index 60d1fb408..000000000 --- a/devtools/shared/heapsnapshot/DeserializedNode.h +++ /dev/null @@ -1,317 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_DeserializedNode__ -#define mozilla_devtools_DeserializedNode__ - -#include "js/UbiNode.h" -#include "js/UniquePtr.h" -#include "mozilla/devtools/CoreDump.pb.h" -#include "mozilla/Maybe.h" -#include "mozilla/Move.h" -#include "mozilla/Vector.h" - -// `Deserialized{Node,Edge}` translate protobuf messages from our core dump -// format into structures we can rely upon for implementing `JS::ubi::Node` -// specializations on top of. All of the properties of the protobuf messages are -// optional for future compatibility, and this is the layer where we validate -// that the properties that do actually exist in any given message fulfill our -// semantic requirements. -// -// Both `DeserializedNode` and `DeserializedEdge` are always owned by a -// `HeapSnapshot` instance, and their lifetimes must not extend after that of -// their owning `HeapSnapshot`. - -namespace mozilla { -namespace devtools { - -class HeapSnapshot; - -using NodeId = uint64_t; -using StackFrameId = uint64_t; - -// A `DeserializedEdge` represents an edge in the heap graph pointing to the -// node with id equal to `DeserializedEdge::referent` that we deserialized from -// a core dump. -struct DeserializedEdge { - NodeId referent; - // A borrowed reference to a string owned by this node's owning HeapSnapshot. - const char16_t* name; - - explicit DeserializedEdge(NodeId referent, const char16_t* edgeName = nullptr) - : referent(referent) - , name(edgeName) - { } - DeserializedEdge(DeserializedEdge&& rhs); - DeserializedEdge& operator=(DeserializedEdge&& rhs); - -private: - DeserializedEdge(const DeserializedEdge&) = delete; - DeserializedEdge& operator=(const DeserializedEdge&) = delete; -}; - -// A `DeserializedNode` is a node in the heap graph that we deserialized from a -// core dump. -struct DeserializedNode { - using EdgeVector = Vector<DeserializedEdge>; - using UniqueStringPtr = UniquePtr<char16_t[]>; - - NodeId id; - JS::ubi::CoarseType coarseType; - // A borrowed reference to a string owned by this node's owning HeapSnapshot. - const char16_t* typeName; - uint64_t size; - EdgeVector edges; - Maybe<StackFrameId> allocationStack; - // A borrowed reference to a string owned by this node's owning HeapSnapshot. - const char* jsObjectClassName; - // A borrowed reference to a string owned by this node's owning HeapSnapshot. - const char* scriptFilename; - // A weak pointer to this node's owning `HeapSnapshot`. Safe without - // AddRef'ing because this node's lifetime is equal to that of its owner. - HeapSnapshot* owner; - - DeserializedNode(NodeId id, - JS::ubi::CoarseType coarseType, - const char16_t* typeName, - uint64_t size, - EdgeVector&& edges, - Maybe<StackFrameId> allocationStack, - const char* className, - const char* filename, - HeapSnapshot& owner) - : id(id) - , coarseType(coarseType) - , typeName(typeName) - , size(size) - , edges(Move(edges)) - , allocationStack(allocationStack) - , jsObjectClassName(className) - , scriptFilename(filename) - , owner(&owner) - { } - virtual ~DeserializedNode() { } - - DeserializedNode(DeserializedNode&& rhs) - : id(rhs.id) - , coarseType(rhs.coarseType) - , typeName(rhs.typeName) - , size(rhs.size) - , edges(Move(rhs.edges)) - , allocationStack(rhs.allocationStack) - , jsObjectClassName(rhs.jsObjectClassName) - , scriptFilename(rhs.scriptFilename) - , owner(rhs.owner) - { } - - DeserializedNode& operator=(DeserializedNode&& rhs) - { - MOZ_ASSERT(&rhs != this); - this->~DeserializedNode(); - new(this) DeserializedNode(Move(rhs)); - return *this; - } - - // Get a borrowed reference to the given edge's referent. This method is - // virtual to provide a hook for gmock and gtest. - virtual JS::ubi::Node getEdgeReferent(const DeserializedEdge& edge); - - struct HashPolicy; - -protected: - // This is only for use with `MockDeserializedNode` in testing. - DeserializedNode(NodeId id, const char16_t* typeName, uint64_t size) - : id(id) - , coarseType(JS::ubi::CoarseType::Other) - , typeName(typeName) - , size(size) - , edges() - , allocationStack(Nothing()) - , jsObjectClassName(nullptr) - , scriptFilename(nullptr) - , owner(nullptr) - { } - -private: - DeserializedNode(const DeserializedNode&) = delete; - DeserializedNode& operator=(const DeserializedNode&) = delete; -}; - -static inline js::HashNumber -hashIdDerivedFromPtr(uint64_t id) -{ - // NodeIds and StackFrameIds are always 64 bits, but they are derived from - // the original referents' addresses, which could have been either 32 or 64 - // bits long. As such, NodeId and StackFrameId have little entropy in their - // bottom three bits, and may or may not have entropy in their upper 32 - // bits. This hash should manage both cases well. - id >>= 3; - return js::HashNumber((id >> 32) ^ id); -} - -struct DeserializedNode::HashPolicy -{ - using Lookup = NodeId; - - static js::HashNumber hash(const Lookup& lookup) { - return hashIdDerivedFromPtr(lookup); - } - - static bool match(const DeserializedNode& existing, const Lookup& lookup) { - return existing.id == lookup; - } -}; - -// A `DeserializedStackFrame` is a stack frame referred to by a thing in the -// heap graph that we deserialized from a core dump. -struct DeserializedStackFrame { - StackFrameId id; - Maybe<StackFrameId> parent; - uint32_t line; - uint32_t column; - // Borrowed references to strings owned by this DeserializedStackFrame's - // owning HeapSnapshot. - const char16_t* source; - const char16_t* functionDisplayName; - bool isSystem; - bool isSelfHosted; - // A weak pointer to this frame's owning `HeapSnapshot`. Safe without - // AddRef'ing because this frame's lifetime is equal to that of its owner. - HeapSnapshot* owner; - - explicit DeserializedStackFrame(StackFrameId id, - const Maybe<StackFrameId>& parent, - uint32_t line, - uint32_t column, - const char16_t* source, - const char16_t* functionDisplayName, - bool isSystem, - bool isSelfHosted, - HeapSnapshot& owner) - : id(id) - , parent(parent) - , line(line) - , column(column) - , source(source) - , functionDisplayName(functionDisplayName) - , isSystem(isSystem) - , isSelfHosted(isSelfHosted) - , owner(&owner) - { - MOZ_ASSERT(source); - } - - JS::ubi::StackFrame getParentStackFrame() const; - - struct HashPolicy; - -protected: - // This is exposed only for MockDeserializedStackFrame in the gtests. - explicit DeserializedStackFrame() - : id(0) - , parent(Nothing()) - , line(0) - , column(0) - , source(nullptr) - , functionDisplayName(nullptr) - , isSystem(false) - , isSelfHosted(false) - , owner(nullptr) - { }; -}; - -struct DeserializedStackFrame::HashPolicy { - using Lookup = StackFrameId; - - static js::HashNumber hash(const Lookup& lookup) { - return hashIdDerivedFromPtr(lookup); - } - - static bool match(const DeserializedStackFrame& existing, const Lookup& lookup) { - return existing.id == lookup; - } -}; - -} // namespace devtools -} // namespace mozilla - -namespace JS { -namespace ubi { - -using mozilla::devtools::DeserializedNode; -using mozilla::devtools::DeserializedStackFrame; - -template<> -class Concrete<DeserializedNode> : public Base -{ -protected: - explicit Concrete(DeserializedNode* ptr) : Base(ptr) { } - DeserializedNode& get() const { - return *static_cast<DeserializedNode*>(ptr); - } - -public: - static void construct(void* storage, DeserializedNode* ptr) { - new (storage) Concrete(ptr); - } - - CoarseType coarseType() const final { return get().coarseType; } - Id identifier() const override { return get().id; } - bool isLive() const override { return false; } - const char16_t* typeName() const override; - Node::Size size(mozilla::MallocSizeOf mallocSizeof) const override; - const char* jsObjectClassName() const override { return get().jsObjectClassName; } - const char* scriptFilename() const final { return get().scriptFilename; } - - bool hasAllocationStack() const override { return get().allocationStack.isSome(); } - StackFrame allocationStack() const override; - - // We ignore the `bool wantNames` parameter because we can't control whether - // the core dump was serialized with edge names or not. - js::UniquePtr<EdgeRange> edges(JSContext* cx, bool) const override; - - static const char16_t concreteTypeName[]; -}; - -template<> -class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame -{ -protected: - explicit ConcreteStackFrame(DeserializedStackFrame* ptr) - : BaseStackFrame(ptr) - { } - - DeserializedStackFrame& get() const { - return *static_cast<DeserializedStackFrame*>(ptr); - } - -public: - static void construct(void* storage, DeserializedStackFrame* ptr) { - new (storage) ConcreteStackFrame(ptr); - } - - uint64_t identifier() const override { return get().id; } - uint32_t line() const override { return get().line; } - uint32_t column() const override { return get().column; } - bool isSystem() const override { return get().isSystem; } - bool isSelfHosted(JSContext* cx) const override { return get().isSelfHosted; } - void trace(JSTracer* trc) override { } - AtomOrTwoByteChars source() const override { - return AtomOrTwoByteChars(get().source); - } - AtomOrTwoByteChars functionDisplayName() const override { - return AtomOrTwoByteChars(get().functionDisplayName); - } - - StackFrame parent() const override; - bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) - const override; -}; - -} // namespace ubi -} // namespace JS - -#endif // mozilla_devtools_DeserializedNode__ diff --git a/devtools/shared/heapsnapshot/DominatorTree.cpp b/devtools/shared/heapsnapshot/DominatorTree.cpp deleted file mode 100644 index e53c196cf..000000000 --- a/devtools/shared/heapsnapshot/DominatorTree.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/DominatorTree.h" -#include "mozilla/dom/DominatorTreeBinding.h" - -namespace mozilla { -namespace devtools { - -dom::Nullable<uint64_t> -DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv) -{ - JS::ubi::Node::Id id(aNodeId); - auto node = mHeapSnapshot->getNodeById(id); - if (node.isNothing()) - return dom::Nullable<uint64_t>(); - - auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); - JS::ubi::Node::Size size = 0; - if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return dom::Nullable<uint64_t>(); - } - - MOZ_ASSERT(size != 0, - "The node should not have been unknown since we got it from the heap snapshot."); - return dom::Nullable<uint64_t>(size); -} - -struct NodeAndRetainedSize -{ - JS::ubi::Node mNode; - JS::ubi::Node::Size mSize; - - NodeAndRetainedSize(const JS::ubi::Node& aNode, JS::ubi::Node::Size aSize) - : mNode(aNode) - , mSize(aSize) - { } - - struct Comparator - { - static bool - Equals(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs) - { - return aLhs.mSize == aRhs.mSize; - } - - static bool - LessThan(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs) - { - // Use > because we want to sort from greatest to least retained size. - return aLhs.mSize > aRhs.mSize; - } - }; -}; - -void -DominatorTree::GetImmediatelyDominated(uint64_t aNodeId, - dom::Nullable<nsTArray<uint64_t>>& aOutResult, - ErrorResult& aRv) -{ - MOZ_ASSERT(aOutResult.IsNull()); - - JS::ubi::Node::Id id(aNodeId); - Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id); - if (node.isNothing()) - return; - - // Get all immediately dominated nodes and their retained sizes. - MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); - Maybe<JS::ubi::DominatorTree::DominatedSetRange> range = mDominatorTree.getDominatedSet(*node); - MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot."); - size_t length = range->length(); - nsTArray<NodeAndRetainedSize> dominatedNodes(length); - for (const JS::ubi::Node& dominatedNode : *range) { - JS::ubi::Node::Size retainedSize = 0; - if (NS_WARN_IF(!mDominatorTree.getRetainedSize(dominatedNode, mallocSizeOf, retainedSize))) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - MOZ_ASSERT(retainedSize != 0, - "retainedSize should not be zero since we know the node is in the dominator tree."); - - dominatedNodes.AppendElement(NodeAndRetainedSize(dominatedNode, retainedSize)); - } - - // Sort them by retained size. - NodeAndRetainedSize::Comparator comparator; - dominatedNodes.Sort(comparator); - - // Fill the result with the nodes' ids. - JS::ubi::Node root = mDominatorTree.root(); - aOutResult.SetValue(nsTArray<uint64_t>(length)); - for (const NodeAndRetainedSize& entry : dominatedNodes) { - // The root dominates itself, but we don't want to expose that to JS. - if (entry.mNode == root) - continue; - - aOutResult.Value().AppendElement(entry.mNode.identifier()); - } -} - -dom::Nullable<uint64_t> -DominatorTree::GetImmediateDominator(uint64_t aNodeId) const -{ - JS::ubi::Node::Id id(aNodeId); - Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id); - if (node.isNothing()) - return dom::Nullable<uint64_t>(); - - JS::ubi::Node dominator = mDominatorTree.getImmediateDominator(*node); - if (!dominator || dominator == *node) - return dom::Nullable<uint64_t>(); - - return dom::Nullable<uint64_t>(dominator.identifier()); -} - - -/*** Cycle Collection Boilerplate *****************************************************************/ - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent, mHeapSnapshot) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(DominatorTree) -NS_IMPL_CYCLE_COLLECTING_RELEASE(DominatorTree) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DominatorTree) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -/* virtual */ JSObject* -DominatorTree::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) -{ - return dom::DominatorTreeBinding::Wrap(aCx, this, aGivenProto); -} - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/DominatorTree.h b/devtools/shared/heapsnapshot/DominatorTree.h deleted file mode 100644 index f785d4916..000000000 --- a/devtools/shared/heapsnapshot/DominatorTree.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_DominatorTree__ -#define mozilla_devtools_DominatorTree__ - -#include "mozilla/devtools/HeapSnapshot.h" -#include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/ErrorResult.h" -#include "mozilla/RefCounted.h" -#include "js/UbiNodeDominatorTree.h" -#include "nsWrapperCache.h" - -namespace mozilla { -namespace devtools { - -class DominatorTree final : public nsISupports - , public nsWrapperCache -{ -protected: - nsCOMPtr<nsISupports> mParent; - - virtual ~DominatorTree() { } - -private: - JS::ubi::DominatorTree mDominatorTree; - RefPtr<HeapSnapshot> mHeapSnapshot; - -public: - explicit DominatorTree(JS::ubi::DominatorTree&& aDominatorTree, HeapSnapshot* aHeapSnapshot, - nsISupports* aParent) - : mParent(aParent) - , mDominatorTree(Move(aDominatorTree)) - , mHeapSnapshot(aHeapSnapshot) - { - MOZ_ASSERT(aParent); - MOZ_ASSERT(aHeapSnapshot); - }; - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS; - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DominatorTree); - - nsISupports* GetParentObject() const { return mParent; } - - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) override; - - // readonly attribute NodeId root - uint64_t Root() const { return mDominatorTree.root().identifier(); } - - // [Throws] NodeSize getRetainedSize(NodeId node) - dom::Nullable<uint64_t> GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv); - - // [Throws] sequence<NodeId>? getImmediatelyDominated(NodeId node); - void GetImmediatelyDominated(uint64_t aNodeId, dom::Nullable<nsTArray<uint64_t>>& aOutDominated, - ErrorResult& aRv); - - // NodeId? getImmediateDominator(NodeId node); - dom::Nullable<uint64_t> GetImmediateDominator(uint64_t aNodeId) const; -}; - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_DominatorTree__ diff --git a/devtools/shared/heapsnapshot/DominatorTreeNode.js b/devtools/shared/heapsnapshot/DominatorTreeNode.js deleted file mode 100644 index 13a847fd0..000000000 --- a/devtools/shared/heapsnapshot/DominatorTreeNode.js +++ /dev/null @@ -1,336 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { immutableUpdate } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js"); -const { Visitor, walk } = require("resource://devtools/shared/heapsnapshot/CensusUtils.js"); -const { deduplicatePaths } = require("resource://devtools/shared/heapsnapshot/shortest-paths"); - -const DEFAULT_MAX_DEPTH = 4; -const DEFAULT_MAX_SIBLINGS = 15; -const DEFAULT_MAX_NUM_PATHS = 5; - -/** - * A single node in a dominator tree. - * - * @param {NodeId} nodeId - * @param {NodeSize} retainedSize - */ -function DominatorTreeNode(nodeId, label, shallowSize, retainedSize) { - // The id of this node. - this.nodeId = nodeId; - - // The label structure generated by describing the given node. - this.label = label; - - // The shallow size of this node. - this.shallowSize = shallowSize; - - // The retained size of this node. - this.retainedSize = retainedSize; - - // The id of this node's parent or undefined if this node is the root. - this.parentId = undefined; - - // An array of immediately dominated child `DominatorTreeNode`s, or undefined. - this.children = undefined; - - // An object of the form returned by `deduplicatePaths`, encoding the set of - // the N shortest retaining paths for this node as a graph. - this.shortestPaths = undefined; - - // True iff the `children` property does not contain every immediately - // dominated node. - // - // * If children is an array and this property is true: the array does not - // contain the complete set of immediately dominated children. - // * If children is an array and this property is false: the array contains - // the complete set of immediately dominated children. - // * If children is undefined and this property is true: there exist - // immediately dominated children for this node, but they have not been - // loaded yet. - // * If children is undefined and this property is false: this node does not - // dominate any others and therefore has no children. - this.moreChildrenAvailable = true; -} - -DominatorTreeNode.prototype = null; - -module.exports = DominatorTreeNode; - -/** - * Add `child` to the `parent`'s set of children. - * - * @param {DominatorTreeNode} parent - * @param {DominatorTreeNode} child - */ -DominatorTreeNode.addChild = function (parent, child) { - if (parent.children === undefined) { - parent.children = []; - } - - parent.children.push(child); - child.parentId = parent.nodeId; -}; - -/** - * A Visitor that is used to generate a label for a node in the heap snapshot - * and get its shallow size as well while we are at it. - */ -function LabelAndShallowSizeVisitor() { - // As we walk the description, we accumulate edges in this array. - this._labelPieces = []; - - // Once we reach the non-zero count leaf node in the description, we move the - // labelPieces here to signify that we no longer need to accumulate edges. - this._label = undefined; - - // Once we reach the non-zero count leaf node in the description, we grab the - // shallow size and place it here. - this._shallowSize = 0; -} - -DominatorTreeNode.LabelAndShallowSizeVisitor = LabelAndShallowSizeVisitor; - -LabelAndShallowSizeVisitor.prototype = Object.create(Visitor); - -/** - * @overrides Visitor.prototype.enter - */ -LabelAndShallowSizeVisitor.prototype.enter = function (breakdown, report, edge) { - if (this._labelPieces && edge) { - this._labelPieces.push(edge); - } -}; - -/** - * @overrides Visitor.prototype.exit - */ -LabelAndShallowSizeVisitor.prototype.exit = function (breakdown, report, edge) { - if (this._labelPieces && edge) { - this._labelPieces.pop(); - } -}; - -/** - * @overrides Visitor.prototype.count - */ -LabelAndShallowSizeVisitor.prototype.count = function (breakdown, report, edge) { - if (report.count === 0) { - return; - } - - this._label = this._labelPieces; - this._labelPieces = undefined; - - this._shallowSize = report.bytes; -}; - -/** - * Get the generated label structure accumulated by this visitor. - * - * @returns {Object} - */ -LabelAndShallowSizeVisitor.prototype.label = function () { - return this._label; -}; - -/** - * Get the shallow size of the node this visitor visited. - * - * @returns {Number} - */ -LabelAndShallowSizeVisitor.prototype.shallowSize = function () { - return this._shallowSize; -}; - -/** - * Generate a label structure for the node with the given id and grab its - * shallow size. - * - * What is a "label" structure? HeapSnapshot.describeNode essentially takes a - * census of a single node rather than the whole heap graph. The resulting - * report has only one count leaf that is non-zero. The label structure is the - * path in this report from the root to the non-zero count leaf. - * - * @param {Number} nodeId - * @param {HeapSnapshot} snapshot - * @param {Object} breakdown - * - * @returns {Object} - * An object with the following properties: - * - {Number} shallowSize - * - {Object} label - */ -DominatorTreeNode.getLabelAndShallowSize = function (nodeId, - snapshot, - breakdown) { - const description = snapshot.describeNode(breakdown, nodeId); - - const visitor = new LabelAndShallowSizeVisitor(); - walk(breakdown, description, visitor); - - return { - label: visitor.label(), - shallowSize: visitor.shallowSize(), - }; -}; - -/** - * Do a partial traversal of the given dominator tree and convert it into a tree - * of `DominatorTreeNode`s. Dominator trees have a node for every node in the - * snapshot's heap graph, so we must not allocate a JS object for every node. It - * would be way too many and the node count is effectively unbounded. - * - * Go no deeper down the tree than `maxDepth` and only consider at most - * `maxSiblings` within any single node's children. - * - * @param {DominatorTree} dominatorTree - * @param {HeapSnapshot} snapshot - * @param {Object} breakdown - * @param {Number} maxDepth - * @param {Number} maxSiblings - * - * @returns {DominatorTreeNode} - */ -DominatorTreeNode.partialTraversal = function (dominatorTree, - snapshot, - breakdown, - maxDepth = DEFAULT_MAX_DEPTH, - maxSiblings = DEFAULT_MAX_SIBLINGS) { - function dfs(nodeId, depth) { - const { label, shallowSize } = - DominatorTreeNode.getLabelAndShallowSize(nodeId, snapshot, breakdown); - const retainedSize = dominatorTree.getRetainedSize(nodeId); - const node = new DominatorTreeNode(nodeId, label, shallowSize, retainedSize); - const childNodeIds = dominatorTree.getImmediatelyDominated(nodeId); - - const newDepth = depth + 1; - if (newDepth < maxDepth) { - const endIdx = Math.min(childNodeIds.length, maxSiblings); - for (let i = 0; i < endIdx; i++) { - DominatorTreeNode.addChild(node, dfs(childNodeIds[i], newDepth)); - } - node.moreChildrenAvailable = endIdx < childNodeIds.length; - } else { - node.moreChildrenAvailable = childNodeIds.length > 0; - } - - return node; - } - - return dfs(dominatorTree.root, 0); -}; - -/** - * Insert more children into the given (partially complete) dominator tree. - * - * The tree is updated in an immutable and persistent manner: a new tree is - * returned, but all unmodified subtrees (which is most) are shared with the - * original tree. Only the modified nodes are re-allocated. - * - * @param {DominatorTreeNode} tree - * @param {Array<NodeId>} path - * @param {Array<DominatorTreeNode>} newChildren - * @param {Boolean} moreChildrenAvailable - * - * @returns {DominatorTreeNode} - */ -DominatorTreeNode.insert = function (tree, path, newChildren, moreChildrenAvailable) { - function insert(tree, i) { - if (tree.nodeId !== path[i]) { - return tree; - } - - if (i == path.length - 1) { - return immutableUpdate(tree, { - children: (tree.children || []).concat(newChildren), - moreChildrenAvailable, - }); - } - - return tree.children - ? immutableUpdate(tree, { - children: tree.children.map(c => insert(c, i + 1)) - }) - : tree; - } - - return insert(tree, 0); -}; - -/** - * Get the new canonical node with the given `id` in `tree` that exists along - * `path`. If there is no such node along `path`, return null. - * - * This is useful if we have a reference to a now-outdated DominatorTreeNode due - * to a recent call to DominatorTreeNode.insert and want to get the up-to-date - * version. We don't have to walk the whole tree: if there is an updated version - * of the node then it *must* be along the path. - * - * @param {NodeId} id - * @param {DominatorTreeNode} tree - * @param {Array<NodeId>} path - * - * @returns {DominatorTreeNode|null} - */ -DominatorTreeNode.getNodeByIdAlongPath = function (id, tree, path) { - function find(node, i) { - if (!node || node.nodeId !== path[i]) { - return null; - } - - if (node.nodeId === id) { - return node; - } - - if (i === path.length - 1 || !node.children) { - return null; - } - - const nextId = path[i + 1]; - return find(node.children.find(c => c.nodeId === nextId), i + 1); - } - - return find(tree, 0); -}; - -/** - * Find the shortest retaining paths for the given set of DominatorTreeNodes, - * and populate each node's `shortestPaths` property with them in place. - * - * @param {HeapSnapshot} snapshot - * @param {Object} breakdown - * @param {NodeId} start - * @param {Array<DominatorTreeNode>} treeNodes - * @param {Number} maxNumPaths - */ -DominatorTreeNode.attachShortestPaths = function (snapshot, - breakdown, - start, - treeNodes, - maxNumPaths = DEFAULT_MAX_NUM_PATHS) { - const idToTreeNode = new Map(); - const targets = []; - for (let node of treeNodes) { - const id = node.nodeId; - idToTreeNode.set(id, node); - targets.push(id); - } - - const shortestPaths = snapshot.computeShortestPaths(start, - targets, - maxNumPaths); - - for (let [target, paths] of shortestPaths) { - const deduped = deduplicatePaths(target, paths); - deduped.nodes = deduped.nodes.map(id => { - const { label } = - DominatorTreeNode.getLabelAndShallowSize(id, snapshot, breakdown); - return { id, label }; - }); - - idToTreeNode.get(target).shortestPaths = deduped; - } -}; diff --git a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp b/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp deleted file mode 100644 index 72a289558..000000000 --- a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/FileDescriptorOutputStream.h" -#include "private/pprio.h" - -namespace mozilla { -namespace devtools { - -/* static */ already_AddRefed<FileDescriptorOutputStream> -FileDescriptorOutputStream::Create(const ipc::FileDescriptor& fileDescriptor) -{ - if (NS_WARN_IF(!fileDescriptor.IsValid())) - return nullptr; - - auto rawFD = fileDescriptor.ClonePlatformHandle(); - PRFileDesc* prfd = PR_ImportFile(PROsfd(rawFD.release())); - if (NS_WARN_IF(!prfd)) - return nullptr; - - RefPtr<FileDescriptorOutputStream> stream = new FileDescriptorOutputStream(prfd); - return stream.forget(); -} - -NS_IMPL_ISUPPORTS(FileDescriptorOutputStream, nsIOutputStream); - -NS_IMETHODIMP -FileDescriptorOutputStream::Close() -{ - // Repeatedly closing is idempotent. - if (!fd) - return NS_OK; - - if (PR_Close(fd) != PR_SUCCESS) - return NS_ERROR_FAILURE; - fd = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -FileDescriptorOutputStream::Write(const char* buf, uint32_t count, uint32_t* retval) -{ - if (NS_WARN_IF(!fd)) - return NS_ERROR_FAILURE; - - auto written = PR_Write(fd, buf, count); - if (written < 0) - return NS_ERROR_FAILURE; - *retval = written; - return NS_OK; -} - -NS_IMETHODIMP -FileDescriptorOutputStream::Flush() -{ - if (NS_WARN_IF(!fd)) - return NS_ERROR_FAILURE; - - return PR_Sync(fd) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -FileDescriptorOutputStream::WriteFrom(nsIInputStream* fromStream, uint32_t count, - uint32_t* retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -FileDescriptorOutputStream::WriteSegments(nsReadSegmentFun reader, void* closure, - uint32_t count, uint32_t* retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -FileDescriptorOutputStream::IsNonBlocking(bool* retval) -{ - *retval = false; - return NS_OK; -} - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.h b/devtools/shared/heapsnapshot/FileDescriptorOutputStream.h deleted file mode 100644 index 6990f1fc3..000000000 --- a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_FileDescriptorOutputStream_h -#define mozilla_devtools_FileDescriptorOutputStream_h - -#include <prio.h> - -#include "mozilla/AlreadyAddRefed.h" -#include "mozilla/ipc/FileDescriptor.h" -#include "nsIOutputStream.h" - -namespace mozilla { -namespace devtools { - -class FileDescriptorOutputStream final : public nsIOutputStream -{ -private: - PRFileDesc* fd; - -public: - static already_AddRefed<FileDescriptorOutputStream> - Create(const ipc::FileDescriptor& fileDescriptor); - -private: - explicit FileDescriptorOutputStream(PRFileDesc* prfd) - : fd(prfd) - { } - - virtual ~FileDescriptorOutputStream() { } - - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIOUTPUTSTREAM -}; - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_FileDescriptorOutputStream_h diff --git a/devtools/shared/heapsnapshot/HeapAnalysesClient.js b/devtools/shared/heapsnapshot/HeapAnalysesClient.js deleted file mode 100644 index 98601a2b1..000000000 --- a/devtools/shared/heapsnapshot/HeapAnalysesClient.js +++ /dev/null @@ -1,277 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const DevToolsUtils = require("devtools/shared/DevToolsUtils"); -const { DevToolsWorker } = require("devtools/shared/worker/worker"); - -const WORKER_URL = - "resource://devtools/shared/heapsnapshot/HeapAnalysesWorker.js"; -var workerCounter = 0; - -/** - * A HeapAnalysesClient instance provides a developer-friendly interface for - * interacting with a HeapAnalysesWorker. This enables users to be ignorant of - * the message passing protocol used to communicate with the worker. The - * HeapAnalysesClient owns the worker, and terminating the worker is done by - * terminating the client (see the `destroy` method). - */ -const HeapAnalysesClient = module.exports = function () { - this._worker = new DevToolsWorker(WORKER_URL, { - name: `HeapAnalyses-${workerCounter++}`, - verbose: DevToolsUtils.dumpv.wantVerbose - }); -}; - -/** - * Destroy the worker, causing it to release its resources (such as heap - * snapshots it has deserialized and read into memory). The client is no longer - * usable after calling this method. - */ -HeapAnalysesClient.prototype.destroy = function () { - this._worker.destroy(); - this._worker = null; -}; - -/** - * Tell the worker to read into memory the heap snapshot at the given file - * path. This is a prerequisite for asking the worker to perform various - * analyses on a heap snapshot. - * - * @param {String} snapshotFilePath - * - * @returns Promise - * The promise is fulfilled if the heap snapshot is successfully - * deserialized and read into memory. The promise is rejected if that - * does not happen, eg due to a bad file path or malformed heap - * snapshot file. - */ -HeapAnalysesClient.prototype.readHeapSnapshot = function (snapshotFilePath) { - return this._worker.performTask("readHeapSnapshot", { snapshotFilePath }); -}; - -/** - * Tell the worker to delete all references to the snapshot and dominator trees - * linked to the provided snapshot file path. - * - * @param {String} snapshotFilePath - * @return Promise<undefined> - */ -HeapAnalysesClient.prototype.deleteHeapSnapshot = function (snapshotFilePath) { - return this._worker.performTask("deleteHeapSnapshot", { snapshotFilePath }); -}; - -/** - * Request the creation time given a snapshot file path. Returns `null` - * if snapshot does not exist. - * - * @param {String} snapshotFilePath - * The path to the snapshot. - * @return {Number?} - * The unix timestamp of the creation time of the snapshot, or null if - * snapshot does not exist. - */ -HeapAnalysesClient.prototype.getCreationTime = function (snapshotFilePath) { - return this._worker.performTask("getCreationTime", snapshotFilePath); -}; - -/** * Censuses *****************************************************************/ - -/** - * Ask the worker to perform a census analysis on the heap snapshot with the - * given path. The heap snapshot at the given path must have already been read - * into memory by the worker (see `readHeapSnapshot`). - * - * @param {String} snapshotFilePath - * - * @param {Object} censusOptions - * A structured-cloneable object specifying the requested census's - * breakdown. See the "takeCensus" section of - * `js/src/doc/Debugger/Debugger.Memory.md` for detailed documentation. - * - * @param {Object} requestOptions - * An object specifying options of this worker request. - * - {Boolean} asTreeNode - * Whether or not the census is returned as a CensusTreeNode, - * or just a breakdown report. Defaults to false. - * @see `devtools/shared/heapsnapshot/census-tree-node.js` - * - {Boolean} asInvertedTreeNode - * Whether or not the census is returned as an inverted - * CensusTreeNode. Defaults to false. - * - {String} filter - * A filter string to prune the resulting tree with. Only applies if - * either asTreeNode or asInvertedTreeNode is true. - * - * @returns Promise<Object> - * An object with the following properties: - * - report: - * The report generated by the given census breakdown, or a - * CensusTreeNode generated by the given census breakdown if - * `asTreeNode` is true. - * - parentMap: - * The result of calling CensusUtils.createParentMap on the generated - * report. Only exists if asTreeNode or asInvertedTreeNode are set. - */ -HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath, - censusOptions, - requestOptions = {}) { - return this._worker.performTask("takeCensus", { - snapshotFilePath, - censusOptions, - requestOptions, - }); -}; - -/** - * Get the individual nodes that correspond to the given census report leaf - * indices. - * - * @param {Object} opts - * An object with the following properties: - * - {DominatorTreeId} dominatorTreeId: The id of the dominator tree. - * - {Set<Number>} indices: The indices of the census report leaves we - * would like to get the individuals for. - * - {Object} censusBreakdown: The breakdown used to generate the census. - * - {Object} labelBreakdown: The breakdown we would like to use when - * labeling the resulting nodes. - * - {Number} maxRetainingPaths: The maximum number of retaining paths to - * compute for each node. - * - {Number} maxIndividuals: The maximum number of individual nodes to - * return. - * - * @returns {Promise<Object>} - * A promise of an object with the following properties: - * - {Array<DominatorTreeNode>} nodes: An array of `DominatorTreeNode`s - * with their shortest paths attached, and without any dominator tree - * child/parent information attached. The results are sorted by - * retained size. - * - */ -HeapAnalysesClient.prototype.getCensusIndividuals = function (opts) { - return this._worker.performTask("getCensusIndividuals", opts); -}; - -/** - * Request that the worker take a census on the heap snapshots with the given - * paths and then return the difference between them. Both heap snapshots must - * have already been read into memory by the worker (see `readHeapSnapshot`). - * - * @param {String} firstSnapshotFilePath - * The first snapshot file path. - * - * @param {String} secondSnapshotFilePath - * The second snapshot file path. - * - * @param {Object} censusOptions - * A structured-cloneable object specifying the requested census's - * breakdown. See the "takeCensus" section of - * `js/src/doc/Debugger/Debugger.Memory.md` for detailed documentation. - * - * @param {Object} requestOptions - * An object specifying options for this request. - * - {Boolean} asTreeNode - * Whether the resulting delta report should be converted to a census - * tree node before returned. Defaults to false. - * - {Boolean} asInvertedTreeNode - * Whether or not the census is returned as an inverted - * CensusTreeNode. Defaults to false. - * - {String} filter - * A filter string to prune the resulting tree with. Only applies if - * either asTreeNode or asInvertedTreeNode is true. - * - * @returns Promise<Object> - * - delta: - * The delta report generated by diffing the two census reports, or a - * CensusTreeNode generated from the delta report if - * `requestOptions.asTreeNode` was true. - * - parentMap: - * The result of calling CensusUtils.createParentMap on the generated - * delta. Only exists if asTreeNode or asInvertedTreeNode are set. - */ -HeapAnalysesClient.prototype.takeCensusDiff = function (firstSnapshotFilePath, - secondSnapshotFilePath, - censusOptions, - requestOptions = {}) { - return this._worker.performTask("takeCensusDiff", { - firstSnapshotFilePath, - secondSnapshotFilePath, - censusOptions, - requestOptions - }); -}; - -/** * Dominator Trees **********************************************************/ - -/** - * Compute the dominator tree of the heap snapshot loaded from the given file - * path. Returns the id of the computed dominator tree. - * - * @param {String} snapshotFilePath - * - * @returns {Promise<DominatorTreeId>} - */ -HeapAnalysesClient.prototype.computeDominatorTree = function (snapshotFilePath) { - return this._worker.performTask("computeDominatorTree", snapshotFilePath); -}; - -/** - * Get the initial, partial view of the dominator tree with the given id. - * - * @param {Object} opts - * An object specifying options for this request. - * - {DominatorTreeId} dominatorTreeId - * The id of the dominator tree. - * - {Object} breakdown - * The breakdown used to generate node labels. - * - {Number} maxDepth - * The maximum depth to traverse down the tree to create this initial - * view. - * - {Number} maxSiblings - * The maximum number of siblings to visit within each traversed node's - * children. - * - {Number} maxRetainingPaths - * The maximum number of retaining paths to find for each node. - * - * @returns {Promise<DominatorTreeNode>} - */ -HeapAnalysesClient.prototype.getDominatorTree = function (opts) { - return this._worker.performTask("getDominatorTree", opts); -}; - -/** - * Get a subset of a nodes children in the dominator tree. - * - * @param {Object} opts - * An object specifying options for this request. - * - {DominatorTreeId} dominatorTreeId - * The id of the dominator tree. - * - {NodeId} nodeId - * The id of the node whose children are being found. - * - {Object} breakdown - * The breakdown used to generate node labels. - * - {Number} startIndex - * The starting index within the full set of immediately dominated - * children of the children being requested. Children are always sorted - * by greatest to least retained size. - * - {Number} maxCount - * The maximum number of children to return. - * - {Number} maxRetainingPaths - * The maximum number of retaining paths to find for each node. - * - * @returns {Promise<Object>} - * A promise of an object with the following properties: - * - {Array<DominatorTreeNode>} nodes - * The requested nodes that are immediately dominated by the node - * identified by `opts.nodeId`. - * - {Boolean} moreChildrenAvailable - * True iff there are more children available after the returned - * nodes. - * - {Array<NodeId>} path - * The path through the tree from the root to these node's parent, eg - * [root's id, child of root's id, child of child of root's id, ..., `nodeId`]. - */ -HeapAnalysesClient.prototype.getImmediatelyDominated = function (opts) { - return this._worker.performTask("getImmediatelyDominated", opts); -}; diff --git a/devtools/shared/heapsnapshot/HeapAnalysesWorker.js b/devtools/shared/heapsnapshot/HeapAnalysesWorker.js deleted file mode 100644 index d07d67f80..000000000 --- a/devtools/shared/heapsnapshot/HeapAnalysesWorker.js +++ /dev/null @@ -1,303 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* global ThreadSafeChromeUtils*/ - -// This is a worker which reads offline heap snapshots into memory and performs -// heavyweight analyses on them without blocking the main thread. A -// HeapAnalysesWorker is owned and communicated with by a HeapAnalysesClient -// instance. See HeapAnalysesClient.js. - -"use strict"; - -importScripts("resource://gre/modules/workers/require.js"); -importScripts("resource://devtools/shared/worker/helper.js"); -const { censusReportToCensusTreeNode } = require("resource://devtools/shared/heapsnapshot/census-tree-node.js"); -const DominatorTreeNode = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js"); -const CensusUtils = require("resource://devtools/shared/heapsnapshot/CensusUtils.js"); - -const DEFAULT_START_INDEX = 0; -const DEFAULT_MAX_COUNT = 50; - -/** - * The set of HeapSnapshot instances this worker has read into memory. Keyed by - * snapshot file path. - */ -const snapshots = Object.create(null); - -/** - * The set of `DominatorTree`s that have been computed, mapped by their id (aka - * the index into this array). - * - * @see /dom/webidl/DominatorTree.webidl - */ -const dominatorTrees = []; - -/** - * The i^th HeapSnapshot in this array is the snapshot used to generate the i^th - * dominator tree in `dominatorTrees` above. This lets us map from a dominator - * tree id to the snapshot it came from. - */ -const dominatorTreeSnapshots = []; - -/** - * @see HeapAnalysesClient.prototype.readHeapSnapshot - */ -workerHelper.createTask(self, "readHeapSnapshot", ({ snapshotFilePath }) => { - snapshots[snapshotFilePath] = - ThreadSafeChromeUtils.readHeapSnapshot(snapshotFilePath); - return true; -}); - -/** - * @see HeapAnalysesClient.prototype.deleteHeapSnapshot - */ -workerHelper.createTask(self, "deleteHeapSnapshot", ({ snapshotFilePath }) => { - let snapshot = snapshots[snapshotFilePath]; - if (!snapshot) { - throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); - } - - snapshots[snapshotFilePath] = undefined; - - let dominatorTreeId = dominatorTreeSnapshots.indexOf(snapshot); - if (dominatorTreeId != -1) { - dominatorTreeSnapshots[dominatorTreeId] = undefined; - dominatorTrees[dominatorTreeId] = undefined; - } -}); - -/** - * @see HeapAnalysesClient.prototype.takeCensus - */ -workerHelper.createTask(self, "takeCensus", ({ snapshotFilePath, censusOptions, requestOptions }) => { - if (!snapshots[snapshotFilePath]) { - throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); - } - - let report = snapshots[snapshotFilePath].takeCensus(censusOptions); - let parentMap; - - if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) { - const opts = { filter: requestOptions.filter || null }; - if (requestOptions.asInvertedTreeNode) { - opts.invert = true; - } - report = censusReportToCensusTreeNode(censusOptions.breakdown, report, opts); - parentMap = CensusUtils.createParentMap(report); - } - - return { report, parentMap }; -}); - -/** - * @see HeapAnalysesClient.prototype.getCensusIndividuals - */ -workerHelper.createTask(self, "getCensusIndividuals", request => { - const { - dominatorTreeId, - indices, - censusBreakdown, - labelBreakdown, - maxRetainingPaths, - maxIndividuals, - } = request; - - const dominatorTree = dominatorTrees[dominatorTreeId]; - if (!dominatorTree) { - throw new Error( - `There does not exist a DominatorTree with the id ${dominatorTreeId}`); - } - - const snapshot = dominatorTreeSnapshots[dominatorTreeId]; - const nodeIds = CensusUtils.getCensusIndividuals(indices, censusBreakdown, snapshot); - - const nodes = nodeIds - .sort((a, b) => dominatorTree.getRetainedSize(b) - dominatorTree.getRetainedSize(a)) - .slice(0, maxIndividuals) - .map(id => { - const { label, shallowSize } = - DominatorTreeNode.getLabelAndShallowSize(id, snapshot, labelBreakdown); - const retainedSize = dominatorTree.getRetainedSize(id); - const node = new DominatorTreeNode(id, label, shallowSize, retainedSize); - node.moreChildrenAvailable = false; - return node; - }); - - DominatorTreeNode.attachShortestPaths(snapshot, - labelBreakdown, - dominatorTree.root, - nodes, - maxRetainingPaths); - - return { nodes }; -}); - -/** - * @see HeapAnalysesClient.prototype.takeCensusDiff - */ -workerHelper.createTask(self, "takeCensusDiff", request => { - const { - firstSnapshotFilePath, - secondSnapshotFilePath, - censusOptions, - requestOptions - } = request; - - if (!snapshots[firstSnapshotFilePath]) { - throw new Error(`No known heap snapshot for '${firstSnapshotFilePath}'`); - } - - if (!snapshots[secondSnapshotFilePath]) { - throw new Error(`No known heap snapshot for '${secondSnapshotFilePath}'`); - } - - const first = snapshots[firstSnapshotFilePath].takeCensus(censusOptions); - const second = snapshots[secondSnapshotFilePath].takeCensus(censusOptions); - let delta = CensusUtils.diff(censusOptions.breakdown, first, second); - let parentMap; - - if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) { - const opts = { filter: requestOptions.filter || null }; - if (requestOptions.asInvertedTreeNode) { - opts.invert = true; - } - delta = censusReportToCensusTreeNode(censusOptions.breakdown, delta, opts); - parentMap = CensusUtils.createParentMap(delta); - } - - return { delta, parentMap }; -}); - -/** - * @see HeapAnalysesClient.prototype.getCreationTime - */ -workerHelper.createTask(self, "getCreationTime", snapshotFilePath => { - if (!snapshots[snapshotFilePath]) { - throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); - } - return snapshots[snapshotFilePath].creationTime; -}); - -/** - * @see HeapAnalysesClient.prototype.computeDominatorTree - */ -workerHelper.createTask(self, "computeDominatorTree", snapshotFilePath => { - const snapshot = snapshots[snapshotFilePath]; - if (!snapshot) { - throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); - } - - const id = dominatorTrees.length; - dominatorTrees.push(snapshot.computeDominatorTree()); - dominatorTreeSnapshots.push(snapshot); - return id; -}); - -/** - * @see HeapAnalysesClient.prototype.getDominatorTree - */ -workerHelper.createTask(self, "getDominatorTree", request => { - const { - dominatorTreeId, - breakdown, - maxDepth, - maxSiblings, - maxRetainingPaths, - } = request; - - if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) { - throw new Error( - `There does not exist a DominatorTree with the id ${dominatorTreeId}`); - } - - const dominatorTree = dominatorTrees[dominatorTreeId]; - const snapshot = dominatorTreeSnapshots[dominatorTreeId]; - - const tree = DominatorTreeNode.partialTraversal(dominatorTree, - snapshot, - breakdown, - maxDepth, - maxSiblings); - - const nodes = []; - (function getNodes(node) { - nodes.push(node); - if (node.children) { - for (let i = 0, length = node.children.length; i < length; i++) { - getNodes(node.children[i]); - } - } - }(tree)); - - DominatorTreeNode.attachShortestPaths(snapshot, - breakdown, - dominatorTree.root, - nodes, - maxRetainingPaths); - - return tree; -}); - -/** - * @see HeapAnalysesClient.prototype.getImmediatelyDominated - */ -workerHelper.createTask(self, "getImmediatelyDominated", request => { - const { - dominatorTreeId, - nodeId, - breakdown, - startIndex, - maxCount, - maxRetainingPaths, - } = request; - - if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) { - throw new Error( - `There does not exist a DominatorTree with the id ${dominatorTreeId}`); - } - - const dominatorTree = dominatorTrees[dominatorTreeId]; - const snapshot = dominatorTreeSnapshots[dominatorTreeId]; - - const childIds = dominatorTree.getImmediatelyDominated(nodeId); - if (!childIds) { - throw new Error(`${nodeId} is not a node id in the dominator tree`); - } - - const start = startIndex || DEFAULT_START_INDEX; - const count = maxCount || DEFAULT_MAX_COUNT; - const end = start + count; - - const nodes = childIds - .slice(start, end) - .map(id => { - const { label, shallowSize } = - DominatorTreeNode.getLabelAndShallowSize(id, snapshot, breakdown); - const retainedSize = dominatorTree.getRetainedSize(id); - const node = new DominatorTreeNode(id, label, shallowSize, retainedSize); - node.parentId = nodeId; - // DominatorTree.getImmediatelyDominated will always return non-null here - // because we got the id directly from the dominator tree. - node.moreChildrenAvailable = dominatorTree.getImmediatelyDominated(id).length > 0; - return node; - }); - - const path = []; - let id = nodeId; - do { - path.push(id); - id = dominatorTree.getImmediateDominator(id); - } while (id !== null); - path.reverse(); - - const moreChildrenAvailable = childIds.length > end; - - DominatorTreeNode.attachShortestPaths(snapshot, - breakdown, - dominatorTree.root, - nodes, - maxRetainingPaths); - - return { nodes, moreChildrenAvailable, path }; -}); diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp deleted file mode 100644 index 299a96a9c..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ /dev/null @@ -1,1619 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "HeapSnapshot.h" - -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/gzip_stream.h> -#include <google/protobuf/io/zero_copy_stream_impl_lite.h> - -#include "js/Debug.h" -#include "js/TypeDecls.h" -#include "js/UbiNodeBreadthFirst.h" -#include "js/UbiNodeCensus.h" -#include "js/UbiNodeDominatorTree.h" -#include "js/UbiNodeShortestPaths.h" -#include "mozilla/Attributes.h" -#include "mozilla/CycleCollectedJSContext.h" -#include "mozilla/devtools/AutoMemMap.h" -#include "mozilla/devtools/CoreDump.pb.h" -#include "mozilla/devtools/DeserializedNode.h" -#include "mozilla/devtools/DominatorTree.h" -#include "mozilla/devtools/FileDescriptorOutputStream.h" -#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h" -#include "mozilla/devtools/ZeroCopyNSIOutputStream.h" -#include "mozilla/dom/ChromeUtils.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/dom/HeapSnapshotBinding.h" -#include "mozilla/RangedPtr.h" -#include "mozilla/Unused.h" - -#include "jsapi.h" -#include "jsfriendapi.h" -#include "nsCycleCollectionParticipant.h" -#include "nsCRTGlue.h" -#include "nsDirectoryServiceDefs.h" -#include "nsIFile.h" -#include "nsIOutputStream.h" -#include "nsISupportsImpl.h" -#include "nsNetUtil.h" -#include "nsPrintfCString.h" -#include "prerror.h" -#include "prio.h" -#include "prtypes.h" - -namespace mozilla { -namespace devtools { - -using namespace JS; -using namespace dom; - -using ::google::protobuf::io::ArrayInputStream; -using ::google::protobuf::io::CodedInputStream; -using ::google::protobuf::io::GzipInputStream; -using ::google::protobuf::io::ZeroCopyInputStream; - -using JS::ubi::AtomOrTwoByteChars; -using JS::ubi::ShortestPaths; - -MallocSizeOf -GetCurrentThreadDebuggerMallocSizeOf() -{ - auto ccjscx = CycleCollectedJSContext::Get(); - MOZ_ASSERT(ccjscx); - auto cx = ccjscx->Context(); - MOZ_ASSERT(cx); - auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(cx); - MOZ_ASSERT(mallocSizeOf); - return mallocSizeOf; -} - -/*** Cycle Collection Boilerplate *****************************************************************/ - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HeapSnapshot, mParent) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(HeapSnapshot) -NS_IMPL_CYCLE_COLLECTING_RELEASE(HeapSnapshot) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HeapSnapshot) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -/* virtual */ JSObject* -HeapSnapshot::WrapObject(JSContext* aCx, HandleObject aGivenProto) -{ - return HeapSnapshotBinding::Wrap(aCx, this, aGivenProto); -} - -/*** Reading Heap Snapshots ***********************************************************************/ - -/* static */ already_AddRefed<HeapSnapshot> -HeapSnapshot::Create(JSContext* cx, - GlobalObject& global, - const uint8_t* buffer, - uint32_t size, - ErrorResult& rv) -{ - RefPtr<HeapSnapshot> snapshot = new HeapSnapshot(cx, global.GetAsSupports()); - if (!snapshot->init(cx, buffer, size)) { - rv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - return snapshot.forget(); -} - -template<typename MessageType> -static bool -parseMessage(ZeroCopyInputStream& stream, uint32_t sizeOfMessage, MessageType& message) -{ - // We need to create a new `CodedInputStream` for each message so that the - // 64MB limit is applied per-message rather than to the whole stream. - CodedInputStream codedStream(&stream); - - // The protobuf message nesting that core dumps exhibit is dominated by - // allocation stacks' frames. In the most deeply nested case, each frame has - // two messages: a StackFrame message and a StackFrame::Data message. These - // frames are on top of a small constant of other messages. There are a - // MAX_STACK_DEPTH number of frames, so we multiply this by 3 to make room for - // the two messages per frame plus some head room for the constant number of - // non-dominating messages. - codedStream.SetRecursionLimit(HeapSnapshot::MAX_STACK_DEPTH * 3); - - auto limit = codedStream.PushLimit(sizeOfMessage); - if (NS_WARN_IF(!message.ParseFromCodedStream(&codedStream)) || - NS_WARN_IF(!codedStream.ConsumedEntireMessage()) || - NS_WARN_IF(codedStream.BytesUntilLimit() != 0)) - { - return false; - } - - codedStream.PopLimit(limit); - return true; -} - -template<typename CharT, typename InternedStringSet> -struct GetOrInternStringMatcher -{ - InternedStringSet& internedStrings; - - explicit GetOrInternStringMatcher(InternedStringSet& strings) : internedStrings(strings) { } - - const CharT* match(const std::string* str) { - MOZ_ASSERT(str); - size_t length = str->length() / sizeof(CharT); - auto tempString = reinterpret_cast<const CharT*>(str->data()); - - UniquePtr<CharT[], NSFreePolicy> owned(NS_strndup(tempString, length)); - if (!owned || !internedStrings.append(Move(owned))) - return nullptr; - - return internedStrings.back().get(); - } - - const CharT* match(uint64_t ref) { - if (MOZ_LIKELY(ref < internedStrings.length())) { - auto& string = internedStrings[ref]; - MOZ_ASSERT(string); - return string.get(); - } - - return nullptr; - } -}; - -template< - // Either char or char16_t. - typename CharT, - // A reference to either `internedOneByteStrings` or `internedTwoByteStrings` - // if CharT is char or char16_t respectively. - typename InternedStringSet> -const CharT* -HeapSnapshot::getOrInternString(InternedStringSet& internedStrings, - Maybe<StringOrRef>& maybeStrOrRef) -{ - // Incomplete message: has neither a string nor a reference to an already - // interned string. - if (MOZ_UNLIKELY(maybeStrOrRef.isNothing())) - return nullptr; - - GetOrInternStringMatcher<CharT, InternedStringSet> m(internedStrings); - return maybeStrOrRef->match(m); -} - -// Get a de-duplicated string as a Maybe<StringOrRef> from the given `msg`. -#define GET_STRING_OR_REF_WITH_PROP_NAMES(msg, strPropertyName, refPropertyName) \ - (msg.has_##refPropertyName() \ - ? Some(StringOrRef(msg.refPropertyName())) \ - : msg.has_##strPropertyName() \ - ? Some(StringOrRef(&msg.strPropertyName())) \ - : Nothing()) - -#define GET_STRING_OR_REF(msg, property) \ - (msg.has_##property##ref() \ - ? Some(StringOrRef(msg.property##ref())) \ - : msg.has_##property() \ - ? Some(StringOrRef(&msg.property())) \ - : Nothing()) - -bool -HeapSnapshot::saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents) -{ - // NB: de-duplicated string properties must be read back and interned in the - // same order here as they are written and serialized in - // `CoreDumpWriter::writeNode` or else indices in references to already - // serialized strings will be off. - - if (NS_WARN_IF(!node.has_id())) - return false; - NodeId id = node.id(); - - // NodeIds are derived from pointers (at most 48 bits) and we rely on them - // fitting into JS numbers (IEEE 754 doubles, can precisely store 53 bit - // integers) despite storing them on disk as 64 bit integers. - if (NS_WARN_IF(!JS::Value::isNumberRepresentable(id))) - return false; - - // Should only deserialize each node once. - if (NS_WARN_IF(nodes.has(id))) - return false; - - if (NS_WARN_IF(!JS::ubi::Uint32IsValidCoarseType(node.coarsetype()))) - return false; - auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype()); - - Maybe<StringOrRef> typeNameOrRef = GET_STRING_OR_REF_WITH_PROP_NAMES(node, typename_, typenameref); - auto typeName = getOrInternString<char16_t>(internedTwoByteStrings, typeNameOrRef); - if (NS_WARN_IF(!typeName)) - return false; - - if (NS_WARN_IF(!node.has_size())) - return false; - uint64_t size = node.size(); - - auto edgesLength = node.edges_size(); - DeserializedNode::EdgeVector edges; - if (NS_WARN_IF(!edges.reserve(edgesLength))) - return false; - for (decltype(edgesLength) i = 0; i < edgesLength; i++) { - auto& protoEdge = node.edges(i); - - if (NS_WARN_IF(!protoEdge.has_referent())) - return false; - NodeId referent = protoEdge.referent(); - - if (NS_WARN_IF(!edgeReferents.put(referent))) - return false; - - const char16_t* edgeName = nullptr; - if (protoEdge.EdgeNameOrRef_case() != protobuf::Edge::EDGENAMEORREF_NOT_SET) { - Maybe<StringOrRef> edgeNameOrRef = GET_STRING_OR_REF(protoEdge, name); - edgeName = getOrInternString<char16_t>(internedTwoByteStrings, edgeNameOrRef); - if (NS_WARN_IF(!edgeName)) - return false; - } - - edges.infallibleAppend(DeserializedEdge(referent, edgeName)); - } - - Maybe<StackFrameId> allocationStack; - if (node.has_allocationstack()) { - StackFrameId id = 0; - if (NS_WARN_IF(!saveStackFrame(node.allocationstack(), id))) - return false; - allocationStack.emplace(id); - } - MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack()); - - const char* jsObjectClassName = nullptr; - if (node.JSObjectClassNameOrRef_case() != protobuf::Node::JSOBJECTCLASSNAMEORREF_NOT_SET) { - Maybe<StringOrRef> clsNameOrRef = GET_STRING_OR_REF(node, jsobjectclassname); - jsObjectClassName = getOrInternString<char>(internedOneByteStrings, clsNameOrRef); - if (NS_WARN_IF(!jsObjectClassName)) - return false; - } - - const char* scriptFilename = nullptr; - if (node.ScriptFilenameOrRef_case() != protobuf::Node::SCRIPTFILENAMEORREF_NOT_SET) { - Maybe<StringOrRef> scriptFilenameOrRef = GET_STRING_OR_REF(node, scriptfilename); - scriptFilename = getOrInternString<char>(internedOneByteStrings, scriptFilenameOrRef); - if (NS_WARN_IF(!scriptFilename)) - return false; - } - - if (NS_WARN_IF(!nodes.putNew(id, DeserializedNode(id, coarseType, typeName, - size, Move(edges), - allocationStack, - jsObjectClassName, - scriptFilename, *this)))) - { - return false; - }; - - return true; -} - -bool -HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame, - StackFrameId& outFrameId) -{ - // NB: de-duplicated string properties must be read in the same order here as - // they are written in `CoreDumpWriter::getProtobufStackFrame` or else indices - // in references to already serialized strings will be off. - - 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; - - if (!data.has_line()) - return false; - uint32_t line = data.line(); - - if (!data.has_column()) - return false; - uint32_t column = data.column(); - - if (!data.has_issystem()) - return false; - bool isSystem = data.issystem(); - - if (!data.has_isselfhosted()) - return false; - bool isSelfHosted = data.isselfhosted(); - - Maybe<StringOrRef> sourceOrRef = GET_STRING_OR_REF(data, source); - auto source = getOrInternString<char16_t>(internedTwoByteStrings, sourceOrRef); - if (!source) - return false; - - const char16_t* functionDisplayName = nullptr; - if (data.FunctionDisplayNameOrRef_case() != - protobuf::StackFrame_Data::FUNCTIONDISPLAYNAMEORREF_NOT_SET) - { - Maybe<StringOrRef> nameOrRef = GET_STRING_OR_REF(data, functiondisplayname); - functionDisplayName = getOrInternString<char16_t>(internedTwoByteStrings, nameOrRef); - if (!functionDisplayName) - return false; - } - - Maybe<StackFrameId> parent; - if (data.has_parent()) { - StackFrameId parentId = 0; - if (!saveStackFrame(data.parent(), parentId)) - return false; - parent = Some(parentId); - } - - if (!frames.putNew(id, DeserializedStackFrame(id, parent, line, column, - source, functionDisplayName, - isSystem, isSelfHosted, *this))) - { - return false; - } - - outFrameId = id; - return true; -} - -#undef GET_STRING_OR_REF_WITH_PROP_NAMES -#undef GET_STRING_OR_REF - -// Because protobuf messages aren't self-delimiting, we serialize each message -// preceded by its size in bytes. When deserializing, we read this size and then -// limit reading from the stream to the given byte size. If we didn't, then the -// first message would consume the entire stream. -static bool -readSizeOfNextMessage(ZeroCopyInputStream& stream, uint32_t* sizep) -{ - MOZ_ASSERT(sizep); - CodedInputStream codedStream(&stream); - return codedStream.ReadVarint32(sizep) && *sizep > 0; -} - -bool -HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size) -{ - if (!nodes.init() || !frames.init()) - return false; - - ArrayInputStream stream(buffer, size); - GzipInputStream gzipStream(&stream); - uint32_t sizeOfMessage = 0; - - // First is the metadata. - - protobuf::Metadata metadata; - if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage))) - return false; - if (!parseMessage(gzipStream, sizeOfMessage, metadata)) - return false; - if (metadata.has_timestamp()) - timestamp.emplace(metadata.timestamp()); - - // Next is the root node. - - protobuf::Node root; - if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage))) - return false; - if (!parseMessage(gzipStream, sizeOfMessage, root)) - return false; - - // Although the id is optional in the protobuf format for future proofing, we - // can't currently do anything without it. - if (NS_WARN_IF(!root.has_id())) - return false; - rootId = root.id(); - - // The set of all node ids we've found edges pointing to. - NodeIdSet edgeReferents(cx); - if (NS_WARN_IF(!edgeReferents.init())) - return false; - - if (NS_WARN_IF(!saveNode(root, edgeReferents))) - return false; - - // Finally, the rest of the nodes in the core dump. - - // Test for the end of the stream. The protobuf library gives no way to tell - // the difference between an underlying read error and the stream being - // done. All we can do is attempt to read the size of the next message and - // extrapolate guestimations from the result of that operation. - while (readSizeOfNextMessage(gzipStream, &sizeOfMessage)) { - protobuf::Node node; - if (!parseMessage(gzipStream, sizeOfMessage, node)) - return false; - if (NS_WARN_IF(!saveNode(node, edgeReferents))) - return false; - } - - // Check the set of node ids referred to by edges we found and ensure that we - // have the node corresponding to each id. If we don't have all of them, it is - // unsafe to perform analyses of this heap snapshot. - for (auto range = edgeReferents.all(); !range.empty(); range.popFront()) { - if (NS_WARN_IF(!nodes.has(range.front()))) - return false; - } - - return true; -} - - -/*** Heap Snapshot Analyses ***********************************************************************/ - -void -HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, - JS::MutableHandleValue rval, ErrorResult& rv) -{ - JS::ubi::Census census(cx); - if (NS_WARN_IF(!census.init())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - JS::ubi::CountTypePtr rootType; - if (NS_WARN_IF(!JS::ubi::ParseCensusOptions(cx, census, options, rootType))) { - rv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); - if (NS_WARN_IF(!rootCount)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - JS::ubi::CensusHandler handler(census, rootCount, GetCurrentThreadDebuggerMallocSizeOf()); - - { - JS::AutoCheckCannotGC nogc; - - JS::ubi::CensusTraversal traversal(cx, handler, nogc); - if (NS_WARN_IF(!traversal.init())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - if (NS_WARN_IF(!traversal.addStart(getRoot()))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - if (NS_WARN_IF(!traversal.traverse())) { - rv.Throw(NS_ERROR_UNEXPECTED); - return; - } - } - - if (NS_WARN_IF(!handler.report(cx, rval))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } -} - -void -HeapSnapshot::DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId, - JS::MutableHandleValue rval, ErrorResult& rv) { - MOZ_ASSERT(breakdown); - JS::RootedValue breakdownVal(cx, JS::ObjectValue(*breakdown)); - JS::ubi::CountTypePtr rootType = JS::ubi::ParseBreakdown(cx, breakdownVal); - if (NS_WARN_IF(!rootType)) { - rv.Throw(NS_ERROR_UNEXPECTED); - return; - } - - JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); - if (NS_WARN_IF(!rootCount)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - JS::ubi::Node::Id id(nodeId); - Maybe<JS::ubi::Node> node = getNodeById(id); - if (NS_WARN_IF(node.isNothing())) { - rv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); - if (NS_WARN_IF(!rootCount->count(mallocSizeOf, *node))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - if (NS_WARN_IF(!rootCount->report(cx, rval))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } -} - - -already_AddRefed<DominatorTree> -HeapSnapshot::ComputeDominatorTree(ErrorResult& rv) -{ - Maybe<JS::ubi::DominatorTree> maybeTree; - { - auto ccjscx = CycleCollectedJSContext::Get(); - MOZ_ASSERT(ccjscx); - auto cx = ccjscx->Context(); - MOZ_ASSERT(cx); - JS::AutoCheckCannotGC nogc(cx); - maybeTree = JS::ubi::DominatorTree::Create(cx, nogc, getRoot()); - } - - if (NS_WARN_IF(maybeTree.isNothing())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return nullptr; - } - - return MakeAndAddRef<DominatorTree>(Move(*maybeTree), this, mParent); -} - -void -HeapSnapshot::ComputeShortestPaths(JSContext*cx, uint64_t start, - const Sequence<uint64_t>& targets, - uint64_t maxNumPaths, - JS::MutableHandleObject results, - ErrorResult& rv) -{ - // First ensure that our inputs are valid. - - if (NS_WARN_IF(maxNumPaths == 0)) { - rv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - Maybe<JS::ubi::Node> startNode = getNodeById(start); - if (NS_WARN_IF(startNode.isNothing())) { - rv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - if (NS_WARN_IF(targets.Length() == 0)) { - rv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - // Aggregate the targets into a set and make sure that they exist in the heap - // snapshot. - - JS::ubi::NodeSet targetsSet; - if (NS_WARN_IF(!targetsSet.init())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - for (const auto& target : targets) { - Maybe<JS::ubi::Node> targetNode = getNodeById(target); - if (NS_WARN_IF(targetNode.isNothing())) { - rv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - if (NS_WARN_IF(!targetsSet.put(*targetNode))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - } - - // Walk the heap graph and find the shortest paths. - - Maybe<ShortestPaths> maybeShortestPaths; - { - JS::AutoCheckCannotGC nogc(cx); - maybeShortestPaths = ShortestPaths::Create(cx, nogc, maxNumPaths, *startNode, - Move(targetsSet)); - } - - if (NS_WARN_IF(maybeShortestPaths.isNothing())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - auto& shortestPaths = *maybeShortestPaths; - - // Convert the results into a Map object mapping target node IDs to arrays of - // paths found. - - RootedObject resultsMap(cx, JS::NewMapObject(cx)); - if (NS_WARN_IF(!resultsMap)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - for (auto range = shortestPaths.eachTarget(); !range.empty(); range.popFront()) { - JS::RootedValue key(cx, JS::NumberValue(range.front().identifier())); - JS::AutoValueVector paths(cx); - - bool ok = shortestPaths.forEachPath(range.front(), [&](JS::ubi::Path& path) { - JS::AutoValueVector pathValues(cx); - - for (JS::ubi::BackEdge* edge : path) { - JS::RootedObject pathPart(cx, JS_NewPlainObject(cx)); - if (!pathPart) { - return false; - } - - JS::RootedValue predecessor(cx, NumberValue(edge->predecessor().identifier())); - if (!JS_DefineProperty(cx, pathPart, "predecessor", predecessor, JSPROP_ENUMERATE)) { - return false; - } - - RootedValue edgeNameVal(cx, NullValue()); - if (edge->name()) { - RootedString edgeName(cx, JS_AtomizeUCString(cx, edge->name().get())); - if (!edgeName) { - return false; - } - edgeNameVal = StringValue(edgeName); - } - - if (!JS_DefineProperty(cx, pathPart, "edge", edgeNameVal, JSPROP_ENUMERATE)) { - return false; - } - - if (!pathValues.append(ObjectValue(*pathPart))) { - return false; - } - } - - RootedObject pathObj(cx, JS_NewArrayObject(cx, pathValues)); - return pathObj && paths.append(ObjectValue(*pathObj)); - }); - - if (NS_WARN_IF(!ok)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - JS::RootedObject pathsArray(cx, JS_NewArrayObject(cx, paths)); - if (NS_WARN_IF(!pathsArray)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - JS::RootedValue pathsVal(cx, ObjectValue(*pathsArray)); - if (NS_WARN_IF(!JS::MapSet(cx, resultsMap, key, pathsVal))) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - } - - results.set(resultsMap); -} - -/*** Saving Heap Snapshots ************************************************************************/ - -// If we are only taking a snapshot of the heap affected by the given set of -// globals, find the set of compartments the globals are allocated -// within. Returns false on OOM failure. -static bool -PopulateCompartmentsWithGlobals(CompartmentSet& compartments, AutoObjectVector& globals) -{ - if (!compartments.init()) - return false; - - unsigned length = globals.length(); - for (unsigned i = 0; i < length; i++) { - if (!compartments.put(GetObjectCompartment(globals[i]))) - return false; - } - - return true; -} - -// Add the given set of globals as explicit roots in the given roots -// list. Returns false on OOM failure. -static bool -AddGlobalsAsRoots(AutoObjectVector& globals, ubi::RootList& roots) -{ - unsigned length = globals.length(); - for (unsigned i = 0; i < length; i++) { - if (!roots.addRoot(ubi::Node(globals[i].get()), - u"heap snapshot global")) - { - return false; - } - } - return true; -} - -// Choose roots and limits for a traversal, given `boundaries`. Set `roots` to -// the set of nodes within the boundaries that are referred to by nodes -// outside. If `boundaries` does not include all JS compartments, initialize -// `compartments` to the set of included compartments; otherwise, leave -// `compartments` uninitialized. (You can use compartments.initialized() to -// check.) -// -// If `boundaries` is incoherent, or we encounter an error while trying to -// handle it, or we run out of memory, set `rv` appropriately and return -// `false`. -static bool -EstablishBoundaries(JSContext* cx, - ErrorResult& rv, - const HeapSnapshotBoundaries& boundaries, - ubi::RootList& roots, - CompartmentSet& compartments) -{ - MOZ_ASSERT(!roots.initialized()); - MOZ_ASSERT(!compartments.initialized()); - - bool foundBoundaryProperty = false; - - if (boundaries.mRuntime.WasPassed()) { - foundBoundaryProperty = true; - - if (!boundaries.mRuntime.Value()) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - - if (!roots.init()) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return false; - } - } - - if (boundaries.mDebugger.WasPassed()) { - if (foundBoundaryProperty) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - foundBoundaryProperty = true; - - JSObject* dbgObj = boundaries.mDebugger.Value(); - if (!dbgObj || !dbg::IsDebugger(*dbgObj)) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - - AutoObjectVector globals(cx); - if (!dbg::GetDebuggeeGlobals(cx, *dbgObj, globals) || - !PopulateCompartmentsWithGlobals(compartments, globals) || - !roots.init(compartments) || - !AddGlobalsAsRoots(globals, roots)) - { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return false; - } - } - - if (boundaries.mGlobals.WasPassed()) { - if (foundBoundaryProperty) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - foundBoundaryProperty = true; - - uint32_t length = boundaries.mGlobals.Value().Length(); - if (length == 0) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - - AutoObjectVector globals(cx); - for (uint32_t i = 0; i < length; i++) { - JSObject* global = boundaries.mGlobals.Value().ElementAt(i); - if (!JS_IsGlobalObject(global)) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - if (!globals.append(global)) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return false; - } - } - - if (!PopulateCompartmentsWithGlobals(compartments, globals) || - !roots.init(compartments) || - !AddGlobalsAsRoots(globals, roots)) - { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return false; - } - } - - if (!foundBoundaryProperty) { - rv.Throw(NS_ERROR_INVALID_ARG); - return false; - } - - MOZ_ASSERT(roots.initialized()); - MOZ_ASSERT_IF(boundaries.mDebugger.WasPassed(), compartments.initialized()); - MOZ_ASSERT_IF(boundaries.mGlobals.WasPassed(), compartments.initialized()); - return true; -} - - -// A variant covering all the various two-byte strings that we can get from the -// ubi::Node API. -class TwoByteString : public Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName> -{ - using Base = Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>; - - struct AsTwoByteStringMatcher - { - TwoByteString match(JSAtom* atom) { - return TwoByteString(atom); - } - - TwoByteString match(const char16_t* chars) { - return TwoByteString(chars); - } - }; - - struct IsNonNullMatcher - { - template<typename T> - bool match(const T& t) { return t != nullptr; } - }; - - struct LengthMatcher - { - size_t match(JSAtom* atom) { - MOZ_ASSERT(atom); - JS::ubi::AtomOrTwoByteChars s(atom); - return s.length(); - } - - size_t match(const char16_t* chars) { - MOZ_ASSERT(chars); - return NS_strlen(chars); - } - - size_t match(const JS::ubi::EdgeName& ptr) { - MOZ_ASSERT(ptr); - return NS_strlen(ptr.get()); - } - }; - - struct CopyToBufferMatcher - { - RangedPtr<char16_t> destination; - size_t maxLength; - - CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength) - : destination(destination) - , maxLength(maxLength) - { } - - size_t match(JS::ubi::EdgeName& ptr) { - return ptr ? match(ptr.get()) : 0; - } - - size_t match(JSAtom* atom) { - MOZ_ASSERT(atom); - JS::ubi::AtomOrTwoByteChars s(atom); - return s.copyToBuffer(destination, maxLength); - } - - size_t match(const char16_t* chars) { - MOZ_ASSERT(chars); - JS::ubi::AtomOrTwoByteChars s(chars); - return s.copyToBuffer(destination, maxLength); - } - }; - -public: - template<typename T> - MOZ_IMPLICIT TwoByteString(T&& rhs) : Base(Forward<T>(rhs)) { } - - template<typename T> - TwoByteString& operator=(T&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move disallowed"); - this->~TwoByteString(); - new (this) TwoByteString(Forward<T>(rhs)); - return *this; - } - - TwoByteString(const TwoByteString&) = delete; - TwoByteString& operator=(const TwoByteString&) = delete; - - // Rewrap the inner value of a JS::ubi::AtomOrTwoByteChars as a TwoByteString. - static TwoByteString from(JS::ubi::AtomOrTwoByteChars&& s) { - AsTwoByteStringMatcher m; - return s.match(m); - } - - // Returns true if the given TwoByteString is non-null, false otherwise. - bool isNonNull() const { - IsNonNullMatcher m; - return match(m); - } - - // Return the length of the string, 0 if it is null. - size_t length() const { - LengthMatcher m; - return match(m); - } - - // Copy the contents of a TwoByteString into the provided buffer. The buffer - // is NOT null terminated. The number of characters written is returned. - size_t copyToBuffer(RangedPtr<char16_t> destination, size_t maxLength) { - CopyToBufferMatcher m(destination, maxLength); - return match(m); - } - - struct HashPolicy; -}; - -// A hashing policy for TwoByteString. -// -// Atoms are pointer hashed and use pointer equality, which means that we -// tolerate some duplication across atoms and the other two types of two-byte -// strings. In practice, we expect the amount of this duplication to be very low -// because each type is generally a different semantic thing in addition to -// having a slightly different representation. For example, the set of edge -// names and the set stack frames' source names naturally tend not to overlap -// very much if at all. -struct TwoByteString::HashPolicy { - using Lookup = TwoByteString; - - struct HashingMatcher { - js::HashNumber match(const JSAtom* atom) { - return js::DefaultHasher<const JSAtom*>::hash(atom); - } - - js::HashNumber match(const char16_t* chars) { - MOZ_ASSERT(chars); - auto length = NS_strlen(chars); - return HashString(chars, length); - } - - js::HashNumber match(const JS::ubi::EdgeName& ptr) { - MOZ_ASSERT(ptr); - return match(ptr.get()); - } - }; - - static js::HashNumber hash(const Lookup& l) { - HashingMatcher hasher; - return l.match(hasher); - } - - struct EqualityMatcher { - const TwoByteString& rhs; - explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) { } - - bool match(const JSAtom* atom) { - return rhs.is<JSAtom*>() && rhs.as<JSAtom*>() == atom; - } - - bool match(const char16_t* chars) { - MOZ_ASSERT(chars); - - const char16_t* rhsChars = nullptr; - if (rhs.is<const char16_t*>()) - rhsChars = rhs.as<const char16_t*>(); - else if (rhs.is<JS::ubi::EdgeName>()) - rhsChars = rhs.as<JS::ubi::EdgeName>().get(); - else - return false; - MOZ_ASSERT(rhsChars); - - auto length = NS_strlen(chars); - if (NS_strlen(rhsChars) != length) - return false; - - return memcmp(chars, rhsChars, length * sizeof(char16_t)) == 0; - } - - bool match(const JS::ubi::EdgeName& ptr) { - MOZ_ASSERT(ptr); - return match(ptr.get()); - } - }; - - static bool match(const TwoByteString& k, const Lookup& l) { - EqualityMatcher eq(l); - return k.match(eq); - } - - static void rekey(TwoByteString& k, TwoByteString&& newKey) { - k = Move(newKey); - } -}; - -// Returns whether `edge` should be included in a heap snapshot of -// `compartments`. The optional `policy` out-param is set to INCLUDE_EDGES -// if we want to include the referent's edges, or EXCLUDE_EDGES if we don't -// want to include them. -static bool -ShouldIncludeEdge(JS::CompartmentSet* compartments, - const ubi::Node& origin, const ubi::Edge& edge, - CoreDumpWriter::EdgePolicy* policy = nullptr) -{ - if (policy) { - *policy = CoreDumpWriter::INCLUDE_EDGES; - } - - if (!compartments) { - // We aren't targeting a particular set of compartments, so serialize all the - // things! - return true; - } - - // We are targeting a particular set of compartments. If this node is in our target - // set, serialize it and all of its edges. If this node is _not_ in our - // target set, we also serialize under the assumption that it is a shared - // resource being used by something in our target compartments since we reached it - // by traversing the heap graph. However, we do not serialize its outgoing - // edges and we abandon further traversal from this node. - // - // If the node does not belong to any compartment, we also serialize its outgoing - // edges. This case is relevant for Shapes: they don't belong to a specific - // compartment and contain edges to parent/kids Shapes we want to include. Note - // that these Shapes may contain pointers into our target compartment (the - // Shape's getter/setter JSObjects). However, we do not serialize nodes in other - // compartments that are reachable from these non-compartment nodes. - - JSCompartment* compartment = edge.referent.compartment(); - - if (!compartment || compartments->has(compartment)) { - return true; - } - - if (policy) { - *policy = CoreDumpWriter::EXCLUDE_EDGES; - } - - return !!origin.compartment(); -} - -// A `CoreDumpWriter` that serializes nodes to protobufs and writes them to the -// given `ZeroCopyOutputStream`. -class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter -{ - using FrameSet = js::HashSet<uint64_t>; - using TwoByteStringMap = js::HashMap<TwoByteString, uint64_t, TwoByteString::HashPolicy>; - using OneByteStringMap = js::HashMap<const char*, uint64_t>; - - JSContext* cx; - bool wantNames; - // The set of |JS::ubi::StackFrame::identifier()|s that have already been - // serialized and written to the core dump. - FrameSet framesAlreadySerialized; - // The set of two-byte strings that have already been serialized and written - // to the core dump. - TwoByteStringMap twoByteStringsAlreadySerialized; - // The set of one-byte strings that have already been serialized and written - // to the core dump. - OneByteStringMap oneByteStringsAlreadySerialized; - - ::google::protobuf::io::ZeroCopyOutputStream& stream; - - JS::CompartmentSet* compartments; - - bool writeMessage(const ::google::protobuf::MessageLite& message) { - // We have to create a new CodedOutputStream when writing each message so - // that the 64MB size limit used by Coded{Output,Input}Stream to prevent - // integer overflow is enforced per message rather than on the whole stream. - ::google::protobuf::io::CodedOutputStream codedStream(&stream); - codedStream.WriteVarint32(message.ByteSize()); - message.SerializeWithCachedSizes(&codedStream); - return !codedStream.HadError(); - } - - // Attach the full two-byte string or a reference to a two-byte string that - // has already been serialized to a protobuf message. - template <typename SetStringFunction, - typename SetRefFunction> - bool attachTwoByteString(TwoByteString& string, SetStringFunction setString, - SetRefFunction setRef) { - auto ptr = twoByteStringsAlreadySerialized.lookupForAdd(string); - if (ptr) { - setRef(ptr->value()); - return true; - } - - auto length = string.length(); - auto stringData = MakeUnique<std::string>(length * sizeof(char16_t), '\0'); - if (!stringData) - return false; - - auto buf = const_cast<char16_t*>(reinterpret_cast<const char16_t*>(stringData->data())); - string.copyToBuffer(RangedPtr<char16_t>(buf, length), length); - - uint64_t ref = twoByteStringsAlreadySerialized.count(); - if (!twoByteStringsAlreadySerialized.add(ptr, Move(string), ref)) - return false; - - setString(stringData.release()); - return true; - } - - // Attach the full one-byte string or a reference to a one-byte string that - // has already been serialized to a protobuf message. - template <typename SetStringFunction, - typename SetRefFunction> - bool attachOneByteString(const char* string, SetStringFunction setString, - SetRefFunction setRef) { - auto ptr = oneByteStringsAlreadySerialized.lookupForAdd(string); - if (ptr) { - setRef(ptr->value()); - return true; - } - - auto length = strlen(string); - auto stringData = MakeUnique<std::string>(string, length); - if (!stringData) - return false; - - uint64_t ref = oneByteStringsAlreadySerialized.count(); - if (!oneByteStringsAlreadySerialized.add(ptr, string, ref)) - return false; - - setString(stringData.release()); - return true; - } - - protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame, - size_t depth = 1) { - // NB: de-duplicated string properties must be written in the same order - // here as they are read in `HeapSnapshot::saveStackFrame` or else indices - // in references to already serialized strings will be off. - - MOZ_ASSERT(frame, - "null frames should be represented as the lack of a serialized " - "stack frame"); - - auto id = frame.identifier(); - auto protobufStackFrame = MakeUnique<protobuf::StackFrame>(); - if (!protobufStackFrame) - return nullptr; - - if (framesAlreadySerialized.has(id)) { - protobufStackFrame->set_ref(id); - return protobufStackFrame.release(); - } - - auto data = MakeUnique<protobuf::StackFrame_Data>(); - if (!data) - return nullptr; - - data->set_id(id); - data->set_line(frame.line()); - data->set_column(frame.column()); - data->set_issystem(frame.isSystem()); - data->set_isselfhosted(frame.isSelfHosted(cx)); - - auto dupeSource = TwoByteString::from(frame.source()); - if (!attachTwoByteString(dupeSource, - [&] (std::string* source) { data->set_allocated_source(source); }, - [&] (uint64_t ref) { data->set_sourceref(ref); })) - { - return nullptr; - } - - auto dupeName = TwoByteString::from(frame.functionDisplayName()); - if (dupeName.isNonNull()) { - if (!attachTwoByteString(dupeName, - [&] (std::string* name) { data->set_allocated_functiondisplayname(name); }, - [&] (uint64_t ref) { data->set_functiondisplaynameref(ref); })) - { - return nullptr; - } - } - - auto parent = frame.parent(); - if (parent && depth < HeapSnapshot::MAX_STACK_DEPTH) { - auto protobufParent = getProtobufStackFrame(parent, depth + 1); - if (!protobufParent) - return nullptr; - data->set_allocated_parent(protobufParent); - } - - protobufStackFrame->set_allocated_data(data.release()); - - if (!framesAlreadySerialized.put(id)) - return nullptr; - - return protobufStackFrame.release(); - } - -public: - StreamWriter(JSContext* cx, - ::google::protobuf::io::ZeroCopyOutputStream& stream, - bool wantNames, - JS::CompartmentSet* compartments) - : cx(cx) - , wantNames(wantNames) - , framesAlreadySerialized(cx) - , twoByteStringsAlreadySerialized(cx) - , oneByteStringsAlreadySerialized(cx) - , stream(stream) - , compartments(compartments) - { } - - bool init() { - return framesAlreadySerialized.init() && - twoByteStringsAlreadySerialized.init() && - oneByteStringsAlreadySerialized.init(); - } - - ~StreamWriter() override { } - - virtual bool writeMetadata(uint64_t timestamp) final { - protobuf::Metadata metadata; - metadata.set_timestamp(timestamp); - return writeMessage(metadata); - } - - virtual bool writeNode(const JS::ubi::Node& ubiNode, - EdgePolicy includeEdges) override final { - // NB: de-duplicated string properties must be written in the same order - // here as they are read in `HeapSnapshot::saveNode` or else indices in - // references to already serialized strings will be off. - - protobuf::Node protobufNode; - protobufNode.set_id(ubiNode.identifier()); - - protobufNode.set_coarsetype(JS::ubi::CoarseTypeToUint32(ubiNode.coarseType())); - - auto typeName = TwoByteString(ubiNode.typeName()); - if (NS_WARN_IF(!attachTwoByteString(typeName, - [&] (std::string* name) { protobufNode.set_allocated_typename_(name); }, - [&] (uint64_t ref) { protobufNode.set_typenameref(ref); }))) - { - return false; - } - - mozilla::MallocSizeOf mallocSizeOf = dbg::GetDebuggerMallocSizeOf(cx); - MOZ_ASSERT(mallocSizeOf); - protobufNode.set_size(ubiNode.size(mallocSizeOf)); - - if (includeEdges) { - auto edges = ubiNode.edges(cx, wantNames); - if (NS_WARN_IF(!edges)) - return false; - - for ( ; !edges->empty(); edges->popFront()) { - ubi::Edge& ubiEdge = edges->front(); - if (!ShouldIncludeEdge(compartments, ubiNode, ubiEdge)) { - continue; - } - - protobuf::Edge* protobufEdge = protobufNode.add_edges(); - if (NS_WARN_IF(!protobufEdge)) { - return false; - } - - protobufEdge->set_referent(ubiEdge.referent.identifier()); - - if (wantNames && ubiEdge.name) { - TwoByteString edgeName(Move(ubiEdge.name)); - if (NS_WARN_IF(!attachTwoByteString(edgeName, - [&] (std::string* name) { protobufEdge->set_allocated_name(name); }, - [&] (uint64_t ref) { protobufEdge->set_nameref(ref); }))) - { - return false; - } - } - } - } - - if (ubiNode.hasAllocationStack()) { - auto ubiStackFrame = ubiNode.allocationStack(); - auto protoStackFrame = getProtobufStackFrame(ubiStackFrame); - if (NS_WARN_IF(!protoStackFrame)) - return false; - protobufNode.set_allocated_allocationstack(protoStackFrame); - } - - if (auto className = ubiNode.jsObjectClassName()) { - if (NS_WARN_IF(!attachOneByteString(className, - [&] (std::string* name) { protobufNode.set_allocated_jsobjectclassname(name); }, - [&] (uint64_t ref) { protobufNode.set_jsobjectclassnameref(ref); }))) - { - return false; - } - } - - if (auto scriptFilename = ubiNode.scriptFilename()) { - if (NS_WARN_IF(!attachOneByteString(scriptFilename, - [&] (std::string* name) { protobufNode.set_allocated_scriptfilename(name); }, - [&] (uint64_t ref) { protobufNode.set_scriptfilenameref(ref); }))) - { - return false; - } - } - - return writeMessage(protobufNode); - } -}; - -// A JS::ubi::BreadthFirst handler that serializes a snapshot of the heap into a -// core dump. -class MOZ_STACK_CLASS HeapSnapshotHandler -{ - CoreDumpWriter& writer; - JS::CompartmentSet* compartments; - -public: - HeapSnapshotHandler(CoreDumpWriter& writer, - JS::CompartmentSet* compartments) - : writer(writer), - compartments(compartments) - { } - - // JS::ubi::BreadthFirst handler interface. - - class NodeData { }; - typedef JS::ubi::BreadthFirst<HeapSnapshotHandler> Traversal; - bool operator() (Traversal& traversal, - JS::ubi::Node origin, - const JS::ubi::Edge& edge, - NodeData*, - bool first) - { - // We're only interested in the first time we reach edge.referent, not in - // every edge arriving at that node. "But, don't we want to serialize every - // edge in the heap graph?" you ask. Don't worry! This edge is still - // serialized into the core dump. Serializing a node also serializes each of - // its edges, and if we are traversing a given edge, we must have already - // visited and serialized the origin node and its edges. - if (!first) - return true; - - CoreDumpWriter::EdgePolicy policy; - if (!ShouldIncludeEdge(compartments, origin, edge, &policy)) - return true; - - if (policy == CoreDumpWriter::EXCLUDE_EDGES) - traversal.abandonReferent(); - - return writer.writeNode(edge.referent, policy); - } -}; - - -bool -WriteHeapGraph(JSContext* cx, - const JS::ubi::Node& node, - CoreDumpWriter& writer, - bool wantNames, - JS::CompartmentSet* compartments, - JS::AutoCheckCannotGC& noGC) -{ - // Serialize the starting node to the core dump. - - if (NS_WARN_IF(!writer.writeNode(node, CoreDumpWriter::INCLUDE_EDGES))) { - return false; - } - - // Walk the heap graph starting from the given node and serialize it into the - // core dump. - - HeapSnapshotHandler handler(writer, compartments); - HeapSnapshotHandler::Traversal traversal(cx, handler, noGC); - if (!traversal.init()) - return false; - traversal.wantNames = wantNames; - - bool ok = traversal.addStartVisited(node) && - traversal.traverse(); - - return ok; -} - -static unsigned long -msSinceProcessCreation(const TimeStamp& now) -{ - bool ignored; - auto duration = now - TimeStamp::ProcessCreation(ignored); - return (unsigned long) duration.ToMilliseconds(); -} - -/* static */ already_AddRefed<nsIFile> -HeapSnapshot::CreateUniqueCoreDumpFile(ErrorResult& rv, - const TimeStamp& now, - nsAString& outFilePath) -{ - nsCOMPtr<nsIFile> file; - rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file)); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - auto ms = msSinceProcessCreation(now); - rv = file->AppendNative(nsPrintfCString("%lu.fxsnapshot", ms)); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - rv = file->GetPath(outFilePath); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - return file.forget(); -} - -// Deletion policy for cleaning up PHeapSnapshotTempFileHelperChild pointers. -class DeleteHeapSnapshotTempFileHelperChild -{ -public: - constexpr DeleteHeapSnapshotTempFileHelperChild() { } - - void operator()(PHeapSnapshotTempFileHelperChild* ptr) const { - Unused << NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr)); - } -}; - -// A UniquePtr alias to automatically manage PHeapSnapshotTempFileHelperChild -// pointers. -using UniqueHeapSnapshotTempFileHelperChild = UniquePtr<PHeapSnapshotTempFileHelperChild, - DeleteHeapSnapshotTempFileHelperChild>; - -// Get an nsIOutputStream that we can write the heap snapshot to. In non-e10s -// and in the e10s parent process, open a file directly and create an output -// stream for it. In e10s child processes, we are sandboxed without access to -// the filesystem. Use IPDL to request a file descriptor from the parent -// process. -static already_AddRefed<nsIOutputStream> -getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePath) -{ - if (XRE_IsParentProcess()) { - // Create the file and open the output stream directly. - - nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv, - start, - outFilePath); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - nsCOMPtr<nsIOutputStream> outputStream; - rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file, - PR_WRONLY, -1, 0); - if (NS_WARN_IF(rv.Failed())) - return nullptr; - - return outputStream.forget(); - } else { - // Request a file descriptor from the parent process over IPDL. - - auto cc = ContentChild::GetSingleton(); - if (!cc) { - rv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - UniqueHeapSnapshotTempFileHelperChild helper( - cc->SendPHeapSnapshotTempFileHelperConstructor()); - if (NS_WARN_IF(!helper)) { - rv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - OpenHeapSnapshotTempFileResponse response; - if (!helper->SendOpenHeapSnapshotTempFile(&response)) { - rv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - if (response.type() == OpenHeapSnapshotTempFileResponse::Tnsresult) { - rv.Throw(response.get_nsresult()); - return nullptr; - } - - auto opened = response.get_OpenedFile(); - outFilePath = opened.path(); - nsCOMPtr<nsIOutputStream> outputStream = - FileDescriptorOutputStream::Create(opened.descriptor()); - if (NS_WARN_IF(!outputStream)) { - rv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - return outputStream.forget(); - } -} - -} // namespace devtools - -namespace dom { - -using namespace JS; -using namespace devtools; - -/* static */ void -ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global, - const HeapSnapshotBoundaries& boundaries, - nsAString& outFilePath, - ErrorResult& rv) -{ - auto start = TimeStamp::Now(); - - bool wantNames = true; - CompartmentSet compartments; - - nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start, outFilePath); - if (NS_WARN_IF(rv.Failed())) - return; - - ZeroCopyNSIOutputStream zeroCopyStream(outputStream); - ::google::protobuf::io::GzipOutputStream gzipStream(&zeroCopyStream); - - JSContext* cx = global.Context(); - - { - Maybe<AutoCheckCannotGC> maybeNoGC; - ubi::RootList rootList(cx, maybeNoGC, wantNames); - if (!EstablishBoundaries(cx, rv, boundaries, rootList, compartments)) - return; - - StreamWriter writer(cx, gzipStream, wantNames, - compartments.initialized() ? &compartments : nullptr); - if (NS_WARN_IF(!writer.init())) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - MOZ_ASSERT(maybeNoGC.isSome()); - ubi::Node roots(&rootList); - - // Serialize the initial heap snapshot metadata to the core dump. - if (!writer.writeMetadata(PR_Now()) || - // Serialize the heap graph to the core dump, starting from our list of - // roots. - !WriteHeapGraph(cx, - roots, - writer, - wantNames, - compartments.initialized() ? &compartments : nullptr, - maybeNoGC.ref())) - { - rv.Throw(zeroCopyStream.failed() - ? zeroCopyStream.result() - : NS_ERROR_UNEXPECTED); - return; - } - } -} - -/* static */ already_AddRefed<HeapSnapshot> -ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global, - const nsAString& filePath, - ErrorResult& rv) -{ - UniquePtr<char[]> path(ToNewCString(filePath)); - if (!path) { - rv.Throw(NS_ERROR_OUT_OF_MEMORY); - return nullptr; - } - - AutoMemMap mm; - rv = mm.init(path.get()); - if (rv.Failed()) - return nullptr; - - RefPtr<HeapSnapshot> snapshot = HeapSnapshot::Create( - global.Context(), global, reinterpret_cast<const uint8_t*>(mm.address()), - mm.size(), rv); - - return snapshot.forget(); -} - -} // namespace dom -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.h b/devtools/shared/heapsnapshot/HeapSnapshot.h deleted file mode 100644 index 12dfa4c2b..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshot.h +++ /dev/null @@ -1,224 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_HeapSnapshot__ -#define mozilla_devtools_HeapSnapshot__ - -#include "js/HashTable.h" -#include "mozilla/ErrorResult.h" -#include "mozilla/devtools/DeserializedNode.h" -#include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/dom/Nullable.h" -#include "mozilla/HashFunctions.h" -#include "mozilla/Maybe.h" -#include "mozilla/RefCounted.h" -#include "mozilla/RefPtr.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/UniquePtr.h" - -#include "CoreDump.pb.h" -#include "nsCOMPtr.h" -#include "nsCRTGlue.h" -#include "nsCycleCollectionParticipant.h" -#include "nsISupports.h" -#include "nsWrapperCache.h" -#include "nsXPCOM.h" - -namespace mozilla { -namespace devtools { - -class DominatorTree; - -struct NSFreePolicy { - void operator()(void* ptr) { - NS_Free(ptr); - } -}; - -using UniqueTwoByteString = UniquePtr<char16_t[], NSFreePolicy>; -using UniqueOneByteString = UniquePtr<char[], NSFreePolicy>; - -class HeapSnapshot final : public nsISupports - , public nsWrapperCache -{ - friend struct DeserializedNode; - friend struct DeserializedEdge; - friend struct DeserializedStackFrame; - friend class JS::ubi::Concrete<JS::ubi::DeserializedNode>; - - explicit HeapSnapshot(JSContext* cx, nsISupports* aParent) - : timestamp(Nothing()) - , rootId(0) - , nodes(cx) - , frames(cx) - , mParent(aParent) - { - MOZ_ASSERT(aParent); - }; - - // Initialize this HeapSnapshot from the given buffer that contains a - // serialized core dump. Do NOT take ownership of the buffer, only borrow it - // for the duration of the call. Return false on failure. - bool init(JSContext* cx, const uint8_t* buffer, uint32_t size); - - using NodeIdSet = js::HashSet<NodeId>; - - // Save the given `protobuf::Node` message in this `HeapSnapshot` as a - // `DeserializedNode`. - bool saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents); - - // Save the given `protobuf::StackFrame` message in this `HeapSnapshot` as a - // `DeserializedStackFrame`. The saved stack frame's id is returned via the - // out parameter. - bool saveStackFrame(const protobuf::StackFrame& frame, - StackFrameId& outFrameId); - -public: - // The maximum number of stack frames that we will serialize into a core - // dump. This helps prevent over-recursion in the protobuf library when - // deserializing stacks. - static const size_t MAX_STACK_DEPTH = 60; - -private: - // If present, a timestamp in the same units that `PR_Now` gives. - Maybe<uint64_t> timestamp; - - // The id of the root node for this deserialized heap graph. - NodeId rootId; - - // The set of nodes in this deserialized heap graph, keyed by id. - using NodeSet = js::HashSet<DeserializedNode, DeserializedNode::HashPolicy>; - NodeSet nodes; - - // The set of stack frames in this deserialized heap graph, keyed by id. - using FrameSet = js::HashSet<DeserializedStackFrame, - DeserializedStackFrame::HashPolicy>; - FrameSet frames; - - Vector<UniqueTwoByteString> internedTwoByteStrings; - Vector<UniqueOneByteString> internedOneByteStrings; - - using StringOrRef = Variant<const std::string*, uint64_t>; - - template<typename CharT, - typename InternedStringSet> - const CharT* getOrInternString(InternedStringSet& internedStrings, - Maybe<StringOrRef>& maybeStrOrRef); - -protected: - nsCOMPtr<nsISupports> mParent; - - virtual ~HeapSnapshot() { } - -public: - // Create a `HeapSnapshot` from the given buffer that contains a serialized - // core dump. Do NOT take ownership of the buffer, only borrow it for the - // duration of the call. - static already_AddRefed<HeapSnapshot> Create(JSContext* cx, - dom::GlobalObject& global, - const uint8_t* buffer, - uint32_t size, - ErrorResult& rv); - - // Creates the `$TEMP_DIR/XXXXXX-XXX.fxsnapshot` core dump file that heap - // snapshots are serialized into. - static already_AddRefed<nsIFile> CreateUniqueCoreDumpFile(ErrorResult& rv, - const TimeStamp& now, - nsAString& outFilePath); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HeapSnapshot) - MOZ_DECLARE_REFCOUNTED_TYPENAME(HeapSnapshot) - - nsISupports* GetParentObject() const { return mParent; } - - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) override; - - const char16_t* borrowUniqueString(const char16_t* duplicateString, - size_t length); - - // Get the root node of this heap snapshot's graph. - JS::ubi::Node getRoot() { - MOZ_ASSERT(nodes.initialized()); - auto p = nodes.lookup(rootId); - MOZ_ASSERT(p); - const DeserializedNode& node = *p; - return JS::ubi::Node(const_cast<DeserializedNode*>(&node)); - } - - Maybe<JS::ubi::Node> getNodeById(JS::ubi::Node::Id nodeId) { - auto p = nodes.lookup(nodeId); - if (!p) - return Nothing(); - return Some(JS::ubi::Node(const_cast<DeserializedNode*>(&*p))); - } - - void TakeCensus(JSContext* cx, JS::HandleObject options, - JS::MutableHandleValue rval, ErrorResult& rv); - - void DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId, - JS::MutableHandleValue rval, ErrorResult& rv); - - already_AddRefed<DominatorTree> ComputeDominatorTree(ErrorResult& rv); - - void ComputeShortestPaths(JSContext*cx, uint64_t start, - const dom::Sequence<uint64_t>& targets, - uint64_t maxNumPaths, - JS::MutableHandleObject results, - ErrorResult& rv); - - dom::Nullable<uint64_t> GetCreationTime() { - static const uint64_t maxTime = uint64_t(1) << 53; - if (timestamp.isSome() && timestamp.ref() <= maxTime) { - return dom::Nullable<uint64_t>(timestamp.ref()); - } - - return dom::Nullable<uint64_t>(); - } -}; - -// A `CoreDumpWriter` is given the data we wish to save in a core dump and -// serializes it to disk, or memory, or a socket, etc. -class CoreDumpWriter -{ -public: - virtual ~CoreDumpWriter() { }; - - // Write the given bits of metadata we would like to associate with this core - // dump. - virtual bool writeMetadata(uint64_t timestamp) = 0; - - enum EdgePolicy : bool { - INCLUDE_EDGES = true, - EXCLUDE_EDGES = false - }; - - // Write the given `JS::ubi::Node` to the core dump. The given `EdgePolicy` - // dictates whether its outgoing edges should also be written to the core - // dump, or excluded. - virtual bool writeNode(const JS::ubi::Node& node, - EdgePolicy includeEdges) = 0; -}; - -// Serialize the heap graph as seen from `node` with the given `CoreDumpWriter`. -// If `wantNames` is true, capture edge names. If `zones` is non-null, only -// capture the sub-graph within the zone set, otherwise capture the whole heap -// graph. Returns false on failure. -bool -WriteHeapGraph(JSContext* cx, - const JS::ubi::Node& node, - CoreDumpWriter& writer, - bool wantNames, - JS::CompartmentSet* compartments, - JS::AutoCheckCannotGC& noGC); - -// Get the mozilla::MallocSizeOf for the current thread's JSRuntime. -MallocSizeOf GetCurrentThreadDebuggerMallocSizeOf(); - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_HeapSnapshot__ diff --git a/devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js b/devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js deleted file mode 100644 index abd44fc30..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js +++ /dev/null @@ -1,95 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Heap snapshots are always saved in the temp directory, and have a regular -// naming convention. This module provides helpers for working with heap -// snapshot files in a safe manner. Because we attempt to avoid unnecessary -// copies of the heap snapshot files by checking the local filesystem for a heap -// snapshot file with the given snapshot id, we want to ensure that we are only -// attempting to open heap snapshot files and not `~/.ssh/id_rsa`, for -// example. Therefore, the RDP only talks about snapshot ids, or transfering the -// bulk file data. A file path can be recovered from a snapshot id, which allows -// one to check for the presence of the heap snapshot file on the local file -// system, but we don't have to worry about opening arbitrary files. -// -// The heap snapshot file path conventions permits the following forms: -// -// $TEMP_DIRECTORY/XXXXXXXXXX.fxsnapshot -// $TEMP_DIRECTORY/XXXXXXXXXX-XXXXX.fxsnapshot -// -// Where the strings of "X" are zero or more digits. - -"use strict"; - -const { Ci } = require("chrome"); -loader.lazyRequireGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm", true); -loader.lazyRequireGetter(this, "OS", "resource://gre/modules/osfile.jsm", true); - -function getHeapSnapshotFileTemplate() { - return OS.Path.join(OS.Constants.Path.tmpDir, `${Date.now()}.fxsnapshot`); -} - -/** - * Get a unique temp file path for a new heap snapshot. The file is guaranteed - * not to exist before this call. - * - * @returns String - */ -exports.getNewUniqueHeapSnapshotTempFilePath = function () { - let file = new FileUtils.File(getHeapSnapshotFileTemplate()); - // The call to createUnique will append "-N" after the leaf name (but before - // the extension) until a new file is found and create it. This guarantees we - // won't accidentally choose the same file twice. - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); - return file.path; -}; - -function isValidSnapshotFileId(snapshotId) { - return /^\d+(\-\d+)?$/.test(snapshotId); -} - -/** - * Get the file path for the given snapshot id. - * - * @param {String} snapshotId - * - * @returns String | null - */ -exports.getHeapSnapshotTempFilePath = function (snapshotId) { - // Don't want anyone sneaking "../../../.." strings into the snapshot id and - // trying to make us open arbitrary files. - if (!isValidSnapshotFileId(snapshotId)) { - return null; - } - return OS.Path.join(OS.Constants.Path.tmpDir, snapshotId + ".fxsnapshot"); -}; - -/** - * Return true if we have the heap snapshot file for the given snapshot id on - * the local file system. False is returned otherwise. - * - * @returns Promise<Boolean> - */ -exports.haveHeapSnapshotTempFile = function (snapshotId) { - const path = exports.getHeapSnapshotTempFilePath(snapshotId); - if (!path) { - return Promise.resolve(false); - } - - return OS.File.stat(path).then(() => true, - () => false); -}; - -/** - * Given a heap snapshot's file path, extricate the snapshot id. - * - * @param {String} path - * - * @returns String - */ -exports.getSnapshotIdFromPath = function (path) { - return path.slice(OS.Constants.Path.tmpDir.length + 1, - path.length - ".fxsnapshot".length); -}; diff --git a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperChild.h b/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperChild.h deleted file mode 100644 index a1d433a5e..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperChild.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_HeapSnapshotTempFileHelperChild_h -#define mozilla_devtools_HeapSnapshotTempFileHelperChild_h - -#include "mozilla/devtools/PHeapSnapshotTempFileHelperChild.h" - -namespace mozilla { -namespace devtools { - -class HeapSnapshotTempFileHelperChild : public PHeapSnapshotTempFileHelperChild -{ - explicit HeapSnapshotTempFileHelperChild() { } - -public: - static inline PHeapSnapshotTempFileHelperChild* Create(); -}; - -/* static */ inline PHeapSnapshotTempFileHelperChild* -HeapSnapshotTempFileHelperChild::Create() -{ - return new HeapSnapshotTempFileHelperChild(); -} - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_HeapSnapshotTempFileHelperChild_h diff --git a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp b/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp deleted file mode 100644 index 7246a9daa..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/HeapSnapshot.h" -#include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h" -#include "mozilla/ErrorResult.h" -#include "private/pprio.h" - -#include "nsIFile.h" - -namespace mozilla { -namespace devtools { - -using ipc::FileDescriptor; - -static bool -openFileFailure(ErrorResult& rv, - OpenHeapSnapshotTempFileResponse* outResponse) -{ - *outResponse = rv.StealNSResult(); - return true; -} - -bool -HeapSnapshotTempFileHelperParent::RecvOpenHeapSnapshotTempFile( - OpenHeapSnapshotTempFileResponse* outResponse) -{ - auto start = TimeStamp::Now(); - ErrorResult rv; - nsAutoString filePath; - nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv, - start, - filePath); - if (NS_WARN_IF(rv.Failed())) - return openFileFailure(rv, outResponse); - - PRFileDesc* prfd; - rv = file->OpenNSPRFileDesc(PR_WRONLY, 0, &prfd); - if (NS_WARN_IF(rv.Failed())) - return openFileFailure(rv, outResponse); - - FileDescriptor::PlatformHandleType handle = - FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd)); - FileDescriptor fd(handle); - *outResponse = OpenedFile(filePath, fd); - return true; -} - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.h b/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.h deleted file mode 100644 index 1582279da..000000000 --- a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_HeapSnapshotTempFileHelperParent_h -#define mozilla_devtools_HeapSnapshotTempFileHelperParent_h - -#include "mozilla/devtools/PHeapSnapshotTempFileHelperParent.h" - -namespace mozilla { -namespace devtools { - -class HeapSnapshotTempFileHelperParent : public PHeapSnapshotTempFileHelperParent -{ - explicit HeapSnapshotTempFileHelperParent() { } - void ActorDestroy(ActorDestroyReason why) override { } - bool RecvOpenHeapSnapshotTempFile(OpenHeapSnapshotTempFileResponse* outResponse) - override; - - public: - static inline PHeapSnapshotTempFileHelperParent* Create(); -}; - -/* static */ inline PHeapSnapshotTempFileHelperParent* -HeapSnapshotTempFileHelperParent::Create() -{ - return new HeapSnapshotTempFileHelperParent(); -} - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_HeapSnapshotTempFileHelperParent_h diff --git a/devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl b/devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl deleted file mode 100644 index 2576470e2..000000000 --- a/devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -include protocol PContent; - -namespace mozilla { -namespace devtools { - -struct OpenedFile -{ - nsString path; - FileDescriptor descriptor; -}; - -union OpenHeapSnapshotTempFileResponse -{ - nsresult; - OpenedFile; -}; - -sync protocol PHeapSnapshotTempFileHelper -{ - manager PContent; - -parent: - sync OpenHeapSnapshotTempFile() returns (OpenHeapSnapshotTempFileResponse response); - - async __delete__(); -}; - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp b/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp deleted file mode 100644 index 0c29db7f9..000000000 --- a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/devtools/ZeroCopyNSIOutputStream.h" - -#include "mozilla/DebugOnly.h" -#include "mozilla/Unused.h" - -namespace mozilla { -namespace devtools { - -ZeroCopyNSIOutputStream::ZeroCopyNSIOutputStream(nsCOMPtr<nsIOutputStream>& out) - : out(out) - , result_(NS_OK) - , amountUsed(0) - , writtenCount(0) -{ - DebugOnly<bool> nonBlocking = false; - MOZ_ASSERT(out->IsNonBlocking(&nonBlocking) == NS_OK); - MOZ_ASSERT(!nonBlocking); -} - -ZeroCopyNSIOutputStream::~ZeroCopyNSIOutputStream() -{ - if (!failed()) - Unused << NS_WARN_IF(NS_FAILED(writeBuffer())); -} - -nsresult -ZeroCopyNSIOutputStream::writeBuffer() -{ - if (failed()) - return result_; - - if (amountUsed == 0) - return NS_OK; - - int32_t amountWritten = 0; - while (amountWritten < amountUsed) { - uint32_t justWritten = 0; - - result_ = out->Write(buffer + amountWritten, - amountUsed - amountWritten, - &justWritten); - if (NS_WARN_IF(NS_FAILED(result_))) - return result_; - - amountWritten += justWritten; - } - - writtenCount += amountUsed; - amountUsed = 0; - return NS_OK; -} - -// ZeroCopyOutputStream Interface - -bool -ZeroCopyNSIOutputStream::Next(void** data, int* size) -{ - MOZ_ASSERT(data != nullptr); - MOZ_ASSERT(size != nullptr); - - if (failed()) - return false; - - if (amountUsed == BUFFER_SIZE) { - if (NS_FAILED(writeBuffer())) - return false; - } - - *data = buffer + amountUsed; - *size = BUFFER_SIZE - amountUsed; - amountUsed = BUFFER_SIZE; - return true; -} - -void -ZeroCopyNSIOutputStream::BackUp(int count) -{ - MOZ_ASSERT(count >= 0, - "Cannot back up a negative amount of bytes."); - MOZ_ASSERT(amountUsed == BUFFER_SIZE, - "Can only call BackUp directly after calling Next."); - MOZ_ASSERT(count <= amountUsed, - "Can't back up further than we've given out."); - - amountUsed -= count; -} - -::google::protobuf::int64 -ZeroCopyNSIOutputStream::ByteCount() const -{ - return writtenCount + amountUsed; -} - -} // namespace devtools -} // namespace mozilla diff --git a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.h b/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.h deleted file mode 100644 index 117fc0f87..000000000 --- a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_ZeroCopyNSIOutputStream__ -#define mozilla_devtools_ZeroCopyNSIOutputStream__ - -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/stubs/common.h> - -#include "nsCOMPtr.h" -#include "nsIOutputStream.h" - -namespace mozilla { -namespace devtools { - -// A `google::protobuf::io::ZeroCopyOutputStream` implementation that uses an -// `nsIOutputStream` under the covers. -// -// This class will automatically write and flush its data to the -// `nsIOutputStream` in its destructor, but if you care whether that call -// succeeds or fails, then you should call the `flush` method yourself. Errors -// will be logged, however. -class MOZ_STACK_CLASS ZeroCopyNSIOutputStream - : public ::google::protobuf::io::ZeroCopyOutputStream -{ - static const int BUFFER_SIZE = 8192; - - // The nsIOutputStream we are streaming to. - nsCOMPtr<nsIOutputStream>& out; - - // The buffer we write data to before passing it to the output stream. - char buffer[BUFFER_SIZE]; - - // The status of writing to the underlying output stream. - nsresult result_; - - // The number of bytes in the buffer that have been used thus far. - int amountUsed; - - // Excluding the amount of the buffer currently used (which hasn't been - // written and flushed yet), this is the number of bytes written to the output - // stream. - int64_t writtenCount; - - // Write the internal buffer to the output stream and flush it. - nsresult writeBuffer(); - -public: - explicit ZeroCopyNSIOutputStream(nsCOMPtr<nsIOutputStream>& out); - - nsresult flush() { return writeBuffer(); } - - // Return true if writing to the underlying output stream ever failed. - bool failed() const { return NS_FAILED(result_); } - - nsresult result() const { return result_; } - - // ZeroCopyOutputStream Interface - virtual ~ZeroCopyNSIOutputStream() override; - virtual bool Next(void** data, int* size) override; - virtual void BackUp(int count) override; - virtual ::google::protobuf::int64 ByteCount() const override; -}; - -} // namespace devtools -} // namespace mozilla - -#endif // mozilla_devtools_ZeroCopyNSIOutputStream__ diff --git a/devtools/shared/heapsnapshot/census-tree-node.js b/devtools/shared/heapsnapshot/census-tree-node.js deleted file mode 100644 index b041e77f9..000000000 --- a/devtools/shared/heapsnapshot/census-tree-node.js +++ /dev/null @@ -1,748 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -// CensusTreeNode is an intermediate representation of a census report that -// exists between after a report is generated by taking a census and before the -// report is rendered in the DOM. It must be dead simple to render, with no -// further data processing or massaging needed before rendering DOM nodes. Our -// goal is to do the census report to CensusTreeNode transformation in the -// HeapAnalysesWorker, and ensure that the **only** work that the main thread -// has to do is strictly DOM rendering work. - -const { - Visitor, - walk, - basisTotalBytes, - basisTotalCount, -} = require("resource://devtools/shared/heapsnapshot/CensusUtils.js"); - -// Monotonically increasing integer for CensusTreeNode `id`s. -let censusTreeNodeIdCounter = 0; - -/** - * Return true if the given object is a SavedFrame stack object, false otherwise. - * - * @param {any} obj - * @returns {Boolean} - */ -function isSavedFrame(obj) { - return Object.prototype.toString.call(obj) === "[object SavedFrame]"; -} - -/** - * A CensusTreeNodeCache maps from SavedFrames to CensusTreeNodes. It is used when - * aggregating multiple SavedFrame allocation stack keys into a tree of many - * CensusTreeNodes. Each stack may share older frames, and we want to preserve - * this sharing when converting to CensusTreeNode, so before creating a new - * CensusTreeNode, we look for an existing one in one of our CensusTreeNodeCaches. - */ -function CensusTreeNodeCache() {} -CensusTreeNodeCache.prototype = null; - -/** - * The value of a single entry stored in a CensusTreeNodeCache. It is a pair of - * the CensusTreeNode for this cache value, and the subsequent - * CensusTreeNodeCache for this node's children. - * - * @param {SavedFrame} frame - * The frame being cached. - */ -function CensusTreeNodeCacheValue() { - // The CensusTreeNode for this cache value. - this.node = undefined; - // The CensusTreeNodeCache for this frame's children. - this.children = undefined; -} - -CensusTreeNodeCacheValue.prototype = null; - -/** - * Create a unique string for the given SavedFrame (ignoring the frame's parent - * chain) that can be used as a hash to key this frame within a CensusTreeNodeCache. - * - * NB: We manually hash rather than using an ES6 Map because we are purposely - * ignoring the parent chain and wish to consider frames with everything the - * same except their parents as the same. - * - * @param {SavedFrame} frame - * The SavedFrame object we would like to lookup in or insert into a - * CensusTreeNodeCache. - * - * @returns {String} - * The unique string that can be used as a key in a CensusTreeNodeCache. - */ -CensusTreeNodeCache.hashFrame = function (frame) { - return `FRAME,${frame.functionDisplayName},${frame.source},${frame.line},${frame.column},${frame.asyncCause}`; -}; - -/** - * Create a unique string for the given CensusTreeNode **with regards to - * siblings at the current depth of the tree, not within the whole tree.** It - * can be used as a hash to key this node within a CensusTreeNodeCache. - * - * @param {CensusTreeNode} node - * The node we would like to lookup in or insert into a cache. - * - * @returns {String} - * The unique string that can be used as a key in a CensusTreeNodeCache. - */ -CensusTreeNodeCache.hashNode = function (node) { - return isSavedFrame(node.name) - ? CensusTreeNodeCache.hashFrame(node.name) - : `NODE,${node.name}`; -}; - -/** - * Insert the given CensusTreeNodeCacheValue whose node.name is a SavedFrame - * object in the given cache. - * - * @param {CensusTreeNodeCache} cache - * @param {CensusTreeNodeCacheValue} value - */ -CensusTreeNodeCache.insertFrame = function (cache, value) { - cache[CensusTreeNodeCache.hashFrame(value.node.name)] = value; -}; - -/** - * Insert the given value in the cache. - * - * @param {CensusTreeNodeCache} cache - * @param {CensusTreeNodeCacheValue} value - */ -CensusTreeNodeCache.insertNode = function (cache, value) { - if (isSavedFrame(value.node.name)) { - CensusTreeNodeCache.insertFrame(cache, value); - } else { - cache[CensusTreeNodeCache.hashNode(value.node)] = value; - } -}; - -/** - * Lookup `frame` in `cache` and return its value if it exists. - * - * @param {CensusTreeNodeCache} cache - * @param {SavedFrame} frame - * - * @returns {undefined|CensusTreeNodeCacheValue} - */ -CensusTreeNodeCache.lookupFrame = function (cache, frame) { - return cache[CensusTreeNodeCache.hashFrame(frame)]; -}; - -/** - * Lookup `node` in `cache` and return its value if it exists. - * - * @param {CensusTreeNodeCache} cache - * @param {CensusTreeNode} node - * - * @returns {undefined|CensusTreeNodeCacheValue} - */ -CensusTreeNodeCache.lookupNode = function (cache, node) { - return isSavedFrame(node.name) - ? CensusTreeNodeCache.lookupFrame(cache, node.name) - : cache[CensusTreeNodeCache.hashNode(node)]; -}; - -/** - * Add `child` to `parent`'s set of children and store the parent ID - * on the child. - * - * @param {CensusTreeNode} parent - * @param {CensusTreeNode} child - */ -function addChild(parent, child) { - if (!parent.children) { - parent.children = []; - } - child.parent = parent.id; - parent.children.push(child); -} - -/** - * Get an array of each frame in the provided stack. - * - * @param {SavedFrame} stack - * @returns {Array<SavedFrame>} - */ -function getArrayOfFrames(stack) { - const frames = []; - let frame = stack; - while (frame) { - frames.push(frame); - frame = frame.parent; - } - frames.reverse(); - return frames; -} - -/** - * Given an `edge` to a sub-`report` whose structure is described by - * `breakdown`, create a CensusTreeNode tree. - * - * @param {Object} breakdown - * The breakdown specifying the structure of the given report. - * - * @param {Object} report - * The census report. - * - * @param {null|String|SavedFrame} edge - * The edge leading to this report from the parent report. - * - * @param {CensusTreeNodeCache} cache - * The cache of CensusTreeNodes we have already made for the siblings of - * the node being created. The existing nodes are reused when possible. - * - * @param {Object} outParams - * The return values are attached to this object after this function - * returns. Because we create a CensusTreeNode for each frame in a - * SavedFrame stack edge, there may multiple nodes per sub-report. - * - * - top: The deepest node in the CensusTreeNode subtree created. - * - * - bottom: The shallowest node in the CensusTreeNode subtree created. - * This is null if the shallowest node in the subtree was - * found in the `cache` and reused. - * - * Note that top and bottom are not necessarily different. In the case - * where there is a 1:1 correspondence between an edge in the report and - * a CensusTreeNode, top and bottom refer to the same node. - */ -function makeCensusTreeNodeSubTree(breakdown, report, edge, cache, outParams) { - if (!isSavedFrame(edge)) { - const node = new CensusTreeNode(edge); - outParams.top = outParams.bottom = node; - return; - } - - const frames = getArrayOfFrames(edge); - let currentCache = cache; - let prevNode; - for (let i = 0, length = frames.length; i < length; i++) { - const frame = frames[i]; - - // Get or create the CensusTreeNodeCacheValue for this frame. If we already - // have a CensusTreeNodeCacheValue (and hence a CensusTreeNode) for this - // frame, we don't need to add the node to the previous node's children as - // we have already done that. If we don't have a CensusTreeNodeCacheValue - // and CensusTreeNode for this frame, then create one and make sure to hook - // it up as a child of the previous node. - let isNewNode = false; - let val = CensusTreeNodeCache.lookupFrame(currentCache, frame); - if (!val) { - isNewNode = true; - val = new CensusTreeNodeCacheValue(); - val.node = new CensusTreeNode(frame); - - CensusTreeNodeCache.insertFrame(currentCache, val); - if (prevNode) { - addChild(prevNode, val.node); - } - } - - if (i === 0) { - outParams.bottom = isNewNode ? val.node : null; - } - if (i === length - 1) { - outParams.top = val.node; - } - - prevNode = val.node; - - if (i !== length - 1 && !val.children) { - // This is not the last frame and therefore this node will have - // children, which we must cache. - val.children = new CensusTreeNodeCache(); - } - - currentCache = val.children; - } -} - -/** - * A Visitor that walks a census report and creates the corresponding - * CensusTreeNode tree. - */ -function CensusTreeNodeVisitor() { - // The root of the resulting CensusTreeNode tree. - this._root = null; - - // The stack of CensusTreeNodes that we are in the process of building while - // walking the census report. - this._nodeStack = []; - - // To avoid unnecessary allocations, we reuse the same out parameter object - // passed to `makeCensusTreeNodeSubTree` every time we call it. - this._outParams = { - top: null, - bottom: null, - }; - - // The stack of `CensusTreeNodeCache`s that we use to aggregate many - // SavedFrame stacks into a single CensusTreeNode tree. - this._cacheStack = [new CensusTreeNodeCache()]; - - // The current index in the DFS of the census report tree. - this._index = -1; -} - -CensusTreeNodeVisitor.prototype = Object.create(Visitor); - -/** - * Create the CensusTreeNode subtree for this sub-report and link it to the - * parent CensusTreeNode. - * - * @overrides Visitor.prototype.enter - */ -CensusTreeNodeVisitor.prototype.enter = function (breakdown, report, edge) { - this._index++; - - const cache = this._cacheStack[this._cacheStack.length - 1]; - makeCensusTreeNodeSubTree(breakdown, report, edge, cache, this._outParams); - const { top, bottom } = this._outParams; - - if (!this._root) { - this._root = bottom; - } else if (bottom) { - addChild(this._nodeStack[this._nodeStack.length - 1], bottom); - } - - this._cacheStack.push(new CensusTreeNodeCache()); - this._nodeStack.push(top); -}; - -function values(cache) { - return Object.keys(cache).map(k => cache[k]); -} - -function isNonEmpty(node) { - return (node.children !== undefined && node.children.length) - || node.bytes !== 0 - || node.count !== 0; -} - -/** - * We have finished adding children to the CensusTreeNode subtree for the - * current sub-report. Make sure that the children are sorted for every node in - * the subtree. - * - * @overrides Visitor.prototype.exit - */ -CensusTreeNodeVisitor.prototype.exit = function (breakdown, report, edge) { - // Ensure all children are sorted and have their counts/bytes aggregated. We - // only need to consider cache children here, because other children - // correspond to other sub-reports and we already fixed them up in an earlier - // invocation of `exit`. - - function dfs(node, childrenCache) { - if (childrenCache) { - const childValues = values(childrenCache); - for (let i = 0, length = childValues.length; i < length; i++) { - dfs(childValues[i].node, childValues[i].children); - } - } - - node.totalCount = node.count; - node.totalBytes = node.bytes; - - if (node.children) { - // Prune empty leaves. - node.children = node.children.filter(isNonEmpty); - - node.children.sort(compareByTotal); - - for (let i = 0, length = node.children.length; i < length; i++) { - node.totalCount += node.children[i].totalCount; - node.totalBytes += node.children[i].totalBytes; - } - } - } - - const top = this._nodeStack.pop(); - const cache = this._cacheStack.pop(); - dfs(top, cache); -}; - -/** - * @overrides Visitor.prototype.count - */ -CensusTreeNodeVisitor.prototype.count = function (breakdown, report, edge) { - const node = this._nodeStack[this._nodeStack.length - 1]; - node.reportLeafIndex = this._index; - - if (breakdown.count) { - node.count = report.count; - } - - if (breakdown.bytes) { - node.bytes = report.bytes; - } -}; - -/** - * Get the root of the resulting CensusTreeNode tree. - * - * @returns {CensusTreeNode} - */ -CensusTreeNodeVisitor.prototype.root = function () { - if (!this._root) { - throw new Error("Attempt to get the root before walking the census report!"); - } - - if (this._nodeStack.length) { - throw new Error("Attempt to get the root while walking the census report!"); - } - - return this._root; -}; - -/** - * Create a single, uninitialized CensusTreeNode. - * - * @param {null|String|SavedFrame} name - */ -function CensusTreeNode(name) { - // Display name for this CensusTreeNode. Either null, a string, or a - // SavedFrame. - this.name = name; - - // The number of bytes occupied by matching things in the heap snapshot. - this.bytes = 0; - - // The sum of `this.bytes` and `child.totalBytes` for each child in - // `this.children`. - this.totalBytes = 0; - - // The number of things in the heap snapshot that match this node in the - // census tree. - this.count = 0; - - // The sum of `this.count` and `child.totalCount` for each child in - // `this.children`. - this.totalCount = 0; - - // An array of this node's children, or undefined if it has no children. - this.children = undefined; - - // The unique ID of this node. - this.id = ++censusTreeNodeIdCounter; - - // If present, the unique ID of this node's parent. If this node does not have - // a parent, then undefined. - this.parent = undefined; - - // The `reportLeafIndex` property allows mapping a CensusTreeNode node back to - // a leaf in the census report it was generated from. It is always one of the - // following variants: - // - // * A `Number` index pointing a leaf report in a pre-order DFS traversal of - // this CensusTreeNode's census report. - // - // * A `Set` object containing such indices, when this is part of an inverted - // CensusTreeNode tree and multiple leaves in the report map onto this node. - // - // * Finally, `undefined` when no leaves in the census report correspond with - // this node. - // - // The first and third cases are the common cases. The second case is rather - // uncommon, and to avoid doubling the number of allocations when creating - // CensusTreeNode trees, and objects that get structured cloned when sending - // such trees from the HeapAnalysesWorker to the main thread, we only allocate - // a Set object once a node actually does have multiple leaves it corresponds - // to. - this.reportLeafIndex = undefined; -} - -CensusTreeNode.prototype = null; - -/** - * Compare the given nodes by their `totalBytes` properties, and breaking ties - * with the `totalCount`, `bytes`, and `count` properties (in that order). - * - * @param {CensusTreeNode} node1 - * @param {CensusTreeNode} node2 - * - * @returns {Number} - * A number suitable for using with Array.prototype.sort. - */ -function compareByTotal(node1, node2) { - return Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) - || Math.abs(node2.totalCount) - Math.abs(node1.totalCount) - || Math.abs(node2.bytes) - Math.abs(node1.bytes) - || Math.abs(node2.count) - Math.abs(node1.count); -} - -/** - * Compare the given nodes by their `bytes` properties, and breaking ties with - * the `count`, `totalBytes`, and `totalCount` properties (in that order). - * - * @param {CensusTreeNode} node1 - * @param {CensusTreeNode} node2 - * - * @returns {Number} - * A number suitable for using with Array.prototype.sort. - */ -function compareBySelf(node1, node2) { - return Math.abs(node2.bytes) - Math.abs(node1.bytes) - || Math.abs(node2.count) - Math.abs(node1.count) - || Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) - || Math.abs(node2.totalCount) - Math.abs(node1.totalCount); -} - -/** - * Given a parent cache value from a tree we are building and a child node from - * a tree we are basing the new tree off of, if we already have a corresponding - * node in the parent's children cache, merge this node's counts with - * it. Otherwise, create the corresponding node, add it to the parent's children - * cache, and create the parent->child edge. - * - * @param {CensusTreeNodeCacheValue} parentCachevalue - * @param {CensusTreeNode} node - * - * @returns {CensusTreeNodeCacheValue} - * The new or extant child node's corresponding cache value. - */ -function insertOrMergeNode(parentCacheValue, node) { - if (!parentCacheValue.children) { - parentCacheValue.children = new CensusTreeNodeCache(); - } - - let val = CensusTreeNodeCache.lookupNode(parentCacheValue.children, node); - - if (val) { - // When inverting, it is possible that multiple leaves in the census report - // get merged into a single CensusTreeNode node. When this occurs, switch - // from a single index to a set of indices. - if (val.node.reportLeafIndex !== undefined && - val.node.reportLeafIndex !== node.reportLeafIndex) { - if (typeof val.node.reportLeafIndex === "number") { - const oldIndex = val.node.reportLeafIndex; - val.node.reportLeafIndex = new Set(); - val.node.reportLeafIndex.add(oldIndex); - val.node.reportLeafIndex.add(node.reportLeafIndex); - } else { - val.node.reportLeafIndex.add(node.reportLeafIndex); - } - } - - val.node.count += node.count; - val.node.bytes += node.bytes; - } else { - val = new CensusTreeNodeCacheValue(); - - val.node = new CensusTreeNode(node.name); - val.node.reportLeafIndex = node.reportLeafIndex; - val.node.count = node.count; - val.node.totalCount = node.totalCount; - val.node.bytes = node.bytes; - val.node.totalBytes = node.totalBytes; - - addChild(parentCacheValue.node, val.node); - CensusTreeNodeCache.insertNode(parentCacheValue.children, val); - } - - return val; -} - -/** - * Given an un-inverted CensusTreeNode tree, return the corresponding inverted - * CensusTreeNode tree. The input tree is not modified. The resulting inverted - * tree is sorted by self bytes rather than by total bytes. - * - * @param {CensusTreeNode} tree - * The un-inverted tree. - * - * @returns {CensusTreeNode} - * The corresponding inverted tree. - */ -function invert(tree) { - const inverted = new CensusTreeNodeCacheValue(); - inverted.node = new CensusTreeNode(null); - - // Do a depth-first search of the un-inverted tree. As we reach each leaf, - // take the path from the old root to the leaf, reverse that path, and add it - // to the new, inverted tree's root. - - const path = []; - (function addInvertedPaths(node) { - path.push(node); - - if (node.children) { - for (let i = 0, length = node.children.length; i < length; i++) { - addInvertedPaths(node.children[i]); - } - } else { - // We found a leaf node, add the reverse path to the inverted tree. - let currentCacheValue = inverted; - for (let i = path.length - 1; i >= 0; i--) { - currentCacheValue = insertOrMergeNode(currentCacheValue, path[i]); - } - } - - path.pop(); - }(tree)); - - // Ensure that the root node always has the totals. - inverted.node.totalBytes = tree.totalBytes; - inverted.node.totalCount = tree.totalCount; - - return inverted.node; -} - -/** - * Given a CensusTreeNode tree and predicate function, create the tree - * containing only the nodes in any path `(node_0, node_1, ..., node_n-1)` in - * the given tree where `predicate(node_j)` is true for `0 <= j < n`, `node_0` - * is the given tree's root, and `node_n-1` is a leaf in the given tree. The - * given tree is left unmodified. - * - * @param {CensusTreeNode} tree - * @param {Function} predicate - * - * @returns {CensusTreeNode} - */ -function filter(tree, predicate) { - const filtered = new CensusTreeNodeCacheValue(); - filtered.node = new CensusTreeNode(null); - - // Do a DFS over the given tree. If the predicate returns true for any node, - // add that node and its whole subtree to the filtered tree. - - const path = []; - let match = false; - - function addMatchingNodes(node) { - path.push(node); - - let oldMatch = match; - if (!match && predicate(node)) { - match = true; - } - - if (node.children) { - for (let i = 0, length = node.children.length; i < length; i++) { - addMatchingNodes(node.children[i]); - } - } else if (match) { - // We found a matching leaf node, add it to the filtered tree. - let currentCacheValue = filtered; - for (let i = 0, length = path.length; i < length; i++) { - currentCacheValue = insertOrMergeNode(currentCacheValue, path[i]); - } - } - - match = oldMatch; - path.pop(); - } - - if (tree.children) { - for (let i = 0, length = tree.children.length; i < length; i++) { - addMatchingNodes(tree.children[i]); - } - } - - filtered.node.count = tree.count; - filtered.node.totalCount = tree.totalCount; - filtered.node.bytes = tree.bytes; - filtered.node.totalBytes = tree.totalBytes; - - return filtered.node; -} - -/** - * Given a filter string, return a predicate function that takes a node and - * returns true iff the node matches the filter. - * - * @param {String} filterString - * @returns {Function} - */ -function makeFilterPredicate(filterString) { - return function (node) { - if (!node.name) { - return false; - } - - if (isSavedFrame(node.name)) { - return node.name.source.includes(filterString) - || (node.name.functionDisplayName || "").includes(filterString) - || (node.name.asyncCause || "").includes(filterString); - } - - return String(node.name).includes(filterString); - }; -} - -/** - * Takes a report from a census (`dbg.memory.takeCensus()`) and the breakdown - * used to generate the census and returns a structure used to render - * a tree to display the data. - * - * Returns a recursive "CensusTreeNode" object, looking like: - * - * CensusTreeNode = { - * // `children` if it exists, is sorted by `bytes`, if they are leaf nodes. - * children: ?[<CensusTreeNode...>], - * name: <?String> - * count: <?Number> - * bytes: <?Number> - * id: <?Number> - * parent: <?Number> - * } - * - * @param {Object} breakdown - * The breakdown used to generate the census report. - * - * @param {Object} report - * The census report generated with the specified breakdown. - * - * @param {Object} options - * Configuration options. - * - invert: Whether to invert the resulting tree or not. Defaults to - * false, ie uninverted. - * - * @returns {CensusTreeNode} - */ -exports.censusReportToCensusTreeNode = function (breakdown, report, - options = { - invert: false, - filter: null - }) { - // Reset the counter so that turning the same census report into a - // CensusTreeNode tree repeatedly is idempotent. - censusTreeNodeIdCounter = 0; - - const visitor = new CensusTreeNodeVisitor(); - walk(breakdown, report, visitor); - let result = visitor.root(); - - if (options.invert) { - result = invert(result); - } - - if (typeof options.filter === "string") { - result = filter(result, makeFilterPredicate(options.filter)); - } - - // If the report is a delta report that was generated by diffing two other - // reports, make sure to use the basis totals rather than the totals of the - // difference. - if (typeof report[basisTotalBytes] === "number") { - result.totalBytes = report[basisTotalBytes]; - result.totalCount = report[basisTotalCount]; - } - - // Inverting and filtering could have messed up the sort order, so do a - // depth-first search of the tree and ensure that siblings are sorted. - const comparator = options.invert ? compareBySelf : compareByTotal; - (function ensureSorted(node) { - if (node.children) { - node.children.sort(comparator); - for (let i = 0, length = node.children.length; i < length; i++) { - ensureSorted(node.children[i]); - } - } - }(result)); - - return result; -}; diff --git a/devtools/shared/heapsnapshot/generate-core-dump-sources.sh b/devtools/shared/heapsnapshot/generate-core-dump-sources.sh deleted file mode 100755 index 97e492ff0..000000000 --- a/devtools/shared/heapsnapshot/generate-core-dump-sources.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# A script to generate devtools/server/CoreDump.pb.{h,cc} from -# devtools/server/CoreDump.proto. This script assumes you have -# downloaded and installed the protocol buffer compiler, and that it is either -# on your $PATH or located at $PROTOC_PATH. -# -# These files were last compiled with libprotoc 2.4.1. - -set -e - -cd $(dirname $0) - -if [ -n $PROTOC_PATH ]; then - PROTOC_PATH=`which protoc` -fi - -if [ ! -e $PROTOC_PATH ]; then - echo You must install the protocol compiler from - echo https://code.google.com/p/protobuf/downloads/list - exit 1 -fi - -echo Using $PROTOC_PATH as the protocol compiler - -$PROTOC_PATH --cpp_out="." CoreDump.proto diff --git a/devtools/shared/heapsnapshot/moz.build b/devtools/shared/heapsnapshot/moz.build deleted file mode 100644 index fa9ef3915..000000000 --- a/devtools/shared/heapsnapshot/moz.build +++ /dev/null @@ -1,63 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -with Files('**'): - BUG_COMPONENT = ('Firefox', 'Developer Tools: Memory') - -if CONFIG['ENABLE_TESTS']: - DIRS += ['tests/gtest'] - -XPCSHELL_TESTS_MANIFESTS += [ 'tests/unit/xpcshell.ini' ] -MOCHITEST_MANIFESTS += [ 'tests/mochitest/mochitest.ini' ] -MOCHITEST_CHROME_MANIFESTS += [ 'tests/mochitest/chrome.ini' ] - -EXPORTS.mozilla.devtools += [ - 'AutoMemMap.h', - 'CoreDump.pb.h', - 'DeserializedNode.h', - 'DominatorTree.h', - 'FileDescriptorOutputStream.h', - 'HeapSnapshot.h', - 'HeapSnapshotTempFileHelperChild.h', - 'HeapSnapshotTempFileHelperParent.h', - 'ZeroCopyNSIOutputStream.h', -] - -IPDL_SOURCES += [ - 'PHeapSnapshotTempFileHelper.ipdl', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -SOURCES += [ - 'AutoMemMap.cpp', - 'CoreDump.pb.cc', - 'DeserializedNode.cpp', - 'DominatorTree.cpp', - 'FileDescriptorOutputStream.cpp', - 'HeapSnapshot.cpp', - 'HeapSnapshotTempFileHelperParent.cpp', - 'ZeroCopyNSIOutputStream.cpp', -] - -# Disable RTTI in google protocol buffer -DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True - -FINAL_LIBRARY = 'xul' - -if CONFIG['MOZ_DEVTOOLS_SERVER']: - DevToolsModules( - 'census-tree-node.js', - 'CensusUtils.js', - 'DominatorTreeNode.js', - 'HeapAnalysesClient.js', - 'HeapAnalysesWorker.js', - 'HeapSnapshotFileUtils.js', - 'shortest-paths.js', - ) - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-error=shadow'] diff --git a/devtools/shared/heapsnapshot/shortest-paths.js b/devtools/shared/heapsnapshot/shortest-paths.js deleted file mode 100644 index 2d97b7de9..000000000 --- a/devtools/shared/heapsnapshot/shortest-paths.js +++ /dev/null @@ -1,91 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -/** - * Compress a set of paths leading to `target` into a single graph, returned as - * a set of nodes and a set of edges. - * - * @param {NodeId} target - * The target node passed to `HeapSnapshot.computeShortestPaths`. - * - * @param {Array<Path>} paths - * An array of paths to `target`, as returned by - * `HeapSnapshot.computeShortestPaths`. - * - * @returns {Object} - * An object with two properties: - * - edges: An array of unique objects of the form: - * { - * from: <node ID>, - * to: <node ID>, - * name: <string or null> - * } - * - nodes: An array of unique node IDs. Every `from` and `to` id is - * guaranteed to be in this array exactly once. - */ -exports.deduplicatePaths = function (target, paths) { - // Use this structure to de-duplicate edges among many retaining paths from - // start to target. - // - // Map<FromNodeId, Map<ToNodeId, Set<EdgeName>>> - const deduped = new Map(); - - function insert(from, to, name) { - let toMap = deduped.get(from); - if (!toMap) { - toMap = new Map(); - deduped.set(from, toMap); - } - - let nameSet = toMap.get(to); - if (!nameSet) { - nameSet = new Set(); - toMap.set(to, nameSet); - } - - nameSet.add(name); - } - - outer: for (let path of paths) { - const pathLength = path.length; - - // Check for duplicate predecessors in the path, and skip paths that contain - // them. - const predecessorsSeen = new Set(); - predecessorsSeen.add(target); - for (let i = 0; i < pathLength; i++) { - if (predecessorsSeen.has(path[i].predecessor)) { - continue outer; - } - predecessorsSeen.add(path[i].predecessor); - } - - for (let i = 0; i < pathLength - 1; i++) { - insert(path[i].predecessor, path[i + 1].predecessor, path[i].edge); - } - - insert(path[pathLength - 1].predecessor, target, path[pathLength - 1].edge); - } - - const nodes = [target]; - const edges = []; - - for (let [from, toMap] of deduped) { - // If the second/third/etc shortest path contains the `target` anywhere - // other than the very last node, we could accidentally put the `target` in - // `nodes` more than once. - if (from !== target) { - nodes.push(from); - } - - for (let [to, edgeNameSet] of toMap) { - for (let name of edgeNameSet) { - edges.push({ from, to, name }); - } - } - } - - return { nodes, edges }; -}; diff --git a/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp b/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp deleted file mode 100644 index e236a0acf..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that the `JS::ubi::Node`s we create from -// `mozilla::devtools::DeserializedNode` instances look and behave as we would -// like. - -#include "DevTools.h" -#include "js/TypeDecls.h" -#include "mozilla/devtools/DeserializedNode.h" - -using testing::Field; -using testing::ReturnRef; - -// A mock DeserializedNode for testing. -struct MockDeserializedNode : public DeserializedNode -{ - MockDeserializedNode(NodeId id, const char16_t* typeName, uint64_t size) - : DeserializedNode(id, typeName, size) - { } - - bool addEdge(DeserializedEdge&& edge) - { - return edges.append(Move(edge)); - } - - MOCK_METHOD1(getEdgeReferent, JS::ubi::Node(const DeserializedEdge&)); -}; - -size_t fakeMallocSizeOf(const void*) { - EXPECT_TRUE(false); - MOZ_ASSERT_UNREACHABLE("fakeMallocSizeOf should never be called because " - "DeserializedNodes report the deserialized size."); - return 0; -} - -DEF_TEST(DeserializedNodeUbiNodes, { - const char16_t* typeName = u"TestTypeName"; - const char* className = "MyObjectClassName"; - const char* filename = "my-cool-filename.js"; - - NodeId id = uint64_t(1) << 33; - uint64_t size = uint64_t(1) << 60; - MockDeserializedNode mocked(id, typeName, size); - mocked.coarseType = JS::ubi::CoarseType::Script; - mocked.jsObjectClassName = className; - mocked.scriptFilename = filename; - - DeserializedNode& deserialized = mocked; - JS::ubi::Node ubi(&deserialized); - - // Test the ubi::Node accessors. - - EXPECT_EQ(size, ubi.size(fakeMallocSizeOf)); - EXPECT_EQ(typeName, ubi.typeName()); - EXPECT_EQ(JS::ubi::CoarseType::Script, ubi.coarseType()); - EXPECT_EQ(id, ubi.identifier()); - EXPECT_FALSE(ubi.isLive()); - EXPECT_EQ(ubi.jsObjectClassName(), className); - EXPECT_EQ(ubi.scriptFilename(), filename); - - // Test the ubi::Node's edges. - - UniquePtr<DeserializedNode> referent1(new MockDeserializedNode(1, - nullptr, - 10)); - DeserializedEdge edge1(referent1->id); - mocked.addEdge(Move(edge1)); - EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent1->id))) - .Times(1) - .WillOnce(Return(JS::ubi::Node(referent1.get()))); - - UniquePtr<DeserializedNode> referent2(new MockDeserializedNode(2, - nullptr, - 20)); - DeserializedEdge edge2(referent2->id); - mocked.addEdge(Move(edge2)); - EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent2->id))) - .Times(1) - .WillOnce(Return(JS::ubi::Node(referent2.get()))); - - UniquePtr<DeserializedNode> referent3(new MockDeserializedNode(3, - nullptr, - 30)); - DeserializedEdge edge3(referent3->id); - mocked.addEdge(Move(edge3)); - EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent3->id))) - .Times(1) - .WillOnce(Return(JS::ubi::Node(referent3.get()))); - - auto range = ubi.edges(cx); - ASSERT_TRUE(!!range); - - for ( ; !range->empty(); range->popFront()) { - // Nothing to do here. This loop ensures that we get each edge referent - // that we expect above. - } - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp deleted file mode 100644 index 72e363934..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that the `JS::ubi::StackFrame`s we create from -// `mozilla::devtools::DeserializedStackFrame` instances look and behave as we would -// like. - -#include "DevTools.h" -#include "js/TypeDecls.h" -#include "mozilla/devtools/DeserializedNode.h" - -using testing::Field; -using testing::ReturnRef; - -// A mock DeserializedStackFrame for testing. -struct MockDeserializedStackFrame : public DeserializedStackFrame -{ - MockDeserializedStackFrame() : DeserializedStackFrame() { } -}; - -DEF_TEST(DeserializedStackFrameUbiStackFrames, { - StackFrameId id = uint64_t(1) << 42; - uint32_t line = 1337; - uint32_t column = 9; // 3 space tabs!? - const char16_t* source = u"my-javascript-file.js"; - const char16_t* functionDisplayName = u"myFunctionName"; - - MockDeserializedStackFrame mocked; - mocked.id = id; - mocked.line = line; - mocked.column = column; - mocked.source = source; - mocked.functionDisplayName = functionDisplayName; - - DeserializedStackFrame& deserialized = mocked; - JS::ubi::StackFrame ubiFrame(&deserialized); - - // Test the JS::ubi::StackFrame accessors. - - EXPECT_EQ(id, ubiFrame.identifier()); - EXPECT_EQ(JS::ubi::StackFrame(), ubiFrame.parent()); - EXPECT_EQ(line, ubiFrame.line()); - EXPECT_EQ(column, ubiFrame.column()); - EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(source), ubiFrame.source()); - EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(functionDisplayName), - ubiFrame.functionDisplayName()); - EXPECT_FALSE(ubiFrame.isSelfHosted(cx)); - EXPECT_FALSE(ubiFrame.isSystem()); - - JS::RootedObject savedFrame(cx); - EXPECT_TRUE(ubiFrame.constructSavedFrameStack(cx, &savedFrame)); - - uint32_t frameLine; - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameLine(cx, savedFrame, &frameLine)); - EXPECT_EQ(line, frameLine); - - uint32_t frameColumn; - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameColumn(cx, savedFrame, &frameColumn)); - EXPECT_EQ(column, frameColumn); - - JS::RootedObject parent(cx); - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameParent(cx, savedFrame, &parent)); - EXPECT_EQ(nullptr, parent); - - ASSERT_EQ(NS_strlen(source), 21U); - char16_t sourceBuf[21] = {}; - - // Test when the length is shorter than the string length. - auto written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 3); - EXPECT_EQ(written, 3U); - for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sourceBuf[i], source[i]); - } - - written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 21); - EXPECT_EQ(written, 21U); - for (size_t i = 0; i < 21; i++) { - EXPECT_EQ(sourceBuf[i], source[i]); - } - - ASSERT_EQ(NS_strlen(functionDisplayName), 14U); - char16_t nameBuf[14] = {}; - - written = ubiFrame.functionDisplayName(RangedPtr<char16_t>(nameBuf), 14); - EXPECT_EQ(written, 14U); - for (size_t i = 0; i < 14; i++) { - EXPECT_EQ(nameBuf[i], functionDisplayName[i]); - } -}); diff --git a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h deleted file mode 100644 index 6eb5cfe21..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_devtools_gtest_DevTools__ -#define mozilla_devtools_gtest_DevTools__ - -#include "CoreDump.pb.h" -#include "jsapi.h" -#include "jspubtd.h" -#include "nsCRTGlue.h" - -#include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "mozilla/devtools/HeapSnapshot.h" -#include "mozilla/dom/ChromeUtils.h" -#include "mozilla/CycleCollectedJSContext.h" -#include "mozilla/Move.h" -#include "js/Principals.h" -#include "js/UbiNode.h" -#include "js/UniquePtr.h" - -using namespace mozilla; -using namespace mozilla::devtools; -using namespace mozilla::dom; -using namespace testing; - -// GTest fixture class that all of our tests derive from. -struct DevTools : public ::testing::Test { - bool _initialized; - JSContext* cx; - JSCompartment* compartment; - JS::Zone* zone; - JS::PersistentRootedObject global; - - DevTools() - : _initialized(false), - cx(nullptr) - { } - - virtual void SetUp() { - MOZ_ASSERT(!_initialized); - - cx = getContext(); - if (!cx) - return; - - JS_BeginRequest(cx); - - global.init(cx, createGlobal()); - if (!global) - return; - JS_EnterCompartment(cx, global); - - compartment = js::GetContextCompartment(cx); - zone = js::GetContextZone(cx); - - _initialized = true; - } - - JSContext* getContext() { - return CycleCollectedJSContext::Get()->Context(); - } - - static void reportError(JSContext* cx, const char* message, JSErrorReport* report) { - fprintf(stderr, "%s:%u:%s\n", - report->filename ? report->filename : "<no filename>", - (unsigned int) report->lineno, - message); - } - - static const JSClass* getGlobalClass() { - static const JSClassOps globalClassOps = { - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - JS_GlobalObjectTraceHook - }; - static const JSClass globalClass = { - "global", JSCLASS_GLOBAL_FLAGS, - &globalClassOps - }; - return &globalClass; - } - - JSObject* createGlobal() - { - /* Create the global object. */ - JS::RootedObject newGlobal(cx); - JS::CompartmentOptions options; - options.behaviors().setVersion(JSVERSION_LATEST); - newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr, - JS::FireOnNewGlobalHook, options); - if (!newGlobal) - return nullptr; - - JSAutoCompartment ac(cx, newGlobal); - - /* Populate the global object with the standard globals, like Object and - Array. */ - if (!JS_InitStandardClasses(cx, newGlobal)) - return nullptr; - - return newGlobal; - } - - virtual void TearDown() { - _initialized = false; - - if (global) { - JS_LeaveCompartment(cx, nullptr); - global = nullptr; - } - if (cx) - JS_EndRequest(cx); - } -}; - - -// Helper to define a test and ensure that the fixture is initialized properly. -#define DEF_TEST(name, body) \ - TEST_F(DevTools, name) { \ - ASSERT_TRUE(_initialized); \ - body \ - } - - -// Fake JS::ubi::Node implementation -class MOZ_STACK_CLASS FakeNode -{ -public: - JS::ubi::EdgeVector edges; - JSCompartment* compartment; - JS::Zone* zone; - size_t size; - - explicit FakeNode() - : edges(), - compartment(nullptr), - zone(nullptr), - size(1) - { } -}; - -namespace JS { -namespace ubi { - -template<> -class Concrete<FakeNode> : public Base -{ - const char16_t* typeName() const override { - return concreteTypeName; - } - - js::UniquePtr<EdgeRange> edges(JSContext*, bool) const override { - return js::UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges)); - } - - Size size(mozilla::MallocSizeOf) const override { - return get().size; - } - - JS::Zone* zone() const override { - return get().zone; - } - - JSCompartment* compartment() const override { - return get().compartment; - } - -protected: - explicit Concrete(FakeNode* ptr) : Base(ptr) { } - FakeNode& get() const { return *static_cast<FakeNode*>(ptr); } - -public: - static const char16_t concreteTypeName[]; - static void construct(void* storage, FakeNode* ptr) { - new (storage) Concrete(ptr); - } -}; - -const char16_t Concrete<FakeNode>::concreteTypeName[] = u"FakeNode"; - -} // namespace ubi -} // namespace JS - -void AddEdge(FakeNode& node, FakeNode& referent, const char16_t* edgeName = nullptr) { - char16_t* ownedEdgeName = nullptr; - if (edgeName) { - ownedEdgeName = NS_strdup(edgeName); - ASSERT_NE(ownedEdgeName, nullptr); - } - - JS::ubi::Edge edge(ownedEdgeName, &referent); - ASSERT_TRUE(node.edges.append(mozilla::Move(edge))); -} - - -// Custom GMock Matchers - -// Use the testing namespace to avoid static analysis failures in the gmock -// matcher classes that get generated from MATCHER_P macros. -namespace testing { - -// Ensure that given node has the expected number of edges. -MATCHER_P2(EdgesLength, cx, expectedLength, "") { - auto edges = arg.edges(cx); - if (!edges) - return false; - - int actualLength = 0; - for ( ; !edges->empty(); edges->popFront()) - actualLength++; - - return Matcher<int>(Eq(expectedLength)) - .MatchAndExplain(actualLength, result_listener); -} - -// Get the nth edge and match it with the given matcher. -MATCHER_P3(Edge, cx, n, matcher, "") { - auto edges = arg.edges(cx); - if (!edges) - return false; - - int i = 0; - for ( ; !edges->empty(); edges->popFront()) { - if (i == n) { - return Matcher<const JS::ubi::Edge&>(matcher) - .MatchAndExplain(edges->front(), result_listener); - } - - i++; - } - - return false; -} - -// Ensures that two char16_t* strings are equal. -MATCHER_P(UTF16StrEq, str, "") { - return NS_strcmp(arg, str) == 0; -} - -MATCHER_P(UniqueUTF16StrEq, str, "") { - return NS_strcmp(arg.get(), str) == 0; -} - -MATCHER(UniqueIsNull, "") { - return arg.get() == nullptr; -} - -// Matches an edge whose referent is the node with the given id. -MATCHER_P(EdgeTo, id, "") { - return Matcher<const DeserializedEdge&>(Field(&DeserializedEdge::referent, id)) - .MatchAndExplain(arg, result_listener); -} - -} // namespace testing - - -// A mock `Writer` class to be used with testing `WriteHeapGraph`. -class MockWriter : public CoreDumpWriter -{ -public: - virtual ~MockWriter() override { } - MOCK_METHOD2(writeNode, bool(const JS::ubi::Node&, CoreDumpWriter::EdgePolicy)); - MOCK_METHOD1(writeMetadata, bool(uint64_t)); -}; - -void ExpectWriteNode(MockWriter& writer, FakeNode& node) { - EXPECT_CALL(writer, writeNode(Eq(JS::ubi::Node(&node)), _)) - .Times(1) - .WillOnce(Return(true)); -} - -#endif // mozilla_devtools_gtest_DevTools__ diff --git a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp b/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp deleted file mode 100644 index bc517d6d9..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that heap snapshots cross compartment boundaries when expected. - -#include "DevTools.h" - -DEF_TEST(DoesCrossCompartmentBoundaries, { - // Create a new global to get a new compartment. - JS::CompartmentOptions options; - JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx, - getGlobalClass(), - nullptr, - JS::FireOnNewGlobalHook, - options)); - ASSERT_TRUE(newGlobal); - JSCompartment* newCompartment = nullptr; - { - JSAutoCompartment ac(cx, newGlobal); - ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal)); - newCompartment = js::GetContextCompartment(cx); - } - ASSERT_TRUE(newCompartment); - ASSERT_NE(newCompartment, compartment); - - // Our set of target compartments is both the old and new compartments. - JS::CompartmentSet targetCompartments; - ASSERT_TRUE(targetCompartments.init()); - ASSERT_TRUE(targetCompartments.put(compartment)); - ASSERT_TRUE(targetCompartments.put(newCompartment)); - - FakeNode nodeA; - FakeNode nodeB; - FakeNode nodeC; - FakeNode nodeD; - - nodeA.compartment = compartment; - nodeB.compartment = nullptr; - nodeC.compartment = newCompartment; - nodeD.compartment = nullptr; - - AddEdge(nodeA, nodeB); - AddEdge(nodeA, nodeC); - AddEdge(nodeB, nodeD); - - ::testing::NiceMock<MockWriter> writer; - - // Should serialize nodeA, because it is in one of our target compartments. - ExpectWriteNode(writer, nodeA); - - // Should serialize nodeB, because it doesn't belong to a compartment and is - // therefore assumed to be shared. - ExpectWriteNode(writer, nodeB); - - // Should also serialize nodeC, which is in our target compartments, but a - // different compartment than A. - ExpectWriteNode(writer, nodeC); - - // Should serialize nodeD because it's reachable via B and both nodes B and D - // don't belong to a specific compartment. - ExpectWriteNode(writer, nodeD); - - JS::AutoCheckCannotGC noGC(cx); - - ASSERT_TRUE(WriteHeapGraph(cx, - JS::ubi::Node(&nodeA), - writer, - /* wantNames = */ false, - &targetCompartments, - noGC)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp b/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp deleted file mode 100644 index 2fe5e6ace..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that heap snapshots walk the compartment boundaries correctly. - -#include "DevTools.h" - -DEF_TEST(DoesntCrossCompartmentBoundaries, { - // Create a new global to get a new compartment. - JS::CompartmentOptions options; - JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx, - getGlobalClass(), - nullptr, - JS::FireOnNewGlobalHook, - options)); - ASSERT_TRUE(newGlobal); - JSCompartment* newCompartment = nullptr; - { - JSAutoCompartment ac(cx, newGlobal); - ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal)); - newCompartment = js::GetContextCompartment(cx); - } - ASSERT_TRUE(newCompartment); - ASSERT_NE(newCompartment, compartment); - - // Our set of target compartments is only the pre-existing compartment and - // does not include the new compartment. - JS::CompartmentSet targetCompartments; - ASSERT_TRUE(targetCompartments.init()); - ASSERT_TRUE(targetCompartments.put(compartment)); - - FakeNode nodeA; - FakeNode nodeB; - FakeNode nodeC; - - nodeA.compartment = compartment; - nodeB.compartment = nullptr; - nodeC.compartment = newCompartment; - - AddEdge(nodeA, nodeB); - AddEdge(nodeB, nodeC); - - ::testing::NiceMock<MockWriter> writer; - - // Should serialize nodeA, because it is in our target compartments. - ExpectWriteNode(writer, nodeA); - - // Should serialize nodeB, because it doesn't belong to a compartment and is - // therefore assumed to be shared. - ExpectWriteNode(writer, nodeB); - - // But we shouldn't ever serialize nodeC. - - JS::AutoCheckCannotGC noGC(cx); - - ASSERT_TRUE(WriteHeapGraph(cx, - JS::ubi::Node(&nodeA), - writer, - /* wantNames = */ false, - &targetCompartments, - noGC)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp b/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp deleted file mode 100644 index be135dbb4..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that edge names get serialized correctly. - -#include "DevTools.h" - -using testing::Field; -using testing::IsNull; -using testing::Property; -using testing::Return; - -DEF_TEST(SerializesEdgeNames, { - FakeNode node; - FakeNode referent; - - const char16_t edgeName[] = u"edge name"; - const char16_t emptyStr[] = u""; - - AddEdge(node, referent, edgeName); - AddEdge(node, referent, emptyStr); - AddEdge(node, referent, nullptr); - - ::testing::NiceMock<MockWriter> writer; - - // Should get the node with edges once. - EXPECT_CALL( - writer, - writeNode(AllOf(EdgesLength(cx, 3), - Edge(cx, 0, Field(&JS::ubi::Edge::name, - UniqueUTF16StrEq(edgeName))), - Edge(cx, 1, Field(&JS::ubi::Edge::name, - UniqueUTF16StrEq(emptyStr))), - Edge(cx, 2, Field(&JS::ubi::Edge::name, - UniqueIsNull()))), - _) - ) - .Times(1) - .WillOnce(Return(true)); - - // Should get the referent node that doesn't have any edges once. - ExpectWriteNode(writer, referent); - - JS::AutoCheckCannotGC noGC(cx); - ASSERT_TRUE(WriteHeapGraph(cx, - JS::ubi::Node(&node), - writer, - /* wantNames = */ true, - /* zones = */ nullptr, - noGC)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp b/devtools/shared/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp deleted file mode 100644 index 475442df8..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that everything in the heap graph gets serialized once, and only once. - -#include "DevTools.h" - -DEF_TEST(SerializesEverythingInHeapGraphOnce, { - FakeNode nodeA; - FakeNode nodeB; - FakeNode nodeC; - FakeNode nodeD; - - AddEdge(nodeA, nodeB); - AddEdge(nodeB, nodeC); - AddEdge(nodeC, nodeD); - AddEdge(nodeD, nodeA); - - ::testing::NiceMock<MockWriter> writer; - - // Should serialize each node once. - ExpectWriteNode(writer, nodeA); - ExpectWriteNode(writer, nodeB); - ExpectWriteNode(writer, nodeC); - ExpectWriteNode(writer, nodeD); - - JS::AutoCheckCannotGC noGC(cx); - - ASSERT_TRUE(WriteHeapGraph(cx, - JS::ubi::Node(&nodeA), - writer, - /* wantNames = */ false, - /* zones = */ nullptr, - noGC)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/SerializesTypeNames.cpp b/devtools/shared/heapsnapshot/tests/gtest/SerializesTypeNames.cpp deleted file mode 100644 index a259c297b..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/SerializesTypeNames.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Test that a ubi::Node's typeName gets properly serialized into a core dump. - -#include "DevTools.h" - -using testing::Property; -using testing::Return; - -DEF_TEST(SerializesTypeNames, { - FakeNode node; - - ::testing::NiceMock<MockWriter> writer; - EXPECT_CALL(writer, writeNode(Property(&JS::ubi::Node::typeName, - UTF16StrEq(u"FakeNode")), - _)) - .Times(1) - .WillOnce(Return(true)); - - JS::AutoCheckCannotGC noGC(cx); - ASSERT_TRUE(WriteHeapGraph(cx, - JS::ubi::Node(&node), - writer, - /* wantNames = */ true, - /* zones = */ nullptr, - noGC)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/moz.build b/devtools/shared/heapsnapshot/tests/gtest/moz.build deleted file mode 100644 index 08c31e47c..000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/moz.build +++ /dev/null @@ -1,31 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at http://mozilla.org/MPL/2.0/. - -Library('devtoolstests') - -LOCAL_INCLUDES += [ - '../..', -] - -UNIFIED_SOURCES = [ - 'DeserializedNodeUbiNodes.cpp', - 'DeserializedStackFrameUbiStackFrames.cpp', - 'DoesCrossCompartmentBoundaries.cpp', - 'DoesntCrossCompartmentBoundaries.cpp', - 'SerializesEdgeNames.cpp', - 'SerializesEverythingInHeapGraphOnce.cpp', - 'SerializesTypeNames.cpp', -] - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-error=shadow'] - -# THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard -# to work around, so we just ignore it. -if CONFIG['CLANG_CXX']: - CXXFLAGS += ['-Wno-inconsistent-missing-override'] - -FINAL_LIBRARY = 'xul-gtest' diff --git a/devtools/shared/heapsnapshot/tests/mochitest/chrome.ini b/devtools/shared/heapsnapshot/tests/mochitest/chrome.ini deleted file mode 100644 index 497b6fe37..000000000 --- a/devtools/shared/heapsnapshot/tests/mochitest/chrome.ini +++ /dev/null @@ -1,8 +0,0 @@ -[DEFAULT] -tags = devtools devtools-memory -skip-if = os == 'android' -support-files = - -[test_DominatorTree_01.html] -[test_SaveHeapSnapshot.html] - diff --git a/devtools/shared/heapsnapshot/tests/mochitest/mochitest.ini b/devtools/shared/heapsnapshot/tests/mochitest/mochitest.ini deleted file mode 100644 index 5e7aa8d10..000000000 --- a/devtools/shared/heapsnapshot/tests/mochitest/mochitest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] -tags = devtools devtools-memory -support-files = - -[test_saveHeapSnapshot_e10s_01.html] - diff --git a/devtools/shared/heapsnapshot/tests/mochitest/test_DominatorTree_01.html b/devtools/shared/heapsnapshot/tests/mochitest/test_DominatorTree_01.html deleted file mode 100644 index 1f9d8c080..000000000 --- a/devtools/shared/heapsnapshot/tests/mochitest/test_DominatorTree_01.html +++ /dev/null @@ -1,37 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -Sanity test that we can compute dominator trees from a heap snapshot in a web window. ---> -<head> - <meta charset="utf-8"> - <title>ChromeUtils.saveHeapSnapshot test</title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> -</head> -<body> -<pre id="test"> -<script> -SimpleTest.waitForExplicitFinish(); -window.onload = function() { - const path = ChromeUtils.saveHeapSnapshot({ runtime: true }); - const snapshot = ChromeUtils.readHeapSnapshot(path); - - const dominatorTree = snapshot.computeDominatorTree(); - ok(dominatorTree); - ok(dominatorTree instanceof DominatorTree); - - let threw = false; - try { - new DominatorTree(); - } catch (e) { - threw = true; - } - ok(threw, "Constructor shouldn't be usable"); - - SimpleTest.finish(); -}; -</script> -</pre> -</body> -</html> diff --git a/devtools/shared/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html b/devtools/shared/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html deleted file mode 100644 index f150a99c7..000000000 --- a/devtools/shared/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html +++ /dev/null @@ -1,25 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -Bug 1024774 - Sanity test that we can take a heap snapshot in a web window. ---> -<head> - <meta charset="utf-8"> - <title>ChromeUtils.saveHeapSnapshot test</title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> -</head> -<body> -<pre id="test"> -<script> -SimpleTest.waitForExplicitFinish(); -window.onload = function() { - ok(ChromeUtils, "The ChromeUtils interface should be exposed in chrome windows."); - ChromeUtils.saveHeapSnapshot({ runtime: true }); - ok(true, "Should save a heap snapshot and shouldn't throw."); - SimpleTest.finish(); -}; -</script> -</pre> -</body> -</html> diff --git a/devtools/shared/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html b/devtools/shared/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html deleted file mode 100644 index 15f88f8e0..000000000 --- a/devtools/shared/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE HTML> -<!-- -Bug 1201597 - Sanity test that we can take a heap snapshot in an e10s child process. ---> -<html> -<head> - <title>saveHeapSnapshot in e10s child processes</title> - <script type="application/javascript" - src="/tests/SimpleTest/SimpleTest.js"> - </script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body> - <script type="application/javascript"> - window.onerror = function (msg, url, line, col, err) { - ok(false, "@" + url + ":" + line + ":" + col + ": " + msg + "\n" + err.stack); - }; - - SimpleTest.waitForExplicitFinish(); - - var childFrameURL = "data:text/html,<!DOCTYPE HTML><html><body></body></html>"; - - // This function is stringified and loaded in the child process as a frame - // script. - function childFrameScript() { - try { - ChromeUtils.saveHeapSnapshot({ runtime: true }); - } catch (err) { - sendAsyncMessage("testSaveHeapSnapshot:error", - { error: err.toString() }); - return; - } - - sendAsyncMessage("testSaveHeapSnapshot:done", {}); - } - - // Kick everything off on load. - window.onload = function () { - info("window.onload fired"); - SpecialPowers.addPermission("browser", true, document); - SpecialPowers.pushPrefEnv({ - "set": [ - ["dom.ipc.browser_frames.oop_by_default", true], - ["dom.mozBrowserFramesEnabled", true], - ["browser.pagethumbnails.capturing_disabled", true] - ] - }, function () { - var iframe = document.createElement("iframe"); - SpecialPowers.wrap(iframe).mozbrowser = true; - iframe.id = "iframe"; - iframe.src = childFrameURL; - - - iframe.addEventListener("mozbrowserloadend", function onLoadEnd() { - iframe.removeEventListener("mozbrowserloadend", onLoadEnd); - info("iframe done loading"); - - var mm = SpecialPowers.getBrowserFrameMessageManager(iframe); - - function onError(e) { - ok(false, e.data.error); - } - mm.addMessageListener("testSaveHeapSnapshot:error", onError); - - mm.addMessageListener("testSaveHeapSnapshot:done", function onMsg() { - mm.removeMessageListener("testSaveHeapSnapshot:done", onMsg); - mm.removeMessageListener("testSaveHeapSnapshot:error", onError); - ok(true, "Saved heap snapshot in child process"); - SimpleTest.finish(); - }); - - info("Loading frame script to save heap snapshot"); - mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();", - false); - }); - - info("Loading iframe"); - document.body.appendChild(iframe); - }); - }; - </script> -</window> diff --git a/devtools/shared/heapsnapshot/tests/unit/.eslintrc.js b/devtools/shared/heapsnapshot/tests/unit/.eslintrc.js deleted file mode 100644 index 59adf410a..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; - -module.exports = { - // Extend from the common devtools xpcshell eslintrc config. - "extends": "../../../../.eslintrc.xpcshell.js" -}; diff --git a/devtools/shared/heapsnapshot/tests/unit/Census.jsm b/devtools/shared/heapsnapshot/tests/unit/Census.jsm deleted file mode 100644 index f8fb1ce44..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/Census.jsm +++ /dev/null @@ -1,165 +0,0 @@ -// Functions for checking results returned by -// Debugger.Memory.prototype.takeCensus and -// HeapSnapshot.prototype.takeCensus. Adapted from js/src/jit-test/lib/census.js. - -this.EXPORTED_SYMBOLS = ["Census"]; - -this.Census = (function () { - const Census = {}; - - function dumpn(msg) { - dump("DBG-TEST: Census.jsm: " + msg + "\n"); - } - - // Census.walkCensus(subject, name, walker) - // - // Use |walker| to check |subject|, a census object of the sort returned by - // Debugger.Memory.prototype.takeCensus: a tree of objects with integers at the - // leaves. Use |name| as the name for |subject| in diagnostic messages. Return - // the number of leaves of |subject| we visited. - // - // A walker is an object with three methods: - // - // - enter(prop): Return the walker we should use to check the property of the - // subject census named |prop|. This is for recursing into the subobjects of - // the subject. - // - // - done(): Called after we have called 'enter' on every property of the - // subject. - // - // - check(value): Check |value|, a leaf in the subject. - // - // Walker methods are expected to simply throw if a node we visit doesn't look - // right. - Census.walkCensus = (subject, name, walker) => walk(subject, name, walker, 0); - function walk(subject, name, walker, count) { - if (typeof subject === "object") { - dumpn(name); - for (let prop in subject) { - count = walk(subject[prop], - name + "[" + uneval(prop) + "]", - walker.enter(prop), - count); - } - walker.done(); - } else { - dumpn(name + " = " + uneval(subject)); - walker.check(subject); - count++; - } - - return count; - } - - // A walker that doesn't check anything. - Census.walkAnything = { - enter: () => Census.walkAnything, - done: () => undefined, - check: () => undefined - }; - - // A walker that requires all leaves to be zeros. - Census.assertAllZeros = { - enter: () => Census.assertAllZeros, - done: () => undefined, - check: elt => { if (elt !== 0) throw new Error("Census mismatch: expected zero, found " + elt); } - }; - - function expectedObject() { - throw new Error("Census mismatch: subject has leaf where basis has nested object"); - } - - function expectedLeaf() { - throw new Error("Census mismatch: subject has nested object where basis has leaf"); - } - - // Return a function that, given a 'basis' census, returns a census walker that - // compares the subject census against the basis. The returned walker calls the - // given |compare|, |missing|, and |extra| functions as follows: - // - // - compare(subjectLeaf, basisLeaf): Check a leaf of the subject against the - // corresponding leaf of the basis. - // - // - missing(prop, value): Called when the subject is missing a property named - // |prop| which is present in the basis with value |value|. - // - // - extra(prop): Called when the subject has a property named |prop|, but the - // basis has no such property. This should return a walker that can check - // the subject's value. - function makeBasisChecker({compare, missing, extra}) { - return function makeWalker(basis) { - if (typeof basis === "object") { - var unvisited = new Set(Object.getOwnPropertyNames(basis)); - return { - enter: prop => { - unvisited.delete(prop); - if (prop in basis) { - return makeWalker(basis[prop]); - } else { - return extra(prop); - } - }, - - done: () => unvisited.forEach(prop => missing(prop, basis[prop])), - check: expectedObject - }; - } else { - return { - enter: expectedLeaf, - done: expectedLeaf, - check: elt => compare(elt, basis) - }; - } - }; - } - - function missingProp(prop) { - throw new Error("Census mismatch: subject lacks property present in basis: " + prop); - } - - function extraProp(prop) { - throw new Error("Census mismatch: subject has property not present in basis: " + prop); - } - - // Return a walker that checks that the subject census has counts all equal to - // |basis|. - Census.assertAllEqual = makeBasisChecker({ - compare: (a, b) => { if (a !== b) throw new Error("Census mismatch: expected " + a + " got " + b);}, - missing: missingProp, - extra: extraProp - }); - - function ok(val) { - if (!val) { - throw new Error("Census mismatch: expected truthy, got " + val); - } - } - - // Return a walker that checks that the subject census has at least as many - // items of each category as |basis|. - Census.assertAllNotLessThan = makeBasisChecker({ - compare: (subject, basis) => ok(subject >= basis), - missing: missingProp, - extra: () => Census.walkAnything - }); - - // Return a walker that checks that the subject census has at most as many - // items of each category as |basis|. - Census.assertAllNotMoreThan = makeBasisChecker({ - compare: (subject, basis) => ok(subject <= basis), - missing: missingProp, - extra: () => Census.walkAnything - }); - - // Return a walker that checks that the subject census has within |fudge| - // items of each category of the count in |basis|. - Census.assertAllWithin = function (fudge, basis) { - return makeBasisChecker({ - compare: (subject, basis) => ok(Math.abs(subject - basis) <= fudge), - missing: missingProp, - extra: () => Census.walkAnything - })(basis); - }; - - return Census; -}()); diff --git a/devtools/shared/heapsnapshot/tests/unit/Match.jsm b/devtools/shared/heapsnapshot/tests/unit/Match.jsm deleted file mode 100644 index c29e6484e..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/Match.jsm +++ /dev/null @@ -1,190 +0,0 @@ -// A little pattern-matching library. -// -// Ported from js/src/tests/js1_8_5/reflect-parse/Match.js for use with devtools -// server xpcshell tests. - -this.EXPORTED_SYMBOLS = ["Match"]; - -this.Match = (function() { - - function Pattern(template) { - // act like a constructor even as a function - if (!(this instanceof Pattern)) - return new Pattern(template); - - this.template = template; - } - - Pattern.prototype = { - match: function(act) { - return match(act, this.template); - }, - - matches: function(act) { - try { - return this.match(act); - } - catch (e if e instanceof MatchError) { - return false; - } - }, - - assert: function(act, message) { - try { - return this.match(act); - } - catch (e if e instanceof MatchError) { - throw new Error((message || "failed match") + ": " + e.message); - } - }, - - toString: () => "[object Pattern]" - }; - - Pattern.ANY = new Pattern; - Pattern.ANY.template = Pattern.ANY; - - Pattern.NUMBER = new Pattern; - Pattern.NUMBER.match = function (act) { - if (typeof act !== 'number') { - throw new MatchError("Expected number, got: " + quote(act)); - } - } - - Pattern.NATURAL = new Pattern - Pattern.NATURAL.match = function (act) { - if (typeof act !== 'number' || act !== Math.floor(act) || act < 0) { - throw new MatchError("Expected natural number, got: " + quote(act)); - } - } - - var quote = uneval; - - function MatchError(msg) { - this.message = msg; - } - - MatchError.prototype = { - toString: function() { - return "match error: " + this.message; - } - }; - - function isAtom(x) { - return (typeof x === "number") || - (typeof x === "string") || - (typeof x === "boolean") || - (x === null) || - (typeof x === "object" && x instanceof RegExp); - } - - function isObject(x) { - return (x !== null) && (typeof x === "object"); - } - - function isFunction(x) { - return typeof x === "function"; - } - - function isArrayLike(x) { - return isObject(x) && ("length" in x); - } - - function matchAtom(act, exp) { - if ((typeof exp) === "number" && isNaN(exp)) { - if ((typeof act) !== "number" || !isNaN(act)) - throw new MatchError("expected NaN, got: " + quote(act)); - return true; - } - - if (exp === null) { - if (act !== null) - throw new MatchError("expected null, got: " + quote(act)); - return true; - } - - if (exp instanceof RegExp) { - if (!(act instanceof RegExp) || exp.source !== act.source) - throw new MatchError("expected " + quote(exp) + ", got: " + quote(act)); - return true; - } - - switch (typeof exp) { - case "string": - if (act !== exp) - throw new MatchError("expected " + quote(exp) + ", got " + quote(act)); - return true; - case "boolean": - case "number": - if (exp !== act) - throw new MatchError("expected " + exp + ", got " + quote(act)); - return true; - } - - throw new Error("bad pattern: " + exp.toSource()); - } - - function matchObject(act, exp) { - if (!isObject(act)) - throw new MatchError("expected object, got " + quote(act)); - - for (var key in exp) { - if (!(key in act)) - throw new MatchError("expected property " + quote(key) + " not found in " + quote(act)); - match(act[key], exp[key]); - } - - return true; - } - - function matchFunction(act, exp) { - if (!isFunction(act)) - throw new MatchError("expected function, got " + quote(act)); - - if (act !== exp) - throw new MatchError("expected function: " + exp + - "\nbut got different function: " + act); - } - - function matchArray(act, exp) { - if (!isObject(act) || !("length" in act)) - throw new MatchError("expected array-like object, got " + quote(act)); - - var length = exp.length; - if (act.length !== exp.length) - throw new MatchError("expected array-like object of length " + length + ", got " + quote(act)); - - for (var i = 0; i < length; i++) { - if (i in exp) { - if (!(i in act)) - throw new MatchError("expected array property " + i + " not found in " + quote(act)); - match(act[i], exp[i]); - } - } - - return true; - } - - function match(act, exp) { - if (exp === Pattern.ANY) - return true; - - if (exp instanceof Pattern) - return exp.match(act); - - if (isAtom(exp)) - return matchAtom(act, exp); - - if (isArrayLike(exp)) - return matchArray(act, exp); - - if (isFunction(exp)) - return matchFunction(act, exp); - - return matchObject(act, exp); - } - - return { Pattern: Pattern, - MatchError: MatchError }; - -})(); diff --git a/devtools/shared/heapsnapshot/tests/unit/dominator-tree-worker.js b/devtools/shared/heapsnapshot/tests/unit/dominator-tree-worker.js deleted file mode 100644 index 1f49ca841..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/dominator-tree-worker.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -console.log("Initializing worker."); - -self.onmessage = e => { - console.log("Starting test."); - try { - const path = ThreadSafeChromeUtils.saveHeapSnapshot({ runtime: true }); - const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(path); - - const dominatorTree = snapshot.computeDominatorTree(); - ok(dominatorTree); - ok(dominatorTree instanceof DominatorTree); - - let threw = false; - try { - new DominatorTree(); - } catch (e) { - threw = true; - } - ok(threw, "Constructor shouldn't be usable"); - } catch (e) { - ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack); - } finally { - done(); - } -}; - -// Proxy assertions to the main thread. -function ok(val, msg) { - console.log("ok(" + !!val + ", \"" + msg + "\")"); - self.postMessage({ - type: "assertion", - passed: !!val, - msg, - stack: Error().stack - }); -} - -// Tell the main thread we are done with the tests. -function done() { - console.log("done()"); - self.postMessage({ - type: "done" - }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js b/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js deleted file mode 100644 index 3171c8a6f..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js +++ /dev/null @@ -1,448 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; - -const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const { Match } = Cu.import("resource://test/Match.jsm", {}); -const { Census } = Cu.import("resource://test/Census.jsm", {}); -const { addDebuggerToGlobal } = - Cu.import("resource://gre/modules/jsdebugger.jsm", {}); -const { Task } = require("devtools/shared/task"); - -const DevToolsUtils = require("devtools/shared/DevToolsUtils"); -const flags = require("devtools/shared/flags"); -const HeapAnalysesClient = - require("devtools/shared/heapsnapshot/HeapAnalysesClient"); -const Services = require("Services"); -const { censusReportToCensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node"); -const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils"); -const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNode"); -const { deduplicatePaths } = require("devtools/shared/heapsnapshot/shortest-paths"); -const { LabelAndShallowSizeVisitor } = DominatorTreeNode; - - -// Always log packets when running tests. runxpcshelltests.py will throw -// the output away anyway, unless you give it the --verbose flag. -if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) { - Services.prefs.setBoolPref("devtools.debugger.log", true); -} -flags.wantLogging = true; - -const SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"] - .createInstance(Ci.nsIPrincipal); - -function dumpn(msg) { - dump("HEAPSNAPSHOT-TEST: " + msg + "\n"); -} - -function addTestingFunctionsToGlobal(global) { - global.eval( - ` - const testingFunctions = Components.utils.getJSTestingFunctions(); - for (let k in testingFunctions) { - this[k] = testingFunctions[k]; - } - ` - ); - if (!global.print) { - global.print = do_print; - } - if (!global.newGlobal) { - global.newGlobal = newGlobal; - } - if (!global.Debugger) { - addDebuggerToGlobal(global); - } -} - -addTestingFunctionsToGlobal(this); - -/** - * Create a new global, with all the JS shell testing functions. Similar to the - * newGlobal function exposed to JS shells, and useful for porting JS shell - * tests to xpcshell tests. - */ -function newGlobal() { - const global = new Cu.Sandbox(SYSTEM_PRINCIPAL, { freshZone: true }); - addTestingFunctionsToGlobal(global); - return global; -} - -function assertThrowsValue(f, val, msg) { - var fullmsg; - try { - f(); - } catch (exc) { - if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val)) - return; - fullmsg = "Assertion failed: expected exception " + val + ", got " + exc; - } - if (fullmsg === undefined) - fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown"; - if (msg !== undefined) - fullmsg += " - " + msg; - throw new Error(fullmsg); -} - -/** - * Returns the full path of the file with the specified name in a - * platform-independent and URL-like form. - */ -function getFilePath(aName, aAllowMissing = false, aUsePlatformPathSeparator = false) -{ - let file = do_get_file(aName, aAllowMissing); - let path = Services.io.newFileURI(file).spec; - let filePrePath = "file://"; - if ("nsILocalFileWin" in Ci && - file instanceof Ci.nsILocalFileWin) { - filePrePath += "/"; - } - - path = path.slice(filePrePath.length); - - if (aUsePlatformPathSeparator && path.match(/^\w:/)) { - path = path.replace(/\//g, "\\"); - } - - return path; -} - -function saveNewHeapSnapshot(opts = { runtime: true }) { - const filePath = ChromeUtils.saveHeapSnapshot(opts); - ok(filePath, "Should get a file path to save the core dump to."); - ok(true, "Saved a heap snapshot to " + filePath); - return filePath; -} - -function readHeapSnapshot(filePath) { - const snapshot = ChromeUtils.readHeapSnapshot(filePath); - ok(snapshot, "Should have read a heap snapshot back from " + filePath); - ok(snapshot instanceof HeapSnapshot, "snapshot should be an instance of HeapSnapshot"); - return snapshot; -} - -/** - * Save a heap snapshot to the file with the given name in the current - * directory, read it back as a HeapSnapshot instance, and then take a census of - * the heap snapshot's serialized heap graph with the provided census options. - * - * @param {Object|undefined} censusOptions - * Options that should be passed through to the takeCensus method. See - * js/src/doc/Debugger/Debugger.Memory.md for details. - * - * @param {Debugger|null} dbg - * If a Debugger object is given, only serialize the subgraph covered by - * the Debugger's debuggees. If null, serialize the whole heap graph. - * - * @param {String} fileName - * The file name to save the heap snapshot's core dump file to, within - * the current directory. - * - * @returns Census - */ -function saveHeapSnapshotAndTakeCensus(dbg = null, censusOptions = undefined) { - const snapshotOptions = dbg ? { debugger: dbg } : { runtime: true }; - const filePath = saveNewHeapSnapshot(snapshotOptions); - const snapshot = readHeapSnapshot(filePath); - - equal(typeof snapshot.takeCensus, "function", "snapshot should have a takeCensus method"); - - return snapshot.takeCensus(censusOptions); -} - -/** - * Save a heap snapshot to disk, read it back as a HeapSnapshot instance, and - * then compute its dominator tree. - * - * @param {Debugger|null} dbg - * If a Debugger object is given, only serialize the subgraph covered by - * the Debugger's debuggees. If null, serialize the whole heap graph. - * - * @returns {DominatorTree} - */ -function saveHeapSnapshotAndComputeDominatorTree(dbg = null) { - const snapshotOptions = dbg ? { debugger: dbg } : { runtime: true }; - const filePath = saveNewHeapSnapshot(snapshotOptions); - const snapshot = readHeapSnapshot(filePath); - - equal(typeof snapshot.computeDominatorTree, "function", - "snapshot should have a `computeDominatorTree` method"); - - const dominatorTree = snapshot.computeDominatorTree(); - - ok(dominatorTree, "Should be able to compute a dominator tree"); - ok(dominatorTree instanceof DominatorTree, "Should be an instance of DominatorTree"); - - return dominatorTree; -} - -function isSavedFrame(obj) { - return Object.prototype.toString.call(obj) === "[object SavedFrame]"; -} - -function savedFrameReplacer(key, val) { - if (isSavedFrame(val)) { - return `<SavedFrame '${val.toString().split(/\n/g).shift()}'>`; - } else { - return val; - } -} - -/** - * Assert that creating a CensusTreeNode from the given `report` with the - * specified `breakdown` creates the given `expected` CensusTreeNode. - * - * @param {Object} breakdown - * The census breakdown. - * - * @param {Object} report - * The census report. - * - * @param {Object} expected - * The expected CensusTreeNode result. - * - * @param {Object} options - * The options to pass through to `censusReportToCensusTreeNode`. - */ -function compareCensusViewData(breakdown, report, expected, options) { - dumpn("Generating CensusTreeNode from report:"); - dumpn("breakdown: " + JSON.stringify(breakdown, null, 4)); - dumpn("report: " + JSON.stringify(report, null, 4)); - dumpn("expected: " + JSON.stringify(expected, savedFrameReplacer, 4)); - - const actual = censusReportToCensusTreeNode(breakdown, report, options); - dumpn("actual: " + JSON.stringify(actual, savedFrameReplacer, 4)); - - assertStructurallyEquivalent(actual, expected); -} - -// Deep structural equivalence that can handle Map objects in addition to plain -// objects. -function assertStructurallyEquivalent(actual, expected, path = "root") { - if (actual === expected) { - equal(actual, expected, "actual and expected are the same"); - return; - } - - equal(typeof actual, typeof expected, `${path}: typeof should be the same`); - - if (actual && typeof actual === "object") { - const actualProtoString = Object.prototype.toString.call(actual); - const expectedProtoString = Object.prototype.toString.call(expected); - equal(actualProtoString, expectedProtoString, - `${path}: Object.prototype.toString.call() should be the same`); - - if (actualProtoString === "[object Map]") { - const expectedKeys = new Set([...expected.keys()]); - - for (let key of actual.keys()) { - ok(expectedKeys.has(key), - `${path}: every key in actual should exist in expected: ${String(key).slice(0, 10)}`); - expectedKeys.delete(key); - - assertStructurallyEquivalent(actual.get(key), expected.get(key), - path + ".get(" + String(key).slice(0, 20) + ")"); - } - - equal(expectedKeys.size, 0, - `${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`); - } else if (actualProtoString === "[object Set]") { - const expectedItems = new Set([...expected]); - - for (let item of actual) { - ok(expectedItems.has(item), - `${path}: every set item in actual should exist in expected: ${item}`); - expectedItems.delete(item); - } - - equal(expectedItems.size, 0, - `${path}: every set item in expected should also exist in actual, did not see ${[...expectedItems]}`); - } else { - const expectedKeys = new Set(Object.keys(expected)); - - for (let key of Object.keys(actual)) { - ok(expectedKeys.has(key), - `${path}: every key in actual should exist in expected: ${key}`); - expectedKeys.delete(key); - - assertStructurallyEquivalent(actual[key], expected[key], path + "." + key); - } - - equal(expectedKeys.size, 0, - `${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`); - } - } else { - equal(actual, expected, `${path}: primitives should be equal`); - } -} - -/** - * Assert that creating a diff of the `first` and `second` census reports - * creates the `expected` delta-report. - * - * @param {Object} breakdown - * The census breakdown. - * - * @param {Object} first - * The first census report. - * - * @param {Object} second - * The second census report. - * - * @param {Object} expected - * The expected delta-report. - */ -function assertDiff(breakdown, first, second, expected) { - dumpn("Diffing census reports:"); - dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4)); - dumpn("First census report: " + JSON.stringify(first, null, 4)); - dumpn("Second census report: " + JSON.stringify(second, null, 4)); - dumpn("Expected delta-report: " + JSON.stringify(expected, null, 4)); - - const actual = CensusUtils.diff(breakdown, first, second); - dumpn("Actual delta-report: " + JSON.stringify(actual, null, 4)); - - assertStructurallyEquivalent(actual, expected); -} - -/** - * Assert that creating a label and getting a shallow size from the given node - * description with the specified breakdown is as expected. - * - * @param {Object} breakdown - * @param {Object} givenDescription - * @param {Number} expectedShallowSize - * @param {Object} expectedLabel - */ -function assertLabelAndShallowSize(breakdown, givenDescription, expectedShallowSize, expectedLabel) { - dumpn("Computing label and shallow size from node description:"); - dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4)); - dumpn("Given description: " + JSON.stringify(givenDescription, null, 4)); - - const visitor = new LabelAndShallowSizeVisitor(); - CensusUtils.walk(breakdown, description, visitor); - - dumpn("Expected shallow size: " + expectedShallowSize); - dumpn("Actual shallow size: " + visitor.shallowSize()); - equal(visitor.shallowSize(), expectedShallowSize, "Shallow size should be correct"); - - dumpn("Expected label: " + JSON.stringify(expectedLabel, null, 4)); - dumpn("Actual label: " + JSON.stringify(visitor.label(), null, 4)); - assertStructurallyEquivalent(visitor.label(), expectedLabel); -} - -// Counter for mock DominatorTreeNode ids. -let TEST_NODE_ID_COUNTER = 0; - -/** - * Create a mock DominatorTreeNode for testing, with sane defaults. Override any - * property by providing it on `opts`. Optionally pass child nodes as well. - * - * @param {Object} opts - * @param {Array<DominatorTreeNode>?} children - * - * @returns {DominatorTreeNode} - */ -function makeTestDominatorTreeNode(opts, children) { - const nodeId = TEST_NODE_ID_COUNTER++; - - const node = Object.assign({ - nodeId, - label: undefined, - shallowSize: 1, - retainedSize: (children || []).reduce((size, c) => size + c.retainedSize, 1), - parentId: undefined, - children, - moreChildrenAvailable: true, - }, opts); - - if (children && children.length) { - children.map(c => c.parentId = node.nodeId); - } - - return node; -} - -/** - * Insert `newChildren` into the given dominator `tree` as specified by the - * `path` from the root to the node the `newChildren` should be inserted - * beneath. Assert that the resulting tree matches `expected`. - */ -function assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected) { - dumpn("Inserting new children into a dominator tree:"); - dumpn("Dominator tree: " + JSON.stringify(tree, null, 2)); - dumpn("Path: " + JSON.stringify(path, null, 2)); - dumpn("New children: " + JSON.stringify(newChildren, null, 2)); - dumpn("Expected resulting tree: " + JSON.stringify(expected, null, 2)); - - const actual = DominatorTreeNode.insert(tree, path, newChildren, moreChildrenAvailable); - dumpn("Actual resulting tree: " + JSON.stringify(actual, null, 2)); - - assertStructurallyEquivalent(actual, expected); -} - -function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }) { - dumpn("Deduplicating paths:"); - dumpn("target = " + target); - dumpn("paths = " + JSON.stringify(paths, null, 2)); - dumpn("expectedNodes = " + expectedNodes); - dumpn("expectedEdges = " + JSON.stringify(expectedEdges, null, 2)); - - const { nodes, edges } = deduplicatePaths(target, paths); - - dumpn("Actual nodes = " + nodes); - dumpn("Actual edges = " + JSON.stringify(edges, null, 2)); - - equal(nodes.length, expectedNodes.length, - "actual number of nodes is equal to the expected number of nodes"); - - equal(edges.length, expectedEdges.length, - "actual number of edges is equal to the expected number of edges"); - - const expectedNodeSet = new Set(expectedNodes); - const nodeSet = new Set(nodes); - ok(nodeSet.size === nodes.length, - "each returned node should be unique"); - - for (let node of nodes) { - ok(expectedNodeSet.has(node), `the ${node} node was expected`); - } - - for (let expectedEdge of expectedEdges) { - let count = 0; - for (let edge of edges) { - if (edge.from === expectedEdge.from && - edge.to === expectedEdge.to && - edge.name === expectedEdge.name) { - count++; - } - } - equal(count, 1, - "should have exactly one matching edge for the expected edge = " + JSON.stringify(edge)); - } -} - -function assertCountToBucketBreakdown(breakdown, expected) { - dumpn("count => bucket breakdown"); - dumpn("Initial breakdown = ", JSON.stringify(breakdown, null, 2)); - dumpn("Expected results = ", JSON.stringify(expected, null, 2)); - - const actual = CensusUtils.countToBucketBreakdown(breakdown); - dumpn("Actual results = ", JSON.stringify(actual, null, 2)); - - assertStructurallyEquivalent(actual, expected); -} - -/** - * Create a mock path entry for the given predecessor and edge. - */ -function pathEntry(predecessor, edge) { - return { predecessor, edge }; -} diff --git a/devtools/shared/heapsnapshot/tests/unit/heap-snapshot-worker.js b/devtools/shared/heapsnapshot/tests/unit/heap-snapshot-worker.js deleted file mode 100644 index 10ee70cec..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/heap-snapshot-worker.js +++ /dev/null @@ -1,46 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -console.log("Initializing worker."); - -self.onmessage = e => { - console.log("Starting test."); - try { - ok(typeof ChromeUtils === "undefined", - "Should not have access to ChromeUtils in a worker."); - ok(ThreadSafeChromeUtils, - "Should have access to ThreadSafeChromeUtils in a worker."); - ok(HeapSnapshot, - "Should have access to HeapSnapshot in a worker."); - - const filePath = ThreadSafeChromeUtils.saveHeapSnapshot({ globals: [this] }); - ok(true, "Should be able to save a snapshot."); - - const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(filePath); - ok(snapshot, "Should be able to read a heap snapshot"); - ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot"); - } catch (e) { - ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack); - } finally { - done(); - } -}; - -// Proxy assertions to the main thread. -function ok(val, msg) { - console.log("ok(" + !!val + ", \"" + msg + "\")"); - self.postMessage({ - type: "assertion", - passed: !!val, - msg, - stack: Error().stack - }); -} - -// Tell the main thread we are done with the tests. -function done() { - console.log("done()"); - self.postMessage({ - type: "done" - }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js deleted file mode 100644 index 845a0d263..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js +++ /dev/null @@ -1,46 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can generate label structures from node description reports. - -const breakdown = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -const description = { - objects: { - Function: { count: 1, bytes: 32 }, - other: { count: 0, bytes: 0 } - }, - strings: {}, - scripts: {}, - other: {} -}; - -const expected = [ - "objects", - "Function" -]; - -const shallowSize = 32; - -function run_test() { - assertLabelAndShallowSize(breakdown, description, shallowSize, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js deleted file mode 100644 index e1f32de58..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js +++ /dev/null @@ -1,45 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can generate label structures from node description reports. - -const breakdown = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -const description = { - objects: { - other: { count: 1, bytes: 10 } - }, - strings: {}, - scripts: {}, - other: {} -}; - -const expected = [ - "objects", - "other" -]; - -const shallowSize = 10; - -function run_test() { - assertLabelAndShallowSize(breakdown, description, shallowSize, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js deleted file mode 100644 index ad35dcec1..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can generate label structures from node description reports. - -const breakdown = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -const description = { - objects: { - other: { count: 0, bytes: 0 } - }, - strings: { - "JSString": { count: 1, bytes: 42 }, - }, - scripts: {}, - other: {} -}; - -const expected = [ - "strings", - "JSString" -]; - -const shallowSize = 42; - -function run_test() { - assertLabelAndShallowSize(breakdown, description, shallowSize, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js deleted file mode 100644 index 566ad0dab..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js +++ /dev/null @@ -1,53 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can generate label structures from node description reports. - -const breakdown = { - by: "coarseType", - objects: { - by: "objectClass", - then: { - by: "allocationStack", - then: { by: "count", count: true, bytes: true }, - noStack: { by: "count", count: true, bytes: true }, - }, - other: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -const stack = saveStack(); - -const description = { - objects: { - Array: new Map([[stack, { count: 1, bytes: 512 }]]), - other: { count: 0, bytes: 0 } - }, - strings: {}, - scripts: {}, - other: {} -}; - -const expected = [ - "objects", - "Array", - stack -]; - -const shallowSize = 512; - -function run_test() { - assertLabelAndShallowSize(breakdown, description, shallowSize, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js deleted file mode 100644 index 24e8e2eb5..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js +++ /dev/null @@ -1,132 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// Test that the DominatorTreeNode.attachShortestPaths function can correctly -// attach the deduplicated shortest retaining paths for each node it is given. - -const startNodeId = 9999; -const maxNumPaths = 2; - -// Mock data mapping node id to shortest paths to that node id. -const shortestPaths = new Map([ - [1000, [ - [pathEntry(1100, "a"), pathEntry(1200, "b")], - [pathEntry(1100, "c"), pathEntry(1300, "d")], - ]], - [2000, [ - [pathEntry(2100, "e"), pathEntry(2200, "f"), pathEntry(2300, "g")] - ]], - [3000, [ - [pathEntry(3100, "h")], - [pathEntry(3100, "i")], - [pathEntry(3100, "j")], - [pathEntry(3200, "k")], - [pathEntry(3300, "l")], - [pathEntry(3400, "m")], - ]], -]); - -const actual = [ - makeTestDominatorTreeNode({ nodeId: 1000 }), - makeTestDominatorTreeNode({ nodeId: 2000 }), - makeTestDominatorTreeNode({ nodeId: 3000 }), -]; - -const expected = [ - makeTestDominatorTreeNode({ - nodeId: 1000, - shortestPaths: { - nodes: [ - { id: 1000, label: ["SomeType-1000"] }, - { id: 1100, label: ["SomeType-1100"] }, - { id: 1200, label: ["SomeType-1200"] }, - { id: 1300, label: ["SomeType-1300"] }, - ], - edges: [ - { from: 1100, to: 1200, name: "a" }, - { from: 1100, to: 1300, name: "c" }, - { from: 1200, to: 1000, name: "b" }, - { from: 1300, to: 1000, name: "d" }, - ] - } - }), - - makeTestDominatorTreeNode({ - nodeId: 2000, - shortestPaths: { - nodes: [ - { id: 2000, label: ["SomeType-2000"] }, - { id: 2100, label: ["SomeType-2100"] }, - { id: 2200, label: ["SomeType-2200"] }, - { id: 2300, label: ["SomeType-2300"] }, - ], - edges: [ - { from: 2100, to: 2200, name: "e" }, - { from: 2200, to: 2300, name: "f" }, - { from: 2300, to: 2000, name: "g" }, - ] - } - }), - - makeTestDominatorTreeNode({ nodeId: 3000, - shortestPaths: { - nodes: [ - { id: 3000, label: ["SomeType-3000"] }, - { id: 3100, label: ["SomeType-3100"] }, - { id: 3200, label: ["SomeType-3200"] }, - { id: 3300, label: ["SomeType-3300"] }, - { id: 3400, label: ["SomeType-3400"] }, - ], - edges: [ - { from: 3100, to: 3000, name: "h" }, - { from: 3100, to: 3000, name: "i" }, - { from: 3100, to: 3000, name: "j" }, - { from: 3200, to: 3000, name: "k" }, - { from: 3300, to: 3000, name: "l" }, - { from: 3400, to: 3000, name: "m" }, - ] - } - }), -]; - -const breakdown = { - by: "internalType", - then: { by: "count", count: true, bytes: true } -}; - -const mockSnapshot = { - computeShortestPaths: (start, nodeIds, max) => { - equal(start, startNodeId); - equal(max, maxNumPaths); - - return new Map(nodeIds.map(nodeId => { - const paths = shortestPaths.get(nodeId); - ok(paths, "Expected computeShortestPaths call for node id = " + nodeId); - return [nodeId, paths]; - })); - }, - - describeNode: (bd, nodeId) => { - equal(bd, breakdown); - return { - ["SomeType-" + nodeId]: { - count: 1, - bytes: 10, - } - }; - }, -}; - -function run_test() { - DominatorTreeNode.attachShortestPaths(mockSnapshot, - breakdown, - startNodeId, - actual, - maxNumPaths); - - dumpn("Expected = " + JSON.stringify(expected, null, 2)); - dumpn("Actual = " + JSON.stringify(actual, null, 2)); - - assertStructurallyEquivalent(expected, actual); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js deleted file mode 100644 index de2907809..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js +++ /dev/null @@ -1,44 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can find the node with the given id along the specified path. - -const node3000 = makeTestDominatorTreeNode({ nodeId: 3000 }); - -const node2000 = makeTestDominatorTreeNode({ nodeId: 2000 }, [ - makeTestDominatorTreeNode({}), - node3000, - makeTestDominatorTreeNode({}), -]); - -const node1000 = makeTestDominatorTreeNode({ nodeId: 1000 }, [ - makeTestDominatorTreeNode({}), - node2000, - makeTestDominatorTreeNode({}), -]); - -const tree = node1000; - -const path = [1000, 2000, 3000]; - -const tests = [ - { id: 1000, expected: node1000 }, - { id: 2000, expected: node2000 }, - { id: 3000, expected: node3000 }, -]; - -function run_test() { - for (let { id, expected } of tests) { - const actual = DominatorTreeNode.getNodeByIdAlongPath(id, tree, path); - equal(actual, expected, `We should have got the node with id = ${id}`); - } - - equal(null, - DominatorTreeNode.getNodeByIdAlongPath(999999999999, tree, path), - "null is returned for nodes that are not even in the tree"); - - const lastNodeId = tree.children[tree.children.length - 1].nodeId; - equal(null, - DominatorTreeNode.getNodeByIdAlongPath(lastNodeId, tree, path), - "null is returned for nodes that are not along the path"); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js deleted file mode 100644 index 979232ff4..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js +++ /dev/null @@ -1,112 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can insert new children into an existing DominatorTreeNode tree. - -const tree = makeTestDominatorTreeNode({ nodeId: 1000 }, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({ nodeId: 2000 }, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({ nodeId: 3000 }), - makeTestDominatorTreeNode({}), - ]), - makeTestDominatorTreeNode({}), -]); - -const path = [1000, 2000, 3000]; - -const newChildren = [ - makeTestDominatorTreeNode({ parentId: 3000 }), - makeTestDominatorTreeNode({ parentId: 3000 }), -]; - -const moreChildrenAvailable = false; - -const expected = { - nodeId: 1000, - parentId: undefined, - label: undefined, - shallowSize: 1, - retainedSize: 7, - children: [ - { - nodeId: 0, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 1000, - moreChildrenAvailable: true, - children: undefined, - }, - { - nodeId: 2000, - label: undefined, - shallowSize: 1, - retainedSize: 4, - parentId: 1000, - children: [ - { - nodeId: 1, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 2000, - moreChildrenAvailable: true, - children: undefined, - }, - { - nodeId: 3000, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 2000, - children: [ - { - nodeId: 7, - parentId: 3000, - label: undefined, - shallowSize: 1, - retainedSize: 1, - moreChildrenAvailable: true, - children: undefined, - }, - { - nodeId: 8, - parentId: 3000, - label: undefined, - shallowSize: 1, - retainedSize: 1, - moreChildrenAvailable: true, - children: undefined, - }, - ], - moreChildrenAvailable: false - }, - { - nodeId: 3, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 2000, - moreChildrenAvailable: true, - children: undefined, - }, - ], - moreChildrenAvailable: true - }, - { - nodeId: 5, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 1000, - moreChildrenAvailable: true, - children: undefined, - } - ], - moreChildrenAvailable: true -}; - -function run_test() { - assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js deleted file mode 100644 index 9a8d11d0b..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js +++ /dev/null @@ -1,30 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test attempting to insert new children into an existing DominatorTreeNode -// tree with a bad path. - -const tree = makeTestDominatorTreeNode({}, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}), - ]), - makeTestDominatorTreeNode({}), -]); - -const path = [111111, 222222, 333333]; - -const newChildren = [ - makeTestDominatorTreeNode({ parentId: 333333 }), - makeTestDominatorTreeNode({ parentId: 333333 }), -]; - -const moreChildrenAvailable = false; - -const expected = tree; - -function run_test() { - assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js deleted file mode 100644 index f8cb5eec3..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js +++ /dev/null @@ -1,117 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test inserting new children into an existing DominatorTreeNode at the root. - -const tree = makeTestDominatorTreeNode({ nodeId: 666 }, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}, [ - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}), - makeTestDominatorTreeNode({}), - ]), - makeTestDominatorTreeNode({}), -]); - -const path = [666]; - -const newChildren = [ - makeTestDominatorTreeNode({ - nodeId: 777, - parentId: 666 - }), - makeTestDominatorTreeNode({ - nodeId: 888, - parentId: 666 - }), -]; - -const moreChildrenAvailable = false; - -const expected = { - nodeId: 666, - label: undefined, - parentId: undefined, - shallowSize: 1, - retainedSize: 7, - children: [ - { - nodeId: 0, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 666, - moreChildrenAvailable: true, - children: undefined - }, - { - nodeId: 4, - label: undefined, - shallowSize: 1, - retainedSize: 4, - parentId: 666, - children: [ - { - nodeId: 1, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 4, - moreChildrenAvailable: true, - children: undefined - }, - { - nodeId: 2, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 4, - moreChildrenAvailable: true, - children: undefined - }, - { - nodeId: 3, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 4, - moreChildrenAvailable: true, - children: undefined - } - ], - moreChildrenAvailable: true - }, - { - nodeId: 5, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 666, - moreChildrenAvailable: true, - children: undefined - }, - { - nodeId: 777, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 666, - moreChildrenAvailable: true, - children: undefined - }, - { - nodeId: 888, - label: undefined, - shallowSize: 1, - retainedSize: 1, - parentId: 666, - moreChildrenAvailable: true, - children: undefined - } - ], - moreChildrenAvailable: false -}; - -function run_test() { - assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js deleted file mode 100644 index 78ec47b64..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js +++ /dev/null @@ -1,164 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we correctly set `moreChildrenAvailable` when doing a partial -// traversal of a dominator tree to create the initial incrementally loaded -// `DominatorTreeNode` tree. - -// `tree` maps parent to children: -// -// 100 -// |- 200 -// | |- 500 -// | |- 600 -// | `- 700 -// |- 300 -// | |- 800 -// | |- 900 -// `- 400 -// |- 1000 -// |- 1100 -// `- 1200 -const tree = new Map([ - [100, [200, 300, 400]], - [200, [500, 600, 700]], - [300, [800, 900]], - [400, [1000, 1100, 1200]] -]); - -const mockDominatorTree = { - root: 100, - getRetainedSize: _ => 10, - getImmediatelyDominated: id => (tree.get(id) || []).slice() -}; - -const mockSnapshot = { - describeNode: _ => ({ - objects: { count: 0, bytes: 0 }, - strings: { count: 0, bytes: 0 }, - scripts: { count: 0, bytes: 0 }, - other: { SomeType: { count: 1, bytes: 10 } } - }) -}; - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true } - }, -}; - -const expected = { - nodeId: 100, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - shortestPaths: undefined, - children: [ - { - nodeId: 200, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 100, - shortestPaths: undefined, - children: [ - { - nodeId: 500, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 200, - moreChildrenAvailable: false, - shortestPaths: undefined, - children: undefined - }, - { - nodeId: 600, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 200, - moreChildrenAvailable: false, - shortestPaths: undefined, - children: undefined - } - ], - moreChildrenAvailable: true - }, - { - nodeId: 300, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 100, - shortestPaths: undefined, - children: [ - { - nodeId: 800, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 300, - moreChildrenAvailable: false, - shortestPaths: undefined, - children: undefined - }, - { - nodeId: 900, - label: [ - "other", - "SomeType" - ], - shallowSize: 10, - retainedSize: 10, - parentId: 300, - moreChildrenAvailable: false, - shortestPaths: undefined, - children: undefined - } - ], - moreChildrenAvailable: false - } - ], - moreChildrenAvailable: true, - parentId: undefined, -}; - -function run_test() { - // Traverse the whole depth of the test tree, but one short of the number of - // siblings. This will exercise the moreChildrenAvailable handling for - // siblings. - const actual = DominatorTreeNode.partialTraversal(mockDominatorTree, - mockSnapshot, - breakdown, - /* maxDepth = */ 4, - /* siblings = */ 2); - - dumpn("Expected = " + JSON.stringify(expected, null, 2)); - dumpn("Actual = " + JSON.stringify(actual, null, 2)); - - assertStructurallyEquivalent(expected, actual); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_01.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_01.js deleted file mode 100644 index e8145f658..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_01.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Sanity test that we can compute dominator trees. - -function run_test() { - const path = ChromeUtils.saveHeapSnapshot({ runtime: true }); - const snapshot = ChromeUtils.readHeapSnapshot(path); - - const dominatorTree = snapshot.computeDominatorTree(); - ok(dominatorTree); - ok(dominatorTree instanceof DominatorTree); - - let threw = false; - try { - new DominatorTree(); - } catch (e) { - threw = true; - } - ok(threw, "Constructor shouldn't be usable"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_02.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_02.js deleted file mode 100644 index a518f8a27..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_02.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can compute dominator trees from a snapshot in a worker. - -add_task(function* () { - const worker = new ChromeWorker("resource://test/dominator-tree-worker.js"); - worker.postMessage({}); - - let assertionCount = 0; - worker.onmessage = e => { - if (e.data.type !== "assertion") { - return; - } - - ok(e.data.passed, e.data.msg + "\n" + e.data.stack); - assertionCount++; - }; - - yield waitForDone(worker); - - ok(assertionCount > 0); - worker.terminate(); -}); - -function waitForDone(w) { - return new Promise((resolve, reject) => { - w.onerror = e => { - reject(); - ok(false, "Error in worker: " + e); - }; - - w.addEventListener("message", function listener(e) { - if (e.data.type === "done") { - w.removeEventListener("message", listener, false); - resolve(); - } - }, false); - }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_03.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_03.js deleted file mode 100644 index 0a14ce53d..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_03.js +++ /dev/null @@ -1,13 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can get the root of dominator trees. - -function run_test() { - const dominatorTree = saveHeapSnapshotAndComputeDominatorTree(); - equal(typeof dominatorTree.root, "number", "root should be a number"); - equal(Math.floor(dominatorTree.root), dominatorTree.root, "root should be an integer"); - ok(dominatorTree.root >= 0, "root should be positive"); - ok(dominatorTree.root <= Math.pow(2, 48), "root should be less than or equal to 2^48"); - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_04.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_04.js deleted file mode 100644 index e5aef3fec..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_04.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can get the retained sizes of dominator trees. - -function run_test() { - const dominatorTree = saveHeapSnapshotAndComputeDominatorTree(); - equal(typeof dominatorTree.getRetainedSize, "function", - "getRetainedSize should be a function"); - - const size = dominatorTree.getRetainedSize(dominatorTree.root); - ok(size, "should get a size for the root"); - equal(typeof size, "number", "retained sizes should be a number"); - equal(Math.floor(size), size, "size should be an integer"); - ok(size > 0, "size should be positive"); - ok(size <= Math.pow(2, 64), "size should be less than or equal to 2^64"); - - const bad = dominatorTree.getRetainedSize(1); - equal(bad, null, "null is returned for unknown node ids"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_05.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_05.js deleted file mode 100644 index c07cee994..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_05.js +++ /dev/null @@ -1,75 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can get the set of immediately dominated nodes for any given -// node and that this forms a tree. - -function run_test() { - var dominatorTree = saveHeapSnapshotAndComputeDominatorTree(); - equal(typeof dominatorTree.getImmediatelyDominated, "function", - "getImmediatelyDominated should be a function"); - - // Do a traversal of the dominator tree. - // - // Note that we don't assert directly, only if we get an unexpected - // value. There are just way too many nodes in the heap graph to assert for - // every one. This test would constantly time out and assertion messages would - // overflow the log size. - - var root = dominatorTree.root; - equal(dominatorTree.getImmediateDominator(root), null, - "The root should not have a parent"); - - var seen = new Set(); - var stack = [root]; - while (stack.length > 0) { - var top = stack.pop(); - - if (seen.has(top)) { - ok(false, - "This is a tree, not a graph: we shouldn't have multiple edges to the same node"); - } - seen.add(top); - if (seen.size % 1000 === 0) { - dumpn("Progress update: seen size = " + seen.size); - } - - var newNodes = dominatorTree.getImmediatelyDominated(top); - if (Object.prototype.toString.call(newNodes) !== "[object Array]") { - ok(false, "getImmediatelyDominated should return an array for known node ids"); - } - - var topSize = dominatorTree.getRetainedSize(top); - - var lastSize = Infinity; - for (var i = 0; i < newNodes.length; i++) { - if (typeof newNodes[i] !== "number") { - ok(false, "Every dominated id should be a number"); - } - - if (dominatorTree.getImmediateDominator(newNodes[i]) !== top) { - ok(false, "child's parent should be the expected parent"); - } - - var thisSize = dominatorTree.getRetainedSize(newNodes[i]); - - if (thisSize >= topSize) { - ok(false, "the size of children in the dominator tree should always be less than that of their parent"); - } - - if (thisSize > lastSize) { - ok(false, - "children should be sorted by greatest to least retained size, " - + "lastSize = " + lastSize + ", thisSize = " + thisSize); - } - - lastSize = thisSize; - stack.push(newNodes[i]); - } - } - - ok(true, "Successfully walked the tree"); - dumpn("Walked " + seen.size + " nodes"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_06.js b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_06.js deleted file mode 100644 index 680478623..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_DominatorTree_06.js +++ /dev/null @@ -1,56 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the retained size of a node is the sum of its children retained -// sizes plus its shallow size. - -// Note that we don't assert directly, only if we get an unexpected -// value. There are just way too many nodes in the heap graph to assert for -// every one. This test would constantly time out and assertion messages would -// overflow the log size. -function fastAssert(cond, msg) { - if (!cond) { - ok(false, msg); - } -} - -var COUNT = { by: "count", count: false, bytes: true }; - -function run_test() { - var path = saveNewHeapSnapshot(); - var snapshot = ChromeUtils.readHeapSnapshot(path); - var dominatorTree = snapshot.computeDominatorTree(); - - // Do a traversal of the dominator tree and assert the relationship between - // retained size, shallow size, and children's retained sizes. - - var root = dominatorTree.root; - var stack = [root]; - while (stack.length > 0) { - var top = stack.pop(); - - var children = dominatorTree.getImmediatelyDominated(top); - - var topRetainedSize = dominatorTree.getRetainedSize(top); - var topShallowSize = snapshot.describeNode(COUNT, top).bytes; - fastAssert(topShallowSize <= topRetainedSize, - "The shallow size should be less than or equal to the " + - "retained size"); - - var sumOfChildrensRetainedSizes = 0; - for (var i = 0; i < children.length; i++) { - sumOfChildrensRetainedSizes += dominatorTree.getRetainedSize(children[i]); - stack.push(children[i]); - } - - fastAssert(sumOfChildrensRetainedSizes <= topRetainedSize, - "The sum of the children's retained sizes should be less than " + - "or equal to the retained size"); - fastAssert(sumOfChildrensRetainedSizes + topShallowSize === topRetainedSize, - "The sum of the children's retained sizes plus the shallow " + - "size should be equal to the retained size"); - } - - ok(true, "Successfully walked the tree"); - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js deleted file mode 100644 index 0114e0b69..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - equal(typeof dominatorTreeId, "number", - "should get a dominator tree id, and it should be a number"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js deleted file mode 100644 index 6e3f5b257..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request with bad -// file paths. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - let threw = false; - try { - yield client.computeDominatorTree("/etc/passwd"); - } catch (_) { - threw = true; - } - ok(threw, "should throw when given a bad path"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js deleted file mode 100644 index 7708de93c..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can delete heap snapshots. - -function run_test() { - run_next_test(); -} - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - let dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - ok(true, "Should have computed the dominator tree"); - - yield client.deleteHeapSnapshot(snapshotFilePath); - ok(true, "Should have deleted the snapshot"); - - let threw = false; - try { - yield client.getDominatorTree({ - dominatorTreeId: dominatorTreeId, - breakdown - }); - } catch (_) { - threw = true; - } - ok(threw, "getDominatorTree on deleted tree should throw an error"); - - threw = false; - try { - yield client.computeDominatorTree(snapshotFilePath); - } catch (_) { - threw = true; - } - ok(threw, "computeDominatorTree on deleted snapshot should throw an error"); - - threw = false; - try { - yield client.takeCensus(snapshotFilePath); - } catch (_) { - threw = true; - } - ok(threw, "takeCensus on deleted tree should throw an error"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js deleted file mode 100644 index 3e25ddac4..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test deleteHeapSnapshot is a noop if the provided path matches no snapshot - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - let threw = false; - try { - yield client.deleteHeapSnapshot("path-does-not-exist"); - } catch (_) { - threw = true; - } - ok(threw, "deleteHeapSnapshot on non-existant path should throw an error"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js deleted file mode 100644 index e648c9407..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js +++ /dev/null @@ -1,62 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test other dominatorTrees can still be retrieved after deleting a snapshot - -function run_test() { - run_next_test(); -} - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -function* createSnapshotAndDominatorTree(client) { - let snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - let dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - return { dominatorTreeId, snapshotFilePath }; -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - let savedSnapshots = [ - yield createSnapshotAndDominatorTree(client), - yield createSnapshotAndDominatorTree(client), - yield createSnapshotAndDominatorTree(client) - ]; - ok(true, "Create 3 snapshots and dominator trees"); - - yield client.deleteHeapSnapshot(savedSnapshots[1].snapshotFilePath); - ok(true, "Snapshot deleted"); - - let tree = yield client.getDominatorTree({ - dominatorTreeId: savedSnapshots[0].dominatorTreeId, - breakdown - }); - ok(tree, "Should get a valid tree for first snapshot"); - - let threw = false; - try { - yield client.getDominatorTree({ - dominatorTreeId: savedSnapshots[1].dominatorTreeId, - breakdown - }); - } catch (_) { - threw = true; - } - ok(threw, "getDominatorTree on a deleted snapshot should throw an error"); - - tree = yield client.getDominatorTree({ - dominatorTreeId: savedSnapshots[2].dominatorTreeId, - breakdown - }); - ok(tree, "Should get a valid tree for third snapshot"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js deleted file mode 100644 index b63ad4230..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can get census individuals. - -function run_test() { - run_next_test(); -} - -const COUNT = { by: "count", count: true, bytes: true }; - -const CENSUS_BREAKDOWN = { - by: "coarseType", - objects: COUNT, - strings: COUNT, - scripts: COUNT, - other: COUNT, -}; - -const LABEL_BREAKDOWN = { - by: "internalType", - then: COUNT, -}; - -const MAX_INDIVIDUALS = 10; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - ok(true, "Should have computed dominator tree"); - - const { report } = yield client.takeCensus(snapshotFilePath, - { breakdown: CENSUS_BREAKDOWN }, - { asTreeNode: true }); - ok(report, "Should get a report"); - - let nodesWithLeafIndicesFound = 0; - - yield* (function* assertCanGetIndividuals(censusNode) { - if (censusNode.reportLeafIndex !== undefined) { - nodesWithLeafIndicesFound++; - - const response = yield client.getCensusIndividuals({ - dominatorTreeId, - indices: DevToolsUtils.isSet(censusNode.reportLeafIndex) - ? censusNode.reportLeafIndex - : new Set([censusNode.reportLeafIndex]), - censusBreakdown: CENSUS_BREAKDOWN, - labelBreakdown: LABEL_BREAKDOWN, - maxRetainingPaths: 1, - maxIndividuals: MAX_INDIVIDUALS, - }); - - dumpn(`response = ${JSON.stringify(response, null, 4)}`); - - equal(response.nodes.length, Math.min(MAX_INDIVIDUALS, censusNode.count), - "response.nodes.length === Math.min(MAX_INDIVIDUALS, censusNode.count)"); - - let lastRetainedSize = Infinity; - for (let individual of response.nodes) { - equal(typeof individual.nodeId, "number", - "individual.nodeId should be a number"); - ok(individual.retainedSize <= lastRetainedSize, - "individual.retainedSize <= lastRetainedSize"); - lastRetainedSize = individual.retainedSize; - ok(individual.shallowSize, "individual.shallowSize should exist and be non-zero"); - ok(individual.shortestPaths, "individual.shortestPaths should exist"); - ok(individual.shortestPaths.nodes, "individual.shortestPaths.nodes should exist"); - ok(individual.shortestPaths.edges, "individual.shortestPaths.edges should exist"); - ok(individual.label, "individual.label should exist"); - } - } - - if (censusNode.children) { - for (let child of censusNode.children) { - yield* assertCanGetIndividuals(child); - } - } - }(report)); - - equal(nodesWithLeafIndicesFound, 4, "Should have found a leaf for each coarse type"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js deleted file mode 100644 index 5df79de7a..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js +++ /dev/null @@ -1,58 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can get a HeapSnapshot's -// creation time. - -function waitForThirtyMilliseconds() { - const start = Date.now(); - while (Date.now() - start < 30) ; -} - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "internalType", - then: { by: "count", count: true, bytes: true } -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - const start = Date.now() * 1000; - - // Because Date.now() is less precise than the snapshot's time stamp, give it - // a little bit of head room. Additionally, WinXP's timers have a granularity - // of only +/-15 ms. - waitForThirtyMilliseconds(); - const snapshotFilePath = saveNewHeapSnapshot(); - waitForThirtyMilliseconds(); - const end = Date.now() * 1000; - - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - let threw = false; - try { - yield client.getCreationTime("/not/a/real/path", { - breakdown: BREAKDOWN - }); - } catch (_) { - threw = true; - } - ok(threw, "getCreationTime should throw when snapshot does not exist"); - - let time = yield client.getCreationTime(snapshotFilePath, { - breakdown: BREAKDOWN - }); - - dumpn("Start = " + start); - dumpn("End = " + end); - dumpn("Time = " + time); - - ok(time >= start, "creation time occurred after start"); - ok(time <= end, "creation time occurred before end"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js deleted file mode 100644 index cedea5375..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js +++ /dev/null @@ -1,69 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request. - -function run_test() { - run_next_test(); -} - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - equal(typeof dominatorTreeId, "number", - "should get a dominator tree id, and it should be a number"); - - const partialTree = yield client.getDominatorTree({ - dominatorTreeId, - breakdown - }); - ok(partialTree, "Should get a partial tree"); - equal(typeof partialTree, "object", - "partialTree should be an object"); - - function checkTree(node) { - equal(typeof node.nodeId, "number", "each node should have an id"); - - if (node === partialTree) { - equal(node.parentId, undefined, "the root has no parent"); - } else { - equal(typeof node.parentId, "number", "each node should have a parent id"); - } - - equal(typeof node.retainedSize, "number", - "each node should have a retained size"); - - ok(node.children === undefined || Array.isArray(node.children), - "each node either has a list of children, or undefined meaning no children loaded"); - equal(typeof node.moreChildrenAvailable, "boolean", - "each node should indicate if there are more children available or not"); - - equal(typeof node.shortestPaths, "object", - "Should have shortest paths"); - equal(typeof node.shortestPaths.nodes, "object", - "Should have shortest paths' nodes"); - equal(typeof node.shortestPaths.edges, "object", - "Should have shortest paths' edges"); - - if (node.children) { - node.children.forEach(checkTree); - } - } - - checkTree(partialTree); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js deleted file mode 100644 index fd29beece..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js +++ /dev/null @@ -1,31 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request with bad -// dominator tree ids. - -function run_test() { - run_next_test(); -} - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - let threw = false; - try { - yield client.getDominatorTree({ dominatorTreeId: 42, breakdown }); - } catch (_) { - threw = true; - } - ok(threw, "should throw when given a bad id"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js deleted file mode 100644 index caf1c2056..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js +++ /dev/null @@ -1,81 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the HeapAnalyses{Client,Worker} "getImmediatelyDominated" request. - -function run_test() { - run_next_test(); -} - -const breakdown = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath); - - const partialTree = yield client.getDominatorTree({ - dominatorTreeId, - breakdown - }); - ok(partialTree.children.length > 0, - "root should immediately dominate some nodes"); - - // First, test getting a subset of children available. - const response = yield client.getImmediatelyDominated({ - dominatorTreeId, - breakdown, - nodeId: partialTree.nodeId, - startIndex: 0, - maxCount: partialTree.children.length - 1 - }); - - ok(Array.isArray(response.nodes)); - ok(response.nodes.every(node => node.parentId === partialTree.nodeId)); - ok(response.moreChildrenAvailable); - equal(response.path.length, 1); - equal(response.path[0], partialTree.nodeId); - - for (let node of response.nodes) { - equal(typeof node.shortestPaths, "object", - "Should have shortest paths"); - equal(typeof node.shortestPaths.nodes, "object", - "Should have shortest paths' nodes"); - equal(typeof node.shortestPaths.edges, "object", - "Should have shortest paths' edges"); - } - - // Next, test getting a subset of children available. - const secondResponse = yield client.getImmediatelyDominated({ - dominatorTreeId, - breakdown, - nodeId: partialTree.nodeId, - startIndex: 0, - maxCount: Infinity - }); - - ok(Array.isArray(secondResponse.nodes)); - ok(secondResponse.nodes.every(node => node.parentId === partialTree.nodeId)); - ok(!secondResponse.moreChildrenAvailable); - equal(secondResponse.path.length, 1); - equal(secondResponse.path[0], partialTree.nodeId); - - for (let node of secondResponse.nodes) { - equal(typeof node.shortestPaths, "object", - "Should have shortest paths"); - equal(typeof node.shortestPaths.nodes, "object", - "Should have shortest paths' nodes"); - equal(typeof node.shortestPaths.edges, "object", - "Should have shortest paths' edges"); - } - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js deleted file mode 100644 index 0d0d58bef..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js +++ /dev/null @@ -1,18 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can read heap snapshots. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js deleted file mode 100644 index 6f22cbad3..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js +++ /dev/null @@ -1,54 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses. - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "objectClass", - then: { by: "count", count: true, bytes: false }, - other: { by: "count", count: true, bytes: false }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const markers = [allocationMarker()]; - - const firstSnapshotFilePath = saveNewHeapSnapshot(); - - // Allocate and hold an additional AllocationMarker object so we can see it in - // the next heap snapshot. - markers.push(allocationMarker()); - - const secondSnapshotFilePath = saveNewHeapSnapshot(); - - yield client.readHeapSnapshot(firstSnapshotFilePath); - yield client.readHeapSnapshot(secondSnapshotFilePath); - ok(true, "Should have read both heap snapshot files"); - - const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath, - secondSnapshotFilePath, - { breakdown: BREAKDOWN }); - - equal(delta.AllocationMarker.count, 1, - "There exists one new AllocationMarker in the second heap snapshot"); - - const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath, - secondSnapshotFilePath, - { breakdown: BREAKDOWN }, - { asTreeNode: true }); - - // Have to manually set these because symbol properties aren't structured - // cloned. - delta[CensusUtils.basisTotalBytes] = deltaTreeNode.totalBytes; - delta[CensusUtils.basisTotalCount] = deltaTreeNode.totalCount; - - compareCensusViewData(BREAKDOWN, delta, deltaTreeNode, - "Returning delta-census as a tree node represents same data as the report"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js deleted file mode 100644 index f1ba9ce84..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses as -// inverted trees. - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -add_task(function* () { - const firstSnapshotFilePath = saveNewHeapSnapshot(); - const secondSnapshotFilePath = saveNewHeapSnapshot(); - - const client = new HeapAnalysesClient(); - yield client.readHeapSnapshot(firstSnapshotFilePath); - yield client.readHeapSnapshot(secondSnapshotFilePath); - - ok(true, "Should have read both heap snapshot files"); - - const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath, - secondSnapshotFilePath, - { breakdown: BREAKDOWN }); - - const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath, - secondSnapshotFilePath, - { breakdown: BREAKDOWN }, - { asInvertedTreeNode: true }); - - // Have to manually set these because symbol properties aren't structured - // cloned. - delta[CensusUtils.basisTotalBytes] = deltaTreeNode.totalBytes; - delta[CensusUtils.basisTotalCount] = deltaTreeNode.totalCount; - - compareCensusViewData(BREAKDOWN, delta, deltaTreeNode, { invert: true }); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js deleted file mode 100644 index e26981db4..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js +++ /dev/null @@ -1,27 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take censuses. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const { report } = yield client.takeCensus(snapshotFilePath); - ok(report, "Should get a report"); - equal(typeof report, "object", "report should be an object"); - - ok(report.objects); - ok(report.scripts); - ok(report.strings); - ok(report.other); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js deleted file mode 100644 index 34494af70..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js +++ /dev/null @@ -1,29 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take censuses with breakdown -// options. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const { report } = yield client.takeCensus(snapshotFilePath, { - breakdown: { by: "count", count: true, bytes: true } - }); - - ok(report, "Should get a report"); - equal(typeof report, "object", "report should be an object"); - - ok(report.count); - ok(report.bytes); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js deleted file mode 100644 index 486e250b5..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js +++ /dev/null @@ -1,48 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} bubbles errors properly when things -// go wrong. - -function run_test() { - run_next_test(); -} - -add_task(function* () { - const client = new HeapAnalysesClient(); - - // Snapshot file path to a file that doesn't exist. - let failed = false; - try { - yield client.readHeapSnapshot(getFilePath("foo-bar-baz" + Math.random(), true)); - } catch (e) { - failed = true; - } - ok(failed, "should not read heap snapshots that do not exist"); - - // Snapshot file path to a file that is not a heap snapshot. - failed = false; - try { - yield client.readHeapSnapshot(getFilePath("test_HeapAnalyses_takeCensus_03.js")); - } catch (e) { - failed = true; - } - ok(failed, "should not be able to read a file that is not a heap snapshot as a heap snapshot"); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - // Bad census breakdown options. - failed = false; - try { - yield client.takeCensus(snapshotFilePath, { - breakdown: { by: "some classification that we do not have" } - }); - } catch (e) { - failed = true; - } - ok(failed, "should not be able to breakdown by an unknown classification"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js deleted file mode 100644 index 769a2d99d..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js +++ /dev/null @@ -1,118 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from -// by-allocation-stack reports from the worker. - -function run_test() { - run_next_test(); -} - -add_task(function* test() { - const client = new HeapAnalysesClient(); - - // Track some allocation stacks. - - const g = newGlobal(); - const dbg = new Debugger(g); - g.eval(` // 1 - this.log = []; // 2 - function f() { this.log.push(allocationMarker()); } // 3 - function g() { this.log.push(allocationMarker()); } // 4 - function h() { this.log.push(allocationMarker()); } // 5 - `); // 6 - - // Create one allocationMarker with tracking turned off, - // so it will have no associated stack. - g.f(); - - dbg.memory.allocationSamplingProbability = 1; - - for (let [func, n] of [ [g.f, 20], - [g.g, 10], - [g.h, 5] ]) { - for (let i = 0; i < n; i++) { - dbg.memory.trackingAllocationSites = true; - // All allocations of allocationMarker occur with this line as the oldest - // stack frame. - func(); - dbg.memory.trackingAllocationSites = false; - } - } - - // Take a heap snapshot. - - const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg }); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - // Run a census broken down by class name -> allocation stack so we can grab - // only the AllocationMarker objects we have complete control over. - - const { report } = yield client.takeCensus(snapshotFilePath, { - breakdown: { by: "objectClass", - then: { by: "allocationStack", - then: { by: "count", - bytes: true, - count: true - }, - noStack: { by: "count", - bytes: true, - count: true - } - } - } - }); - - // Test the generated report. - - ok(report, "Should get a report"); - - const map = report.AllocationMarker; - ok(map, "Should get AllocationMarkers in the report."); - // From a module with a different global, and therefore a different Map - // constructor, so we can't use instanceof. - equal(map.__proto__.constructor.name, "Map"); - - equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)"); - - // Gather the stacks we are expecting to appear as keys, and - // check that there are no unexpected keys. - let stacks = {}; - - map.forEach((v, k) => { - if (k === "noStack") { - // No need to save this key. - } else if (k.functionDisplayName === "f" && - k.parent.functionDisplayName === "test") { - stacks.f = k; - } else if (k.functionDisplayName === "g" && - k.parent.functionDisplayName === "test") { - stacks.g = k; - } else if (k.functionDisplayName === "h" && - k.parent.functionDisplayName === "test") { - stacks.h = k; - } else { - dumpn("Unexpected allocation stack:"); - k.toString().split(/\n/g).forEach(s => dumpn(s)); - ok(false); - } - }); - - ok(map.get("noStack")); - equal(map.get("noStack").count, 1); - - ok(stacks.f); - ok(map.get(stacks.f)); - equal(map.get(stacks.f).count, 20); - - ok(stacks.g); - ok(map.get(stacks.g)); - equal(map.get(stacks.g).count, 10); - - ok(stacks.h); - ok(map.get(stacks.h)); - equal(map.get(stacks.h).count, 5); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js deleted file mode 100644 index 7e16d9f00..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js +++ /dev/null @@ -1,44 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take censuses and return -// a CensusTreeNode. - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "internalType", - then: { by: "count", count: true, bytes: true } -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const { report } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }); - - const { report: treeNode } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }, { - asTreeNode: true - }); - - ok(treeNode.children.length > 0, "treeNode has children"); - ok(treeNode.children.every(type => { - return "name" in type && - "bytes" in type && - "count" in type; - }), "all of tree node's children have name, bytes, count"); - - compareCensusViewData(BREAKDOWN, report, treeNode, - "Returning census as a tree node represents same data as the report"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js deleted file mode 100644 index 7795a9700..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js +++ /dev/null @@ -1,109 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take censuses by -// "allocationStack" and return a CensusTreeNode. - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "objectClass", - then: { - by: "allocationStack", - then: { by: "count", count: true, bytes: true }, - noStack: { by: "count", count: true, bytes: true } - }, - other: { by: "count", count: true, bytes: true } -}; - -add_task(function* () { - const g = newGlobal(); - const dbg = new Debugger(g); - - // 5 allocation markers with no stack. - g.eval(` - this.markers = []; - for (var i = 0; i < 5; i++) { - markers.push(allocationMarker()); - } - `); - - dbg.memory.allocationSamplingProbability = 1; - dbg.memory.trackingAllocationSites = true; - - // 5 allocation markers at 5 stacks. - g.eval(` - (function shouldHaveCountOfOne() { - markers.push(allocationMarker()); - markers.push(allocationMarker()); - markers.push(allocationMarker()); - markers.push(allocationMarker()); - markers.push(allocationMarker()); - }()); - `); - - // 5 allocation markers at 1 stack. - g.eval(` - (function shouldHaveCountOfFive() { - for (var i = 0; i < 5; i++) { - markers.push(allocationMarker()); - } - }()); - `); - - const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg }); - - const client = new HeapAnalysesClient(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const { report } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }); - - const { report: treeNode } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }, { - asTreeNode: true - }); - - const markers = treeNode.children.find(c => c.name === "AllocationMarker"); - ok(markers); - - const noStack = markers.children.find(c => c.name === "noStack"); - equal(noStack.count, 5); - - let numShouldHaveFiveFound = 0; - let numShouldHaveOneFound = 0; - - function walk(node) { - if (node.children) { - node.children.forEach(walk); - } - - if (!isSavedFrame(node.name)) { - return; - } - - if (node.name.functionDisplayName === "shouldHaveCountOfFive") { - equal(node.count, 5, "shouldHaveCountOfFive should have count of five"); - numShouldHaveFiveFound++; - } - - if (node.name.functionDisplayName === "shouldHaveCountOfOne") { - equal(node.count, 1, "shouldHaveCountOfOne should have count of one"); - numShouldHaveOneFound++; - } - } - markers.children.forEach(walk); - - equal(numShouldHaveFiveFound, 1); - equal(numShouldHaveOneFound, 5); - - compareCensusViewData(BREAKDOWN, report, treeNode, - "Returning census as a tree node represents same data as the report"); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js deleted file mode 100644 index 986b3aaa8..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js +++ /dev/null @@ -1,52 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the HeapAnalyses{Client,Worker} can take censuses and return -// an inverted CensusTreeNode. - -function run_test() { - run_next_test(); -} - -const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, -}; - -add_task(function* () { - const client = new HeapAnalysesClient(); - - const snapshotFilePath = saveNewHeapSnapshot(); - yield client.readHeapSnapshot(snapshotFilePath); - ok(true, "Should have read the heap snapshot"); - - const { report } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }); - - const { report: treeNode } = yield client.takeCensus(snapshotFilePath, { - breakdown: BREAKDOWN - }, { - asInvertedTreeNode: true - }); - - compareCensusViewData(BREAKDOWN, report, treeNode, { invert: true }); - - client.destroy(); -}); diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js deleted file mode 100644 index 2ec577bd0..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js +++ /dev/null @@ -1,69 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Sanity test that we can compute shortest paths. -// -// Because the actual heap graph is too unpredictable and likely to drastically -// change as various implementation bits change, we don't test exact paths -// here. See js/src/jsapi-tests/testUbiNode.cpp for such tests, where we can -// control the specific graph shape and structure and so testing exact paths is -// reliable. - -function run_test() { - const path = ChromeUtils.saveHeapSnapshot({ runtime: true }); - const snapshot = ChromeUtils.readHeapSnapshot(path); - - const dominatorTree = snapshot.computeDominatorTree(); - const dominatedByRoot = dominatorTree.getImmediatelyDominated(dominatorTree.root) - .slice(0, 10); - ok(dominatedByRoot); - ok(dominatedByRoot.length); - - const targetSet = new Set(dominatedByRoot); - - const shortestPaths = snapshot.computeShortestPaths(dominatorTree.root, dominatedByRoot, 2); - ok(shortestPaths); - ok(shortestPaths instanceof Map); - ok(shortestPaths.size === targetSet.size); - - for (let [target, paths] of shortestPaths) { - ok(targetSet.has(target), - "We should only get paths for our targets"); - targetSet.delete(target); - - ok(paths.length > 0, - "We must have at least one path, since the target is dominated by the root"); - ok(paths.length <= 2, - "Should not have recorded more paths than the max requested"); - - dumpn("---------------------"); - dumpn("Shortest paths for 0x" + target.toString(16) + ":"); - for (let path of paths) { - dumpn(" path ="); - for (let part of path) { - dumpn(" predecessor: 0x" + part.predecessor.toString(16) + - "; edge: " + part.edge); - } - } - dumpn("---------------------"); - - for (let path of paths) { - ok(path.length > 0, "Cannot have zero length paths"); - ok(path[0].predecessor === dominatorTree.root, - "The first predecessor is always our start node"); - - for (let part of path) { - ok(part.predecessor, "Each part of a path has a predecessor"); - ok(!!snapshot.describeNode({ by: "count", count: true, bytes: true}, - part.predecessor), - "The predecessor is in the heap snapshot"); - ok("edge" in part, "Each part has an (potentially null) edge property"); - } - } - } - - ok(targetSet.size === 0, - "We found paths for all of our targets"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js deleted file mode 100644 index 04fe58733..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test computing shortest paths with invalid arguments. - -function run_test() { - const path = ChromeUtils.saveHeapSnapshot({ runtime: true }); - const snapshot = ChromeUtils.readHeapSnapshot(path); - - const dominatorTree = snapshot.computeDominatorTree(); - const target = dominatorTree.getImmediatelyDominated(dominatorTree.root).pop(); - ok(target); - - let threw = false; - try { - snapshot.computeShortestPaths(0, [target], 2); - } catch (_) { - threw = true; - } - ok(threw, "invalid start node should throw"); - - threw = false; - try { - snapshot.computeShortestPaths(dominatorTree.root, [0], 2); - } catch (_) { - threw = true; - } - ok(threw, "invalid target nodes should throw"); - - threw = false; - try { - snapshot.computeShortestPaths(dominatorTree.root, [], 2); - } catch (_) { - threw = true; - } - ok(threw, "empty target nodes should throw"); - - threw = false; - try { - snapshot.computeShortestPaths(dominatorTree.root, [target], 0); - } catch (_) { - threw = true; - } - ok(threw, "0 max paths should throw"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js deleted file mode 100644 index 0d08fea16..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js +++ /dev/null @@ -1,30 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.creationTime returns the expected time. - -function waitForThirtyMilliseconds() { - const start = Date.now(); - while (Date.now() - start < 30) ; -} - -function run_test() { - const start = Date.now() * 1000; - do_print("start = " + start); - - // Because Date.now() is less precise than the snapshot's time stamp, give it - // a little bit of head room. Additionally, WinXP's timer only has granularity - // of +/- 15ms. - waitForThirtyMilliseconds(); - const path = ChromeUtils.saveHeapSnapshot({ runtime: true }); - waitForThirtyMilliseconds(); - - const end = Date.now() * 1000; - do_print("end = " + end); - - const snapshot = ChromeUtils.readHeapSnapshot(path); - do_print("snapshot.creationTime = " + snapshot.creationTime); - - ok(snapshot.creationTime >= start); - ok(snapshot.creationTime <= end); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js deleted file mode 100644 index 9eb11d9af..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js +++ /dev/null @@ -1,70 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can save a core dump with very deep allocation stacks and read -// it back into a HeapSnapshot. - -function stackDepth(stack) { - return stack ? 1 + stackDepth(stack.parent) : 0; -} - -function run_test() { - // Create a Debugger observing a debuggee's allocations. - const debuggee = new Cu.Sandbox(null); - const dbg = new Debugger(debuggee); - dbg.memory.trackingAllocationSites = true; - - // Allocate some objects in the debuggee that will have their allocation - // stacks recorded by the Debugger. - - debuggee.eval("this.objects = []"); - debuggee.eval( - (function recursiveAllocate(n) { - if (n <= 0) - return; - - // Make sure to recurse before pushing the object so that when TCO is - // implemented sometime in the future, it doesn't invalidate this test. - recursiveAllocate(n - 1); - this.objects.push({}); - }).toString() - ); - debuggee.eval("recursiveAllocate = recursiveAllocate.bind(this);"); - debuggee.eval("recursiveAllocate(200);"); - - // Now save a snapshot that will include the allocation stacks and read it - // back again. - - const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true }); - ok(true, "Should be able to save a snapshot."); - - const snapshot = ChromeUtils.readHeapSnapshot(filePath); - ok(snapshot, "Should be able to read a heap snapshot"); - ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot"); - - const report = snapshot.takeCensus({ - breakdown: { by: "allocationStack", - then: { by: "count", bytes: true, count: true }, - noStack: { by: "count", bytes: true, count: true } - } - }); - - // Keep this synchronized with `HeapSnapshot::MAX_STACK_DEPTH`! - const MAX_STACK_DEPTH = 60; - - let foundStacks = false; - report.forEach((v, k) => { - if (k === "noStack") { - return; - } - - foundStacks = true; - const depth = stackDepth(k); - dumpn("Stack depth is " + depth); - ok(depth <= MAX_STACK_DEPTH, - "Every stack should have depth less than or equal to the maximum stack depth"); - }); - ok(foundStacks); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js deleted file mode 100644 index d79cb5a7b..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js +++ /dev/null @@ -1,42 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can describe nodes with a breakdown. - -function run_test() { - const path = saveNewHeapSnapshot(); - const snapshot = ChromeUtils.readHeapSnapshot(path); - ok(snapshot.describeNode); - equal(typeof snapshot.describeNode, "function"); - - const dt = snapshot.computeDominatorTree(); - - let threw = false; - try { - snapshot.describeNode(undefined, dt.root); - } catch (_) { - threw = true; - } - ok(threw, "Should require a breakdown"); - - const breakdown = { - by: "coarseType", - objects: { by: "objectClass" }, - scripts: { by: "internalType" }, - strings: { by: "internalType" }, - other: { by: "internalType" } - }; - - threw = false; - try { - snapshot.describeNode(breakdown, 0); - } catch (_) { - threw = true; - } - ok(threw, "Should throw when given an invalid node id"); - - const description = snapshot.describeNode(breakdown, dt.root); - ok(description); - ok(description.other); - ok(description.other["JS::ubi::RootList"]); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js deleted file mode 100644 index f3b3090b0..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js +++ /dev/null @@ -1,31 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus returns a value of an appropriate -// shape. Ported from js/src/jit-tests/debug/Memory-takeCensus-01.js - -function run_test() { - var dbg = new Debugger; - - function checkProperties(census) { - equal(typeof census, "object"); - for (prop of Object.getOwnPropertyNames(census)) { - var desc = Object.getOwnPropertyDescriptor(census, prop); - equal(desc.enumerable, true); - equal(desc.configurable, true); - equal(desc.writable, true); - if (typeof desc.value === "object") - checkProperties(desc.value); - else - equal(typeof desc.value, "number"); - } - } - - checkProperties(saveHeapSnapshotAndTakeCensus(dbg)); - - var g = newGlobal(); - dbg.addDebuggee(g); - checkProperties(saveHeapSnapshotAndTakeCensus(dbg)); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js deleted file mode 100644 index 680ac9b58..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js +++ /dev/null @@ -1,57 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus behaves plausibly as we allocate objects. -// -// Exact object counts vary in ways we can't predict. For example, -// BaselineScripts can hold onto "template objects", which exist only to hold -// the shape and type for newly created objects. When BaselineScripts are -// discarded, these template objects go with them. -// -// So instead of expecting precise counts, we expect counts that are at least as -// many as we would expect given the object graph we've built. -// -// Ported from js/src/jit-tests/debug/Memory-takeCensus-02.js - -function run_test() { - // A Debugger with no debuggees had better not find anything. - var dbg = new Debugger; - var census0 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census0, "census0", Census.assertAllZeros); - - function newGlobalWithDefs() { - var g = newGlobal(); - g.eval(` - function times(n, fn) { - var a=[]; - for (var i = 0; i<n; i++) - a.push(fn()); - return a; - } - `); - return g; - } - - // Allocate a large number of various types of objects, and check that census - // finds them. - var g = newGlobalWithDefs(); - dbg.addDebuggee(g); - - g.eval("var objs = times(100, () => ({}));"); - g.eval("var rxs = times(200, () => /foo/);"); - g.eval("var ars = times(400, () => []);"); - g.eval("var fns = times(800, () => () => {});"); - - var census1 = dbg.memory.takeCensus(dbg); - Census.walkCensus(census1, "census1", - Census.assertAllNotLessThan( - { "objects": - { "Object": { count: 100 }, - "RegExp": { count: 200 }, - "Array": { count: 400 }, - "Function": { count: 800 } - } - })); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js deleted file mode 100644 index 25f2c3791..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js +++ /dev/null @@ -1,34 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus behaves plausibly as we add and remove -// debuggees. -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-03.js - -function run_test() { - var dbg = new Debugger; - - var census0 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census0, "census0", Census.assertAllZeros); - - var g1 = newGlobal(); - dbg.addDebuggee(g1); - var census1 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census1, "census1", Census.assertAllNotLessThan(census0)); - - var g2 = newGlobal(); - dbg.addDebuggee(g2); - var census2 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census2, "census2", Census.assertAllNotLessThan(census1)); - - dbg.removeDebuggee(g2); - var census3 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census3, "census3", Census.assertAllEqual(census1)); - - dbg.removeDebuggee(g1); - var census4 = saveHeapSnapshotAndTakeCensus(dbg); - Census.walkCensus(census4, "census4", Census.assertAllEqual(census0)); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js deleted file mode 100644 index 799844cde..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js +++ /dev/null @@ -1,36 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that HeapSnapshot.prototype.takeCensus finds GC roots that are on the -// stack. -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-04.js - -function run_test() { - var g = newGlobal(); - var dbg = new Debugger(g); - - g.eval(` -function withAllocationMarkerOnStack(f) { - (function () { - var onStack = allocationMarker(); - f(); - }()); -} -`); - - equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false, - "There shouldn't exist any allocation markers in the census."); - - var allocationMarkerCount; - g.withAllocationMarkerOnStack(() => { - const census = saveHeapSnapshotAndTakeCensus(dbg); - allocationMarkerCount = census.objects.AllocationMarker.count; - }); - - equal(allocationMarkerCount, 1, - "Should have one allocation marker in the census, because there " + - "was one on the stack."); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js deleted file mode 100644 index da6067624..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that HeapSnapshot.prototype.takeCensus finds cross compartment -// wrapper GC roots. -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-05.js - -function run_test() { - var g = newGlobal(); - var dbg = new Debugger(g); - - equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false, - "No allocation markers should exist in the census."); - - this.ccw = g.allocationMarker(); - - const census = saveHeapSnapshotAndTakeCensus(dbg); - equal(census.objects.AllocationMarker.count, 1, - "Should have one allocation marker in the census, because there " + - "is one cross-compartment wrapper referring to it."); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js deleted file mode 100644 index 0412410c0..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js +++ /dev/null @@ -1,125 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Check HeapSnapshot.prototype.takeCensus handling of 'breakdown' argument. -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-06.js - -function run_test() { - var Pattern = Match.Pattern; - - var g = newGlobal(); - var dbg = new Debugger(g); - - Pattern({ count: Pattern.NATURAL, - bytes: Pattern.NATURAL }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count" } })); - - let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: false } }); - equal("count" in census, false); - equal("bytes" in census, false); - - census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: false } }); - equal("count" in census, true); - equal("bytes" in census, false); - - census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: true } }); - equal("count" in census, false); - equal("bytes" in census, true); - - census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: true } }); - equal("count" in census, true); - equal("bytes" in census, true); - - - // Pattern doesn't mind objects with extra properties, so we'll restrict this - // list to the object classes we're pretty sure are going to stick around for - // the forseeable future. - Pattern({ - Function: { count: Pattern.NATURAL }, - Object: { count: Pattern.NATURAL }, - Debugger: { count: Pattern.NATURAL }, - Sandbox: { count: Pattern.NATURAL }, - - // The below are all Debugger prototype objects. - Source: { count: Pattern.NATURAL }, - Environment: { count: Pattern.NATURAL }, - Script: { count: Pattern.NATURAL }, - Memory: { count: Pattern.NATURAL }, - Frame: { count: Pattern.NATURAL } - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass" } })); - - Pattern({ - objects: { count: Pattern.NATURAL }, - scripts: { count: Pattern.NATURAL }, - strings: { count: Pattern.NATURAL }, - other: { count: Pattern.NATURAL } - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "coarseType" } })); - - // As for { by: 'objectClass' }, restrict our pattern to the types - // we predict will stick around for a long time. - Pattern({ - JSString: { count: Pattern.NATURAL }, - "js::Shape": { count: Pattern.NATURAL }, - JSObject: { count: Pattern.NATURAL }, - JSScript: { count: Pattern.NATURAL } - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "internalType" } })); - - - // Nested breakdowns. - - let coarseTypePattern = { - objects: { count: Pattern.NATURAL }, - scripts: { count: Pattern.NATURAL }, - strings: { count: Pattern.NATURAL }, - other: { count: Pattern.NATURAL } - }; - - Pattern({ - JSString: coarseTypePattern, - "js::Shape": coarseTypePattern, - JSObject: coarseTypePattern, - JSScript: coarseTypePattern, - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "internalType", - then: { by: "coarseType" } - } - })); - - Pattern({ - Function: { count: Pattern.NATURAL }, - Object: { count: Pattern.NATURAL }, - Debugger: { count: Pattern.NATURAL }, - Sandbox: { count: Pattern.NATURAL }, - other: coarseTypePattern - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { - by: "objectClass", - then: { by: "count" }, - other: { by: "coarseType" } - } - })); - - Pattern({ - objects: { count: Pattern.NATURAL, label: "object" }, - scripts: { count: Pattern.NATURAL, label: "scripts" }, - strings: { count: Pattern.NATURAL, label: "strings" }, - other: { count: Pattern.NATURAL, label: "other" } - }) - .assert(saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { - by: "coarseType", - objects: { by: "count", label: "object" }, - scripts: { by: "count", label: "scripts" }, - strings: { by: "count", label: "strings" }, - other: { by: "count", label: "other" } - } - })); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js deleted file mode 100644 index f5c36056f..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js +++ /dev/null @@ -1,82 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus breakdown: check error handling on property -// gets. -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-07.js - -function run_test() { - var g = newGlobal(); - var dbg = new Debugger(g); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { get by() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "count", get count() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "count", get bytes() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "objectClass", get then() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "objectClass", get other() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "coarseType", get objects() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "coarseType", get scripts() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "coarseType", get strings() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "coarseType", get other() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - - - assertThrowsValue(() => { - saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "internalType", get then() { throw "ಠ_ಠ"; } } - }); - }, "ಠ_ಠ"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js deleted file mode 100644 index 5934aa919..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js +++ /dev/null @@ -1,82 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus: test by: 'count' breakdown -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-08.js - -function run_test() { - let g = newGlobal(); - let dbg = new Debugger(g); - - g.eval(` - var stuff = []; - function add(n, c) { - for (let i = 0; i < n; i++) - stuff.push(c()); - } - - let count = 0; - - function obj() { return { count: count++ }; } - obj.factor = 1; - - // This creates a closure (a function JSObject) that has captured - // a Call object. So each call creates two items. - function fun() { let v = count; return () => { return v; } } - fun.factor = 2; - - function str() { return 'perambulator' + count++; } - str.factor = 1; - - // Eval a fresh text each time, allocating: - // - a fresh ScriptSourceObject - // - a new JSScripts, not an eval cache hits - // - a fresh prototype object - // - a fresh Call object, since the eval makes 'ev' heavyweight - // - the new function itself - function ev() { - return eval(\`(function () { return \${ count++ } })\`); - } - ev.factor = 5; - - // A new object (1) with a new shape (2) with a new atom (3) - function shape() { return { [ 'theobroma' + count++ ]: count }; } - shape.factor = 3; - `); - - let baseline = 0; - function countIncreasedByAtLeast(n) { - let oldBaseline = baseline; - - // Since a census counts only reachable objects, one might assume that calling - // GC here would have no effect on the census results. But GC also throws away - // JIT code and any objects it might be holding (template objects, say); - // takeCensus reaches those. Shake everything loose that we can, to make the - // census approximate reachability a bit more closely, and make our results a - // bit more predictable. - gc(g, "shrinking"); - - baseline = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count" } }).count; - return baseline >= oldBaseline + n; - } - - countIncreasedByAtLeast(0); - - g.add(100, g.obj); - ok(countIncreasedByAtLeast(g.obj.factor * 100)); - - g.add(100, g.fun); - ok(countIncreasedByAtLeast(g.fun.factor * 100)); - - g.add(100, g.str); - ok(countIncreasedByAtLeast(g.str.factor * 100)); - - g.add(100, g.ev); - ok(countIncreasedByAtLeast(g.ev.factor * 100)); - - g.add(100, g.shape); - ok(countIncreasedByAtLeast(g.shape.factor * 100)); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js deleted file mode 100644 index bbacccc8d..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js +++ /dev/null @@ -1,92 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// HeapSnapshot.prototype.takeCensus: by: allocationStack breakdown -// -// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-09.js - -function run_test() { - var g = newGlobal(); - var dbg = new Debugger(g); - - g.eval(` // 1 - var log = []; // 2 - function f() { log.push(allocationMarker()); } // 3 - function g() { f(); } // 4 - function h() { f(); } // 5 - `); // 6 - - // Create one allocationMarker with tracking turned off, - // so it will have no associated stack. - g.f(); - - dbg.memory.allocationSamplingProbability = 1; - - for ([func, n] of [[g.f, 20], [g.g, 10], [g.h, 5]]) { - for (let i = 0; i < n; i++) { - dbg.memory.trackingAllocationSites = true; - // All allocations of allocationMarker occur with this line as the oldest - // stack frame. - func(); - dbg.memory.trackingAllocationSites = false; - } - } - - let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass", - then: { by: "allocationStack", - then: { by: "count", - label: "haz stack" - }, - noStack: { by: "count", - label: "no haz stack" - } - } - } - }); - - let map = census.AllocationMarker; - ok(map instanceof Map, "Should be a Map instance"); - equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)"); - - // Gather the stacks we are expecting to appear as keys, and - // check that there are no unexpected keys. - let stacks = { }; - - map.forEach((v, k) => { - if (k === "noStack") { - // No need to save this key. - } else if (k.functionDisplayName === "f" && - k.parent.functionDisplayName === "run_test") { - stacks.f = k; - } else if (k.functionDisplayName === "f" && - k.parent.functionDisplayName === "g" && - k.parent.parent.functionDisplayName === "run_test") { - stacks.fg = k; - } else if (k.functionDisplayName === "f" && - k.parent.functionDisplayName === "h" && - k.parent.parent.functionDisplayName === "run_test") { - stacks.fh = k; - } else { - dumpn("Unexpected allocation stack:"); - k.toString().split(/\n/g).forEach(s => dumpn(s)); - ok(false); - } - }); - - equal(map.get("noStack").label, "no haz stack"); - equal(map.get("noStack").count, 1); - - ok(stacks.f); - equal(map.get(stacks.f).label, "haz stack"); - equal(map.get(stacks.f).count, 20); - - ok(stacks.fg); - equal(map.get(stacks.fg).label, "haz stack"); - equal(map.get(stacks.fg).count, 10); - - ok(stacks.fh); - equal(map.get(stacks.fh).label, "haz stack"); - equal(map.get(stacks.fh).count, 5); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js deleted file mode 100644 index a7f987f5a..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Check byte counts produced by takeCensus. -// -// Ported from js/src/jit-test/tests/debug/Memory-take Census-10.js - -function run_test() { - let g = newGlobal(); - let dbg = new Debugger(g); - - let sizeOfAM = byteSize(allocationMarker()); - - // Allocate a single allocation marker, and check that we can find it. - g.eval("var hold = allocationMarker();"); - let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass" } }); - equal(census.AllocationMarker.count, 1); - equal(census.AllocationMarker.bytes, sizeOfAM); - g.hold = null; - - g.eval(` // 1 - var objs = []; // 2 - function fnerd() { // 3 - objs.push(allocationMarker()); // 4 - for (let i = 0; i < 10; i++) // 5 - objs.push(allocationMarker()); // 6 - } // 7 - `); // 8 - - dbg.memory.allocationSamplingProbability = 1; - dbg.memory.trackingAllocationSites = true; - g.fnerd(); - dbg.memory.trackingAllocationSites = false; - - census = saveHeapSnapshotAndTakeCensus(dbg, { - breakdown: { by: "objectClass", - then: { by: "allocationStack" } - } - }); - - let seen = 0; - census.AllocationMarker.forEach((v, k) => { - equal(k.functionDisplayName, "fnerd"); - switch (k.line) { - case 4: - equal(v.count, 1); - equal(v.bytes, sizeOfAM); - seen++; - break; - - case 6: - equal(v.count, 10); - equal(v.bytes, 10 * sizeOfAM); - seen++; - break; - - default: - dumpn("Unexpected stack:"); - k.toString().split(/\n/g).forEach(s => dumpn(s)); - ok(false); - break; - } - }); - - equal(seen, 2); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js deleted file mode 100644 index 3d898b2d1..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js +++ /dev/null @@ -1,116 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that Debugger.Memory.prototype.takeCensus and -// HeapSnapshot.prototype.takeCensus return the same data for the same heap -// graph. - -function doLiveAndOfflineCensus(g, dbg, opts) { - dbg.memory.allocationSamplingProbability = 1; - dbg.memory.trackingAllocationSites = true; - g.eval(` // 1 - (function unsafeAtAnySpeed() { // 2 - for (var i = 0; i < 100; i++) { // 3 - this.markers.push(allocationMarker()); // 4 - } // 5 - }()); // 6 - `); // 7 - dbg.memory.trackingAllocationSites = false; - - return { - live: dbg.memory.takeCensus(opts), - offline: saveHeapSnapshotAndTakeCensus(dbg, opts) - }; -} - -function run_test() { - var g = newGlobal(); - var dbg = new Debugger(g); - - g.eval("this.markers = []"); - const markerSize = byteSize(allocationMarker()); - - // First, test that we get the same counts and sizes as we allocate and retain - // more things. - - let prevCount = 0; - let prevBytes = 0; - - for (var i = 0; i < 10; i++) { - const { live, offline } = doLiveAndOfflineCensus(g, dbg, { - breakdown: { by: "objectClass", - then: { by: "count"} } - }); - - equal(live.AllocationMarker.count, offline.AllocationMarker.count); - equal(live.AllocationMarker.bytes, offline.AllocationMarker.bytes); - equal(live.AllocationMarker.count, prevCount + 100); - equal(live.AllocationMarker.bytes, prevBytes + 100 * markerSize); - - prevCount = live.AllocationMarker.count; - prevBytes = live.AllocationMarker.bytes; - } - - // Second, test that the reported allocation stacks and counts and sizes at - // those allocation stacks match up. - - const { live, offline } = doLiveAndOfflineCensus(g, dbg, { - breakdown: { by: "objectClass", - then: { by: "allocationStack"} } - }); - - equal(live.AllocationMarker.size, offline.AllocationMarker.size); - // One stack with the loop further above, and another stack featuring the call - // right above. - equal(live.AllocationMarker.size, 2); - - // Note that because SavedFrame stacks reconstructed from an offline heap - // snapshot don't have the same principals as SavedFrame stacks captured from - // a live stack, the live and offline allocation stacks won't be identity - // equal, but should be structurally the same. - - const liveEntries = []; - live.AllocationMarker.forEach((v, k) => { - dumpn("Allocation stack:"); - k.toString().split(/\n/g).forEach(s => dumpn(s)); - - equal(k.functionDisplayName, "unsafeAtAnySpeed"); - equal(k.line, 4); - - liveEntries.push([k.toString(), v]); - }); - - const offlineEntries = []; - offline.AllocationMarker.forEach((v, k) => { - dumpn("Allocation stack:"); - k.toString().split(/\n/g).forEach(s => dumpn(s)); - - equal(k.functionDisplayName, "unsafeAtAnySpeed"); - equal(k.line, 4); - - offlineEntries.push([k.toString(), v]); - }); - - const sortEntries = (a, b) => { - if (a[0] < b[0]) { - return -1; - } else if (a[0] > b[0]) { - return 1; - } else { - return 0; - } - }; - liveEntries.sort(sortEntries); - offlineEntries.sort(sortEntries); - - equal(liveEntries.length, live.AllocationMarker.size); - equal(liveEntries.length, offlineEntries.length); - - for (let i = 0; i < liveEntries.length; i++) { - equal(liveEntries[i][0], offlineEntries[i][0]); - equal(liveEntries[i][1].count, offlineEntries[i][1].count); - equal(liveEntries[i][1].bytes, offlineEntries[i][1].bytes); - } - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js deleted file mode 100644 index f10dd5b03..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js +++ /dev/null @@ -1,50 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that when we take a census and get a bucket list of ids that matched the -// given category, that the returned ids are all in the snapshot and their -// reported category. - -function run_test() { - const g = newGlobal(); - const dbg = new Debugger(g); - - const path = saveNewHeapSnapshot({ debugger: dbg }); - const snapshot = readHeapSnapshot(path); - - const bucket = { by: "bucket" }; - const count = { by: "count", count: true, bytes: false }; - const objectClassCount = { by: "objectClass", then: count, other: count }; - - const byClassName = snapshot.takeCensus({ - breakdown: { - by: "objectClass", - then: bucket, - other: bucket, - } - }); - - const byClassNameCount = snapshot.takeCensus({ - breakdown: objectClassCount - }); - - const keys = new Set(Object.keys(byClassName)); - equal(keys.size, Object.keys(byClassNameCount).length, - "Should have the same number of keys."); - for (let k of Object.keys(byClassNameCount)) { - ok(keys.has(k), "Should not have any unexpected class names"); - } - - for (let key of Object.keys(byClassName)) { - equal(byClassNameCount[key].count, byClassName[key].length, - "Length of the bucket and count should be equal"); - - for (let id of byClassName[key]) { - const desc = snapshot.describeNode(objectClassCount, id); - equal(desc[key].count, 1, - "Describing the bucketed node confirms that it belongs to the category"); - } - } - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js b/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js deleted file mode 100644 index dde139ffd..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js +++ /dev/null @@ -1,20 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can read core dumps into HeapSnapshot instances. - -if (typeof Debugger != "function") { - const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {}); - addDebuggerToGlobal(this); -} - -function run_test() { - const filePath = ChromeUtils.saveHeapSnapshot({ globals: [this] }); - ok(true, "Should be able to save a snapshot."); - - const snapshot = ChromeUtils.readHeapSnapshot(filePath); - ok(snapshot, "Should be able to read a heap snapshot"); - ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js b/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js deleted file mode 100644 index d91f36f56..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js +++ /dev/null @@ -1,36 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can save a core dump with allocation stacks and read it back -// into a HeapSnapshot. - -if (typeof Debugger != "function") { - const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {}); - addDebuggerToGlobal(this); -} - -function run_test() { - // Create a Debugger observing a debuggee's allocations. - const debuggee = new Cu.Sandbox(null); - const dbg = new Debugger(debuggee); - dbg.memory.trackingAllocationSites = true; - - // Allocate some objects in the debuggee that will have their allocation - // stacks recorded by the Debugger. - debuggee.eval("this.objects = []"); - for (let i = 0; i < 100; i++) { - debuggee.eval("this.objects.push({})"); - } - - // Now save a snapshot that will include the allocation stacks and read it - // back again. - - const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true }); - ok(true, "Should be able to save a snapshot."); - - const snapshot = ChromeUtils.readHeapSnapshot(filePath); - ok(snapshot, "Should be able to read a heap snapshot"); - ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot"); - - do_test_finished(); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js b/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js deleted file mode 100644 index 76461b694..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that we can read core dumps into HeapSnapshot instances in a worker. - -add_task(function* () { - const worker = new ChromeWorker("resource://test/heap-snapshot-worker.js"); - worker.postMessage({}); - - let assertionCount = 0; - worker.onmessage = e => { - if (e.data.type !== "assertion") { - return; - } - - ok(e.data.passed, e.data.msg + "\n" + e.data.stack); - assertionCount++; - }; - - yield waitForDone(worker); - - ok(assertionCount > 0); - worker.terminate(); -}); - -function waitForDone(w) { - return new Promise((resolve, reject) => { - w.onerror = e => { - reject(); - ok(false, "Error in worker: " + e); - }; - - w.addEventListener("message", function listener(e) { - if (e.data.type === "done") { - w.removeEventListener("message", listener, false); - resolve(); - } - }, false); - }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js b/devtools/shared/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js deleted file mode 100644 index affd8d1e4..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js +++ /dev/null @@ -1,82 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the ChromeUtils interface. - -if (typeof Debugger != "function") { - const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {}); - addDebuggerToGlobal(this); -} - -function run_test() { - ok(ChromeUtils, "Should be able to get the ChromeUtils interface"); - - testBadParameters(); - testGoodParameters(); - - do_test_finished(); -} - -function testBadParameters() { - throws(() => ChromeUtils.saveHeapSnapshot(), - "Should throw if arguments aren't passed in."); - - throws(() => ChromeUtils.saveHeapSnapshot(null), - "Should throw if boundaries isn't an object."); - - throws(() => ChromeUtils.saveHeapSnapshot({}), - "Should throw if the boundaries object doesn't have any properties."); - - throws(() => ChromeUtils.saveHeapSnapshot({ runtime: true, - globals: [this] }), - "Should throw if the boundaries object has more than one property."); - - throws(() => ChromeUtils.saveHeapSnapshot({ debugger: {} }), - "Should throw if the debuggees object is not a Debugger object"); - - throws(() => ChromeUtils.saveHeapSnapshot({ globals: [{}] }), - "Should throw if the globals array contains non-global objects."); - - throws(() => ChromeUtils.saveHeapSnapshot({ runtime: false }), - "Should throw if runtime is supplied and is not true."); - - throws(() => ChromeUtils.saveHeapSnapshot({ globals: null }), - "Should throw if globals is not an object."); - - throws(() => ChromeUtils.saveHeapSnapshot({ globals: {} }), - "Should throw if globals is not an array."); - - throws(() => ChromeUtils.saveHeapSnapshot({ debugger: Debugger.prototype }), - "Should throw if debugger is the Debugger.prototype object."); - - throws(() => ChromeUtils.saveHeapSnapshot({ get globals() { return [this]; } }), - "Should throw if boundaries property is a getter."); -} - -const makeNewSandbox = () => - Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")()); - -function testGoodParameters() { - let sandbox = makeNewSandbox(); - let dbg = new Debugger(sandbox); - - ChromeUtils.saveHeapSnapshot({ debugger: dbg }); - ok(true, "Should be able to save a snapshot for a debuggee global."); - - dbg = new Debugger; - let sandboxes = Array(10).fill(null).map(makeNewSandbox); - sandboxes.forEach(sb => dbg.addDebuggee(sb)); - - ChromeUtils.saveHeapSnapshot({ debugger: dbg }); - ok(true, "Should be able to save a snapshot for many debuggee globals."); - - dbg = new Debugger; - ChromeUtils.saveHeapSnapshot({ debugger: dbg }); - ok(true, "Should be able to save a snapshot with no debuggee globals."); - - ChromeUtils.saveHeapSnapshot({ globals: [this] }); - ok(true, "Should be able to save a snapshot for a specific global."); - - ChromeUtils.saveHeapSnapshot({ runtime: true }); - ok(true, "Should be able to save a snapshot of the full runtime."); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-01.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-01.js deleted file mode 100644 index 16038c5c4..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-01.js +++ /dev/null @@ -1,76 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Tests CensusTreeNode with `internalType` breakdown. - */ - -const BREAKDOWN = { - by: "internalType", - then: { by: "count", count: true, bytes: true } -}; - -const REPORT = { - "JSObject": { - "bytes": 100, - "count": 10, - }, - "js::Shape": { - "bytes": 500, - "count": 50, - }, - "JSString": { - "bytes": 10, - "count": 1, - }, -}; - -const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 610, - count: 0, - totalCount: 61, - children: [ - { - name: "js::Shape", - bytes: 500, - totalBytes: 500, - count: 50, - totalCount: 50, - children: undefined, - id: 3, - parent: 1, - reportLeafIndex: 2, - }, - { - name: "JSObject", - bytes: 100, - totalBytes: 100, - count: 10, - totalCount: 10, - children: undefined, - id: 2, - parent: 1, - reportLeafIndex: 1, - }, - { - name: "JSString", - bytes: 10, - totalBytes: 10, - count: 1, - totalCount: 1, - children: undefined, - id: 4, - parent: 1, - reportLeafIndex: 3, - }, - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, -}; - -function run_test() { - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-02.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-02.js deleted file mode 100644 index 37d039954..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-02.js +++ /dev/null @@ -1,136 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Tests CensusTreeNode with `coarseType` breakdown. - */ - -const countBreakdown = { by: "count", count: true, bytes: true }; - -const BREAKDOWN = { - by: "coarseType", - objects: { by: "objectClass", then: countBreakdown }, - strings: countBreakdown, - scripts: countBreakdown, - other: { by: "internalType", then: countBreakdown }, -}; - -const REPORT = { - "objects": { - "Function": { bytes: 10, count: 1 }, - "Array": { bytes: 20, count: 2 }, - }, - "strings": { bytes: 10, count: 1 }, - "scripts": { bytes: 1, count: 1 }, - "other": { - "js::Shape": { bytes: 30, count: 3 }, - "js::Shape2": { bytes: 40, count: 4 } - }, -}; - -const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 111, - count: 0, - totalCount: 12, - children: [ - { - name: "other", - count: 0, - totalCount: 7, - bytes: 0, - totalBytes: 70, - children: [ - { - name: "js::Shape2", - bytes: 40, - totalBytes: 40, - count: 4, - totalCount: 4, - children: undefined, - id: 9, - parent: 7, - reportLeafIndex: 8, - }, - { - name: "js::Shape", - bytes: 30, - totalBytes: 30, - count: 3, - totalCount: 3, - children: undefined, - id: 8, - parent: 7, - reportLeafIndex: 7, - }, - ], - id: 7, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "objects", - count: 0, - totalCount: 3, - bytes: 0, - totalBytes: 30, - children: [ - { - name: "Array", - bytes: 20, - totalBytes: 20, - count: 2, - totalCount: 2, - children: undefined, - id: 4, - parent: 2, - reportLeafIndex: 3, - }, - { - name: "Function", - bytes: 10, - totalBytes: 10, - count: 1, - totalCount: 1, - children: undefined, - id: 3, - parent: 2, - reportLeafIndex: 2, - }, - ], - id: 2, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "strings", - count: 1, - totalCount: 1, - bytes: 10, - totalBytes: 10, - children: undefined, - id: 6, - parent: 1, - reportLeafIndex: 5, - }, - { - name: "scripts", - count: 1, - totalCount: 1, - bytes: 1, - totalBytes: 1, - children: undefined, - id: 5, - parent: 1, - reportLeafIndex: 4, - }, - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, -}; - -function run_test() { - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-03.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-03.js deleted file mode 100644 index bdf932099..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-03.js +++ /dev/null @@ -1,96 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Tests CensusTreeNode with `objectClass` breakdown. - */ - -const countBreakdown = { by: "count", count: true, bytes: true }; - -const BREAKDOWN = { - by: "objectClass", - then: countBreakdown, - other: { by: "internalType", then: countBreakdown } -}; - -const REPORT = { - "Function": { bytes: 10, count: 10 }, - "Array": { bytes: 100, count: 1 }, - "other": { - "JIT::CODE::NOW!!!": { bytes: 20, count: 2 }, - "JIT::CODE::LATER!!!": { bytes: 40, count: 4 } - } -}; - -const EXPECTED = { - name: null, - count: 0, - totalCount: 17, - bytes: 0, - totalBytes: 170, - children: [ - { - name: "Array", - bytes: 100, - totalBytes: 100, - count: 1, - totalCount: 1, - children: undefined, - id: 3, - parent: 1, - reportLeafIndex: 2, - }, - { - name: "other", - count: 0, - totalCount: 6, - bytes: 0, - totalBytes: 60, - children: [ - { - name: "JIT::CODE::LATER!!!", - bytes: 40, - totalBytes: 40, - count: 4, - totalCount: 4, - children: undefined, - id: 6, - parent: 4, - reportLeafIndex: 5, - }, - { - name: "JIT::CODE::NOW!!!", - bytes: 20, - totalBytes: 20, - count: 2, - totalCount: 2, - children: undefined, - id: 5, - parent: 4, - reportLeafIndex: 4, - }, - ], - id: 4, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "Function", - bytes: 10, - totalBytes: 10, - count: 10, - totalCount: 10, - children: undefined, - id: 2, - parent: 1, - reportLeafIndex: 1, - }, - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, -}; - -function run_test() { - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-04.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-04.js deleted file mode 100644 index cc0c3bac0..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-04.js +++ /dev/null @@ -1,159 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Tests CensusTreeNode with `allocationStack` breakdown. - */ - -function run_test() { - const countBreakdown = { by: "count", count: true, bytes: true }; - - const BREAKDOWN = { - by: "allocationStack", - then: countBreakdown, - noStack: countBreakdown, - }; - - let stack1, stack2, stack3, stack4, stack5; - - (function a() { - (function b() { - (function c() { - stack1 = saveStack(3); - }()); - (function d() { - stack2 = saveStack(3); - stack3 = saveStack(3); - }()); - stack4 = saveStack(2); - }()); - }()); - - stack5 = saveStack(1); - - const REPORT = new Map([ - [stack1, { bytes: 10, count: 1 }], - [stack2, { bytes: 20, count: 2 }], - [stack3, { bytes: 30, count: 3 }], - [stack4, { bytes: 40, count: 4 }], - [stack5, { bytes: 50, count: 5 }], - ["noStack", { bytes: 60, count: 6 }], - ]); - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 210, - count: 0, - totalCount: 21, - children: [ - { - name: stack4.parent, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: stack3.parent, - bytes: 0, - totalBytes: 50, - count: 0, - totalCount: 5, - children: [ - { - name: stack3, - bytes: 30, - totalBytes: 30, - count: 3, - totalCount: 3, - children: undefined, - id: 7, - parent: 5, - reportLeafIndex: 3, - }, - { - name: stack2, - bytes: 20, - totalBytes: 20, - count: 2, - totalCount: 2, - children: undefined, - id: 6, - parent: 5, - reportLeafIndex: 2, - } - ], - id: 5, - parent: 2, - reportLeafIndex: undefined, - }, - { - name: stack4, - bytes: 40, - totalBytes: 40, - count: 4, - totalCount: 4, - children: undefined, - id: 8, - parent: 2, - reportLeafIndex: 4, - }, - { - name: stack1.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: stack1, - bytes: 10, - totalBytes: 10, - count: 1, - totalCount: 1, - children: undefined, - id: 4, - parent: 3, - reportLeafIndex: 1, - }, - ], - id: 3, - parent: 2, - reportLeafIndex: undefined, - }, - ], - id: 2, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "noStack", - bytes: 60, - totalBytes: 60, - count: 6, - totalCount: 6, - children: undefined, - id: 10, - parent: 1, - reportLeafIndex: 6, - }, - { - name: stack5, - bytes: 50, - totalBytes: 50, - count: 5, - totalCount: 5, - children: undefined, - id: 9, - parent: 1, - reportLeafIndex: 5 - }, - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-05.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-05.js deleted file mode 100644 index 20fb76bd2..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-05.js +++ /dev/null @@ -1,145 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Tests CensusTreeNode with `allocationStack` => `objectClass` breakdown. - */ - -function run_test() { - const countBreakdown = { by: "count", count: true, bytes: true }; - - const BREAKDOWN = { - by: "allocationStack", - then: { - by: "objectClass", - then: countBreakdown, - other: countBreakdown - }, - noStack: countBreakdown, - }; - - let stack; - - (function a() { - (function b() { - (function c() { - stack = saveStack(3); - }()); - }()); - }()); - - const REPORT = new Map([ - [stack, { Foo: { bytes: 10, count: 1 }, - Bar: { bytes: 20, count: 2 }, - Baz: { bytes: 30, count: 3 }, - other: { bytes: 40, count: 4 } - }], - ["noStack", { bytes: 50, count: 5 }], - ]); - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 150, - count: 0, - totalCount: 15, - children: [ - { - name: stack.parent.parent, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: stack.parent, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: stack, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: "other", - bytes: 40, - totalBytes: 40, - count: 4, - totalCount: 4, - children: undefined, - id: 8, - parent: 4, - reportLeafIndex: 5, - }, - { - name: "Baz", - bytes: 30, - totalBytes: 30, - count: 3, - totalCount: 3, - children: undefined, - id: 7, - parent: 4, - reportLeafIndex: 4, - }, - { - name: "Bar", - bytes: 20, - totalBytes: 20, - count: 2, - totalCount: 2, - children: undefined, - id: 6, - parent: 4, - reportLeafIndex: 3, - }, - { - name: "Foo", - bytes: 10, - totalBytes: 10, - count: 1, - totalCount: 1, - children: undefined, - id: 5, - parent: 4, - reportLeafIndex: 2, - }, - ], - id: 4, - parent: 3, - reportLeafIndex: undefined, - } - ], - id: 3, - parent: 2, - reportLeafIndex: undefined, - } - ], - id: 2, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "noStack", - bytes: 50, - totalBytes: 50, - count: 5, - totalCount: 5, - children: undefined, - id: 9, - parent: 1, - reportLeafIndex: 6, - }, - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-06.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-06.js deleted file mode 100644 index eb1801207..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-06.js +++ /dev/null @@ -1,200 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test inverting CensusTreeNode with a by alloaction stack breakdown. - */ - -function run_test() { - const BREAKDOWN = { - by: "allocationStack", - then: { by: "count", count: true, bytes: true }, - noStack: { by: "count", count: true, bytes: true }, - }; - - let stack1, stack2, stack3, stack4; - - function a(n) { - return b(n); - } - function b(n) { - return c(n); - } - function c(n) { - return saveStack(n); - } - function d(n) { - return b(n); - } - function e(n) { - return c(n); - } - - const abc_Stack = a(3); - const bc_Stack = b(2); - const c_Stack = c(1); - const dbc_Stack = d(3); - const ec_Stack = e(2); - - const REPORT = new Map([ - [abc_Stack, { bytes: 10, count: 1 }], - [ bc_Stack, { bytes: 10, count: 1 }], - [ c_Stack, { bytes: 10, count: 1 }], - [dbc_Stack, { bytes: 10, count: 1 }], - [ ec_Stack, { bytes: 10, count: 1 }], - ["noStack", { bytes: 50, count: 5 }], - ]); - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: "noStack", - bytes: 50, - totalBytes: 50, - count: 5, - totalCount: 5, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 16, - parent: 15, - reportLeafIndex: undefined, - } - ], - id: 15, - parent: 14, - reportLeafIndex: 6, - }, - { - name: abc_Stack, - bytes: 50, - totalBytes: 10, - count: 5, - totalCount: 1, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 18, - parent: 17, - reportLeafIndex: undefined, - }, - { - name: abc_Stack.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 22, - parent: 19, - reportLeafIndex: undefined, - }, - { - name: abc_Stack.parent.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 21, - parent: 20, - reportLeafIndex: undefined, - } - ], - id: 20, - parent: 19, - reportLeafIndex: undefined, - }, - { - name: dbc_Stack.parent.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 24, - parent: 23, - reportLeafIndex: undefined, - } - ], - id: 23, - parent: 19, - reportLeafIndex: undefined, - } - ], - id: 19, - parent: 17, - reportLeafIndex: undefined, - }, - { - name: ec_Stack.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: null, - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: undefined, - id: 26, - parent: 25, - reportLeafIndex: undefined, - }, - ], - id: 25, - parent: 17, - reportLeafIndex: undefined, - }, - ], - id: 17, - parent: 14, - reportLeafIndex: new Set([1, 2, 3, 4, 5]), - } - ], - id: 14, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-07.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-07.js deleted file mode 100644 index 6bc085257..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-07.js +++ /dev/null @@ -1,200 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test inverting CensusTreeNode with a non-allocation stack breakdown. - */ - -function run_test() { - const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other:{ - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - }; - - const REPORT = { - objects: { - Array: { bytes: 50, count: 5 }, - other: { bytes: 0, count: 0 }, - }, - scripts: { - "js::jit::JitScript": { bytes: 30, count: 3 }, - }, - strings: { - JSAtom: { bytes: 60, count: 6 }, - }, - other: { - "js::Shape": { bytes: 80, count: 8 }, - } - }; - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 220, - count: 0, - totalCount: 22, - children: [ - { - name: "js::Shape", - bytes: 80, - totalBytes: 80, - count: 8, - totalCount: 8, - children: [ - { - name: "other", - bytes: 0, - totalBytes: 80, - count: 0, - totalCount: 8, - children: [ - { - name: null, - bytes: 0, - totalBytes: 220, - count: 0, - totalCount: 22, - children: undefined, - id: 14, - parent: 13, - reportLeafIndex: undefined, - } - ], - id: 13, - parent: 12, - reportLeafIndex: undefined, - } - ], - id: 12, - parent: 11, - reportLeafIndex: 9, - }, - { - name: "JSAtom", - bytes: 60, - totalBytes: 60, - count: 6, - totalCount: 6, - children: [ - { - name: "strings", - bytes: 0, - totalBytes: 60, - count: 0, - totalCount: 6, - children: [ - { - name: null, - bytes: 0, - totalBytes: 220, - count: 0, - totalCount: 22, - children: undefined, - id: 17, - parent: 16, - reportLeafIndex: undefined, - } - ], - id: 16, - parent: 15, - reportLeafIndex: undefined, - } - ], - id: 15, - parent: 11, - reportLeafIndex: 7, - }, - { - name: "Array", - bytes: 50, - totalBytes: 50, - count: 5, - totalCount: 5, - children: [ - { - name: "objects", - bytes: 0, - totalBytes: 50, - count: 0, - totalCount: 5, - children: [ - { - name: null, - bytes: 0, - totalBytes: 220, - count: 0, - totalCount: 22, - children: undefined, - id: 20, - parent: 19, - reportLeafIndex: undefined, - } - ], - id: 19, - parent: 18, - reportLeafIndex: undefined, - } - ], - id: 18, - parent: 11, - reportLeafIndex: 2, - }, - { - name: "js::jit::JitScript", - bytes: 30, - totalBytes: 30, - count: 3, - totalCount: 3, - children: [ - { - name: "scripts", - bytes: 0, - totalBytes: 30, - count: 0, - totalCount: 3, - children: [ - { - name: null, - bytes: 0, - totalBytes: 220, - count: 0, - totalCount: 22, - children: undefined, - id: 23, - parent: 22, - reportLeafIndex: undefined, - } - ], - id: 22, - parent: 21, - reportLeafIndex: undefined, - } - ], - id: 21, - parent: 11, - reportLeafIndex: 5, - }, - ], - id: 11, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-08.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-08.js deleted file mode 100644 index 1c686c810..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-08.js +++ /dev/null @@ -1,142 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test inverting CensusTreeNode with a non-allocation stack breakdown. - */ - -function run_test() { - const BREAKDOWN = { - by: "filename", - then: { - by: "internalType", - then: { by: "count", count: true, bytes: true } - }, - noFilename: { - by: "internalType", - then: { by: "count", count: true, bytes: true } - }, - }; - - const REPORT = { - "http://example.com/app.js": { - JSScript: { count: 10, bytes: 100 } - }, - "http://example.com/ads.js": { - "js::LazyScript": { count: 20, bytes: 200 } - }, - "http://example.com/trackers.js": { - JSScript: { count: 30, bytes: 300 } - }, - noFilename: { - "js::jit::JitCode": { count: 40, bytes: 400 } - } - }; - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 1000, - count: 0, - totalCount: 100, - children: [ - { - name: "noFilename", - bytes: 0, - totalBytes: 400, - count: 0, - totalCount: 40, - children: [ - { - name: "js::jit::JitCode", - bytes: 400, - totalBytes: 400, - count: 40, - totalCount: 40, - children: undefined, - id: 9, - parent: 8, - reportLeafIndex: 8, - } - ], - id: 8, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "http://example.com/trackers.js", - bytes: 0, - totalBytes: 300, - count: 0, - totalCount: 30, - children: [ - { - name: "JSScript", - bytes: 300, - totalBytes: 300, - count: 30, - totalCount: 30, - children: undefined, - id: 7, - parent: 6, - reportLeafIndex: 6, - } - ], - id: 6, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "http://example.com/ads.js", - bytes: 0, - totalBytes: 200, - count: 0, - totalCount: 20, - children: [ - { - name: "js::LazyScript", - bytes: 200, - totalBytes: 200, - count: 20, - totalCount: 20, - children: undefined, - id: 5, - parent: 4, - reportLeafIndex: 4, - } - ], - id: 4, - parent: 1, - reportLeafIndex: undefined, - }, - { - name: "http://example.com/app.js", - bytes: 0, - totalBytes: 100, - count: 0, - totalCount: 10, - children: [ - { - name: "JSScript", - bytes: 100, - totalBytes: 100, - count: 10, - totalCount: 10, - children: undefined, - id: 3, - parent: 2, - reportLeafIndex: 2, - } - ], - id: 2, - parent: 1, - reportLeafIndex: undefined, - } - ], - id: 1, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-09.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-09.js deleted file mode 100644 index 3efed04b0..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-09.js +++ /dev/null @@ -1,44 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -/** - * Test that repeatedly converting the same census report to a CensusTreeNode - * tree results in the same CensusTreeNode tree. - */ - -function run_test() { - const BREAKDOWN = { - by: "filename", - then: { - by: "internalType", - then: { by: "count", count: true, bytes: true } - }, - noFilename: { - by: "internalType", - then: { by: "count", count: true, bytes: true } - }, - }; - - const REPORT = { - "http://example.com/app.js": { - JSScript: { count: 10, bytes: 100 } - }, - "http://example.com/ads.js": { - "js::LazyScript": { count: 20, bytes: 200 } - }, - "http://example.com/trackers.js": { - JSScript: { count: 30, bytes: 300 } - }, - noFilename: { - "js::jit::JitCode": { count: 40, bytes: 400 } - } - }; - - const first = censusReportToCensusTreeNode(BREAKDOWN, REPORT); - const second = censusReportToCensusTreeNode(BREAKDOWN, REPORT); - const third = censusReportToCensusTreeNode(BREAKDOWN, REPORT); - - assertStructurallyEquivalent(first, second); - assertStructurallyEquivalent(second, third); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-10.js b/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-10.js deleted file mode 100644 index b7798f23f..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census-tree-node-10.js +++ /dev/null @@ -1,43 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -/** - * Test when multiple leaves in the census report map to the same node in an - * inverted CensusReportTree. - */ - -function run_test() { - const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - }; - - const REPORT = { - objects: { - Array: { count: 1, bytes: 10 }, - }, - other: { - Array: { count: 1, bytes: 10 }, - }, - strings: { count: 0, bytes: 0 }, - scripts: { count: 0, bytes: 0 }, - }; - - const node = censusReportToCensusTreeNode(BREAKDOWN, REPORT, { invert: true }); - - equal(node.children[0].name, "Array"); - equal(node.children[0].reportLeafIndex.size, 2); - dumpn(`node.children[0].reportLeafIndex = ${[...node.children[0].reportLeafIndex]}`); - ok(node.children[0].reportLeafIndex.has(2)); - ok(node.children[0].reportLeafIndex.has(6)); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_01.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_01.js deleted file mode 100644 index 75977bccb..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_01.js +++ /dev/null @@ -1,74 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of breakdown by "internalType". - -const BREAKDOWN = { - by: "internalType", - then: { by: "count", count: true, bytes: true } -}; - -const REPORT1 = { - "JSObject": { - "count": 10, - "bytes": 100, - }, - "js::Shape": { - "count": 50, - "bytes": 500, - }, - "JSString": { - "count": 0, - "bytes": 0, - }, - "js::LazyScript": { - "count": 1, - "bytes": 10, - }, -}; - -const REPORT2 = { - "JSObject": { - "count": 11, - "bytes": 110, - }, - "js::Shape": { - "count": 51, - "bytes": 510, - }, - "JSString": { - "count": 1, - "bytes": 1, - }, - "js::BaseShape": { - "count": 1, - "bytes": 42, - }, -}; - -const EXPECTED = { - "JSObject": { - "count": 1, - "bytes": 10, - }, - "js::Shape": { - "count": 1, - "bytes": 10, - }, - "JSString": { - "count": 1, - "bytes": 1, - }, - "js::LazyScript": { - "count": -1, - "bytes": -10, - }, - "js::BaseShape": { - "count": 1, - "bytes": 42, - }, -}; - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_02.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_02.js deleted file mode 100644 index 169e3f036..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_02.js +++ /dev/null @@ -1,25 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of breakdown by "count". - -const BREAKDOWN = { by: "count", count: true, bytes: true }; - -const REPORT1 = { - "count": 10, - "bytes": 100, -}; - -const REPORT2 = { - "count": 11, - "bytes": 110, -}; - -const EXPECTED = { - "count": 1, - "bytes": 10, -}; - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_03.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_03.js deleted file mode 100644 index 6dbca3e40..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_03.js +++ /dev/null @@ -1,73 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of breakdown by "coarseType". - -const BREAKDOWN = { - by: "coarseType", - objects: { by: "count", count: true, bytes: true }, - scripts: { by: "count", count: true, bytes: true }, - strings: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -const REPORT1 = { - objects: { - count: 1, - bytes: 10, - }, - scripts: { - count: 1, - bytes: 10, - }, - strings: { - count: 1, - bytes: 10, - }, - other: { - count: 3, - bytes: 30, - }, -}; - -const REPORT2 = { - objects: { - count: 1, - bytes: 10, - }, - scripts: { - count: 0, - bytes: 0, - }, - strings: { - count: 2, - bytes: 20, - }, - other: { - count: 4, - bytes: 40, - }, -}; - -const EXPECTED = { - objects: { - count: 0, - bytes: 0, - }, - scripts: { - count: -1, - bytes: -10, - }, - strings: { - count: 1, - bytes: 10, - }, - other: { - count: 1, - bytes: 10, - }, -}; - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_04.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_04.js deleted file mode 100644 index a10097945..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_04.js +++ /dev/null @@ -1,63 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of breakdown by "objectClass". - -const BREAKDOWN = { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, -}; - -const REPORT1 = { - "Array": { - count: 1, - bytes: 100, - }, - "Function": { - count: 10, - bytes: 10, - }, - "other": { - count: 10, - bytes: 100, - } -}; - -const REPORT2 = { - "Object": { - count: 1, - bytes: 100, - }, - "Function": { - count: 20, - bytes: 20, - }, - "other": { - count: 10, - bytes: 100, - } -}; - -const EXPECTED = { - "Array": { - count: -1, - bytes: -100, - }, - "Function": { - count: 10, - bytes: 10, - }, - "other": { - count: 0, - bytes: 0, - }, - "Object": { - count: 1, - bytes: 100, - }, -}; - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_05.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_05.js deleted file mode 100644 index b6d99f823..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_05.js +++ /dev/null @@ -1,34 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of breakdown by "allocationStack". - -const BREAKDOWN = { - by: "allocationStack", - then: { by: "count", count: true, bytes: true }, - noStack: { by: "count", count: true, bytes: true }, -}; - -const stack1 = saveStack(); -const stack2 = saveStack(); -const stack3 = saveStack(); - -const REPORT1 = new Map([ - [stack1, { "count": 10, "bytes": 100 }], - [stack2, { "count": 1, "bytes": 10 }], -]); - -const REPORT2 = new Map([ - [stack2, { "count": 10, "bytes": 100 }], - [stack3, { "count": 1, "bytes": 10 }], -]); - -const EXPECTED = new Map([ - [stack1, { "count": -10, "bytes": -100 }], - [stack2, { "count": 9, "bytes": 90 }], - [stack3, { "count": 1, "bytes": 10 }], -]); - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_06.js b/devtools/shared/heapsnapshot/tests/unit/test_census_diff_06.js deleted file mode 100644 index 430ff8c9c..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_diff_06.js +++ /dev/null @@ -1,137 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test diffing census reports of a "complex" and "realistic" breakdown. - -const BREAKDOWN = { - by: "coarseType", - objects: { - by: "allocationStack", - then: { - by: "objectClass", - then: { by: "count", count: false, bytes: true }, - other: { by: "count", count: false, bytes: true } - }, - noStack: { - by: "objectClass", - then: { by: "count", count: false, bytes: true }, - other: { by: "count", count: false, bytes: true } - } - }, - strings: { - by: "internalType", - then: { by: "count", count: false, bytes: true } - }, - scripts: { - by: "internalType", - then: { by: "count", count: false, bytes: true } - }, - other: { - by: "internalType", - then: { by: "count", count: false, bytes: true } - }, -}; - -const stack1 = saveStack(); -const stack2 = saveStack(); -const stack3 = saveStack(); - -const REPORT1 = { - objects: new Map([ - [stack1, { Function: { bytes: 1 }, - Object: { bytes: 2 }, - other: { bytes: 0 }, - }], - [stack2, { Array: { bytes: 3 }, - Date: { bytes: 4 }, - other: { bytes: 0 }, - }], - ["noStack", { Object: { bytes: 3 }}], - ]), - strings: { - JSAtom: { bytes: 10 }, - JSLinearString: { bytes: 5 }, - }, - scripts: { - JSScript: { bytes: 1 }, - "js::jit::JitCode": { bytes: 2 }, - }, - other: { - "mozilla::dom::Thing": { bytes: 1 }, - } -}; - -const REPORT2 = { - objects: new Map([ - [stack2, { Array: { bytes: 1 }, - Date: { bytes: 2 }, - other: { bytes: 3 }, - }], - [stack3, { Function: { bytes: 1 }, - Object: { bytes: 2 }, - other: { bytes: 0 }, - }], - ["noStack", { Object: { bytes: 3 }}], - ]), - strings: { - JSAtom: { bytes: 5 }, - JSLinearString: { bytes: 10 }, - }, - scripts: { - JSScript: { bytes: 2 }, - "js::LazyScript": { bytes: 42 }, - "js::jit::JitCode": { bytes: 1 }, - }, - other: { - "mozilla::dom::OtherThing": { bytes: 1 }, - } -}; - -const EXPECTED = { - "objects": new Map([ - [stack1, { Function: { bytes: -1 }, - Object: { bytes: -2 }, - other: { bytes: 0 }, - }], - [stack2, { Array: { bytes: -2 }, - Date: { bytes: -2 }, - other: { bytes: 3 }, - }], - [stack3, { Function: { bytes: 1 }, - Object: { bytes: 2 }, - other: { bytes: 0 }, - }], - ["noStack", { Object: { bytes: 0 }}], - ]), - "scripts": { - "JSScript": { - "bytes": 1 - }, - "js::jit::JitCode": { - "bytes": -1 - }, - "js::LazyScript": { - "bytes": 42 - } - }, - "strings": { - "JSAtom": { - "bytes": -5 - }, - "JSLinearString": { - "bytes": 5 - } - }, - "other": { - "mozilla::dom::Thing": { - "bytes": -1 - }, - "mozilla::dom::OtherThing": { - "bytes": 1 - } - } -}; - -function run_test() { - assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_01.js b/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_01.js deleted file mode 100644 index 57724d7c1..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_01.js +++ /dev/null @@ -1,105 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test filtering basic CensusTreeNode trees. - -function run_test() { - const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other:{ - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - }; - - const REPORT = { - objects: { - Array: { bytes: 50, count: 5 }, - UInt8Array: { bytes: 80, count: 8 }, - Int32Array: { bytes: 320, count: 32 }, - other: { bytes: 0, count: 0 }, - }, - scripts: { - "js::jit::JitScript": { bytes: 30, count: 3 }, - }, - strings: { - JSAtom: { bytes: 60, count: 6 }, - }, - other: { - "js::Shape": { bytes: 80, count: 8 }, - } - }; - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 620, - count: 0, - totalCount: 62, - children: [ - { - name: "objects", - bytes: 0, - totalBytes: 450, - count: 0, - totalCount: 45, - children: [ - { - name: "Int32Array", - bytes: 320, - totalBytes: 320, - count: 32, - totalCount: 32, - children: undefined, - id: 15, - parent: 14, - reportLeafIndex: 4, - }, - { - name: "UInt8Array", - bytes: 80, - totalBytes: 80, - count: 8, - totalCount: 8, - children: undefined, - id: 16, - parent: 14, - reportLeafIndex: 3, - }, - { - name: "Array", - bytes: 50, - totalBytes: 50, - count: 5, - totalCount: 5, - children: undefined, - id: 17, - parent: 14, - reportLeafIndex: 2, - } - ], - id: 14, - parent: 13, - reportLeafIndex: undefined, - } - ], - id: 13, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "Array" }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_02.js b/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_02.js deleted file mode 100644 index 0a57ce66d..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_02.js +++ /dev/null @@ -1,124 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test filtering CensusTreeNode trees with an `allocationStack` breakdown. - -function run_test() { - const countBreakdown = { by: "count", count: true, bytes: true }; - - const BREAKDOWN = { - by: "allocationStack", - then: countBreakdown, - noStack: countBreakdown, - }; - - let stack1, stack2, stack3, stack4, stack5; - - (function foo() { - (function bar() { - (function baz() { - stack1 = saveStack(3); - }()); - (function quux() { - stack2 = saveStack(3); - stack3 = saveStack(3); - }()); - }()); - stack4 = saveStack(2); - }()); - - stack5 = saveStack(1); - - const REPORT = new Map([ - [stack1, { bytes: 10, count: 1 }], - [stack2, { bytes: 20, count: 2 }], - [stack3, { bytes: 30, count: 3 }], - [stack4, { bytes: 40, count: 4 }], - [stack5, { bytes: 50, count: 5 }], - ["noStack", { bytes: 60, count: 6 }], - ]); - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 210, - count: 0, - totalCount: 21, - children: [ - { - name: stack1.parent.parent, - bytes: 0, - totalBytes: 60, - count: 0, - totalCount: 6, - children: [ - { - name: stack2.parent, - bytes: 0, - totalBytes: 50, - count: 0, - totalCount: 5, - children: [ - { - name: stack3, - bytes: 30, - totalBytes: 30, - count: 3, - totalCount: 3, - children: undefined, - id: 15, - parent: 14, - reportLeafIndex: 3, - }, - { - name: stack2, - bytes: 20, - totalBytes: 20, - count: 2, - totalCount: 2, - children: undefined, - id: 16, - parent: 14, - reportLeafIndex: 2, - } - ], - id: 14, - parent: 13, - reportLeafIndex: undefined, - }, - { - name: stack1.parent, - bytes: 0, - totalBytes: 10, - count: 0, - totalCount: 1, - children: [ - { - name: stack1, - bytes: 10, - totalBytes: 10, - count: 1, - totalCount: 1, - children: undefined, - id: 18, - parent: 17, - reportLeafIndex: 1, - } - ], - id: 17, - parent: 13, - reportLeafIndex: undefined, - } - ], - id: 13, - parent: 12, - reportLeafIndex: undefined, - } - ], - id: 12, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "bar" }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_03.js b/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_03.js deleted file mode 100644 index 2c69a14b8..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_03.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test filtering with no matches. - -function run_test() { - const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - scripts: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - strings: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - other:{ - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - }; - - const REPORT = { - objects: { - Array: { bytes: 50, count: 5 }, - UInt8Array: { bytes: 80, count: 8 }, - Int32Array: { bytes: 320, count: 32 }, - other: { bytes: 0, count: 0 }, - }, - scripts: { - "js::jit::JitScript": { bytes: 30, count: 3 }, - }, - strings: { - JSAtom: { bytes: 60, count: 6 }, - }, - other: { - "js::Shape": { bytes: 80, count: 8 }, - } - }; - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 620, - count: 0, - totalCount: 62, - children: undefined, - id: 13, - parent: undefined, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "zzzzzzzzzzzzzzzzzzzz" }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_04.js b/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_04.js deleted file mode 100644 index c9871436b..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_04.js +++ /dev/null @@ -1,102 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the filtered nodes' counts and bytes are the same as they were when -// unfiltered. - -function run_test() { - const COUNT = { by: "count", count: true, bytes: true }; - const INTERNAL_TYPE = { by: "internalType", then: COUNT }; - - const BREAKDOWN = { - by: "coarseType", - objects: { by: "objectClass", then: COUNT, other: COUNT }, - strings: COUNT, - scripts: { - by: "filename", - then: INTERNAL_TYPE, - noFilename: INTERNAL_TYPE - }, - other: INTERNAL_TYPE, - }; - - const REPORT = { - objects: { - Function: { - count: 7, - bytes: 70 - }, - Array: { - count: 6, - bytes: 60 - } - }, - scripts: { - "http://mozilla.github.io/pdf.js/build/pdf.js": { - "js::LazyScript": { - count: 4, - bytes: 40 - }, - } - }, - strings: { - count: 2, - bytes: 20 - }, - other: { - "js::Shape": { - count: 1, - bytes: 10 - } - } - }; - - const EXPECTED = { - name: null, - bytes: 0, - totalBytes: 200, - count: 0, - totalCount: 20, - parent: undefined, - children: [ - { - name: "objects", - bytes: 0, - totalBytes: 130, - count: 0, - totalCount: 13, - children: [ - { - name: "Function", - bytes: 70, - totalBytes: 70, - count: 7, - totalCount: 7, - id: 13, - parent: 12, - children: undefined, - reportLeafIndex: 2, - }, - { - name: "Array", - bytes: 60, - totalBytes: 60, - count: 6, - totalCount: 6, - id: 14, - parent: 12, - children: undefined, - reportLeafIndex: 3, - }, - ], - id: 12, - parent: 11, - reportLeafIndex: undefined, - } - ], - id: 11, - reportLeafIndex: undefined, - }; - - compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "objects" }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_05.js b/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_05.js deleted file mode 100644 index 1d1f4fa55..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_census_filtering_05.js +++ /dev/null @@ -1,71 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that filtered and inverted allocation stack census trees are sorted -// properly. - -function run_test() { - const countBreakdown = { by: "count", count: true, bytes: true }; - - const BREAKDOWN = { - by: "allocationStack", - then: countBreakdown, - noStack: countBreakdown, - }; - - const stacks = []; - - function foo(depth = 1) { - stacks.push(saveStack(depth)); - bar(depth + 1); - baz(depth + 1); - stacks.push(saveStack(depth)); - } - - function bar(depth = 1) { - stacks.push(saveStack(depth)); - stacks.push(saveStack(depth)); - } - - function baz(depth = 1) { - stacks.push(saveStack(depth)); - bang(depth + 1); - stacks.push(saveStack(depth)); - } - - function bang(depth = 1) { - stacks.push(saveStack(depth)); - stacks.push(saveStack(depth)); - stacks.push(saveStack(depth)); - } - - foo(); - bar(); - baz(); - bang(); - - const REPORT = new Map(stacks.map((s, i) => { - return [s, { - count: i + 1, - bytes: (i + 1) * 10 - }]; - })); - - const tree = censusReportToCensusTreeNode(BREAKDOWN, REPORT, { - filter: "baz", - invert: true - }); - - dumpn("tree = " + JSON.stringify(tree, savedFrameReplacer, 4)); - - (function assertSortedBySelf(node) { - if (node.children) { - let lastSelfBytes = Infinity; - for (let child of node.children) { - ok(child.bytes <= lastSelfBytes, `${child.bytes} <= ${lastSelfBytes}`); - lastSelfBytes = child.bytes; - assertSortedBySelf(child); - } - } - }(tree)); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js b/devtools/shared/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js deleted file mode 100644 index e89048c33..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js +++ /dev/null @@ -1,37 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// Test that we can turn a breakdown with { by: "count" } leaves into a -// breakdown with { by: "bucket" } leaves. - -const COUNT = { by: "count", count: true, bytes: true }; -const BUCKET = { by: "bucket" }; - -const BREAKDOWN = { - by: "coarseType", - objects: { by: "objectClass", then: COUNT, other: COUNT }, - strings: COUNT, - scripts: { - by: "filename", - then: { by: "internalType", then: COUNT }, - noFilename: { by: "internalType", then: COUNT }, - }, - other: { by: "internalType", then: COUNT }, -}; - -const EXPECTED = { - by: "coarseType", - objects: { by: "objectClass", then: BUCKET, other: BUCKET }, - strings: BUCKET, - scripts: { - by: "filename", - then: { by: "internalType", then: BUCKET }, - noFilename: { by: "internalType", then: BUCKET }, - }, - other: { by: "internalType", then: BUCKET }, -}; - -function run_test() { - assertCountToBucketBreakdown(BREAKDOWN, EXPECTED); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_deduplicatePaths_01.js b/devtools/shared/heapsnapshot/tests/unit/test_deduplicatePaths_01.js deleted file mode 100644 index 418b49db3..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_deduplicatePaths_01.js +++ /dev/null @@ -1,113 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// Test the behavior of the deduplicatePaths utility function. - -function edge(from, to, name) { - return { from, to, name }; -} - -function run_test() { - const a = 1; - const b = 2; - const c = 3; - const d = 4; - const e = 5; - const f = 6; - const g = 7; - - dumpn("Single long path"); - assertDeduplicatedPaths({ - target: g, - paths: [ - [ - pathEntry(a, "e1"), - pathEntry(b, "e2"), - pathEntry(c, "e3"), - pathEntry(d, "e4"), - pathEntry(e, "e5"), - pathEntry(f, "e6"), - ] - ], - expectedNodes: [a, b, c, d, e, f, g], - expectedEdges: [ - edge(a, b, "e1"), - edge(b, c, "e2"), - edge(c, d, "e3"), - edge(d, e, "e4"), - edge(e, f, "e5"), - edge(f, g, "e6"), - ] - }); - - dumpn("Multiple edges from and to the same nodes"); - assertDeduplicatedPaths({ - target: a, - paths: [ - [pathEntry(b, "x")], - [pathEntry(b, "y")], - [pathEntry(b, "z")], - ], - expectedNodes: [a, b], - expectedEdges: [ - edge(b, a, "x"), - edge(b, a, "y"), - edge(b, a, "z"), - ] - }); - - dumpn("Multiple paths sharing some nodes and edges"); - assertDeduplicatedPaths({ - target: g, - paths: [ - [ - pathEntry(a, "a->b"), - pathEntry(b, "b->c"), - pathEntry(c, "foo"), - ], - [ - pathEntry(a, "a->b"), - pathEntry(b, "b->d"), - pathEntry(d, "bar"), - ], - [ - pathEntry(a, "a->b"), - pathEntry(b, "b->e"), - pathEntry(e, "baz"), - ], - ], - expectedNodes: [a, b, c, d, e, g], - expectedEdges: [ - edge(a, b, "a->b"), - edge(b, c, "b->c"), - edge(b, d, "b->d"), - edge(b, e, "b->e"), - edge(c, g, "foo"), - edge(d, g, "bar"), - edge(e, g, "baz"), - ] - }); - - dumpn("Second shortest path contains target itself"); - assertDeduplicatedPaths({ - target: g, - paths: [ - [ - pathEntry(a, "a->b"), - pathEntry(b, "b->g"), - ], - [ - pathEntry(a, "a->b"), - pathEntry(b, "b->g"), - pathEntry(g, "g->f"), - pathEntry(f, "f->g"), - ], - ], - expectedNodes: [a, b, g], - expectedEdges: [ - edge(a, b, "a->b"), - edge(b, g, "b->g"), - ] - }); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js b/devtools/shared/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js deleted file mode 100644 index 9c4f60991..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js +++ /dev/null @@ -1,60 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// Test basic functionality of `CensusUtils.getCensusIndividuals`. - -function run_test() { - const stack1 = saveStack(1); - const stack2 = saveStack(1); - const stack3 = saveStack(1); - - const COUNT = { by: "count", count: true, bytes: true }; - const INTERNAL_TYPE = { by: "internalType", then: COUNT }; - - const BREAKDOWN = { - by: "allocationStack", - then: INTERNAL_TYPE, - noStack: INTERNAL_TYPE, - }; - - const MOCK_SNAPSHOT = { - takeCensus: ({ breakdown }) => { - assertStructurallyEquivalent( - breakdown, - CensusUtils.countToBucketBreakdown(BREAKDOWN)); - - // DFS Index - return new Map([ // 0 - [stack1, { // 1 - JSObject: [101, 102, 103], // 2 - JSString: [111, 112, 113], // 3 - }], - [stack2, { // 4 - JSObject: [201, 202, 203], // 5 - JSString: [211, 212, 213], // 6 - }], - [stack3, { // 7 - JSObject: [301, 302, 303], // 8 - JSString: [311, 312, 313], // 9 - }], - ["noStack", { // 10 - JSObject: [401, 402, 403], // 11 - JSString: [411, 412, 413], // 12 - }], - ]); - } - }; - - const INDICES = new Set([3, 5, 9]); - - const EXPECTED = new Set([111, 112, 113, - 201, 202, 203, - 311, 312, 313]); - - const actual = new Set(CensusUtils.getCensusIndividuals(INDICES, - BREAKDOWN, - MOCK_SNAPSHOT)); - - assertStructurallyEquivalent(EXPECTED, actual); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_getReportLeaves_01.js b/devtools/shared/heapsnapshot/tests/unit/test_getReportLeaves_01.js deleted file mode 100644 index 4c4298b6a..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_getReportLeaves_01.js +++ /dev/null @@ -1,114 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// Test basic functionality of `CensusUtils.getReportLeaves`. - -function run_test() { - const BREAKDOWN = { - by: "coarseType", - objects: { - by: "objectClass", - then: { by: "count", count: true, bytes: true }, - other: { by: "count", count: true, bytes: true }, - }, - strings: { by: "count", count: true, bytes: true }, - scripts: { - by: "filename", - then: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - noFilename: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - }, - other: { - by: "internalType", - then: { by: "count", count: true, bytes: true }, - }, - }; - - const REPORT = { - objects: { - Array: { count: 6, bytes: 60 }, - Function: { count: 1, bytes: 10 }, - Object: { count: 1, bytes: 10 }, - RegExp: { count: 1, bytes: 10 }, - other: { count: 0, bytes: 0 }, - }, - strings: { count: 1, bytes: 10 }, - scripts: { - "foo.js": { - JSScript: { count: 1, bytes: 10 }, - "js::jit::IonScript": { count: 1, bytes: 10 }, - }, - noFilename: { - JSScript: { count: 1, bytes: 10 }, - "js::jit::IonScript": { count: 1, bytes: 10 }, - }, - }, - other: { - "js::Shape": { count: 7, bytes: 70 }, - "js::BaseShape": { count: 1, bytes: 10 }, - }, - }; - - const root = censusReportToCensusTreeNode(BREAKDOWN, REPORT); - dumpn("CensusTreeNode tree = " + JSON.stringify(root, null, 4)); - - (function assertEveryNodeCanFindItsLeaf(node) { - if (node.reportLeafIndex) { - const [ leaf ] = CensusUtils.getReportLeaves(new Set([node.reportLeafIndex]), - BREAKDOWN, - REPORT); - ok(leaf, "Should be able to find leaf for a node with a reportLeafIndex = " + node.reportLeafIndex); - } - - if (node.children) { - for (let child of node.children) { - assertEveryNodeCanFindItsLeaf(child); - } - } - }(root)); - - // Test finding multiple leaves at a time. - - function find(name, node) { - if (node.name === name) { - return node; - } - - if (node.children) { - for (let child of node.children) { - const found = find(name, child); - if (found) { - return found; - } - } - } - } - - const arrayNode = find("Array", root); - ok(arrayNode); - equal(typeof arrayNode.reportLeafIndex, "number"); - - const shapeNode = find("js::Shape", root); - ok(shapeNode); - equal(typeof shapeNode.reportLeafIndex, "number"); - - const indices = new Set([arrayNode.reportLeafIndex, shapeNode.reportLeafIndex]); - const leaves = CensusUtils.getReportLeaves(indices, BREAKDOWN, REPORT); - equal(leaves.length, 2); - - // `getReportLeaves` does not guarantee order of the results, so handle both - // cases. - ok(leaves.some(l => l === REPORT.objects.Array)); - ok(leaves.some(l => l === REPORT.other["js::Shape"])); - - // Test that bad indices do not yield results. - - const none = CensusUtils.getReportLeaves(new Set([999999999999]), BREAKDOWN, REPORT); - equal(none.length, 0); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js b/devtools/shared/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js deleted file mode 100644 index 067b9effb..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test saving a heap snapshot in the sandboxed e10s child process. - -function run_test() { - run_test_in_child("../unit/test_SaveHeapSnapshot.js"); -} diff --git a/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini b/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini deleted file mode 100644 index f84b282d1..000000000 --- a/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini +++ /dev/null @@ -1,98 +0,0 @@ -[DEFAULT] -tags = devtools heapsnapshot devtools-memory -head = head_heapsnapshot.js -tail = -firefox-appdir = browser -skip-if = toolkit == 'android' - -support-files = - Census.jsm - dominator-tree-worker.js - heap-snapshot-worker.js - Match.jsm - -[test_census_diff_01.js] -[test_census_diff_02.js] -[test_census_diff_03.js] -[test_census_diff_04.js] -[test_census_diff_05.js] -[test_census_diff_06.js] -[test_census_filtering_01.js] -[test_census_filtering_02.js] -[test_census_filtering_03.js] -[test_census_filtering_04.js] -[test_census_filtering_05.js] -[test_census-tree-node-01.js] -[test_census-tree-node-02.js] -[test_census-tree-node-03.js] -[test_census-tree-node-04.js] -[test_census-tree-node-05.js] -[test_census-tree-node-06.js] -[test_census-tree-node-07.js] -[test_census-tree-node-08.js] -[test_census-tree-node-09.js] -[test_census-tree-node-10.js] -[test_countToBucketBreakdown_01.js] -[test_deduplicatePaths_01.js] -[test_DominatorTree_01.js] -[test_DominatorTree_02.js] -[test_DominatorTree_03.js] -[test_DominatorTree_04.js] -[test_DominatorTree_05.js] -[test_DominatorTree_06.js] -[test_DominatorTreeNode_attachShortestPaths_01.js] -[test_DominatorTreeNode_getNodeByIdAlongPath_01.js] -[test_DominatorTreeNode_insert_01.js] -[test_DominatorTreeNode_insert_02.js] -[test_DominatorTreeNode_insert_03.js] -[test_DominatorTreeNode_LabelAndShallowSize_01.js] -[test_DominatorTreeNode_LabelAndShallowSize_02.js] -[test_DominatorTreeNode_LabelAndShallowSize_03.js] -[test_DominatorTreeNode_LabelAndShallowSize_04.js] -[test_DominatorTreeNode_partialTraversal_01.js] -[test_getCensusIndividuals_01.js] -[test_getReportLeaves_01.js] -[test_HeapAnalyses_computeDominatorTree_01.js] -[test_HeapAnalyses_computeDominatorTree_02.js] -[test_HeapAnalyses_deleteHeapSnapshot_01.js] -[test_HeapAnalyses_deleteHeapSnapshot_02.js] -[test_HeapAnalyses_deleteHeapSnapshot_03.js] -[test_HeapAnalyses_getCensusIndividuals_01.js] -[test_HeapAnalyses_getCreationTime_01.js] -[test_HeapAnalyses_getDominatorTree_01.js] -[test_HeapAnalyses_getDominatorTree_02.js] -[test_HeapAnalyses_getImmediatelyDominated_01.js] -[test_HeapAnalyses_readHeapSnapshot_01.js] -[test_HeapAnalyses_takeCensusDiff_01.js] -[test_HeapAnalyses_takeCensusDiff_02.js] -[test_HeapAnalyses_takeCensus_01.js] -[test_HeapAnalyses_takeCensus_02.js] -[test_HeapAnalyses_takeCensus_03.js] -[test_HeapAnalyses_takeCensus_04.js] -[test_HeapAnalyses_takeCensus_05.js] -[test_HeapAnalyses_takeCensus_06.js] -[test_HeapAnalyses_takeCensus_07.js] -[test_HeapSnapshot_creationTime_01.js] -[test_HeapSnapshot_deepStack_01.js] -[test_HeapSnapshot_describeNode_01.js] -[test_HeapSnapshot_computeShortestPaths_01.js] -[test_HeapSnapshot_computeShortestPaths_02.js] -[test_HeapSnapshot_takeCensus_01.js] -[test_HeapSnapshot_takeCensus_02.js] -[test_HeapSnapshot_takeCensus_03.js] -[test_HeapSnapshot_takeCensus_04.js] -[test_HeapSnapshot_takeCensus_05.js] -[test_HeapSnapshot_takeCensus_06.js] -[test_HeapSnapshot_takeCensus_07.js] -[test_HeapSnapshot_takeCensus_08.js] -[test_HeapSnapshot_takeCensus_09.js] -[test_HeapSnapshot_takeCensus_10.js] -[test_HeapSnapshot_takeCensus_11.js] -[test_HeapSnapshot_takeCensus_12.js] -[test_ReadHeapSnapshot.js] -[test_ReadHeapSnapshot_with_allocations.js] -skip-if = os == 'linux' # Bug 1176173 -[test_ReadHeapSnapshot_worker.js] -skip-if = os == 'linux' # Bug 1176173 -[test_SaveHeapSnapshot.js] -[test_saveHeapSnapshot_e10s_01.js] diff --git a/devtools/shared/jsinspector/moz.build b/devtools/shared/jsinspector/moz.build deleted file mode 100644 index fc81f7e1e..000000000 --- a/devtools/shared/jsinspector/moz.build +++ /dev/null @@ -1,17 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIJSInspector.idl', -] - -XPIDL_MODULE = 'jsinspector' - -SOURCES += [ - 'nsJSInspector.cpp', -] - -FINAL_LIBRARY = 'xul' diff --git a/devtools/shared/jsinspector/nsIJSInspector.idl b/devtools/shared/jsinspector/nsIJSInspector.idl deleted file mode 100644 index 40ad49523..000000000 --- a/devtools/shared/jsinspector/nsIJSInspector.idl +++ /dev/null @@ -1,75 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -/** - * Utilities for running nested event loops, asking them to return, and - * keeping track of which ones are still running. - */ -[scriptable, uuid(6758d0d7-e96a-4c5c-bca8-3bcbe5a15943)] -interface nsIJSInspector : nsISupports -{ - /** - * Process the current thread's event queue, calling event handlers until - * a call to exitNestedEventLoop, below, asks us to return. - * - * The name 'enterNestedEventLoop' may be misleading if read too literally. - * This method loops calling event handlers until one asks it to stop, and - * then returns. So by that point, the nested event loop has been not only - * entered, but also run and exited. - * - * When enterNestedEventLoop calls an event handler, that handler may itself - * call enterNestedEventLoop, and so on, so that there may be arbitrarily - * many such calls on the stack at the same time. - * - * We say an enterNestedEventLoop call is "running" if it has not yet been - * asked to return, or "stopped" if it has been asked to return once it has - * finished processing the current event. - * - * @param requestor A token of the caller's choice to identify this event - * loop. - * - * @return depth The number of running enterNestedEventLoop calls - * remaining, now that this one has returned. - * - * (Note that not all calls still on the stack are - * necessary running; exitNestedEventLoop can ask any - * number of enterNestedEventLoop calls to return.) - */ - unsigned long enterNestedEventLoop(in jsval requestor); - - /** - * Stop the youngest running enterNestedEventLoop call, asking it to return - * once it has finished processing the current event. - * - * The name 'exitNestedEventLoop' may be misleading if read too literally. - * The affected event loop does not return immediately when this method is - * called. Rather, this method simply returns to its caller; the affected - * loop's current event handler is allowed to run to completion; and then - * that loop returns without processing any more events. - * - * This method ignores loops that have already been stopped, and operates on - * the youngest loop that is still running. Each call to this method stops - * another running loop. - * - * @return depth The number of running enterNestedEventLoop calls - * remaining, now that one has been stopped. - * - * @throws NS_ERROR_FAILURE if there are no running enterNestedEventLoop calls. - */ - unsigned long exitNestedEventLoop(); - - /** - * The number of running enterNestedEventLoop calls on the stack. - * This count does not include stopped enterNestedEventLoop calls. - */ - readonly attribute unsigned long eventLoopNestLevel; - - /** - * The |requestor| value that was passed to the youngest running - * enterNestedEventLoop call. - */ - readonly attribute jsval lastNestRequestor; -}; diff --git a/devtools/shared/jsinspector/nsJSInspector.cpp b/devtools/shared/jsinspector/nsJSInspector.cpp deleted file mode 100644 index 457e64c08..000000000 --- a/devtools/shared/jsinspector/nsJSInspector.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsJSInspector.h" -#include "nsIXPConnect.h" -#include "nsThreadUtils.h" -#include "jsfriendapi.h" -#include "mozilla/HoldDropJSObjects.h" -#include "mozilla/ModuleUtils.h" -#include "mozilla/dom/ScriptSettings.h" -#include "nsServiceManagerUtils.h" -#include "nsMemory.h" -#include "nsArray.h" -#include "nsTArray.h" - -#define JSINSPECTOR_CONTRACTID \ - "@mozilla.org/jsinspector;1" - -#define JSINSPECTOR_CID \ -{ 0xec5aa99c, 0x7abb, 0x4142, { 0xac, 0x5f, 0xaa, 0xb2, 0x41, 0x9e, 0x38, 0xe2 } } - -namespace mozilla { -namespace jsinspector { - -NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSInspector) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSInspector) - NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIJSInspector) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSInspector) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSInspector) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSInspector) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSInspector) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSInspector) - tmp->mRequestors.Clear(); - tmp->mLastRequestor = JS::NullValue(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSInspector) - for (uint32_t i = 0; i < tmp->mRequestors.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRequestors[i]) - } - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLastRequestor) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -nsJSInspector::nsJSInspector() : mNestedLoopLevel(0), mRequestors(1), mLastRequestor(JS::NullValue()) -{ -} - -nsJSInspector::~nsJSInspector() -{ - MOZ_ASSERT(mRequestors.Length() == 0); - MOZ_ASSERT(mLastRequestor.isNull()); - mozilla::DropJSObjects(this); -} - -NS_IMETHODIMP -nsJSInspector::EnterNestedEventLoop(JS::Handle<JS::Value> requestor, uint32_t *out) -{ - nsresult rv = NS_OK; - - mLastRequestor = requestor; - mRequestors.AppendElement(requestor); - mozilla::HoldJSObjects(this); - - mozilla::dom::AutoNoJSAPI nojsapi; - - uint32_t nestLevel = ++mNestedLoopLevel; - while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) { - if (!NS_ProcessNextEvent()) - rv = NS_ERROR_UNEXPECTED; - } - - NS_ASSERTION(mNestedLoopLevel <= nestLevel, - "nested event didn't unwind properly"); - - if (mNestedLoopLevel == nestLevel) { - mLastRequestor = mRequestors.ElementAt(--mNestedLoopLevel); - } - - *out = mNestedLoopLevel; - return rv; -} - -NS_IMETHODIMP -nsJSInspector::ExitNestedEventLoop(uint32_t *out) -{ - if (mNestedLoopLevel > 0) { - mRequestors.RemoveElementAt(--mNestedLoopLevel); - if (mNestedLoopLevel > 0) - mLastRequestor = mRequestors.ElementAt(mNestedLoopLevel - 1); - else - mLastRequestor = JS::NullValue(); - } else { - return NS_ERROR_FAILURE; - } - - *out = mNestedLoopLevel; - - return NS_OK; -} - -NS_IMETHODIMP -nsJSInspector::GetEventLoopNestLevel(uint32_t *out) -{ - *out = mNestedLoopLevel; - return NS_OK; -} - -NS_IMETHODIMP -nsJSInspector::GetLastNestRequestor(JS::MutableHandle<JS::Value> out) -{ - out.set(mLastRequestor); - return NS_OK; -} - -} // namespace jsinspector -} // namespace mozilla - -NS_DEFINE_NAMED_CID(JSINSPECTOR_CID); - -static const mozilla::Module::CIDEntry kJSInspectorCIDs[] = { - { &kJSINSPECTOR_CID, false, nullptr, mozilla::jsinspector::nsJSInspectorConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kJSInspectorContracts[] = { - { JSINSPECTOR_CONTRACTID, &kJSINSPECTOR_CID }, - { nullptr } -}; - -static const mozilla::Module kJSInspectorModule = { - mozilla::Module::kVersion, - kJSInspectorCIDs, - kJSInspectorContracts -}; - -NSMODULE_DEFN(jsinspector) = &kJSInspectorModule; diff --git a/devtools/shared/jsinspector/nsJSInspector.h b/devtools/shared/jsinspector/nsJSInspector.h deleted file mode 100644 index 4e60b0428..000000000 --- a/devtools/shared/jsinspector/nsJSInspector.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef COMPONENTS_JSINSPECTOR_H -#define COMPONENTS_JSINSPECTOR_H - -#include "nsIJSInspector.h" -#include "mozilla/Attributes.h" -#include "nsCycleCollectionParticipant.h" -#include "nsTArray.h" -#include "js/Value.h" -#include "js/RootingAPI.h" - -namespace mozilla { -namespace jsinspector { - -class nsJSInspector final : public nsIJSInspector -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSInspector) - NS_DECL_NSIJSINSPECTOR - - nsJSInspector(); - -private: - ~nsJSInspector(); - - uint32_t mNestedLoopLevel; - nsTArray<JS::Heap<JS::Value> > mRequestors; - JS::Heap<JS::Value> mLastRequestor; -}; - -} // namespace jsinspector -} // namespace mozilla - -#endif diff --git a/devtools/shared/moz.build b/devtools/shared/moz.build index 6c61206dd..9dd4a20d6 100644 --- a/devtools/shared/moz.build +++ b/devtools/shared/moz.build @@ -14,10 +14,8 @@ DIRS += [ 'discovery', 'fronts', 'gcli', - 'heapsnapshot', 'inspector', 'jsbeautify', - 'jsinspector', 'layout', 'locales', 'node-properties', |