blob: 6445944f1dc8247e502f40e93b1feff6362255fc [file] [log] [blame]
/**
* @license
* Copyright 2023 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
mergeInto(LibraryManager.library, {
$promiseMap__deps: ['$HandleAllocator'],
$promiseMap: "new HandleAllocator();",
$getPromise__deps: ['$promiseMap'],
$getPromise: function(id) {
return promiseMap.get(id).promise;
},
$makePromise__deps: ['$promiseMap'],
$makePromise: function() {
var promiseInfo = {};
promiseInfo.promise = new Promise((resolve, reject) => {
promiseInfo.reject = reject;
promiseInfo.resolve = resolve;
});
promiseInfo.id = promiseMap.allocate(promiseInfo);
#if RUNTIME_DEBUG
dbg('makePromise: ' + promiseInfo.id);
#endif
return promiseInfo;
},
emscripten_promise_create__deps: ['$makePromise'],
emscripten_promise_create__sig: 'p',
emscripten_promise_create: function() {
return makePromise().id;
},
emscripten_promise_destroy__deps: ['$promiseMap'],
emscripten_promise_destroy__sig: 'vp',
emscripten_promise_destroy: function(id) {
#if RUNTIME_DEBUG
dbg('emscripten_promise_destroy: ' + id);
#endif
promiseMap.free(id);
},
emscripten_promise_resolve__deps: ['$promiseMap',
'$getPromise',
'emscripten_promise_destroy'],
emscripten_promise_resolve__sig: 'vpip',
emscripten_promise_resolve: function(id, result, value) {
#if RUNTIME_DEBUG
dbg('emscripten_promise_resolve: ' + id);
#endif
var info = promiseMap.get(id);
switch (result) {
case {{{ cDefine('EM_PROMISE_FULFILL') }}}:
info.resolve(value);
return;
case {{{ cDefine('EM_PROMISE_MATCH') }}}:
info.resolve(getPromise(value));
return;
case {{{ cDefine('EM_PROMISE_MATCH_RELEASE') }}}:
info.resolve(getPromise(value));
_emscripten_promise_destroy(value);
return;
case {{{ cDefine('EM_PROMISE_REJECT') }}}:
info.reject(value);
return;
}
#if ASSERTIONS
abort("unexpected promise callback result " + result);
#endif
},
$makePromiseCallback__deps: ['$getPromise',
'$POINTER_SIZE',
'emscripten_promise_destroy'],
$makePromiseCallback: function(callback, userData) {
return (value) => {
#if RUNTIME_DEBUG
dbg('emscripten promise callback: ' + value);
#endif
{{{ runtimeKeepalivePop() }}};
var stack = stackSave();
// Allocate space for the result value and initialize it to NULL.
var resultPtr = stackAlloc(POINTER_SIZE);
{{{ makeSetValue('resultPtr', 0, '0', '*') }}};
try {
var result =
{{{ makeDynCall('ippp', 'callback') }}}(resultPtr, userData, value);
var resultVal = {{{ makeGetValue('resultPtr', 0, '*') }}};
} catch (e) {
// If the thrown value is potentially a valid pointer, use it as the
// rejection reason. Otherwise use a null pointer as the reason. If we
// allow arbitrary objects to be thrown here, we will get a TypeError in
// MEMORY64 mode when they are later converted to void* rejection
// values.
#if MEMORY64
if (typeof e !== 'bigint') {
throw 0n;
}
#else
if (typeof e !== 'number') {
throw 0;
}
#endif
throw e;
} finally {
// Thrown errors will reject the promise, but at least we will restore
// the stack first.
stackRestore(stack);
}
switch (result) {
case {{{ cDefine('EM_PROMISE_FULFILL') }}}:
return resultVal;
case {{{ cDefine('EM_PROMISE_MATCH') }}}:
return getPromise(resultVal);
case {{{ cDefine('EM_PROMISE_MATCH_RELEASE') }}}:
var ret = getPromise(resultVal);
_emscripten_promise_destroy(resultVal);
return ret;
case {{{ cDefine('EM_PROMISE_REJECT') }}}:
throw resultVal;
}
#if ASSERTIONS
abort("unexpected promise callback result " + result);
#endif
};
},
emscripten_promise_then__deps: ['$promiseMap',
'$getPromise',
'$makePromiseCallback'],
emscripten_promise_then__sig: 'ppppp',
emscripten_promise_then: function(id,
onFulfilled,
onRejected,
userData) {
#if RUNTIME_DEBUG
dbg('emscripten_promise_then: ' + id);
#endif
{{{ runtimeKeepalivePush() }}};
var promise = getPromise(id);
var newId = promiseMap.allocate({
promise: promise.then(makePromiseCallback(onFulfilled, userData),
makePromiseCallback(onRejected, userData))
});
#if RUNTIME_DEBUG
dbg('emscripten_promise_then: -> ' + newId);
#endif
return newId;
},
emscripten_promise_all__deps: ['$promiseMap', '$getPromise'],
emscripten_promise_all__sig: 'pppp',
emscripten_promise_all: function(idBuf, resultBuf, size) {
var promises = [];
for (var i = 0; i < size; i++) {
var id = {{{ makeGetValue('idBuf', `i*${Runtime.POINTER_SIZE}`, 'i32') }}};
promises[i] = getPromise(id);
}
#if RUNTIME_DEBUG
dbg('emscripten_promise_all: ' + promises);
#endif
var id = promiseMap.allocate({
promise: Promise.all(promises).then((results) => {
if (resultBuf) {
for (var i = 0; i < size; i++) {
var result = results[i];
{{{ makeSetValue('resultBuf', `i*${Runtime.POINTER_SIZE}`, 'result', '*') }}};
}
}
return resultBuf;
})
});
#if RUNTIME_DEBUG
dbg('create: ' + id);
#endif
return id;
},
});