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