• 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 * as ts from "typescript";
17import { CacheList, getVregisterCache } from "../base/vregisterCache";
18import { NodeKind } from "../debuginfo";
19import {
20    Label,
21    VReg
22} from "../irnodes";
23import { PandaGen } from "../pandagen";
24import { CatchTable, LabelPair } from "../statement/tryStatement";
25
26enum ResumeMode { Return = 0, Throw, Next };
27
28/**
29 * async function foo() {
30 *     await 'promise obj';
31 * }
32 */
33export class AsyncFunctionBuilder {
34    private pandaGen: PandaGen;
35    private beginLabel: Label;
36    private endLabel: Label;
37    private asyncObj: VReg;
38    private retVal: VReg;
39
40    constructor(pandaGen: PandaGen) {
41        this.pandaGen = pandaGen;
42        this.beginLabel = new Label();
43        this.endLabel = new Label();
44        this.asyncObj = pandaGen.getTemp();
45        this.retVal = pandaGen.getTemp();
46    }
47
48    prepare(node: ts.Node): void {
49        let pandaGen = this.pandaGen;
50
51        pandaGen.asyncFunctionEnter(NodeKind.Invalid);
52        pandaGen.storeAccumulator(NodeKind.Invalid, this.asyncObj);
53
54        pandaGen.label(node, this.beginLabel);
55    }
56
57    await(node: ts.Node, value: VReg): void {
58        let pandaGen = this.pandaGen;
59        let promise = this.pandaGen.getTemp();
60
61        pandaGen.asyncFunctionAwaitUncaught(node, this.asyncObj, value);
62        pandaGen.storeAccumulator(node, promise);
63
64        pandaGen.suspendGenerator(node, this.asyncObj, promise);
65
66        pandaGen.freeTemps(promise);
67
68        pandaGen.resumeGenerator(node, this.asyncObj);
69        pandaGen.storeAccumulator(node, this.retVal);
70
71        this.handleMode(node);
72    }
73
74    private handleMode(node: ts.Node) {
75        let pandaGen = this.pandaGen;
76        let modeType = pandaGen.getTemp();
77
78        pandaGen.getResumeMode(node, this.asyncObj);
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.retVal);
89        pandaGen.throw(node);
90
91        pandaGen.freeTemps(modeType);
92
93        // .resolve
94        pandaGen.label(node, notThrowLabel);
95        pandaGen.loadAccumulator(node, this.retVal);
96    }
97
98    resolve(node: ts.Node | NodeKind, value: VReg) {
99        let pandaGen = this.pandaGen;
100
101        pandaGen.asyncFunctionResolve(node, this.asyncObj, getVregisterCache(pandaGen, CacheList.True), value);
102    }
103
104    cleanUp(node: ts.Node): void {
105        let pandaGen = this.pandaGen;
106
107        pandaGen.label(node, this.endLabel);
108
109        // catch
110        let exception = pandaGen.getTemp();
111
112        pandaGen.storeAccumulator(NodeKind.Invalid, exception);
113        pandaGen.asyncFunctionReject(NodeKind.Invalid, this.asyncObj, getVregisterCache(pandaGen, CacheList.True), exception);
114        pandaGen.return(NodeKind.Invalid);
115
116        pandaGen.freeTemps(exception);
117
118        pandaGen.freeTemps(this.asyncObj, this.retVal);
119
120        new CatchTable(pandaGen, this.endLabel, new LabelPair(this.beginLabel, this.endLabel));
121    }
122}