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}