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 screwing up the store buffer.
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