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 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 | 37 |
| 38 // [[PromiseState]] values: | 38 // [[PromiseState]] values: |
| 39 const kPending = 0; | 39 const kPending = 0; |
| 40 const kFulfilled = +1; | 40 const kFulfilled = +1; |
| 41 const kRejected = -1; | 41 const kRejected = -1; |
| 42 | 42 |
| 43 var lastMicrotaskId = 0; | 43 var lastMicrotaskId = 0; |
| 44 | 44 |
| 45 // ES#sec-createresolvingfunctions | 45 // ES#sec-createresolvingfunctions |
| 46 // CreateResolvingFunctions ( promise ) | 46 // CreateResolvingFunctions ( promise ) |
| 47 function CreateResolvingFunctions(promise) { | 47 function CreateResolvingFunctions(promise, suppressDebugEvent) { |
| 48 var alreadyResolved = false; | 48 var alreadyResolved = false; |
| 49 | 49 |
| 50 // ES#sec-promise-resolve-functions | 50 // ES#sec-promise-resolve-functions |
| 51 // Promise Resolve Functions | 51 // Promise Resolve Functions |
| 52 var resolve = value => { | 52 var resolve = value => { |
| 53 if (alreadyResolved === true) return; | 53 if (alreadyResolved === true) return; |
| 54 alreadyResolved = true; | 54 alreadyResolved = true; |
| 55 ResolvePromise(promise, value); | 55 ResolvePromise(promise, value); |
| 56 }; | 56 }; |
| 57 | 57 |
| 58 // ES#sec-promise-reject-functions | 58 // ES#sec-promise-reject-functions |
| 59 // Promise Reject Functions | 59 // Promise Reject Functions |
| 60 var reject = reason => { | 60 var reject = reason => { |
| 61 if (alreadyResolved === true) return; | 61 if (alreadyResolved === true) return; |
| 62 alreadyResolved = true; | 62 alreadyResolved = true; |
| 63 RejectPromise(promise, reason); | 63 RejectPromise(promise, reason, suppressDebugEvent); |
| 64 }; | 64 }; |
| 65 | 65 |
| 66 return { | 66 return { |
| 67 __proto__: null, | 67 __proto__: null, |
| 68 resolve: resolve, | 68 resolve: resolve, |
| 69 reject: reject | 69 reject: reject |
| 70 }; | 70 }; |
| 71 } | 71 } |
| 72 | 72 |
| 73 | 73 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 promiseFulfillReactionsSymbol); | 261 promiseFulfillReactionsSymbol); |
| 262 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); | 262 SET_PRIVATE(promise, promiseHasHandlerSymbol, true); |
| 263 return; | 263 return; |
| 264 } else if (thenableState === kRejected) { | 264 } else if (thenableState === kRejected) { |
| 265 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); | 265 var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol); |
| 266 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { | 266 if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) { |
| 267 // Promise has already been rejected, but had no handler. | 267 // Promise has already been rejected, but had no handler. |
| 268 // Revoke previously triggered reject event. | 268 // Revoke previously triggered reject event. |
| 269 %PromiseRevokeReject(resolution); | 269 %PromiseRevokeReject(resolution); |
| 270 } | 270 } |
| 271 RejectPromise(promise, thenableValue); | 271 RejectPromise(promise, thenableValue, true); |
| 272 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); | 272 SET_PRIVATE(resolution, promiseHasHandlerSymbol, true); |
| 273 return; | 273 return; |
| 274 } | 274 } |
| 275 } | 275 } |
| 276 | 276 |
| 277 if (IS_CALLABLE(then)) { | 277 if (IS_CALLABLE(then)) { |
| 278 // PromiseResolveThenableJob | 278 // PromiseResolveThenableJob |
| 279 var id; | 279 var id; |
| 280 var name = "PromiseResolveThenableJob"; | 280 var name = "PromiseResolveThenableJob"; |
| 281 var instrumenting = DEBUG_IS_ACTIVE; | 281 var instrumenting = DEBUG_IS_ACTIVE; |
| 282 %EnqueueMicrotask(function() { | 282 %EnqueueMicrotask(function() { |
| 283 if (instrumenting) { | 283 if (instrumenting) { |
| 284 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 284 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| 285 } | 285 } |
| 286 var callbacks = CreateResolvingFunctions(promise); | 286 var callbacks = CreateResolvingFunctions(promise, true); |
| 287 try { | 287 try { |
| 288 %_Call(then, resolution, callbacks.resolve, callbacks.reject); | 288 %_Call(then, resolution, callbacks.resolve, callbacks.reject); |
| 289 } catch (e) { | 289 } catch (e) { |
| 290 %_Call(callbacks.reject, UNDEFINED, e); | 290 %_Call(callbacks.reject, UNDEFINED, e); |
| 291 } | 291 } |
| 292 if (instrumenting) { | 292 if (instrumenting) { |
| 293 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); | 293 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
| 294 } | 294 } |
| 295 }); | 295 }); |
| 296 if (instrumenting) { | 296 if (instrumenting) { |
| 297 id = ++lastMicrotaskId; | 297 id = ++lastMicrotaskId; |
| 298 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); | 298 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
| 299 } | 299 } |
| 300 return; | 300 return; |
| 301 } | 301 } |
| 302 } | 302 } |
| 303 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; | 303 FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol) ; |
| 304 } | 304 } |
| 305 | 305 |
| 306 // ES#sec-rejectpromise | 306 // ES#sec-rejectpromise |
| 307 // RejectPromise ( promise, reason ) | 307 // RejectPromise ( promise, reason ) |
| 308 function RejectPromise(promise, reason) { | 308 function RejectPromise(promise, reason, suppressDebugEvent) { |
|
adamk
2016/08/23 22:29:27
It's confusing to me that %PromiseRejectEvent take
Dan Ehrenberg
2016/08/23 23:28:38
Good point. Switched it to debugEvent as a positiv
| |
| 309 // Check promise status to confirm that this reject has an effect. | 309 // Check promise status to confirm that this reject has an effect. |
| 310 // Call runtime for callbacks to the debugger or for unhandled reject. | 310 // Call runtime for callbacks to the debugger or for unhandled reject. |
| 311 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { | 311 if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
| 312 var debug_is_active = DEBUG_IS_ACTIVE; | 312 var debugEvent = DEBUG_IS_ACTIVE && !suppressDebugEvent |
| 313 if (debug_is_active || | 313 if (debugEvent || |
| 314 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { | 314 !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
| 315 %PromiseRejectEvent(promise, reason, debug_is_active); | 315 %PromiseRejectEvent(promise, reason, debugEvent, false); |
| 316 } | 316 } |
| 317 } | 317 } |
| 318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) | 318 FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol) |
| 319 } | 319 } |
| 320 | 320 |
| 321 // ES#sec-newpromisecapability | 321 // ES#sec-newpromisecapability |
| 322 // NewPromiseCapability ( C ) | 322 // NewPromiseCapability ( C ) |
| 323 function NewPromiseCapability(C) { | 323 function NewPromiseCapability(C, suppressDebugEvent) { |
| 324 if (C === GlobalPromise) { | 324 if (C === GlobalPromise) { |
| 325 // Optimized case, avoid extra closure. | 325 // Optimized case, avoid extra closure. |
| 326 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); | 326 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
| 327 var callbacks = CreateResolvingFunctions(promise); | 327 var callbacks = CreateResolvingFunctions(promise, suppressDebugEvent); |
| 328 return { | 328 return { |
| 329 promise: promise, | 329 promise: promise, |
| 330 resolve: callbacks.resolve, | 330 resolve: callbacks.resolve, |
| 331 reject: callbacks.reject | 331 reject: callbacks.reject |
| 332 }; | 332 }; |
| 333 } | 333 } |
| 334 | 334 |
| 335 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; | 335 var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED }; |
| 336 result.promise = new C((resolve, reject) => { | 336 result.promise = new C((resolve, reject) => { |
| 337 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) | 337 if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject)) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 348 | 348 |
| 349 // ES#sec-promise.reject | 349 // ES#sec-promise.reject |
| 350 // Promise.reject ( x ) | 350 // Promise.reject ( x ) |
| 351 function PromiseReject(r) { | 351 function PromiseReject(r) { |
| 352 if (!IS_RECEIVER(this)) { | 352 if (!IS_RECEIVER(this)) { |
| 353 throw %make_type_error(kCalledOnNonObject, PromiseResolve); | 353 throw %make_type_error(kCalledOnNonObject, PromiseResolve); |
| 354 } | 354 } |
| 355 if (this === GlobalPromise) { | 355 if (this === GlobalPromise) { |
| 356 // Optimized case, avoid extra closure. | 356 // Optimized case, avoid extra closure. |
| 357 var promise = PromiseCreateAndSet(kRejected, r); | 357 var promise = PromiseCreateAndSet(kRejected, r); |
| 358 // The debug event for this would always be an uncaught promise reject, | 358 // Trigger debug events if the debugger is on, as Promise.reject is |
| 359 // which is usually simply noise. Do not trigger that debug event. | 359 // equivalent to throwing an exception directly. |
| 360 %PromiseRejectEvent(promise, r, false); | 360 %PromiseRejectEvent(promise, r, DEBUG_IS_ACTIVE, true); |
| 361 return promise; | 361 return promise; |
| 362 } else { | 362 } else { |
| 363 var promiseCapability = NewPromiseCapability(this); | 363 var promiseCapability = NewPromiseCapability(this); |
| 364 %_Call(promiseCapability.reject, UNDEFINED, r); | 364 %_Call(promiseCapability.reject, UNDEFINED, r); |
| 365 return promiseCapability.promise; | 365 return promiseCapability.promise; |
| 366 } | 366 } |
| 367 } | 367 } |
| 368 | 368 |
| 369 // Shortcut Promise.reject and Promise.resolve() implementations, used by | 369 // Shortcut Promise.reject and Promise.resolve() implementations, used by |
| 370 // Async Functions implementation. | 370 // Async Functions implementation. |
| 371 function PromiseCreateRejected(r) { | 371 function PromiseCreateRejected(r) { |
| 372 return %_Call(PromiseReject, GlobalPromise, r); | 372 var promise = PromiseCreateAndSet(kRejected, r); |
| 373 // This is called from the desugaring of async/await; no reason to | |
| 374 // create a redundant reject event. | |
| 375 %PromiseRejectEvent(promise, r, false, false); | |
|
adamk
2016/08/23 22:29:27
Passing two bools is not ideal, see suggestion in
Dan Ehrenberg
2016/08/23 23:28:38
Fixed, now separated out a different function.
| |
| 376 return promise; | |
| 373 } | 377 } |
| 374 | 378 |
| 375 function PromiseCreateResolved(value) { | 379 function PromiseCreateResolved(value) { |
| 376 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); | 380 var promise = PromiseInit(new GlobalPromise(promiseRawSymbol)); |
| 377 var resolveResult = ResolvePromise(promise, value); | 381 var resolveResult = ResolvePromise(promise, value); |
| 378 return promise; | 382 return promise; |
| 379 } | 383 } |
| 380 | 384 |
| 381 function PromiseCastResolved(value) { | 385 function PromiseCastResolved(value) { |
| 382 if (IsPromise(value)) { | 386 if (IsPromise(value)) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 // ES#sec-promise.prototype.then | 424 // ES#sec-promise.prototype.then |
| 421 // Promise.prototype.then ( onFulfilled, onRejected ) | 425 // Promise.prototype.then ( onFulfilled, onRejected ) |
| 422 // Multi-unwrapped chaining with thenable coercion. | 426 // Multi-unwrapped chaining with thenable coercion. |
| 423 function PromiseThen(onResolve, onReject) { | 427 function PromiseThen(onResolve, onReject) { |
| 424 var status = GET_PRIVATE(this, promiseStateSymbol); | 428 var status = GET_PRIVATE(this, promiseStateSymbol); |
| 425 if (IS_UNDEFINED(status)) { | 429 if (IS_UNDEFINED(status)) { |
| 426 throw %make_type_error(kNotAPromise, this); | 430 throw %make_type_error(kNotAPromise, this); |
| 427 } | 431 } |
| 428 | 432 |
| 429 var constructor = SpeciesConstructor(this, GlobalPromise); | 433 var constructor = SpeciesConstructor(this, GlobalPromise); |
| 430 var resultCapability = NewPromiseCapability(constructor); | 434 var resultCapability = NewPromiseCapability(constructor, true); |
| 431 return PerformPromiseThen(this, onResolve, onReject, resultCapability); | 435 return PerformPromiseThen(this, onResolve, onReject, resultCapability); |
| 432 } | 436 } |
| 433 | 437 |
| 434 // ES#sec-promise.prototype.catch | 438 // ES#sec-promise.prototype.catch |
| 435 // Promise.prototype.catch ( onRejected ) | 439 // Promise.prototype.catch ( onRejected ) |
| 436 function PromiseCatch(onReject) { | 440 function PromiseCatch(onReject) { |
| 437 return this.then(UNDEFINED, onReject); | 441 return this.then(UNDEFINED, onReject); |
| 438 } | 442 } |
| 439 | 443 |
| 440 // Combinators. | 444 // Combinators. |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 617 utils.Export(function(to) { | 621 utils.Export(function(to) { |
| 618 to.PromiseCastResolved = PromiseCastResolved; | 622 to.PromiseCastResolved = PromiseCastResolved; |
| 619 to.PromiseThen = PromiseThen; | 623 to.PromiseThen = PromiseThen; |
| 620 | 624 |
| 621 to.GlobalPromise = GlobalPromise; | 625 to.GlobalPromise = GlobalPromise; |
| 622 to.NewPromiseCapability = NewPromiseCapability; | 626 to.NewPromiseCapability = NewPromiseCapability; |
| 623 to.PerformPromiseThen = PerformPromiseThen; | 627 to.PerformPromiseThen = PerformPromiseThen; |
| 624 }); | 628 }); |
| 625 | 629 |
| 626 }) | 630 }) |
| OLD | NEW |