1/* 2 * Copyright (c) 2021-2024 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 "ecmascript/builtins/builtins_promise.h" 17#include "ecmascript/builtins/builtins_promise_job.h" 18#include "ecmascript/global_env.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/jobs/micro_job_queue.h" 21#include "ecmascript/js_array.h" 22#include "ecmascript/js_iterator.h" 23 24namespace panda::ecmascript::builtins { 25using BuiltinsPromiseJob = builtins::BuiltinsPromiseJob; 26// 25.4.3.1 Promise ( executor ) 27JSTaggedValue BuiltinsPromise::PromiseConstructor(EcmaRuntimeCallInfo *argv) 28{ 29 ASSERT(argv); 30 BUILTINS_API_TRACE(argv->GetThread(), Promise, Constructor); 31 JSThread *thread = argv->GetThread(); 32 [[maybe_unused]] EcmaHandleScope handleScope(thread); 33 EcmaVM *ecmaVm = thread->GetEcmaVM(); 34 ObjectFactory *factory = ecmaVm->GetFactory(); 35 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 36 // 1. If NewTarget is undefined, throw a TypeError exception. 37 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 38 if (newTarget->IsUndefined()) { 39 THROW_TYPE_ERROR_AND_RETURN(thread, "PromiseConstructor: NewTarget is undefined", JSTaggedValue::Exception()); 40 } 41 // 2. If IsCallable(executor) is false, throw a TypeError exception. 42 JSHandle<JSTaggedValue> executor = BuiltinsBase::GetCallArg(argv, 0); 43 if (!executor->IsCallable()) { 44 THROW_TYPE_ERROR_AND_RETURN(thread, "PromiseConstructor: executor is not callable", JSTaggedValue::Exception()); 45 } 46 47 // 3. Let promise be OrdinaryCreateFromConstructor(NewTarget, "%PromisePrototype%", 48 // «[[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]]» ). 49 // 4. ReturnIfAbrupt(promise). 50 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 51 JSHandle<JSObject> newObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 52 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 53 JSHandle<JSPromise> instancePromise = JSHandle<JSPromise>::Cast(newObject); 54 55 // 5. Set promise's [[PromiseState]] internal slot to "pending". 56 // 6. Set promise's [[PromiseFulfillReactions]] internal slot to a new empty List. 57 // 7. Set promise's [[PromiseRejectReactions]] internal slot to a new empty List. 58 // 8. Let resolvingFunctions be CreateResolvingFunctions(promise). 59 JSHandle<ResolvingFunctionsRecord> resolvingFunction = JSPromise::CreateResolvingFunctions(thread, instancePromise); 60 // 9. Let completion be Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[reject]]) 61 auto resolveFunc = resolvingFunction->GetResolveFunction(); 62 auto rejectFunc = resolvingFunction->GetRejectFunction(); 63 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 64 const uint32_t argsLength = 2; // 2: «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]» 65 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, executor, undefined, undefined, argsLength); 66 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 67 info->SetCallArg(resolveFunc, rejectFunc); 68 JSTaggedValue taggedValue = JSFunction::Call(info); 69 JSHandle<JSTaggedValue> completionValue(thread, taggedValue); 70 71 // 10. If completion is an abrupt completion, then 72 // a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «completion.[[value]]»). 73 // b. ReturnIfAbrupt(status). 74 if (thread->HasPendingException()) { 75 completionValue = JSPromise::IfThrowGetThrowValue(thread); 76 thread->ClearException(); 77 JSHandle<JSTaggedValue> reject(thread, resolvingFunction->GetRejectFunction()); 78 EcmaRuntimeCallInfo *runtimeInfo = 79 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); 80 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 81 runtimeInfo->SetCallArg(completionValue.GetTaggedValue()); 82 JSFunction::Call(runtimeInfo); 83 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 84 } 85 86 // 11. Return promise. 87 return instancePromise.GetTaggedValue(); 88} 89 90// 25.4.4.1 Promise.all ( iterable ) 91JSTaggedValue BuiltinsPromise::All(EcmaRuntimeCallInfo *argv) 92{ 93 ASSERT(argv); 94 BUILTINS_API_TRACE(argv->GetThread(), Promise, All); 95 JSThread *thread = argv->GetThread(); 96 [[maybe_unused]] EcmaHandleScope handleScope(thread); 97 EcmaVM *ecmaVm = thread->GetEcmaVM(); 98 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 99 ObjectFactory *factory = ecmaVm->GetFactory(); 100 101 // 1. Let C be the this value. 102 JSHandle<JSTaggedValue> ctor = GetThis(argv); 103 // 2. If Type(C) is not Object, throw a TypeError exception. 104 if (!ctor->IsECMAObject()) { 105 THROW_TYPE_ERROR_AND_RETURN(thread, "Promise ALL: this value is not object", JSTaggedValue::Exception()); 106 } 107 // 3. Let S be Get(C, @@species). 108 // 4. ReturnIfAbrupt(S). 109 JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol(); 110 JSHandle<JSTaggedValue> sctor = JSObject::GetProperty(thread, ctor, speciesSymbol).GetValue(); 111 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, sctor.GetTaggedValue()); 112 113 // 5. If S is neither undefined nor null, let C be S. 114 if (!sctor->IsUndefined() && !sctor->IsNull()) { 115 ctor = sctor; 116 } 117 // 6. Let promiseCapability be NewPromiseCapability(C). 118 JSHandle<PromiseCapability> capa = JSPromise::NewPromiseCapability(thread, ctor); 119 // 7. ReturnIfAbrupt(promiseCapability). 120 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, capa.GetTaggedValue()); 121 // 8. Let iterator be GetIterator(iterable). 122 JSHandle<JSTaggedValue> itor = JSIterator::GetIterator(thread, GetCallArg(argv, 0)); 123 // 9. IfAbruptRejectPromise(iterator, promiseCapability). 124 if (thread->HasPendingException()) { 125 itor = JSPromise::IfThrowGetThrowValue(thread); 126 } 127 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, itor, capa); 128 129 // 10. Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. 130 bool done = false; 131 JSHandle<PromiseIteratorRecord> itRecord = factory->NewPromiseIteratorRecord(itor, done); 132 // 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). 133 JSTaggedValue resultValue = PerformPromiseAll(thread, itRecord, ctor, capa); 134 JSHandle<CompletionRecord> result = JSHandle<CompletionRecord>(thread, resultValue); 135 // 12. If result is an abrupt completion, 136 if (result->IsThrow()) { 137 thread->ClearException(); 138 // a. If iteratorRecord.[[done]] is false, let result be IteratorClose(iterator, result). 139 // b. IfAbruptRejectPromise(result, promiseCapability). 140 if (!itRecord->GetDone()) { 141 JSHandle<JSTaggedValue> closeVal = 142 JSIterator::IteratorClose(thread, itor, JSHandle<JSTaggedValue>::Cast(result)); 143 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, capa); 144 if (closeVal.GetTaggedValue().IsRecord()) { 145 result = JSHandle<CompletionRecord>::Cast(closeVal); 146 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, capa); 147 return result->GetValue(); 148 } 149 } 150 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, capa); 151 return result->GetValue(); 152 } 153 // 13. Return Completion(result). 154 return result->GetValue(); 155} 156 157// 25.4.4.3 Promise.race ( iterable ) 158JSTaggedValue BuiltinsPromise::Race(EcmaRuntimeCallInfo *argv) 159{ 160 ASSERT(argv); 161 BUILTINS_API_TRACE(argv->GetThread(), Promise, Race); 162 JSThread *thread = argv->GetThread(); 163 [[maybe_unused]] EcmaHandleScope handleScope(thread); 164 EcmaVM *ecmaVm = thread->GetEcmaVM(); 165 ObjectFactory *factory = ecmaVm->GetFactory(); 166 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 167 // 1. Let C be the this value. 168 // 2. If Type(C) is not Object, throw a TypeError exception. 169 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 170 if (!thisValue->IsECMAObject()) { 171 THROW_TYPE_ERROR_AND_RETURN(thread, "Race: this value is not object", JSTaggedValue::Exception()); 172 } 173 // 3. Let S be Get(C, @@species). 174 // 4. ReturnIfAbrupt(S). 175 // 5. If S is neither undefined nor null, let C be S. 176 JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol(); 177 JSHandle<JSTaggedValue> speciesConstructor = JSObject::GetProperty(thread, thisValue, speciesSymbol).GetValue(); 178 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 179 if (!(speciesConstructor->IsUndefined() || speciesConstructor->IsNull())) { 180 thisValue = speciesConstructor; 181 } 182 183 // 6. Let promiseCapability be NewPromiseCapability(C). 184 // 7. ReturnIfAbrupt(promiseCapability). 185 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, thisValue); 186 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 187 188 // 8. Let iterator be GetIterator(iterable). 189 // 9. IfAbruptRejectPromise(iterator, promiseCapability). 190 JSHandle<JSTaggedValue> iterable = GetCallArg(argv, 0); 191 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, iterable); 192 if (thread->HasPendingException()) { 193 iterator = JSPromise::IfThrowGetThrowValue(thread); 194 } 195 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, iterator, promiseCapability); 196 197 // 10. Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. 198 bool done = false; 199 JSHandle<PromiseIteratorRecord> iteratorRecord = factory->NewPromiseIteratorRecord(iterator, done); 200 201 // 11. Let result be PerformPromiseRace(iteratorRecord, promiseCapability, C). 202 // 12. If result is an abrupt completion, then 203 // a. If iteratorRecord.[[done]] is false, let result be IteratorClose(iterator,result). 204 // b. IfAbruptRejectPromise(result, promiseCapability). 205 // 13. Return Completion(result). 206 JSHandle<CompletionRecord> result = PerformPromiseRace(thread, iteratorRecord, promiseCapability, thisValue); 207 if (result->IsThrow()) { 208 thread->ClearException(); 209 if (!iteratorRecord->GetDone()) { 210 JSHandle<JSTaggedValue> value = 211 JSIterator::IteratorClose(thread, iterator, JSHandle<JSTaggedValue>::Cast(result)); 212 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 213 if (value.GetTaggedValue().IsCompletionRecord()) { 214 result = JSHandle<CompletionRecord>(value); 215 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 216 return result->GetValue(); 217 } 218 } 219 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 220 return result->GetValue(); 221 } 222 return result->GetValue(); 223} 224 225// 25.4.4.5 Promise.resolve ( x ) 226JSTaggedValue BuiltinsPromise::Resolve(EcmaRuntimeCallInfo *argv) 227{ 228 ASSERT(argv); 229 BUILTINS_API_TRACE(argv->GetThread(), Promise, Resolve); 230 JSThread *thread = argv->GetThread(); 231 [[maybe_unused]] EcmaHandleScope handleScope(thread); 232 233 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 234 // 1. Let C be the this value. 235 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 236 // 2. If Type(C) is not Object, throw a TypeError exception. 237 if (!thisValue->IsECMAObject()) { 238 THROW_TYPE_ERROR_AND_RETURN(thread, "Resolve: this value is not object", JSTaggedValue::Exception()); 239 } 240 // 3. If IsPromise(x) is true, 241 // a. Let xConstructor be Get(x, "constructor"). 242 // b. ReturnIfAbrupt(xConstructor). 243 // c. If SameValue(xConstructor, C) is true, return x. 244 JSHandle<JSTaggedValue> xValue = BuiltinsBase::GetCallArg(argv, 0); 245 if (xValue->IsJSPromise()) { 246 JSHandle<JSTaggedValue> ctorKey(globalConst->GetHandledConstructorString()); 247 JSHandle<JSTaggedValue> ctorValue = JSObject::GetProperty(thread, xValue, ctorKey).GetValue(); 248 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 249 if (JSTaggedValue::SameValue(ctorValue.GetTaggedValue(), thisValue.GetTaggedValue())) { 250 JSHandle<JSObject> value = JSHandle<JSObject>::Cast(xValue); 251 return value.GetTaggedValue(); 252 } 253 } 254 // 4. Let promiseCapability be NewPromiseCapability(C). 255 // 5. ReturnIfAbrupt(promiseCapability). 256 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, thisValue); 257 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 258 259 // 6. Let resolveResult be Call(promiseCapability.[[Resolve]], undefined, «x»). 260 // 7. ReturnIfAbrupt(resolveResult). 261 JSHandle<JSTaggedValue> resolve(thread, promiseCapability->GetResolve()); 262 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 263 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); 264 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 265 info->SetCallArg(xValue.GetTaggedValue()); 266 JSFunction::Call(info); 267 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 268 269 // 8. Return promiseCapability.[[Promise]]. 270 JSHandle<JSObject> promise(thread, promiseCapability->GetPromise()); 271 return promise.GetTaggedValue(); 272} 273 274// 25.4.4.4 Promise.reject ( r ) 275JSTaggedValue BuiltinsPromise::Reject(EcmaRuntimeCallInfo *argv) 276{ 277 ASSERT(argv); 278 BUILTINS_API_TRACE(argv->GetThread(), Promise, Reject); 279 JSThread *thread = argv->GetThread(); 280 [[maybe_unused]] EcmaHandleScope handleScope(thread); 281 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 282 283 // 1. Let C be the this value. 284 // 2. If Type(C) is not Object, throw a TypeError exception. 285 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 286 if (!thisValue->IsECMAObject()) { 287 THROW_TYPE_ERROR_AND_RETURN(thread, "Reject: this value is not object", JSTaggedValue::Exception()); 288 } 289 290 // 3. Let promiseCapability be NewPromiseCapability(C). 291 // 4. ReturnIfAbrupt(promiseCapability). 292 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, thisValue); 293 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 294 295 // 5. Let rejectResult be Call(promiseCapability.[[Reject]], undefined, «r»). 296 // 6. ReturnIfAbrupt(rejectResult). 297 JSHandle<JSTaggedValue> reason = GetCallArg(argv, 0); 298 JSHandle<JSTaggedValue> reject(thread, promiseCapability->GetReject()); 299 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 300 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); 301 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 302 info->SetCallArg(reason.GetTaggedValue()); 303 JSFunction::Call(info); 304 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 305 306 // 7. Return promiseCapability.[[Promise]]. 307 JSHandle<JSObject> promise(thread, promiseCapability->GetPromise()); 308 return promise.GetTaggedValue(); 309} 310 311// 25.4.4.6 get Promise [ @@species ] 312JSTaggedValue BuiltinsPromise::GetSpecies(EcmaRuntimeCallInfo *argv) 313{ 314 ASSERT(argv); 315 BUILTINS_API_TRACE(argv->GetThread(), Promise, GetSpecies); 316 return JSTaggedValue(GetThis(argv).GetTaggedValue()); 317} 318 319// 25.4.5.1 Promise.prototype.catch ( onRejected ) 320JSTaggedValue BuiltinsPromise::Catch(EcmaRuntimeCallInfo *argv) 321{ 322 // 1. Let promise be the this value. 323 // 2. Return Invoke(promise, "then", «undefined, onRejected»). 324 ASSERT(argv); 325 BUILTINS_API_TRACE(argv->GetThread(), Promise, Catch); 326 JSThread *thread = argv->GetThread(); 327 [[maybe_unused]] EcmaHandleScope handleScope(thread); 328 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 329 JSHandle<JSTaggedValue> promise = GetThis(argv); 330 JSHandle<JSTaggedValue> thenKey = globalConst->GetHandledPromiseThenString(); 331 JSHandle<JSTaggedValue> reject = GetCallArg(argv, 0); 332 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 333 EcmaRuntimeCallInfo *info = 334 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: «undefined, onRejected» 335 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 336 info->SetCallArg(undefined.GetTaggedValue(), reject.GetTaggedValue()); 337 return JSFunction::Invoke(info, thenKey); 338} 339 340// 25.4.5.3 Promise.prototype.then ( onFulfilled , onRejected ) 341JSTaggedValue BuiltinsPromise::Then(EcmaRuntimeCallInfo *argv) 342{ 343 ASSERT(argv); 344 BUILTINS_API_TRACE(argv->GetThread(), Promise, Then); 345 JSThread *thread = argv->GetThread(); 346 [[maybe_unused]] EcmaHandleScope handleScope(thread); 347 auto ecmaVm = thread->GetEcmaVM(); 348 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 349 350 // 1. Let promise be the this value. 351 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 352 // 2. If IsPromise(promise) is false, throw a TypeError exception. 353 if (!thisValue->IsJSPromise()) { 354 THROW_TYPE_ERROR_AND_RETURN(thread, "Then: thisValue is not promise!", JSTaggedValue::Exception()); 355 } 356 // 3. Let C be SpeciesConstructor(promise, %Promise%). 357 // 4. ReturnIfAbrupt(C). 358 JSHandle<JSObject> promise = JSHandle<JSObject>::Cast(thisValue); 359 JSHandle<JSTaggedValue> defaultFunc = JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()); 360 JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, promise, defaultFunc); 361 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 362 363 // 5. Let resultCapability be NewPromiseCapability(C). 364 // 6. ReturnIfAbrupt(resultCapability). 365 JSHandle<PromiseCapability> resultCapability = JSPromise::NewPromiseCapability(thread, constructor); 366 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 367 368 JSHandle<JSTaggedValue> onFulfilled = BuiltinsBase::GetCallArg(argv, 0); 369 JSHandle<JSTaggedValue> onRejected = BuiltinsBase::GetCallArg(argv, 1); 370 371 // 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability). 372 return PerformPromiseThen(thread, JSHandle<JSPromise>::Cast(promise), onFulfilled, onRejected, resultCapability); 373} 374 375JSTaggedValue BuiltinsPromise::PerformPromiseThen(JSThread *thread, const JSHandle<JSPromise> &promise, 376 const JSHandle<JSTaggedValue> &onFulfilled, 377 const JSHandle<JSTaggedValue> &onRejected, 378 const JSHandle<PromiseCapability> &capability) 379{ 380 auto ecmaVm = thread->GetEcmaVM(); 381 BUILTINS_API_TRACE(thread, Promise, PerformPromiseThen); 382 JSHandle<job::MicroJobQueue> job = thread->GetCurrentEcmaContext()->GetMicroJobQueue(); 383 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 384 ObjectFactory *factory = ecmaVm->GetFactory(); 385 JSMutableHandle<JSTaggedValue> fulfilled(thread, onFulfilled.GetTaggedValue()); 386 auto globalConst = thread->GlobalConstants(); 387 if (!fulfilled->IsCallable()) { 388 fulfilled.Update(globalConst->GetIdentityString()); 389 } 390 JSMutableHandle<JSTaggedValue> rejected(thread, onRejected.GetTaggedValue()); 391 if (!rejected->IsCallable()) { 392 rejected.Update(globalConst->GetThrowerString()); 393 } 394 JSHandle<PromiseReaction> fulfillReaction = factory->NewPromiseReaction(); 395 fulfillReaction->SetPromiseCapability(thread, capability.GetTaggedValue()); 396 fulfillReaction->SetHandler(thread, fulfilled.GetTaggedValue()); 397 398 JSHandle<PromiseReaction> rejectReaction = factory->NewPromiseReaction(); 399 rejectReaction->SetPromiseCapability(thread, capability.GetTaggedValue()); 400 rejectReaction->SetHandler(thread, rejected.GetTaggedValue()); 401 402 PromiseState state = promise->GetPromiseState(); 403 if (state == PromiseState::PENDING) { 404 JSHandle<TaggedQueue> fulfillReactions(thread, promise->GetPromiseFulfillReactions()); 405 TaggedQueue *newQueue = 406 TaggedQueue::Push(thread, fulfillReactions, JSHandle<JSTaggedValue>::Cast(fulfillReaction)); 407 promise->SetPromiseFulfillReactions(thread, JSTaggedValue(newQueue)); 408 409 JSHandle<TaggedQueue> rejectReactions(thread, promise->GetPromiseRejectReactions()); 410 newQueue = TaggedQueue::Push(thread, rejectReactions, JSHandle<JSTaggedValue>::Cast(rejectReaction)); 411 promise->SetPromiseRejectReactions(thread, JSTaggedValue(newQueue)); 412 } else if (state == PromiseState::FULFILLED) { 413 JSHandle<TaggedArray> argv = factory->NewTaggedArray(2); // 2: 2 means two args stored in array 414 argv->Set(thread, 0, fulfillReaction.GetTaggedValue()); 415 argv->Set(thread, 1, promise->GetPromiseResult()); 416 417 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob()); 418 job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); 419 } else if (state == PromiseState::REJECTED) { 420 JSHandle<TaggedArray> argv = factory->NewTaggedArray(2); // 2: 2 means two args stored in array 421 argv->Set(thread, 0, rejectReaction.GetTaggedValue()); 422 argv->Set(thread, 1, promise->GetPromiseResult()); 423 // When a handler is added to a rejected promise for the first time, it is called with its operation 424 // argument set to "handle". 425 if (!promise->GetPromiseIsHandled()) { 426 JSHandle<JSTaggedValue> reason(thread, JSTaggedValue::Null()); 427 thread->GetCurrentEcmaContext()->PromiseRejectionTracker(promise, reason, PromiseRejectionEvent::HANDLE); 428 } 429 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob()); 430 job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); 431 } 432 promise->SetPromiseIsHandled(true); 433 return capability->GetPromise(); 434} 435 436JSTaggedValue BuiltinsPromise::PerformPromiseAll(JSThread *thread, 437 const JSHandle<PromiseIteratorRecord> &itRecord, 438 const JSHandle<JSTaggedValue> &ctor, 439 const JSHandle<PromiseCapability> &capa) 440{ 441 auto ecmaVm = thread->GetEcmaVM(); 442 BUILTINS_API_TRACE(thread, Promise, PerformPromiseAll); 443 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 444 ObjectFactory *factory = ecmaVm->GetFactory(); 445 // 1. Assert: constructor is a constructor function. 446 ASSERT_PRINT(ctor->IsConstructor(), "PerformPromiseAll is not constructor"); 447 // 2. Assert: resultCapability is a PromiseCapability record. (not need) 448 // 3. Let values be a new empty List. 449 JSHandle<PromiseRecord> values = factory->NewPromiseRecord(); 450 JSHandle<TaggedArray> emptyArray = factory->EmptyArray(); 451 values->SetValue(thread, emptyArray); 452 // 4. Let remainingElementsCount be a new Record { [[value]]: 1 }. 453 JSHandle<PromiseRecord> remainCnt = factory->NewPromiseRecord(); 454 remainCnt->SetValue(thread, JSTaggedNumber(1)); 455 // 5. Let index be 0. 456 uint32_t index = 0; 457 // 6. Repeat 458 JSHandle<JSTaggedValue> itor(thread, itRecord->GetIterator()); 459 JSMutableHandle<JSTaggedValue> next(thread, globalConst->GetUndefined()); 460 while (true) { 461 [[maybe_unused]] EcmaHandleScope handleScope(thread); 462 // a. Let next be IteratorStep(iteratorRecord.[[iterator]]). 463 next.Update(JSIterator::IteratorStep(thread, itor).GetTaggedValue()); 464 // b. If next is an abrupt completion, set iteratorRecord.[[done]] to true. 465 if (thread->HasPendingException()) { 466 itRecord->SetDone(true); 467 next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); 468 } 469 // c. ReturnIfAbrupt(next). 470 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, next); 471 // d. If next is false, 472 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined()); 473 if (next->IsFalse()) { 474 // i. Set iteratorRecord.[[done]] to true. 475 itRecord->SetDone(true); 476 // ii. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1. 477 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue())); 478 // iii. If remainingElementsCount.[[value]] is 0, 479 if (remainCnt->GetValue().IsZero()) { 480 // 1. Let valuesArray be CreateArrayFromList(values). 481 JSHandle<JSArray> jsArrayValues = 482 JSArray::CreateArrayFromList(thread, JSHandle<TaggedArray>(thread, values->GetValue())); 483 // 2. Let resolveResult be Call(resultCapability.[[Resolve]], undefined, «valuesArray»). 484 JSHandle<JSTaggedValue> resCapaFunc(thread, capa->GetResolve()); 485 EcmaRuntimeCallInfo *info = 486 EcmaInterpreter::NewRuntimeCallInfo(thread, resCapaFunc, undefined, undefined, 1); 487 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, next); 488 info->SetCallArg(jsArrayValues.GetTaggedValue()); 489 JSTaggedValue resolveRes = JSFunction::Call(info); 490 // 3. ReturnIfAbrupt(resolveResult) 491 JSHandle<JSTaggedValue> resolveAbrupt(thread, resolveRes); 492 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, resolveAbrupt); 493 } 494 // iv. Return resultCapability.[[Promise]]. 495 JSHandle<CompletionRecord> resRecord = factory->NewCompletionRecord( 496 CompletionRecordType::NORMAL, JSHandle<JSTaggedValue>(thread, capa->GetPromise())); 497 return resRecord.GetTaggedValue(); 498 } 499 // e. Let nextValue be IteratorValue(next). 500 JSHandle<JSTaggedValue> nextVal = JSIterator::IteratorValue(thread, next); 501 // f. If nextValue is an abrupt completion, set iteratorRecord.[[done]] to true. 502 if (thread->HasPendingException()) { 503 itRecord->SetDone(true); 504 nextVal = JSHandle<JSTaggedValue>(thread, thread->GetException()); 505 } 506 507 // g. ReturnIfAbrupt(nextValue). 508 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, nextVal); 509 // h. Append undefined to values. 510 JSHandle<TaggedArray> valuesArray = 511 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, values->GetValue())); 512 valuesArray = TaggedArray::SetCapacity(thread, valuesArray, index + 1); 513 valuesArray->Set(thread, index, JSTaggedValue::Undefined()); 514 values->SetValue(thread, valuesArray); 515 // i. Let nextPromise be Invoke(constructor, "resolve", «nextValue»). 516 JSHandle<JSTaggedValue> resolveKey = globalConst->GetHandledPromiseResolveString(); 517 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, ctor, undefined, 1); 518 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, nextVal); 519 info->SetCallArg(nextVal.GetTaggedValue()); 520 JSTaggedValue taggedNextPromise = JSFunction::Invoke(info, resolveKey); 521 // j. ReturnIfAbrupt(nextPromise). 522 JSHandle<JSTaggedValue> nextPromise(thread, taggedNextPromise); 523 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, nextPromise); 524 // k. Let resolveElement be a new built-in function object as defined in Promise.all 525 // Resolve Element Functions. 526 JSHandle<JSPromiseAllResolveElementFunction> resoleveElement = factory->NewJSPromiseAllResolveElementFunction(); 527 // l. Set the [[AlreadyCalled]] internal slot of resolveElement to a new Record {[[value]]: false }. 528 JSHandle<PromiseRecord> falseRecord = factory->NewPromiseRecord(); 529 falseRecord->SetValue(thread, JSTaggedValue::False()); 530 resoleveElement->SetAlreadyCalled(thread, falseRecord); 531 // m. Set the [[Index]] internal slot of resolveElement to index. 532 resoleveElement->SetIndex(thread, JSTaggedValue(index)); 533 // n. Set the [[Values]] internal slot of resolveElement to values. 534 resoleveElement->SetValues(thread, values); 535 // o. Set the [[Capabilities]] internal slot of resolveElement to resultCapability. 536 resoleveElement->SetCapabilities(thread, capa); 537 // p. Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount. 538 resoleveElement->SetRemainingElements(thread, remainCnt); 539 // q. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1. 540 remainCnt->SetValue(thread, ++JSTaggedNumber(remainCnt->GetValue())); 541 // r. Let result be Invoke(nextPromise, "then", «resolveElement, resultCapability.[[Reject]]»). 542 JSHandle<JSTaggedValue> thenKey = globalConst->GetHandledPromiseThenString(); 543 EcmaRuntimeCallInfo *runtimeInfo = 544 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextPromise, 545 undefined, 2); // 2: «resolveElement, resultCapability.[[Reject]]» 546 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, nextPromise); 547 runtimeInfo->SetCallArg(resoleveElement.GetTaggedValue(), capa->GetReject()); 548 JSTaggedValue taggedResult = JSFunction::Invoke(runtimeInfo, thenKey); 549 JSHandle<JSTaggedValue> result(thread, taggedResult); 550 // s. ReturnIfAbrupt(result). 551 RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, result); 552 // t. Set index to index + 1. 553 ++index; 554 } 555} 556 557JSHandle<CompletionRecord> BuiltinsPromise::PerformPromiseRace(JSThread *thread, 558 const JSHandle<PromiseIteratorRecord> &iteratorRecord, 559 const JSHandle<PromiseCapability> &capability, 560 const JSHandle<JSTaggedValue> &constructor) 561{ 562 // 1. Repeat 563 // a. Let next be IteratorStep(iteratorRecord.[[iterator]]). 564 // b. If next is an abrupt completion, set iteratorRecord.[[done]] to true. 565 // c. ReturnIfAbrupt(next). 566 // d. If next is false, then 567 // i. Set iteratorRecord.[[done]] to true. 568 // ii. Return promiseCapability.[[Promise]]. 569 // e. Let nextValue be IteratorValue(next). 570 // f. If nextValue is an abrupt completion, set iteratorRecord.[[done]] to true. 571 // g. ReturnIfAbrupt(nextValue). 572 // h. Let nextPromise be Invoke(C, "resolve", «nextValue»). 573 // i. ReturnIfAbrupt(nextPromise). 574 // j. Let result be Invoke(nextPromise, "then", «promiseCapability.[[Resolve]], promiseCapability.[[Reject]]»). 575 // k. ReturnIfAbrupt(result). 576 BUILTINS_API_TRACE(thread, Promise, PerformPromiseRace); 577 auto ecmaVm = thread->GetEcmaVM(); 578 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 579 ObjectFactory *factory = ecmaVm->GetFactory(); 580 JSHandle<JSTaggedValue> iterator(thread, iteratorRecord->GetIterator()); 581 JSMutableHandle<JSTaggedValue> next(thread, globalConst->GetUndefined()); 582 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined()); 583 while (true) { 584 next.Update(JSIterator::IteratorStep(thread, iterator).GetTaggedValue()); 585 if (thread->HasPendingException()) { 586 iteratorRecord->SetDone(true); 587 next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); 588 } 589 RETURN_COMPLETION_IF_ABRUPT(thread, next); 590 if (next->IsFalse()) { 591 iteratorRecord->SetDone(true); 592 JSHandle<JSTaggedValue> promise(thread, capability->GetPromise()); 593 JSHandle<CompletionRecord> completionRecord = 594 factory->NewCompletionRecord(CompletionRecordType::NORMAL, promise); 595 return completionRecord; 596 } 597 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next); 598 if (thread->HasPendingException()) { 599 iteratorRecord->SetDone(true); 600 nextValue = JSPromise::IfThrowGetThrowValue(thread); 601 } 602 RETURN_COMPLETION_IF_ABRUPT(thread, nextValue); 603 JSHandle<JSTaggedValue> resolveStr = globalConst->GetHandledPromiseResolveString(); 604 605 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, constructor, undefined, 1); 606 RETURN_COMPLETION_IF_ABRUPT(thread, nextValue); 607 info->SetCallArg(nextValue.GetTaggedValue()); 608 JSTaggedValue result = JSFunction::Invoke(info, resolveStr); 609 JSHandle<JSTaggedValue> nextPromise(thread, result); 610 if (thread->HasPendingException()) { 611 nextPromise = JSPromise::IfThrowGetThrowValue(thread); 612 } 613 RETURN_COMPLETION_IF_ABRUPT(thread, nextPromise); 614 615 JSHandle<JSTaggedValue> thenStr = globalConst->GetHandledPromiseThenString(); 616 617 EcmaRuntimeCallInfo *runtimeInfo = 618 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextPromise, undefined, 2); // 2: two args 619 RETURN_COMPLETION_IF_ABRUPT(thread, nextPromise); 620 runtimeInfo->SetCallArg(capability->GetResolve(), capability->GetReject()); 621 result = JSFunction::Invoke(runtimeInfo, thenStr); 622 JSHandle<JSTaggedValue> handleResult(thread, result); 623 if (thread->HasPendingException()) { 624 handleResult = JSPromise::IfThrowGetThrowValue(thread); 625 } 626 RETURN_COMPLETION_IF_ABRUPT(thread, handleResult); 627 } 628} 629 630JSTaggedValue BuiltinsPromise::GetPromiseResolve(JSThread *thread, JSHandle<JSTaggedValue> promiseConstructor) 631{ 632 BUILTINS_API_TRACE(thread, Promise, GetPromiseResolve); 633 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 634 // 1. Let promiseResolve be ? Get(promiseConstructor, "resolve"). 635 JSHandle<JSTaggedValue> resolveKey = globalConst->GetHandledPromiseResolveString(); 636 JSHandle<JSTaggedValue> promiseResolve = JSObject::GetProperty(thread, promiseConstructor, resolveKey).GetValue(); 637 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 638 // 2. If IsCallable(promiseResolve) is false, throw a TypeError exception. 639 if (!promiseResolve->IsCallable()) { 640 THROW_TYPE_ERROR_AND_RETURN(thread, "promiseResolve is not callable", JSTaggedValue::Exception()); 641 } 642 // 3. Return promiseResolve. 643 return promiseResolve.GetTaggedValue(); 644} 645 646// 27.2.4.3 Promise.any ( iterable ) 647JSTaggedValue BuiltinsPromise::Any(EcmaRuntimeCallInfo *argv) 648{ 649 ASSERT(argv); 650 BUILTINS_API_TRACE(argv->GetThread(), Promise, Any); 651 JSThread *thread = argv->GetThread(); 652 auto ecmaVm = thread->GetEcmaVM(); 653 ObjectFactory *factory = ecmaVm->GetFactory(); 654 // 1. Let C be the this value. 655 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 656 // 2. Let promiseCapability be ? NewPromiseCapability(C). 657 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, thisValue); 658 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, promiseCapability.GetTaggedValue()); 659 // 3. Let promiseResolve be GetPromiseResolve(C). 660 JSHandle<JSTaggedValue> promiseResolve(thread, BuiltinsPromise::GetPromiseResolve(thread, thisValue)); 661 // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability). 662 if (thread->HasPendingException()) { 663 promiseResolve = JSPromise::IfThrowGetThrowValue(thread); 664 } 665 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, promiseResolve, promiseCapability); 666 // 5. Let iteratorRecord be GetIterator(iterable). 667 JSHandle<JSTaggedValue> iterable = GetCallArg(argv, 0); 668 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, iterable); 669 // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability). 670 if (thread->HasPendingException()) { 671 iterator = JSPromise::IfThrowGetThrowValue(thread); 672 } 673 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, iterator, promiseCapability); 674 // Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. 675 JSHandle<PromiseIteratorRecord> iteratorRecord = factory->NewPromiseIteratorRecord(iterator, false); 676 // 7. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability, promiseResolve). 677 JSHandle<CompletionRecord> result = PerformPromiseAny(thread, iteratorRecord, thisValue, 678 promiseCapability, promiseResolve); 679 // 8. If result is an abrupt completion, then 680 if (result->IsThrow()) { 681 thread->ClearException(); 682 // a. If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result). 683 // b. IfAbruptRejectPromise(result, promiseCapability). 684 if (!iteratorRecord->GetDone()) { 685 JSHandle<JSTaggedValue> resultHandle = JSHandle<JSTaggedValue>::Cast(result); 686 JSHandle<JSTaggedValue> closeVal = JSIterator::IteratorClose(thread, iterator, resultHandle); 687 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 688 if (closeVal.GetTaggedValue().IsCompletionRecord()) { 689 result = JSHandle<CompletionRecord>(closeVal); 690 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 691 return result->GetValue(); 692 } 693 } 694 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 695 return result->GetValue(); 696 } 697 // 9. Return ? result. 698 return result->GetValue(); 699} 700 701JSHandle<CompletionRecord> BuiltinsPromise::PerformPromiseAny(JSThread *thread, 702 const JSHandle<PromiseIteratorRecord> &iteratorRecord, 703 const JSHandle<JSTaggedValue> &constructor, 704 const JSHandle<PromiseCapability> &resultCapability, 705 const JSHandle<JSTaggedValue> &promiseResolve) 706{ 707 BUILTINS_API_TRACE(thread, Promise, PerformPromiseAny); 708 auto ecmaVm = thread->GetEcmaVM(); 709 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 710 ObjectFactory *factory = ecmaVm->GetFactory(); 711 // 1. Let errors be a new empty List. 712 JSHandle<PromiseRecord> errors = factory->NewPromiseRecord(); 713 JSHandle<TaggedArray> emptyArray = factory->EmptyArray(); 714 errors->SetValue(thread, emptyArray); 715 // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }. 716 JSHandle<PromiseRecord> remainCnt = factory->NewPromiseRecord(); 717 remainCnt->SetValue(thread, JSTaggedNumber(1)); 718 // 3. Let index be 0. 719 uint32_t index = 0; 720 // 4. Repeat, 721 JSHandle<JSTaggedValue> iter(thread, iteratorRecord->GetIterator()); 722 JSMutableHandle<JSTaggedValue> next(thread, globalConst->GetUndefined()); 723 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined()); 724 while (true) { 725 // a. Let next be IteratorStep(iteratorRecord). 726 next.Update(JSIterator::IteratorStep(thread, iter).GetTaggedValue()); 727 // b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true. 728 if (thread->HasPendingException()) { 729 iteratorRecord->SetDone(true); 730 next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); 731 } 732 // c. ReturnIfAbrupt(next). 733 RETURN_COMPLETION_IF_ABRUPT(thread, next); 734 // d. If next is false, then 735 if (next->IsFalse()) { 736 // i. Set iteratorRecord.[[Done]] to true. 737 iteratorRecord->SetDone(true); 738 // ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1. 739 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue())); 740 // iii. If remainingElementsCount.[[Value]] is 0, then 741 if (remainCnt->GetValue().IsZero()) { 742 // 1. Let error be a newly created AggregateError object. 743 JSHandle<JSObject> error = factory->NewJSAggregateError(); 744 // 2. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true, 745 // [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errors) }). 746 JSHandle<JSTaggedValue> errorsKey(thread, globalConst->GetErrorsString()); 747 JSHandle<TaggedArray> errorsArray = 748 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, errors->GetValue())); 749 JSHandle<JSTaggedValue> errorsValue(JSArray::CreateArrayFromList(thread, errorsArray)); 750 PropertyDescriptor msgDesc(thread, errorsValue, true, false, true); 751 JSHandle<JSTaggedValue> errorTagged = JSHandle<JSTaggedValue>::Cast(error); 752 JSTaggedValue::DefinePropertyOrThrow(thread, errorTagged, errorsKey, msgDesc); 753 RETURN_HANDLE_IF_ABRUPT_COMPLETION(CompletionRecord, thread); 754 // 3. Return ThrowCompletion(error). 755 JSHandle<JSTaggedValue> errorCompletion( 756 factory->NewCompletionRecord(CompletionRecordType::THROW, errorTagged)); 757 JSHandle<CompletionRecord> errorResult = JSHandle<CompletionRecord>::Cast(errorCompletion); 758 return errorResult; 759 } 760 // iv. Return resultCapability.[[Promise]]. 761 JSHandle<JSTaggedValue> resultCapabilityHandle(thread, resultCapability->GetPromise()); 762 JSHandle<CompletionRecord> resRecord = factory->NewCompletionRecord( 763 CompletionRecordType::NORMAL, resultCapabilityHandle); 764 return resRecord; 765 } 766 // e. Let nextValue be IteratorValue(next). 767 JSHandle<JSTaggedValue> nextVal = JSIterator::IteratorValue(thread, next); 768 // f. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true. 769 if (thread->HasPendingException()) { 770 iteratorRecord->SetDone(true); 771 nextVal = JSHandle<JSTaggedValue>(thread, thread->GetException()); 772 } 773 // g. ReturnIfAbrupt(nextValue). 774 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 775 // h. Append undefined to errors. 776 JSHandle<JSTaggedValue> errorsHandle(thread, errors->GetValue()); 777 JSHandle<TaggedArray> errorsArray = JSHandle<TaggedArray>::Cast(errorsHandle); 778 errorsArray = TaggedArray::SetCapacity(thread, errorsArray, index + 1); 779 errorsArray->Set(thread, index, JSTaggedValue::Undefined()); 780 errors->SetValue(thread, errorsArray); 781 // i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). 782 EcmaRuntimeCallInfo *taggedInfo = 783 EcmaInterpreter::NewRuntimeCallInfo(thread, promiseResolve, constructor, undefined, 1); 784 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 785 taggedInfo->SetCallArg(nextVal.GetTaggedValue()); 786 JSTaggedValue taggedNextPromise = JSFunction::Call(taggedInfo); 787 JSHandle<JSTaggedValue> nextPromise(thread, taggedNextPromise); 788 if (thread->HasPendingException()) { 789 JSHandle<JSTaggedValue> promiseResult = JSPromise::IfThrowGetThrowValue(thread); 790 JSHandle<CompletionRecord> completionRecord = 791 factory->NewCompletionRecord(CompletionRecordType::THROW, promiseResult); 792 return completionRecord; 793 } 794 // j. Let stepsRejected be the algorithm steps defined in Promise.any Reject Element Functions. 795 // k. Let lengthRejected be the number of non-optional parameters of the function definition in 796 // Promise.any Reject Element Functions. 797 // l. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", « [[AlreadyCalled]], 798 // [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »). 799 JSHandle<JSPromiseAnyRejectElementFunction> onRejected = factory->NewJSPromiseAnyRejectElementFunction(); 800 // m. Set onRejected.[[AlreadyCalled]] to false. 801 onRejected->SetAlreadyCalled(thread, JSTaggedValue::False()); 802 // n. Set onRejected.[[Index]] to index. 803 onRejected->SetIndex(index); 804 // o. Set onRejected.[[Errors]] to errors. 805 onRejected->SetErrors(thread, errors); 806 // p. Set onRejected.[[Capability]] to resultCapability. 807 onRejected->SetCapability(thread, resultCapability); 808 // q. Set onRejected.[[RemainingElements]] to remainingElementsCount. 809 onRejected->SetRemainingElements(thread, remainCnt); 810 // r. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1. 811 remainCnt->SetValue(thread, ++JSTaggedNumber(remainCnt->GetValue())); 812 // s. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »). 813 JSHandle<JSTaggedValue> thenKey = globalConst->GetHandledPromiseThenString(); 814 JSHandle<JSTaggedValue> resCapaFunc(thread, resultCapability->GetResolve()); 815 EcmaRuntimeCallInfo *invokeInfo = 816 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextPromise, undefined, 2); // 2: two args 817 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 818 invokeInfo->SetCallArg(resCapaFunc.GetTaggedValue(), onRejected.GetTaggedValue()); 819 JSFunction::Invoke(invokeInfo, thenKey); 820 if (thread->HasPendingException()) { 821 JSHandle<JSTaggedValue> taggedResult = JSPromise::IfThrowGetThrowValue(thread); 822 JSHandle<CompletionRecord> completionRecord = 823 factory->NewCompletionRecord(CompletionRecordType::THROW, taggedResult); 824 return completionRecord; 825 } 826 // t. Set index to index + 1. 827 ++index; 828 } 829} 830 831// 25.6.4.2 Promise.allSettled ( iterable ) 832JSTaggedValue BuiltinsPromise::AllSettled(EcmaRuntimeCallInfo *argv) 833{ 834 ASSERT(argv); 835 BUILTINS_API_TRACE(argv->GetThread(), Promise, AllSettled); 836 JSThread *thread = argv->GetThread(); 837 auto ecmaVm = thread->GetEcmaVM(); 838 ObjectFactory *factory = ecmaVm->GetFactory(); 839 // 1. Let C be the this value. 840 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 841 // 2. Let promiseCapability be ? NewPromiseCapability(C). 842 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, thisValue); 843 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, promiseCapability.GetTaggedValue()); 844 // 3. Let promiseResolve be Completion(GetPromiseResolve(C)). 845 JSHandle<JSTaggedValue> promiseResolve(thread, BuiltinsPromise::GetPromiseResolve(thread, thisValue)); 846 // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability). 847 if (thread->HasPendingException()) { 848 promiseResolve = JSPromise::IfThrowGetThrowValue(thread); 849 } 850 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, promiseResolve, promiseCapability); 851 // 5. Let iteratorRecord be Completion(GetIterator(iterable)). 852 JSHandle<JSTaggedValue> iterable = GetCallArg(argv, 0); 853 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, iterable); 854 // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability). 855 if (thread->HasPendingException()) { 856 iterator = JSPromise::IfThrowGetThrowValue(thread); 857 } 858 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, iterator, promiseCapability); 859 // Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. 860 JSHandle<PromiseIteratorRecord> iteratorRecord = factory->NewPromiseIteratorRecord(iterator, false); 861 // 7. Let result be PerformPromiseAllSettled(iteratorRecord, C, promiseCapability). 862 JSHandle<CompletionRecord> result = PerformPromiseAllSettled(thread, iteratorRecord, thisValue, 863 promiseCapability, promiseResolve); 864 // 8. If result is an abrupt completion, then 865 if (result->IsThrow()) { 866 thread->ClearException(); 867 // a. If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result). 868 if (!iteratorRecord->GetDone()) { 869 JSHandle<JSTaggedValue> resultHandle = JSHandle<JSTaggedValue>::Cast(result); 870 JSHandle<JSTaggedValue> closeVal = JSIterator::IteratorClose(thread, iterator, resultHandle); 871 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 872 if (closeVal.GetTaggedValue().IsCompletionRecord()) { 873 result = JSHandle<CompletionRecord>(closeVal); 874 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 875 return result->GetValue(); 876 } 877 } 878 // b. IfAbruptRejectPromise(result, promiseCapability). 879 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); 880 return result->GetValue(); 881 } 882 // 7.Return Completion(result). 883 return result->GetValue(); 884} 885 886JSHandle<CompletionRecord> BuiltinsPromise::PerformPromiseAllSettled(JSThread *thread, 887 const JSHandle<PromiseIteratorRecord> &iterRecord, 888 const JSHandle<JSTaggedValue> &constructor, 889 const JSHandle<PromiseCapability> &resultCapa, 890 const JSHandle<JSTaggedValue> &promiseResolve) 891{ 892 BUILTINS_API_TRACE(thread, Promise, PerformPromiseAllSettled); 893 auto ecmaVm = thread->GetEcmaVM(); 894 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 895 ObjectFactory *factory = ecmaVm->GetFactory(); 896 // 1. Let values be a new empty List. 897 JSHandle<PromiseRecord> values = factory->NewPromiseRecord(); 898 JSHandle<TaggedArray> emptyArray = factory->EmptyArray(); 899 values->SetValue(thread, emptyArray); 900 // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }. 901 JSHandle<PromiseRecord> remainCnt = factory->NewPromiseRecord(); 902 remainCnt->SetValue(thread, JSTaggedNumber(1)); 903 // 3. Let index be 0. 904 uint32_t index = 0; 905 // 4. Repeat, 906 JSHandle<JSTaggedValue> iter(thread, iterRecord->GetIterator()); 907 JSMutableHandle<JSTaggedValue> next(thread, globalConst->GetUndefined()); 908 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined()); 909 while (true) { 910 // a. Let next be IteratorStep(iteratorRecord). 911 next.Update(JSIterator::IteratorStep(thread, iter).GetTaggedValue()); 912 // b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true. 913 if (thread->HasPendingException()) { 914 iterRecord->SetDone(true); 915 next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); 916 } 917 // c. ReturnIfAbrupt(next). 918 RETURN_COMPLETION_IF_ABRUPT(thread, next); 919 // d. If next is false, then 920 if (next->IsFalse()) { 921 // i. Set iteratorRecord.[[Done]] to true. 922 iterRecord->SetDone(true); 923 // ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1. 924 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue())); 925 // iii. If remainingElementsCount.[[Value]] is 0, then 926 if (remainCnt->GetValue().IsZero()) { 927 // 1. Let valuesArray be ! CreateArrayFromList(values). 928 JSHandle<TaggedArray> taggedValues(thread, values->GetValue()); 929 JSHandle<JSArray> jsArrayValues = JSArray::CreateArrayFromList(thread, taggedValues); 930 // 2. Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »). 931 JSHandle<JSTaggedValue> resCapaFunc(thread, resultCapa->GetResolve()); 932 EcmaRuntimeCallInfo *info = 933 EcmaInterpreter::NewRuntimeCallInfo(thread, resCapaFunc, undefined, undefined, 1); 934 RETURN_COMPLETION_IF_ABRUPT(thread, next); 935 info->SetCallArg(jsArrayValues.GetTaggedValue()); 936 JSFunction::Call(info); 937 if (thread->HasPendingException()) { 938 JSHandle<JSTaggedValue> throwValue = JSPromise::IfThrowGetThrowValue(thread); 939 JSHandle<CompletionRecord> completionRecord = 940 factory->NewCompletionRecord(CompletionRecordType::THROW, throwValue); 941 return completionRecord; 942 } 943 } 944 // iv. Return resultCapability.[[Promise]]. 945 JSHandle<JSTaggedValue> resultCapabilityHandle(thread, resultCapa->GetPromise()); 946 JSHandle<CompletionRecord> resRecord = factory->NewCompletionRecord( 947 CompletionRecordType::NORMAL, resultCapabilityHandle); 948 return resRecord; 949 } 950 // e. Let nextValue be IteratorValue(next). 951 JSHandle<JSTaggedValue> nextVal = JSIterator::IteratorValue(thread, next); 952 // f. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true. 953 if (thread->HasPendingException()) { 954 iterRecord->SetDone(true); 955 nextVal = JSHandle<JSTaggedValue>(thread, thread->GetException()); 956 } 957 // g. ReturnIfAbrupt(nextValue). 958 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 959 // h. Append undefined to values. 960 JSHandle<JSTaggedValue> valuesHandle(thread, values->GetValue()); 961 JSHandle<TaggedArray> valuesArray = JSHandle<TaggedArray>::Cast(valuesHandle); 962 valuesArray = TaggedArray::SetCapacity(thread, valuesArray, index + 1); 963 valuesArray->Set(thread, index, JSTaggedValue::Undefined()); 964 values->SetValue(thread, valuesArray); 965 // i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). 966 EcmaRuntimeCallInfo *taggedInfo = 967 EcmaInterpreter::NewRuntimeCallInfo(thread, promiseResolve, constructor, undefined, 1); 968 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 969 taggedInfo->SetCallArg(nextVal.GetTaggedValue()); 970 JSTaggedValue taggedNextPromise = JSFunction::Call(taggedInfo); 971 JSHandle<JSTaggedValue> nextPromise(thread, taggedNextPromise); 972 if (thread->HasPendingException()) { 973 JSHandle<JSTaggedValue> promiseResult = JSPromise::IfThrowGetThrowValue(thread); 974 JSHandle<CompletionRecord> completionRecord = 975 factory->NewCompletionRecord(CompletionRecordType::THROW, promiseResult); 976 return completionRecord; 977 } 978 // j. Let stepsFulfilled be the algorithm steps defined in Promise.allSettled Resolve Element Functions. 979 // k. Let lengthFulfilled be the number of non-optional parameters of the function definition in 980 // Promise.allSettled Resolve Element Functions. 981 // l. Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, lengthFulfilled, "", 982 // « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »). 983 JSHandle<JSPromiseAllSettledElementFunction> onFulfilled = 984 factory->NewJSPromiseAllSettledResolveElementFunction(); 985 // m. Let alreadyCalled be the Record { [[Value]]: false }. 986 JSHandle<PromiseRecord> alreadyCalled = factory->NewPromiseRecord(); 987 alreadyCalled->SetValue(thread, JSTaggedValue::False()); 988 // n. Set onFulfilled.[[AlreadyCalled]] to alreadyCalled. 989 onFulfilled->SetAlreadyCalled(thread, alreadyCalled); 990 // o. Set onFulfilled.[[Index]] to index. 991 onFulfilled->SetIndex(index); 992 // p. Set onFulfilled.[[Values]] to values. 993 onFulfilled->SetValues(thread, values); 994 // q. Set onFulfilled.[[Capability]] to resultCapability. 995 onFulfilled->SetCapability(thread, resultCapa); 996 // r. Set onFulfilled.[[RemainingElements]] to remainingElementsCount. 997 onFulfilled->SetRemainingElements(thread, remainCnt); 998 // s. Let stepsRejected be the algorithm steps defined in Promise.allSettled Reject Element Functions. 999 // t. Let lengthRejected be the number of non-optional parameters of the function definition in 1000 // Promise.allSettled Reject Element Functions. 1001 // u. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", 1002 // « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »). 1003 JSHandle<JSPromiseAllSettledElementFunction> onRejected = 1004 factory->NewJSPromiseAllSettledRejectElementFunction(); 1005 // v. Set onRejected.[[AlreadyCalled]] to alreadyCalled. 1006 onRejected->SetAlreadyCalled(thread, alreadyCalled); 1007 // w. Set onRejected.[[Index]] to index. 1008 onRejected->SetIndex(index); 1009 // x. Set onRejected.[[Values]] to values. 1010 onRejected->SetValues(thread, values); 1011 // y. Set onRejected.[[Capability]] to resultCapability. 1012 onRejected->SetCapability(thread, resultCapa); 1013 // z. Set onRejected.[[RemainingElements]] to remainingElementsCount. 1014 onRejected->SetRemainingElements(thread, remainCnt); 1015 // aa. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1. 1016 remainCnt->SetValue(thread, ++JSTaggedNumber(remainCnt->GetValue())); 1017 // ab. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »). 1018 JSHandle<JSTaggedValue> thenKey = globalConst->GetHandledPromiseThenString(); 1019 EcmaRuntimeCallInfo *invokeInfo = 1020 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextPromise, undefined, 2); // 2: two args 1021 RETURN_COMPLETION_IF_ABRUPT(thread, nextVal); 1022 invokeInfo->SetCallArg(onFulfilled.GetTaggedValue(), onRejected.GetTaggedValue()); 1023 JSFunction::Invoke(invokeInfo, thenKey); 1024 if (thread->HasPendingException()) { 1025 JSHandle<JSTaggedValue> taggedResult = JSPromise::IfThrowGetThrowValue(thread); 1026 JSHandle<CompletionRecord> completionRecord = 1027 factory->NewCompletionRecord(CompletionRecordType::THROW, taggedResult); 1028 return completionRecord; 1029 } 1030 // ac. Set index to index + 1. 1031 ++index; 1032 } 1033} 1034 1035// 27.2.5.3 Promise.prototype.finally ( onFinally ) 1036JSTaggedValue BuiltinsPromise::Finally(EcmaRuntimeCallInfo *argv) 1037{ 1038 ASSERT(argv); 1039 BUILTINS_API_TRACE(argv->GetThread(), Promise, Finally); 1040 JSThread *thread = argv->GetThread(); 1041 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1042 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 1043 auto ecmaVm = thread->GetEcmaVM(); 1044 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 1045 ObjectFactory *factory = ecmaVm->GetFactory(); 1046 // 1. Let promise be the this value. 1047 // 2. If Type(promise) is not Object, throw a TypeError exception. 1048 JSHandle<JSTaggedValue> promise = GetThis(argv); 1049 if (!promise->IsECMAObject()) { 1050 THROW_TYPE_ERROR_AND_RETURN(thread, "Reject: this value is not object", JSTaggedValue::Exception()); 1051 } 1052 // 3. Let C be SpeciesConstructor(promise, %Promise%). 1053 // 4. Assert: IsConstructor(C) is true. 1054 JSHandle<JSTaggedValue> onFinally = BuiltinsBase::GetCallArg(argv, 0); 1055 JSHandle<JSObject> ctor = JSHandle<JSObject>::Cast(promise); 1056 JSHandle<JSTaggedValue> promiseFunc = JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()); 1057 JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, ctor, promiseFunc); 1058 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1059 ASSERT_PRINT(constructor->IsConstructor(), "constructor is not constructor"); 1060 JSHandle<JSTaggedValue> thenFinally; 1061 JSHandle<JSTaggedValue> catchFinally; 1062 // 5. If IsCallable(onFinally) is false, then 1063 if (!onFinally->IsCallable()) { 1064 // a. Let thenFinally be onFinally. 1065 // b. Let catchFinally be onFinally. 1066 thenFinally = onFinally; 1067 catchFinally = onFinally; 1068 // 6. Else, 1069 } else { 1070 // a. Let stepsThenFinally be the algorithm steps defined in Then Finally Functions. 1071 // b. Let thenFinally be CreateBuiltinFunction(stepsThenFinally, « [[Constructor]], [[OnFinally]] »). 1072 JSHandle<JSPromiseFinallyFunction> thenFinallyFun = 1073 factory->NewJSPromiseThenFinallyFunction(); 1074 // c. Set thenFinally.[[Constructor]] to C. 1075 // d. Set thenFinally.[[OnFinally]] to onFinally. 1076 thenFinallyFun->SetConstructor(thread, constructor); 1077 thenFinallyFun->SetOnFinally(thread, onFinally); 1078 thenFinally = JSHandle<JSTaggedValue>(thenFinallyFun); 1079 // e. Let stepsCatchFinally be the algorithm steps defined in Catch Finally Functions. 1080 // f. Let catchFinally be CreateBuiltinFunction(stepsCatchFinally, « [[Constructor]], [[OnFinally]] »). 1081 JSHandle<JSPromiseFinallyFunction> catchFinallyFun = 1082 factory->NewJSPromiseCatchFinallyFunction(); 1083 // g. Set catchFinally.[[Constructor]] to C. 1084 // h. Set catchFinally.[[OnFinally]] to onFinally. 1085 catchFinallyFun->SetConstructor(thread, constructor); 1086 catchFinallyFun->SetOnFinally(thread, onFinally); 1087 catchFinally = JSHandle<JSTaggedValue>(catchFinallyFun); 1088 } 1089 // 7. return invoke(promise, "then", <<thenFinally, catchFinally>>) 1090 JSHandle<JSTaggedValue> thenKey(globalConst->GetHandledPromiseThenString()); 1091 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined()); 1092 EcmaRuntimeCallInfo *invokeInfo = 1093 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args 1094 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1095 invokeInfo->SetCallArg(thenFinally.GetTaggedValue(), catchFinally.GetTaggedValue()); 1096 return JSFunction::Invoke(invokeInfo, thenKey); 1097} 1098} // namespace panda::ecmascript::builtins 1099