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 24namespace panda::ecmascript::builtins { 25// es6 25.4.1.3.2 Promise Resolve Functions 26JSTaggedValue 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 101JSTaggedValue 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 130JSTaggedValue 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 163JSTaggedValue 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 214JSTaggedValue 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 225JSTaggedValue 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 236JSTaggedValue 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 244JSTaggedValue 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 254JSTaggedValue 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 296JSTaggedValue 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 338JSHandle<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 379JSTaggedValue 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 444JSTaggedValue 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 509JSTaggedValue 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