Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions src/jsifier.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ function sigToArgs(sig) {
return args.join(',');
}

function handleI64Signatures(symbol, snippet, sig, i53abi) {
function handleI64Signatures(symbol, snippet, sig, i53abi, isAsyncFunction) {
// Handle i64 parameters and return values.
//
// When WASM_BIGINT is enabled these arrive as BigInt values which we
Expand Down Expand Up @@ -311,9 +311,19 @@ function handleI64Signatures(symbol, snippet, sig, i53abi) {
}

if ((sig[0] == 'j' && i53abi) || (sig[0] == 'p' && MEMORY64)) {
const await_ = async_ ? 'await ' : '';
// For functions that where we need to mutate the return value, we
// also need to wrap the body in an inner function.

// If the inner function is marked as `__async` then we need to `await`
// the result before casting it to BigInt. Note that we use the `__async`
// attribute here rather than the presence of the `async` JS keyword
// because this is what tells us that the function is going to return
// a promise. i.e. we support async functions that return promises but
// are not marked with the `async` keyword (the latter is only necessary
// if the function uses the `await` keyword))
const await_ = isAsyncFunction ? 'await ' : '';
const orig_async_ = async_;
async_ = isAsyncFunction ? 'async ' : async_;
if (oneliner) {
// Special case for abort(), this a noreturn function and but closure
// compiler doesn't have a way to express that, so it complains if we
Expand All @@ -332,7 +342,7 @@ return ${makeReturn64(await_ + body)};
return `\
${async_}function(${args}) {
${argConversions}
var ret = (() => { ${body} })();
var ret = (${orig_async_}() => { ${body} })();
return ${makeReturn64(await_ + 'ret')};
}`;
}
Expand All @@ -350,15 +360,20 @@ ${body};
});
}

function handleAsyncFunction(snippet) {
function handleAsyncFunction(snippet, sig) {
const return64 = sig && (MEMORY64 && sig.startsWith('p') || sig.startsWith('j'))
let handleAsync = 'Asyncify.handleAsync(innerFunc)'
if (return64 && ASYNCIFY == 1) {
handleAsync = makeReturn64(handleAsync);
}
return modifyJSFunction(snippet, (args, body, async_, oneliner) => {
if (!oneliner) {
body = `{\n${body}\n}`;
}
return `\
function(${args}) {
let innerFunc = ${async_} () => ${body};
return Asyncify.handleAsync(innerFunc);
return ${handleAsync};
}\n`;
});
}
Expand Down Expand Up @@ -433,31 +448,30 @@ function(${args}) {
});
}

const isAsyncFunction = LibraryManager.library[symbol + '__async'];
if (ASYNCIFY && isAsyncFunction == 'auto') {
snippet = handleAsyncFunction(snippet);
}

const sig = LibraryManager.library[symbol + '__sig'];
const isAsyncFunction = ASYNCIFY && LibraryManager.library[symbol + '__async'];

const i53abi = LibraryManager.library[symbol + '__i53abi'];
if (i53abi) {
if (!sig) {
error(`JS library error: '__i53abi' decorator requires '__sig' decorator: '${symbol}'`);
}
if (!sig.includes('j')) {
error(
`JS library error: '__i53abi' only makes sense when '__sig' includes 'j' (int64): '${symbol}'`,
);
error(`JS library error: '__i53abi' only makes sense when '__sig' includes 'j' (int64): '${symbol}'`);
}
}
if (
sig &&
((i53abi && sig.includes('j')) || ((MEMORY64 || CAN_ADDRESS_2GB) && sig.includes('p')))
) {
snippet = handleI64Signatures(symbol, snippet, sig, i53abi);
snippet = handleI64Signatures(symbol, snippet, sig, i53abi, isAsyncFunction);
compileTimeContext.i53ConversionDeps.forEach((d) => deps.push(d));
}

if (ASYNCIFY && isAsyncFunction == 'auto') {
snippet = handleAsyncFunction(snippet, sig);
}

const proxyingMode = LibraryManager.library[symbol + '__proxy'];
if (proxyingMode) {
if (!['sync', 'async', 'none'].includes(proxyingMode)) {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/libasync.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,8 @@ addToLibrary({
var reachedAfterCallback = false;
startAsync((handleSleepReturnValue = 0) => {
#if ASSERTIONS
assert(!handleSleepReturnValue || typeof handleSleepReturnValue == 'number' || typeof handleSleepReturnValue == 'boolean'); // old emterpretify API supported other stuff
// old emterpretify API supported other stuff
assert(['undefined', 'number', 'boolean', 'bigint'].includes(typeof handleSleepReturnValue), `invalid type for handleSleepReturnValue: '${typeof handleSleepReturnValue}'`);
#endif
if (ABORT) return;
Asyncify.handleSleepReturnValue = handleSleepReturnValue;
Expand Down
17 changes: 4 additions & 13 deletions src/lib/libdylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -1317,22 +1317,13 @@ var LibraryDylink = {
},

_dlopen_js__deps: ['$dlopenInternal'],
_dlopen_js__async: 'auto',
_dlopen_js: (handle) =>
#if ASYNCIFY
_dlopen_js__async: true,
#endif
_dlopen_js: {{{ asyncIf(ASYNCIFY == 2) }}} (handle) =>
#if ASYNCIFY
Asyncify.handleSleep((wakeUp) =>
dlopenInternal(handle, { loadAsync: true })
.then(wakeUp)
// Note: this currently relies on being able to catch errors even from `wakeUp` callback itself.
// That's why we can't refactor it to `handleAsync` at the moment.
.catch(() => wakeUp(0))
)
dlopenInternal(handle, { loadAsync: true }),
#else
dlopenInternal(handle, { loadAsync: false })
dlopenInternal(handle, { loadAsync: false }),
#endif
,

// Async version of dlopen.
_emscripten_dlopen_js__deps: ['$dlopenInternal', '$callUserCallback', '$dlSetError'],
Expand Down