]>
Commit | Line | Data |
---|---|---|
81345200 A |
1 | /* |
2 | * Copyright (C) 2013 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
23 | * THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "JSPromiseConstructor.h" | |
28 | ||
29 | #if ENABLE(PROMISES) | |
30 | ||
31 | #include "Error.h" | |
32 | #include "JSCJSValueInlines.h" | |
33 | #include "JSCellInlines.h" | |
34 | #include "JSPromise.h" | |
35 | #include "JSPromiseDeferred.h" | |
36 | #include "JSPromiseFunctions.h" | |
37 | #include "JSPromisePrototype.h" | |
38 | #include "Lookup.h" | |
39 | #include "NumberObject.h" | |
40 | #include "StructureInlines.h" | |
41 | ||
42 | namespace JSC { | |
43 | ||
44 | STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor); | |
45 | ||
46 | static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState*); | |
47 | static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState*); | |
48 | static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState*); | |
49 | static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState*); | |
50 | static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState*); | |
51 | } | |
52 | ||
53 | #include "JSPromiseConstructor.lut.h" | |
54 | ||
55 | namespace JSC { | |
56 | ||
57 | const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) }; | |
58 | ||
59 | /* Source for JSPromiseConstructor.lut.h | |
60 | @begin promiseConstructorTable | |
61 | cast JSPromiseConstructorFuncCast DontEnum|Function 1 | |
62 | resolve JSPromiseConstructorFuncResolve DontEnum|Function 1 | |
63 | reject JSPromiseConstructorFuncReject DontEnum|Function 1 | |
64 | race JSPromiseConstructorFuncRace DontEnum|Function 1 | |
65 | all JSPromiseConstructorFuncAll DontEnum|Function 1 | |
66 | @end | |
67 | */ | |
68 | ||
69 | JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype) | |
70 | { | |
71 | JSPromiseConstructor* constructor = new (NotNull, allocateCell<JSPromiseConstructor>(vm.heap)) JSPromiseConstructor(vm, structure); | |
72 | constructor->finishCreation(vm, promisePrototype); | |
73 | return constructor; | |
74 | } | |
75 | ||
76 | Structure* JSPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) | |
77 | { | |
78 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); | |
79 | } | |
80 | ||
81 | JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure) | |
82 | : InternalFunction(vm, structure) | |
83 | { | |
84 | } | |
85 | ||
86 | void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype) | |
87 | { | |
88 | Base::finishCreation(vm, "Promise"); | |
89 | putDirectWithoutTransition(vm, vm.propertyNames->prototype, promisePrototype, DontEnum | DontDelete | ReadOnly); | |
90 | putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); | |
91 | } | |
92 | ||
93 | static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec) | |
94 | { | |
95 | // NOTE: We ignore steps 1-4 as they only matter if you support subclassing, which we do not yet. | |
96 | // 1. Let promise be the this value. | |
97 | // 2. If Type(promise) is not Object, then throw a TypeError exception. | |
98 | // 3. If promise does not have a [[PromiseStatus]] internal slot, then throw a TypeError exception. | |
99 | // 4. If promise's [[PromiseStatus]] internal slot is not undefined, then throw a TypeError exception. | |
100 | ||
101 | JSValue resolver = exec->argument(0); | |
102 | ||
103 | // 5. IsCallable(resolver) is false, then throw a TypeError exception | |
104 | CallData callData; | |
105 | CallType callType = getCallData(resolver, callData); | |
106 | if (callType == CallTypeNone) | |
107 | return JSValue::encode(throwTypeError(exec, ASCIILiteral("Promise constructor takes a function argument"))); | |
108 | ||
109 | VM& vm = exec->vm(); | |
110 | JSGlobalObject* globalObject = exec->callee()->globalObject(); | |
111 | ||
112 | JSPromise* promise = JSPromise::create(vm, globalObject, jsCast<JSPromiseConstructor*>(exec->callee())); | |
113 | ||
114 | // NOTE: Steps 6-8 are handled by JSPromise::create(). | |
115 | // 6. Set promise's [[PromiseStatus]] internal slot to "unresolved". | |
116 | // 7. Set promise's [[ResolveReactions]] internal slot to a new empty List. | |
117 | // 8. Set promise's [[RejectReactions]] internal slot to a new empty List. | |
118 | ||
119 | // 9. Let 'resolve' be a new built-in function object as defined in Resolve Promise Functions. | |
120 | JSFunction* resolve = createResolvePromiseFunction(vm, globalObject); | |
121 | ||
122 | // 10. Set the [[Promise]] internal slot of 'resolve' to 'promise'. | |
123 | resolve->putDirect(vm, vm.propertyNames->promisePrivateName, promise); | |
124 | ||
125 | // 11. Let 'reject' be a new built-in function object as defined in Reject Promise Functions | |
126 | JSFunction* reject = createRejectPromiseFunction(vm, globalObject); | |
127 | ||
128 | // 12. Set the [[Promise]] internal slot of 'reject' to 'promise'. | |
129 | reject->putDirect(vm, vm.propertyNames->promisePrivateName, promise); | |
130 | ||
131 | // 13. Let 'result' be the result of calling the [[Call]] internal method of resolver with | |
132 | // undefined as thisArgument and a List containing resolve and reject as argumentsList. | |
133 | MarkedArgumentBuffer arguments; | |
134 | arguments.append(resolve); | |
135 | arguments.append(reject); | |
136 | call(exec, resolver, callType, callData, jsUndefined(), arguments); | |
137 | ||
138 | // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]). | |
139 | if (exec->hadException()) { | |
140 | JSValue exception = exec->exception(); | |
141 | exec->clearException(); | |
142 | ||
143 | promise->reject(vm, exception); | |
144 | } | |
145 | ||
146 | // 15. Return promise. | |
147 | return JSValue::encode(promise); | |
148 | } | |
149 | ||
150 | ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData) | |
151 | { | |
152 | constructData.native.function = constructPromise; | |
153 | return ConstructTypeHost; | |
154 | } | |
155 | ||
156 | CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData) | |
157 | { | |
158 | callData.native.function = constructPromise; | |
159 | return CallTypeHost; | |
160 | } | |
161 | ||
162 | bool JSPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) | |
163 | { | |
164 | return getStaticFunctionSlot<InternalFunction>(exec, ExecState::promiseConstructorTable(exec->vm()), jsCast<JSPromiseConstructor*>(object), propertyName, slot); | |
165 | } | |
166 | ||
167 | EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState* exec) | |
168 | { | |
169 | // -- Promise.cast(x) -- | |
170 | JSValue x = exec->argument(0); | |
171 | ||
172 | // 1. Let 'C' be the this value. | |
173 | JSValue C = exec->thisValue(); | |
174 | ||
175 | // 2. If IsPromise(x) is true, | |
176 | JSPromise* promise = jsDynamicCast<JSPromise*>(x); | |
177 | if (promise) { | |
178 | // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot. | |
179 | JSValue constructor = promise->constructor(); | |
180 | // ii. If SameValue(constructor, C) is true, return x. | |
181 | if (sameValue(exec, constructor, C)) | |
182 | return JSValue::encode(x); | |
183 | } | |
184 | ||
185 | // 3. Let 'deferred' be the result of calling GetDeferred(C). | |
186 | JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); | |
187 | ||
188 | // 4. ReturnIfAbrupt(deferred). | |
189 | if (exec->hadException()) | |
190 | return JSValue::encode(jsUndefined()); | |
191 | ||
192 | JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); | |
193 | ||
194 | // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method | |
195 | // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x | |
196 | // as argumentsList. | |
197 | performDeferredResolve(exec, deferred, x); | |
198 | ||
199 | // 6. ReturnIfAbrupt(resolveResult). | |
200 | if (exec->hadException()) | |
201 | return JSValue::encode(jsUndefined()); | |
202 | ||
203 | // 7. Return deferred.[[Promise]]. | |
204 | return JSValue::encode(deferred->promise()); | |
205 | } | |
206 | ||
207 | EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec) | |
208 | { | |
209 | // -- Promise.resolve(x) -- | |
210 | JSValue x = exec->argument(0); | |
211 | ||
212 | // 1. Let 'C' be the this value. | |
213 | JSValue C = exec->thisValue(); | |
214 | ||
215 | // 2. Let 'deferred' be the result of calling GetDeferred(C). | |
216 | JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); | |
217 | ||
218 | // 3. ReturnIfAbrupt(deferred). | |
219 | if (exec->hadException()) | |
220 | return JSValue::encode(jsUndefined()); | |
221 | ||
222 | JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); | |
223 | ||
224 | // 4. Let 'resolveResult' be the result of calling the [[Call]] internal method | |
225 | // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x | |
226 | // as argumentsList. | |
227 | performDeferredResolve(exec, deferred, x); | |
228 | ||
229 | // 5. ReturnIfAbrupt(resolveResult). | |
230 | if (exec->hadException()) | |
231 | return JSValue::encode(jsUndefined()); | |
232 | ||
233 | // 6. Return deferred.[[Promise]]. | |
234 | return JSValue::encode(deferred->promise()); | |
235 | } | |
236 | ||
237 | EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec) | |
238 | { | |
239 | // -- Promise.reject(x) -- | |
240 | JSValue r = exec->argument(0); | |
241 | ||
242 | // 1. Let 'C' be the this value. | |
243 | JSValue C = exec->thisValue(); | |
244 | ||
245 | // 2. Let 'deferred' be the result of calling GetDeferred(C). | |
246 | JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); | |
247 | ||
248 | // 3. ReturnIfAbrupt(deferred). | |
249 | if (exec->hadException()) | |
250 | return JSValue::encode(jsUndefined()); | |
251 | ||
252 | JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); | |
253 | ||
254 | // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method | |
255 | // of deferred.[[Reject]] with undefined as thisArgument and a List containing r | |
256 | // as argumentsList. | |
257 | performDeferredReject(exec, deferred, r); | |
258 | ||
259 | // 5. ReturnIfAbrupt(resolveResult). | |
260 | if (exec->hadException()) | |
261 | return JSValue::encode(jsUndefined()); | |
262 | ||
263 | // 6. Return deferred.[[Promise]]. | |
264 | return JSValue::encode(deferred->promise()); | |
265 | } | |
266 | ||
267 | EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec) | |
268 | { | |
269 | // -- Promise.race(iterable) -- | |
270 | JSValue iterable = exec->argument(0); | |
271 | VM& vm = exec->vm(); | |
272 | ||
273 | // 1. Let 'C' be the this value. | |
274 | JSValue C = exec->thisValue(); | |
275 | ||
276 | // 2. Let 'deferred' be the result of calling GetDeferred(C). | |
277 | JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); | |
278 | ||
279 | // 3. ReturnIfAbrupt(deferred). | |
280 | if (exec->hadException()) | |
281 | return JSValue::encode(jsUndefined()); | |
282 | ||
283 | JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); | |
284 | ||
285 | // 4. Let 'iterator' be the result of calling GetIterator(iterable). | |
286 | JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); | |
287 | if (exec->hadException()) | |
288 | return JSValue::encode(abruptRejection(exec, deferred)); | |
289 | ||
290 | CallData iteratorFunctionCallData; | |
291 | CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); | |
292 | if (iteratorFunctionCallType == CallTypeNone) { | |
293 | throwTypeError(exec); | |
294 | return JSValue::encode(abruptRejection(exec, deferred)); | |
295 | } | |
296 | ||
297 | ArgList iteratorFunctionArguments; | |
298 | JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); | |
299 | ||
300 | // 5. RejectIfAbrupt(iterator, deferred). | |
301 | if (exec->hadException()) | |
302 | return JSValue::encode(abruptRejection(exec, deferred)); | |
303 | ||
304 | // 6. Repeat | |
305 | do { | |
306 | // i. Let 'next' be the result of calling IteratorStep(iterator). | |
307 | JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); | |
308 | if (exec->hadException()) | |
309 | return JSValue::encode(abruptRejection(exec, deferred)); | |
310 | ||
311 | CallData nextFunctionCallData; | |
312 | CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); | |
313 | if (nextFunctionCallType == CallTypeNone) { | |
314 | throwTypeError(exec); | |
315 | return JSValue::encode(abruptRejection(exec, deferred)); | |
316 | } | |
317 | ||
318 | MarkedArgumentBuffer nextFunctionArguments; | |
319 | nextFunctionArguments.append(jsUndefined()); | |
320 | JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); | |
321 | ||
322 | // ii. RejectIfAbrupt(next, deferred). | |
323 | if (exec->hadException()) | |
324 | return JSValue::encode(abruptRejection(exec, deferred)); | |
325 | ||
326 | // iii. If 'next' is false, return deferred.[[Promise]]. | |
327 | // Note: We implement this as an iterationTerminator | |
328 | if (next == vm.iterationTerminator.get()) | |
329 | return JSValue::encode(deferred->promise()); | |
330 | ||
331 | // iv. Let 'nextValue' be the result of calling IteratorValue(next). | |
332 | // v. RejectIfAbrupt(nextValue, deferred). | |
333 | // Note: 'next' is already the value, so there is nothing to do here. | |
334 | ||
335 | // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). | |
336 | JSValue castFunction = C.get(exec, vm.propertyNames->cast); | |
337 | if (exec->hadException()) | |
338 | return JSValue::encode(abruptRejection(exec, deferred)); | |
339 | ||
340 | CallData castFunctionCallData; | |
341 | CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); | |
342 | if (castFunctionCallType == CallTypeNone) { | |
343 | throwTypeError(exec); | |
344 | return JSValue::encode(abruptRejection(exec, deferred)); | |
345 | } | |
346 | ||
347 | MarkedArgumentBuffer castFunctionArguments; | |
348 | castFunctionArguments.append(next); | |
349 | JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); | |
350 | ||
351 | // vii. RejectIfAbrupt(nextPromise, deferred). | |
352 | if (exec->hadException()) | |
353 | return JSValue::encode(abruptRejection(exec, deferred)); | |
354 | ||
355 | // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])). | |
356 | JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); | |
357 | if (exec->hadException()) | |
358 | return JSValue::encode(abruptRejection(exec, deferred)); | |
359 | ||
360 | CallData thenFunctionCallData; | |
361 | CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); | |
362 | if (thenFunctionCallType == CallTypeNone) { | |
363 | throwTypeError(exec); | |
364 | return JSValue::encode(abruptRejection(exec, deferred)); | |
365 | } | |
366 | ||
367 | MarkedArgumentBuffer thenFunctionArguments; | |
368 | thenFunctionArguments.append(deferred->resolve()); | |
369 | thenFunctionArguments.append(deferred->reject()); | |
370 | ||
371 | call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); | |
372 | ||
373 | // ix. RejectIfAbrupt(result, deferred). | |
374 | if (exec->hadException()) | |
375 | return JSValue::encode(abruptRejection(exec, deferred)); | |
376 | } while (true); | |
377 | } | |
378 | ||
379 | EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec) | |
380 | { | |
381 | // -- Promise.all(iterable) -- | |
382 | ||
383 | JSValue iterable = exec->argument(0); | |
384 | VM& vm = exec->vm(); | |
385 | ||
386 | // 1. Let 'C' be the this value. | |
387 | JSValue C = exec->thisValue(); | |
388 | ||
389 | // 2. Let 'deferred' be the result of calling GetDeferred(C). | |
390 | JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); | |
391 | ||
392 | // 3. ReturnIfAbrupt(deferred). | |
393 | if (exec->hadException()) | |
394 | return JSValue::encode(jsUndefined()); | |
395 | ||
396 | // NOTE: A non-abrupt completion of createJSPromiseDeferredFromConstructor implies that | |
397 | // C and deferredValue are objects. | |
398 | JSObject* thisObject = asObject(C); | |
399 | JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); | |
400 | ||
401 | // 4. Let 'iterator' be the result of calling GetIterator(iterable). | |
402 | JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); | |
403 | if (exec->hadException()) | |
404 | return JSValue::encode(abruptRejection(exec, deferred)); | |
405 | ||
406 | CallData iteratorFunctionCallData; | |
407 | CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); | |
408 | if (iteratorFunctionCallType == CallTypeNone) { | |
409 | throwTypeError(exec); | |
410 | return JSValue::encode(abruptRejection(exec, deferred)); | |
411 | } | |
412 | ||
413 | ArgList iteratorFunctionArguments; | |
414 | JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); | |
415 | ||
416 | // 5. RejectIfAbrupt(iterator, deferred). | |
417 | if (exec->hadException()) | |
418 | return JSValue::encode(abruptRejection(exec, deferred)); | |
419 | ||
420 | // 6. Let 'values' be the result of calling ArrayCreate(0). | |
421 | JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject()); | |
422 | ||
423 | // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }. | |
424 | NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0)); | |
425 | ||
426 | // 8. Let 'index' be 0. | |
427 | unsigned index = 0; | |
428 | ||
429 | // 9. Repeat. | |
430 | do { | |
431 | // i. Let 'next' be the result of calling IteratorStep(iterator). | |
432 | JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); | |
433 | if (exec->hadException()) | |
434 | return JSValue::encode(abruptRejection(exec, deferred)); | |
435 | ||
436 | CallData nextFunctionCallData; | |
437 | CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); | |
438 | if (nextFunctionCallType == CallTypeNone) { | |
439 | throwTypeError(exec); | |
440 | return JSValue::encode(abruptRejection(exec, deferred)); | |
441 | } | |
442 | ||
443 | MarkedArgumentBuffer nextFunctionArguments; | |
444 | nextFunctionArguments.append(jsUndefined()); | |
445 | JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); | |
446 | ||
447 | // ii. RejectIfAbrupt(next, deferred). | |
448 | if (exec->hadException()) | |
449 | return JSValue::encode(abruptRejection(exec, deferred)); | |
450 | ||
451 | // iii. If 'next' is false, | |
452 | // Note: We implement this as an iterationTerminator | |
453 | if (next == vm.iterationTerminator.get()) { | |
454 | // a. If 'index' is 0, | |
455 | if (!index) { | |
456 | // a. Let 'resolveResult' be the result of calling the [[Call]] internal method | |
457 | // of deferred.[[Resolve]] with undefined as thisArgument and a List containing | |
458 | // values as argumentsList. | |
459 | performDeferredResolve(exec, deferred, values); | |
460 | ||
461 | // b. ReturnIfAbrupt(resolveResult). | |
462 | if (exec->hadException()) | |
463 | return JSValue::encode(jsUndefined()); | |
464 | } | |
465 | ||
466 | // b. Return deferred.[[Promise]]. | |
467 | return JSValue::encode(deferred->promise()); | |
468 | } | |
469 | ||
470 | // iv. Let 'nextValue' be the result of calling IteratorValue(next). | |
471 | // v. RejectIfAbrupt(nextValue, deferred). | |
472 | // Note: 'next' is already the value, so there is nothing to do here. | |
473 | ||
474 | // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). | |
475 | JSValue castFunction = C.get(exec, vm.propertyNames->cast); | |
476 | if (exec->hadException()) | |
477 | return JSValue::encode(abruptRejection(exec, deferred)); | |
478 | ||
479 | CallData castFunctionCallData; | |
480 | CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); | |
481 | if (castFunctionCallType == CallTypeNone) { | |
482 | throwTypeError(exec); | |
483 | return JSValue::encode(abruptRejection(exec, deferred)); | |
484 | } | |
485 | ||
486 | MarkedArgumentBuffer castFunctionArguments; | |
487 | castFunctionArguments.append(next); | |
488 | JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); | |
489 | ||
490 | // vii. RejectIfAbrupt(nextPromise, deferred). | |
491 | if (exec->hadException()) | |
492 | return JSValue::encode(abruptRejection(exec, deferred)); | |
493 | ||
494 | // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions. | |
495 | JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject()); | |
496 | ||
497 | // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'. | |
498 | countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index)); | |
499 | ||
500 | // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'. | |
501 | countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values); | |
502 | ||
503 | // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'. | |
504 | countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred); | |
505 | ||
506 | // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'. | |
507 | countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder); | |
508 | ||
509 | // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])). | |
510 | JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); | |
511 | if (exec->hadException()) | |
512 | return JSValue::encode(abruptRejection(exec, deferred)); | |
513 | ||
514 | CallData thenFunctionCallData; | |
515 | CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); | |
516 | if (thenFunctionCallType == CallTypeNone) { | |
517 | throwTypeError(exec); | |
518 | return JSValue::encode(abruptRejection(exec, deferred)); | |
519 | } | |
520 | ||
521 | MarkedArgumentBuffer thenFunctionArguments; | |
522 | thenFunctionArguments.append(countdownFunction); | |
523 | thenFunctionArguments.append(deferred->reject()); | |
524 | ||
525 | call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); | |
526 | ||
527 | // xiv. RejectIfAbrupt(result, deferred). | |
528 | if (exec->hadException()) | |
529 | return JSValue::encode(abruptRejection(exec, deferred)); | |
530 | ||
531 | // xv. Set index to index + 1. | |
532 | index++; | |
533 | ||
534 | // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1. | |
535 | uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1; | |
536 | countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); | |
537 | } while (true); | |
538 | } | |
539 | ||
540 | JSPromise* constructPromise(ExecState* exec, JSGlobalObject* globalObject, JSFunction* resolver) | |
541 | { | |
542 | JSPromiseConstructor* promiseConstructor = globalObject->promiseConstructor(); | |
543 | ||
544 | ConstructData constructData; | |
545 | ConstructType constructType = getConstructData(promiseConstructor, constructData); | |
546 | ASSERT(constructType != ConstructTypeNone); | |
547 | ||
548 | MarkedArgumentBuffer arguments; | |
549 | arguments.append(resolver); | |
550 | ||
551 | return jsCast<JSPromise*>(construct(exec, promiseConstructor, constructType, constructData, arguments)); | |
552 | } | |
553 | ||
554 | } // namespace JSC | |
555 | ||
556 | #endif // ENABLE(PROMISES) |