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