11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include 'src/builtins/builtins-promise.h' 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-promise-jobs 81cb0ef41Sopenharmony_cinamespace promise { 91cb0ef41Sopenharmony_ciextern macro IsJSPromiseMap(Map): bool; 101cb0ef41Sopenharmony_ciextern macro NeedsAnyPromiseHooks(): bool; 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci// https://tc39.es/ecma262/#sec-promiseresolvethenablejob 131cb0ef41Sopenharmony_citransitioning builtin 141cb0ef41Sopenharmony_ciPromiseResolveThenableJob(implicit context: Context)( 151cb0ef41Sopenharmony_ci promiseToResolve: JSPromise, thenable: JSReceiver, then: JSAny): JSAny { 161cb0ef41Sopenharmony_ci // We can use a simple optimization here if we know that {then} is the 171cb0ef41Sopenharmony_ci // initial Promise.prototype.then method, and {thenable} is a JSPromise 181cb0ef41Sopenharmony_ci // whose 191cb0ef41Sopenharmony_ci // @@species lookup chain is intact: We can connect {thenable} and 201cb0ef41Sopenharmony_ci // {promise_to_resolve} directly in that case and avoid the allocation of a 211cb0ef41Sopenharmony_ci // temporary JSPromise and the closures plus context. 221cb0ef41Sopenharmony_ci // 231cb0ef41Sopenharmony_ci // We take the generic (slow-)path if a PromiseHook is enabled or the 241cb0ef41Sopenharmony_ci // debugger is active, to make sure we expose spec compliant behavior. 251cb0ef41Sopenharmony_ci const nativeContext = LoadNativeContext(context); 261cb0ef41Sopenharmony_ci const promiseThen = *NativeContextSlot(ContextSlot::PROMISE_THEN_INDEX); 271cb0ef41Sopenharmony_ci const thenableMap = thenable.map; 281cb0ef41Sopenharmony_ci if (TaggedEqual(then, promiseThen) && IsJSPromiseMap(thenableMap) && 291cb0ef41Sopenharmony_ci !NeedsAnyPromiseHooks() && 301cb0ef41Sopenharmony_ci IsPromiseSpeciesLookupChainIntact(nativeContext, thenableMap)) { 311cb0ef41Sopenharmony_ci // We know that the {thenable} is a JSPromise, which doesn't require 321cb0ef41Sopenharmony_ci // any special treatment and that {then} corresponds to the initial 331cb0ef41Sopenharmony_ci // Promise.prototype.then method. So instead of allocating a temporary 341cb0ef41Sopenharmony_ci // JSPromise to connect the {thenable} with the {promise_to_resolve}, 351cb0ef41Sopenharmony_ci // we can directly schedule the {promise_to_resolve} with default 361cb0ef41Sopenharmony_ci // handlers onto the {thenable} promise. This does not only save the 371cb0ef41Sopenharmony_ci // JSPromise allocation, but also avoids the allocation of the two 381cb0ef41Sopenharmony_ci // resolving closures and the shared context. 391cb0ef41Sopenharmony_ci // 401cb0ef41Sopenharmony_ci // What happens normally in this case is 411cb0ef41Sopenharmony_ci // 421cb0ef41Sopenharmony_ci // resolve, reject = CreateResolvingFunctions(promise_to_resolve) 431cb0ef41Sopenharmony_ci // result_capability = NewPromiseCapability(%Promise%) 441cb0ef41Sopenharmony_ci // PerformPromiseThen(thenable, resolve, reject, result_capability) 451cb0ef41Sopenharmony_ci // 461cb0ef41Sopenharmony_ci // which means that PerformPromiseThen will either schedule a new 471cb0ef41Sopenharmony_ci // PromiseReaction with resolve and reject or a PromiseReactionJob 481cb0ef41Sopenharmony_ci // with resolve or reject based on the state of {thenable}. And 491cb0ef41Sopenharmony_ci // resolve or reject will just invoke the default [[Resolve]] or 501cb0ef41Sopenharmony_ci // [[Reject]] functions on the {promise_to_resolve}. 511cb0ef41Sopenharmony_ci // 521cb0ef41Sopenharmony_ci // This is the same as just doing 531cb0ef41Sopenharmony_ci // 541cb0ef41Sopenharmony_ci // PerformPromiseThen(thenable, undefined, undefined, 551cb0ef41Sopenharmony_ci // promise_to_resolve) 561cb0ef41Sopenharmony_ci // 571cb0ef41Sopenharmony_ci // which performs exactly the same (observable) steps. 581cb0ef41Sopenharmony_ci return PerformPromiseThen( 591cb0ef41Sopenharmony_ci UnsafeCast<JSPromise>(thenable), UndefinedConstant(), 601cb0ef41Sopenharmony_ci UndefinedConstant(), promiseToResolve); 611cb0ef41Sopenharmony_ci } else { 621cb0ef41Sopenharmony_ci const funcs = 631cb0ef41Sopenharmony_ci CreatePromiseResolvingFunctions(promiseToResolve, False, nativeContext); 641cb0ef41Sopenharmony_ci const resolve = funcs.resolve; 651cb0ef41Sopenharmony_ci const reject = funcs.reject; 661cb0ef41Sopenharmony_ci try { 671cb0ef41Sopenharmony_ci return Call( 681cb0ef41Sopenharmony_ci context, UnsafeCast<Callable>(then), thenable, resolve, reject); 691cb0ef41Sopenharmony_ci } catch (e, _message) { 701cb0ef41Sopenharmony_ci return Call(context, UnsafeCast<Callable>(reject), Undefined, e); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci} 75