1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/builtins/builtins_promise_handler.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/interpreter/interpreter.h"
19 #include "ecmascript/jobs/micro_job_queue.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_async_function.h"
22 #include "ecmascript/js_promise.h"
23
24 namespace panda::ecmascript::builtins {
25 // es6 25.4.1.3.2 Promise Resolve Functions
Resolve(EcmaRuntimeCallInfo * argv)26 JSTaggedValue BuiltinsPromiseHandler::Resolve(EcmaRuntimeCallInfo *argv)
27 {
28 ASSERT(argv);
29 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, Resolve);
30 JSThread *thread = argv->GetThread();
31 [[maybe_unused]] EcmaHandleScope handleScope(thread);
32 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33 auto ecmaVm = thread->GetEcmaVM();
34 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
35
36 // 1. Assert: F has a [[Promise]] internal slot whose value is an Object.
37 JSHandle<JSPromiseReactionsFunction> resolve = JSHandle<JSPromiseReactionsFunction>::Cast(GetConstructor(argv));
38 ASSERT_PRINT(resolve->GetPromise().IsECMAObject(), "Resolve: promise must be js object");
39
40 // 2. Let promise be the value of F's [[Promise]] internal slot.
41 // 3. Let alreadyResolved be the value of F's [[AlreadyResolved]] internal slot.
42 // 4. If alreadyResolved.[[value]] is true, return undefined.
43 // 5. Set alreadyResolved.[[value]] to true.
44 JSHandle<JSPromise> resolvePromise(thread, resolve->GetPromise());
45 JSHandle<PromiseRecord> alreadyResolved(thread, resolve->GetAlreadyResolved());
46 if (alreadyResolved->GetValue().IsTrue()) {
47 return JSTaggedValue::Undefined();
48 }
49 alreadyResolved->SetValue(thread, JSTaggedValue::True());
50
51 // 6. If SameValue(resolution, promise) is true, then
52 // a. Let selfResolutionError be a newly created TypeError object.
53 // b. Return RejectPromise(promise, selfResolutionError).
54 JSHandle<JSTaggedValue> resolution = BuiltinsBase::GetCallArg(argv, 0);
55 if (JSTaggedValue::SameValue(resolution.GetTaggedValue(), resolvePromise.GetTaggedValue())) {
56 JSHandle<JSObject> resolutionError = factory->GetJSError(ErrorType::TYPE_ERROR,
57 "Resolve: The promise and resolution cannot be the same.", StackCheck::NO);
58 JSPromise::RejectPromise(thread, resolvePromise, JSHandle<JSTaggedValue>::Cast(resolutionError));
59 return JSTaggedValue::Undefined();
60 }
61 // 7. If Type(resolution) is not Object, then
62 // a. Return FulfillPromise(promise, resolution).
63 if (!resolution.GetTaggedValue().IsECMAObject()) {
64 JSPromise::FulfillPromise(thread, resolvePromise, resolution);
65 return JSTaggedValue::Undefined();
66 }
67 // 8. Let then be Get(resolution, "then").
68 // 9. If then is an abrupt completion, then
69 // a. Return RejectPromise(promise, then.[[value]]).
70 JSHandle<JSTaggedValue> thenKey(thread->GlobalConstants()->GetHandledPromiseThenString());
71 JSHandle<JSTaggedValue> thenValue = JSObject::GetProperty(thread, resolution, thenKey).GetValue();
72 if (thread->HasPendingException()) {
73 if (!thenValue->IsJSError()) {
74 thenValue = JSHandle<JSTaggedValue>(thread, thread->GetException());
75 }
76 thread->ClearException();
77 return JSPromise::RejectPromise(thread, resolvePromise, thenValue);
78 }
79 // 10. Let thenAction be then.[[value]].
80 // 11. If IsCallable(thenAction) is false, then
81 // a. Return FulfillPromise(promise, resolution).
82 if (!thenValue->IsCallable()) {
83 JSPromise::FulfillPromise(thread, resolvePromise, resolution);
84 return JSTaggedValue::Undefined();
85 }
86 // 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, resolution, thenAction»)
87 JSHandle<TaggedArray> arguments = factory->NewTaggedArray(3); // 3: 3 means three args stored in array
88 arguments->Set(thread, 0, resolvePromise);
89 arguments->Set(thread, 1, resolution);
90 arguments->Set(thread, 2, thenValue); // 2: 2 means index of array is 2
91
92 JSHandle<JSFunction> promiseResolveThenableJob(env->GetPromiseResolveThenableJob());
93 JSHandle<job::MicroJobQueue> job = thread->GetCurrentEcmaContext()->GetMicroJobQueue();
94 job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseResolveThenableJob, arguments);
95
96 // 13. Return undefined.
97 return JSTaggedValue::Undefined();
98 }
99
100 // es6 25.4.1.3.1 Promise Reject Functions
Reject(EcmaRuntimeCallInfo * argv)101 JSTaggedValue BuiltinsPromiseHandler::Reject(EcmaRuntimeCallInfo *argv)
102 {
103 ASSERT(argv);
104 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, Reject);
105 JSThread *thread = argv->GetThread();
106 [[maybe_unused]] EcmaHandleScope handleScope(thread);
107
108 // 1. Assert: F has a [[Promise]] internal slot whose value is an Object.
109 JSHandle<JSPromiseReactionsFunction> reject = JSHandle<JSPromiseReactionsFunction>::Cast(GetConstructor(argv));
110 ASSERT_PRINT(reject->GetPromise().IsECMAObject(), "Reject: promise must be js object");
111
112 // 2. Let promise be the value of F's [[Promise]] internal slot.
113 // 3. Let alreadyResolved be the value of F's [[AlreadyResolved]] internal slot.
114 // 4. If alreadyResolved.[[value]] is true, return undefined.
115 // 5. Set alreadyResolved.[[value]] to true.
116 JSHandle<JSPromise> rejectPromise(thread, reject->GetPromise());
117 JSHandle<PromiseRecord> alreadyResolved(thread, reject->GetAlreadyResolved());
118 if (alreadyResolved->GetValue().IsTrue()) {
119 return JSTaggedValue::Undefined();
120 }
121 alreadyResolved->SetValue(thread, JSTaggedValue::True());
122
123 // 6. Return RejectPromise(promise, reason).
124 JSHandle<JSTaggedValue> reason = GetCallArg(argv, 0);
125 JSHandle<JSTaggedValue> result(thread, JSPromise::RejectPromise(thread, rejectPromise, reason));
126 return result.GetTaggedValue();
127 }
128
129 // es6 25.4.1.5.1 GetCapabilitiesExecutor Functions
Executor(EcmaRuntimeCallInfo * argv)130 JSTaggedValue BuiltinsPromiseHandler::Executor(EcmaRuntimeCallInfo *argv)
131 {
132 ASSERT(argv);
133 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, Executor);
134 JSThread *thread = argv->GetThread();
135 [[maybe_unused]] EcmaHandleScope handleScope(thread);
136
137 // 1. Assert: F has a [[Capability]] internal slot whose value is a PromiseCapability Record.
138 JSHandle<JSPromiseExecutorFunction> executor = JSHandle<JSPromiseExecutorFunction>::Cast(GetConstructor(argv));
139 ASSERT_PRINT(executor->GetCapability().IsRecord(),
140 "Executor: F has a [[Capability]] internal slot whose value is a PromiseCapability Record.");
141
142 // 2. Let promiseCapability be the value of F's [[Capability]] internal slot.
143 // 3. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
144 JSHandle<PromiseCapability> promiseCapability(thread, executor->GetCapability());
145 if (!promiseCapability->GetResolve().IsUndefined()) {
146 THROW_TYPE_ERROR_AND_RETURN(thread, "Executor: resolve should be undefine!", JSTaggedValue::Undefined());
147 }
148 // 4. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
149 if (!promiseCapability->GetReject().IsUndefined()) {
150 THROW_TYPE_ERROR_AND_RETURN(thread, "Executor: reject should be undefine!", JSTaggedValue::Undefined());
151 }
152 // 5. Set promiseCapability.[[Resolve]] to resolve.
153 // 6. Set promiseCapability.[[Reject]] to reject.
154 JSHandle<JSTaggedValue> resolve = GetCallArg(argv, 0);
155 JSHandle<JSTaggedValue> reject = GetCallArg(argv, 1);
156 promiseCapability->SetResolve(thread, resolve);
157 promiseCapability->SetReject(thread, reject);
158 // 7. Return undefined.
159 return JSTaggedValue::Undefined();
160 }
161
162 // es6 25.4.4.1.2 Promise.all Resolve Element Functions
ResolveElementFunction(EcmaRuntimeCallInfo * argv)163 JSTaggedValue BuiltinsPromiseHandler::ResolveElementFunction(EcmaRuntimeCallInfo *argv)
164 {
165 ASSERT(argv);
166 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, ResolveElementFunction);
167 JSThread *thread = argv->GetThread();
168 [[maybe_unused]] EcmaHandleScope handleScope(thread);
169 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
170 JSHandle<JSPromiseAllResolveElementFunction> func =
171 JSHandle<JSPromiseAllResolveElementFunction>::Cast(GetConstructor(argv));
172 // 1. Let alreadyCalled be the value of F's [[AlreadyCalled]] internal slot.
173 JSHandle<PromiseRecord> alreadyCalled =
174 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, func->GetAlreadyCalled()));
175 // 2. If alreadyCalled.[[value]] is true, return undefined.
176 if (alreadyCalled->GetValue().IsTrue()) {
177 return JSTaggedValue::Undefined();
178 }
179 // 3. Set alreadyCalled.[[value]] to true.
180 alreadyCalled->SetValue(thread, JSTaggedValue::True());
181 // 4. Let index be the value of F's [[Index]] internal slot.
182 JSHandle<JSTaggedValue> index(thread, func->GetIndex());
183 // 5. Let values be the value of F's [[Values]] internal slot.
184 JSHandle<PromiseRecord> values = JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, func->GetValues()));
185 // 6. Let promiseCapability be the value of F's [[Capabilities]] internal slot.
186 JSHandle<PromiseCapability> capa =
187 JSHandle<PromiseCapability>::Cast(JSHandle<JSTaggedValue>(thread, func->GetCapabilities()));
188 // 7. Let remainingElementsCount be the value of F's [[RemainingElements]] internal slot.
189 JSHandle<PromiseRecord> remainCnt =
190 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, func->GetRemainingElements()));
191 // 8. Set values[index] to x.
192 JSHandle<TaggedArray> arrayValues =
193 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, values->GetValue()));
194 arrayValues->Set(thread, JSTaggedValue::ToUint32(thread, index), GetCallArg(argv, 0).GetTaggedValue());
195 // 9. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1.
196 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue()));
197 // 10. If remainingElementsCount.[[value]] is 0,
198 if (remainCnt->GetValue().IsZero()) {
199 // a. Let valuesArray be CreateArrayFromList(values).
200 JSHandle<JSArray> jsArrayValues = JSArray::CreateArrayFromList(thread, arrayValues);
201 // b. Return Call(promiseCapability.[[Resolve]], undefined, «valuesArray»).
202 JSHandle<JSTaggedValue> capaResolve(thread, capa->GetResolve());
203 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
204 EcmaRuntimeCallInfo *info =
205 EcmaInterpreter::NewRuntimeCallInfo(thread, capaResolve, undefined, undefined, 1);
206 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
207 info->SetCallArg(jsArrayValues.GetTaggedValue());
208 return JSFunction::Call(info);
209 }
210 // 11. Return undefined.
211 return JSTaggedValue::Undefined();
212 }
213
AsyncAwaitFulfilled(EcmaRuntimeCallInfo * argv)214 JSTaggedValue BuiltinsPromiseHandler::AsyncAwaitFulfilled(EcmaRuntimeCallInfo *argv)
215 {
216 ASSERT(argv);
217 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, AsyncAwaitFulfilled);
218 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
219
220 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
221 JSHandle<JSAsyncAwaitStatusFunction> func(GetConstructor(argv));
222 return JSAsyncAwaitStatusFunction::AsyncFunctionAwaitFulfilled(argv->GetThread(), func, value).GetTaggedValue();
223 }
224
AsyncAwaitRejected(EcmaRuntimeCallInfo * argv)225 JSTaggedValue BuiltinsPromiseHandler::AsyncAwaitRejected(EcmaRuntimeCallInfo *argv)
226 {
227 ASSERT(argv);
228 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, AsyncAwaitRejected);
229 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
230
231 JSHandle<JSTaggedValue> reason = GetCallArg(argv, 0);
232 JSHandle<JSAsyncAwaitStatusFunction> func(GetConstructor(argv));
233 return JSAsyncAwaitStatusFunction::AsyncFunctionAwaitRejected(argv->GetThread(), func, reason).GetTaggedValue();
234 }
235
valueThunkFunction(EcmaRuntimeCallInfo * argv)236 JSTaggedValue BuiltinsPromiseHandler::valueThunkFunction(EcmaRuntimeCallInfo *argv)
237 {
238 BUILTINS_API_TRACE(argv->GetThread(), PromiseHandler, valueThunkFunction);
239 JSHandle<JSPromiseValueThunkOrThrowerFunction> valueThunk =
240 JSHandle<JSPromiseValueThunkOrThrowerFunction>::Cast(GetConstructor(argv));
241 return valueThunk->GetResult();
242 }
243
throwerFunction(EcmaRuntimeCallInfo * argv)244 JSTaggedValue BuiltinsPromiseHandler::throwerFunction(EcmaRuntimeCallInfo *argv)
245 {
246 JSThread *thread = argv->GetThread();
247 BUILTINS_API_TRACE(thread, PromiseHandler, throwerFunction);
248 JSHandle<JSPromiseValueThunkOrThrowerFunction> thrower =
249 JSHandle<JSPromiseValueThunkOrThrowerFunction>::Cast(GetConstructor(argv));
250 JSTaggedValue undefined = thread->GlobalConstants()->GetUndefined();
251 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, thrower->GetResult(), undefined);
252 }
253
ThenFinally(EcmaRuntimeCallInfo * argv)254 JSTaggedValue BuiltinsPromiseHandler::ThenFinally(EcmaRuntimeCallInfo *argv)
255 {
256 // 1. Let F be the active function object.
257 JSThread *thread = argv->GetThread();
258 BUILTINS_API_TRACE(thread, PromiseHandler, ThenFinally);
259 auto ecmaVm = thread->GetEcmaVM();
260 ObjectFactory *factory = ecmaVm->GetFactory();
261 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
262 JSHandle<JSPromiseFinallyFunction> thenFinally(GetConstructor(argv));
263 JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, 0);
264 // 2. Let onFinally be F.[[OnFinally]].
265 // 3. Assert: IsCallable(onFinally) is true.
266 JSHandle<JSTaggedValue> onFinally(thread, thenFinally->GetOnFinally());
267 ASSERT_PRINT(onFinally->IsCallable(), "onFinally is not callable");
268 // 4. Let result be ? Call(onFinally, undefined).
269 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
270 EcmaRuntimeCallInfo *taggedInfo =
271 EcmaInterpreter::NewRuntimeCallInfo(thread, onFinally, undefined, undefined, 0);
272 JSTaggedValue result = JSFunction::Call(taggedInfo);
273 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
274 JSHandle<JSTaggedValue> resultHandle(thread, result);
275 // 5. Let C be F.[[Constructor]].
276 // 6. Assert: IsConstructor(C) is true.
277 JSHandle<JSTaggedValue> thenFinallyConstructor(thread, thenFinally->GetConstructor());
278 ASSERT_PRINT(thenFinallyConstructor->IsConstructor(), "thenFinallyConstructor is not constructor");
279 // 7. Let promise be ? PromiseResolve(C, result).
280 JSHandle<JSTaggedValue> promiseHandle =
281 BuiltinsPromiseHandler::PromiseResolve(thread, thenFinallyConstructor, resultHandle);
282 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
283 // 8. Let valueThunk be equivalent to a function that returns value.
284 JSHandle<JSPromiseValueThunkOrThrowerFunction> valueThunk =
285 factory->NewJSPromiseValueThunkFunction();
286 valueThunk->SetResult(thread, value);
287 JSHandle<JSTaggedValue> thenKey(globalConst->GetHandledPromiseThenString());
288 EcmaRuntimeCallInfo *invokeInfo =
289 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promiseHandle, undefined, 1);
290 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
291 invokeInfo->SetCallArg(valueThunk.GetTaggedValue());
292 // 9. Return ? Invoke(promise, "then", « valueThunk »).
293 return JSFunction::Invoke(invokeInfo, thenKey);
294 }
295
CatchFinally(EcmaRuntimeCallInfo * argv)296 JSTaggedValue BuiltinsPromiseHandler::CatchFinally(EcmaRuntimeCallInfo *argv)
297 {
298 // 1. Let F be the active function object.
299 JSThread *thread = argv->GetThread();
300 BUILTINS_API_TRACE(thread, PromiseHandler, CatchFinally);
301 auto ecmaVm = thread->GetEcmaVM();
302 ObjectFactory *factory = ecmaVm->GetFactory();
303 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
304 JSHandle<JSPromiseFinallyFunction> catchFinally(GetConstructor(argv));
305 // 2. Let onFinally be F.[[OnFinally]].
306 // 3. Assert: IsCallable(onFinally) is true.
307 JSHandle<JSTaggedValue> onFinally(thread, catchFinally->GetOnFinally());
308 ASSERT_PRINT(onFinally->IsCallable(), "thenOnFinally is not callable");
309 // 4. Let result be ? Call(onFinally, undefined).
310 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
311 EcmaRuntimeCallInfo *info =
312 EcmaInterpreter::NewRuntimeCallInfo(thread, onFinally, undefined, undefined, 0);
313 JSTaggedValue result = JSFunction::Call(info);
314 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
315 JSHandle<JSTaggedValue> resultHandle(thread, result);
316 // 5. Let C be F.[[Constructor]].
317 // 6. Assert: IsConstructor(C) is true.
318 JSHandle<JSTaggedValue> catchFinallyConstructor(thread, catchFinally->GetConstructor());
319 ASSERT_PRINT(catchFinallyConstructor->IsConstructor(), "catchFinallyConstructor is not constructor");
320 // 7. Let promise be ? PromiseResolve(C, result).
321 JSHandle<JSTaggedValue> promiseHandle =
322 BuiltinsPromiseHandler::PromiseResolve(thread, catchFinallyConstructor, resultHandle);
323 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
324 // 8. Let thrower be equivalent to a function that throws reason.
325 JSHandle<JSTaggedValue> reason = BuiltinsBase::GetCallArg(argv, 0);
326 JSHandle<JSTaggedValue> thenKey(globalConst->GetHandledPromiseThenString());
327 JSHandle<JSPromiseValueThunkOrThrowerFunction> thrower =
328 factory->NewJSPromiseThrowerFunction();
329 thrower->SetResult(thread, reason);
330 EcmaRuntimeCallInfo *invokeInfo =
331 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promiseHandle, undefined, 1);
332 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
333 invokeInfo->SetCallArg(thrower.GetTaggedValue());
334 // 9. Return ? Invoke(promise, "then", « thrower »).
335 return JSFunction::Invoke(invokeInfo, thenKey);
336 }
337
PromiseResolve(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & xValue)338 JSHandle<JSTaggedValue> BuiltinsPromiseHandler::PromiseResolve(JSThread *thread,
339 const JSHandle<JSTaggedValue> &constructor,
340 const JSHandle<JSTaggedValue> &xValue)
341 {
342 BUILTINS_API_TRACE(thread, PromiseHandler, PromiseResolve);
343 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
344 // 1. Assert: Type(C) is Object.
345 ASSERT_PRINT(constructor->IsECMAObject(), "PromiseResolve : is not callable");
346 // 2. If IsPromise(x) is true, then
347 if (xValue->IsJSPromise()) {
348 // a. Let xConstructor be ? Get(x, "constructor").
349 JSHandle<JSTaggedValue> ctorKey(globalConst->GetHandledConstructorString());
350 JSHandle<JSTaggedValue> ctorValue = JSObject::GetProperty(thread, xValue, ctorKey).GetValue();
351 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ctorValue);
352 // b. If SameValue(xConstructor, C) is true, return x.
353 if (JSTaggedValue::SameValue(ctorValue, constructor)) {
354 return xValue;
355 }
356 }
357 // 3. Let promiseCapability be ? NewPromiseCapability(C).
358 // 4. ReturnIfAbrupt(promiseCapability)
359 JSHandle<PromiseCapability> promiseCapability = JSPromise::NewPromiseCapability(thread, constructor);
360 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
361 JSHandle<JSTaggedValue> promiseCapaHandle = JSHandle<JSTaggedValue>::Cast(promiseCapability);
362 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, promiseCapaHandle);
363 // 6. Let resolveResult be Call(promiseCapability.[[Resolve]], undefined, «x»).
364 // 7. ReturnIfAbrupt(resolveResult).
365 JSHandle<JSTaggedValue> resolve(thread, promiseCapability->GetResolve());
366 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined());
367 EcmaRuntimeCallInfo *info =
368 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1);
369 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, promiseCapaHandle);
370 info->SetCallArg(xValue.GetTaggedValue());
371 JSTaggedValue resolveResult = JSFunction::Call(info);
372 JSHandle<JSTaggedValue> resolveResultHandle(thread, resolveResult);
373 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, resolveResultHandle);
374 // 8. Return promiseCapability.[[Promise]].
375 JSHandle<JSTaggedValue> promise(thread, promiseCapability->GetPromise());
376 return promise;
377 }
378
AllSettledResolveElementFunction(EcmaRuntimeCallInfo * argv)379 JSTaggedValue BuiltinsPromiseHandler::AllSettledResolveElementFunction(EcmaRuntimeCallInfo *argv)
380 {
381 // 1. Let F be the active function object.
382 JSThread *thread = argv->GetThread();
383 BUILTINS_API_TRACE(thread, PromiseHandler, AllSettledResolveElementFunction);
384 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
385 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
386 JSHandle<JSPromiseAllSettledElementFunction> resolveElement =
387 JSHandle<JSPromiseAllSettledElementFunction>::Cast((GetConstructor(argv)));
388 // 2. Let alreadyCalled be F.[[AlreadyCalled]].
389 JSHandle<PromiseRecord> alreadyCalled =
390 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, resolveElement->GetAlreadyCalled()));
391 // 3. If alreadyCalled.[[Value]] is true, return undefined.
392 if (alreadyCalled->GetValue().IsTrue()) {
393 return JSTaggedValue::Undefined();
394 }
395 // 4. Set alreadyCalled.[[Value]] to true.
396 alreadyCalled->SetValue(thread, JSTaggedValue::True());
397 // 5. Let index be F.[[Index]].
398 uint32_t index = resolveElement->GetIndex();
399 // 6. Let values be F.[[Values]].
400 JSHandle<PromiseRecord> values =
401 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, resolveElement->GetValues()));
402 // 7. Let promiseCapability be F.[[Capability]].
403 JSHandle<PromiseCapability> capa =
404 JSHandle<PromiseCapability>::Cast(JSHandle<JSTaggedValue>(thread, resolveElement->GetCapability()));
405 // 8. Let remainingElementsCount be F.[[RemainingElements]].
406 JSHandle<PromiseRecord> remainCnt =
407 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, resolveElement->GetRemainingElements()));
408 // 9. Let obj be ! OrdinaryObjectCreate(%Object.prototype%).
409 JSHandle<JSTaggedValue> proto = env->GetObjectFunctionPrototype();
410 JSHandle<JSObject> obj = thread->GetEcmaVM()->GetFactory()->OrdinaryNewJSObjectCreate(proto);
411 // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled").
412 JSHandle<JSTaggedValue> statusKey = globalConst->GetHandledPromiseStatusString();
413 JSHandle<JSTaggedValue> fulfilledKey = globalConst->GetHandledPromiseFulfilledString();
414 JSObject::CreateDataPropertyOrThrow(thread, obj, statusKey, fulfilledKey);
415 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
416 // 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x).
417 JSHandle<JSTaggedValue> valueKey = globalConst->GetHandledValueString();
418 JSHandle<JSTaggedValue> xValue = GetCallArg(argv, 0);
419 JSObject::CreateDataPropertyOrThrow(thread, obj, valueKey, xValue);
420 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
421 // 12. Set values[index] to obj.
422 JSHandle<TaggedArray> arrayValues =
423 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, values->GetValue()));
424 arrayValues->Set(thread, index, obj.GetTaggedValue());
425 // 13. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
426 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue()));
427 // 14. If remainingElementsCount.[[Value]] is 0, then
428 if (remainCnt->GetValue().IsZero()) {
429 // a. Let valuesArray be CreateArrayFromList(values).
430 JSHandle<JSArray> jsArrayValues = JSArray::CreateArrayFromList(thread, arrayValues);
431 // b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »).
432 JSHandle<JSTaggedValue> capaResolve(thread, capa->GetResolve());
433 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined());
434 EcmaRuntimeCallInfo *info =
435 EcmaInterpreter::NewRuntimeCallInfo(thread, capaResolve, undefined, undefined, 1);
436 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
437 info->SetCallArg(jsArrayValues.GetTaggedValue());
438 return JSFunction::Call(info);
439 }
440 // 15. Return undefined.
441 return JSTaggedValue::Undefined();
442 }
443
AllSettledRejectElementFunction(EcmaRuntimeCallInfo * argv)444 JSTaggedValue BuiltinsPromiseHandler::AllSettledRejectElementFunction(EcmaRuntimeCallInfo *argv)
445 {
446 // 1. Let F be the active function object.
447 JSThread *thread = argv->GetThread();
448 BUILTINS_API_TRACE(thread, PromiseHandler, AllSettledRejectElementFunction);
449 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
450 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
451 JSHandle<JSPromiseAllSettledElementFunction> rejectElement =
452 JSHandle<JSPromiseAllSettledElementFunction>::Cast((GetConstructor(argv)));
453 // 2. Let alreadyCalled be F.[[AlreadyCalled]].
454 JSHandle<PromiseRecord> alreadyCalled =
455 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetAlreadyCalled()));
456 // 3. If alreadyCalled.[[Value]] is true, return undefined.
457 if (alreadyCalled->GetValue().IsTrue()) {
458 return JSTaggedValue::Undefined();
459 }
460 // 4. Set alreadyCalled.[[Value]] to true.
461 alreadyCalled->SetValue(thread, JSTaggedValue::True());
462 // 5. Let index be F.[[Index]].
463 uint32_t index = rejectElement->GetIndex();
464 // 6. Let values be F.[[Values]].
465 JSHandle<PromiseRecord> values =
466 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetValues()));
467 // 7. Let promiseCapability be F.[[Capability]].
468 JSHandle<PromiseCapability> capa =
469 JSHandle<PromiseCapability>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetCapability()));
470 // 8. Let remainingElementsCount be F.[[RemainingElements]].
471 JSHandle<PromiseRecord> remainCnt =
472 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetRemainingElements()));
473 // 9. Let obj be ! OrdinaryObjectCreate(%Object.prototype%).
474 JSHandle<JSTaggedValue> proto = env->GetObjectFunctionPrototype();
475 JSHandle<JSObject> obj = thread->GetEcmaVM()->GetFactory()->OrdinaryNewJSObjectCreate(proto);
476 // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected").
477 JSHandle<JSTaggedValue> statusKey = globalConst->GetHandledPromiseStatusString();
478 JSHandle<JSTaggedValue> rejectedKey = globalConst->GetHandledPromiseRejectedString();
479 JSObject::CreateDataPropertyOrThrow(thread, obj, statusKey, rejectedKey);
480 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
481 // 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x).
482 JSHandle<JSTaggedValue> xReason = GetCallArg(argv, 0);
483 JSHandle<JSTaggedValue> reasonKey = globalConst->GetHandledPromiseReasonString();
484 JSObject::CreateDataPropertyOrThrow(thread, obj, reasonKey, xReason);
485 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
486 // 12. Set values[index] to obj.
487 JSHandle<TaggedArray> arrayValues =
488 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, values->GetValue()));
489 arrayValues->Set(thread, index, obj.GetTaggedValue());
490 // 13. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
491 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue()));
492 // 14. If remainingElementsCount.[[Value]] is 0, then
493 if (remainCnt->GetValue().IsZero()) {
494 // a. Let valuesArray be CreateArrayFromList(values).
495 JSHandle<JSArray> jsArrayValues = JSArray::CreateArrayFromList(thread, arrayValues);
496 // b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »).
497 JSHandle<JSTaggedValue> capaResolve(thread, capa->GetResolve());
498 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined());
499 EcmaRuntimeCallInfo *info =
500 EcmaInterpreter::NewRuntimeCallInfo(thread, capaResolve, undefined, undefined, 1);
501 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
502 info->SetCallArg(jsArrayValues.GetTaggedValue());
503 return JSFunction::Call(info);
504 }
505 // 15. Return undefined.
506 return JSTaggedValue::Undefined();
507 }
508
AnyRejectElementFunction(EcmaRuntimeCallInfo * argv)509 JSTaggedValue BuiltinsPromiseHandler::AnyRejectElementFunction(EcmaRuntimeCallInfo *argv)
510 {
511 // 1. Let F be the active function object.
512 JSThread *thread = argv->GetThread();
513 BUILTINS_API_TRACE(thread, PromiseHandler, AnyRejectElementFunction);
514 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
515 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
516 JSHandle<JSPromiseAnyRejectElementFunction> rejectElement =
517 JSHandle<JSPromiseAnyRejectElementFunction>::Cast((GetConstructor(argv)));
518 // 2. If F.[[AlreadyCalled]] is true, return undefined.
519 JSTaggedValue alreadyCalled = rejectElement->GetAlreadyCalled();
520 if (alreadyCalled.IsTrue()) {
521 return JSTaggedValue::Undefined();
522 }
523 // 3. Set F.[[AlreadyCalled]] to true.
524 rejectElement->SetAlreadyCalled(thread, JSTaggedValue::True());
525 // 4. Let index be F.[[Index]].
526 uint32_t index = rejectElement->GetIndex();
527 // 5. Let errors be F.[[Errors]].
528 JSHandle<PromiseRecord> errors =
529 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetErrors()));
530 // 6. Let promiseCapability be F.[[Capability]].
531 JSHandle<PromiseCapability> capa =
532 JSHandle<PromiseCapability>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetCapability()));
533 // 7. Let remainingElementsCount be F.[[RemainingElements]].
534 JSHandle<PromiseRecord> remainCnt =
535 JSHandle<PromiseRecord>::Cast(JSHandle<JSTaggedValue>(thread, rejectElement->GetRemainingElements()));
536 // 8. Set errors[index] to x.
537 JSHandle<JSTaggedValue> xValue = GetCallArg(argv, 0);
538 JSHandle<TaggedArray> errorsArray =
539 JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread, errors->GetValue()));
540 errorsArray->Set(thread, index, xValue.GetTaggedValue());
541 // 9. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
542 remainCnt->SetValue(thread, --JSTaggedNumber(remainCnt->GetValue()));
543 // 10. If remainingElementsCount.[[Value]] is 0, then
544 if (remainCnt->GetValue().IsZero()) {
545 // a. Let error be a newly created AggregateError object.
546 JSHandle<JSObject> error = factory->NewJSAggregateError();
547 // b. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true,
548 // [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errors) }).
549 JSHandle<JSTaggedValue> errorsKey(thread, globalConst->GetErrorsString());
550 JSHandle<JSTaggedValue> errorsValue(JSArray::CreateArrayFromList(thread, errorsArray));
551 PropertyDescriptor msgDesc(thread, errorsValue, true, false, true);
552 JSHandle<JSTaggedValue> errorTagged = JSHandle<JSTaggedValue>::Cast(error);
553 JSTaggedValue::DefinePropertyOrThrow(thread, errorTagged, errorsKey, msgDesc);
554 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
555 // c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »).
556 JSHandle<JSTaggedValue> capaReject(thread, capa->GetReject());
557 JSHandle<JSTaggedValue> undefined(globalConst->GetHandledUndefined());
558 EcmaRuntimeCallInfo *info =
559 EcmaInterpreter::NewRuntimeCallInfo(thread, capaReject, undefined, undefined, 1);
560 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
561 info->SetCallArg(error.GetTaggedValue());
562 return JSFunction::Call(info);
563 }
564 // 11. Return undefined.
565 return JSTaggedValue::Undefined();
566 }
567 } // namespace panda::ecmascript::builtins
568