Fix wrong lex env when control flow changed

Signed-off-by: hufeng <hufeng20@huawei.com>
Change-Id: I19a93fe4f60479f8a89add044ca567be3f985731
This commit is contained in:
hufeng
2022-04-26 23:13:52 +08:00
parent fe09a27762
commit c9a992777e
6 changed files with 122 additions and 60 deletions
+46 -1
View File
@@ -587,6 +587,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);
@@ -596,6 +626,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()!);
}
@@ -608,6 +643,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());
}
@@ -620,7 +660,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);
}
@@ -643,6 +683,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);
}
+1 -1
View File
@@ -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);
+35 -2
View File
@@ -22,13 +22,19 @@ import { Label } from "../irnodes";
export class LabelTarget {
private static name2LabelTarget: Map<string, LabelTarget> = new Map<string, LabelTarget>();
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) {
+25 -37
View File
@@ -35,16 +35,17 @@ import { LabelTarget } from "./labelTarget";
export function compileDoStatement(stmt: ts.DoStatement, compiler: Compiler) {
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let conditionLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, conditionLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
let loopScope = <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(stmt, loopEndLabel, conditionLabel, needCreateLoopEnv);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
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 loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, new LabelTarget(loopEndLabel, loopStartLabel));
let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLoopEnv);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
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,25 +253,17 @@ export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compile
compiler.pushScope(stmt);
let pandaGen = compiler.getPandaGen();
// init label info;
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(loopEndLabel, loopStartLabel);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
// determine the location where env should be created
let loopScope = <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;
}
});
}
// init label info;
let loopStartLabel = new Label();
let loopEndLabel = new Label();
let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLexEnv);
LabelTarget.pushLabelTarget(labelTarget);
LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
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) {
+1 -1
View File
@@ -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);
}
+14 -18
View File
@@ -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 = <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, <VReg>this.loopEnv, loopScope);
compiler.pushEnv(<VReg>this.loopEnv);
}
@@ -292,10 +292,6 @@ export class TryBuilderWithForOf extends TryBuilderBase {
pandaGen.loadAccumulator(stmt, resultReg);
lref.setValue();
if (this.hasLoopEnv && !createLoopEnvAtBegining) {
pandaGen.createLexEnv(stmt, <VReg>this.loopEnv, loopScope);
compiler.pushEnv(<VReg>this.loopEnv);
}
this.compiler.compileStatement(stmt.statement);
this.tryStatement.destroy();
pandaGen.freeTemps(resultReg);