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 Scoped<QV4::PromiseReaction> r(scope);
245 for (uint i = 0; i < sz; i++) {
247 r->d()->triggerWithValue(scope.engine, value);
252void Heap::PromiseObject::triggerRejectReactions(ExecutionEngine *e)
255 ScopedArrayObject a(scope, rejectReactions);
256 if (a->arrayData()) {
257 Scoped<QV4::ArrayData> ad(scope, a->arrayData());
258 const uint sz = ad->d()->length();
259 ScopedValue value(scope, resolution);
260 Scoped<QV4::PromiseReaction> r(scope);
261 for (uint i = 0; i < sz; i++) {
263 r->d()->triggerWithValue(scope.engine, value);
268Heap::PromiseReaction *Heap::PromiseReaction::createFulfillReaction(ExecutionEngine* e,
269 const QV4::PromiseCapability *capability,
const QV4::FunctionObject *onFulfilled)
272 Scoped<QV4::PromiseReaction> fulfillReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
273 fulfillReaction->d()->capability.set(e, capability->d());
276 QV4::ScopedFunctionObject scopedFullfillReaction(scope, onFulfilled);
277 if (!scopedFullfillReaction) {
278 fulfillReaction->d()->type = PromiseReaction::Identity;
280 fulfillReaction->d()->type = PromiseReaction::Function;
281 fulfillReaction->d()->handler.set(e, scopedFullfillReaction);
284 fulfillReaction->d()->type = PromiseReaction::Identity;
287 return fulfillReaction->d();
290Heap::PromiseReaction *Heap::PromiseReaction::createRejectReaction(ExecutionEngine* e,
291 const QV4::PromiseCapability *capability,
const QV4::FunctionObject *onRejected)
294 Scoped<QV4::PromiseReaction> rejectReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
295 rejectReaction->d()->capability.set(e, capability->d());
298 ScopedFunctionObject scopedRejectReaction(scope, onRejected);
299 if (!scopedRejectReaction) {
300 rejectReaction->d()->type = PromiseReaction::Thrower;
302 rejectReaction->d()->type = PromiseReaction::Function;
303 rejectReaction->d()->handler.set(e, scopedRejectReaction);
306 rejectReaction->d()->type = PromiseReaction::Thrower;
309 return rejectReaction->d();
312void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e,
const Value *value)
315 auto handler = e->getPromiseReactionHandler();
316 ScopedValue reaction(scope, Value::fromHeapObject(
this));
317 handler->addReaction(e, reaction, value);
320void Heap::PromiseCtor::init(QV4::ExecutionEngine *engine)
322 Heap::FunctionObject::init(engine, QStringLiteral(
"Promise"));
325void Heap::PromiseObject::init(ExecutionEngine *e)
327 Heap::Object::init();
330 Heap::ArrayObject* a = e->newArrayObject();
331 fulfillReactions.set(e, a);
335 Heap::ArrayObject* a = e->newArrayObject();
336 rejectReactions.set(e, a);
340void Heap::CapabilitiesExecutorWrapper::init()
342 Heap::FunctionObject::init();
345void Heap::CapabilitiesExecutorWrapper::destroy()
347 Heap::FunctionObject::destroy();
350void Heap::PromiseExecutionState::init()
353 remainingElementCount = 0;
356void Heap::ResolveElementWrapper::init()
359 alreadyResolved =
false;
361 Heap::FunctionObject::init();
364void Heap::ResolveWrapper::init()
366 alreadyResolved =
false;
367 Heap::FunctionObject::init();
370void Heap::RejectWrapper::init()
372 alreadyResolved =
false;
373 Heap::FunctionObject::init();
376ReturnedValue PromiseCtor::virtualCall(
const FunctionObject *f,
const Value *,
const Value *,
int)
384ReturnedValue PromiseCtor::virtualCallAsConstructor(
const FunctionObject *f,
const Value *argv,
int argc,
const Value *newTarget)
393 ScopedFunctionObject executor(scope, argv[0].as<
const FunctionObject>());
397 Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
398 if (scope.hasException())
399 return Encode::undefined();
401 a->d()->state = Heap::PromiseObject::Pending;
407 ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
408 ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
410 JSCallArguments jsCallData(scope, 2);
411 jsCallData.args[0] = resolve;
412 jsCallData.args[1] = reject;
415 executor->call(jsCallData);
417 if (scope.hasException()) {
418 ScopedValue exception {scope, scope.engine->catchException()};
419 JSCallArguments callData {scope, 1};
420 callData.args[0] = exception;
421 reject->call(callData);
425 a->setProtoFromNewTarget(newTarget);
427 return a->asReturnedValue();
431ReturnedValue PromiseCtor::method_resolve(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
435 ExecutionEngine* e = scope.engine;
436 if (!thisObject || !thisObject->isObject())
439 ScopedValue x(scope);
441 x = Encode::undefined();
447 if (isPromise(x) && x->isObject()) {
448 ScopedObject so(scope, thisObject);
450 ScopedObject constructor(scope, x->objectValue()->get(e->id_constructor()));
451 if (so->d() == constructor->d())
452 return x->asReturnedValue();
456 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
458 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<
const FunctionObject>(), capability));
459 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
463 ScopedValue undefined(scope, Value::undefinedValue());
464 ScopedFunctionObject resolve(scope, capability->d()->resolve);
465 resolve->call(undefined, x, 1);
467 return newPromise.asReturnedValue();
470ReturnedValue PromiseCtor::method_reject(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
473 ExecutionEngine *e = scope.engine;
476 if (!thisObject || !thisObject->isObject())
479 ScopedValue r(scope);
481 r = Encode::undefined();
487 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
489 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<
const FunctionObject>(), capability));
490 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
493 ScopedValue undefined(scope, Value::undefinedValue());
494 ScopedFunctionObject reject(scope, capability->d()->reject.as<
const FunctionObject>());
496 reject->call(undefined, r, 1);
498 return newPromise.asReturnedValue();
501ReturnedValue PromiseCtor::method_all(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int)
504 ExecutionEngine* e = scope.engine;
507 if (!thisObject || !thisObject->isObject())
510 ScopedString resolveName(scope, e->newIdentifier(QStringLiteral(
"resolve")));
511 ScopedString thenName(scope, e->newIdentifier(QStringLiteral(
"then")));
513 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
515 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
516 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject)) {
517 if (scope.hasException()) {
518 return e->exceptionValue->asReturnedValue();
523 capability->d()->promise.set(e, newPromise);
525 ScopedFunctionObject reject(scope, capability->d()->reject);
527 ScopedObject itemsObject(scope, argv);
528 ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject,
true));
529 if (!iteratorObject || scope.hasException()) {
530 ScopedObject error(scope);
531 if (scope.hasException()) {
532 error = e->exceptionValue;
535 error = e->newTypeErrorObject(QStringLiteral(
"Type error"));
537 reject->call(newPromise, error, 1);
538 return newPromise.asReturnedValue();
541 Scoped<QV4::PromiseExecutionState> executionState(scope, e->memoryManager->allocate<QV4::PromiseExecutionState>());
542 executionState->d()->remainingElementCount = 1;
543 executionState->d()->capability.set(e, capability);
545 Scoped<QV4::ArrayObject> results(scope, e->newArrayObject(0));
546 executionState->d()->values.set(e, results);
548 ScopedValue doneValue(scope);
552 ScopedValue nextValue(scope);
553 doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
555 if (doneValue->toBoolean())
558 ScopedObject nextObject(scope);
559 if (nextValue->isObject()) {
560 nextObject = *nextValue;
561 }
else if (nextValue->isBoolean()) {
562 nextObject = e->newBooleanObject(nextValue->toBoolean());
563 }
else if (nextValue->isInteger() || nextValue->isDouble()) {
564 nextObject = e->newNumberObject(nextValue->toInteger());
565 }
else if (nextValue->isString()) {
566 ScopedString scopedString(scope, nextValue->toString(scope.engine));
567 nextObject = e->newStringObject(scopedString);
570 ScopedFunctionObject resolve(scope, thisObject->as<Object>()->get(resolveName));
571 if (!resolve || scope.hasException()) {
572 ScopedValue completion(scope);
573 if (!scope.hasException()) {
574 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
576 completion = e->exceptionValue->asReturnedValue();
580 if (!doneValue->toBoolean())
581 completion = Runtime::IteratorClose::call(e, iteratorObject);
583 reject->call(newPromise, completion, 1);
584 return newPromise.asReturnedValue();
587 ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
588 if (scope.hasException() || !nextPromise) {
589 ScopedValue completion(scope, doneValue->toBoolean()
590 ? Encode::undefined()
591 : Runtime::IteratorClose::call(e, iteratorObject));
592 if (scope.hasException()) {
593 completion = e->exceptionValue->asReturnedValue();
596 reject->call(newPromise, completion, 1);
597 return newPromise.asReturnedValue();
600 executionState->d()->remainingElementCount++;
602 ScopedFunctionObject then(scope, nextPromise->get(thenName));
603 if (!then || scope.hasException()) {
604 ScopedValue completion(scope);
605 if (!scope.hasException()) {
606 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
608 completion = e->exceptionValue->asReturnedValue();
612 if (!doneValue->toBoolean())
613 completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
615 reject->call(newPromise, completion, 1);
616 return newPromise.asReturnedValue();
619 ScopedFunctionObject resolveElement(scope, FunctionBuilder::makeResolveElementFunction(e, index, executionState->d()));
621 JSCallArguments jsCallData(scope, 2);
622 jsCallData.args[0] = resolveElement;
623 jsCallData.args[1] = reject;
624 jsCallData.thisObject = nextPromise;
626 then->call(jsCallData);
627 if (scope.hasException()) {
628 ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
631 if (!doneValue->toBoolean())
632 completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
634 reject->call(newPromise, completion, 1);
635 return newPromise.asReturnedValue();
642 executionState->d()->remainingElementCount--;
643 if (executionState->d()->remainingElementCount == 0) {
644 const FunctionObject *resolve = capability->d()->resolve.as<FunctionObject>();
648 ScopedValue values(scope, executionState->d()->values);
649 resolve->call(newPromise, values, 1);
650 if (scope.hasException()) {
652 reject->call(newPromise, scope.engine->exceptionValue, 1);
656 return newPromise.asReturnedValue();
659ReturnedValue PromiseCtor::method_race(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int)
662 ExecutionEngine* e = scope.engine;
664 if (!thisObject || !thisObject->isObject())
667 ScopedString resolveName(scope, e->newIdentifier(QStringLiteral(
"resolve")));
668 ScopedString thenName(scope, e->newIdentifier(QStringLiteral(
"then")));
670 Scoped<PromiseCapability> capability(scope, scope.engine->memoryManager->allocate<QV4::PromiseCapability>());
672 ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
673 if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
675 capability->d()->promise.set(scope.engine, newPromise);
677 ScopedFunctionObject reject(scope, capability->d()->reject);
679 ScopedObject itemsObject(scope, argv);
680 ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject,
true));
681 if (!iteratorObject) {
682 ScopedObject error(scope, e->newTypeErrorObject(QStringLiteral(
"Type error")));
683 reject->call(newPromise, error, 1);
684 return newPromise.asReturnedValue();
687 ScopedValue doneValue(scope);
690 ScopedValue nextValue(scope);
691 doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
693 if (scope.hasException()) {
694 ScopedValue completion(scope, doneValue->toBoolean()
695 ? Encode::undefined()
696 : Runtime::IteratorClose::call(e, iteratorObject));
697 if (scope.hasException()) {
698 completion = e->exceptionValue->asReturnedValue();
701 reject->call(newPromise, completion, 1);
702 return newPromise.asReturnedValue();
705 if (doneValue->toBoolean())
708 ScopedObject nextObject(scope);
709 if (nextValue->isObject()) {
710 nextObject = *nextValue;
711 }
else if (nextValue->isBoolean()) {
712 nextObject = scope.engine->newBooleanObject(nextValue->toBoolean());
713 }
else if (nextValue->isInteger() || nextValue->isDouble()) {
714 nextObject = scope.engine->newNumberObject(nextValue->toInteger());
715 }
else if (nextValue->isString()) {
716 ScopedString scopedString(scope, nextValue->toString(scope.engine));
717 nextObject = scope.engine->newStringObject(scopedString);
720 ScopedFunctionObject resolve(scope, thisObject->as<FunctionObject>()->get(resolveName));
721 if (!resolve || scope.hasException()) {
722 ScopedValue completion(scope);
723 if (!scope.hasException()) {
724 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
726 completion = e->exceptionValue->asReturnedValue();
730 if (!doneValue->toBoolean())
731 completion = Runtime::IteratorClose::call(e, iteratorObject);
733 reject->call(newPromise, completion, 1);
734 return newPromise.asReturnedValue();
737 ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
738 if (scope.hasException() || !nextPromise) {
739 ScopedValue completion(scope, doneValue->toBoolean()
740 ? Encode::undefined()
741 : Runtime::IteratorClose::call(e, iteratorObject));
742 if (scope.hasException()) {
743 completion = e->exceptionValue->asReturnedValue();
746 reject->call(newPromise, completion, 1);
747 return newPromise.asReturnedValue();
750 ScopedFunctionObject then(scope, nextPromise->get(thenName));
751 if (!then || scope.hasException()) {
752 ScopedValue completion(scope);
753 if (!scope.hasException()) {
754 completion = e->newTypeErrorObject(QStringLiteral(
"Type error"));
756 completion = e->exceptionValue->asReturnedValue();
760 if (!doneValue->toBoolean())
761 completion = Runtime::IteratorClose::call(e, iteratorObject);
763 reject->call(newPromise, completion, 1);
764 return newPromise.asReturnedValue();
767 ScopedFunctionObject resolveOriginalPromise(scope, capability->d()->resolve);
769 JSCallArguments jsCallData(scope, 2);
770 jsCallData.args[0] = resolveOriginalPromise;
771 jsCallData.args[1] = reject;
772 jsCallData.thisObject = nextPromise;
774 then->call(jsCallData);
775 if (scope.hasException()) {
776 ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
779 if (!doneValue->toBoolean())
780 completion = Runtime::IteratorClose::call(e, iteratorObject);
782 reject->call(newPromise, completion, 1);
783 return newPromise.asReturnedValue();
787 return newPromise.asReturnedValue();
790void PromisePrototype::init(ExecutionEngine *engine, Object *ctor)
793 ScopedObject o(scope);
795 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
796 ctor->defineReadonlyProperty(engine->id_prototype(), (o =
this));
798 ctor->defineDefaultProperty(QStringLiteral(
"resolve"), PromiseCtor::method_resolve, 1);
799 ctor->defineDefaultProperty(QStringLiteral(
"reject"), PromiseCtor::method_reject, 1);
800 ctor->defineDefaultProperty(QStringLiteral(
"all"), PromiseCtor::method_all, 1);
801 ctor->defineDefaultProperty(QStringLiteral(
"race"), PromiseCtor::method_race, 1);
802 ctor->addSymbolSpecies();
804 defineDefaultProperty(engine->id_constructor(), (o = ctor));
806 ScopedString val(scope, engine->newString(QLatin1String(
"Promise")));
807 defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
809 defineDefaultProperty(QStringLiteral(
"then"), method_then, 2);
810 defineDefaultProperty(QStringLiteral(
"catch"), method_catch, 1);
813ReturnedValue PromisePrototype::method_then(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
817 ExecutionEngine* e = scope.engine;
819 Scoped<QV4::PromiseObject> promise(scope, thisObject);
823 ScopedFunctionObject onFulfilled(scope);
825 onFulfilled = argv[0];
827 onFulfilled = Encode::undefined();
830 ScopedFunctionObject onRejected(scope);
832 onRejected = argv[1];
834 onRejected = Encode::undefined();
837 Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<PromiseCapability>());
839 ScopedFunctionObject constructor(scope, promise->get(e->id_constructor()));
840 if (!constructor || scope.hasException())
844 ScopedObject nextPromise(scope, e->newPromiseObject(constructor, capability));
845 capability->d()->promise.set(scope.engine, nextPromise);
847 Scoped<PromiseReaction> fulfillReaction(scope, Heap::PromiseReaction::createFulfillReaction(scope.engine, capability, onFulfilled));
848 Scoped<PromiseReaction> rejectReaction(scope, Heap::PromiseReaction::createRejectReaction(scope.engine, capability, onRejected));
850 ScopedValue resolution(scope, promise->d()->resolution);
851 if (promise->d()->isPending()) {
854 ScopedArrayObject a(scope, promise->d()->fulfillReactions);
855 ScopedValue newValue(scope, fulfillReaction->d());
856 a->push_back(newValue);
861 ScopedArrayObject a(scope, promise->d()->rejectReactions);
862 ScopedValue newValue(scope, rejectReaction->d());
863 a->push_back(newValue);
865 }
else if (promise->d()->isFulfilled()) {
867 fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
868 }
else if (promise->d()->isRejected()) {
870 rejectReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
873 THROW_GENERIC_ERROR(
"Should never be thrown. Unknown promise state");
876 return nextPromise->asReturnedValue();
879ReturnedValue PromisePrototype::method_catch(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
882 Scoped<Object> promise(scope);
883 if (thisObject->isObject()) {
884 promise.setPointer(thisObject->as<Object>());
885 }
else if (thisObject->isBoolean()) {
886 promise = scope.engine->newBooleanObject(thisObject->toBoolean());
887 }
else if (thisObject->isInteger() || thisObject->isDouble()) {
888 promise = scope.engine->newNumberObject(thisObject->toInteger());
889 }
else if (thisObject->isString()) {
890 ScopedString scopedString(scope, thisObject->toString(scope.engine));
891 promise = scope.engine->newStringObject(scopedString);
896 ScopedValue onRejected(scope);
898 onRejected = Encode::undefined();
900 onRejected = argv[0];
903 JSCallArguments jsCallData(scope, 2);
904 jsCallData.args[0] = Encode::undefined();
905 jsCallData.args[1] = onRejected;
906 jsCallData.thisObject = promise;
908 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"then")));
909 ScopedFunctionObject then(scope, promise->get(thenName));
910 if (!then || scope.hasException())
913 return then->call(jsCallData);
916ReturnedValue CapabilitiesExecutorWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
918 Q_UNUSED(thisObject);
921 const CapabilitiesExecutorWrapper* self =
static_cast<
const CapabilitiesExecutorWrapper*>(f);
922 Heap::PromiseCapability *capabilities = self->d()->capabilities;
924 if (!capabilities->resolve.isUndefined() || !capabilities->reject.isUndefined())
927 if (argc >= 1 && !argv[0].isUndefined())
928 capabilities->resolve.set(scope.engine, argv[0]);
930 if (argc >= 2 && !argv[1].isUndefined())
931 capabilities->reject.set(scope.engine, argv[1]);
933 return Encode::undefined();
936ReturnedValue ResolveElementWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
938 Q_UNUSED(thisObject);
941 const ResolveElementWrapper* self =
static_cast<
const ResolveElementWrapper*>(f);
943 if (self->d()->alreadyResolved)
944 return Encode::undefined();
946 ScopedValue value(scope);
950 value = Encode::undefined();
953 Scoped<PromiseExecutionState> so(scope, self->d()->state);
954 self->d()->alreadyResolved =
true;
956 ScopedObject values(scope, so->d()->values);
957 values->arraySet(self->d()->index, value);
959 so->d()->remainingElementCount--;
960 if (so->d()->remainingElementCount == 0) {
961 Scoped<PromiseCapability> capability(scope, so->d()->capability);
962 ScopedValue promise(scope, capability->d()->promise);
963 ScopedFunctionObject resolve(scope, capability->d()->resolve.as<QV4::FunctionObject>());
964 resolve->call(promise, values, 1);
967 return Encode::undefined();
970ReturnedValue ResolveWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
974 Q_UNUSED(thisObject);
977 const ResolveWrapper *self =
static_cast<
const ResolveWrapper*>(f);
979 Scoped<PromiseObject> promise(scope, self->d()->promise);
981 if (self->d()->alreadyResolved || !promise->d()->isPending())
982 return Encode::undefined();
985 self->d()->alreadyResolved =
true;
987 ScopedValue resolution(scope);
989 resolution = argv[0];
991 resolution = Encode::undefined();
994 if (!resolution->isObject()) {
997 promise->d()->setState(Heap::PromiseObject::Fulfilled);
998 promise->d()->resolution.set(scope.engine, resolution);
999 promise->d()->triggerFullfillReactions(scope.engine);
1002 auto resolutionObject = resolution->as<Object>();
1003 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"then")));
1006 ScopedFunctionObject thenAction { scope, resolutionObject->get(thenName)};
1008 if (scope.hasException()) {
1010 ScopedValue thenValue {scope, scope.engine->catchException()};
1011 promise->d()->setState(Heap::PromiseObject::Rejected);
1012 promise->d()->resolution.set(scope.engine, thenValue);
1013 promise->d()->triggerRejectReactions(scope.engine);
1017 promise->d()->setState(Heap::PromiseObject::Fulfilled);
1018 promise->d()->resolution.set(scope.engine, resolution);
1019 promise->d()->triggerFullfillReactions(scope.engine);
1022 scope.engine->getPromiseReactionHandler()->addResolveThenable(scope.engine, promise.getPointer(), resolutionObject, thenAction);
1027 return Encode::undefined();
1030ReturnedValue RejectWrapper::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
1032 Q_UNUSED(thisObject);
1035 const RejectWrapper *self =
static_cast<
const RejectWrapper*>(f);
1037 Scoped<PromiseObject> promise(scope, self->d()->promise);
1038 if (self->d()->alreadyResolved || !promise->d()->isPending())
1039 return Encode::undefined();
1041 ScopedValue value(scope);
1045 value = Encode::undefined();
1048 if (!isPromise(value)) {
1049 self->d()->alreadyResolved =
true;
1050 promise->d()->setState(Heap::PromiseObject::Rejected);
1051 promise->d()->resolution.set(scope.engine, value);
1053 promise->d()->triggerRejectReactions(scope.engine);
1056 PromiseObject *promise = value->as<PromiseObject>();
1057 ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral(
"catch")));
1059 ScopedFunctionObject then(scope, promise->get(thenName));
1060 JSCallArguments jsCallData(scope, 2);
1061 jsCallData.args[0] = *f;
1062 jsCallData.args[1] = Encode::undefined();
1063 jsCallData.thisObject = value;
1065 then->call(jsCallData);
1068 return Encode::undefined();
1073#include "moc_qv4promiseobject_p.cpp"
Combined button and popup list for selecting options.
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_)