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