Chromium Code Reviews| 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 promiseCombinedDeferredSymbol = | 15 var promiseCombinedDeferredSymbol = |
| 16 utils.ImportNow("promise_combined_deferred_symbol"); | 16 utils.ImportNow("promise_combined_deferred_symbol"); |
| 17 var promiseResolvingFunctionCalledSymbol = | |
| 18 utils.ImportNow("promise_resolving_function_called_symbol"); | |
| 17 var promiseHasHandlerSymbol = | 19 var promiseHasHandlerSymbol = |
| 18 utils.ImportNow("promise_has_handler_symbol"); | 20 utils.ImportNow("promise_has_handler_symbol"); |
| 19 var promiseRejectReactionsSymbol = | 21 var promiseRejectReactionsSymbol = |
| 20 utils.ImportNow("promise_reject_reactions_symbol"); | 22 utils.ImportNow("promise_reject_reactions_symbol"); |
| 21 var promiseFulfillReactionsSymbol = | 23 var promiseFulfillReactionsSymbol = |
| 22 utils.ImportNow("promise_fulfill_reactions_symbol"); | 24 utils.ImportNow("promise_fulfill_reactions_symbol"); |
| 23 var promiseDeferredReactionsSymbol = | 25 var promiseDeferredReactionsSymbol = |
| 24 utils.ImportNow("promise_deferred_reactions_symbol"); | 26 utils.ImportNow("promise_deferred_reactions_symbol"); |
| 25 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); | 27 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
| 26 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); | 28 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
| 27 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); | 29 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
| 28 var SpeciesConstructor; | 30 var SpeciesConstructor; |
| 29 var speciesSymbol = utils.ImportNow("species_symbol"); | 31 var speciesSymbol = utils.ImportNow("species_symbol"); |
| 30 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 32 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
| 31 | 33 |
| 32 utils.Import(function(from) { | 34 utils.Import(function(from) { |
| 33 SpeciesConstructor = from.SpeciesConstructor; | 35 SpeciesConstructor = from.SpeciesConstructor; |
| 34 }); | 36 }); |
| 35 | 37 |
| 36 // ------------------------------------------------------------------- | 38 // ------------------------------------------------------------------- |
| 37 | 39 |
| 38 // [[PromiseState]] values: | 40 // [[PromiseState]] values: |
| 39 const kPending = 0; | 41 const kPending = 0; |
| 40 const kFulfilled = +1; | 42 const kFulfilled = +1; |
| 41 const kRejected = -1; | 43 const kRejected = -1; |
| 42 | 44 |
| 43 var lastMicrotaskId = 0; | 45 var lastMicrotaskId = 0; |
| 44 | 46 |
| 45 // ES#sec-createresolvingfunctions | |
| 46 // CreateResolvingFunctions ( promise ) | |
| 47 function CreateResolvingFunctions(promise, debugEvent) { | |
|
Dan Ehrenberg
2016/08/30 22:29:28
The spec calls this in two places, in the promise
| |
| 48 var alreadyResolved = false; | |
| 49 | |
| 50 // ES#sec-promise-resolve-functions | |
| 51 // Promise Resolve Functions | |
| 52 var resolve = value => { | |
| 53 if (alreadyResolved === true) return; | |
| 54 alreadyResolved = true; | |
| 55 ResolvePromise(promise, value); | |
| 56 }; | |
| 57 | |
| 58 // ES#sec-promise-reject-functions | |
| 59 // Promise Reject Functions | |
| 60 var reject = reason => { | |
| 61 if (alreadyResolved === true) return; | |
| 62 alreadyResolved = true; | |
| 63 RejectPromise(promise, reason, debugEvent); | |
| 64 }; | |
| 65 | |
| 66 return { | |
| 67 __proto__: null, | |
| 68 resolve: resolve, | |
| 69 reject: reject | |
| 70 }; | |
| 71 } | |
| 72 | |
| 73 | 47 |
| 74 // ES#sec-promise-executor | 48 // ES#sec-promise-executor |
| 75 // Promise ( executor ) | 49 // Promise ( executor ) |
| 76 var GlobalPromise = function Promise(executor) { | 50 var GlobalPromise = function Promise(executor) { |
| 77 if (executor === promiseRawSymbol) { | 51 if (executor === promiseRawSymbol) { |
| 78 return %_NewObject(GlobalPromise, new.target); | 52 return %_NewObject(GlobalPromise, new.target); |
| 79 } | 53 } |
| 80 if (IS_UNDEFINED(new.target)) throw %make_type_error(kNotAPromise, this); | 54 if (IS_UNDEFINED(new.target)) throw %make_type_error(kNotAPromise, this); |
| 81 if (!IS_CALLABLE(executor)) { | 55 if (!IS_CALLABLE(executor)) { |
| 82 throw %make_type_error(kResolverNotAFunction, executor); | 56 throw %make_type_error(kResolverNotAFunction, executor); |
| 83 } | 57 } |
| 84 | 58 |
| 85 var promise = PromiseInit(%_NewObject(GlobalPromise, new.target)); | 59 var promise = PromiseInit(%_NewObject(GlobalPromise, new.target)); |
| 86 // Calling the reject function would be a new exception, so debugEvent = true | 60 // Calling the reject function would be a new exception, so debugEvent = true |
| 87 var callbacks = CreateResolvingFunctions(promise, true); | |
| 88 var debug_is_active = DEBUG_IS_ACTIVE; | 61 var debug_is_active = DEBUG_IS_ACTIVE; |
| 62 var reject = reason => RejectPromise(promise, reason, true, true); | |
|
Dan Ehrenberg
2016/08/30 22:29:28
I wonder, how is performance if you call Function.
| |
| 89 try { | 63 try { |
| 90 if (debug_is_active) %DebugPushPromise(promise); | 64 if (debug_is_active) %DebugPushPromise(promise); |
| 91 executor(callbacks.resolve, callbacks.reject); | 65 executor(value => ResolvePromise(promise, value, true), |
| 66 reject); | |
| 92 } %catch (e) { // Natives syntax to mark this catch block. | 67 } %catch (e) { // Natives syntax to mark this catch block. |
| 93 %_Call(callbacks.reject, UNDEFINED, e); | 68 %_Call(reject, UNDEFINED, e); |
| 94 } finally { | 69 } finally { |
| 95 if (debug_is_active) %DebugPopPromise(); | 70 if (debug_is_active) %DebugPopPromise(); |
| 96 } | 71 } |
| 97 | 72 |
| 98 return promise; | 73 return promise; |
| 99 } | 74 } |
| 100 | 75 |
| 101 // Core functionality. | 76 // Core functionality. |
| 102 | 77 |
| 103 function PromiseSet(promise, status, value) { | 78 function PromiseSet(promise, status, value) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 119 // There are 2 possible states for this symbol -- | 94 // There are 2 possible states for this symbol -- |
| 120 // 1) UNDEFINED -- This is the zero state, no deferred object is | 95 // 1) UNDEFINED -- This is the zero state, no deferred object is |
| 121 // attached to this symbol. When we want to add a new deferred we | 96 // attached to this symbol. When we want to add a new deferred we |
| 122 // directly attach it to this symbol. | 97 // directly attach it to this symbol. |
| 123 // 2) symbol with attached deferred object -- New deferred objects | 98 // 2) symbol with attached deferred object -- New deferred objects |
| 124 // are not attached to this symbol, but instead they are directly | 99 // are not attached to this symbol, but instead they are directly |
| 125 // attached to the resolve, reject callback arrays. At this point, | 100 // attached to the resolve, reject callback arrays. At this point, |
| 126 // the deferred symbol's state is stale, and the deferreds should be | 101 // the deferred symbol's state is stale, and the deferreds should be |
| 127 // read from the reject, resolve callbacks. | 102 // read from the reject, resolve callbacks. |
| 128 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED); | 103 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED); |
| 104 SET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol, UNDEFINED); | |
| 129 | 105 |
| 130 return promise; | 106 return promise; |
| 131 } | 107 } |
| 132 | 108 |
| 133 function PromiseCreateAndSet(status, value) { | 109 function PromiseCreateAndSet(status, value) { |
| 134 var promise = new GlobalPromise(promiseRawSymbol); | 110 var promise = new GlobalPromise(promiseRawSymbol); |
| 135 // If debug is active, notify about the newly created promise first. | 111 // If debug is active, notify about the newly created promise first. |
| 136 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); | 112 if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); |
| 137 return PromiseSet(promise, status, value); | 113 return PromiseSet(promise, status, value); |
| 138 } | 114 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 function IsPromise(x) { | 206 function IsPromise(x) { |
| 231 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); | 207 return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); |
| 232 } | 208 } |
| 233 | 209 |
| 234 function PromiseCreate() { | 210 function PromiseCreate() { |
| 235 return new GlobalPromise(PromiseNopResolver) | 211 return new GlobalPromise(PromiseNopResolver) |
| 236 } | 212 } |
| 237 | 213 |
| 238 // ES#sec-promise-resolve-functions | 214 // ES#sec-promise-resolve-functions |
| 239 // Promise Resolve Functions, steps 6-13 | 215 // Promise Resolve Functions, steps 6-13 |
| 240 function ResolvePromise(promise, resolution) { | 216 function ResolvePromise(promise, resolution, follow) { |
| 217 var status = GET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol); | |
| 218 if (!IS_UNDEFINED(status) && follow) return; | |
| 219 | |
| 241 if (resolution === promise) { | 220 if (resolution === promise) { |
| 242 return RejectPromise(promise, | 221 return RejectPromise(promise, |
| 243 %make_type_error(kPromiseCyclic, resolution), | 222 %make_type_error(kPromiseCyclic, resolution), |
| 244 true); | 223 true); |
| 245 } | 224 } |
| 225 | |
| 246 if (IS_RECEIVER(resolution)) { | 226 if (IS_RECEIVER(resolution)) { |
| 247 // 25.4.1.3.2 steps 8-12 | 227 // 25.4.1.3.2 steps 8-12 |
| 248 try { | 228 try { |
| 249 var then = resolution.then; | 229 var then = resolution.then; |
| 250 } catch (e) { | 230 } catch (e) { |
| 251 return RejectPromise(promise, e, true); | 231 return RejectPromise(promise, e, true); |
| 252 } | 232 } |
| 253 | 233 |
| 254 // Resolution is a native promise and if it's already resolved or | 234 // Resolution is a native promise and if it's already resolved or |
| 255 // rejected, shortcircuit the resolution procedure by directly | 235 // rejected, shortcircuit the resolution procedure by directly |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 276 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 256 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
| 277 return; | 257 return; |
| 278 } | 258 } |
| 279 } | 259 } |
| 280 | 260 |
| 281 if (IS_CALLABLE(then)) { | 261 if (IS_CALLABLE(then)) { |
| 282 // PromiseResolveThenableJob | 262 // PromiseResolveThenableJob |
| 283 var id; | 263 var id; |
| 284 var name = "PromiseResolveThenableJob"; | 264 var name = "PromiseResolveThenableJob"; |
| 285 var instrumenting = DEBUG_IS_ACTIVE; | 265 var instrumenting = DEBUG_IS_ACTIVE; |
| 266 SET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol, true); | |
| 267 | |
| 286 %EnqueueMicrotask(function() { | 268 %EnqueueMicrotask(function() { |
| 287 if (instrumenting) { | 269 if (instrumenting) { |
| 288 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 270 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| 289 } | 271 } |
| 290 // These resolving functions simply forward the exception, so | 272 // These resolving functions simply forward the exception, so |
| 291 // don't create a new debugEvent. | 273 // don't create a new debugEvent. |
| 292 var callbacks = CreateResolvingFunctions(promise, false); | 274 |
| 293 try { | 275 try { |
| 294 %_Call(then, resolution, callbacks.resolve, callbacks.reject); | 276 %_Call(then, resolution, |
| 277 value => ResolvePromise(promise, value, false), | |
| 278 reason => RejectPromise(promise, reason, false, false)); | |
| 295 } catch (e) { | 279 } catch (e) { |
| 296 %_Call(callbacks.reject, UNDEFINED, e); | 280 %_Call(reason => RejectPromise(promise, reason, false, true), UNDEFINE D, e); |
| 297 } | 281 } |
| 298 if (instrumenting) { | 282 if (instrumenting) { |
| 299 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); | 283 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
| 300 } | 284 } |
| 301 }); | 285 }); |
| 302 if (instrumenting) { | 286 if (instrumenting) { |
| 303 id = ++lastMicrotaskId; | 287 id = ++lastMicrotaskId; |
| 304 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); | 288 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
| 305 } | 289 } |
| 306 return; | 290 return; |
| 307 } | 291 } |
| 308 } | 292 } |
| 309 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; | 293 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; |
| 310 } | 294 } |
| 311 | 295 |
| 312 // ES#sec-rejectpromise | 296 // ES#sec-rejectpromise |
| 313 // RejectPromise ( promise, reason ) | 297 // RejectPromise ( promise, reason ) |
| 314 function RejectPromise(promise, reason, debugEvent) { | 298 function RejectPromise(promise, reason, debugEvent, follow) { |
|
Dan Ehrenberg
2016/08/30 22:29:28
I know I made things bad with the debugEvent param
| |
| 299 var status = GET_PRIVATE(promise, promiseResolvingFunctionCalledSymbol); | |
| 300 if (!IS_UNDEFINED(status) && follow) return; | |
| 301 | |
| 302 status = GET_PRIVATE(promise, promiseStateSymbol); | |
| 303 if (status === kFulfilled) return; | |
|
adamk
2016/08/30 23:00:35
This looks like an unrelated bit of inlining, cons
| |
| 315 // Check promise status to confirm that this reject has an effect. | 304 // Check promise status to confirm that this reject has an effect. |
| 316 // Call runtime for callbacks to the debugger or for unhandled reject. | 305 // Call runtime for callbacks to the debugger or for unhandled reject. |
| 317 // The debugEvent parameter sets whether a debug ExceptionEvent should | 306 // The debugEvent parameter sets whether a debug ExceptionEvent should |
| 318 // be triggered. It should be set to false when forwarding a rejection | 307 // be triggered. It should be set to false when forwarding a rejection |
| 319 // rather than creating a new one. | 308 // rather than creating a new one. |
| 320 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { | 309 if (status === kPending) { |
| 321 // This check is redundant with checks in the runtime, but it may help | 310 // This check is redundant with checks in the runtime, but it may help |
| 322 // avoid unnecessary runtime calls. | 311 // avoid unnecessary runtime calls. |
| 323 if ((debugEvent && DEBUG_IS_ACTIVE) || | 312 if ((debugEvent && DEBUG_IS_ACTIVE) || |
| 324 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { | 313 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
| 325 %PromiseRejectEvent(promise, reason, debugEvent); | 314 %PromiseRejectEvent(promise, reason, debugEvent); |
| 326 } | 315 } |
| 327 } | 316 } |
| 317 | |
| 328 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) | 318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) |
| 329 } | 319 } |
| 330 | 320 |
| 331 // Export to bindings | 321 // Export to bindings |
| 332 function DoRejectPromise(promise, reason) { | 322 function DoRejectPromise(promise, reason) { |
| 333 return RejectPromise(promise, reason, true); | 323 return RejectPromise(promise, reason, true); |
| 334 } | 324 } |
| 335 | 325 |
| 336 // ES#sec-newpromisecapability | 326 // ES#sec-newpromisecapability |
| 337 // NewPromiseCapability ( C ) | 327 // NewPromiseCapability ( C ) |
| 338 function NewPromiseCapability(C, debugEvent) { | 328 function NewPromiseCapability(C, debugEvent) { |
| 339 if (C === GlobalPromise) { | 329 if (C === GlobalPromise) { |
| 340 // Optimized case, avoid extra closure. | 330 // Optimized case, avoid extra closure. |
| 341 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); | 331 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
| 342 var callbacks = CreateResolvingFunctions(promise, debugEvent); | |
| 343 return { | 332 return { |
| 344 promise: promise, | 333 promise: promise, |
| 345 resolve: callbacks.resolve, | 334 resolve: value => ResolvePromise(promise, value, true), |
| 346 reject: callbacks.reject | 335 reject: reason => RejectPromise(promise, reason, debugEvent, true) |
| 347 }; | 336 }; |
| 348 } | 337 } |
| 349 | 338 |
| 350 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; | 339 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; |
| 351 result.promise = new C((resolve, reject) => { | 340 result.promise = new C((resolve, reject) => { |
| 352 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) | 341 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) |
| 353 throw %make_type_error(kPromiseExecutorAlreadyInvoked); | 342 throw %make_type_error(kPromiseExecutorAlreadyInvoked); |
| 354 result.resolve = resolve; | 343 result.resolve = resolve; |
| 355 result.reject = reject; | 344 result.reject = reject; |
| 356 }); | 345 }); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 to.PromiseCastResolved = PromiseCastResolved; | 615 to.PromiseCastResolved = PromiseCastResolved; |
| 627 to.PromiseThen = PromiseThen; | 616 to.PromiseThen = PromiseThen; |
| 628 | 617 |
| 629 to.GlobalPromise = GlobalPromise; | 618 to.GlobalPromise = GlobalPromise; |
| 630 to.NewPromiseCapability = NewPromiseCapability; | 619 to.NewPromiseCapability = NewPromiseCapability; |
| 631 to.PerformPromiseThen = PerformPromiseThen; | 620 to.PerformPromiseThen = PerformPromiseThen; |
| 632 to.RejectPromise = RejectPromise; | 621 to.RejectPromise = RejectPromise; |
| 633 }); | 622 }); |
| 634 | 623 |
| 635 }) | 624 }) |
| OLD | NEW |