• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device 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
16/**
17 * The loopStatement implementation.
18 * This file implements Compilation process of loop statement
19 * and uses Pandagen to generate bytecode.
20 *
21 */
22
23import { Variable } from "src/variable";
24import * as ts from "typescript";
25import { LReference } from "../base/lreference";
26import {
27    CacheList,
28    getVregisterCache
29} from "../base/vregisterCache";
30import { Compiler } from "../compiler";
31import { Label, VReg } from "../irnodes";
32import { LoopScope, Scope } from "../scope";
33import { LabelTarget } from "./labelTarget";
34
35export function compileDoStatement(stmt: ts.DoStatement, compiler: Compiler): void {
36    compiler.pushScope(stmt);
37    let pandaGen = compiler.getPandaGen();
38
39    let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
40    let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
41
42    let loopStartLabel = new Label();
43    let loopEndLabel = new Label();
44    let conditionLabel = new Label();
45    let labelTarget = new LabelTarget(stmt, loopEndLabel, conditionLabel, needCreateLoopEnv);
46    LabelTarget.pushLabelTarget(labelTarget);
47    LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
48
49
50    pandaGen.label(stmt, loopStartLabel);
51    if (needCreateLoopEnv) {
52        pandaGen.createLexEnv(stmt, loopScope);
53    }
54
55    compiler.compileStatement(stmt.statement);
56    pandaGen.label(stmt, conditionLabel);
57    compiler.compileCondition(stmt.expression, loopEndLabel);
58
59    if (needCreateLoopEnv) {
60        pandaGen.popLexicalEnv(stmt);
61    }
62
63    pandaGen.branch(stmt, loopStartLabel);
64    pandaGen.label(stmt, loopEndLabel);
65
66    if (needCreateLoopEnv) {
67        pandaGen.popLexicalEnv(stmt);
68        compiler.popEnv();
69    }
70
71    LabelTarget.popLabelTarget();
72    compiler.popScope();
73}
74
75export function compileWhileStatement(stmt: ts.WhileStatement, compiler: Compiler): void {
76    compiler.pushScope(stmt);
77    let pandaGen = compiler.getPandaGen();
78
79    let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
80    let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
81
82    let loopStartLabel = new Label();
83    let loopEndLabel = new Label();
84    let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLoopEnv);
85    LabelTarget.pushLabelTarget(labelTarget);
86    LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
87
88    pandaGen.label(stmt, loopStartLabel);
89    if (needCreateLoopEnv) {
90        pandaGen.createLexEnv(stmt, loopScope);
91    }
92    compiler.compileCondition(stmt.expression, loopEndLabel);
93
94    compiler.compileStatement(stmt.statement);
95
96    if (needCreateLoopEnv) {
97        pandaGen.popLexicalEnv(stmt);
98    }
99
100    pandaGen.branch(stmt, loopStartLabel);
101    pandaGen.label(stmt, loopEndLabel);
102
103    if (needCreateLoopEnv) {
104        pandaGen.popLexicalEnv(stmt);
105        compiler.popEnv();
106    }
107
108    LabelTarget.popLabelTarget();
109    compiler.popScope();
110}
111
112export function compileForStatement(stmt: ts.ForStatement, compiler: Compiler): void {
113    compiler.pushScope(stmt);
114    let pandaGen = compiler.getPandaGen();
115
116    // determine if loopenv need to be created
117    let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
118    let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv();
119    let createEnvAtBegining: boolean = false;
120    if (needCreateLoopEnv) {
121        // determine the location where loopenv should be created
122        if (stmt.initializer && ts.isVariableDeclarationList(stmt.initializer)) {
123            loopScope.getName2variable().forEach(v => {
124                if (v.isLetOrConst() && v.isLexVar) {
125                    createEnvAtBegining = true;
126                }
127            });
128        }
129    }
130
131    let loopStartLabel = new Label();
132    let loopEndLabel = new Label();
133    let incLabel = new Label();
134    let labelTarget = new LabelTarget(stmt, loopEndLabel, incLabel, needCreateLoopEnv);
135    LabelTarget.pushLabelTarget(labelTarget);
136    LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
137
138    if (stmt.initializer && ts.isVariableDeclarationList(stmt.initializer) && createEnvAtBegining && needCreateLoopEnv) {
139        pandaGen.createLexEnv(stmt, loopScope);
140
141        let declList = <ts.VariableDeclarationList>stmt.initializer;
142        declList.declarations.forEach(decl => compiler.compileVariableDeclaration(decl));
143
144        // loopCondition
145        pandaGen.label(stmt, loopStartLabel);
146
147        if (stmt.condition) {
148            compiler.compileCondition(stmt.condition, loopEndLabel);
149        }
150
151        // loopBody
152        compiler.compileStatement(stmt.statement);
153
154        // loopIncrementor
155        pandaGen.label(stmt, incLabel);
156
157        // load init from current env for the use of the next iteration
158        type variableInfo = { scope: Scope | undefined, level: number, v: Variable | undefined };
159        let variables: Map<variableInfo, VReg> = new Map<variableInfo, VReg>();
160        let tmpVregs: Array<VReg> = new Array<VReg>();
161        loopScope.getName2variable().forEach((v, name) => {
162            if (v.isLexVar && v.isLetOrConst()) {
163                let tmp = pandaGen.getTemp();
164                tmpVregs.push(tmp);
165                let varInfo = loopScope.find(name);
166                variables.set(varInfo, tmp);
167                compiler.loadTarget(stmt, varInfo);
168                pandaGen.storeAccumulator(stmt, tmp);
169            }
170        });
171
172        // pop the current loopenv and create a new loopenv before the next iteration
173        pandaGen.popLexicalEnv(stmt);
174        pandaGen.createLexEnv(stmt, loopScope);
175        variables.forEach((reg, varInfo) => {
176            let slot: number = (<Variable>varInfo.v).idxLex;
177            // emitStore is not used here to avoid dead-zone check within it, just use storeLexcialVar
178            pandaGen.storeLexicalVar(stmt, varInfo.level, slot, reg);
179        })
180
181        // must compile incrementor after store the previous value into the corresponding slot, otherwise will fall into a dead loop
182        if (stmt.incrementor) {
183            compiler.compileExpression(stmt.incrementor);
184        }
185
186        pandaGen.branch(stmt, loopStartLabel);
187        pandaGen.label(stmt, loopEndLabel);
188
189        pandaGen.popLexicalEnv(stmt);
190        compiler.popEnv();
191        pandaGen.freeTemps(...tmpVregs);
192    } else { // compile for in fast mode
193        if (needCreateLoopEnv) {
194            pandaGen.createLexEnv(stmt, loopScope);
195        }
196
197        if (stmt.initializer) {
198            if (ts.isVariableDeclarationList(stmt.initializer)) {
199                let declList = <ts.VariableDeclarationList>stmt.initializer;
200                declList.declarations.forEach((decl) => compiler.compileVariableDeclaration(decl));
201            } else {
202                compiler.compileExpression(stmt.initializer);
203            }
204        }
205
206        if (needCreateLoopEnv) {
207            pandaGen.popLexicalEnv(stmt);
208            compiler.popEnv();
209        }
210
211        // loopCondition
212        pandaGen.label(stmt, loopStartLabel);
213
214        // createLoopEnv if needed
215        if (needCreateLoopEnv) {
216            pandaGen.createLexEnv(stmt, loopScope);
217        }
218
219        if (stmt.condition) {
220            compiler.compileCondition(stmt.condition, loopEndLabel);
221        }
222
223        // loopBody
224        compiler.compileStatement(stmt.statement);
225
226        // loopIncrementor
227        pandaGen.label(stmt, incLabel);
228        if (stmt.incrementor) {
229            compiler.compileExpression(stmt.incrementor);
230        }
231
232        // pop the current loopenv before next iteration
233        if (needCreateLoopEnv) {
234            pandaGen.popLexicalEnv(stmt);
235        }
236
237        pandaGen.branch(stmt, loopStartLabel);
238        pandaGen.label(stmt, loopEndLabel);
239
240        if (needCreateLoopEnv) {
241            pandaGen.popLexicalEnv(stmt);
242            compiler.popEnv();
243        }
244    }
245
246    LabelTarget.popLabelTarget();
247    compiler.popScope();
248}
249
250export function compileForInStatement(stmt: ts.ForInStatement, compiler: Compiler): void {
251    compiler.pushScope(stmt);
252    let pandaGen = compiler.getPandaGen();
253
254    // determine the location where env should be created
255    let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt);
256    let needCreateLexEnv: boolean = loopScope.need2CreateLexEnv() ? true : false;
257
258    // init label info;
259    let loopStartLabel = new Label();
260    let loopEndLabel = new Label();
261    let labelTarget = new LabelTarget(stmt, loopEndLabel, loopStartLabel, needCreateLexEnv);
262    LabelTarget.pushLabelTarget(labelTarget);
263    LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
264
265    let iterReg = pandaGen.getTemp();
266    let propName = pandaGen.getTemp();
267
268    if (needCreateLexEnv) {
269        pandaGen.createLexEnv(stmt, loopScope);
270    }
271
272    // create enumerator
273    compiler.compileExpression(stmt.expression);
274    pandaGen.getPropIterator(stmt);
275    pandaGen.storeAccumulator(stmt, iterReg);
276
277    if (needCreateLexEnv) {
278        pandaGen.popLexicalEnv(stmt);
279        compiler.popEnv();
280    }
281
282    pandaGen.label(stmt, loopStartLabel);
283    if (needCreateLexEnv) {
284        pandaGen.createLexEnv(stmt, loopScope);
285    }
286
287    // get next prop of enumerator
288    pandaGen.getNextPropName(stmt, iterReg);
289    pandaGen.storeAccumulator(stmt, propName);
290    pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.UNDEFINED), loopEndLabel);
291
292    let lref = LReference.generateLReference(compiler, stmt.initializer, false);
293    pandaGen.loadAccumulator(stmt, propName);
294    lref.setValue();
295
296    compiler.compileStatement(stmt.statement);
297
298    if (needCreateLexEnv) {
299        pandaGen.popLexicalEnv(stmt);
300    }
301    pandaGen.branch(stmt, loopStartLabel);
302    pandaGen.label(stmt, loopEndLabel);
303
304    if (needCreateLexEnv) {
305        pandaGen.popLexicalEnv(stmt);
306        compiler.popEnv();
307    }
308
309    pandaGen.freeTemps(iterReg, propName);
310    LabelTarget.popLabelTarget();
311    compiler.popScope();
312}