mirror of
https://github.com/openharmony/ark_ts2abc.git
synced 2026-07-21 00:05:28 -04:00
Fix wrong lex env when control flow changed
Signed-off-by: hufeng <hufeng20@huawei.com> Change-Id: I19a93fe4f60479f8a89add044ca567be3f985731
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user