Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1061)

Side by Side Diff: src/js/promise.js

Issue 2357423002: Improve stack traces for async functions (Closed)
Patch Set: Format Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 =
16 utils.ImportNow("promise_async_stack_id_symbol");
15 var promiseHandledBySymbol = 17 var promiseHandledBySymbol =
16 utils.ImportNow("promise_handled_by_symbol"); 18 utils.ImportNow("promise_handled_by_symbol");
17 var promiseForwardingHandlerSymbol = 19 var promiseForwardingHandlerSymbol =
18 utils.ImportNow("promise_forwarding_handler_symbol"); 20 utils.ImportNow("promise_forwarding_handler_symbol");
19 var promiseHasHandlerSymbol = 21 var promiseHasHandlerSymbol =
20 utils.ImportNow("promise_has_handler_symbol"); 22 utils.ImportNow("promise_has_handler_symbol");
21 var promiseRejectReactionsSymbol = 23 var promiseRejectReactionsSymbol =
22 utils.ImportNow("promise_reject_reactions_symbol"); 24 utils.ImportNow("promise_reject_reactions_symbol");
23 var promiseFulfillReactionsSymbol = 25 var promiseFulfillReactionsSymbol =
24 utils.ImportNow("promise_fulfill_reactions_symbol"); 26 utils.ImportNow("promise_fulfill_reactions_symbol");
25 var promiseDeferredReactionsSymbol = 27 var promiseDeferredReactionsSymbol =
26 utils.ImportNow("promise_deferred_reactions_symbol"); 28 utils.ImportNow("promise_deferred_reactions_symbol");
27 var promiseHandledHintSymbol = 29 var promiseHandledHintSymbol =
28 utils.ImportNow("promise_handled_hint_symbol"); 30 utils.ImportNow("promise_handled_hint_symbol");
29 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); 31 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
30 var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); 32 var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
31 var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); 33 var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
32 var SpeciesConstructor; 34 var SpeciesConstructor;
33 var speciesSymbol = utils.ImportNow("species_symbol"); 35 var speciesSymbol = utils.ImportNow("species_symbol");
34 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 36 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
37 var ObjectHasOwnProperty;
gsathya 2016/09/23 06:06:20 Is this used anywhere?
Dan Ehrenberg 2016/09/23 07:05:56 Yes, inside of HAS_PRIVATE.
35 38
36 utils.Import(function(from) { 39 utils.Import(function(from) {
40 ObjectHasOwnProperty = from.ObjectHasOwnProperty;
37 SpeciesConstructor = from.SpeciesConstructor; 41 SpeciesConstructor = from.SpeciesConstructor;
38 }); 42 });
39 43
40 // ------------------------------------------------------------------- 44 // -------------------------------------------------------------------
41 45
42 // [[PromiseState]] values: 46 // [[PromiseState]] values:
43 const kPending = 0; 47 const kPending = 0;
44 const kFulfilled = +1; 48 const kFulfilled = +1;
45 const kRejected = -1; 49 const kRejected = -1;
46 50
47 var lastMicrotaskId = 0; 51 var lastMicrotaskId = 0;
48 52
53 function PromiseNextMicrotaskID() {
54 return ++lastMicrotaskId;
55 }
56
49 // ES#sec-createresolvingfunctions 57 // ES#sec-createresolvingfunctions
50 // CreateResolvingFunctions ( promise ) 58 // CreateResolvingFunctions ( promise )
51 function CreateResolvingFunctions(promise, debugEvent) { 59 function CreateResolvingFunctions(promise, debugEvent) {
52 var alreadyResolved = false; 60 var alreadyResolved = false;
53 61
54 // ES#sec-promise-resolve-functions 62 // ES#sec-promise-resolve-functions
55 // Promise Resolve Functions 63 // Promise Resolve Functions
56 var resolve = value => { 64 var resolve = value => {
57 if (alreadyResolved === true) return; 65 if (alreadyResolved === true) return;
58 alreadyResolved = true; 66 alreadyResolved = true;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 PromiseHandle(value, tasks[i], tasks[i + 1]); 188 PromiseHandle(value, tasks[i], tasks[i + 1]);
181 } 189 }
182 } else { 190 } else {
183 PromiseHandle(value, tasks, deferreds); 191 PromiseHandle(value, tasks, deferreds);
184 } 192 }
185 if (instrumenting) { 193 if (instrumenting) {
186 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 194 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
187 } 195 }
188 }); 196 });
189 if (instrumenting) { 197 if (instrumenting) {
190 id = ++lastMicrotaskId; 198 // In an async function, reuse the existing stack related to the outer
191 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; 199 // Promise. Otherwise, e.g. in a direct call to then, save a new stack.
192 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 200 // Promises with multiple reactions with one or more of them being async
201 // functions will not get a good stack trace, as async functions require
202 // different stacks from direct Promise use, but we save and restore a
203 // stack once for all reactions. TODO(littledan): Improve this case.
204 if (!IS_UNDEFINED(deferreds) &&
205 HAS_PRIVATE(deferreds.promise, promiseHandledBySymbol) &&
206 HAS_PRIVATE(GET_PRIVATE(deferreds.promise, promiseHandledBySymbol),
207 promiseAsyncStackIDSymbol)) {
208 id = GET_PRIVATE(GET_PRIVATE(deferreds.promise, promiseHandledBySymbol),
209 promiseAsyncStackIDSymbol);
210 name = "async function";
211 } else {
212 id = PromiseNextMicrotaskID();
213 name = status === kFulfilled ? "Promise.resolve" : "Promise.reject";
214 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
215 }
193 } 216 }
194 } 217 }
195 218
196 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) { 219 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) {
197 var maybeResolveCallbacks = 220 var maybeResolveCallbacks =
198 GET_PRIVATE(promise, promiseFulfillReactionsSymbol); 221 GET_PRIVATE(promise, promiseFulfillReactionsSymbol);
199 if (IS_UNDEFINED(maybeResolveCallbacks)) { 222 if (IS_UNDEFINED(maybeResolveCallbacks)) {
200 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); 223 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
201 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); 224 SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
202 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferred); 225 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferred);
203 } else if (!IS_ARRAY(maybeResolveCallbacks)) { 226 } else if (!IS_ARRAY(maybeResolveCallbacks)) {
204 var resolveCallbacks = new InternalArray(); 227 var resolveCallbacks = new InternalArray();
205 var rejectCallbacks = new InternalArray(); 228 var rejectCallbacks = new InternalArray();
206 var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionsSymbol); 229 var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
207 230
208 resolveCallbacks.push( 231 resolveCallbacks.push(
209 maybeResolveCallbacks, existingDeferred, onResolve, deferred); 232 maybeResolveCallbacks, existingDeferred, onResolve, deferred);
210 rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol), 233 rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol),
211 existingDeferred, 234 existingDeferred,
212 onReject, 235 onReject,
213 deferred); 236 deferred);
214 237
215 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks); 238 SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
216 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks); 239 SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
240 SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED);
gsathya 2016/09/23 16:06:25 Extra symbol lookup + update here in non debug cas
Dan Ehrenberg 2016/09/23 18:11:44 If this actually made things slower, I'd argue 2 s
217 } else { 241 } else {
218 maybeResolveCallbacks.push(onResolve, deferred); 242 maybeResolveCallbacks.push(onResolve, deferred);
219 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred); 243 GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred);
220 } 244 }
221 } 245 }
222 246
223 function PromiseIdResolveHandler(x) { return x; } 247 function PromiseIdResolveHandler(x) { return x; }
224 function PromiseIdRejectHandler(r) { %_ReThrow(r); } 248 function PromiseIdRejectHandler(r) { %_ReThrow(r); }
225 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true); 249 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true);
226 250
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 309
286 if (IS_CALLABLE(then)) { 310 if (IS_CALLABLE(then)) {
287 var callbacks = CreateResolvingFunctions(promise, false); 311 var callbacks = CreateResolvingFunctions(promise, false);
288 var id, before_debug_event, after_debug_event; 312 var id, before_debug_event, after_debug_event;
289 var instrumenting = DEBUG_IS_ACTIVE; 313 var instrumenting = DEBUG_IS_ACTIVE;
290 if (instrumenting) { 314 if (instrumenting) {
291 if (IsPromise(resolution)) { 315 if (IsPromise(resolution)) {
292 // Mark the dependency of the new promise on the resolution 316 // Mark the dependency of the new promise on the resolution
293 SET_PRIVATE(resolution, promiseHandledBySymbol, promise); 317 SET_PRIVATE(resolution, promiseHandledBySymbol, promise);
294 } 318 }
295 id = ++lastMicrotaskId; 319 id = PromiseNextMicrotaskID();
296 before_debug_event = { 320 before_debug_event = {
297 type: "willHandle", 321 type: "willHandle",
298 id: id, 322 id: id,
299 name: "PromiseResolveThenableJob" 323 name: "PromiseResolveThenableJob"
300 }; 324 };
301 after_debug_event = { 325 after_debug_event = {
302 type: "didHandle", 326 type: "didHandle",
303 id: id, 327 id: id,
304 name: "PromiseResolveThenableJob" 328 name: "PromiseResolveThenableJob"
305 }; 329 };
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 utils.InstallFunctions(extrasUtils, 0, [ 688 utils.InstallFunctions(extrasUtils, 0, [
665 "createPromise", PromiseCreate, 689 "createPromise", PromiseCreate,
666 "resolvePromise", ResolvePromise, 690 "resolvePromise", ResolvePromise,
667 "rejectPromise", DoRejectPromise 691 "rejectPromise", DoRejectPromise
668 ]); 692 ]);
669 693
670 utils.Export(function(to) { 694 utils.Export(function(to) {
671 to.IsPromise = IsPromise; 695 to.IsPromise = IsPromise;
672 to.PromiseCreate = PromiseCreate; 696 to.PromiseCreate = PromiseCreate;
673 to.PromiseThen = PromiseThen; 697 to.PromiseThen = PromiseThen;
698 to.PromiseNextMicrotaskID = PromiseNextMicrotaskID;
674 699
675 to.GlobalPromise = GlobalPromise; 700 to.GlobalPromise = GlobalPromise;
676 to.NewPromiseCapability = NewPromiseCapability; 701 to.NewPromiseCapability = NewPromiseCapability;
677 to.PerformPromiseThen = PerformPromiseThen; 702 to.PerformPromiseThen = PerformPromiseThen;
678 to.ResolvePromise = ResolvePromise; 703 to.ResolvePromise = ResolvePromise;
679 to.RejectPromise = RejectPromise; 704 to.RejectPromise = RejectPromise;
680 }); 705 });
681 706
682 }) 707 })
OLDNEW
« src/inspector/v8-debugger.cc ('K') | « src/js/prologue.js ('k') | src/parsing/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698