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}