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'; 17import { AllocationFunction, FileInfo } from './UiStruct'; 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 = []; 115 this.retainsNodeIdx = []; 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 return `(${getNodeTypeName(this.type)})`.toLowerCase(); 130 } 131 } 132 133 nodeName(): string { 134 return this.displayName || this.name; 135 } 136 137 addEdge(edge: HeapEdge): void { 138 this.edges.add(edge); 139 } 140 141 idHidden(): boolean { 142 return this.type === NodeType.HIDDEN; 143 } 144 145 isArray(): boolean { 146 return this.type === NodeType.ARRAY; 147 } 148 149 isUserRoot(): boolean { 150 return this.type !== NodeType.SYNTHETIC; 151 } 152 153 isDocumentDOMTreesRoot(): boolean { 154 return this.type !== NodeType.SYNTHETIC && this.name === '(Document DOM trees)'; 155 } 156} 157 158export class HeapEdge { 159 edgeOldIndex: number; 160 edgeIndex: number; 161 type: EdgeType; 162 nameOrIndex: string; 163 nodeId: number; 164 fromNodeId: number; 165 toNodeId: number; 166 retainsNode: Array<HeapNode>; 167 retainEdge: Array<HeapEdge>; 168 169 constructor( 170 edgeIndex: number, 171 type: number, 172 nameOrIndex: string, 173 nodeId: number, 174 fromNodeId: number, 175 toNodeId: number 176 ) { 177 this.edgeIndex = edgeIndex; 178 this.edgeOldIndex = edgeIndex * 3; 179 this.type = type; 180 this.nameOrIndex = nameOrIndex; 181 this.nodeId = nodeId; 182 this.fromNodeId = fromNodeId; 183 this.toNodeId = toNodeId; 184 this.retainsNode = []; 185 this.retainEdge = []; 186 } 187} 188 189export class HeapTraceFunctionInfo { 190 id: number; 191 index: number; 192 name: string; 193 scriptName: string; 194 scriptId: number; 195 line: number; 196 column: number; 197 198 constructor( 199 id: number, 200 index: number, 201 name: string, 202 scriptName: string, 203 scriptId: number, 204 line: number, 205 column: number 206 ) { 207 this.id = id; 208 this.index = index; 209 this.name = name; 210 this.scriptName = scriptName; 211 this.scriptId = scriptId; 212 this.line = line; 213 this.column = column; 214 } 215} 216 217export class HeapSample { 218 timestamp: number; 219 lastAssignedId: number; 220 size: number = 0; 221 222 constructor(timestamp: number, lastAssignedId: number) { 223 this.timestamp = timestamp; 224 this.lastAssignedId = lastAssignedId; 225 } 226} 227export class HeapLocation { 228 objectIndex: number; 229 scriptId: number; 230 line: number; 231 column: number; 232 233 constructor(objectIndex: number, scriptId: number, line: number, column: number) { 234 this.objectIndex = objectIndex; 235 this.scriptId = scriptId; 236 this.line = line; 237 this.column = column; 238 } 239} 240 241export class HeapSnapshotStruct { 242 nodeCount!: number; 243 edgeCount!: number; 244 functionCount!: number; 245 nodeMap: Map<number, HeapNode>; 246 edges: Array<HeapEdge>; 247 functionInfos: Array<HeapTraceFunctionInfo>; 248 traceNodes: Array<AllocationFunction>; 249 samples: Array<HeapSample>; 250 strings: Array<string>; 251 rootNodeId: number = -1; 252 253 constructor() { 254 this.nodeMap = new Map<number, HeapNode>(); 255 this.edges = []; 256 this.functionInfos = []; 257 this.traceNodes = []; 258 this.samples = []; 259 this.strings = []; 260 } 261 262 public clear(): void { 263 this.nodeMap.clear(); 264 this.edges.length = 0; 265 this.functionInfos.length = 0; 266 this.traceNodes.length = 0; 267 this.samples.length = 0; 268 this.strings.length = 0; 269 } 270} 271 272export class FileStruct extends FileInfo { 273 snapshotStruct: HeapSnapshotStruct; 274 isParseSuccess: boolean; 275 heapLoader!: HeapLoader; 276 277 constructor() { 278 super(); 279 this.isParseSuccess = true; 280 this.snapshotStruct = new HeapSnapshotStruct(); 281 } 282} 283