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#include "asyncGeneratorFunctionBuilder.h" 17 18#include <compiler/base/catchTable.h> 19#include <compiler/core/pandagen.h> 20#include <ir/base/scriptFunction.h> 21 22namespace panda::es2panda::compiler { 23void AsyncGeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) 24{ 25 RegScope rs(pg_); 26 VReg callee = FunctionReg(node); 27 VReg completionType = pg_->AllocReg(); 28 VReg completionValue = pg_->AllocReg(); 29 30 pg_->CreateAsyncGeneratorObj(node, callee); 31 pg_->StoreAccumulator(node, funcObj_); 32 33 pg_->SetLabel(node, catchTable_->LabelSet().TryBegin()); 34 35 pg_->LoadConst(node, Constant::JS_UNDEFINED); 36 SuspendResumeExecution(node, completionType, completionValue); 37} 38 39void AsyncGeneratorFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const 40{ 41 const auto &labelSet = catchTable_->LabelSet(); 42 43 RegScope rs(pg_); 44 VReg retVal = pg_->AllocReg(); 45 46 pg_->SetLabel(node, labelSet.TryEnd()); 47 pg_->SetLabel(node, labelSet.CatchBegin()); 48 pg_->StoreAccumulator(node, retVal); 49 pg_->GeneratorComplete(node, funcObj_); 50 pg_->LoadAccumulator(node, retVal); 51 pg_->AsyncGeneratorReject(node, funcObj_); 52 pg_->EmitReturn(node); 53 pg_->SetLabel(node, labelSet.CatchEnd()); 54} 55 56void AsyncGeneratorFunctionBuilder::DirectReturn(const ir::AstNode *node) const 57{ 58 RegScope rs(pg_); 59 VReg retVal = pg_->AllocReg(); 60 VReg canSuspend = pg_->AllocReg(); 61 62 pg_->StoreAccumulator(node, retVal); 63 pg_->StoreConst(node, canSuspend, Constant::JS_TRUE); 64 65 pg_->GeneratorComplete(node, funcObj_); 66 pg_->AsyncGeneratorResolve(node, funcObj_, retVal, canSuspend); 67 // The INVALID_SOURCE_LOCATION is set in the implicitReturn method. When implicitReturn invokes 68 // the DirectReturn method, the EmitReturn needs to be associated with a valid node 69 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION); 70 pg_->EmitReturn(node); 71} 72 73void AsyncGeneratorFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const 74{ 75 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION); 76 pg_->LoadConst(node, Constant::JS_UNDEFINED); 77 DirectReturn(node); 78} 79 80void AsyncGeneratorFunctionBuilder::ExplicitReturn(const ir::AstNode *node) const 81{ 82 RegScope rs(pg_); 83 VReg resumeType = pg_->AllocReg(); 84 VReg resumeValue = pg_->AllocReg(); 85 VReg canSuspend = pg_->AllocReg(); 86 87 pg_->AsyncFunctionAwait(node, funcObj_); 88 SuspendResumeExecution(node, resumeType, resumeValue); 89 pg_->GeneratorComplete(node, funcObj_); 90 pg_->StoreConst(node, canSuspend, Constant::JS_TRUE); 91 pg_->AsyncGeneratorResolve(node, funcObj_, resumeValue, canSuspend); 92 pg_->EmitReturn(node); 93} 94 95void AsyncGeneratorFunctionBuilder::Yield(const ir::AstNode *node) 96{ 97 RegScope rs(pg_); 98 VReg value = pg_->AllocReg(); 99 VReg resumeType = pg_->AllocReg(); 100 VReg resumeValue = pg_->AllocReg(); 101 auto *notReturn = pg_->AllocLabel(); 102 auto *normalCompletion = pg_->AllocLabel(); 103 auto *notThrowCompletion = pg_->AllocLabel(); 104 105 // 27.6.3.8.5 Set value to ? Await(value). 106 Await(node); 107 pg_->StoreAccumulator(node, value); 108 109 AsyncYield(node, value, resumeType, resumeValue); 110 111 // 27.6.3.8.8.a If resumptionValue.[[Type]] is not return 112 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN)); 113 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, resumeType, notReturn); 114 115 // 27.6.3.8.8.b Let awaited be Await(resumptionValue.[[Value]]). 116 pg_->LoadAccumulator(node, resumeValue); 117 pg_->AsyncFunctionAwait(node, funcObj_); 118 SuspendResumeExecution(node, resumeType, resumeValue); 119 120 // 27.6.3.8.8.c. If awaited.[[Type]] is throw, return Completion(awaited). 121 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW)); 122 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, resumeType, normalCompletion); 123 pg_->LoadAccumulator(node, resumeValue); 124 pg_->EmitThrow(node); 125 126 pg_->SetLabel(node, normalCompletion); 127 // 27.6.3.8.8.d. Assert: awaited.[[Type]] is normal. 128 // 27.6.3.8.8.e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty } 129 pg_->ControlFlowChangeBreak(); 130 pg_->LoadAccumulator(node, resumeValue); 131 DirectReturn(node); 132 133 pg_->SetLabel(node, notReturn); 134 // 27.6.3.8.8.a return Completion(resumptionValue) 135 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW)); 136 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, resumeType, notThrowCompletion); 137 pg_->LoadAccumulator(node, resumeValue); 138 pg_->EmitThrow(node); 139 pg_->SetLabel(node, notThrowCompletion); 140 pg_->LoadAccumulator(node, resumeValue); 141} 142 143IteratorType AsyncGeneratorFunctionBuilder::GeneratorKind() const 144{ 145 return IteratorType::ASYNC; 146} 147} // namespace panda::es2panda::compiler 148