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-gen.h' 6 7namespace promise { 8 9// https://tc39.es/ecma262/#sec-promise.race 10transitioning javascript builtin 11PromiseRace( 12 js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { 13 const receiver = Cast<JSReceiver>(receiver) 14 otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race'); 15 16 // This builtin is attached to JSFunction created by the bootstrapper so 17 // `context` is the native context. 18 check(Is<NativeContext>(context)); 19 const nativeContext = UnsafeCast<NativeContext>(context); 20 21 // Let promiseCapability be ? NewPromiseCapability(C). 22 // Don't fire debugEvent so that forwarding the rejection through all does 23 // not trigger redundant ExceptionEvents 24 const capability = NewPromiseCapability(receiver, False); 25 const resolve = capability.resolve; 26 const reject = capability.reject; 27 const promise = capability.promise; 28 29 // NewPromiseCapability guarantees that receiver is Constructor. 30 dcheck(Is<Constructor>(receiver)); 31 const constructor = UnsafeCast<Constructor>(receiver); 32 33 // For catch prediction, don't treat the .then calls as handling it; 34 // instead, recurse outwards. 35 if (IsDebugActive()) deferred { 36 SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True); 37 } 38 39 try { 40 let promiseResolveFunction: JSAny; 41 let i: iterator::IteratorRecord; 42 try { 43 // Let promiseResolve be GetPromiseResolve(C). 44 // IfAbruptRejectPromise(promiseResolve, promiseCapability). 45 promiseResolveFunction = GetPromiseResolve(nativeContext, constructor); 46 47 // Let iterator be GetIterator(iterable). 48 // IfAbruptRejectPromise(iterator, promiseCapability). 49 i = iterator::GetIterator(iterable); 50 } catch (e, _message) deferred { 51 goto Reject(e); 52 } 53 54 // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). 55 try { 56 const fastIteratorResultMap = *NativeContextSlot( 57 nativeContext, ContextSlot::ITERATOR_RESULT_MAP_INDEX); 58 while (true) { 59 let nextValue: JSAny; 60 try { 61 // Let next be IteratorStep(iteratorRecord.[[Iterator]]). 62 // If next is an abrupt completion, set iteratorRecord.[[Done]] to 63 // true. ReturnIfAbrupt(next). 64 const next: JSReceiver = iterator::IteratorStep( 65 i, fastIteratorResultMap) otherwise return promise; 66 67 // Let nextValue be IteratorValue(next). 68 // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] 69 // to true. 70 // ReturnIfAbrupt(nextValue). 71 nextValue = iterator::IteratorValue(next, fastIteratorResultMap); 72 } catch (e, _message) { 73 goto Reject(e); 74 } 75 // Let nextPromise be ? Call(constructor, _promiseResolve_, « 76 // nextValue »). 77 const nextPromise = 78 CallResolve(constructor, promiseResolveFunction, nextValue); 79 80 // Perform ? Invoke(nextPromise, "then", « resolveElement, 81 // resultCapability.[[Reject]] »). 82 const then = GetProperty(nextPromise, kThenString); 83 const thenResult = Call( 84 context, then, nextPromise, UnsafeCast<JSAny>(resolve), 85 UnsafeCast<JSAny>(reject)); 86 87 // For catch prediction, mark that rejections here are semantically 88 // handled by the combined Promise. 89 if (IsDebugActive() && !Is<JSPromise>(promise)) deferred { 90 SetPropertyStrict( 91 context, thenResult, kPromiseHandledBySymbol, promise); 92 } 93 } 94 } catch (e, _message) deferred { 95 iterator::IteratorCloseOnException(i); 96 goto Reject(e); 97 } 98 } label Reject(exception: JSAny) deferred { 99 Call(context, UnsafeCast<JSAny>(reject), Undefined, exception); 100 return promise; 101 } 102 unreachable; 103} 104} 105