1// Copyright 2019 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include 'src/builtins/builtins-promise.h' 6#include 'src/builtins/builtins-promise-gen.h' 7 8namespace runtime { 9extern transitioning runtime 10RejectPromise(implicit context: Context)(JSPromise, JSAny, Boolean): JSAny; 11 12extern transitioning runtime 13PromiseRevokeReject(implicit context: Context)(JSPromise): JSAny; 14 15extern transitioning runtime 16PromiseRejectAfterResolved(implicit context: Context)(JSPromise, JSAny): JSAny; 17 18extern transitioning runtime 19PromiseResolveAfterResolved(implicit context: Context)(JSPromise, JSAny): JSAny; 20 21extern transitioning runtime 22PromiseRejectEventFromStack(implicit context: Context)(JSPromise, JSAny): JSAny; 23} 24 25// https://tc39.es/ecma262/#sec-promise-abstract-operations 26namespace promise { 27 28extern macro PromiseForwardingHandlerSymbolConstant(): Symbol; 29const kPromiseForwardingHandlerSymbol: Symbol = 30 PromiseForwardingHandlerSymbolConstant(); 31extern macro PromiseHandledBySymbolConstant(): Symbol; 32const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant(); 33extern macro ResolveStringConstant(): String; 34const kResolveString: String = ResolveStringConstant(); 35extern macro IsPromiseResolveProtectorCellInvalid(): bool; 36 37extern macro AllocateFunctionWithMapAndContext( 38 Map, SharedFunctionInfo, FunctionContext): JSFunction; 39 40extern macro PromiseReactionMapConstant(): Map; 41extern macro PromiseFulfillReactionJobTaskMapConstant(): Map; 42extern macro PromiseRejectReactionJobTaskMapConstant(): Map; 43extern transitioning builtin 44ResolvePromise(Context, JSPromise, JSAny): JSAny; 45 46extern transitioning builtin 47EnqueueMicrotask(Context, Microtask): Undefined; 48 49macro 50ExtractHandlerContextInternal(implicit context: Context)( 51 handler: Callable|Undefined): Context labels NotFound { 52 let iter: JSAny = handler; 53 while (true) { 54 typeswitch (iter) { 55 case (b: JSBoundFunction): { 56 iter = b.bound_target_function; 57 } 58 case (p: JSProxy): { 59 iter = p.target; 60 } 61 case (f: JSFunction): { 62 return f.context; 63 } 64 case (JSAny): { 65 break; 66 } 67 } 68 } 69 goto NotFound; 70} 71 72macro 73ExtractHandlerContext(implicit context: Context)(handler: Callable| 74 Undefined): Context { 75 try { 76 return ExtractHandlerContextInternal(handler) otherwise NotFound; 77 } label NotFound deferred { 78 return context; 79 } 80} 81 82macro 83ExtractHandlerContext(implicit context: Context)( 84 primary: Callable|Undefined, secondary: Callable|Undefined): Context { 85 try { 86 return ExtractHandlerContextInternal(primary) otherwise NotFound; 87 } label NotFound deferred { 88 return ExtractHandlerContextInternal(secondary) otherwise Default; 89 } label Default deferred { 90 return context; 91 } 92} 93 94transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( 95 promiseReaction: PromiseReaction, argument: JSAny, 96 reactionType: constexpr PromiseReactionType): void { 97 let primaryHandler: Callable|Undefined; 98 let secondaryHandler: Callable|Undefined; 99 if constexpr (reactionType == kPromiseReactionFulfill) { 100 primaryHandler = promiseReaction.fulfill_handler; 101 secondaryHandler = promiseReaction.reject_handler; 102 } else { 103 static_assert(reactionType == kPromiseReactionReject); 104 primaryHandler = promiseReaction.reject_handler; 105 secondaryHandler = promiseReaction.fulfill_handler; 106 } 107 108 // According to HTML, we use the context of the appropriate handler as the 109 // context of the microtask. See step 3 of HTML's EnqueueJob: 110 // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments) 111 const handlerContext: Context = 112 ExtractHandlerContext(primaryHandler, secondaryHandler); 113 114 // Morph {current} from a PromiseReaction into a PromiseReactionJobTask 115 // and schedule that on the microtask queue. We try to minimize the number 116 // of stores here to avoid write barrier overhead. 117 static_assert( 118 kPromiseReactionSize == 119 kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks); 120 if constexpr (reactionType == kPromiseReactionFulfill) { 121 *UnsafeConstCast(&promiseReaction.map) = 122 PromiseFulfillReactionJobTaskMapConstant(); 123 const promiseReactionJobTask = 124 UnsafeCast<PromiseFulfillReactionJobTask>(promiseReaction); 125 promiseReactionJobTask.argument = argument; 126 promiseReactionJobTask.context = handlerContext; 127 EnqueueMicrotask(handlerContext, promiseReactionJobTask); 128 static_assert( 129 kPromiseReactionFulfillHandlerOffset == 130 kPromiseReactionJobTaskHandlerOffset); 131 static_assert( 132 kPromiseReactionPromiseOrCapabilityOffset == 133 kPromiseReactionJobTaskPromiseOrCapabilityOffset); 134 } else { 135 static_assert(reactionType == kPromiseReactionReject); 136 *UnsafeConstCast(&promiseReaction.map) = 137 PromiseRejectReactionJobTaskMapConstant(); 138 const promiseReactionJobTask = 139 UnsafeCast<PromiseRejectReactionJobTask>(promiseReaction); 140 promiseReactionJobTask.argument = argument; 141 promiseReactionJobTask.context = handlerContext; 142 promiseReactionJobTask.handler = primaryHandler; 143 EnqueueMicrotask(handlerContext, promiseReactionJobTask); 144 static_assert( 145 kPromiseReactionPromiseOrCapabilityOffset == 146 kPromiseReactionJobTaskPromiseOrCapabilityOffset); 147 } 148} 149 150// https://tc39.es/ecma262/#sec-triggerpromisereactions 151transitioning macro TriggerPromiseReactions(implicit context: Context)( 152 reactions: Zero|PromiseReaction, argument: JSAny, 153 reactionType: constexpr PromiseReactionType): void { 154 // We need to reverse the {reactions} here, since we record them on the 155 // JSPromise in the reverse order. 156 let current = reactions; 157 let reversed: Zero|PromiseReaction = kZero; 158 159 // As an additional safety net against misuse of the V8 Extras API, we 160 // sanity check the {reactions} to make sure that they are actually 161 // PromiseReaction instances and not actual JavaScript values (which 162 // would indicate that we're rejecting or resolving an already settled 163 // promise), see https://crbug.com/931640 for details on this. 164 while (true) { 165 typeswitch (current) { 166 case (Zero): { 167 break; 168 } 169 case (currentReaction: PromiseReaction): { 170 current = currentReaction.next; 171 currentReaction.next = reversed; 172 reversed = currentReaction; 173 } 174 } 175 } 176 // Morph the {reactions} into PromiseReactionJobTasks and push them 177 // onto the microtask queue. 178 current = reversed; 179 while (true) { 180 typeswitch (current) { 181 case (Zero): { 182 break; 183 } 184 case (currentReaction: PromiseReaction): { 185 current = currentReaction.next; 186 MorphAndEnqueuePromiseReaction(currentReaction, argument, reactionType); 187 } 188 } 189 } 190} 191 192// https://tc39.es/ecma262/#sec-fulfillpromise 193transitioning builtin 194FulfillPromise(implicit context: Context)( 195 promise: JSPromise, value: JSAny): Undefined { 196 // Assert: The value of promise.[[PromiseState]] is "pending". 197 dcheck(promise.Status() == PromiseState::kPending); 198 199 RunContextPromiseHookResolve(promise); 200 201 // 2. Let reactions be promise.[[PromiseFulfillReactions]]. 202 const reactions = 203 UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); 204 205 // 3. Set promise.[[PromiseResult]] to value. 206 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 207 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 208 promise.reactions_or_result = value; 209 210 // 6. Set promise.[[PromiseState]] to "fulfilled". 211 promise.SetStatus(PromiseState::kFulfilled); 212 213 // 7. Return TriggerPromiseReactions(reactions, value). 214 TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill); 215 return Undefined; 216} 217 218extern macro PromiseBuiltinsAssembler:: 219 IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool; 220 221extern macro PromiseBuiltinsAssembler:: 222 IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(uint32): 223 bool; 224 225// https://tc39.es/ecma262/#sec-rejectpromise 226transitioning builtin 227RejectPromise(implicit context: Context)( 228 promise: JSPromise, reason: JSAny, debugEvent: Boolean): JSAny { 229 const promiseHookFlags = PromiseHookFlags(); 230 231 // If promise hook is enabled or the debugger is active, let 232 // the runtime handle this operation, which greatly reduces 233 // the complexity here and also avoids a couple of back and 234 // forth between JavaScript and C++ land. 235 if (IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate( 236 promiseHookFlags) || 237 !promise.HasHandler()) { 238 // 7. If promise.[[PromiseIsHandled]] is false, perform 239 // HostPromiseRejectionTracker(promise, "reject"). 240 // We don't try to handle rejecting {promise} without handler 241 // here, but we let the C++ code take care of this completely. 242 return runtime::RejectPromise(promise, reason, debugEvent); 243 } 244 245 RunContextPromiseHookResolve(promise, promiseHookFlags); 246 247 // 2. Let reactions be promise.[[PromiseRejectReactions]]. 248 const reactions = 249 UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); 250 251 // 3. Set promise.[[PromiseResult]] to reason. 252 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 253 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 254 promise.reactions_or_result = reason; 255 256 // 6. Set promise.[[PromiseState]] to "rejected". 257 promise.SetStatus(PromiseState::kRejected); 258 259 // 8. Return TriggerPromiseReactions(reactions, reason). 260 TriggerPromiseReactions(reactions, reason, kPromiseReactionReject); 261 return Undefined; 262} 263 264const kPromiseCapabilitySize: 265 constexpr int31 generates 'PromiseCapability::kSize'; 266 267type PromiseResolvingFunctionContext extends FunctionContext; 268extern enum PromiseResolvingFunctionContextSlot extends intptr 269constexpr 'PromiseBuiltins::PromiseResolvingFunctionContextSlot' { 270 kPromiseSlot: Slot<PromiseResolvingFunctionContext, JSPromise>, 271 kAlreadyResolvedSlot: Slot<PromiseResolvingFunctionContext, Boolean>, 272 kDebugEventSlot: Slot<PromiseResolvingFunctionContext, Boolean>, 273 kPromiseContextLength 274} 275 276type PromiseCapabilitiesExecutorContext extends FunctionContext; 277extern enum FunctionContextSlot extends intptr 278constexpr 'PromiseBuiltins::FunctionContextSlot' { 279 kCapabilitySlot: Slot<PromiseCapabilitiesExecutorContext, PromiseCapability>, 280 kCapabilitiesContextLength 281} 282 283@export 284macro CreatePromiseCapabilitiesExecutorContext( 285 nativeContext: NativeContext, capability: PromiseCapability): 286 PromiseCapabilitiesExecutorContext { 287 const executorContext = %RawDownCast<PromiseCapabilitiesExecutorContext>( 288 AllocateSyntheticFunctionContext( 289 nativeContext, FunctionContextSlot::kCapabilitiesContextLength)); 290 291 InitContextSlot( 292 executorContext, FunctionContextSlot::kCapabilitySlot, capability); 293 return executorContext; 294} 295 296@export 297macro CreatePromiseCapability( 298 promise: JSReceiver|Undefined, resolve: JSFunction|Undefined, 299 reject: JSFunction|Undefined): PromiseCapability { 300 return new PromiseCapability{ 301 map: kPromiseCapabilityMap, 302 promise: promise, 303 resolve: resolve, 304 reject: reject 305 }; 306} 307 308@export 309struct PromiseResolvingFunctions { 310 resolve: JSFunction; 311 reject: JSFunction; 312} 313 314@export 315macro CreatePromiseResolvingFunctions(implicit context: Context)( 316 promise: JSPromise, debugEvent: Boolean, nativeContext: NativeContext): 317 PromiseResolvingFunctions { 318 const promiseContext = CreatePromiseResolvingFunctionsContext( 319 promise, debugEvent, nativeContext); 320 const map = *NativeContextSlot( 321 nativeContext, ContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); 322 const resolveInfo = PromiseCapabilityDefaultResolveSharedFunConstant(); 323 324 const resolve: JSFunction = 325 AllocateFunctionWithMapAndContext(map, resolveInfo, promiseContext); 326 const rejectInfo = PromiseCapabilityDefaultRejectSharedFunConstant(); 327 const reject: JSFunction = 328 AllocateFunctionWithMapAndContext(map, rejectInfo, promiseContext); 329 return PromiseResolvingFunctions{resolve: resolve, reject: reject}; 330} 331 332transitioning macro 333InnerNewPromiseCapability(implicit context: Context)( 334 constructor: HeapObject, debugEvent: Boolean): PromiseCapability { 335 const nativeContext = LoadNativeContext(context); 336 if (constructor == 337 *NativeContextSlot(nativeContext, ContextSlot::PROMISE_FUNCTION_INDEX)) { 338 const promise = NewJSPromise(); 339 340 const pair = 341 CreatePromiseResolvingFunctions(promise, debugEvent, nativeContext); 342 343 return CreatePromiseCapability(promise, pair.resolve, pair.reject); 344 } else { 345 // We have to create the capability before the associated promise 346 // because the builtin PromiseConstructor uses the executor. 347 const capability = CreatePromiseCapability(Undefined, Undefined, Undefined); 348 const executorContext = 349 CreatePromiseCapabilitiesExecutorContext(nativeContext, capability); 350 351 const executorInfo = PromiseGetCapabilitiesExecutorSharedFunConstant(); 352 const functionMap = 353 *NativeContextSlot( 354 nativeContext, 355 ContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); 356 const executor = AllocateFunctionWithMapAndContext( 357 functionMap, executorInfo, executorContext); 358 359 const promiseConstructor = UnsafeCast<Constructor>(constructor); 360 const promise = Construct(promiseConstructor, executor); 361 capability.promise = promise; 362 363 if (!Is<Callable>(capability.resolve) || !Is<Callable>(capability.reject)) { 364 ThrowTypeError(MessageTemplate::kPromiseNonCallable); 365 } 366 return capability; 367 } 368} 369 370// https://tc39.es/ecma262/#sec-newpromisecapability 371transitioning builtin 372NewPromiseCapability(implicit context: Context)( 373 maybeConstructor: Object, debugEvent: Boolean): PromiseCapability { 374 typeswitch (maybeConstructor) { 375 case (Smi): { 376 ThrowTypeError(MessageTemplate::kNotConstructor, maybeConstructor); 377 } 378 case (constructor: HeapObject): { 379 if (!IsConstructor(constructor)) { 380 ThrowTypeError(MessageTemplate::kNotConstructor, maybeConstructor); 381 } 382 return InnerNewPromiseCapability(constructor, debugEvent); 383 } 384 } 385} 386 387// https://tc39.es/ecma262/#sec-promise-reject-functions 388transitioning javascript builtin 389PromiseCapabilityDefaultReject( 390 js-implicit context: Context, receiver: JSAny)(reason: JSAny): JSAny { 391 const context = %RawDownCast<PromiseResolvingFunctionContext>(context); 392 // 2. Let promise be F.[[Promise]]. 393 const promise = 394 *ContextSlot(context, PromiseResolvingFunctionContextSlot::kPromiseSlot); 395 396 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. 397 const alreadyResolved = *ContextSlot( 398 context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot); 399 400 // 4. If alreadyResolved.[[Value]] is true, return undefined. 401 if (alreadyResolved == True) { 402 return runtime::PromiseRejectAfterResolved(promise, reason); 403 } 404 405 // 5. Set alreadyResolved.[[Value]] to true. 406 *ContextSlot( 407 context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot) = 408 True; 409 410 // 6. Return RejectPromise(promise, reason). 411 const debugEvent = *ContextSlot( 412 context, PromiseResolvingFunctionContextSlot::kDebugEventSlot); 413 return RejectPromise(promise, reason, debugEvent); 414} 415 416// https://tc39.es/ecma262/#sec-promise-resolve-functions 417transitioning javascript builtin 418PromiseCapabilityDefaultResolve( 419 js-implicit context: Context, receiver: JSAny)(resolution: JSAny): JSAny { 420 const context = %RawDownCast<PromiseResolvingFunctionContext>(context); 421 // 2. Let promise be F.[[Promise]]. 422 const promise: JSPromise = 423 *ContextSlot(context, PromiseResolvingFunctionContextSlot::kPromiseSlot); 424 425 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. 426 const alreadyResolved: Boolean = *ContextSlot( 427 context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot); 428 429 // 4. If alreadyResolved.[[Value]] is true, return undefined. 430 if (alreadyResolved == True) { 431 return runtime::PromiseResolveAfterResolved(promise, resolution); 432 } 433 434 // 5. Set alreadyResolved.[[Value]] to true. 435 *ContextSlot( 436 context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot) = 437 True; 438 439 // The rest of the logic (and the catch prediction) is 440 // encapsulated in the dedicated ResolvePromise builtin. 441 return ResolvePromise(context, promise, resolution); 442} 443 444@export 445transitioning macro PerformPromiseThenImpl(implicit context: Context)( 446 promise: JSPromise, onFulfilled: Callable|Undefined, 447 onRejected: Callable|Undefined, 448 resultPromiseOrCapability: JSPromise|PromiseCapability|Undefined): void { 449 if (promise.Status() == PromiseState::kPending) { 450 // The {promise} is still in "Pending" state, so we just record a new 451 // PromiseReaction holding both the onFulfilled and onRejected callbacks. 452 // Once the {promise} is resolved we decide on the concrete handler to 453 // push onto the microtask queue. 454 const handlerContext = ExtractHandlerContext(onFulfilled, onRejected); 455 const promiseReactions = 456 UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); 457 const reaction = NewPromiseReaction( 458 handlerContext, promiseReactions, resultPromiseOrCapability, 459 onFulfilled, onRejected); 460 promise.reactions_or_result = reaction; 461 } else { 462 const reactionsOrResult = promise.reactions_or_result; 463 let microtask: PromiseReactionJobTask; 464 let handlerContext: Context; 465 if (promise.Status() == PromiseState::kFulfilled) { 466 handlerContext = ExtractHandlerContext(onFulfilled, onRejected); 467 microtask = NewPromiseFulfillReactionJobTask( 468 handlerContext, reactionsOrResult, onFulfilled, 469 resultPromiseOrCapability); 470 } else 471 deferred { 472 dcheck(promise.Status() == PromiseState::kRejected); 473 handlerContext = ExtractHandlerContext(onRejected, onFulfilled); 474 microtask = NewPromiseRejectReactionJobTask( 475 handlerContext, reactionsOrResult, onRejected, 476 resultPromiseOrCapability); 477 if (!promise.HasHandler()) { 478 runtime::PromiseRevokeReject(promise); 479 } 480 } 481 EnqueueMicrotask(handlerContext, microtask); 482 } 483 promise.SetHasHandler(); 484} 485 486// https://tc39.es/ecma262/#sec-performpromisethen 487transitioning builtin 488PerformPromiseThen(implicit context: Context)( 489 promise: JSPromise, onFulfilled: Callable|Undefined, 490 onRejected: Callable|Undefined, resultPromise: JSPromise|Undefined): JSAny { 491 PerformPromiseThenImpl(promise, onFulfilled, onRejected, resultPromise); 492 return resultPromise; 493} 494 495// https://tc39.es/ecma262/#sec-promise-reject-functions 496transitioning javascript builtin 497PromiseReject( 498 js-implicit context: NativeContext, receiver: JSAny)(reason: JSAny): JSAny { 499 // 1. Let C be the this value. 500 // 2. If Type(C) is not Object, throw a TypeError exception. 501 const receiver = Cast<JSReceiver>(receiver) otherwise 502 ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'PromiseReject'); 503 504 const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); 505 if (promiseFun == receiver) { 506 const promise = NewJSPromise(PromiseState::kRejected, reason); 507 runtime::PromiseRejectEventFromStack(promise, reason); 508 return promise; 509 } else { 510 // 3. Let promiseCapability be ? NewPromiseCapability(C). 511 const capability = NewPromiseCapability(receiver, True); 512 513 // 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »). 514 const reject = UnsafeCast<Callable>(capability.reject); 515 Call(context, reject, Undefined, reason); 516 517 // 5. Return promiseCapability.[[Promise]]. 518 return capability.promise; 519 } 520} 521 522const kPromiseExecutorAlreadyInvoked: constexpr MessageTemplate 523 generates 'MessageTemplate::kPromiseExecutorAlreadyInvoked'; 524 525// https://tc39.es/ecma262/#sec-getcapabilitiesexecutor-functions 526transitioning javascript builtin 527PromiseGetCapabilitiesExecutor(js-implicit context: Context, receiver: JSAny)( 528 resolve: JSAny, reject: JSAny): JSAny { 529 const context = %RawDownCast<PromiseCapabilitiesExecutorContext>(context); 530 const capability: PromiseCapability = 531 *ContextSlot(context, FunctionContextSlot::kCapabilitySlot); 532 if (capability.resolve != Undefined || capability.reject != Undefined) 533 deferred { 534 ThrowTypeError(kPromiseExecutorAlreadyInvoked); 535 } 536 537 capability.resolve = resolve; 538 capability.reject = reject; 539 return Undefined; 540} 541 542macro IsPromiseResolveLookupChainIntact(implicit context: Context)( 543 nativeContext: NativeContext, constructor: JSReceiver): bool { 544 if (IsForceSlowPath()) return false; 545 const promiseFun = 546 *NativeContextSlot(nativeContext, ContextSlot::PROMISE_FUNCTION_INDEX); 547 return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid(); 548} 549 550// https://tc39.es/ecma262/#sec-getpromiseresolve 551transitioning macro GetPromiseResolve(implicit context: Context)( 552 nativeContext: NativeContext, constructor: Constructor): JSAny { 553 // 1. Assert: IsConstructor(constructor) is true. 554 555 // We can skip the "resolve" lookup on {constructor} if it's the 556 // Promise constructor and the Promise.resolve protector is intact, 557 // as that guards the lookup path for the "resolve" property on the 558 // Promise constructor. In this case, promiseResolveFunction is undefined, 559 // and when CallResolve is called with it later, it will call Promise.resolve. 560 let promiseResolveFunction: JSAny = Undefined; 561 562 if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) { 563 let promiseResolve: JSAny; 564 565 // 2. Let promiseResolve be ? Get(constructor, "resolve"). 566 promiseResolve = GetProperty(constructor, kResolveString); 567 568 // 3. If IsCallable(promiseResolve) is false, throw a TypeError exception. 569 promiseResolveFunction = 570 Cast<Callable>(promiseResolve) otherwise ThrowTypeError( 571 MessageTemplate::kCalledNonCallable, 'resolve'); 572 } 573 // 4. return promiseResolve. 574 return promiseResolveFunction; 575} 576 577transitioning macro CallResolve(implicit context: Context)( 578 constructor: Constructor, resolve: JSAny, value: JSAny): JSAny { 579 // Undefined can never be a valid value for the resolve function, 580 // instead it is used as a special marker for the fast path. 581 if (resolve == Undefined) { 582 return PromiseResolve(constructor, value); 583 } else 584 deferred { 585 return Call(context, UnsafeCast<Callable>(resolve), constructor, value); 586 } 587} 588 589transitioning javascript builtin 590PromiseConstructorLazyDeoptContinuation( 591 js-implicit context: NativeContext, receiver: JSAny)( 592 promise: JSAny, reject: JSAny, exception: JSAny|TheHole, 593 _result: JSAny): JSAny { 594 typeswitch (exception) { 595 case (TheHole): { 596 } 597 case (e: JSAny): { 598 Call(context, reject, Undefined, e); 599 } 600 } 601 return promise; 602} 603 604extern macro PromiseCapabilityDefaultRejectSharedFunConstant(): 605 SharedFunctionInfo; 606extern macro PromiseCapabilityDefaultResolveSharedFunConstant(): 607 SharedFunctionInfo; 608extern macro PromiseGetCapabilitiesExecutorSharedFunConstant(): 609 SharedFunctionInfo; 610} 611