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