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

Side by Side Diff: src/promise.js

Issue 1098663002: Promise assimilation fix. Base URL: git://github.com/v8/v8.git@master
Patch Set: Created 5 years, 7 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
« no previous file with comments | « no previous file | test/mjsunit/es6/promises.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "use strict"; 5 "use strict";
6 6
7 // This file relies on the fact that the following declaration has been made 7 // This file relies on the fact that the following declaration has been made
8 // in runtime.js: 8 // in runtime.js:
9 // var $Object = global.Object 9 // var $Object = global.Object
10 // var $WeakMap = global.WeakMap 10 // var $WeakMap = global.WeakMap
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 %_CallFunction(x, deferred.resolve, deferred.reject, then); 93 %_CallFunction(x, deferred.resolve, deferred.reject, then);
94 } catch(r) { 94 } catch(r) {
95 deferred.reject(r); 95 deferred.reject(r);
96 } 96 }
97 return deferred.promise; 97 return deferred.promise;
98 } 98 }
99 } 99 }
100 return x; 100 return x;
101 } 101 }
102 102
103 function PromiseHandle(value, handler, deferred) { 103 function PromiseHandle(value, handler, deferred, thenable) {
104 try { 104 try {
105 %DebugPushPromise(deferred.promise); 105 %DebugPushPromise(deferred.promise);
106 var result = handler(value); 106 var result = handler(value);
107 if (result === deferred.promise) 107 if (result === deferred.promise) {
108 throw MakeTypeError('promise_cyclic', [result]); 108 throw MakeTypeError('promise_cyclic', [result]);
109 else if (IsPromise(result)) 109 } else if (IsPromise(result) && thenable) {
110 var then = result.then;
arv (Not doing code reviews) 2015/05/11 13:53:15 Isn't this extra Get observable?
yhirano 2015/05/12 06:09:19 In PromiseReactionJob[1], promiseCapability.[[Reso
111 if (IS_SPEC_FUNCTION(then)) {
112 %EnqueueMicrotask(function() {
113 try {
114 %_CallFunction(result, deferred.resolve, deferred.reject, then);
115 } catch(exception) {
116 try { deferred.reject(exception); } catch (e) { }
caitp (gmail) 2015/05/11 03:02:16 Is this not already handled by the enclosing try/c
caitp (gmail) 2015/05/11 03:06:05 wait, I get it --- I guess it's not
arv (Not doing code reviews) 2015/05/11 13:53:15 I think it is :-) Line 128
caitp (gmail) 2015/05/11 15:02:34 Yeah, but this one is in a closure passed to Enque
117 }
118 });
119 } else {
120 deferred.resolve(result);
caitp (gmail) 2015/05/11 03:02:16 This same branch is repeated a few times, maybe it
yhirano 2015/05/12 06:09:19 Hmm, I don't have a good idea to unify them (parti
121 }
122 } else if (IsPromise(result)) {
110 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); 123 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
111 else 124 } else {
112 deferred.resolve(result); 125 deferred.resolve(result);
126 }
113 } catch (exception) { 127 } catch (exception) {
114 try { deferred.reject(exception); } catch (e) { } 128 try { deferred.reject(exception); } catch (e) { }
115 } finally { 129 } finally {
116 %DebugPopPromise(); 130 %DebugPopPromise();
117 } 131 }
118 } 132 }
119 133
120 function PromiseEnqueue(value, tasks, status) { 134 function PromiseEnqueue(value, tasks, status) {
121 var id, name, instrumenting = DEBUG_IS_ACTIVE; 135 var id, name, instrumenting = DEBUG_IS_ACTIVE;
122 %EnqueueMicrotask(function() { 136 %EnqueueMicrotask(function() {
123 if (instrumenting) { 137 if (instrumenting) {
124 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 138 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
125 } 139 }
126 for (var i = 0; i < tasks.length; i += 2) { 140 for (var i = 0; i < tasks.length; i += 3) {
caitp (gmail) 2015/05/11 03:02:16 This gets confusing, comments would be helpful
yhirano 2015/05/12 06:09:19 Done.
127 PromiseHandle(value, tasks[i], tasks[i + 1]) 141 PromiseHandle(value, tasks[i], tasks[i + 1], tasks[i + 2])
128 } 142 }
129 if (instrumenting) { 143 if (instrumenting) {
130 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 144 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
131 } 145 }
132 }); 146 });
133 if (instrumenting) { 147 if (instrumenting) {
134 id = ++lastMicrotaskId; 148 id = ++lastMicrotaskId;
135 name = status > 0 ? "Promise.resolve" : "Promise.reject"; 149 name = status > 0 ? "Promise.resolve" : "Promise.reject";
136 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 150 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
137 } 151 }
138 } 152 }
139 153
154 function PromiseChainInternal(onResolve, onReject, thenable) {
155 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
156 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
157 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
158 switch (GET_PRIVATE(this, promiseStatus)) {
159 case UNDEFINED:
160 throw MakeTypeError('not_a_promise', [this]);
161 case 0: // Pending
162 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred, thenable);
163 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred, thenable);
164 break;
165 case +1: // Resolved
166 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
167 [onResolve, deferred, thenable],
168 +1);
169 break;
170 case -1: // Rejected
171 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
172 // Promise has already been rejected, but had no handler.
173 // Revoke previously triggered reject event.
174 %PromiseRevokeReject(this);
175 }
176 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
177 [onReject, deferred, thenable],
178 -1);
179 break;
180 }
181 // Mark this promise as having handler.
182 SET_PRIVATE(this, promiseHasHandler, true);
183 if (DEBUG_IS_ACTIVE) {
184 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
185 }
186 return deferred.promise;
187 }
188
140 function PromiseIdResolveHandler(x) { return x } 189 function PromiseIdResolveHandler(x) { return x }
141 function PromiseIdRejectHandler(r) { throw r } 190 function PromiseIdRejectHandler(r) { throw r }
142 191
143 function PromiseNopResolver() {} 192 function PromiseNopResolver() {}
144 193
145 // ------------------------------------------------------------------- 194 // -------------------------------------------------------------------
146 // Define exported functions. 195 // Define exported functions.
147 196
148 // For bootstrapper. 197 // For bootstrapper.
149 198
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 } else { 261 } else {
213 promise = new this(function(resolve, reject) { reject(r) }); 262 promise = new this(function(resolve, reject) { reject(r) });
214 } 263 }
215 return promise; 264 return promise;
216 } 265 }
217 266
218 // Simple chaining. 267 // Simple chaining.
219 268
220 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a. 269 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a.
221 // flatMap 270 // flatMap
222 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; 271 return %_CallFunction(this, onResolve, onReject, false,
223 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; 272 PromiseChainInternal);
224 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
225 switch (GET_PRIVATE(this, promiseStatus)) {
226 case UNDEFINED:
227 throw MakeTypeError('not_a_promise', [this]);
228 case 0: // Pending
229 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
230 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
231 break;
232 case +1: // Resolved
233 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
234 [onResolve, deferred],
235 +1);
236 break;
237 case -1: // Rejected
238 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
239 // Promise has already been rejected, but had no handler.
240 // Revoke previously triggered reject event.
241 %PromiseRevokeReject(this);
242 }
243 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
244 [onReject, deferred],
245 -1);
246 break;
247 }
248 // Mark this promise as having handler.
249 SET_PRIVATE(this, promiseHasHandler, true);
250 if (DEBUG_IS_ACTIVE) {
251 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
252 }
253 return deferred.promise;
254 } 273 }
255 274
256 PromiseCatch = function PromiseCatch(onReject) { 275 PromiseCatch = function PromiseCatch(onReject) {
257 return this.then(UNDEFINED, onReject); 276 return this.then(UNDEFINED, onReject);
258 } 277 }
259 278
260 // Multi-unwrapped chaining with thenable coercion. 279 // Multi-unwrapped chaining with thenable coercion.
261 280
262 PromiseThen = function PromiseThen(onResolve, onReject) { 281 PromiseThen = function PromiseThen(onResolve, onReject) {
263 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve 282 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
264 : PromiseIdResolveHandler; 283 : PromiseIdResolveHandler;
265 onReject = IS_SPEC_FUNCTION(onReject) ? onReject 284 onReject = IS_SPEC_FUNCTION(onReject) ? onReject
266 : PromiseIdRejectHandler; 285 : PromiseIdRejectHandler;
267 var that = this; 286 var that = this;
268 var constructor = this.constructor; 287 var constructor = this.constructor;
269 return %_CallFunction( 288 return %_CallFunction(
270 this, 289 this,
271 function(x) { 290 function(x) {
272 x = PromiseCoerce(constructor, x); 291 x = PromiseCoerce(constructor, x);
273 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : 292 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
274 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); 293 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
275 }, 294 },
276 onReject, 295 onReject,
277 PromiseChain 296 true,
297 PromiseChainInternal
278 ); 298 );
279 } 299 }
280 300
281 // Combinators. 301 // Combinators.
282 302
283 function PromiseCast(x) { 303 function PromiseCast(x) {
284 // TODO(rossberg): cannot do better until we support @@create. 304 // TODO(rossberg): cannot do better until we support @@create.
285 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) }); 305 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
286 } 306 }
287 307
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 } 356 }
337 return deferred.promise; 357 return deferred.promise;
338 } 358 }
339 359
340 360
341 // Utility for debugger 361 // Utility for debugger
342 362
343 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { 363 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
344 var queue = GET_PRIVATE(promise, promiseOnReject); 364 var queue = GET_PRIVATE(promise, promiseOnReject);
345 if (IS_UNDEFINED(queue)) return false; 365 if (IS_UNDEFINED(queue)) return false;
346 for (var i = 0; i < queue.length; i += 2) { 366 for (var i = 0; i < queue.length; i += 3) {
347 if (queue[i] != PromiseIdRejectHandler) return true; 367 if (queue[i] != PromiseIdRejectHandler) return true;
348 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) { 368 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
349 return true; 369 return true;
350 } 370 }
351 } 371 }
352 return false; 372 return false;
353 } 373 }
354 374
355 // Return whether the promise will be handled by a user-defined reject 375 // Return whether the promise will be handled by a user-defined reject
356 // handler somewhere down the promise chain. For this, we do a depth-first 376 // handler somewhere down the promise chain. For this, we do a depth-first
(...skipping 18 matching lines...) Expand all
375 "race", PromiseOne, 395 "race", PromiseOne,
376 "resolve", PromiseCast 396 "resolve", PromiseCast
377 ]); 397 ]);
378 InstallFunctions($Promise.prototype, DONT_ENUM, [ 398 InstallFunctions($Promise.prototype, DONT_ENUM, [
379 "chain", PromiseChain, 399 "chain", PromiseChain,
380 "then", PromiseThen, 400 "then", PromiseThen,
381 "catch", PromiseCatch 401 "catch", PromiseCatch
382 ]); 402 ]);
383 403
384 })(); 404 })();
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/es6/promises.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698