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};