From 1278cde7c697658df975bca7412c3d85dc02534e Mon Sep 17 00:00:00 2001 From: hufeng Date: Tue, 26 Apr 2022 23:13:52 +0800 Subject: [PATCH] fixed c9a9927 from https://gitee.com/hufeng20/ark_ts2abc/pulls/215 Fix wrong lex env when control flow changed Signed-off-by: hufeng Change-Id: I19a93fe4f60479f8a89add044ca567be3f985731 --- ts2panda/src/compiler.ts | 47 +++++++++++++++++++- ts2panda/src/statement/forOfStatement.ts | 2 +- ts2panda/src/statement/labelTarget.ts | 37 +++++++++++++++- ts2panda/src/statement/loopStatement.ts | 52 +++++++++-------------- ts2panda/src/statement/switchStatement.ts | 2 +- ts2panda/src/statement/tryStatement.ts | 32 ++++++-------- 6 files changed, 117 insertions(+), 55 deletions(-) diff --git a/ts2panda/src/compiler.ts b/ts2panda/src/compiler.ts index 132ee56efe..e5c7df34dd 100644 --- a/ts2panda/src/compiler.ts +++ b/ts2panda/src/compiler.ts @@ -595,6 +595,36 @@ export class Compiler { this.popScope(); } + private popLoopEnv(node: ts.Node, times: number) { + while(times--) { + this.pandaGen.popLexicalEnv(node); + } + } + + private popLoopEnvWhenContinueOrBreak(labelTarget: LabelTarget, isContinue: boolean) { + let node: ts.Node = labelTarget.getCorrespondingNode(); + let loopEnvLevel = labelTarget.getLoopEnvLevel(); + switch (node.kind) { + case ts.SyntaxKind.DoStatement: + case ts.SyntaxKind.ForStatement: { + this.popLoopEnv(node, loopEnvLevel - 1); + break; + } + case ts.SyntaxKind.WhileStatement: + case ts.SyntaxKind.ForInStatement: + case ts.SyntaxKind.ForOfStatement: { + let popTimes = isContinue ? loopEnvLevel : loopEnvLevel - 1; + this.popLoopEnv(node, popTimes); + break; + } + // SwitchStatement & BlockStatement could also have break labelTarget which changes + // the control flow out of their inner env loop. We should pop Loop env with such cases either. + default: { + this.popLoopEnv(node, loopEnvLevel); + } + } + } + private compileContinueStatement(stmt: ts.ContinueStatement) { let continueLabelTarget = LabelTarget.getLabelTarget(stmt); @@ -604,6 +634,11 @@ export class Compiler { continueLabelTarget.getContinueTargetLabel()! ); + // before jmp out of loops, pop the loops env + if (continueLabelTarget.getLoopEnvLevel()) { + this.popLoopEnvWhenContinueOrBreak(continueLabelTarget, true); + } + this.pandaGen.branch(stmt, continueLabelTarget.getContinueTargetLabel()!); } @@ -616,6 +651,11 @@ export class Compiler { undefined ); + // before jmp out of loops, pop the loops env + if (breakLabelTarget.getLoopEnvLevel()) { + this.popLoopEnvWhenContinueOrBreak(breakLabelTarget, false); + } + this.pandaGen.branch(stmt, breakLabelTarget.getBreakTargetLabel()); } @@ -628,7 +668,7 @@ export class Compiler { if (stmt.statement.kind == ts.SyntaxKind.Block || stmt.statement.kind == ts.SyntaxKind.IfStatement) { blockEndLabel = new Label(); - let labelTarget = new LabelTarget(blockEndLabel, undefined); + let labelTarget = new LabelTarget(stmt, blockEndLabel, undefined); LabelTarget.updateName2LabelTarget(stmt, labelTarget); } @@ -651,6 +691,11 @@ export class Compiler { } else { throw new DiagnosticError(stmt, DiagnosticCode.Line_break_not_permitted_here); } + + // before CFG, pop the loops env + let popTimes = TryStatement.getCurrentTryStatement() ? TryStatement.getCurrentTryStatement().getLoopEnvLevel() : 0; + this.popLoopEnv(stmt, popTimes); + pandaGen.throw(stmt); } diff --git a/ts2panda/src/statement/forOfStatement.ts b/ts2panda/src/statement/forOfStatement.ts index a6bbe5feb7..ca3fb6a40c 100644 --- a/ts2panda/src/statement/forOfStatement.ts +++ b/ts2panda/src/statement/forOfStatement.ts @@ -76,7 +76,7 @@ export function compileForOfStatement(stmt: ts.ForOfStatement, compiler: Compile pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.False)); pandaGen.storeAccumulator(stmt, doneReg); - let labelTarget = new LabelTarget(endLabel, nextLabel); + let labelTarget = new LabelTarget(stmt, endLabel, nextLabel, needCreateLoopEnv); LabelTarget.pushLabelTarget(labelTarget); LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); diff --git a/ts2panda/src/statement/labelTarget.ts b/ts2panda/src/statement/labelTarget.ts index 0ee16c2c1c..889cb8c947 100644 --- a/ts2panda/src/statement/labelTarget.ts +++ b/ts2panda/src/statement/labelTarget.ts @@ -22,13 +22,19 @@ import { Label } from "../irnodes"; export class LabelTarget { private static name2LabelTarget: Map = new Map(); private static labelTargetStack: LabelTarget[] = []; + private node: ts.Node; private breakTargetLabel: Label; private continueTargetLabel: Label | undefined; + private hasLoopEnv: boolean; + private loopEnvLevel: number; private tryStatement: TryStatement | undefined; - constructor(breakTargetLabel: Label, continueTargetLabel: Label | undefined) { + constructor(node: ts.Node, breakTargetLabel: Label, continueTargetLabel: Label | undefined, hasLoopEnv: boolean = false) { + this.node = node; this.breakTargetLabel = breakTargetLabel; this.continueTargetLabel = continueTargetLabel; + this.hasLoopEnv = hasLoopEnv; + this.loopEnvLevel = hasLoopEnv ? 1 : 0; this.tryStatement = TryStatement.getCurrentTryStatement(); } @@ -40,10 +46,26 @@ export class LabelTarget { return this.continueTargetLabel; } + getLoopEnvLevel() { + return this.loopEnvLevel; + } + getTryStatement() { return this.tryStatement; } + getCorrespondingNode() { + return this.node; + } + + private increaseLoopEnvLevel() { + this.loopEnvLevel += 1; + } + + private decreaseLoopEnvLevel() { + this.loopEnvLevel -= 1; + } + private static isLabelTargetsEmpty(): boolean { if (LabelTarget.labelTargetStack.length == 0) { return true; @@ -68,11 +90,22 @@ export class LabelTarget { } static pushLabelTarget(labelTarget: LabelTarget) { + if (labelTarget.hasLoopEnv) { + if (TryStatement.getCurrentTryStatement()) { + TryStatement.getCurrentTryStatement().increaseLoopEnvLevel(); + } + LabelTarget.labelTargetStack.forEach(lt => lt.increaseLoopEnvLevel()); + } LabelTarget.labelTargetStack.push(labelTarget); } static popLabelTarget() { - LabelTarget.labelTargetStack.pop(); + if (!LabelTarget.isLabelTargetsEmpty() && LabelTarget.labelTargetStack.pop().hasLoopEnv) { + if (TryStatement.getCurrentTryStatement()) { + TryStatement.getCurrentTryStatement().decreaseLoopEnvLevel(); + } + LabelTarget.labelTargetStack.forEach(lt => lt.decreaseLoopEnvLevel()); + } } static updateName2LabelTarget(node: ts.Node, labelTarget: LabelTarget) { diff --git a/ts2panda/src/statement/loopStatement.ts b/ts2panda/src/statement/loopStatement.ts index e8cafffd82..f7e1bd0d8f 100644 --- a/ts2panda/src/statement/loopStatement.ts +++ b/ts2panda/src/statement/loopStatement.ts @@ -35,16 +35,17 @@ import { LabelTarget } from "./labelTarget"; export function compileDoStatement(stmt: ts.DoStatement, compiler: Compiler) { compiler.pushScope(stmt); let pandaGen = compiler.getPandaGen(); + + let loopScope = compiler.getRecorder().getScopeOfNode(stmt); + let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; + let loopStartLabel = new Label(); let loopEndLabel = new Label(); let conditionLabel = new Label(); - - let labelTarget = new LabelTarget(loopEndLabel, conditionLabel); + let labelTarget = new LabelTarget(stmt, loopEndLabel, conditionLabel, needCreateLoopEnv); LabelTarget.pushLabelTarget(labelTarget); LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); - let loopScope = compiler.getRecorder().getScopeOfNode(stmt); - let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; let loopEnv = pandaGen.getTemp(); pandaGen.label(stmt, loopStartLabel); @@ -77,24 +78,24 @@ export function compileDoStatement(stmt: ts.DoStatement, compiler: Compiler) { export function compileWhileStatement(stmt: ts.WhileStatement, compiler: Compiler) { compiler.pushScope(stmt); let pandaGen = compiler.getPandaGen(); + + let loopScope = compiler.getRecorder().getScopeOfNode(stmt); + let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; + let loopStartLabel = new Label(); let loopEndLabel = new Label(); - - let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel); + let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLoopEnv); LabelTarget.pushLabelTarget(labelTarget); - LabelTarget.updateName2LabelTarget(stmt.parent, new LabelTarget(loopEndLabel, loopStartLabel)); + LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); - let loopScope = compiler.getRecorder().getScopeOfNode(stmt); - let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; let loopEnv = pandaGen.getTemp(); pandaGen.label(stmt, loopStartLabel); - compiler.compileCondition(stmt.expression, loopEndLabel); - if (needCreateLoopEnv) { pandaGen.createLexEnv(stmt, loopEnv, loopScope); compiler.pushEnv(loopEnv); } + compiler.compileCondition(stmt.expression, loopEndLabel); compiler.compileStatement(stmt.statement); @@ -138,8 +139,7 @@ export function compileForStatement(stmt: ts.ForStatement, compiler: Compiler) { let loopStartLabel = new Label(); let loopEndLabel = new Label(); let incLabel = new Label(); - - let labelTarget = new LabelTarget(loopEndLabel, incLabel); + let labelTarget = new LabelTarget(stmt, loopEndLabel, incLabel, needCreateLoopEnv); LabelTarget.pushLabelTarget(labelTarget); LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); @@ -253,26 +253,18 @@ export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compile compiler.pushScope(stmt); let pandaGen = compiler.getPandaGen(); + // determine the location where env should be created + let loopScope = compiler.getRecorder().getScopeOfNode(stmt); + let needCreateLexEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; + let loopEnv = pandaGen.getTemp(); + // init label info; let loopStartLabel = new Label(); let loopEndLabel = new Label(); - let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel); + let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLexEnv); LabelTarget.pushLabelTarget(labelTarget); LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); - // determine the location where env should be created - let loopScope = compiler.getRecorder().getScopeOfNode(stmt); - let needCreateLexEnv: boolean = loopScope.need2CreateLexEnv() ? true : false; - let createEnvAtBegining: boolean = false; - let loopEnv = pandaGen.getTemp(); - if (needCreateLexEnv && ts.isVariableDeclarationList(stmt.initializer)) { - loopScope.getName2variable().forEach(v => { - if (v.isLetOrConst() && v.isLexVar) { - createEnvAtBegining = true; - } - }); - } - let iterReg = pandaGen.getTemp(); let propName = pandaGen.getTemp(); @@ -282,7 +274,7 @@ export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compile pandaGen.storeAccumulator(stmt, iterReg); pandaGen.label(stmt, loopStartLabel); - if (needCreateLexEnv && createEnvAtBegining) { + if (needCreateLexEnv) { pandaGen.createLexEnv(stmt, loopEnv, loopScope); compiler.pushEnv(loopEnv); } @@ -296,10 +288,6 @@ export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compile pandaGen.loadAccumulator(stmt, propName); lref.setValue(); - if (needCreateLexEnv && !createEnvAtBegining) { - pandaGen.createLexEnv(stmt, loopEnv, loopScope); - compiler.pushEnv(loopEnv); - } compiler.compileStatement(stmt.statement); if (needCreateLexEnv) { diff --git a/ts2panda/src/statement/switchStatement.ts b/ts2panda/src/statement/switchStatement.ts index 3bf95465fb..7c4213bafa 100644 --- a/ts2panda/src/statement/switchStatement.ts +++ b/ts2panda/src/statement/switchStatement.ts @@ -45,7 +45,7 @@ export class SwitchBase { * switchStatements doesn't have continue target * so we use the uplevel continue label as it's continue target. */ - let labelTarget = new LabelTarget(switchEndLabel, LabelTarget.getCloseContinueTarget()); + let labelTarget = new LabelTarget(stmt, switchEndLabel, LabelTarget.getCloseContinueTarget()); LabelTarget.pushLabelTarget(labelTarget); LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); } diff --git a/ts2panda/src/statement/tryStatement.ts b/ts2panda/src/statement/tryStatement.ts index a70b249b3e..bdc0a632df 100644 --- a/ts2panda/src/statement/tryStatement.ts +++ b/ts2panda/src/statement/tryStatement.ts @@ -111,6 +111,7 @@ export class TryStatement { private outer: TryStatement | undefined; private stmt: ts.Statement; private catchTable: CatchTable; + private loopEnvLevel: number = 0; trybuilder: TryBuilderBase | undefined; constructor(stmt: ts.Statement, catchTable: CatchTable, trybuilder?: TryBuilderBase) { @@ -153,6 +154,18 @@ export class TryStatement { getCatchTable() { return this.catchTable; } + + getLoopEnvLevel() { + return this.loopEnvLevel; + } + + increaseLoopEnvLevel() { + this.loopEnvLevel += 1; + } + + decreaseLoopEnvLevel() { + this.loopEnvLevel -= 1; + } } export abstract class TryBuilderBase { @@ -254,25 +267,12 @@ export class TryBuilderWithForOf extends TryBuilderBase { let isDeclaration: boolean = false; let loopScope = compiler.getRecorder().getScopeOfNode(stmt); - let createLoopEnvAtBegining: boolean = false; - - if (ts.isVariableDeclarationList(stmt.initializer)) { - isDeclaration = true; - - if (this.hasLoopEnv) { - let decl = stmt.initializer.declarations[0]; - let declKind = astutils.getVarDeclarationKind(decl); - if (declKind == VarDeclarationKind.LET || declKind == VarDeclarationKind.CONST) { - createLoopEnvAtBegining = true; - } - } - } pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.True)); pandaGen.storeAccumulator(stmt, this.doneReg); pandaGen.label(stmt, this.labelTarget.getContinueTargetLabel()!); - if (this.hasLoopEnv && createLoopEnvAtBegining) { + if (this.hasLoopEnv) { pandaGen.createLexEnv(stmt, this.loopEnv, loopScope); compiler.pushEnv(this.loopEnv); } @@ -292,10 +292,6 @@ export class TryBuilderWithForOf extends TryBuilderBase { pandaGen.loadAccumulator(stmt, resultReg); lref.setValue(); - if (this.hasLoopEnv && !createLoopEnvAtBegining) { - pandaGen.createLexEnv(stmt, this.loopEnv, loopScope); - compiler.pushEnv(this.loopEnv); - } this.compiler.compileStatement(stmt.statement); this.tryStatement.destroy(); pandaGen.freeTemps(resultReg); -- Gitee