Promise.h (11747B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef builtin_Promise_h 8 #define builtin_Promise_h 9 10 #include "jstypes.h" // JS_PUBLIC_API 11 12 #include "js/RootingAPI.h" // JS::{,Mutable}Handle 13 #include "js/TypeDecls.h" // JS::HandleObjectVector 14 15 struct JS_PUBLIC_API JSContext; 16 class JS_PUBLIC_API JSObject; 17 18 namespace JS { 19 class CallArgs; 20 class Value; 21 } // namespace JS 22 23 namespace js { 24 25 class AsyncFunctionGeneratorObject; 26 class AsyncGeneratorObject; 27 class PromiseObject; 28 class SavedFrame; 29 30 enum class CompletionKind : uint8_t; 31 32 enum class PromiseHandler : uint32_t { 33 Identity = 0, 34 Thrower, 35 36 // ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14 37 // 38 // Await in async function 39 // https://tc39.es/ecma262/#await 40 // 41 // Step 3. fulfilledClosure Abstract Closure. 42 // Step 5. rejectedClosure Abstract Closure. 43 AsyncFunctionAwaitedFulfilled, 44 AsyncFunctionAwaitedRejected, 45 46 // Await in async generator 47 // https://tc39.es/ecma262/#await 48 // 49 // Step 3. fulfilledClosure Abstract Closure. 50 // Step 5. rejectedClosure Abstract Closure. 51 AsyncGeneratorAwaitedFulfilled, 52 AsyncGeneratorAwaitedRejected, 53 54 // AsyncGeneratorAwaitReturn ( generator ) 55 // https://tc39.es/ecma262/#sec-asyncgeneratorawaitreturn 56 // 57 // Step 7. fulfilledClosure Abstract Closure. 58 // Step 9. rejectedClosure Abstract Closure. 59 AsyncGeneratorAwaitReturnFulfilled, 60 AsyncGeneratorAwaitReturnRejected, 61 62 // AsyncGeneratorUnwrapYieldResumption 63 // https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption 64 // 65 // Steps 3-5 for awaited.[[Type]] handling. 66 AsyncGeneratorYieldReturnAwaitedFulfilled, 67 AsyncGeneratorYieldReturnAwaitedRejected, 68 69 // AsyncFromSyncIteratorContinuation ( result, promiseCapability ) 70 // https://tc39.es/ecma262/#sec-asyncfromsynciteratorcontinuation 71 // 72 // Step 9. unwrap Abstract Closure. 73 AsyncFromSyncIteratorValueUnwrapDone, 74 AsyncFromSyncIteratorValueUnwrapNotDone, 75 76 // AsyncFromSyncIteratorContinuation ( result, promiseCapability ) 77 // https://tc39.es/ecma262/#sec-asyncfromsynciteratorcontinuation 78 // 79 // Step 13.a. closeIterator Abstract Closure. 80 AsyncFromSyncIteratorClose, 81 82 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 83 // Explicit Resource Management Proposal 84 // 27.1.3.1 %AsyncIteratorPrototype% [ @@asyncDispose ] ( ) 85 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-%25asynciteratorprototype%25-%40%40asyncdispose 86 // 87 // Step 6.e. unwrap Abstract Closure 88 AsyncIteratorDisposeAwaitFulfilled, 89 #endif 90 91 // One past the maximum allowed PromiseHandler value. 92 Limit 93 }; 94 95 // Promise.prototype.then. 96 extern bool Promise_then(JSContext* cx, unsigned argc, JS::Value* vp); 97 98 // Promise[Symbol.species]. 99 extern bool Promise_static_species(JSContext* cx, unsigned argc, JS::Value* vp); 100 101 // Promise.resolve. 102 extern bool Promise_static_resolve(JSContext* cx, unsigned argc, JS::Value* vp); 103 104 /** 105 * Unforgeable version of the JS builtin Promise.all. 106 * 107 * Takes a HandleValueVector of Promise objects and returns a promise that's 108 * resolved with an array of resolution values when all those promises have 109 * been resolved, or rejected with the rejection value of the first rejected 110 * promise. 111 * 112 * Asserts that all objects in the `promises` vector are, maybe wrapped, 113 * instances of `Promise` or a subclass of `Promise`. 114 */ 115 [[nodiscard]] JSObject* GetWaitForAllPromise(JSContext* cx, 116 JS::HandleObjectVector promises); 117 118 /** 119 * Enqueues resolve/reject reactions in the given Promise's reactions lists 120 * as though by calling the original value of Promise.prototype.then, and 121 * without regard to any Promise subclassing used in `promiseObj` itself. 122 */ 123 [[nodiscard]] PromiseObject* OriginalPromiseThen( 124 JSContext* cx, JS::Handle<JSObject*> promiseObj, 125 JS::Handle<JSObject*> onFulfilled, JS::Handle<JSObject*> onRejected); 126 127 enum class UnhandledRejectionBehavior { Ignore, Report }; 128 129 /** 130 * React to[0] `unwrappedPromise` (which may not be from the current realm) as 131 * if by using a fresh promise created for the provided nullable fulfill/reject 132 * IsCallable objects. 133 * 134 * However, no dependent Promise will be created, and mucking with `Promise`, 135 * `Promise.prototype.then`, and `Promise[Symbol.species]` will not alter this 136 * function's behavior. 137 * 138 * If `unwrappedPromise` rejects and `onRejected_` is null, handling is 139 * determined by `behavior`. If `behavior == Report`, a fresh Promise will be 140 * constructed and rejected on the fly (and thus will be reported as unhandled). 141 * But if `behavior == Ignore`, the rejection is ignored and is not reported as 142 * unhandled. 143 * 144 * Note: Reactions pushed using this function contain a null `promise` field. 145 * That field is only ever used by devtools, which have to treat these reactions 146 * specially. 147 * 148 * 0. The sense of "react" here is the sense of the term as defined by Web IDL: 149 * https://heycam.github.io/webidl/#dfn-perform-steps-once-promise-is-settled 150 */ 151 [[nodiscard]] extern bool ReactToUnwrappedPromise( 152 JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise, 153 JS::Handle<JSObject*> onFulfilled_, JS::Handle<JSObject*> onRejected_, 154 UnhandledRejectionBehavior behavior); 155 156 /** 157 * PromiseResolve ( C, x ) 158 * 159 * The abstract operation PromiseResolve, given a constructor and a value, 160 * returns a new promise resolved with that value. 161 */ 162 [[nodiscard]] JSObject* PromiseResolve(JSContext* cx, 163 JS::Handle<JSObject*> constructor, 164 JS::Handle<JS::Value> value); 165 166 /** 167 * Reject |promise| with the value of the current pending exception. 168 * 169 * |promise| must be from the current realm. Callers must enter the realm of 170 * |promise| if they are not already in it. 171 */ 172 [[nodiscard]] bool RejectPromiseWithPendingError( 173 JSContext* cx, JS::Handle<PromiseObject*> promise); 174 175 /** 176 * Create the promise object which will be used as the return value of an async 177 * function. 178 */ 179 [[nodiscard]] PromiseObject* CreatePromiseObjectForAsync(JSContext* cx); 180 181 /** 182 * Returns true if the given object is a promise created by 183 * either CreatePromiseObjectForAsync function or async generator's method. 184 */ 185 [[nodiscard]] bool IsPromiseForAsyncFunctionOrGenerator(JSObject* promise); 186 187 [[nodiscard]] bool AsyncFunctionReturned( 188 JSContext* cx, JS::Handle<PromiseObject*> resultPromise, 189 JS::Handle<JS::Value> value); 190 191 [[nodiscard]] bool AsyncFunctionThrown( 192 JSContext* cx, JS::Handle<PromiseObject*> resultPromise, 193 JS::Handle<JS::Value> reason, 194 JS::Handle<SavedFrame*> unwrappedRejectionStack = nullptr); 195 196 // Start awaiting `value` in an async function (, but doesn't suspend the 197 // async function's execution!). Returns the async function's result promise. 198 [[nodiscard]] JSObject* AsyncFunctionAwait( 199 JSContext* cx, JS::Handle<AsyncFunctionGeneratorObject*> genObj, 200 JS::Handle<JS::Value> value); 201 202 // If the await operation can be skipped and the resolution value for `val` can 203 // be acquired, stored the resolved value to `resolved` and `true` to 204 // `*canSkip`. Otherwise, stores `false` to `*canSkip`. 205 [[nodiscard]] bool CanSkipAwait(JSContext* cx, JS::Handle<JS::Value> val, 206 bool* canSkip); 207 [[nodiscard]] bool ExtractAwaitValue(JSContext* cx, JS::Handle<JS::Value> val, 208 JS::MutableHandle<JS::Value> resolved); 209 210 bool AsyncFromSyncIteratorMethod(JSContext* cx, JS::CallArgs& args, 211 CompletionKind completionKind); 212 213 // Callback for describing promise reaction records, for use with 214 // PromiseObject::getReactionRecords. 215 struct PromiseReactionRecordBuilder { 216 // A reaction record created by a call to 'then' or 'catch', with functions to 217 // call on resolution or rejection, and the promise that will be settled 218 // according to the result of calling them. 219 // 220 // Note that resolve, reject, and result may not be same-compartment with cx, 221 // or with the promise we're inspecting. This function presents the values 222 // exactly as they appear in the reaction record. They may also be wrapped or 223 // unwrapped. 224 // 225 // Some reaction records refer to internal resolution or rejection functions 226 // that are not naturally represented as debuggee JavaScript functions. In 227 // this case, resolve and reject may be nullptr. 228 [[nodiscard]] virtual bool then(JSContext* cx, JS::Handle<JSObject*> resolve, 229 JS::Handle<JSObject*> reject, 230 JS::Handle<JSObject*> result) = 0; 231 232 // A reaction record created when one native promise is resolved to another. 233 // The 'promise' argument is the promise that will be settled in the same way 234 // the promise this reaction record is attached to is settled. 235 // 236 // Note that promise may not be same-compartment with cx. This function 237 // presents the promise exactly as it appears in the reaction record. 238 [[nodiscard]] virtual bool direct( 239 JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise) = 0; 240 241 // A reaction record that resumes an asynchronous function suspended at an 242 // await expression. The 'generator' argument is the generator object 243 // representing the call. 244 // 245 // Note that generator may not be same-compartment with cx. This function 246 // presents the generator exactly as it appears in the reaction record. 247 [[nodiscard]] virtual bool asyncFunction( 248 JSContext* cx, 249 JS::Handle<AsyncFunctionGeneratorObject*> unwrappedGenerator) = 0; 250 251 // A reaction record that resumes an asynchronous generator suspended at an 252 // await expression. The 'generator' argument is the generator object 253 // representing the call. 254 // 255 // Note that generator may not be same-compartment with cx. This function 256 // presents the generator exactly as it appears in the reaction record. 257 [[nodiscard]] virtual bool asyncGenerator( 258 JSContext* cx, JS::Handle<AsyncGeneratorObject*> unwrappedGenerator) = 0; 259 }; 260 261 [[nodiscard]] PromiseObject* CreatePromiseObjectForAsyncGenerator( 262 JSContext* cx); 263 264 // This implements "Let promiseCapability be ! NewPromiseCapability(%Promise%)". 265 [[nodiscard]] PromiseObject* CreatePromiseObjectWithoutResolutionFunctions( 266 JSContext* cx); 267 268 [[nodiscard]] bool ResolvePromiseInternal(JSContext* cx, 269 JS::Handle<JSObject*> promise, 270 JS::Handle<JS::Value> resolutionVal); 271 [[nodiscard]] bool RejectPromiseInternal( 272 JSContext* cx, JS::Handle<PromiseObject*> promise, 273 JS::Handle<JS::Value> reason, 274 JS::Handle<SavedFrame*> unwrappedRejectionStack = nullptr); 275 276 [[nodiscard]] bool InternalAsyncGeneratorAwait( 277 JSContext* cx, JS::Handle<AsyncGeneratorObject*> generator, 278 JS::Handle<JS::Value> value, PromiseHandler onFulfilled, 279 PromiseHandler onRejected); 280 281 bool IsPromiseWithDefaultResolvingFunction(PromiseObject* promise); 282 void SetAlreadyResolvedPromiseWithDefaultResolvingFunction( 283 PromiseObject* promise); 284 285 bool IsPromiseConstructor(const JSObject* obj); 286 287 bool AbruptRejectPromise(JSContext* cx, JS::CallArgs& args, 288 JS::Handle<JSObject*> promiseObj, 289 JS::Handle<JSObject*> reject); 290 291 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 292 [[nodiscard]] bool InternalAsyncIteratorDisposeAwait( 293 JSContext* cx, JS::Handle<JS::Value> value, 294 JS::Handle<JSObject*> resultPromise); 295 #endif 296 } // namespace js 297 298 #endif // builtin_Promise_h