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

Side by Side Diff: src/promise.js

Issue 1181603003: Revert of Revert of Revert of Promise assimilation fix. (Closed) 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, thenable) { 108 function PromiseHandle(value, handler, deferred) {
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) && thenable) { 115 else if (IsPromise(result))
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)) {
123 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); 116 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
124 } else { 117 else
125 deferred.resolve(result); 118 deferred.resolve(result);
126 }
127 } catch (exception) { 119 } catch (exception) {
128 try { deferred.reject(exception); } catch (e) { } 120 try { deferred.reject(exception); } catch (e) { }
129 } finally { 121 } finally {
130 %DebugPopPromise(); 122 %DebugPopPromise();
131 } 123 }
132 } 124 }
133 125
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
156 function PromiseEnqueue(value, tasks, status) { 126 function PromiseEnqueue(value, tasks, status) {
157 var id, name, instrumenting = DEBUG_IS_ACTIVE; 127 var id, name, instrumenting = DEBUG_IS_ACTIVE;
158 %EnqueueMicrotask(function() { 128 %EnqueueMicrotask(function() {
159 if (instrumenting) { 129 if (instrumenting) {
160 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); 130 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
161 } 131 }
162 for (var i = 0; i < tasks.length; i += 3) { 132 for (var i = 0; i < tasks.length; i += 2) {
163 // tasks[i: i + 2] consists of the reaction handler, the associated 133 PromiseHandle(value, tasks[i], tasks[i + 1])
164 // deferred object and whether the thenable handling is required.
165 PromiseHandle(value, tasks[i], tasks[i + 1], tasks[i + 2])
166 } 134 }
167 if (instrumenting) { 135 if (instrumenting) {
168 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); 136 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
169 } 137 }
170 }); 138 });
171 if (instrumenting) { 139 if (instrumenting) {
172 id = ++lastMicrotaskId; 140 id = ++lastMicrotaskId;
173 name = status > 0 ? "Promise.resolve" : "Promise.reject"; 141 name = status > 0 ? "Promise.resolve" : "Promise.reject";
174 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); 142 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
175 } 143 }
176 } 144 }
177 145
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
213 function PromiseIdResolveHandler(x) { return x } 146 function PromiseIdResolveHandler(x) { return x }
214 function PromiseIdRejectHandler(r) { throw r } 147 function PromiseIdRejectHandler(r) { throw r }
215 148
216 function PromiseNopResolver() {} 149 function PromiseNopResolver() {}
217 150
218 // ------------------------------------------------------------------- 151 // -------------------------------------------------------------------
219 // Define exported functions. 152 // Define exported functions.
220 153
221 // For bootstrapper. 154 // For bootstrapper.
222 155
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 %PromiseRejectEvent(promise, r, false); 217 %PromiseRejectEvent(promise, r, false);
285 } else { 218 } else {
286 promise = new this(function(resolve, reject) { reject(r) }); 219 promise = new this(function(resolve, reject) { reject(r) });
287 } 220 }
288 return promise; 221 return promise;
289 } 222 }
290 223
291 // Simple chaining. 224 // Simple chaining.
292 225
293 function PromiseChain(onResolve, onReject) { // a.k.a. flatMap 226 function PromiseChain(onResolve, onReject) { // a.k.a. flatMap
294 return %_CallFunction(this, onResolve, onReject, false, 227 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
295 PromiseChainInternal); 228 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
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;
296 } 259 }
297 260
298 function PromiseCatch(onReject) { 261 function PromiseCatch(onReject) {
299 return this.then(UNDEFINED, onReject); 262 return this.then(UNDEFINED, onReject);
300 } 263 }
301 264
302 // Multi-unwrapped chaining with thenable coercion. 265 // Multi-unwrapped chaining with thenable coercion.
303 266
304 function PromiseThen(onResolve, onReject) { 267 function PromiseThen(onResolve, onReject) {
305 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve 268 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
(...skipping 10 matching lines...) Expand all
316 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject); 279 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
317 return onReject(MakeTypeError(kPromiseCyclic, x)); 280 return onReject(MakeTypeError(kPromiseCyclic, x));
318 } else if (IsPromise(x)) { 281 } else if (IsPromise(x)) {
319 return x.then(onResolve, onReject); 282 return x.then(onResolve, onReject);
320 } else { 283 } else {
321 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve); 284 DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
322 return onResolve(x); 285 return onResolve(x);
323 } 286 }
324 }, 287 },
325 onReject, 288 onReject,
326 true, 289 PromiseChain
327 PromiseChainInternal
328 ); 290 );
329 } 291 }
330 292
331 // Combinators. 293 // Combinators.
332 294
333 function PromiseCast(x) { 295 function PromiseCast(x) {
334 // TODO(rossberg): cannot do better until we support @@create. 296 // TODO(rossberg): cannot do better until we support @@create.
335 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) }); 297 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
336 } 298 }
337 299
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 } 341 }
380 return deferred.promise; 342 return deferred.promise;
381 } 343 }
382 344
383 345
384 // Utility for debugger 346 // Utility for debugger
385 347
386 function PromiseHasUserDefinedRejectHandlerRecursive(promise) { 348 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
387 var queue = GET_PRIVATE(promise, promiseOnReject); 349 var queue = GET_PRIVATE(promise, promiseOnReject);
388 if (IS_UNDEFINED(queue)) return false; 350 if (IS_UNDEFINED(queue)) return false;
389 for (var i = 0; i < queue.length; i += 3) { 351 for (var i = 0; i < queue.length; i += 2) {
390 if (queue[i] != PromiseIdRejectHandler) return true; 352 if (queue[i] != PromiseIdRejectHandler) return true;
391 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) { 353 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
392 return true; 354 return true;
393 } 355 }
394 } 356 }
395 return false; 357 return false;
396 } 358 }
397 359
398 // Return whether the promise will be handled by a user-defined reject 360 // Return whether the promise will be handled by a user-defined reject
399 // handler somewhere down the promise chain. For this, we do a depth-first 361 // handler somewhere down the promise chain. For this, we do a depth-first
(...skipping 28 matching lines...) Expand all
428 $promiseResolve = PromiseResolve; 390 $promiseResolve = PromiseResolve;
429 $promiseReject = PromiseReject; 391 $promiseReject = PromiseReject;
430 $promiseChain = PromiseChain; 392 $promiseChain = PromiseChain;
431 $promiseCatch = PromiseCatch; 393 $promiseCatch = PromiseCatch;
432 $promiseThen = PromiseThen; 394 $promiseThen = PromiseThen;
433 $promiseHasUserDefinedRejectHandler = PromiseHasUserDefinedRejectHandler; 395 $promiseHasUserDefinedRejectHandler = PromiseHasUserDefinedRejectHandler;
434 $promiseStatus = promiseStatus; 396 $promiseStatus = promiseStatus;
435 $promiseValue = promiseValue; 397 $promiseValue = promiseValue;
436 398
437 }) 399 })
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