1/* 2 * Copyright (c) 2021-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 * as ts from "typescript"; 17import { CmdOptions } from "./cmdOptions"; 18import { 19 Callrange, 20 DebugInsStartPlaceHolder, 21 DebugInsEndPlaceHolder, 22 IRNode, 23 Label, 24 VReg, 25 WideCallrange 26} from "./irnodes"; 27import * as jshelpers from "./jshelpers"; 28import { PandaGen } from "./pandagen"; 29import { Scope } from "./scope"; 30import { 31 Variable 32} from "./variable"; 33 34export class DebugPosInfo { 35 private bl: number | undefined; // bound left 36 private br: number | undefined; // bound right 37 private l: number = -1; // line number 38 private c: number = -1; // column number 39 private nodeKind: NodeKind | undefined = NodeKind.FIRST_NODE_OF_FUNCTION; 40 41 constructor() { } 42 43 public setDebugPosInfoNodeState(extendedNode: ts.Node | NodeKind): void { 44 if (DebugInfo.isNode(extendedNode)) { 45 this.nodeKind = NodeKind.NORMAL; 46 } else { 47 this.nodeKind = <NodeKind>extendedNode; 48 } 49 } 50 51 public getDebugPosInfoNodeState(): NodeKind | undefined { 52 return this.nodeKind; 53 } 54 55 public setBoundLeft(boundLeft: number): void { 56 this.bl = boundLeft; 57 } 58 59 public getBoundLeft(): number | undefined { 60 return this.bl; 61 } 62 63 public setBoundRight(boundRight: number): void { 64 this.br = boundRight; 65 } 66 67 public getBoundRight(): number | undefined { 68 return this.br; 69 } 70 71 public setSourecLineNum(lineNum: number): void { 72 this.l = lineNum; 73 } 74 75 public getSourceLineNum(): number { 76 return this.l; 77 } 78 79 public setSourecColumnNum(columnNum: number): void { 80 this.c = columnNum; 81 } 82 83 public getSourceColumnNum(): number { 84 return this.c; 85 } 86 87 public clearNodeKind(): void { 88 this.nodeKind = undefined; 89 } 90} 91 92export class VariableDebugInfo { 93 // @ts-ignore 94 private n = ""; // name 95 // @ts-ignore 96 private v: Variable | undefined; // variables 97 // @ts-ignore 98 private s = ""; // signature 99 // @ts-ignore 100 private st = ""; // signature type 101 // @ts-ignore 102 private r: number = -1; 103 private start: number = -1; 104 // @ts-ignore 105 private len: number = -1; 106 107 constructor(name: string, signature: string, signatureType: string, 108 reg: number, start: number = 0, length: number = 0) { 109 this.n = name; 110 this.s = signature; 111 this.st = signatureType; 112 this.r = reg; 113 this.start = start; 114 this.len = length; 115 } 116 117 public setStart(start: number): void { 118 this.start = start; 119 } 120 121 public getStart(): number { 122 return this.start; 123 } 124 125 public setLength(length: number): void { 126 this.len = length; 127 } 128} 129 130export enum NodeKind { 131 NORMAL, 132 INVALID, 133 FIRST_NODE_OF_FUNCTION, 134} 135 136export class DebugInfo { 137 private static scopeArray: Scope[] = []; 138 private static lastNode: ts.Node; 139 constructor() { } 140 141 public static isNode(extendedNode: ts.Node | NodeKind): boolean { 142 if (extendedNode != NodeKind.INVALID && 143 extendedNode != NodeKind.FIRST_NODE_OF_FUNCTION && 144 extendedNode != NodeKind.NORMAL) { 145 return true; 146 } 147 148 return false; 149 } 150 151 public static updateLastNode(lastNode: ts.Node | NodeKind): void { 152 if (DebugInfo.isNode(lastNode)) { 153 DebugInfo.lastNode = <ts.Node>lastNode; 154 } 155 } 156 157 public static getLastNode() { 158 return DebugInfo.lastNode; 159 } 160 161 public static searchForPos(node: ts.Node) { 162 let file = jshelpers.getSourceFileOfNode(node); 163 if (!file) { 164 return undefined; 165 } 166 167 let pos : number = 0; 168 if (node.pos === -1 || node.end === -1) { 169 return { 170 loc: { 171 line : -1, 172 character : -1 173 } 174 } 175 } 176 177 pos = node.getStart(); 178 let loc = file.getLineAndCharacterOfPosition(pos); 179 return { 180 loc: loc 181 } 182 } 183 184 public static setPosInfoForUninitializeIns(posInfo: DebugPosInfo, pandaGen: PandaGen): void { 185 let firstStmt = pandaGen.getFirstStmt(); 186 if (firstStmt) { 187 let res = this.searchForPos(firstStmt); 188 if (!res) { 189 return; 190 } 191 posInfo.setSourecLineNum(res.loc.line); 192 posInfo.setSourecColumnNum(res.loc.character); 193 } 194 } 195 196 public static setInvalidPosInfoForUninitializeIns(posInfo: DebugPosInfo, pandaGen: PandaGen): void { 197 posInfo.setSourecLineNum(-1); 198 posInfo.setSourecColumnNum(-1); 199 } 200 201 public static addScope(scope: Scope) { 202 DebugInfo.scopeArray.push(scope); 203 } 204 205 public static getScopeArray() { 206 return DebugInfo.scopeArray; 207 } 208 209 public static clearScopeArray() { 210 DebugInfo.scopeArray = []; 211 } 212 213 public static setDebuginfoForIns(node: ts.Node | NodeKind, ...insns: IRNode[]): void { 214 DebugInfo.updateLastNode(node); 215 216 let lineNumber = -1; 217 let columnNumber = -1; 218 if (DebugInfo.isNode(node)) { 219 let tsNode = <ts.Node>(node); 220 let res = this.searchForPos(tsNode); 221 if (!res) { 222 return; 223 } 224 lineNumber = res.loc.line; 225 columnNumber = res.loc.character; 226 } 227 228 insns.forEach(insn => { 229 insn.debugPosInfo.setSourecLineNum(lineNumber); 230 insn.debugPosInfo.setSourecColumnNum(columnNumber); 231 insn.debugPosInfo.setDebugPosInfoNodeState(node); 232 }) 233 } 234 235 private static matchFormat(irnode: IRNode): number { 236 let formatIndex = 0; 237 let formats = irnode.getFormats(); 238 for (let i = 0; i < formats[0].length; i++) { 239 if (irnode.operands[i] instanceof VReg) { 240 for (let j = 0; j < formats.length; j++) { 241 // formats[j][i][1] is vreg’s bitwidth 242 if ((<VReg>irnode.operands[i]).num < (1 << formats[j][i][1])) { 243 formatIndex = j > formatIndex ? j : formatIndex; 244 continue; 245 } 246 } 247 } 248 } 249 return formatIndex; 250 } 251 252 private static getIRNodeWholeLength(irnode: IRNode): number { 253 if (irnode instanceof Label || 254 irnode instanceof DebugInsStartPlaceHolder || 255 irnode instanceof DebugInsEndPlaceHolder) { 256 return 0; 257 } 258 let length = 1; 259 if (!irnode.getFormats()[0]) { 260 return 0; 261 } 262 let formatIndex = this.matchFormat(irnode); 263 let formats = irnode.getFormats()[formatIndex]; 264 // count operands length 265 for (let i = 0; i < formats.length; i++) { 266 if ((irnode instanceof WideCallrange) || (irnode instanceof Callrange)) { 267 length += formats[0][1] / 8; // 8 indicates that one byte is composed of 8 bits 268 length += formats[1][1] / 8; 269 break; 270 } 271 272 length += (formats[i][1] / 8); 273 } 274 275 return length; 276 } 277 278 private static setPosDebugInfo(pandaGen: PandaGen): void { 279 let insns: IRNode[] = pandaGen.getInsns(); 280 let offset = 0; 281 282 // count pos offset 283 for (let i = 0; i < insns.length; i++) { 284 if (insns[i].debugPosInfo.getDebugPosInfoNodeState() === NodeKind.FIRST_NODE_OF_FUNCTION) { 285 DebugInfo.setInvalidPosInfoForUninitializeIns(insns[i].debugPosInfo, pandaGen); 286 } 287 288 let insLength = DebugInfo.getIRNodeWholeLength(insns[i]); 289 let insnsDebugPosInfo = insns[i].debugPosInfo; 290 291 if (insnsDebugPosInfo && CmdOptions.isDebugMode()) { 292 insnsDebugPosInfo.setBoundLeft(offset); 293 insnsDebugPosInfo.setBoundRight(offset + insLength); 294 } 295 296 offset += insLength; 297 298 if (i > 0 && insns[i - 1] instanceof Label) { 299 insns[i - 1].debugPosInfo = insns[i].debugPosInfo; 300 } 301 } 302 } 303 304 private static setVariablesDebugInfo(pandaGen: PandaGen): void { 305 let insns = pandaGen.getInsns(); 306 307 for (let i = 0; i < insns.length; i++) { 308 if (insns[i] instanceof DebugInsStartPlaceHolder) { 309 (<DebugInsStartPlaceHolder> insns[i]).getScope().setScopeStartInsIdx(i); 310 // delete ins placeholder 311 insns.splice(i, 1); 312 if (i > 0) { 313 i--; 314 } 315 } 316 if (insns[i] instanceof DebugInsEndPlaceHolder) { 317 (<DebugInsEndPlaceHolder> insns[i]).getScope().setScopeEndInsIdx(i > 0 ? i - 1 : 0); 318 // delete ins placeholder 319 insns.splice(i, 1); 320 if (i > 0) { 321 i--; 322 } 323 } 324 } 325 326 let recordArray = DebugInfo.getScopeArray(); 327 recordArray.forEach(scope => { 328 let name2variable = scope.getName2variable(); 329 name2variable.forEach((value, key) => { 330 if (!value.hasAlreadyBinded()) { 331 return; 332 } 333 if (value.getName() === "0this" || value.getName() === "0newTarget") { 334 return; 335 } 336 let variableInfo = new VariableDebugInfo(key, "any", "any", (value.getVreg().num)); 337 variableInfo.setStart(scope.getScopeStartInsIdx()); 338 variableInfo.setLength(scope.getScopeEndInsIdx() - scope.getScopeStartInsIdx() + 1); 339 pandaGen.addDebugVariableInfo(variableInfo); 340 }); 341 }); 342 } 343 344 public static setDebugInfo(pandaGen: PandaGen): void { 345 // set position debug info 346 DebugInfo.setPosDebugInfo(pandaGen); 347 if (CmdOptions.isDebugMode()) { 348 // set variable debug info 349 DebugInfo.setVariablesDebugInfo(pandaGen); 350 351 // clear scope array 352 DebugInfo.clearScopeArray(); 353 return; 354 } 355 } 356 357 public static setSourceFileDebugInfo(pandaGen: PandaGen, node: ts.SourceFile | ts.FunctionLikeDeclaration): void { 358 let sourceFile = jshelpers.getSourceFileOfNode(node); 359 if (CmdOptions.getSourceFile().length > 0) { 360 pandaGen.setSourceFileDebugInfo(CmdOptions.getSourceFile()); 361 } else { 362 pandaGen.setSourceFileDebugInfo(sourceFile.fileName); 363 } 364 365 if (CmdOptions.isDebugMode() && ts.isSourceFile(node)) { 366 pandaGen.setSourceCode(node.text); 367 } 368 } 369 370 public static copyDebugInfo(insn: IRNode, expansion: IRNode[]): void { 371 expansion.forEach(irNode => irNode.debugPosInfo = insn.debugPosInfo); 372 } 373 374 public static addDebugIns(scope: Scope, pandaGen: PandaGen, isStart: boolean): void { 375 if (!CmdOptions.isDebugMode()) { 376 return; 377 } 378 379 let insns = pandaGen.getInsns(); 380 let placeHolder: IRNode; 381 if (isStart) { 382 placeHolder = new DebugInsStartPlaceHolder(scope); 383 DebugInfo.addScope(scope); 384 } else { 385 placeHolder = new DebugInsEndPlaceHolder(scope); 386 } 387 insns.push(placeHolder); 388 } 389} 390