diff --git a/ets2panda/linter/arkanalyzer/src/core/graph/Cfg.ts b/ets2panda/linter/arkanalyzer/src/core/graph/Cfg.ts index 54284012979954f1ee7fdf446e5cf3c2ea2753bb..7b1c4a6e5adc3d0341893d1ec8355cb0642f8333 100644 --- a/ets2panda/linter/arkanalyzer/src/core/graph/Cfg.ts +++ b/ets2panda/linter/arkanalyzer/src/core/graph/Cfg.ts @@ -121,6 +121,18 @@ export class Cfg { } } + public setBlocks(blocks: Set, resetStmtToBlock: boolean = true): void { + this.blocks = blocks; + if (resetStmtToBlock) { + this.stmtToBlock.clear(); + for (const block of this.blocks) { + for (const stmt of block.getStmts()) { + this.stmtToBlock.set(stmt, block); + } + } + } + } + public getBlocks(): Set { return this.blocks; } diff --git a/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts b/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts index 478d0a7121bc5a7753f791936c3e07bbef8e7df2..ca81f85119bbb7c16b4dcac1b22e249c768a3a30 100644 --- a/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts +++ b/ets2panda/linter/arkanalyzer/src/core/graph/builder/CfgBuilder.ts @@ -1114,7 +1114,6 @@ export class CfgBuilder { arkIRTransformer ); - const currBlockId = this.blocks.length; this.linkBasicBlocks(blockBuilderToCfgBlock); this.adjustBlocks( blockBuilderToCfgBlock, @@ -1128,7 +1127,7 @@ export class CfgBuilder { const trapBuilder = new TrapBuilder(); const traps = trapBuilder.buildTraps(blockBuilderToCfgBlock, blockBuildersBeforeTry, arkIRTransformer, basicBlockSet); - const cfg = this.createCfg(blockBuilderToCfgBlock, basicBlockSet, currBlockId); + const cfg = this.createCfg(blockBuilderToCfgBlock, basicBlockSet); return { cfg, locals: arkIRTransformer.getLocals(), @@ -1239,20 +1238,11 @@ export class CfgBuilder { conditionalBuilder.rebuildBlocksContainConditionalOperator(basicBlockSet, ModelUtils.isArkUIBuilderMethod(this.declaringMethod)); } - private createCfg(blockBuilderToCfgBlock: Map, basicBlockSet: Set, prevBlockId: number): Cfg { - let currBlockId = prevBlockId; - for (const blockBuilder of this.blocks) { - if (blockBuilder.id === -1) { - blockBuilder.id = currBlockId++; - const block = blockBuilderToCfgBlock.get(blockBuilder) as BasicBlock; - block.setId(blockBuilder.id); - } - } - + private createCfg(blockBuilderToCfgBlock: Map, basicBlockSet: Set): Cfg { const cfg = new Cfg(); const startingBasicBlock = blockBuilderToCfgBlock.get(this.blocks[0])!; cfg.setStartingStmt(startingBasicBlock.getStmts()[0]); - currBlockId = 0; + let currBlockId = 0; for (const basicBlock of basicBlockSet) { basicBlock.setId(currBlockId++); cfg.addBlock(basicBlock); @@ -1260,9 +1250,45 @@ export class CfgBuilder { for (const stmt of cfg.getStmts()) { stmt.setCfg(cfg); } + this.topologicalSortBlock(cfg); return cfg; } + private topologicalSortBlock(cfg: Cfg): void { + function dfs(block: BasicBlock): void { + if (visited[block.getId()]) { + return; + } + + visited[block.getId()] = true; + result.add(block); + + for (const succ of block.getSuccessors() || []) { + dfs(succ); + } + } + + const startingBlock = cfg.getStartingBlock(); + if (!startingBlock) { + return; + } + const blocks = cfg.getBlocks(); + const visited: boolean[] = new Array(blocks.size).fill(false); + const result: Set = new Set(); + + dfs(startingBlock); + + // handle rest blocks haven't visted, which should be with no predecessorBlocks or the rest block in a block circle + for (const block of blocks) { + if (!visited[block.getId()]) { + dfs(block); + } + } + if (result.size === blocks.size) { + cfg.setBlocks(result, false); + } + } + private linkBasicBlocks(blockBuilderToCfgBlock: Map): void { for (const [blockBuilder, cfgBlock] of blockBuilderToCfgBlock) { for (const successorBlockBuilder of blockBuilder.nexts) {