• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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
16const { XTools } = require('../engine/XTools');
17const { X2DFast } = require('../engine/graphics/X2DFast');
18
19const INTYPE = {
20  state: 0,
21  depend: 1,
22  value: 2,
23  framestate: 3,
24  root: 4,
25  other: 5,
26};
27
28class NodeTypeMask {
29  static NONE = 0;
30  static CONTROL = 1 << INTYPE.state;
31  static DEPEND = 1 << INTYPE.depend;
32  static VALUE = 1 << INTYPE.value;
33  static FRAMESTATE = 1 << INTYPE.framestate;
34  static ROOT = 1 << INTYPE.root;
35  static OTHER = 1 << INTYPE.other;
36}
37
38class IrToPicture {
39  static INVALID_DEEP = -99999;
40  static NODEH = 20;
41  static LINE_TYPE = ['state', 'depend', 'value', 'framestate', 'root'];
42  static nodeType(ir) {
43    if (XTools.CONFIG.OpTypeControl.indexOf(ir.op) >= 0) {
44      return 'control';
45    }
46    if (ir.in[INTYPE.state].length > 0 && XTools.CONFIG.OpNotControl.indexOf(ir.op) === -1) {
47      return 'control';
48    }
49    if (XTools.CONFIG.OpTypeDepend.indexOf(ir.op) >= 0 || ir.in[INTYPE.depend].length > 0) {
50      return 'depend';
51    }
52    if (XTools.CONFIG.OpTypeValue.indexOf(ir.op) >= 0 || ir.in[INTYPE.value].length > 0) {
53      return 'value';
54    }
55    return 'other';
56  }
57  static nodeTypeMask(ir) {
58    let mask = NodeTypeMask.NONE;
59    if (XTools.CONFIG.OpTypeControl.indexOf(ir.op) >= 0) {
60      mask |= NodeTypeMask.CONTROL;
61    }
62    if (ir.in[INTYPE.state].length > 0 && XTools.CONFIG.OpNotControl.indexOf(ir.op) === -1) {
63      mask |= NodeTypeMask.CONTROL;
64    }
65    if (XTools.CONFIG.OpTypeDepend.indexOf(ir.op) >= 0 || ir.in[INTYPE.depend].length > 0) {
66      mask |= NodeTypeMask.DEPEND;
67    }
68    if (XTools.CONFIG.OpTypeValue.indexOf(ir.op) >= 0 || ir.in[INTYPE.value].length > 0) {
69      mask |= NodeTypeMask.VALUE;
70    }
71    if (XTools.CONFIG.OpTypeFrameState.indexOf(ir.op) >= 0 || ir.in[INTYPE.framestate].length > 0) {
72      mask |= NodeTypeMask.FRAMESTATE;
73    }
74    if (XTools.CONFIG.OpTypeCircuitRoot.indexOf(ir.op) >= 0 || ir.in[INTYPE.root].length > 0) {
75      mask |= NodeTypeMask.ROOT;
76    }
77    if (mask === NodeTypeMask.NONE) {
78      mask = NodeTypeMask.OTHER;
79    }
80    return mask;
81  }
82  static isLoopBack(l, nodes) {
83    if (XTools.CONFIG.OpTypeLoopBegin.indexOf(nodes[l.toId].ir.op) >= 0 && l.fromId === nodes[l.toId].ir.in[0][1]) {
84      return true;
85    }
86    if (XTools.CONFIG.OpTypeDependSelector.indexOf(nodes[l.toId].ir.op) >= 0 && l.fromId === nodes[l.toId].ir.in[1][1]) {
87      return true;
88    }
89    if (XTools.CONFIG.OpTypeValueSelector.indexOf(nodes[l.toId].ir.op) >= 0 && l.fromId === nodes[l.toId].ir.in[2][1]) {
90      return true;
91    }
92    return false;
93  }
94  static toPicture(irList, type, isBlock) {
95    let nodes = {};
96    let entry = -1;
97    for (let ir of irList) {//用于生成图的所有节点
98      if (type === 0) {//仅控制流
99        if (this.nodeType(ir) !== 'control') {
100          continue;
101        }
102      }
103      let name = ir.id + ',' + ir.op;
104      if (XTools.CONFIG.OpTypeJsBytecode.indexOf(ir.op) >= 0) {
105        name = ir.id + ',' + ir.bytecode;
106      }
107      nodes[ir.id] = {
108        type: this.nodeType(ir),
109        mask: this.nodeTypeMask(ir),
110        hide: false,
111        inCount: 0,
112        in: [],
113        inh: {},
114        outCount: 0,
115        out: [],
116        outh: [],
117        pos: { x: -1, y: -1 },
118        deep: this.INVALID_DEEP,
119        name: name,
120        nameWidth: X2DFast.gi().getTextWidth(name, 14),
121        ir: ir,
122      };
123      if (entry === -1) {
124        entry = ir.id;
125      }
126    }
127
128    let lines = [];
129    let lid = 0;
130    this.generateLine(nodes, lines, lid);
131    this.resetPicture(nodes, isBlock);
132
133    return {
134      nodes: nodes,
135      lines: lines,
136    };
137  }
138  static generateLine(nodes, lines, lid) {
139    for (let i in nodes) { //生成连接线
140      let inId = parseInt(i);
141      for (let inP1 = 0; inP1 < nodes[inId].ir.in.length; inP1++) {
142        for (let inP2 = 0; inP2 < nodes[inId].ir.in[inP1].length; inP2++) {
143          let outId = nodes[inId].ir.in[inP1][inP2];
144          if (outId in nodes) {
145            let line = {
146              lid: lid++,
147              lineType: this.LINE_TYPE[inP1],
148              inNum: nodes[inId].inCount,
149              outNum: nodes[outId].outCount,
150              fromId: outId,
151              toId: inId,
152              inP1: inP1,
153              inP2: inP2,
154              outP: nodes[outId].ir.out.indexOf(inId),
155              used: false,
156            };
157            nodes[inId].inCount++;
158            nodes[inId].in.push(line);
159            nodes[outId].outCount++;
160            nodes[outId].out.push(line);
161            lines.push(line);
162          }
163        }
164      }
165    }
166  }
167
168  static deepTest(n, nodes, isBlock, stack, dist) {
169    try {
170      stack.push(n.ir.id);
171    }
172    catch (e) {
173      console.log(1);
174    }
175    if (stack.length > Object.keys(nodes).length * 2) {
176      return true;
177    }
178    if (stack.length > 1 && n.ir.id === dist) {
179      return true;
180    }
181    for (let i = 0; i < n.out.length; i++) {
182      let nout = nodes[n.out[i].toId];
183      if (n.deep !== this.INVALID_DEEP) {
184        if (nout.deep === this.INVALID_DEEP) {
185          nout.deep = n.deep + 1;
186          if (this.deepTest(nout, nodes, isBlock, stack, dist)) {
187            return true;
188          }
189        }
190        if (nout.deep <= n.deep) {
191          if (!this.isLoopBack(n.out[i], nodes) && !isBlock) {
192            nout.deep = n.deep + 1;
193            if (this.deepTest(nout, nodes, isBlock, stack, dist)) {
194              return true;
195            }
196          }
197        }
198      }
199    }
200    stack.pop();
201    return false;
202  }
203  static checkoutLoop(ls) {
204    console.log(JSON.stringify(ls));
205    let dicts = {};
206    for (let l of ls) {
207      if (!(l in dicts)) {
208        dicts[l] = 1;
209      }
210      else {
211        dicts[l]++;
212      }
213    }
214    console.log(JSON.stringify(dicts, null, 4));
215  }
216  static TEST_LOOP = true;
217  static resetPicture(nodes, isBlock) {
218    if (this.TEST_LOOP && Object.keys(nodes).length > 0) {
219      for (let k in nodes) {
220        if (k === 0) {
221          nodes[k].deep = 0;
222        }
223        else {
224          nodes[k].deep = this.INVALID_DEEP;
225        }
226      }
227      let testResult = [];
228      this.deepTest(nodes[0], nodes, isBlock, testResult, 0);
229      if (testResult.length > 0) {
230        this.checkoutLoop(testResult);
231      }
232    }
233
234    let entry = true;
235    let enums = [];
236    for (let k in nodes) {
237      let n = nodes[k];
238      if (n.hide) {
239        continue;
240      }
241      if (entry) {
242        n.pos.x = 0;
243        n.pos.y = 0;
244        n.deep = 0;
245        entry = false;
246        enums.push(k);
247      }
248      else {
249        n.deep = this.INVALID_DEEP;
250      }
251    }
252    let collectDebug = [];
253    while (enums.length > 0) { //12,18,27,28,31,34
254      let nextenums = [];
255      for (let e = 0; e < enums.length; e++) {
256        let k = enums[e];
257        let n = nodes[k];
258        if (n.hide) {
259          continue;
260        }
261        for (let i = 0; i < n.out.length; i++) {
262          let nout = nodes[n.out[i].toId];
263          if (n.deep !== this.INVALID_DEEP) {
264            if (nout.deep === this.INVALID_DEEP) {
265              nout.deep = n.deep + 1;
266              nextenums.push(nout.ir.id);
267            }
268            if (nout.deep <= n.deep) {
269              if (!this.isLoopBack(n.out[i], nodes) && !isBlock) {
270                nout.deep = n.deep + 1;
271                nextenums.push(nout.ir.id);
272              }
273            }
274          }
275        }
276        for (let i = 0; i < n.in.length; i++) {
277          let nin = nodes[n.in[i].fromId];
278          if (n.deep !== this.INVALID_DEEP) {
279            if (nin.deep === this.INVALID_DEEP) {
280              nin.deep = n.deep - 1;
281              nextenums.push(nin.ir.id);
282            }
283            if (nin.deep >= n.deep) {
284              if (!this.isLoopBack(n.in[i], nodes) && !isBlock) {
285                n.deep = nin.deep + 1;
286                nextenums.push(n.ir.id);
287              }
288            }
289          }
290        }
291      }
292      collectDebug.push(enums);
293
294      enums = nextenums;
295    }
296
297    let levels = {};
298    for (let k in nodes) { //节点分层
299      let n = nodes[k];
300      if (n.hide) {
301        continue;
302      }
303      if (!(n.deep in levels)) {
304        levels[n.deep] = [];
305      }
306      levels[n.deep].push(n);
307    }
308    let ty = 50;
309    for (let k in nodes) {
310      let n = nodes[k];
311      let ltypes = [];
312      for (let l of n.out) {
313        if (ltypes.indexOf(l.lineType) < 0) {
314          ltypes.push(l.lineType);
315        }
316      }
317      n.ltypes = ltypes;
318      if (n.hide) {
319        continue;
320      }
321      if (n.deep === this.INVALID_DEEP) {
322        n.pos.x = this.INVALID_DEEP; //Scr.logicw - 100;
323        n.pos.y = ty;
324        ty += 50;
325      }
326    }
327    let posy = 0;
328    let ks = Object.keys(levels).sort((a, b) => { return parseInt(a) - parseInt(b) });
329    for (let k of ks) {
330      k = parseInt(k);
331      if (k === this.INVALID_DEEP) {
332        continue;
333      }
334      let inCount = 0;
335      let outCount = 0;
336      let inP = 0;
337      for (let i = 0; i < levels[k].length; i++) {
338        let n = levels[k];
339        if (n.hide) {
340          continue;
341        }
342        for (let j = 0; j < n[i].in.length; j++) {
343          let l = n[i].in[j];
344          if (!n[i].inh[l.fromId + l.lineType]) {
345            n[i].inh[l.fromId + l.lineType] = (inP + 1) * 5;
346            inP += 1;
347          }
348        }
349        inCount += Object.keys(n[i].inh).length;
350
351        outCount += n[i].ltypes.length;
352      }
353      posy += (inCount + 1) * 5;
354
355      let outP = 0;
356      for (let i = 0; i < levels[k].length; i++) {
357        let n = levels[k];
358        if (n.hide) {
359          continue;
360        }
361        for (let j = 0; j < n[i].out.length; j++) {
362          n[i].outh[j] = (outP + 1 + n[i].ltypes.indexOf(n[i].out[j].lineType)) * 5;
363        }
364        n[i].pos.y = posy;
365        outP += n[i].ltypes.length;
366      }
367
368      posy += (outCount + 1) * 5 + this.NODEH;
369
370      let w = 0;
371      for (let i = 0; i < levels[k].length; i++) { //当前行总宽度
372        w += levels[k][i].nameWidth + 20;
373      }
374      let x = -w / 2;
375      for (let i = 0; i < levels[k].length; i++) { //每个节点x偏移
376        levels[k][i].pos.x = x + 10;
377        x += levels[k][i].nameWidth + 20;
378      }
379    }
380  }
381}
382
383module.exports = {
384  IrToPicture
385};