• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { HeapLoader } from '../logic/HeapLoader.js';
17import { AllocationFunction, FileInfo } from './UiStruct.js';
18
19export enum EdgeType {
20  CONTEXT = 0,
21  ELEMENT = 1,
22  PROPERTY = 2,
23  INTERNAL = 3,
24  HIDDEN = 4,
25  SHORTCUT = 5,
26  WEAK = 6,
27  STRING_OR_NUMBER = 6,
28  NODE = 7,
29  INVISIBLE = 8,
30}
31export enum NodeType {
32  HIDDEN = 0,
33  ARRAY = 1,
34  STRING = 2,
35  OBJECT = 3,
36  CODE = 4,
37  CLOSURE = 5,
38  REGEXP = 6,
39  NUMBER = 7,
40  NATIVE = 8,
41  SYNTHETIC = 9,
42  CONCATENATED_STRING = 10,
43  SLICED_STRING = 11,
44  SYMBOL = 12,
45  BIGINT = 13,
46  OBJECT_SHAPE = 14,
47}
48
49function getNodeTypeName(nodeType: NodeType): keyof typeof NodeType {
50  return Object.keys(NodeType).find(
51    (key) => NodeType[key as keyof typeof NodeType] === nodeType
52  ) as keyof typeof NodeType;
53}
54
55function getEdgeTypeName(nodeType: EdgeType): keyof typeof EdgeType {
56  return Object.keys(EdgeType).find(
57    (key) => EdgeType[key as keyof typeof EdgeType] === nodeType
58  ) as keyof typeof EdgeType;
59}
60
61export enum DetachedNessState {
62  UNKNOWN,
63  ATTACHED,
64  DETACHED,
65}
66
67export class HeapNode {
68  fileId: number;
69  nodeIndex: number;
70  nodeOldIndex: number;
71  type: NodeType;
72  name: string;
73  nameIdx!: number;
74  id: number;
75  selfSize: number;
76  edgeCount: number;
77  traceNodeId: number;
78  detachedness: number;
79  edges: Set<HeapEdge>;
80  distance: number = -5;
81  retainedSize: number;
82  displayName: string = '';
83  firstEdgeIndex: number;
84  flag: number;
85  retainsCount: number = 0;
86  retainsEdgeIdx: Array<number>;
87  retainsNodeIdx: Array<number>;
88
89  constructor(
90    fileId: number,
91    nodeIndex: number,
92    type: number,
93    name: string,
94    id: number,
95    selfSize: number,
96    edgeCount: number,
97    traceNodeId: number,
98    detachedness: number,
99    firstEdgeIndex: number
100  ) {
101    this.fileId = fileId;
102    this.nodeIndex = nodeIndex;
103    this.nodeOldIndex = nodeIndex * 7;
104    this.type = type;
105    this.name = name;
106    this.id = id;
107    this.selfSize = selfSize;
108    this.retainedSize = selfSize;
109    this.edgeCount = edgeCount;
110    this.traceNodeId = traceNodeId;
111    this.detachedness = detachedness;
112    this.firstEdgeIndex = firstEdgeIndex;
113    this.edges = new Set<HeapEdge>();
114    this.retainsEdgeIdx = new Array<number>();
115    this.retainsNodeIdx = new Array<number>();
116    this.flag = 0;
117  }
118
119  className(): string {
120    switch (this.type) {
121      case NodeType.HIDDEN:
122        return '(system)';
123      case NodeType.OBJECT:
124      case NodeType.NATIVE:
125        return this.nodeName();
126      case NodeType.CODE:
127        return '(compiled code)';
128      default:
129        let typeName = '(' + getNodeTypeName(this.type) + ')';
130        return typeName.toLowerCase();
131    }
132  }
133
134  nodeName(): string {
135    return this.displayName || this.name;
136  }
137
138  addEdge(edge: HeapEdge) {
139    this.edges.add(edge);
140  }
141
142  idHidden(): boolean {
143    return this.type == NodeType.HIDDEN;
144  }
145
146  isArray(): boolean {
147    return this.type === NodeType.ARRAY;
148  }
149
150  isUserRoot(): boolean {
151    return this.type != NodeType.SYNTHETIC;
152  }
153
154  isDocumentDOMTreesRoot(): boolean {
155    return this.type != NodeType.SYNTHETIC && this.name === '(Document DOM trees)';
156  }
157}
158
159export class HeapEdge {
160  edgeOldIndex: number;
161  edgeIndex: number;
162  type: EdgeType;
163  nameOrIndex: string;
164  nodeId: number;
165  fromNodeId: number;
166  toNodeId: number;
167  retainsNode: Array<HeapNode>;
168  retainEdge: Array<HeapEdge>;
169
170  constructor(
171    edgeIndex: number,
172    type: number,
173    nameOrIndex: string,
174    nodeId: number,
175    fromNodeId: number,
176    toNodeId: number
177  ) {
178    this.edgeIndex = edgeIndex;
179    this.edgeOldIndex = edgeIndex * 3;
180    this.type = type;
181    this.nameOrIndex = nameOrIndex;
182    this.nodeId = nodeId;
183    this.fromNodeId = fromNodeId;
184    this.toNodeId = toNodeId;
185    this.retainsNode = new Array<HeapNode>();
186    this.retainEdge = new Array<HeapEdge>();
187  }
188}
189
190export class HeapTraceFunctionInfo {
191  id: number;
192  index: number;
193  name: string;
194  scriptName: string;
195  scriptId: number;
196  line: number;
197  column: number;
198
199  constructor(
200    id: number,
201    index: number,
202    name: string,
203    scriptName: string,
204    scriptId: number,
205    line: number,
206    column: number
207  ) {
208    this.id = id;
209    this.index = index;
210    this.name = name;
211    this.scriptName = scriptName;
212    this.scriptId = scriptId;
213    this.line = line;
214    this.column = column;
215  }
216}
217
218export class HeapSample {
219  timestamp: number;
220  lastAssignedId: number;
221  size: number = 0;
222
223  constructor(timestamp: number, lastAssignedId: number) {
224    this.timestamp = timestamp;
225    this.lastAssignedId = lastAssignedId;
226  }
227}
228export class HeapLocation {
229  objectIndex: number;
230  scriptId: number;
231  line: number;
232  column: number;
233
234  constructor(objectIndex: number, scriptId: number, line: number, column: number) {
235    this.objectIndex = objectIndex;
236    this.scriptId = scriptId;
237    this.line = line;
238    this.column = column;
239  }
240}
241
242export class HeapSnapshotStruct {
243  nodeCount!: number;
244  edgeCount!: number;
245  functionCount!: number;
246
247  nodeMap: Map<number, HeapNode>;
248  edges: Array<HeapEdge>;
249  functionInfos: Array<HeapTraceFunctionInfo>;
250  traceNodes: Array<AllocationFunction>;
251  samples: Array<HeapSample>;
252  strings: Array<string>;
253
254  rootNodeId: number = -1;
255
256  constructor() {
257    this.nodeMap = new Map<number, HeapNode>();
258    this.edges = new Array<HeapEdge>();
259    this.functionInfos = new Array<HeapTraceFunctionInfo>();
260    this.traceNodes = new Array<AllocationFunction>();
261    this.samples = new Array<HeapSample>();
262    this.strings = new Array<string>();
263  }
264
265  public clear() {
266    this.nodeMap.clear();
267    this.edges.length = 0;
268    this.functionInfos.length = 0;
269    this.traceNodes.length = 0;
270    this.samples.length = 0;
271    this.strings.length = 0;
272  }
273}
274
275export class FileStruct extends FileInfo {
276  snapshotStruct: HeapSnapshotStruct;
277  isParseSuccess: boolean;
278  heapLoader!: HeapLoader;
279
280  constructor() {
281    super();
282    this.isParseSuccess = true;
283    this.snapshotStruct = new HeapSnapshotStruct();
284  }
285}
286