• 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
16import { CacheList, getVregisterCache } from "../base/vregisterCache";
17import * as ts from "typescript";
18import { NodeKind } from "../debuginfo";
19import {
20    Label,
21    VReg
22} from "../irnodes";
23import { PandaGen } from "../pandagen";
24import { CatchTable, LabelPair } from "../statement/tryStatement";
25import { FunctionBuilder, FunctionBuilderType } from "./functionBuilder";
26
27enum ResumeMode {
28    RETURN,
29    THROW,
30    NEXT
31};
32
33/**
34 * async function foo() {
35 *     await 'promise obj';
36 * }
37 */
38export class AsyncFunctionBuilder extends FunctionBuilder {
39    constructor(pandaGen: PandaGen) {
40        super(pandaGen);
41        this.funcObj = pandaGen.getTemp();
42        this.resumeVal = pandaGen.getTemp();
43        this.beginLabel = new Label();
44        this.endLabel = new Label();
45    }
46
47    prepare(node: ts.Node): void {
48        let pandaGen = this.pg;
49
50        pandaGen.asyncFunctionEnter(NodeKind.INVALID);
51        pandaGen.storeAccumulator(NodeKind.INVALID, this.funcObj);
52
53        pandaGen.label(node, this.beginLabel);
54    }
55
56    await(node: ts.Node): void {
57        // value is in acc
58        this.functionAwait(node);
59        this.handleMode(node);
60    }
61
62    explicitReturn(node: ts.Node | NodeKind, empty ? : boolean): void {
63        // value is in acc
64        this.pg.asyncFunctionResolve(node, this.funcObj);
65        this.pg.return(node);
66    }
67
68    implicitReturn(node: ts.Node | NodeKind): void {
69        this.pg.loadAccumulator(node, getVregisterCache(this.pg, CacheList.UNDEFINED));
70        this.pg.asyncFunctionResolve(node, this.funcObj);
71        this.pg.return(node);
72    }
73
74    private handleMode(node: ts.Node): void {
75        let pandaGen = this.pg;
76        let modeType = pandaGen.getTemp();
77
78        pandaGen.getResumeMode(node, this.funcObj);
79        pandaGen.storeAccumulator(node, modeType);
80
81        // .reject
82        pandaGen.loadAccumulatorInt(node, ResumeMode.THROW);
83
84        let notThrowLabel = new Label();
85
86        // jump to normal code
87        pandaGen.condition(node, ts.SyntaxKind.EqualsEqualsToken, modeType, notThrowLabel);
88        pandaGen.loadAccumulator(node, this.resumeVal);
89        pandaGen.throw(node);
90
91        pandaGen.freeTemps(modeType);
92
93        // .resolve
94        pandaGen.label(node, notThrowLabel);
95        pandaGen.loadAccumulator(node, this.resumeVal);
96    }
97
98    resolve(node: ts.Node | NodeKind, value: VReg): void {
99        let pandaGen = this.pg;
100        pandaGen.loadAccumulator(node, value);
101        pandaGen.asyncFunctionResolve(node, this.funcObj);
102    }
103
104    cleanUp(node: ts.Node): void {
105        let pandaGen = this.pg;
106
107        pandaGen.label(node, this.endLabel);
108
109        // exception is in acc
110        pandaGen.asyncFunctionReject(NodeKind.INVALID, this.funcObj);
111        pandaGen.return(NodeKind.INVALID);
112
113        pandaGen.freeTemps(this.funcObj, this.resumeVal);
114
115        new CatchTable(pandaGen, this.endLabel, new LabelPair(this.beginLabel, this.endLabel));
116    }
117
118    builderType(): FunctionBuilderType {
119        return FunctionBuilderType.ASYNC;
120    }
121}