1/* 2 * Copyright (c) 2021 - 2023 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 "functionBuilder.h" 17 18#include "varbinder/varbinder.h" 19#include "util/helpers.h" 20#include "ir/statement.h" 21#include "ir/base/scriptFunction.h" 22#include "compiler/base/iterators.h" 23#include "compiler/core/pandagen.h" 24 25namespace ark::es2panda::compiler { 26FunctionBuilder::FunctionBuilder(PandaGen *pg, CatchTable *catchTable) 27 : pg_(pg), catchTable_(catchTable), funcObj_(catchTable != nullptr ? pg_->AllocReg() : VReg(VReg::REG_START)) 28{ 29} 30 31IteratorType FunctionBuilder::GeneratorKind() const 32{ 33 return IteratorType::SYNC; 34} 35 36void FunctionBuilder::DirectReturn(const ir::AstNode *node) const 37{ 38 pg_->EmitReturn(node); 39} 40 41void FunctionBuilder::ImplicitReturn(const ir::AstNode *node) const 42{ 43 const auto *rootNode = pg_->RootNode(); 44 45 if (!rootNode->IsScriptFunction() || !rootNode->AsScriptFunction()->IsConstructor()) { 46 pg_->EmitReturnUndefined(node); 47 return; 48 } 49 50 pg_->GetThis(rootNode); 51 pg_->ThrowIfSuperNotCorrectCall(rootNode, 0); 52 pg_->EmitReturn(node); 53} 54 55void FunctionBuilder::AsyncYield(const ir::AstNode *node, VReg completionType, VReg completionValue) const 56{ 57 ASSERT(BuilderKind() == BuilderType::ASYNC_GENERATOR); 58 59 pg_->GeneratorYield(node, funcObj_); 60 pg_->SuspendAsyncGenerator(node, funcObj_); 61 62 ResumeGenerator(node, completionType, completionValue); 63} 64 65void FunctionBuilder::SuspendResumeExecution(const ir::AstNode *node, VReg completionType, VReg completionValue) const 66{ 67 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR || 68 BuilderKind() == BuilderType::GENERATOR); 69 70 pg_->SuspendGenerator(node, funcObj_); 71 ResumeGenerator(node, completionType, completionValue); 72} 73 74void FunctionBuilder::ResumeGenerator(const ir::AstNode *node, VReg completionType, VReg completionValue) const 75{ 76 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR || 77 BuilderKind() == BuilderType::GENERATOR); 78 79 pg_->ResumeGenerator(node, funcObj_); 80 pg_->StoreAccumulator(node, completionValue); 81 pg_->GetResumeMode(node, funcObj_); 82 pg_->StoreAccumulator(node, completionType); 83} 84 85VReg FunctionBuilder::FunctionReg(const ir::ScriptFunction *node) const 86{ 87 varbinder::FunctionScope *scope = node->Scope(); 88 auto res = scope->Find(varbinder::VarBinder::MANDATORY_PARAM_FUNC); 89 ASSERT(res.level == 0 && res.variable->IsLocalVariable()); 90 return res.variable->AsLocalVariable()->Vreg(); 91} 92 93void FunctionBuilder::Await(const ir::AstNode *node) 94{ 95 if (BuilderKind() == BuilderType::NORMAL) { 96 // NOTE: frobert. Implement top-level await 97 PandaGen::Unimplemented(); 98 } 99 100 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR); 101 102 RegScope rs(pg_); 103 VReg completionType = pg_->AllocReg(); 104 VReg completionValue = pg_->AllocReg(); 105 106 pg_->AsyncFunctionAwait(node, funcObj_); 107 SuspendResumeExecution(node, completionType, completionValue); 108 109 HandleCompletion(node, completionType, completionValue); 110} 111 112void FunctionBuilder::HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue) 113{ 114 // .return(value) 115 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN)); 116 117 auto *notRetLabel = pg_->AllocLabel(); 118 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notRetLabel); 119 if (!handleReturn_) { 120 handleReturn_ = true; 121 pg_->ControlFlowChangeBreak(); 122 handleReturn_ = false; 123 } 124 125 pg_->LoadAccumulator(node, completionValue); 126 pg_->DirectReturn(node); 127 128 // .throw(value) 129 pg_->SetLabel(node, notRetLabel); 130 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW)); 131 132 auto *notThrowLabel = pg_->AllocLabel(); 133 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notThrowLabel); 134 pg_->LoadAccumulator(node, completionValue); 135 pg_->EmitThrow(node); 136 137 // .next(value) 138 pg_->SetLabel(node, notThrowLabel); 139 pg_->LoadAccumulator(node, completionValue); 140} 141 142void FunctionBuilder::YieldStar(const ir::AstNode *node) 143{ 144 ASSERT(BuilderKind() == BuilderType::GENERATOR || BuilderKind() == BuilderType::ASYNC_GENERATOR); 145 146 RegScope rs(pg_); 147 148 auto *loopStart = pg_->AllocLabel(); 149 auto *returnCompletion = pg_->AllocLabel(); 150 auto *throwCompletion = pg_->AllocLabel(); 151 auto *callMethod = pg_->AllocLabel(); 152 auto *normalOrThrowCompletion = pg_->AllocLabel(); 153 auto *iteratorComplete = pg_->AllocLabel(); 154 155 // 4. Let iteratorRecord be ? GetIterator(value, generatorKind). 156 Iterator iterator(pg_, node, GeneratorKind()); 157 158 // 6. Let received be NormalCompletion(undefined). 159 VReg receivedValue = iterator.NextResult(); 160 VReg receivedType = pg_->AllocReg(); 161 VReg nextMethod = pg_->AllocReg(); 162 VReg exitReturn = pg_->AllocReg(); 163 164 pg_->StoreConst(node, receivedValue, Constant::JS_UNDEFINED); 165 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT)); 166 pg_->StoreAccumulator(node, receivedType); 167 pg_->MoveVreg(node, nextMethod, iterator.Method()); 168 169 // 7. Repeat 170 pg_->SetLabel(node, loopStart); 171 pg_->StoreConst(node, exitReturn, Constant::JS_FALSE); 172 173 // a. If received.[[Type]] is normal, then 174 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT)); 175 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, throwCompletion); 176 pg_->MoveVreg(node, iterator.Method(), nextMethod); 177 pg_->Branch(node, callMethod); 178 179 // b. Else if received.[[Type]] is throw, then 180 pg_->SetLabel(node, throwCompletion); 181 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW)); 182 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, returnCompletion); 183 184 // i. Let throw be ? GetMethod(iterator, "throw"). 185 iterator.GetMethod("throw"); 186 187 // ii. If throw is not undefined, then 188 pg_->BranchIfNotUndefined(node, callMethod); 189 190 // iii. Else, 191 // 1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we 192 // need to give iterator a chance to clean up. 193 // 2. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }. 194 // 3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion). 195 // 4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion). 196 iterator.Close(false); 197 // 5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does 198 // not have a throw method. 199 // 6. Throw a TypeError exception. 200 pg_->ThrowThrowNotExist(node); 201 202 // c. Else, 203 // i. Assert: received.[[Type]] is return. 204 pg_->SetLabel(node, returnCompletion); 205 pg_->StoreConst(node, exitReturn, Constant::JS_TRUE); 206 // ii. Let return be ? GetMethod(iterator, "return"). 207 iterator.GetMethod("return"); 208 209 // iii. If return is undefined, then 210 pg_->BranchIfNotUndefined(node, callMethod); 211 212 // 1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]). 213 pg_->ControlFlowChangeBreak(); 214 pg_->LoadAccumulator(node, receivedValue); 215 216 if (GeneratorKind() == IteratorType::ASYNC) { 217 Await(node); 218 } 219 220 // 2. Return Completion(received). 221 pg_->DirectReturn(node); 222 223 pg_->SetLabel(node, callMethod); 224 // i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »). 225 // 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »). 226 // iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »). 227 iterator.CallMethodWithValue(); 228 229 // ii. ii. If generatorKind is async, set innerResult to ? Await(innerResult). 230 // 2. If generatorKind is async, set innerResult to ? Await(innerResult). 231 // v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult). 232 if (GeneratorKind() == IteratorType::ASYNC) { 233 Await(node); 234 } 235 236 pg_->StoreAccumulator(node, receivedValue); 237 238 // ii. If Type(innerResult) is not Object, throw a TypeError exception. 239 // 4. If Type(innerResult) is not Object, throw a TypeError exception. 240 // vi. If Type(innerReturnResult) is not Object, throw a TypeError exception. 241 pg_->ThrowIfNotObject(node); 242 243 // iv. Let done be ? IteratorComplete(innerResult). 244 // v. Let done be ? IteratorComplete(innerResult). 245 // vii. Let done be ? IteratorComplete(innerReturnResult). 246 iterator.Complete(); 247 pg_->BranchIfTrue(node, iteratorComplete); 248 249 // vi. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)). 250 // 7. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)). 251 // ix. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerReturnResult)). 252 if (GeneratorKind() == IteratorType::ASYNC) { 253 iterator.Value(); 254 // 27.6.3.8 AsyncGeneratorYield 255 // 5. Set value to ? Await(value). 256 Await(node); 257 // 6. Set generator.[[AsyncGeneratorState]] to suspendedYield. 258 AsyncYield(node, receivedType, receivedValue); 259 260 // a. If resumptionValue.[[Type]] is not return 261 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN)); 262 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, receivedType, loopStart); 263 264 // b. Let awaited be Await(resumptionValue.[[Value]]). 265 pg_->LoadAccumulator(node, receivedValue); 266 pg_->AsyncFunctionAwait(node, funcObj_); 267 SuspendResumeExecution(node, receivedType, receivedValue); 268 269 // c. If awaited.[[Type]] is throw, return Completion(awaited). 270 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW)); 271 // d. Assert: awaited.[[Type]] is normal. 272 // e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }. 273 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, receivedType, returnCompletion); 274 } else { 275 // vii. Else, set received to GeneratorYield(innerResult). 276 // 8. Else, set received to GeneratorYield(innerResult). 277 // x. Else, set received to GeneratorYield(innerReturnResult). 278 pg_->LoadAccumulator(node, receivedValue); 279 pg_->GeneratorYield(node, funcObj_); 280 SuspendResumeExecution(node, receivedType, receivedValue); 281 } 282 283 pg_->Branch(node, loopStart); 284 285 // v. If done is true, then 286 // 6. If done is true, then 287 // viii. If done is true, then 288 pg_->SetLabel(node, iteratorComplete); 289 290 pg_->LoadAccumulator(node, exitReturn); 291 pg_->BranchIfFalse(node, normalOrThrowCompletion); 292 293 // 1. Let value be ? IteratorValue(innerReturnResult). 294 iterator.Value(); 295 296 if (pg_->CheckControlFlowChange()) { 297 pg_->StoreAccumulator(node, receivedValue); 298 pg_->ControlFlowChangeBreak(); 299 pg_->LoadAccumulator(node, receivedValue); 300 } 301 302 // 2. Return Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }. 303 pg_->DirectReturn(node); 304 305 pg_->SetLabel(node, normalOrThrowCompletion); 306 // 1. Return ? IteratorValue(innerResult). 307 // a. Return ? IteratorValue(innerResult). 308 iterator.Value(); 309} 310} // namespace ark::es2panda::compiler 311