@memlab/core 1.1.6 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/__tests__/parser/HeapParser.test.d.ts +1 -1
  2. package/dist/__tests__/parser/HeapParser.test.js +3 -3
  3. package/dist/__tests__/parser/NodeHeap.test.d.ts +1 -1
  4. package/dist/__tests__/parser/NodeHeap.test.js +6 -6
  5. package/dist/__tests__/parser/StringNode.test.d.ts +1 -1
  6. package/dist/__tests__/parser/StringNode.test.js +2 -2
  7. package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.d.ts +1 -1
  8. package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.js +3 -3
  9. package/dist/__tests__/utils/utils.test.d.ts +1 -1
  10. package/dist/__tests__/utils/utils.test.js +1 -1
  11. package/dist/index.d.ts +4 -2
  12. package/dist/index.js +6 -3
  13. package/dist/lib/BaseOption.d.ts +1 -1
  14. package/dist/lib/BaseOption.js +1 -1
  15. package/dist/lib/BrowserInfo.d.ts +1 -1
  16. package/dist/lib/BrowserInfo.js +1 -1
  17. package/dist/lib/Config.d.ts +8 -2
  18. package/dist/lib/Config.js +23 -12
  19. package/dist/lib/Console.d.ts +1 -1
  20. package/dist/lib/Console.js +1 -1
  21. package/dist/lib/Constant.d.ts +1 -1
  22. package/dist/lib/Constant.js +1 -1
  23. package/dist/lib/FileManager.d.ts +1 -1
  24. package/dist/lib/FileManager.js +5 -3
  25. package/dist/lib/HeapAnalyzer.d.ts +9 -1
  26. package/dist/lib/HeapAnalyzer.js +51 -9
  27. package/dist/lib/HeapParser.d.ts +2 -2
  28. package/dist/lib/HeapParser.js +2 -2
  29. package/dist/lib/InternalValueSetter.d.ts +1 -1
  30. package/dist/lib/InternalValueSetter.js +1 -1
  31. package/dist/lib/NodeHeap.d.ts +35 -12
  32. package/dist/lib/NodeHeap.js +55 -24
  33. package/dist/lib/PackageInfoLoader.js +1 -1
  34. package/dist/lib/ProcessManager.d.ts +1 -1
  35. package/dist/lib/ProcessManager.js +1 -1
  36. package/dist/lib/Serializer.d.ts +1 -1
  37. package/dist/lib/Serializer.js +1 -1
  38. package/dist/lib/StringLoader.d.ts +2 -2
  39. package/dist/lib/StringLoader.js +2 -2
  40. package/dist/lib/Types.d.ts +51 -33
  41. package/dist/lib/Types.js +1 -1
  42. package/dist/lib/Utils.d.ts +3 -1
  43. package/dist/lib/Utils.js +71 -33
  44. package/dist/lib/heap-data/HeapEdge.d.ts +2 -2
  45. package/dist/lib/heap-data/HeapEdge.js +2 -2
  46. package/dist/lib/heap-data/HeapLocation.d.ts +2 -2
  47. package/dist/lib/heap-data/HeapLocation.js +2 -2
  48. package/dist/lib/heap-data/HeapNode.d.ts +3 -2
  49. package/dist/lib/heap-data/HeapNode.js +6 -2
  50. package/dist/lib/heap-data/HeapSnapshot.d.ts +3 -2
  51. package/dist/lib/heap-data/HeapSnapshot.js +6 -33
  52. package/dist/lib/heap-data/HeapStringNode.d.ts +2 -2
  53. package/dist/lib/heap-data/HeapStringNode.js +4 -2
  54. package/dist/lib/heap-data/HeapUtils.d.ts +2 -2
  55. package/dist/lib/heap-data/HeapUtils.js +2 -2
  56. package/dist/lib/heap-data/MemLabTagStore.d.ts +23 -0
  57. package/dist/lib/heap-data/MemLabTagStore.js +110 -0
  58. package/dist/lib/leak-filters/BaseLeakFilter.rule.d.ts +1 -1
  59. package/dist/lib/leak-filters/BaseLeakFilter.rule.js +1 -1
  60. package/dist/lib/leak-filters/LeakFilterRuleList.d.ts +1 -1
  61. package/dist/lib/leak-filters/LeakFilterRuleList.js +1 -1
  62. package/dist/lib/leak-filters/LeakObjectFilter.d.ts +1 -1
  63. package/dist/lib/leak-filters/LeakObjectFilter.js +1 -1
  64. package/dist/lib/leak-filters/rules/FilterByExternalFilter.rule.d.ts +1 -1
  65. package/dist/lib/leak-filters/rules/FilterByExternalFilter.rule.js +1 -1
  66. package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.d.ts +1 -1
  67. package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.js +1 -1
  68. package/dist/lib/leak-filters/rules/FilterHermesNode.rule.d.ts +1 -1
  69. package/dist/lib/leak-filters/rules/FilterHermesNode.rule.js +1 -1
  70. package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.d.ts +1 -1
  71. package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.js +1 -1
  72. package/dist/lib/leak-filters/rules/FilterStackTraceFrame.rule.d.ts +1 -1
  73. package/dist/lib/leak-filters/rules/FilterStackTraceFrame.rule.js +1 -1
  74. package/dist/lib/leak-filters/rules/FilterTrivialNode.rule.d.ts +1 -1
  75. package/dist/lib/leak-filters/rules/FilterTrivialNode.rule.js +1 -1
  76. package/dist/lib/leak-filters/rules/FilterUnmountedFiberNode.rule.d.ts +1 -1
  77. package/dist/lib/leak-filters/rules/FilterUnmountedFiberNode.rule.js +1 -1
  78. package/dist/logger/LeakClusterLogger.d.ts +1 -1
  79. package/dist/logger/LeakClusterLogger.js +1 -1
  80. package/dist/logger/LeakTraceDetailsLogger.d.ts +1 -1
  81. package/dist/logger/LeakTraceDetailsLogger.js +1 -1
  82. package/dist/modes/BaseMode.d.ts +1 -1
  83. package/dist/modes/BaseMode.js +1 -1
  84. package/dist/modes/InteractionTestMode.d.ts +1 -1
  85. package/dist/modes/InteractionTestMode.js +1 -1
  86. package/dist/modes/MeasureMode.d.ts +1 -1
  87. package/dist/modes/MeasureMode.js +1 -1
  88. package/dist/modes/RunningModes.d.ts +1 -1
  89. package/dist/modes/RunningModes.js +1 -1
  90. package/dist/paths/TraceFinder.d.ts +1 -1
  91. package/dist/paths/TraceFinder.js +58 -40
  92. package/dist/trace-cluster/ClusterUtils.d.ts +1 -1
  93. package/dist/trace-cluster/ClusterUtils.js +1 -1
  94. package/dist/trace-cluster/ClusterUtilsHelper.d.ts +1 -1
  95. package/dist/trace-cluster/ClusterUtilsHelper.js +1 -1
  96. package/dist/trace-cluster/ClusteringHeuristics.d.ts +1 -1
  97. package/dist/trace-cluster/ClusteringHeuristics.js +1 -1
  98. package/dist/trace-cluster/EvalutationMetric.d.ts +1 -1
  99. package/dist/trace-cluster/EvalutationMetric.js +1 -1
  100. package/dist/trace-cluster/SequentialClustering.d.ts +17 -0
  101. package/dist/trace-cluster/SequentialClustering.js +47 -0
  102. package/dist/trace-cluster/TraceBucket.d.ts +2 -1
  103. package/dist/trace-cluster/TraceBucket.js +11 -3
  104. package/dist/trace-cluster/TraceElement.d.ts +3 -1
  105. package/dist/trace-cluster/TraceElement.js +7 -1
  106. package/dist/trace-cluster/strategies/MLTraceSimilarityStrategy.d.ts +1 -1
  107. package/dist/trace-cluster/strategies/MLTraceSimilarityStrategy.js +2 -2
  108. package/dist/trace-cluster/strategies/TraceAsClusterStrategy.d.ts +1 -1
  109. package/dist/trace-cluster/strategies/TraceAsClusterStrategy.js +1 -1
  110. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.d.ts +1 -1
  111. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +1 -1
  112. package/dist/trace-cluster/strategies/machine-learning/DistanceMatrix.d.ts +1 -1
  113. package/dist/trace-cluster/strategies/machine-learning/DistanceMatrix.js +1 -1
  114. package/dist/trace-cluster/strategies/machine-learning/HAC.d.ts +2 -2
  115. package/dist/trace-cluster/strategies/machine-learning/HAC.js +5 -7
  116. package/dist/trace-cluster/strategies/machine-learning/Ngram.d.ts +1 -1
  117. package/dist/trace-cluster/strategies/machine-learning/Ngram.js +1 -1
  118. package/dist/trace-cluster/strategies/machine-learning/TfidfVectorizer.d.ts +1 -1
  119. package/dist/trace-cluster/strategies/machine-learning/TfidfVectorizer.js +7 -3
  120. package/package.json +1 -1
