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