| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 (function(global, utils, extrasUtils) { | 5 (function(global, utils, extrasUtils) { |
| 6 | 6 |
| 7 "use strict"; | 7 "use strict"; |
| 8 | 8 |
| 9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
| 10 | 10 |
| 11 // ------------------------------------------------------------------- | 11 // ------------------------------------------------------------------- |
| 12 // Imports | 12 // Imports |
| 13 | 13 |
| 14 var InternalArray = utils.InternalArray; | 14 var InternalArray = utils.InternalArray; |
| 15 var promiseAsyncStackIDSymbol = | 15 var promiseAsyncStackIDSymbol = |
| 16 utils.ImportNow("promise_async_stack_id_symbol"); | 16 utils.ImportNow("promise_async_stack_id_symbol"); |
| 17 var promiseHandledBySymbol = | 17 var promiseHandledBySymbol = |
| 18 utils.ImportNow("promise_handled_by_symbol"); | 18 utils.ImportNow("promise_handled_by_symbol"); |
| 19 var promiseForwardingHandlerSymbol = | 19 var promiseForwardingHandlerSymbol = |
| 20 utils.ImportNow("promise_forwarding_handler_symbol"); | 20 utils.ImportNow("promise_forwarding_handler_symbol"); |
| 21 var promiseHasHandlerSymbol = | 21 var promiseHasHandlerSymbol = |
| 22 utils.ImportNow("promise_has_handler_symbol"); | 22 utils.ImportNow("promise_has_handler_symbol"); |
| 23 var promiseRejectReactionsSymbol = | |
| 24 utils.ImportNow("promise_reject_reactions_symbol"); | |
| 25 var promiseFulfillReactionsSymbol = | |
| 26 utils.ImportNow("promise_fulfill_reactions_symbol"); | |
| 27 var promiseDeferredReactionSymbol = | |
| 28 utils.ImportNow("promise_deferred_reaction_symbol"); | |
| 29 var promiseHandledHintSymbol = | 23 var promiseHandledHintSymbol = |
| 30 utils.ImportNow("promise_handled_hint_symbol"); | 24 utils.ImportNow("promise_handled_hint_symbol"); |
| 31 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); | 25 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
| 32 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); | 26 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
| 33 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); | 27 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
| 34 var SpeciesConstructor; | 28 var SpeciesConstructor; |
| 35 var speciesSymbol = utils.ImportNow("species_symbol"); | 29 var speciesSymbol = utils.ImportNow("species_symbol"); |
| 36 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 30 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
| 37 var ObjectHasOwnProperty; | 31 var ObjectHasOwnProperty; |
| 38 var GlobalPromise = global.Promise; | 32 var GlobalPromise = global.Promise; |
| 33 var PromiseThen = GlobalPromise.prototype.then; |
| 39 | 34 |
| 40 utils.Import(function(from) { | 35 utils.Import(function(from) { |
| 41 ObjectHasOwnProperty = from.ObjectHasOwnProperty; | 36 ObjectHasOwnProperty = from.ObjectHasOwnProperty; |
| 42 SpeciesConstructor = from.SpeciesConstructor; | 37 SpeciesConstructor = from.SpeciesConstructor; |
| 43 }); | 38 }); |
| 44 | 39 |
| 45 // ------------------------------------------------------------------- | 40 // ------------------------------------------------------------------- |
| 46 | 41 |
| 47 // Core functionality. | 42 // Core functionality. |
| 48 | 43 |
| 49 function PromiseSet(promise, status, value) { | |
| 50 SET_PRIVATE(promise, promiseStateSymbol, status); | |
| 51 SET_PRIVATE(promise, promiseResultSymbol, value); | |
| 52 | |
| 53 // There are 3 possible states for the resolve, reject symbols when we add | |
| 54 // a new callback -- | |
| 55 // 1) UNDEFINED -- This is the zero state where there is no callback | |
| 56 // registered. When we see this state, we directly attach the callbacks to | |
| 57 // the symbol. | |
| 58 // 2) !IS_ARRAY -- There is a single callback directly attached to the | |
| 59 // symbols. We need to create a new array to store additional callbacks. | |
| 60 // 3) IS_ARRAY -- There are multiple callbacks already registered, | |
| 61 // therefore we can just push the new callback to the existing array. | |
| 62 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED); | |
| 63 SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED); | |
| 64 | |
| 65 // This symbol is used only when one deferred needs to be attached. When more | |
| 66 // than one deferred need to be attached the promise, we attach them directly | |
| 67 // to the promiseFulfillReactionsSymbol and promiseRejectReactionsSymbol and | |
| 68 // reset this back to UNDEFINED. | |
| 69 SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED); | |
| 70 | |
| 71 return promise; | |
| 72 } | |
| 73 | |
| 74 function PromiseCreateAndSet(status, value) { | |
| 75 var promise = %promise_internal_constructor(); | |
| 76 // If debug is active, notify about the newly created promise first. | |
| 77 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); | |
| 78 return PromiseSet(promise, status, value); | |
| 79 } | |
| 80 | |
| 81 function PromiseInit(promise) { | |
| 82 return PromiseSet(promise, kPending, UNDEFINED); | |
| 83 } | |
| 84 | |
| 85 function PromiseHandle(value, handler, deferred) { | 44 function PromiseHandle(value, handler, deferred) { |
| 86 var debug_is_active = DEBUG_IS_ACTIVE; | 45 var debug_is_active = DEBUG_IS_ACTIVE; |
| 87 try { | 46 try { |
| 88 if (debug_is_active) %DebugPushPromise(deferred.promise); | 47 if (debug_is_active) %DebugPushPromise(deferred.promise); |
| 89 var result = handler(value); | 48 var result = handler(value); |
| 90 if (IS_UNDEFINED(deferred.resolve)) { | 49 if (IS_UNDEFINED(deferred.resolve)) { |
| 91 ResolvePromise(deferred.promise, result); | 50 ResolvePromise(deferred.promise, result); |
| 92 } else { | 51 } else { |
| 93 %_Call(deferred.resolve, UNDEFINED, result); | 52 %_Call(deferred.resolve, UNDEFINED, result); |
| 94 } | 53 } |
| 95 } %catch (exception) { // Natives syntax to mark this catch block. | 54 } %catch (exception) { // Natives syntax to mark this catch block. |
| 96 try { | 55 try { |
| 97 if (IS_UNDEFINED(deferred.reject)) { | 56 if (IS_UNDEFINED(deferred.reject)) { |
| 98 // Pass false for debugEvent so .then chaining or throwaway promises | 57 // Pass false for debugEvent so .then chaining or throwaway promises |
| 99 // in async functions do not trigger redundant ExceptionEvents. | 58 // in async functions do not trigger redundant ExceptionEvents. |
| 100 %PromiseReject(deferred.promise, exception, false); | 59 %PromiseReject(deferred.promise, exception, false); |
| 101 PromiseSet(deferred.promise, kRejected, exception); | |
| 102 } else { | 60 } else { |
| 103 %_Call(deferred.reject, UNDEFINED, exception); | 61 %_Call(deferred.reject, UNDEFINED, exception); |
| 104 } | 62 } |
| 105 } catch (e) { } | 63 } catch (e) { } |
| 106 } finally { | 64 } finally { |
| 107 if (debug_is_active) %DebugPopPromise(); | 65 if (debug_is_active) %DebugPopPromise(); |
| 108 } | 66 } |
| 109 } | 67 } |
| 110 | 68 |
| 111 function PromiseDebugGetInfo(deferreds, status) { | 69 function PromiseDebugGetInfo(deferreds, status) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 127 name = "async function"; | 85 name = "async function"; |
| 128 } else { | 86 } else { |
| 129 id = %DebugNextMicrotaskId(); | 87 id = %DebugNextMicrotaskId(); |
| 130 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; | 88 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; |
| 131 %DebugAsyncTaskEvent("enqueue", id, name); | 89 %DebugAsyncTaskEvent("enqueue", id, name); |
| 132 } | 90 } |
| 133 } | 91 } |
| 134 return [id, name]; | 92 return [id, name]; |
| 135 } | 93 } |
| 136 | 94 |
| 137 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) { | |
| 138 var maybeResolveCallbacks = | |
| 139 GET_PRIVATE(promise, promiseFulfillReactionsSymbol); | |
| 140 if (IS_UNDEFINED(maybeResolveCallbacks)) { | |
| 141 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); | |
| 142 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); | |
| 143 SET_PRIVATE(promise, promiseDeferredReactionSymbol, deferred); | |
| 144 } else if (!IS_ARRAY(maybeResolveCallbacks)) { | |
| 145 var resolveCallbacks = new InternalArray(); | |
| 146 var rejectCallbacks = new InternalArray(); | |
| 147 var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol); | |
| 148 | |
| 149 resolveCallbacks.push( | |
| 150 maybeResolveCallbacks, existingDeferred, onResolve, deferred); | |
| 151 rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol), | |
| 152 existingDeferred, | |
| 153 onReject, | |
| 154 deferred); | |
| 155 | |
| 156 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks); | |
| 157 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks); | |
| 158 SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED); | |
| 159 } else { | |
| 160 maybeResolveCallbacks.push(onResolve, deferred); | |
| 161 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 function PromiseIdResolveHandler(x) { return x; } | 95 function PromiseIdResolveHandler(x) { return x; } |
| 166 function PromiseIdRejectHandler(r) { %_ReThrow(r); } | 96 function PromiseIdRejectHandler(r) { %_ReThrow(r); } |
| 167 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true); | 97 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true); |
| 168 | 98 |
| 169 // ------------------------------------------------------------------- | 99 // ------------------------------------------------------------------- |
| 170 // Define exported functions. | 100 // Define exported functions. |
| 171 | 101 |
| 172 // For bootstrapper. | 102 // For bootstrapper. |
| 173 | 103 |
| 104 // This is used by utils and v8-extras. |
| 174 function PromiseCreate() { | 105 function PromiseCreate() { |
| 175 return PromiseInit(%promise_internal_constructor()); | 106 return %promise_internal_constructor(); |
| 176 } | 107 } |
| 177 | 108 |
| 178 // ES#sec-promise-resolve-functions | 109 // ES#sec-promise-resolve-functions |
| 179 // Promise Resolve Functions, steps 6-13 | 110 // Promise Resolve Functions, steps 6-13 |
| 180 function ResolvePromise(promise, resolution) { | 111 function ResolvePromise(promise, resolution) { |
| 181 if (resolution === promise) { | 112 if (resolution === promise) { |
| 182 var exception = %make_type_error(kPromiseCyclic, resolution); | 113 var exception = %make_type_error(kPromiseCyclic, resolution); |
| 183 %PromiseReject(promise, exception, true); | 114 %PromiseReject(promise, exception, true); |
| 184 PromiseSet(promise, kRejected, exception); | |
| 185 return; | 115 return; |
| 186 } | 116 } |
| 187 if (IS_RECEIVER(resolution)) { | 117 if (IS_RECEIVER(resolution)) { |
| 188 // 25.4.1.3.2 steps 8-12 | 118 // 25.4.1.3.2 steps 8-12 |
| 189 try { | 119 try { |
| 190 var then = resolution.then; | 120 var then = resolution.then; |
| 191 } catch (e) { | 121 } catch (e) { |
| 192 %PromiseReject(promise, e, true); | 122 %PromiseReject(promise, e, true); |
| 193 PromiseSet(promise, kRejected, e); | |
| 194 return; | 123 return; |
| 195 } | 124 } |
| 196 | 125 |
| 197 // Resolution is a native promise and if it's already resolved or | 126 // Resolution is a native promise and if it's already resolved or |
| 198 // rejected, shortcircuit the resolution procedure by directly | 127 // rejected, shortcircuit the resolution procedure by directly |
| 199 // reusing the value from the promise. | 128 // reusing the value from the promise. |
| 200 if (%is_promise(resolution) && then === PromiseThen) { | 129 if (%is_promise(resolution) && then === PromiseThen) { |
| 201 var thenableState = GET_PRIVATE(resolution, promiseStateSymbol); | 130 var thenableState = %PromiseStatus(resolution); |
| 202 if (thenableState === kFulfilled) { | 131 if (thenableState === kFulfilled) { |
| 203 // This goes inside the if-else to save one symbol lookup in | 132 // This goes inside the if-else to save one symbol lookup in |
| 204 // the slow path. | 133 // the slow path. |
| 205 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); | 134 var thenableValue = %PromiseResult(resolution); |
| 206 %PromiseFulfill(promise, kFulfilled, thenableValue, | 135 %PromiseFulfill(promise, kFulfilled, thenableValue); |
| 207 promiseFulfillReactionsSymbol); | |
| 208 PromiseSet(promise, kFulfilled, thenableValue); | |
| 209 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); | 136 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); |
| 210 return; | 137 return; |
| 211 } else if (thenableState === kRejected) { | 138 } else if (thenableState === kRejected) { |
| 212 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); | 139 var thenableValue = %PromiseResult(resolution); |
| 213 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { | 140 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { |
| 214 // Promise has already been rejected, but had no handler. | 141 // Promise has already been rejected, but had no handler. |
| 215 // Revoke previously triggered reject event. | 142 // Revoke previously triggered reject event. |
| 216 %PromiseRevokeReject(resolution); | 143 %PromiseRevokeReject(resolution); |
| 217 } | 144 } |
| 218 // Don't cause a debug event as this case is forwarding a rejection | 145 // Don't cause a debug event as this case is forwarding a rejection |
| 219 %PromiseReject(promise, thenableValue, false); | 146 %PromiseReject(promise, thenableValue, false); |
| 220 PromiseSet(promise, kRejected, thenableValue); | |
| 221 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 147 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
| 222 return; | 148 return; |
| 223 } | 149 } |
| 224 } | 150 } |
| 225 | 151 |
| 226 if (IS_CALLABLE(then)) { | 152 if (IS_CALLABLE(then)) { |
| 227 if (DEBUG_IS_ACTIVE && %is_promise(resolution)) { | 153 if (DEBUG_IS_ACTIVE && %is_promise(resolution)) { |
| 228 // Mark the dependency of the new promise on the resolution | 154 // Mark the dependency of the new promise on the resolution |
| 229 SET_PRIVATE(resolution, promiseHandledBySymbol, promise); | 155 SET_PRIVATE(resolution, promiseHandledBySymbol, promise); |
| 230 } | 156 } |
| 231 %EnqueuePromiseResolveThenableJob(promise, resolution, then); | 157 %EnqueuePromiseResolveThenableJob(promise, resolution, then); |
| 232 return; | 158 return; |
| 233 } | 159 } |
| 234 } | 160 } |
| 235 %PromiseFulfill(promise, kFulfilled, resolution, | 161 %PromiseFulfill(promise, kFulfilled, resolution); |
| 236 promiseFulfillReactionsSymbol); | |
| 237 PromiseSet(promise, kFulfilled, resolution); | |
| 238 } | 162 } |
| 239 | 163 |
| 240 // Only used by async-await.js | 164 // Only used by async-await.js |
| 241 function RejectPromise(promise, reason, debugEvent) { | 165 function RejectPromise(promise, reason, debugEvent) { |
| 242 %PromiseReject(promise, reason, debugEvent); | 166 %PromiseReject(promise, reason, debugEvent); |
| 243 PromiseSet(promise, kRejected, reason); | |
| 244 } | 167 } |
| 245 | 168 |
| 246 // Export to bindings | 169 // Export to bindings |
| 247 function DoRejectPromise(promise, reason) { | 170 function DoRejectPromise(promise, reason) { |
| 248 %PromiseReject(promise, reason, true); | 171 %PromiseReject(promise, reason, true); |
| 249 PromiseSet(promise, kRejected, reason); | |
| 250 } | 172 } |
| 251 | 173 |
| 252 // The resultCapability.promise is only ever fulfilled internally, | 174 // The resultCapability.promise is only ever fulfilled internally, |
| 253 // so we don't need the closures to protect against accidentally | 175 // so we don't need the closures to protect against accidentally |
| 254 // calling them multiple times. | 176 // calling them multiple times. |
| 255 function CreateInternalPromiseCapability() { | 177 function CreateInternalPromiseCapability() { |
| 256 return { | 178 return { |
| 257 promise: PromiseCreate(), | 179 promise: %promise_internal_constructor(), |
| 258 resolve: UNDEFINED, | 180 resolve: UNDEFINED, |
| 259 reject: UNDEFINED | 181 reject: UNDEFINED |
| 260 }; | 182 }; |
| 261 } | 183 } |
| 262 | 184 |
| 263 // ES#sec-newpromisecapability | 185 // ES#sec-newpromisecapability |
| 264 // NewPromiseCapability ( C ) | 186 // NewPromiseCapability ( C ) |
| 265 function NewPromiseCapability(C, debugEvent) { | 187 function NewPromiseCapability(C, debugEvent) { |
| 266 if (C === GlobalPromise) { | 188 if (C === GlobalPromise) { |
| 267 // Optimized case, avoid extra closure. | 189 // Optimized case, avoid extra closure. |
| 268 var promise = PromiseCreate(); | 190 var promise = %promise_internal_constructor(); |
| 269 // TODO(gsathya): Remove container for callbacks when this is | 191 // TODO(gsathya): Remove container for callbacks when this is |
| 270 // moved to CPP/TF. | 192 // moved to CPP/TF. |
| 271 var callbacks = %create_resolving_functions(promise, debugEvent); | 193 var callbacks = %create_resolving_functions(promise, debugEvent); |
| 272 return { | 194 return { |
| 273 promise: promise, | 195 promise: promise, |
| 274 resolve: callbacks[kResolveCallback], | 196 resolve: callbacks[kResolveCallback], |
| 275 reject: callbacks[kRejectCallback] | 197 reject: callbacks[kRejectCallback] |
| 276 }; | 198 }; |
| 277 } | 199 } |
| 278 | 200 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 291 } | 213 } |
| 292 | 214 |
| 293 // ES#sec-promise.reject | 215 // ES#sec-promise.reject |
| 294 // Promise.reject ( x ) | 216 // Promise.reject ( x ) |
| 295 function PromiseReject(r) { | 217 function PromiseReject(r) { |
| 296 if (!IS_RECEIVER(this)) { | 218 if (!IS_RECEIVER(this)) { |
| 297 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 219 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
| 298 } | 220 } |
| 299 if (this === GlobalPromise) { | 221 if (this === GlobalPromise) { |
| 300 // Optimized case, avoid extra closure. | 222 // Optimized case, avoid extra closure. |
| 301 var promise = PromiseCreateAndSet(kRejected, r); | 223 var promise = %promise_create_and_set(kRejected, r); |
| 302 // Trigger debug events if the debugger is on, as Promise.reject is | 224 // Trigger debug events if the debugger is on, as Promise.reject is |
| 303 // equivalent to throwing an exception directly. | 225 // equivalent to throwing an exception directly. |
| 304 %PromiseRejectEventFromStack(promise, r); | 226 %PromiseRejectEventFromStack(promise, r); |
| 305 return promise; | 227 return promise; |
| 306 } else { | 228 } else { |
| 307 var promiseCapability = NewPromiseCapability(this, true); | 229 var promiseCapability = NewPromiseCapability(this, true); |
| 308 %_Call(promiseCapability.reject, UNDEFINED, r); | 230 %_Call(promiseCapability.reject, UNDEFINED, r); |
| 309 return promiseCapability.promise; | 231 return promiseCapability.promise; |
| 310 } | 232 } |
| 311 } | 233 } |
| 312 | 234 |
| 313 function PerformPromiseThen(promise, onResolve, onReject, resultCapability) { | |
| 314 if (!IS_CALLABLE(onResolve)) onResolve = PromiseIdResolveHandler; | |
| 315 if (!IS_CALLABLE(onReject)) onReject = PromiseIdRejectHandler; | |
| 316 | |
| 317 var status = GET_PRIVATE(promise, promiseStateSymbol); | |
| 318 switch (status) { | |
| 319 case kPending: | |
| 320 PromiseAttachCallbacks(promise, resultCapability, onResolve, onReject); | |
| 321 break; | |
| 322 case kFulfilled: | |
| 323 %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol), | |
| 324 onResolve, resultCapability, kFulfilled); | |
| 325 break; | |
| 326 case kRejected: | |
| 327 if (!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { | |
| 328 // Promise has already been rejected, but had no handler. | |
| 329 // Revoke previously triggered reject event. | |
| 330 %PromiseRevokeReject(promise); | |
| 331 } | |
| 332 %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol), | |
| 333 onReject, resultCapability, kRejected); | |
| 334 break; | |
| 335 } | |
| 336 | |
| 337 // Mark this promise as having handler. | |
| 338 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); | |
| 339 return resultCapability.promise; | |
| 340 } | |
| 341 | |
| 342 // ES#sec-promise.prototype.then | |
| 343 // Promise.prototype.then ( onFulfilled, onRejected ) | |
| 344 // Multi-unwrapped chaining with thenable coercion. | |
| 345 function PromiseThen(onResolve, onReject) { | |
| 346 if (!%is_promise(this)) { | |
| 347 throw %make_type_error(kNotAPromise, this); | |
| 348 } | |
| 349 | |
| 350 var constructor = SpeciesConstructor(this, GlobalPromise); | |
| 351 var resultCapability; | |
| 352 if (constructor === GlobalPromise) { | |
| 353 resultCapability = CreateInternalPromiseCapability(); | |
| 354 } else { | |
| 355 // Pass false for debugEvent so .then chaining does not trigger | |
| 356 // redundant ExceptionEvents. | |
| 357 resultCapability = NewPromiseCapability(constructor, false); | |
| 358 } | |
| 359 return PerformPromiseThen(this, onResolve, onReject, resultCapability); | |
| 360 } | |
| 361 | |
| 362 // ES#sec-promise.prototype.catch | 235 // ES#sec-promise.prototype.catch |
| 363 // Promise.prototype.catch ( onRejected ) | 236 // Promise.prototype.catch ( onRejected ) |
| 364 function PromiseCatch(onReject) { | 237 function PromiseCatch(onReject) { |
| 365 return this.then(UNDEFINED, onReject); | 238 return this.then(UNDEFINED, onReject); |
| 366 } | 239 } |
| 367 | 240 |
| 368 // Combinators. | 241 // Combinators. |
| 369 | 242 |
| 370 // ES#sec-promise.resolve | 243 // ES#sec-promise.resolve |
| 371 // Promise.resolve ( x ) | 244 // Promise.resolve ( x ) |
| 372 function PromiseResolve(x) { | 245 function PromiseResolve(x) { |
| 373 if (!IS_RECEIVER(this)) { | 246 if (!IS_RECEIVER(this)) { |
| 374 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 247 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
| 375 } | 248 } |
| 376 if (%is_promise(x) && x.constructor === this) return x; | 249 if (%is_promise(x) && x.constructor === this) return x; |
| 377 | 250 |
| 378 // Avoid creating resolving functions. | 251 // Avoid creating resolving functions. |
| 379 if (this === GlobalPromise) { | 252 if (this === GlobalPromise) { |
| 380 var promise = PromiseCreate(); | 253 var promise = %promise_internal_constructor(); |
| 381 ResolvePromise(promise, x); | 254 ResolvePromise(promise, x); |
| 382 return promise; | 255 return promise; |
| 383 } | 256 } |
| 384 | 257 |
| 385 // debugEvent is not so meaningful here as it will be resolved | 258 // debugEvent is not so meaningful here as it will be resolved |
| 386 var promiseCapability = NewPromiseCapability(this, true); | 259 var promiseCapability = NewPromiseCapability(this, true); |
| 387 %_Call(promiseCapability.resolve, UNDEFINED, x); | 260 %_Call(promiseCapability.resolve, UNDEFINED, x); |
| 388 return promiseCapability.promise; | 261 return promiseCapability.promise; |
| 389 } | 262 } |
| 390 | 263 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 // with another Promise, or an intermediate, hidden, throwaway Promise | 386 // with another Promise, or an intermediate, hidden, throwaway Promise |
| 514 // within async/await), then recurse on the outer Promise. | 387 // within async/await), then recurse on the outer Promise. |
| 515 // In this case, the dependency is one possible way that the Promise | 388 // In this case, the dependency is one possible way that the Promise |
| 516 // could be resolved, so it does not subsume the other following cases. | 389 // could be resolved, so it does not subsume the other following cases. |
| 517 var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol); | 390 var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol); |
| 518 if (outerPromise && | 391 if (outerPromise && |
| 519 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) { | 392 PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) { |
| 520 return true; | 393 return true; |
| 521 } | 394 } |
| 522 | 395 |
| 523 var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); | 396 if (!%is_promise(promise)) return false; |
| 524 var deferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol); | 397 |
| 398 var queue = %PromiseRejectReactions(promise); |
| 399 var deferred = %PromiseDeferred(promise); |
| 525 | 400 |
| 526 if (IS_UNDEFINED(queue)) return false; | 401 if (IS_UNDEFINED(queue)) return false; |
| 527 | 402 |
| 528 if (!IS_ARRAY(queue)) { | 403 if (!IS_ARRAY(queue)) { |
| 529 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred); | 404 return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred); |
| 530 } | 405 } |
| 531 | 406 |
| 532 for (var i = 0; i < queue.length; i += 2) { | 407 for (var i = 0; i < queue.length; i++) { |
| 533 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) { | 408 if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], deferred[i])) { |
| 534 return true; | 409 return true; |
| 535 } | 410 } |
| 536 } | 411 } |
| 537 return false; | 412 return false; |
| 538 } | 413 } |
| 539 | 414 |
| 540 // Return whether the promise will be handled by a user-defined reject | 415 // Return whether the promise will be handled by a user-defined reject |
| 541 // handler somewhere down the promise chain. For this, we do a depth-first | 416 // handler somewhere down the promise chain. For this, we do a depth-first |
| 542 // search for a reject handler that's not the default PromiseIdRejectHandler. | 417 // search for a reject handler that's not the default PromiseIdRejectHandler. |
| 543 // This function also traverses dependencies of one Promise on another, | 418 // This function also traverses dependencies of one Promise on another, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 561 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ | 436 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ |
| 562 "reject", PromiseReject, | 437 "reject", PromiseReject, |
| 563 "all", PromiseAll, | 438 "all", PromiseAll, |
| 564 "race", PromiseRace, | 439 "race", PromiseRace, |
| 565 "resolve", PromiseResolve | 440 "resolve", PromiseResolve |
| 566 ]); | 441 ]); |
| 567 | 442 |
| 568 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies); | 443 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies); |
| 569 | 444 |
| 570 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ | 445 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
| 571 "then", PromiseThen, | |
| 572 "catch", PromiseCatch | 446 "catch", PromiseCatch |
| 573 ]); | 447 ]); |
| 574 | 448 |
| 575 %InstallToContext([ | 449 %InstallToContext([ |
| 576 "promise_catch", PromiseCatch, | 450 "promise_catch", PromiseCatch, |
| 577 "promise_create", PromiseCreate, | 451 "promise_create", PromiseCreate, |
| 578 "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, | 452 "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, |
| 579 "promise_reject", DoRejectPromise, | 453 "promise_reject", DoRejectPromise, |
| 580 // TODO(gsathya): Remove this once we update the promise builtin. | 454 // TODO(gsathya): Remove this once we update the promise builtin. |
| 581 "promise_internal_reject", RejectPromise, | 455 "promise_internal_reject", RejectPromise, |
| 582 "promise_resolve", ResolvePromise, | 456 "promise_resolve", ResolvePromise, |
| 583 "promise_then", PromiseThen, | 457 "promise_then", PromiseThen, |
| 584 "promise_handle", PromiseHandle, | 458 "promise_handle", PromiseHandle, |
| 585 "promise_debug_get_info", PromiseDebugGetInfo | 459 "promise_debug_get_info", PromiseDebugGetInfo, |
| 460 "new_promise_capability", NewPromiseCapability, |
| 461 "internal_promise_capability", CreateInternalPromiseCapability, |
| 462 "promise_id_resolve_handler", PromiseIdResolveHandler, |
| 463 "promise_id_reject_handler", PromiseIdRejectHandler |
| 586 ]); | 464 ]); |
| 587 | 465 |
| 588 // This allows extras to create promises quickly without building extra | 466 // This allows extras to create promises quickly without building extra |
| 589 // resolve/reject closures, and allows them to later resolve and reject any | 467 // resolve/reject closures, and allows them to later resolve and reject any |
| 590 // promise without having to hold on to those closures forever. | 468 // promise without having to hold on to those closures forever. |
| 591 utils.InstallFunctions(extrasUtils, 0, [ | 469 utils.InstallFunctions(extrasUtils, 0, [ |
| 592 "createPromise", PromiseCreate, | 470 "createPromise", PromiseCreate, |
| 593 "resolvePromise", ResolvePromise, | 471 "resolvePromise", ResolvePromise, |
| 594 "rejectPromise", DoRejectPromise, | 472 "rejectPromise", DoRejectPromise, |
| 595 "markPromiseAsHandled", MarkPromiseAsHandled | 473 "markPromiseAsHandled", MarkPromiseAsHandled |
| 596 ]); | 474 ]); |
| 597 | 475 |
| 598 utils.Export(function(to) { | 476 utils.Export(function(to) { |
| 599 to.PromiseCreate = PromiseCreate; | 477 to.PromiseCreate = PromiseCreate; |
| 600 to.PromiseThen = PromiseThen; | 478 to.PromiseThen = PromiseThen; |
| 601 | 479 |
| 602 to.CreateInternalPromiseCapability = CreateInternalPromiseCapability; | 480 to.CreateInternalPromiseCapability = CreateInternalPromiseCapability; |
| 603 to.PerformPromiseThen = PerformPromiseThen; | |
| 604 to.ResolvePromise = ResolvePromise; | 481 to.ResolvePromise = ResolvePromise; |
| 605 to.RejectPromise = RejectPromise; | 482 to.RejectPromise = RejectPromise; |
| 606 }); | 483 }); |
| 607 | 484 |
| 608 }) | 485 }) |
| OLD | NEW |