package/dist/lib/Utils.js CHANGED
@@ -5,8 +5,8 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  *
8
- * @emails oncall+ws_labs
9
8
  * @format
9
+ * @oncall ws_labs
10
10
  */
11
11
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
12
  if (k2 === undefined) k2 = k;
@@ -136,10 +136,10 @@ function isDetachedFiberNode(node) {
136
136
  // any detached DOM nodes (e.g., HTMLXXElement, IntersectionObserver etc.)
137
137
  // that are not internal nodes.
138
138
  function isDetachedDOMNode(node, args = {}) {
139
- if (!node || typeof node.name !== 'string') {
139
+ let name = null;
140
+ if (!node || typeof (name = node.name) !== 'string') {
140
141
  return false;
141
142
  }
142
- const name = node.name;
143
143
  if (isFiberNode(node)) {
144
144
  return false;
145
145
  }
@@ -212,14 +212,28 @@ function isPendingActivityNode(node) {
212
212
  }
213
213
  return node.type === 'synthetic' && node.name === 'Pending activities';
214
214
  }
215
+ // check the node against a curated list of known HTML Elements
216
+ // the list may be incomplete
217
+ function isDOMNodeIncomplete(node) {
218
+ let name = node.name;
219
+ const pattern = /^HTML.*Element$/;
220
+ const detachedPrefix = 'Detached ';
221
+ if (name.startsWith(detachedPrefix)) {
222
+ name = name.substring(detachedPrefix.length);
223
+ }
224
+ return pattern.test(name);
225
+ }
215
226
  function isRootNode(node, opt = {}) {
216
- if (!node || !node.name) {
227
+ if (!node) {
217
228
  return false;
218
229
  }
219
230
  // consider Hermes snapshot GC roots
220
231
  if (Config_1.default.jsEngine === 'hermes') {
221
232
  return node.name === '(GC roots)' || node.name === '(GC Roots)';
222
233
  }
234
+ if (node.id === 0 || node.id === 1) {
235
+ return true;
236
+ }
223
237
  // the window object
224
238
  if (node.type === 'native' && node.name.indexOf('Window') === 0) {
225
239
  return true;
@@ -355,14 +369,16 @@ function getNodesIdSet(snapshot) {
355
369
  });
356
370
  return set;
357
371
  }
358
- // given a set of nodes S, return a subset S' where
372
+ // given a set of nodes S, return a minimal subset S' where
359
373
  // no nodes are dominated by nodes in S
360
374
  function getConditionalDominatorIds(ids, snapshot, condCb) {
361
375
  const dominatorIds = new Set();
376
+ const fullDominatorIds = new Set();
362
377
  // set all node ids
363
378
  applyToNodes(ids, snapshot, node => {
364
379
  if (condCb(node)) {
365
380
  dominatorIds.add(node.id);
381
+ fullDominatorIds.add(node.id);
366
382
  }
367
383
  });
368
384
  // traverse the dominators and remove the node
@@ -374,7 +390,7 @@ function getConditionalDominatorIds(ids, snapshot, condCb) {
374
390
  if (visited.has(cur.id)) {
375
391
  break;
376
392
  }
377
- if (dominatorIds.has(cur.id)) {
393
+ if (fullDominatorIds.has(cur.id)) {
378
394
  dominatorIds.delete(node.id);
379
395
  break;
380
396
  }
@@ -390,7 +406,6 @@ function setFiberNodeAttribute(node, flag) {
390
406
  if (!node || !isFiberNode(node)) {
391
407
  return;
392
408
  }
393
- // eslint-disable-next-line no-bitwise
394
409
  node.attributes |= flag;
395
410
  }
396
411
  function hasFiberNodeAttribute(node, flag) {
@@ -447,7 +462,6 @@ function filterNodesInPlace(idSet, snapshot, cb) {
447
462
  function applyToNodes(idSet, snapshot, cb, options = {}) {
448
463
  let ids = Array.from(idSet.keys());
449
464
  if (options.shuffle) {
450
- // eslint-disable-next-line fb-www/unsafe-math-random
451
465
  ids.sort(() => Math.random() - 0.5);
452
466
  }
453
467
  else if (options.reverse) {
@@ -508,7 +522,6 @@ function loadScenario(filename) {
508
522
  }
509
523
  let scenario;
510
524
  try {
511
- // eslint-disable-next-line @typescript-eslint/no-var-requires
512
525
  scenario = require(filepath);
513
526
  scenario = checkScenarioInstance(scenario);
514
527
  if (scenario.name == null) {
@@ -534,6 +547,12 @@ function handleSnapshotError(e) {
534
547
  }
535
548
  function getSnapshotFromFile(filename, options) {
536
549
  return __awaiter(this, void 0, void 0, function* () {
550
+ const heapConfig = Config_1.default.heapConfig;
551
+ if (heapConfig &&
552
+ heapConfig.currentHeapFile === filename &&
553
+ heapConfig.currentHeap) {
554
+ return heapConfig.currentHeap;
555
+ }
537
556
  Console_1.default.overwrite('parsing ' + filename + ' ...');
538
557
  let ret = null;
539
558
  try {
@@ -812,7 +831,6 @@ function loadRunMetaInfo(metaFile = undefined) {
812
831
  try {
813
832
  const content = fs_1.default.readFileSync(file, 'UTF-8');
814
833
  return JSON.parse(content);
815
- // eslint-disable-next-line fb-www/no-unused-catch-bindings
816
834
  }
817
835
  catch (_) {
818
836
  throw haltOrThrow('Run info missing. Please make sure `memlab run` is complete.');
@@ -1271,9 +1289,23 @@ function getSnapshotDirForAnalysis() {
1271
1289
  return dir;
1272
1290
  }
1273
1291
  function getSingleSnapshotFileForAnalysis() {
1274
- const path = Config_1.default.useExternalSnapshot && Config_1.default.externalSnapshotFilePaths[0]
1275
- ? Config_1.default.externalSnapshotFilePaths[0]
1276
- : getSnapshotFilePathWithTabType(/(final)|(target)|(baseline)/);
1292
+ let path = null;
1293
+ // if an external snapshot file is specified
1294
+ if (Config_1.default.useExternalSnapshot &&
1295
+ Config_1.default.externalSnapshotFilePaths.length > 0) {
1296
+ path =
1297
+ Config_1.default.externalSnapshotFilePaths[Config_1.default.externalSnapshotFilePaths.length - 1];
1298
+ // if running in interactive heap analysis mode
1299
+ }
1300
+ else if (Config_1.default.heapConfig &&
1301
+ Config_1.default.heapConfig.isCliInteractiveMode &&
1302
+ Config_1.default.heapConfig.currentHeapFile) {
1303
+ path = Config_1.default.heapConfig.currentHeapFile;
1304
+ // search for snapshot labeled as baseline, target, or final
1305
+ }
1306
+ else {
1307
+ path = getSnapshotFilePathWithTabType(/(final)|(target)|(baseline)/);
1308
+ }
1277
1309
  return resolveSnapshotFilePath(path);
1278
1310
  }
1279
1311
  function getSnapshotFilePath(tab) {
@@ -1286,7 +1318,7 @@ function getSnapshotFilePath(tab) {
1286
1318
  }
1287
1319
  return Config_1.default.externalSnapshotFilePaths[tab.idx - 1];
1288
1320
  }
1289
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
1321
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1290
1322
  function equalOrMatch(v1, v2) {
1291
1323
  const t1 = typeof v1;
1292
1324
  const t2 = typeof v2;
@@ -1319,7 +1351,8 @@ function isMeaningfulNode(node) {
1319
1351
  if (!node) {
1320
1352
  return false;
1321
1353
  }
1322
- if (Config_1.default.nodeNameBlockList.has(node.name)) {
1354
+ const nodeName = node.name;
1355
+ if (Config_1.default.nodeNameBlockList.has(nodeName)) {
1323
1356
  return false;
1324
1357
  }
1325
1358
  if (isFiberNode(node)) {
@@ -1330,13 +1363,13 @@ function isMeaningfulNode(node) {
1330
1363
  }
1331
1364
  // More details in https://github.com/ChromeDevTools/devtools-frontend
1332
1365
  // under front_end/heap_snapshot_worker/HeapSnapshot.ts
1333
- if (node.name === 'system / NativeContext') {
1366
+ if (nodeName === 'system / NativeContext') {
1334
1367
  return false;
1335
1368
  }
1336
- if (node.name === 'system / SourcePositionTableWithFrameCache') {
1369
+ if (nodeName === 'system / SourcePositionTableWithFrameCache') {
1337
1370
  return false;
1338
1371
  }
1339
- if (node.name === '(map descriptors)') {
1372
+ if (nodeName === '(map descriptors)') {
1340
1373
  return false;
1341
1374
  }
1342
1375
  if (node.type === 'code') {
@@ -1351,44 +1384,49 @@ function isMeaningfulEdge(edge, options = {}) {
1351
1384
  if (source.id === node.id) {
1352
1385
  return false;
1353
1386
  }
1354
- if (typeof edge.name_or_index === 'string' &&
1355
- Config_1.default.edgeNameBlockList.has(edge.name_or_index)) {
1387
+ const edgeNameOrIndex = edge.name_or_index;
1388
+ if (typeof edgeNameOrIndex === 'string' &&
1389
+ Config_1.default.edgeNameBlockList.has(edgeNameOrIndex)) {
1356
1390
  return false;
1357
1391
  }
1392
+ const edgeType = edge.type;
1358
1393
  // shortcut edge may be meaningful edges
1359
1394
  // --forceUpdate (variable)---> [native_bind]
1360
1395
  // --bound_argument_0 (shortcut)---> [FiberNode]
1361
- if (edge.type === 'weak' /* || edge.type === 'shortcut' */) {
1396
+ if (edgeType === 'weak' /* || edge.type === 'shortcut' */) {
1362
1397
  return false;
1363
1398
  }
1364
1399
  if (options.excludeWeakMapEdge && isWeakMapEdgeToKey(edge)) {
1365
1400
  return false;
1366
1401
  }
1367
- if (options.visited && options.visited[node.nodeIndex]) {
1402
+ const nodeIndex = node.nodeIndex;
1403
+ if (options.visited && options.visited[nodeIndex]) {
1368
1404
  return false;
1369
1405
  }
1370
- if (options.queued && options.queued[node.nodeIndex]) {
1406
+ if (options.queued && options.queued[nodeIndex]) {
1371
1407
  return false;
1372
1408
  }
1373
- if (!options.includeString && node.type === 'string') {
1409
+ const nodeType = node.type;
1410
+ if (!options.includeString && nodeType === 'string') {
1374
1411
  return false;
1375
1412
  }
1376
- if (edge.type === 'internal' && edge.name_or_index === 'code') {
1413
+ if (edgeType === 'internal' && edgeNameOrIndex === 'code') {
1377
1414
  return false;
1378
1415
  }
1379
1416
  // More details about the following three special cases are available
1380
1417
  // in https://github.com/ChromeDevTools/devtools-frontend
1381
1418
  // under front_end/heap_snapshot_worker/HeapSnapshot.ts
1382
- if (edge.type === 'hidden' && edge.name_or_index === 'sloppy_function_map') {
1419
+ if (edgeType === 'hidden' && edgeNameOrIndex === 'sloppy_function_map') {
1383
1420
  return false;
1384
1421
  }
1385
- if (edge.type === 'hidden' && node.name === 'system / NativeContext') {
1422
+ const nodeName = node.name;
1423
+ if (edgeType === 'hidden' && nodeName === 'system / NativeContext') {
1386
1424
  return false;
1387
1425
  }
1388
1426
  // In v8, (map descriptors) are fixed-length descriptors arrays used
1389
1427
  // to hold JS descriptors.
1390
- if (node.type === 'array' && node.name === '(map descriptors)') {
1391
- const index = edge.name_or_index;
1428
+ if (edgeType === 'array' && nodeName === '(map descriptors)') {
1429
+ const index = edgeNameOrIndex;
1392
1430
  // only elements at particular indexes of (map descriptors) are holding
1393
1431
  // representative references to objects.
1394
1432
  if (index >= 2 || (typeof index === 'number' && index % 3 === 1)) {
@@ -1401,12 +1439,12 @@ function isMeaningfulEdge(edge, options = {}) {
1401
1439
  if (Config_1.default.jsEngine === 'hermes' && isDirectPropEdge(edge)) {
1402
1440
  return false;
1403
1441
  }
1404
- if (Config_1.default.ignoreInternalNode && node.name.includes('InternalNode')) {
1442
+ if (Config_1.default.ignoreInternalNode && nodeName.includes('InternalNode')) {
1405
1443
  return false;
1406
1444
  }
1407
1445
  if (Config_1.default.ignoreDevToolsConsoleLeak) {
1408
- const name = edge.name_or_index;
1409
- if (typeof name === 'string' && name.includes('DevTools console')) {
1446
+ if (typeof edgeNameOrIndex === 'string' &&
1447
+ edgeNameOrIndex.includes('DevTools console')) {
1410
1448
  return false;
1411
1449
  }
1412
1450
  }
@@ -1421,7 +1459,6 @@ function isURLEqual(url1, url2) {
1421
1459
  try {
1422
1460
  u1 = new URL(url1);
1423
1461
  u2 = new URL(url2);
1424
- // eslint-disable-next-line fb-www/no-unused-catch-bindings
1425
1462
  }
1426
1463
  catch (_e) {
1427
1464
  return false;
@@ -1709,6 +1746,7 @@ exports.default = {
1709
1746
  isDetachedDOMNode,
1710
1747
  isDirectPropEdge,
1711
1748
  isDocumentDOMTreesRoot,
1749
+ isDOMNodeIncomplete,
1712
1750
  isEssentialEdge,
1713
1751
  isFiberNode,
1714
1752
  isFiberNodeDeletionsEdge,
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  import type { IHeapEdge } from '../Types';
12
12
  import type HeapSnapshot from './HeapSnapshot';
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  var __importDefault = (this && this.__importDefault) || function (mod) {
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  import type { IHeapLocation } from '../Types';
12
12
  import type HeapSnapshot from './HeapSnapshot';
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  import type { IHeapNode, IHeapEdge, Nullable, EdgeIterationCallback, Predicator, IHeapStringNode } from '../Types';
12
12
  import type HeapSnapshot from './HeapSnapshot';
@@ -36,6 +36,7 @@ export default class HeapNode implements IHeapNode {
36
36
  findReferrers(predicate: Predicator<IHeapEdge>): IHeapEdge[];
37
37
  get referrers(): HeapEdge[];
38
38
  forEachReferrer(callback: EdgeIterationCallback): void;
39
+ get hasPathEdge(): boolean;
39
40
  get pathEdge(): Nullable<HeapEdge>;
40
41
  set pathEdge(edge: Nullable<HeapEdge>);
41
42
  get nodeIndex(): number;
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  var __importDefault = (this && this.__importDefault) || function (mod) {
@@ -189,6 +189,10 @@ class HeapNode {
189
189
  }
190
190
  }
191
191
  }
192
+ get hasPathEdge() {
193
+ const heapSnapshot = this.heapSnapshot;
194
+ return heapSnapshot._nodeIdxHasPathEdge[this.idx] !== 0;
195
+ }
192
196
  get pathEdge() {
193
197
  const heapSnapshot = this.heapSnapshot;
194
198
  if (heapSnapshot._nodeIdxHasPathEdge[this.idx] === 0) {
@@ -4,14 +4,15 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  import type { IHeapNode, IHeapNodes, IHeapEdges, IHeapSnapshot, HeapNodeTypes, HeapEdgeTypes, HeapSnapshotMeta, RawHeapSnapshot, NumericDictionary, Nullable } from '../Types';
12
12
  import HeapNode from './HeapNode';
13
13
  export default class HeapSnapshot implements IHeapSnapshot {
14
14
  snapshot: RawHeapSnapshot;
15
+ isProcessed: boolean;
15
16
  nodes: IHeapNodes;
16
17
  _nodeCount: number;
17
18
  edges: IHeapEdges;
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  var __importDefault = (this && this.__importDefault) || function (mod) {
@@ -18,11 +18,13 @@ const Console_1 = __importDefault(require("../Console"));
18
18
  const HeapNode_1 = __importDefault(require("./HeapNode"));
19
19
  const HeapEdge_1 = __importDefault(require("./HeapEdge"));
20
20
  const HeapUtils_1 = require("./HeapUtils");
21
+ const MemLabTagStore_1 = __importDefault(require("./MemLabTagStore"));
21
22
  const EMPTY_UINT8_ARRAY = new Uint8Array(0);
22
23
  const EMPTY_UINT32_ARRAY = new Uint32Array(0);
23
24
  class HeapSnapshot {
24
25
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
25
26
  constructor(snapshot, _options = {}) {
27
+ this.isProcessed = false;
26
28
  this._nodeCount = -1;
27
29
  this._edgeCount = -1;
28
30
  this._nodeId2NodeIdx = {};
@@ -98,7 +100,7 @@ class HeapSnapshot {
98
100
  forEachTraceable(cb) {
99
101
  for (let i = 0; i < this.length; i++) {
100
102
  const node = this.get(i);
101
- if (!node.pathEdge) {
103
+ if (!node.hasPathEdge) {
102
104
  continue;
103
105
  }
104
106
  const ret = cb(node, i);
@@ -158,36 +160,7 @@ class HeapSnapshot {
158
160
  return detected;
159
161
  }
160
162
  hasObjectWithTag(tag) {
161
- // get tagStore
162
- let tagStore = null;
163
- this.nodes.forEach((node) => {
164
- if (node.name === 'MemLabTaggedStore' && node.type === 'object') {
165
- tagStore = node;
166
- return false;
167
- }
168
- });
169
- if (tagStore == null) {
170
- return false;
171
- }
172
- const store = tagStore;
173
- // get tagStore.taggedObjects
174
- const taggedObjects = store.getReferenceNode('taggedObjects', 'property');
175
- if (taggedObjects == null) {
176
- return false;
177
- }
178
- // get taggedObjects[tag]
179
- const weakSet = taggedObjects.getReferenceNode(tag, 'property');
180
- if (weakSet == null) {
181
- return false;
182
- }
183
- // get weakSet.table
184
- const table = weakSet.getReferenceNode('table');
185
- if (table == null) {
186
- return false;
187
- }
188
- // check if the table has any weak reference to any object
189
- const ref = table.findAnyReference((edge) => edge.type === 'weak' && edge.toNode.name !== 'system / Oddball');
190
- return ref != null;
163
+ return MemLabTagStore_1.default.hasObjectWithTag(this, tag);
191
164
  }
192
165
  getNodeById(id) {
193
166
  if (!(id in this._nodeId2NodeIdx)) {
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  import type { IHeapStringNode } from '../Types';
12
12
  import type HeapSnapshot from './HeapSnapshot';
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  var __importDefault = (this && this.__importDefault) || function (mod) {
@@ -35,6 +35,8 @@ class HeapStringNode extends HeapNode_1.default {
35
35
  if (parentNode == null) {
36
36
  throw (0, HeapUtils_1.throwError)(new Error('broken sliced string'));
37
37
  }
38
+ // sliced string in heap snapshot doesn't include
39
+ // the start index and the end index, so this may be inaccurate
38
40
  return parentNode.stringValue;
39
41
  }
40
42
  return this.name;
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  export declare const NodeDetachState: {
12
12
  Unknown: number;
@@ -4,9 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
- * @lightSyntaxTransform
9
7
  * @format
8
+ * @lightSyntaxTransform
9
+ * @oncall ws_labs
10
10
  */
11
11
  'use strict';
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall ws_labs
9
+ */
10
+ import type { AnyValue, IHeapSnapshot } from '../Types';
11
+ declare type AnyObject = Record<AnyValue, AnyValue>;
12
+ /** @internal */
13
+ export default class MemLabTaggedStore {
14
+ taggedObjects: Record<string, WeakSet<AnyObject>>;
15
+ private constructor();
16
+ private static instance;
17
+ readonly id: string;
18
+ static getInstance(): MemLabTaggedStore;
19
+ static tagObject<T extends object>(o: T, tag: string): void;
20
+ static hasObjectWithTag(heap: IHeapSnapshot, tag: string): boolean;
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=MemLabTagStore.d.ts.map
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @format
9
+ * @oncall ws_labs
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const __1 = require("../..");
13
+ let uindex = 1;
14
+ function getUniqueID() {
15
+ const randId = `${Math.random()}`;
16
+ return `${process.pid}-${Date.now()}-${randId}-${uindex++}`;
17
+ }
18
+ /** @internal */
19
+ class MemLabTaggedStore {
20
+ constructor() {
21
+ this.id = getUniqueID();
22
+ this.taggedObjects = Object.create(null);
23
+ }
24
+ // make sure it's a singleton
25
+ static getInstance() {
26
+ if (!MemLabTaggedStore.instance) {
27
+ MemLabTaggedStore.instance = new MemLabTaggedStore();
28
+ }
29
+ return MemLabTaggedStore.instance;
30
+ }
31
+ // tag an object with a mark
32
+ static tagObject(o, tag) {
33
+ const store = MemLabTaggedStore.getInstance();
34
+ if (!store.taggedObjects[tag]) {
35
+ store.taggedObjects[tag] = new WeakSet();
36
+ }
37
+ store.taggedObjects[tag].add(o);
38
+ }
39
+ // check if any object in the heap snapshot has the mark
40
+ // tagged by this MemLabTaggedStore in this execution context
41
+ static hasObjectWithTag(heap, tag) {
42
+ const curContextTagStoreID = MemLabTaggedStore.getInstance().id;
43
+ let tagStore = null;
44
+ // get all MemLabTaggedStore instances in the heap snapshot
45
+ const stores = [];
46
+ heap.nodes.forEach((node) => {
47
+ if (node.name === 'MemLabTaggedStore' && node.type === 'object') {
48
+ stores.push(node);
49
+ }
50
+ });
51
+ // if no tag store found
52
+ if (stores.length === 0) {
53
+ return false;
54
+ // if there is only one store found
55
+ }
56
+ else if (stores.length === 1) {
57
+ tagStore = stores[0];
58
+ // if there are multiple MemLabTagStore instances
59
+ // found in the heap snapshot
60
+ }
61
+ else if (stores.length > 1) {
62
+ stores.forEach((node) => {
63
+ // in case multiple instances of MemLabTaggedStore exists
64
+ // in the heap snapshot, we need to make sure that the
65
+ // tag store is the one matching the current execution context
66
+ let storeID = '';
67
+ // match tag store id
68
+ node.forEachReference(edge => {
69
+ var _a, _b;
70
+ if (edge.name_or_index === 'id' && edge.toNode.isString) {
71
+ storeID = (_b = (_a = edge.toNode.toStringNode()) === null || _a === void 0 ? void 0 : _a.stringValue) !== null && _b !== void 0 ? _b : '';
72
+ return { stop: true };
73
+ }
74
+ });
75
+ if (curContextTagStoreID === storeID) {
76
+ tagStore = node;
77
+ }
78
+ });
79
+ if (tagStore == null) {
80
+ throw __1.utils.haltOrThrow('Multiple MemLabTagStore instances found in heap snapshot ' +
81
+ 'when checking object tags, please make sure only one memlab ' +
82
+ 'instance is running at a time and double check that memlab is ' +
83
+ 'not running in Jest concurrent mode.');
84
+ }
85
+ }
86
+ if (tagStore == null) {
87
+ return false;
88
+ }
89
+ const store = tagStore;
90
+ // get tagStore.taggedObjects
91
+ const taggedObjects = store.getReferenceNode('taggedObjects', 'property');
92
+ if (taggedObjects == null) {
93
+ return false;
94
+ }
95
+ // get taggedObjects[tag]
96
+ const weakSet = taggedObjects.getReferenceNode(tag, 'property');
97
+ if (weakSet == null) {
98
+ return false;
99
+ }
100
+ // get weakSet.table
101
+ const table = weakSet.getReferenceNode('table');
102
+ if (table == null) {
103
+ return false;
104
+ }
105
+ // check if the table has any weak reference to any object
106
+ const ref = table.findAnyReference((edge) => edge.type === 'weak' && edge.toNode.name !== 'system / Oddball');
107
+ return ref != null;
108
+ }
109
+ }
110
+ exports.default = MemLabTaggedStore;
@@ -4,8 +4,8 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @emails oncall+ws_labs
8
7
  * @format
8
+ * @oncall ws_labs
9
9
  */
10
10
  import type { MemLabConfig } from '../Config';
11
11
  import type { HeapNodeIdSet, IHeapNode, IHeapSnapshot } from '../Types';