4#include <QCoreApplication>
6#include <private/qv4promiseobject_p.h>
7#include <private/qv4symbol_p.h>
13using namespace QV4::Promise;
29bool isPromise(
const Value &object)
31 return object.as<PromiseObject>() !=
nullptr;
34bool isCallable(
const Value &object)
36 return object.as<FunctionObject>() !=
nullptr;
39void insertIdLengthTag(Scope& scope, Heap::FunctionObject* function)
41 ScopedFunctionObject scopedFunction(scope, function);
42 scopedFunction->insertMember(scope.engine->id_length(), Primitive::fromInt32(1), Attr_NotWritable|Attr_NotEnumerable);
45void dropException(QV4::ExecutionEngine* e)
47 e->hasException =
false;
59 ReactionEvent(ExecutionEngine *e,
const Value *reaction_,
const Value *resolution_)
71 ResolveThenableEvent(ExecutionEngine *e,
const PromiseObject *promise_,
const Object *thenable_,
const FunctionObject *then_)
84ReactionHandler::ReactionHandler(QObject *parent)
88ReactionHandler::~ReactionHandler()
91void ReactionHandler::addReaction(ExecutionEngine *e,
const Value *reaction,
const Value *value)
93 QCoreApplication::postEvent(
this,
new ReactionEvent(e, reaction, value));
96void ReactionHandler::addResolveThenable(ExecutionEngine *e,
const PromiseObject *promise,
const Object *thenable,
const FunctionObject *then)
98 QCoreApplication::postEvent(
this,
new ResolveThenableEvent(e, promise, thenable, then));
101void ReactionHandler::customEvent(QEvent *event)
105 const int type = event->type();
106 if (type == PROMISE_REACTION_EVENT)
107 executeReaction(
static_cast<ReactionEvent*>(event));
109 if (type == PROMISE_RESOLVE_THENABLE_EVENT)
110 executeResolveThenable(
static_cast<ResolveThenableEvent*>(event));
114void ReactionHandler::executeReaction(ReactionEvent *event)
116 Scope scope(event->reaction.engine());
118 Scoped<QV4::PromiseReaction> ro(scope, event->reaction.as<QV4::PromiseReaction>());
119 Scoped<QV4::PromiseCapability> capability(scope, ro->d()->capability);
121 ScopedValue resolution(scope, event->resolution.value());
122 ScopedValue promise(scope, capability->d()->promise);
124 if (ro->d()->type == Heap::PromiseReaction::Function) {
125 ScopedFunctionObject handler(scope, ro->d()->handler.as<QV4::FunctionObject>());
126 ScopedValue result(scope, handler->call(promise, resolution, 1));
128 ScopedFunctionObject reaction(scope);
129 if (scope.hasException()) {
130 reaction = capability->d()->reject.as<QV4::FunctionObject>();
131 result = scope.engine->catchException();
133 reaction = capability->d()->resolve.as<QV4::FunctionObject>();
136 reaction->call(promise, result, 1);
138 ScopedFunctionObject reaction(scope);
139 if (ro->d()->type == Heap::PromiseReaction::Identity) {
140 reaction = capability->d()->resolve.as<QV4::FunctionObject>();
142 reaction = capability->d()->reject.as<QV4::FunctionObject>();
145 reaction->call(promise, resolution, 1);
152class FunctionBuilder {
154 static Heap::FunctionObject *makeResolveFunction(ExecutionEngine* e, QV4::Heap::PromiseObject *promise) {
156 Scoped<QV4::ResolveWrapper> resolveWrapper(scope, e->memoryManager->allocate<QV4::ResolveWrapper>());
158 insertIdLengthTag(scope, resolveWrapper->d());
159 resolveWrapper->d()->promise.set(e, promise);
161 return resolveWrapper->d();
164 static Heap::FunctionObject *makeRejectFunction(ExecutionEngine* e, QV4::Heap::PromiseObject *promise) {
166 Scoped<QV4::RejectWrapper> rejectWrapper(scope, e->memoryManager->allocate<QV4::RejectWrapper>());
168 insertIdLengthTag(scope, rejectWrapper->d());
169 rejectWrapper->d()->promise.set(e, promise);
171 return rejectWrapper->d();
174 static Heap::FunctionObject *makeResolveElementFunction(ExecutionEngine* e, uint index, Heap::PromiseExecutionState *executionState)
177 Scoped<QV4::ResolveElementWrapper> resolveElementWrapper(scope, e->memoryManager->allocate<QV4::ResolveElementWrapper>());
179 resolveElementWrapper->d()->index = index;
180 resolveElementWrapper->d()->alreadyResolved =
false;
181 resolveElementWrapper->d()->state.set(e, executionState);
183 insertIdLengthTag(scope, resolveElementWrapper->d());
185 return resolveElementWrapper->d();
192void ReactionHandler::executeResolveThenable(ResolveThenableEvent *event)
194 Scope scope(event->then.engine());
195 JSCallArguments jsCallData(scope, 2);
196 PromiseObject *promise = event->promise.as<PromiseObject>();
197 ScopedFunctionObject resolve {scope, FunctionBuilder::makeResolveFunction(scope.engine, promise->d())};
198 ScopedFunctionObject reject {scope, FunctionBuilder::makeRejectFunction(scope.engine, promise->d())};
199 jsCallData.args[0] = resolve;
200 jsCallData.args[1] = reject;
201 jsCallData.thisObject = event->thenable.as<QV4::Object>();
202 event->then.as<
const FunctionObject>()->call(jsCallData);
203 if (scope.hasException()) {
204 JSCallArguments rejectCallData(scope, 1);
205 rejectCallData.args[0] = scope.engine->catchException();
206 Scoped<RejectWrapper> reject {scope, scope.engine->memoryManager->allocate<QV4::RejectWrapper>()};
207 reject->call(rejectCallData);
211void Heap::PromiseObject::setState(PromiseObject::State state)
216bool Heap::PromiseObject::isSettled()
const
218 return (state != Pending);
221bool Heap::PromiseObject::isPending()
const
223 return (state == Pending);
226bool Heap::PromiseObject::isFulfilled()
const
228 return (state == Fulfilled);
231bool Heap::PromiseObject::isRejected()
const
233 return (state == Rejected);
236void Heap::PromiseObject::triggerFullfillReactions(ExecutionEngine *e)
239 ScopedArrayObject a(scope, fulfillReactions);
240 if (a->arrayData()) {
241 Scoped<QV4::ArrayData> ad(scope, a->arrayData());
242 const uint sz = ad->length();
243 ScopedValue value(scope, resolution);
244 for (uint i = 0; i < sz; i++) {
245 Scoped<QV4::PromiseReaction> r(scope, ad->get(i));
246 r->d()->triggerWithValue(scope.engine, value);
251void Heap::PromiseObject::triggerRejectReactions(ExecutionEngine *e)
254 ScopedArrayObject a(scope, rejectReactions);
255 if (a->arrayData()) {
256 Scoped<QV4::ArrayData> ad(scope, a->arrayData());
257 const uint sz = ad->d()->length();
258 ScopedValue value(scope, resolution);
259 for (uint i = 0; i < sz; i++) {
260 Scoped<QV4::PromiseReaction> r(scope, ad->d()->get(i));
261 r->d()->triggerWithValue(scope.engine, value);
266Heap::PromiseReaction *Heap::PromiseReaction::createFulfillReaction(ExecutionEngine* e,
267 const QV4::PromiseCapability *capability,
const QV4::FunctionObject *onFulfilled)
270 Scoped<QV4::PromiseReaction> fulfillReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
271 fulfillReaction->d()->capability.set(e, capability->d());
274 QV4::ScopedFunctionObject scopedFullfillReaction(scope, onFulfilled);
275 if (!scopedFullfillReaction) {
276 fulfillReaction->d()->type = PromiseReaction::Identity;
278 fulfillReaction->d()->type = PromiseReaction::Function;
279 fulfillReaction->d()->handler.set(e, scopedFullfillReaction);
282 fulfillReaction->d()->type = PromiseReaction::Identity;
285 return fulfillReaction->d();
288Heap::PromiseReaction *Heap::PromiseReaction::createRejectReaction(ExecutionEngine* e,
289 const QV4::PromiseCapability *capability,
const QV4::FunctionObject *onRejected)
292 Scoped<QV4::PromiseReaction> rejectReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
293 rejectReaction->d()->capability.set(e, capability->d());
296 ScopedFunctionObject scopedRejectReaction(scope, onRejected);
297 if (!scopedRejectReaction) {
298 rejectReaction->d()->type = PromiseReaction::Thrower;
300 rejectReaction->d()->type = PromiseReaction::Function;
301 rejectReaction->d()->handler.set(e, scopedRejectReaction);
304 rejectReaction->d()->type = PromiseReaction::Thrower;
307 return rejectReaction->d();
310void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e,
const Value *value)
313 auto handler = e->getPromiseReactionHandler();
314 ScopedValue reaction(scope, Value::fromHeapObject(
this));
315 handler->addReaction(e, reaction, value);
318void Heap::PromiseCtor::init(QV4::ExecutionEngine *engine)
320 Heap::FunctionObject::init(engine, QStringLiteral(
"Promise"));
323void Heap::PromiseObject::init(ExecutionEngine *e)
325 Heap::Object::init();
328 Heap::ArrayObject* a = e->newArrayObject();
329 fulfillReactions.set(e, a);
333 Heap::ArrayObject* a = e->newArrayObject();
334 rejectReactions.set(e, a);
338void Heap::CapabilitiesExecutorWrapper::init()
340 Heap::FunctionObject::init();
343void Heap::CapabilitiesExecutorWrapper::destroy()
345 Heap::FunctionObject::destroy();
348void Heap::PromiseExecutionState::init()
351 remainingElementCount = 0;
354void Heap::ResolveElementWrapper::init()
357 alreadyResolved =
false;
359 Heap::FunctionObject::init();
362void Heap::ResolveWrapper::init()
364 alreadyResolved =
false;
365 Heap::FunctionObject::init();
368void Heap::RejectWrapper::init()
370 alreadyResolved =
false;
371 Heap::FunctionObject::init();
374ReturnedValue PromiseCtor::virtualCall(
const FunctionObject *f,
const Value *,
const Value *,
int)
382ReturnedValue PromiseCtor::virtualCallAsConstructor(
const FunctionObject *f,
const Value *argv,
int argc,
const Value *newTarget)
391 ScopedFunctionObject executor(scope, argv[0].as<
const FunctionObject>());
395 Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
396 if (scope.hasException())
397 return Encode::undefined();
399 a->d()->state = Heap::PromiseObject::Pending;
405 ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
406 ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
408 JSCallArguments jsCallData(scope, 2);
409 jsCallData.args[0] = resolve;
410 jsCallData.args[1] = reject;
413 executor->call(jsCallData);
415 if (scope.hasException()) {
416 ScopedValue exception {scope, scope.engine->catchException()};
417 JSCallArguments callData {scope, 1};
418 callData.args[0] = exception;
419 reject->call(callData);
423 a->setProtoFromNewTarget(newTarget);
425 return a->asReturnedValue();
429ReturnedValue PromiseCtor::method_resolve(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
433 ExecutionEngine* e = scope.engine;
434 if (!thisObject || !thisObject->isObject())
437 ScopedValue x(scope);
439 x = Encode::undefined();
445 if (isPromise(x) && x->isObject()) {
446 ScopedObject so(scope, thisObject);
448 ScopedObject constructor(scope, x->objectValue()->get(e->id_constructor()));
449 if (so->d() == constructor->d())
450 return x->asReturnedValue();
454 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
456 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<
const FunctionObject>(), capability));
457 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
461 ScopedValue undefined(scope, Value::undefinedValue());
462 ScopedFunctionObject resolve(scope, capability->d()->resolve);
463 resolve->call(undefined, x, 1);
465 return newPromise.asReturnedValue();
468ReturnedValue PromiseCtor::method_reject(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
471 ExecutionEngine *e = scope.engine;
474 if (!thisObject || !thisObject->isObject())
477 ScopedValue r(scope);
479 r = Encode::undefined();
485 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
487 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<
const FunctionObject>(), capability));
488 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
491 ScopedValue undefined(scope, Value::undefinedValue());
492 ScopedFunctionObject reject(scope, capability->d()->reject.as<
const FunctionObject>());
494 reject->call(undefined, r, 1);
496 return newPromise.asReturnedValue();
499ReturnedValue PromiseCtor::method_all(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int)
502 ExecutionEngine* e = scope.engine;
505 if (!thisObject || !thisObject->isObject())
508 ScopedString resolveName(scope, e->newIdentifier(QStringLiteral(
"resolve")));
509 ScopedString thenName(scope, e->newIdentifier(QStringLiteral(
"then")));
511 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
513 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
514 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject)) {
515 if (scope.hasException()) {
516 return e->exceptionValue->asReturnedValue();
521 capability->d()->promise.set(e, newPromise);
523 ScopedFunctionObject reject(scope, capability->d()->reject);
525 ScopedObject itemsObject(scope, argv);
526 ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject,
true));
527 if (!iteratorObject || scope.hasException()) {
528 ScopedObject error(scope);
529 if (scope.hasException()) {
530 error = e->exceptionValue;
533 error = e->newTypeErrorObject(QStringLiteral(
"Type error"));
535 reject->call(newPromise, error, 1);
536 return newPromise.asReturnedValue();
539 Scoped<QV4::PromiseExecutionState> executionState(scope, e->memoryManager->allocate<QV4::PromiseExecutionState>());
540 executionState->d()->remainingElementCount = 1;
541 executionState->d()->capability.set(e, capability);
543 Scoped<QV4::ArrayObject> results(scope, e->newArrayObject(0));
544 executionState->d()->values.set(e, results);
546 ScopedValue doneValue(scope);
550 ScopedValue nextValue(scope);
551 doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
553 if (doneValue->toBoolean())
556 ScopedObject nextObject(scope);
557 if (nextValue->isObject()) {
558 nextObject = *nextValue;
559 }
else if (nextValue->isBoolean()) {
560 nextObject = e->newBooleanObject(nextValue->toBoolean());
561 }
else if (nextValue->isInteger() || nextValue->isDouble()) {
562 nextObject = e->newNumberObject(nextValue->toInteger());
563 }
else if (nextValue->isString()) {
564 ScopedString scopedString(scope, nextValue->toString(scope.engine));
565 nextObject = e->newStringObject(scopedString);
568 ScopedFunctionObject resolve(scope, thisObject->as<Object>()->get(resolveName));
569 if (!resolve || scope.hasException()) {
570 ScopedValue completion(scope);
571 if (!scope.hasException()) {
572 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
574 completion = e->exceptionValue->asReturnedValue();
578 if (!doneValue->toBoolean())
579 completion = Runtime::IteratorClose::call(e, iteratorObject);
581 reject->call(newPromise, completion, 1);
582 return newPromise.asReturnedValue();
585 ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
586 if (scope.hasException() || !nextPromise) {
587 ScopedValue completion(scope, doneValue->toBoolean()
588 ? Encode::undefined()
589 : Runtime::IteratorClose::call(e, iteratorObject));
590 if (scope.hasException()) {
591 completion = e->exceptionValue->asReturnedValue();
594 reject->call(newPromise, completion, 1);
595 return newPromise.asReturnedValue();
598 executionState->d()->remainingElementCount++;
600 ScopedFunctionObject then(scope, nextPromise->get(thenName));
601 if (!then || scope.hasException()) {
602 ScopedValue completion(scope);
603 if (!scope.hasException()) {
604 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
606 completion = e->exceptionValue->asReturnedValue();
610 if (!doneValue->toBoolean())
611 completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
613 reject->call(newPromise, completion, 1);
614 return newPromise.asReturnedValue();
617 ScopedFunctionObject resolveElement(scope, FunctionBuilder::makeResolveElementFunction(e, index, executionState->d()));
619 JSCallArguments jsCallData(scope, 2);
620 jsCallData.args[0] = resolveElement;
621 jsCallData.args[1] = reject;
622 jsCallData.thisObject = nextPromise;
624 then->call(jsCallData);
625 if (scope.hasException()) {
626 ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
629 if (!doneValue->toBoolean())
630 completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
632 reject->call(newPromise, completion, 1);
633 return newPromise.asReturnedValue();
640 executionState->d()->remainingElementCount--;
641 if (executionState->d()->remainingElementCount == 0) {
642 const FunctionObject *resolve = capability->d()->resolve.as<FunctionObject>();
646 ScopedValue values(scope, executionState->d()->values);
647 resolve->call(newPromise, values, 1);
648 if (scope.hasException()) {
650 reject->call(newPromise, scope.engine->exceptionValue, 1);
654 return newPromise.asReturnedValue();
657ReturnedValue PromiseCtor::method_race(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int)
660 ExecutionEngine* e = scope.engine;
662 if (!thisObject || !thisObject->isObject())
665 ScopedString resolveName(scope, e->newIdentifier(QStringLiteral(
"resolve")));
666 ScopedString thenName(scope, e->newIdentifier(QStringLiteral(
"then")));
668 Scoped<PromiseCapability> capability(scope, scope.engine->memoryManager->allocate<QV4::PromiseCapability>());
670 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
671 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
673 capability->d()->promise.set(scope.engine, newPromise);
675 ScopedFunctionObject reject(scope, capability->d()->reject);
677 ScopedObject itemsObject(scope, argv);
678 ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject,
true));
679 if (!iteratorObject) {
680 ScopedObject error(scope, e->newTypeErrorObject(QStringLiteral(
"Type error")));
681 reject->call(newPromise, error, 1);
682 return newPromise.asReturnedValue();
685 ScopedValue doneValue(scope);
688 ScopedValue nextValue(scope);
689 doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
691 if (scope.hasException()) {
692 ScopedValue completion(scope, doneValue->toBoolean()
693 ? Encode::undefined()
694 : Runtime::IteratorClose::call(e, iteratorObject));
695 if (scope.hasException()) {
696 completion = e->exceptionValue->asReturnedValue();
699 reject->call(newPromise, completion, 1);
700 return newPromise.asReturnedValue();
703 if (doneValue->toBoolean())
706 ScopedObject nextObject(scope);
707 if (nextValue->isObject()) {
708 nextObject = *nextValue;
709 }
else if (nextValue->isBoolean()) {
710 nextObject = scope.engine->newBooleanObject(nextValue->toBoolean());
711 }
else if (nextValue->isInteger() || nextValue->isDouble()) {
712 nextObject = scope.engine->newNumberObject(nextValue->toInteger());
713 }
else if (nextValue->isString()) {
714 ScopedString scopedString(scope, nextValue->toString(scope.engine));
715 nextObject = scope.engine->newStringObject(scopedString);
718 ScopedFunctionObject resolve(scope, thisObject->as<FunctionObject>()->get(resolveName));
719 if (!resolve || scope.hasException()) {
720 ScopedValue completion(scope);
721 if (!scope.hasException()) {
722 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
724 completion = e->exceptionValue->asReturnedValue();
728 if (!doneValue->toBoolean())
729 completion = Runtime::IteratorClose::call(e, iteratorObject);
731 reject->call(newPromise, completion, 1);
732 return newPromise.asReturnedValue();
735 ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
736 if (scope.hasException() || !nextPromise) {
737 ScopedValue completion(scope, doneValue->toBoolean()
738 ? Encode::undefined()
739 : Runtime::IteratorClose::call(e, iteratorObject));
740 if (scope.hasException()) {
741 completion = e->exceptionValue->asReturnedValue();
744 reject->call(newPromise, completion, 1);
745 return newPromise.asReturnedValue();
748 ScopedFunctionObject then(scope, nextPromise->get(thenName));
749 if (!then || scope.hasException()) {
750 ScopedValue completion(scope);
751 if (!scope.hasException()) {
752 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
754 completion = e->exceptionValue->asReturnedValue();
758 if (!doneValue->toBoolean())
759 completion = Runtime::IteratorClose::call(e, iteratorObject);
761 reject->call(newPromise, completion, 1);
762 return newPromise.asReturnedValue();
765 ScopedFunctionObject resolveOriginalPromise(scope, capability->d()->resolve);
767 JSCallArguments jsCallData(scope, 2);
768 jsCallData.args[0] = resolveOriginalPromise;
769 jsCallData.args[1] = reject;
770 jsCallData.thisObject = nextPromise;
772 then->call(jsCallData);
773 if (scope.hasException()) {
774 ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
777 if (!doneValue->toBoolean())
778 completion = Runtime::IteratorClose::call(e, iteratorObject);
780 reject->call(newPromise, completion, 1);
781 return newPromise.asReturnedValue();
785 return newPromise.asReturnedValue();
788void PromisePrototype::init(ExecutionEngine *engine, Object *ctor)
791 ScopedObject o(scope);
793 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
794 ctor->defineReadonlyProperty(engine->id_prototype(), (o =
this));
796 ctor->defineDefaultProperty(QStringLiteral(
"resolve"), PromiseCtor::method_resolve, 1);
797 ctor->defineDefaultProperty(QStringLiteral(
"reject"), PromiseCtor::method_reject, 1);
798 ctor->defineDefaultProperty(QStringLiteral(
"all"), PromiseCtor::method_all, 1);
799 ctor->defineDefaultProperty(QStringLiteral(
"race"), PromiseCtor::method_race, 1);
800 ctor->addSymbolSpecies();
802 defineDefaultProperty(engine->id_constructor(), (o = ctor));
804 ScopedString val(scope, engine->newString(QLatin1String(
"Promise")));
805 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
807 defineDefaultProperty(QStringLiteral(
"then"), method_then, 2);
808 defineDefaultProperty(QStringLiteral(
"catch"), method_catch, 1);
811ReturnedValue PromisePrototype::method_then(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
815 ExecutionEngine* e = scope.engine;
817 Scoped<QV4::PromiseObject> promise(scope, thisObject);
821 ScopedFunctionObject onFulfilled(scope);
823 onFulfilled = argv[0];
825 onFulfilled = Encode::undefined();
828 ScopedFunctionObject onRejected(scope);
830 onRejected = argv[1];
832 onRejected = Encode::undefined();
835 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<PromiseCapability>());
837 ScopedFunctionObject constructor(scope, promise->get(e->id_constructor()));
838 if (!constructor || scope.hasException())
842 ScopedObject nextPromise(scope, e->newPromiseObject(constructor, capability));
843 capability->d()->promise.set(scope.engine, nextPromise);
845 Scoped<PromiseReaction> fulfillReaction(scope, Heap::PromiseReaction::createFulfillReaction(scope.engine, capability, onFulfilled));
846 Scoped<PromiseReaction> rejectReaction(scope, Heap::PromiseReaction::createRejectReaction(scope.engine, capability, onRejected));
848 ScopedValue resolution(scope, promise->d()->resolution);
849 if (promise->d()->isPending()) {
852 ScopedArrayObject a(scope, promise->d()->fulfillReactions);
853 ScopedValue newValue(scope, fulfillReaction->d());
854 a->push_back(newValue);
859 ScopedArrayObject a(scope, promise->d()->rejectReactions);
860 ScopedValue newValue(scope, rejectReaction->d());
861 a->push_back(newValue);
863 }
else if (promise->d()->isFulfilled()) {
865 fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
866 }
else if (promise->d()->isRejected()) {
868 rejectReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
871 THROW_GENERIC_ERROR(
"Should never be thrown. Unknown promise state");
874 return nextPromise->asReturnedValue();
877ReturnedValue PromisePrototype::method_catch(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
880 Scoped<Object> promise(scope);
881 if (thisObject->isObject()) {
882 promise.setPointer(thisObject->as<Object>());
883 }
else if (thisObject->isBoolean()) {
884 promise = scope.engine->newBooleanObject(thisObject->toBoolean());
885 }
else if (thisObject->isInteger() || thisObject->isDouble()) {
886 promise = scope.engine->newNumberObject(thisObject->toInteger());
887 }
else if (thisObject->isString()) {
888 ScopedString scopedString(scope, thisObject->toString(scope.engine));
889 promise = scope.engine->newStringObject(scopedString);
894 ScopedValue onRejected(scope);
896 onRejected = Encode::undefined();
898 onRejected = argv[0];
901 JSCallArguments jsCallData(scope, 2);
902 jsCallData.args[0] = Encode::undefined();
903 jsCallData.args[1] = onRejected;
904 jsCallData.thisObject = promise;
906 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"then")));
907 ScopedFunctionObject then(scope, promise->get(thenName));
908 if (!then || scope.hasException())
911 return then->call(jsCallData);
914ReturnedValue CapabilitiesExecutorWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
916 Q_UNUSED(thisObject);
919 const CapabilitiesExecutorWrapper* self =
static_cast<
const CapabilitiesExecutorWrapper*>(f);
920 Heap::PromiseCapability *capabilities = self->d()->capabilities;
922 if (!capabilities->resolve.isUndefined() || !capabilities->reject.isUndefined())
925 if (argc >= 1 && !argv[0].isUndefined())
926 capabilities->resolve.set(scope.engine, argv[0]);
928 if (argc >= 2 && !argv[1].isUndefined())
929 capabilities->reject.set(scope.engine, argv[1]);
931 return Encode::undefined();
934ReturnedValue ResolveElementWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
936 Q_UNUSED(thisObject);
939 const ResolveElementWrapper* self =
static_cast<
const ResolveElementWrapper*>(f);
941 if (self->d()->alreadyResolved)
942 return Encode::undefined();
944 ScopedValue value(scope);
948 value = Encode::undefined();
951 Scoped<PromiseExecutionState> so(scope, self->d()->state);
952 self->d()->alreadyResolved =
true;
954 ScopedObject values(scope, so->d()->values);
955 values->arraySet(self->d()->index, value);
957 so->d()->remainingElementCount--;
958 if (so->d()->remainingElementCount == 0) {
959 Scoped<PromiseCapability> capability(scope, so->d()->capability);
960 ScopedValue promise(scope, capability->d()->promise);
961 ScopedFunctionObject resolve(scope, capability->d()->resolve.as<QV4::FunctionObject>());
962 resolve->call(promise, values, 1);
965 return Encode::undefined();
968ReturnedValue ResolveWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
972 Q_UNUSED(thisObject);
975 const ResolveWrapper *self =
static_cast<
const ResolveWrapper*>(f);
977 Scoped<PromiseObject> promise(scope, self->d()->promise);
979 if (self->d()->alreadyResolved || !promise->d()->isPending())
980 return Encode::undefined();
983 self->d()->alreadyResolved =
true;
985 ScopedValue resolution(scope);
987 resolution = argv[0];
989 resolution = Encode::undefined();
992 if (!resolution->isObject()) {
995 promise->d()->setState(Heap::PromiseObject::Fulfilled);
996 promise->d()->resolution.set(scope.engine, resolution);
997 promise->d()->triggerFullfillReactions(scope.engine);
1000 auto resolutionObject = resolution->as<Object>();
1001 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"then")));
1004 ScopedFunctionObject thenAction { scope, resolutionObject->get(thenName)};
1006 if (scope.hasException()) {
1008 ScopedValue thenValue {scope, scope.engine->catchException()};
1009 promise->d()->setState(Heap::PromiseObject::Rejected);
1010 promise->d()->resolution.set(scope.engine, thenValue);
1011 promise->d()->triggerRejectReactions(scope.engine);
1015 promise->d()->setState(Heap::PromiseObject::Fulfilled);
1016 promise->d()->resolution.set(scope.engine, resolution);
1017 promise->d()->triggerFullfillReactions(scope.engine);
1020 scope.engine->getPromiseReactionHandler()->addResolveThenable(scope.engine, promise.getPointer(), resolutionObject, thenAction);
1025 return Encode::undefined();
1028ReturnedValue RejectWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
1030 Q_UNUSED(thisObject);
1033 const RejectWrapper *self =
static_cast<
const RejectWrapper*>(f);
1035 Scoped<PromiseObject> promise(scope, self->d()->promise);
1036 if (self->d()->alreadyResolved || !promise->d()->isPending())
1037 return Encode::undefined();
1039 ScopedValue value(scope);
1043 value = Encode::undefined();
1046 if (!isPromise(value)) {
1047 self->d()->alreadyResolved =
true;
1048 promise->d()->setState(Heap::PromiseObject::Rejected);
1049 promise->d()->resolution.set(scope.engine, value);
1051 promise->d()->triggerRejectReactions(scope.engine);
1054 PromiseObject *promise = value->as<PromiseObject>();
1055 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"catch")));
1057 ScopedFunctionObject then(scope, promise->get(thenName));
1058 JSCallArguments jsCallData(scope, 2);
1059 jsCallData.args[0] = *f;
1060 jsCallData.args[1] = Encode::undefined();
1061 jsCallData.thisObject = value;
1063 then->call(jsCallData);
1066 return Encode::undefined();
1071#include "moc_qv4promiseobject_p.cpp"
const int PROMISE_REACTION_EVENT
const int PROMISE_RESOLVE_THENABLE_EVENT
DEFINE_OBJECT_VTABLE(PromiseReaction)
DEFINE_OBJECT_VTABLE(PromiseExecutionState)
DEFINE_OBJECT_VTABLE(ResolveElementWrapper)
DEFINE_OBJECT_VTABLE(ResolveWrapper)
DEFINE_OBJECT_VTABLE(PromiseCapability)
DEFINE_OBJECT_VTABLE(CapabilitiesExecutorWrapper)
DEFINE_OBJECT_VTABLE(PromiseCtor)
DEFINE_OBJECT_VTABLE(RejectWrapper)
DEFINE_OBJECT_VTABLE(PromiseObject)
QV4::PersistentValue resolution
ReactionEvent(ExecutionEngine *e, const Value *reaction_, const Value *resolution_)
QV4::PersistentValue reaction
QV4::PersistentValue thenable
QV4::PersistentValue promise
QV4::PersistentValue then
ResolveThenableEvent(ExecutionEngine *e, const PromiseObject *promise_, const Object *thenable_, const FunctionObject *then_)