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}