// Copyright 2019 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include 'src/builtins/builtins-promise-gen.h' namespace promise { // https://tc39.es/ecma262/#sec-promise.race transitioning javascript builtin PromiseRace( js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { const receiver = Cast<JSReceiver>(receiver) otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race'); const nativeContext = LoadNativeContext(context); // Let promiseCapability be ? NewPromiseCapability(C). // Don't fire debugEvent so that forwarding the rejection through all does // not trigger redundant ExceptionEvents const capability = NewPromiseCapability(receiver, False); const resolve = capability.resolve; const reject = capability.reject; const promise = capability.promise; // NewPromiseCapability guarantees that receiver is Constructor. assert(Is<Constructor>(receiver)); const constructor = UnsafeCast<Constructor>(receiver); // For catch prediction, don't treat the .then calls as handling it; // instead, recurse outwards. if (IsDebugActive()) deferred { SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True); } try { let promiseResolveFunction: JSAny; let i: iterator::IteratorRecord; try { // Let promiseResolve be GetPromiseResolve(C). // IfAbruptRejectPromise(promiseResolve, promiseCapability). promiseResolveFunction = GetPromiseResolve(nativeContext, constructor); // Let iterator be GetIterator(iterable). // IfAbruptRejectPromise(iterator, promiseCapability). i = iterator::GetIterator(iterable); } catch (e) deferred { goto Reject(e); } // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). try { const fastIteratorResultMap = *NativeContextSlot( nativeContext, ContextSlot::ITERATOR_RESULT_MAP_INDEX); while (true) { let nextValue: JSAny; try { // Let next be IteratorStep(iteratorRecord.[[Iterator]]). // If next is an abrupt completion, set iteratorRecord.[[Done]] to // true. ReturnIfAbrupt(next). const next: JSReceiver = iterator::IteratorStep( i, fastIteratorResultMap) otherwise return promise; // Let nextValue be IteratorValue(next). // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] // to true. // ReturnIfAbrupt(nextValue). nextValue = iterator::IteratorValue(next, fastIteratorResultMap); } catch (e) { goto Reject(e); } // Let nextPromise be ? Call(constructor, _promiseResolve_, « // nextValue »). const nextPromise = CallResolve(constructor, promiseResolveFunction, nextValue); // Perform ? Invoke(nextPromise, "then", « resolveElement, // resultCapability.[[Reject]] »). const then = GetProperty(nextPromise, kThenString); const thenResult = Call( context, then, nextPromise, UnsafeCast<JSAny>(resolve), UnsafeCast<JSAny>(reject)); // For catch prediction, mark that rejections here are semantically // handled by the combined Promise. if (IsDebugActive() && !Is<JSPromise>(promise)) deferred { SetPropertyStrict( context, thenResult, kPromiseHandledBySymbol, promise); } } } catch (e) deferred { iterator::IteratorCloseOnException(i); goto Reject(e); } } label Reject(exception: Object) deferred { Call( context, UnsafeCast<JSAny>(reject), Undefined, UnsafeCast<JSAny>(exception)); return promise; } unreachable; } }