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