Skip to content
Open
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
18 changes: 18 additions & 0 deletions src/jsifier.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,19 @@ ${body};
});
}

function handleAsyncFunction(snippet) {
return modifyJSFunction(snippet, (args, body, async_, oneliner) => {
if (!oneliner) {
body = `{\n${body}\n}`;
}
return `\
${async_}function(${args}) {
let innerFunc = ${async_} () => ${body};
return Asyncify.handleAsync(innerFunc);
}\n`;
});
}

export async function runJSify(outputFile, symbolsOnly) {
const libraryItems = [];
const symbolDeps = {};
Expand Down Expand Up @@ -440,6 +453,11 @@ function(${args}) {
compileTimeContext.i53ConversionDeps.forEach((d) => deps.push(d));
}

const isAsyncFunction = LibraryManager.library[symbol + '__async'];
if (ASYNCIFY && isAsyncFunction == 'auto') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For JSPI, I don't think we even need the handleAsync. Though there still may be some issues with balanced runtimeKeepalivePush runtimeKeepalivePop. Maybe worth a try?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think handleAsync is used to keep the runtime alive using runtimeKeepalivePush which I think this currently important. We can look at further simplification are followups perhaps, but for now I'd rather leave the semantics as matching.

snippet = handleAsyncFunction(snippet);
}

