wasm: Fix handling of promise pool in WebPromiseManager

Promises are registered upon entry to the pool and
unregistered upon exit. If all promises are in a 'pending' state,
new promises can't be processed. Upon completion of a registered
promise, it is unregistered, allowing space for a new promise.

The code path responsible for unregistering promises when they
resolve runs each time a promise's callback is called.
Unfortunately, there's no guarantee that the callback will be
invoked upon the promise's resolution. For instance, promises
registered with only a 'catch' callback may never be triggered
when the promise resolves correctly.

This commit ensures that a final callback is always registered,
even if the user did not provide one.
This guarantees that promises are always unregistered upon resolution

Fixes: QTBUG-118161
Pick-to: 6.5
Change-Id: Ifea93d692464a6ef40c4bcad60f840ca0cb650c9
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
(cherry picked from commit 1e6841245dca3bda5dee050fc841c7129142dd9f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit a625d521f70c4897ba4ebeb7f1c7195e571290fb)
This commit is contained in:
Piotr Wiercinski 2023-12-27 12:34:00 +01:00 committed by Qt Cherry-pick Bot
parent ee0b32d77f
commit 129ab89c5d

View File

@ -136,11 +136,12 @@ public:
"catch",
emscripten::val::module_property(thunkName(CallbackType::Catch, id()).data()));
}
if (callbacks.finallyFunc) {
target = target.call<val>(
"finally",
emscripten::val::module_property(thunkName(CallbackType::Finally, id()).data()));
}
// Guarantee the invocation of at least one callback by always
// registering 'finally'. This is required by WebPromiseManager
// design
target = target.call<val>(
"finally", emscripten::val::module_property(
thunkName(CallbackType::Finally, id()).data()));
}
private:
@ -321,25 +322,21 @@ void WebPromiseManager::promiseThunkCallback(int context, CallbackType type, ems
auto* promiseState = &m_promiseRegistry[context];
auto* callbacks = &promiseState->callbacks;
bool expectingOtherCallbacks;
switch (type) {
case CallbackType::Then:
callbacks->thenFunc(result);
// At this point, if there is no finally function, we are sure that the Catch callback won't be issued.
expectingOtherCallbacks = !!callbacks->finallyFunc;
break;
case CallbackType::Catch:
callbacks->catchFunc(result);
expectingOtherCallbacks = !!callbacks->finallyFunc;
break;
case CallbackType::Finally:
callbacks->finallyFunc();
expectingOtherCallbacks = false;
// Final callback may be empty, used solely for promise unregistration
if (callbacks->finallyFunc) {
callbacks->finallyFunc();
}
unregisterPromise(context);
break;
}
if (!expectingOtherCallbacks)
unregisterPromise(context);
}
}
void WebPromiseManager::registerPromise(