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