const proxyingMode = LibraryManager.library[symbol + '__proxy'];
if (proxyingMode) {
if (!['sync', 'async', 'none'].includes(proxyingMode)) {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/libasync.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,8 @@ addToLibrary({
emscripten_sleep: (ms) => Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)),

emscripten_wget_data__deps: ['$asyncLoad', 'malloc'],
emscripten_wget_data__async: true,
emscripten_wget_data: (url, pbuffer, pnum, perror) => Asyncify.handleAsync(async () => {
emscripten_wget_data__async: 'auto',
emscripten_wget_data: async (url, pbuffer, pnum, perror) => {
/* no need for run dependency, this is async but will not do any prepare etc. step */
try {
const byteArray = await asyncLoad(UTF8ToString(url));
Expand All @@ -499,7 +499,7 @@ addToLibrary({
} catch (err) {
{{{ makeSetValue('perror', 0, '1', 'i32') }}};
}
}),
},

emscripten_scan_registers__deps: ['$safeSetTimeout'],
emscripten_scan_registers__async: true,
Expand Down
32 changes: 16 additions & 16 deletions src/lib/libidbstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,56 +92,56 @@ var LibraryIDBStore = {
},

#if ASYNCIFY
emscripten_idb_load__async: true,
emscripten_idb_load__async: 'auto',
emscripten_idb_load__deps: ['malloc'],
emscripten_idb_load: (db, id, pbuffer, pnum, perror) => Asyncify.handleSleep((wakeUp) => {
emscripten_idb_load: (db, id, pbuffer, pnum, perror) => new Promise((resolve) => {
IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), (error, byteArray) => {
if (error) {
{{{ makeSetValue('perror', 0, '1', 'i32') }}};
wakeUp();
resolve();
return;
}
var buffer = _malloc(byteArray.length); // must be freed by the caller!
HEAPU8.set(byteArray, buffer);
{{{ makeSetValue('pbuffer', 0, 'buffer', '*') }}};
{{{ makeSetValue('pnum', 0, 'byteArray.length', 'i32') }}};
{{{ makeSetValue('perror', 0, '0', 'i32') }}};
wakeUp();
resolve();
});
}),
emscripten_idb_store__async: true,
emscripten_idb_store: (db, id, ptr, num, perror) => Asyncify.handleSleep((wakeUp) => {
emscripten_idb_store__async: 'auto',
emscripten_idb_store: (db, id, ptr, num, perror) => new Promise((resolve) => {
IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), (error) => {
// Closure warns about storing booleans in TypedArrays.
/** @suppress{checkTypes} */
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
wakeUp();
resolve();
});
}),
emscripten_idb_delete__async: true,
emscripten_idb_delete: (db, id, perror) => Asyncify.handleSleep((wakeUp) => {
emscripten_idb_delete__async: 'auto',
emscripten_idb_delete: (db, id, perror) => new Promise((resolve) => {
IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), (error) => {
/** @suppress{checkTypes} */
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
wakeUp();
resolve();
});
}),
emscripten_idb_exists__async: true,
emscripten_idb_exists: (db, id, pexists, perror) => Asyncify.handleSleep((wakeUp) => {
emscripten_idb_exists__async: 'auto',
emscripten_idb_exists: (db, id, pexists, perror) => new Promise((resolve) => {
IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), (error, exists) => {
/** @suppress{checkTypes} */
{{{ makeSetValue('pexists', 0, '!!exists', 'i32') }}};
/** @suppress{checkTypes} */
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
wakeUp();
resolve();
});
}),
emscripten_idb_clear__async: true,
emscripten_idb_clear: (db, perror) => Asyncify.handleSleep((wakeUp) => {
emscripten_idb_clear__async: 'auto',
emscripten_idb_clear: (db, perror) => new Promise((resolve) => {
IDBStore.clearStore(UTF8ToString(db), (error) => {
/** @suppress{checkTypes} */
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
wakeUp();
resolve();
});
}),
#else
Expand Down
6 changes: 3 additions & 3 deletions src/lib/libpromise.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ addToLibrary({
return id;
},

emscripten_promise_await__async: true,
emscripten_promise_await__async: 'auto',
#if ASYNCIFY
emscripten_promise_await__deps: ['$getPromise', '$setPromiseResult'],
#endif
Expand All @@ -266,10 +266,10 @@ addToLibrary({
#if RUNTIME_DEBUG
dbg(`emscripten_promise_await: ${id}`);
#endif
return Asyncify.handleAsync(() => getPromise(id).then(
return getPromise(id).then(
value => setPromiseResult(returnValuePtr, true, value),
error => setPromiseResult(returnValuePtr, false, error)
));
);
#else
abort('emscripten_promise_await is only available with ASYNCIFY');
#endif
Expand Down
8 changes: 4 additions & 4 deletions src/lib/libwasi.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,16 +540,16 @@ var WasiLibrary = {
return 0;
},

fd_sync__async: true,
fd_sync: (fd) => {
fd_sync__async: 'auto',
fd_sync: {{{ asyncIf(ASYNCIFY) }}} (fd) => {
#if SYSCALLS_REQUIRE_FILESYSTEM
var stream = SYSCALLS.getStreamFromFD(fd);
var rtn = stream.stream_ops?.fsync?.(stream);
#if ASYNCIFY
var mount = stream.node.mount;
if (mount.type.syncfs) {
return Asyncify.handleSleep((wakeUp) => {
mount.type.syncfs(mount, false, (err) => wakeUp(err ? {{{ cDefs.EIO }}} : 0));
return new Promise((resolve) => {
mount.type.syncfs(mount, false, (err) => resolve(err ? {{{ cDefs.EIO }}} : 0));
});
}
#endif // ASYNCIFY
Expand Down
4 changes: 2 additions & 2 deletions src/utility.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,12 @@ export function mergeInto(obj, other, options = null) {
__noleakcheck: 'boolean',
__internal: 'boolean',
__user: 'boolean',
__async: 'boolean',
__async: ['string', 'boolean'],
__i53abi: 'boolean',
};
const expected = decoratorTypes[decoratorName];
if (type !== expected && !expected.includes(type)) {
error(`Decorator (${key}} has wrong type. Expected '${expected}' not '${type}'`);
error(`Decorator (${key}) has wrong type. Expected '${expected}' not '${type}'`);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/test_jslib.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,12 @@ def test_jslib_invalid_deps(self):
def test_jslib_invalid_decorator(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__async: 'hello',
jslibfunc__internal: 'hello',
jslibfunc: (x) => {},
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'],
"lib.js: Decorator (jslibfunc__async} has wrong type. Expected 'boolean' not 'string'")
"lib.js: Decorator (jslibfunc__internal) has wrong type. Expected 'boolean' not 'string'")

@also_with_wasm64
@also_without_bigint
Expand Down