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