• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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