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

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, 6 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 var $promiseCreate; 5 var $promiseCreate;
6 var $promiseResolve; 6 var $promiseResolve;
7 var $promiseReject; 7 var $promiseReject;
8 var $promiseChain; 8 var $promiseChain;
9 var $promiseCatch; 9 var $promiseCatch;
10 var $promiseThen; 10 var $promiseThen;
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 %_CallFunction(x, deferred.resolve, deferred.reject, then); 98 %_CallFunction(x, deferred.resolve, deferred.reject, then);
99 } catch(r) { 99 } catch(r) {
100 deferred.reject(r); 100 deferred.reject(r);
101 } 101 }
102 return deferred.promise; 102 return deferred.promise;
103 } 103 }
104 } 104 }
105 return x; 105 return x;
106 } 106 }
107 107
108 function PromiseHandle(value, handler, deferred) { 108 function PromiseHandle(value, handler, deferred, thenable) {
109 try { 109 try {
110 %DebugPushPromise(deferred.promise, PromiseHandle); 110 %DebugPushPromise(deferred.promise, PromiseHandle);
111 DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler); 111 DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
112 var result = handler(value); 112 var result = handler(value);
113 if (result === deferred.promise) 113 if (result === deferred.promise) {
114 throw MakeTypeError(kPromiseCyclic, result); 114 throw MakeTypeError(kPromiseCyclic, result);
115 else if (IsPromise(result)) 115 } else if (IsPromise(result) && thenable) {
116 var then = result.then;
117 if (IS_SPEC_FUNCTION(then)) {
118 PromiseCallThenInSeparateTask(result, deferred, then);
119 } else {
120 deferred.resolve(result);
121 }
122 } else if (IsPromise(result)) {
116 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); 123 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
117 else 124 } else {
118 deferred.resolve(result); 125 deferred.resolve(result);
126 }
119 } catch (exception) { 127 } catch (exception) {
120 try { deferred.reject(exception); } catch (e) { } 128 try { deferred.reject(exception); } catch (e) { }
121 } finally { 129 } finally {
122 %DebugPopPromise(); 130 %DebugPopPromise();
123 } 131 }
124 } 132 }
125 133
134 function PromiseCallThenInSeparateTask(result, deferred, then) {
135 var id, name, instrumenting = DEBUG_IS_ACTIVE;
136 %EnqueueMicrotask(function() {
137 if (instrumenting) {
138 %DebugAsyncTaskEvent({ type: "willCall", id: id, name: name });
139 }
140 try {
141 %_CallFunction(result, deferred.resolve, deferred.reject, then);
142 } catch(exception) {
143 try { deferred.reject(exception); } catch (e) { }
144 }
145 if (instrumenting) {
146 %DebugAsyncTaskEvent({ type: "didCall", id: id, name: name });
147 }
148 });
149 if (instrumenting) {
150 id = ++lastMicrotaskId;
151 name = "Promise.prototype.then";
152 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
153 }
154 }
155
126 function PromiseEnqueue(value, tasks, status) { 156 function PromiseEnqueue(value, tasks, status) {
127 var id, name, instrumenting = DEBUG_IS_ACTIVE; 157 var id, name, instrumenting = DEBUG_IS_ACTIVE;
128 %EnqueueMicrotask(function() { 158 %EnqueueMicrotask(function() {
129 if (instrumenting) { 159 if (instrumenting) {
130 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 160 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
131 } 161 }
132 for (var i = 0; i < tasks.length; i += 2) { 162 for (var i = 0; i < tasks.length; i += 3) {
133 PromiseHandle(value, tasks[i], tasks[i + 1]) 163 // tasks[i: i + 2] consists of the reaction handler, the associated
164 // deferred object and whether the thenable handling is required.
165 PromiseHandle(value, tasks[i], tasks[i + 1], tasks[i + 2])
134 } 166 }
135 if (instrumenting) { 167 if (instrumenting) {
136 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 168 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
137 } 169 }
138 }); 170 });
139 if (instrumenting) { 171 if (instrumenting) {
140 id = ++lastMicrotaskId; 172 id = ++lastMicrotaskId;
141 name = status > 0 ? "Promise.resolve" : "Promise.reject"; 173 name = status > 0 ? "Promise.resolve" : "Promise.reject";
142 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 174 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
143 } 175 }
144 } 176 }
145 177
178 function PromiseChainInternal(onResolve, onReject, thenable) {
179 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
180 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
181 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
182 switch (GET_PRIVATE(this, promiseStatus)) {
183 case UNDEFINED:
184 throw MakeTypeError(kNotAPromise, this);
185 case 0: // Pending
186 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred, thenable);
187 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred, thenable);
188 break;
189 case +1: // Resolved
190 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
191 [onResolve, deferred, thenable],
192 +1);
193 break;
194 case -1: // Rejected
195 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
196 // Promise has already been rejected, but had no handler.
197 // Revoke previously triggered reject event.
198 %PromiseRevokeReject(this);
199 }
200 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
201 [onReject, deferred, thenable],
202 -1);
203 break;
204 }
205 // Mark this promise as having handler.
206 SET_PRIVATE(this, promiseHasHandler, true);
207 if (DEBUG_IS_ACTIVE) {
208 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
209 }
210 return deferred.promise;
211 }
212
146 function PromiseIdResolveHandler(x) { return x } 213 function PromiseIdResolveHandler(x) { return x }
147 function PromiseIdRejectHandler(r) { throw r } 214 function PromiseIdRejectHandler(r) { throw r }
148 215
149 function PromiseNopResolver() {} 216 function PromiseNopResolver() {}
150 217
151 // ------------------------------------------------------------------- 218 // -------------------------------------------------------------------
152 // Define exported functions. 219 // Define exported functions.
153 220
154 // For bootstrapper. 221 // For bootstrapper.
155 222
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 %PromiseRejectEvent(promise, r, false); 284 %PromiseRejectEvent(promise, r, false);
218 } else { 285 } else {
219 promise = new this(function(resolve, reject) { reject(r) }); 286 promise = new this(function(resolve, reject) { reject(r) });
220 } 287 }
221 return promise; 288 return promise;
222 } 289 }
223 290
224 // Simple chaining. 291 // Simple chaining.
225 292
226 function PromiseChain(onResolve, onReject) { // a.k.a. flatMap 293 function PromiseChain(onResolve, onReject) { // a.k.a. flatMap
227 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; 294 return %_CallFunction(this, onResolve, onReject, false,
228 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; 295 PromiseChainInternal);
229 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
230 switch (GET_PRIVATE(this, promiseStatus)) {
231 case UNDEFINED:
232 throw MakeTypeError(kNotAPromise, this);
233 case 0: // Pending
234 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
235 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
236 break;
237 case +1: // Resolved
238 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
239 [onResolve, deferred],
240 +1);
241 break;
242 case -1: // Rejected
243 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
244 // Promise has already been rejected, but had no handler.
245 // Revoke previously triggered reject event.
246 %PromiseRevokeReject(this);
247 }
248 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
249 [onReject, deferred],
250 -1);
251 break;
252 }
253 // Mark this promise as having handler.
254 SET_PRIVATE(this, promiseHasHandler, true);
255 if (DEBUG_IS_ACTIVE) {
256 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
257 }
258 return deferred.promise;
259 } 296 }
260 297
261 function PromiseCatch(onReject) { 298 function PromiseCatch(onReject) {
262 return this.then(UNDEFINED, onReject); 299 return this.then(UNDEFINED, onReject);
263 } 300 }
264 301
265 // Multi-unwrapped chaining with thenable coercion. 302 // Multi-unwrapped chaining with thenable coercion.
266 303
267 function PromiseThen(onResolve, onReject) { 304 function PromiseThen(onResolve, onReject) {
268 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve 305 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
(...skipping 10 matching lines...) Expand all
279 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject); 316 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
280 return onReject(MakeTypeError(kPromiseCyclic, x)); 317 return onReject(MakeTypeError(kPromiseCyclic, x));
281 } else if (IsPromise(x)) { 318 } else if (IsPromise(x)) {
282 return x.then(onResolve, onReject); 319 return x.then(onResolve, onReject);
283 } else { 320 } else {
284 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve); 321 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
285 return onResolve(x); 322 return onResolve(x);
286 } 323 }
287 }, 324 },
288 onReject, 325 onReject,
289 PromiseChain 326 true,
327 PromiseChainInternal
290 ); 328 );
291 } 329 }
292 330
293 // Combinators. 331 // Combinators.
294 332
295 function PromiseCast(x) { 333 function PromiseCast(x) {
296 // TODO(rossberg): cannot do better until we support @@create. 334 // TODO(rossberg): cannot do better until we support @@create.
297 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) }); 335 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
298 } 336 }
299 337
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 } 379 }
342 return deferred.promise; 380 return deferred.promise;
343 } 381 }
344 382
345 383
346 // Utility for debugger 384 // Utility for debugger
347 385
348 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { 386 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
349 var queue = GET_PRIVATE(promise, promiseOnReject); 387 var queue = GET_PRIVATE(promise, promiseOnReject);
350 if (IS_UNDEFINED(queue)) return false; 388 if (IS_UNDEFINED(queue)) return false;
351 for (var i = 0; i < queue.length; i += 2) { 389 for (var i = 0; i < queue.length; i += 3) {
352 if (queue[i] != PromiseIdRejectHandler) return true; 390 if (queue[i] != PromiseIdRejectHandler) return true;
353 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) { 391 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
354 return true; 392 return true;
355 } 393 }
356 } 394 }
357 return false; 395 return false;
358 } 396 }
359 397
360 // Return whether the promise will be handled by a user-defined reject 398 // Return whether the promise will be handled by a user-defined reject
361 // handler somewhere down the promise chain. For this, we do a depth-first 399 // handler somewhere down the promise chain. For this, we do a depth-first
(...skipping 28 matching lines...) Expand all
390 $promiseResolve = PromiseResolve; 428 $promiseResolve = PromiseResolve;
391 $promiseReject = PromiseReject; 429 $promiseReject = PromiseReject;
392 $promiseChain = PromiseChain; 430 $promiseChain = PromiseChain;
393 $promiseCatch = PromiseCatch; 431 $promiseCatch = PromiseCatch;
394 $promiseThen = PromiseThen; 432 $promiseThen = PromiseThen;
395 $promiseHasUserDefinedRejectHandler = PromiseHasUserDefinedRejectHandler; 433 $promiseHasUserDefinedRejectHandler = PromiseHasUserDefinedRejectHandler;
396 $promiseStatus = promiseStatus; 434 $promiseStatus = promiseStatus;
397 $promiseValue = promiseValue; 435 $promiseValue = promiseValue;
398 436
399 }) 437 })
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