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
42namespace JSC {
43
44STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor);
45
46static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState*);
47static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState*);
48static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState*);
49static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState*);
50static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState*);
51}
52
53#include "JSPromiseConstructor.lut.h"
54
55namespace JSC {
56
57const 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
69JSPromiseConstructor* 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
76Structure* JSPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
77{
78    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
79}
80
81JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure)
82    : InternalFunction(vm, structure)
83{
84}
85
86void 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
93static 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
150ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData)
151{
152    constructData.native.function = constructPromise;
153    return ConstructTypeHost;
154}
155
156CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData)
157{
158    callData.native.function = constructPromise;
159    return CallTypeHost;
160}
161
162bool 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
167EncodedJSValue 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
207EncodedJSValue 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
237EncodedJSValue 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
267EncodedJSValue 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
379EncodedJSValue 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
540JSPromise* 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)
557