Skip to content

Commit 7309c65

Browse files
committed
Add __async: auto decorator
This decorator automatically generates the Asyncify.handleAsync wrapper code. Hopefully we can transition all out `__async` functions soon and just make this the default.
1 parent fac2779 commit 7309c65

File tree

7 files changed

+48
-30
lines changed

7 files changed

+48
-30
lines changed

src/jsifier.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,19 @@ ${body};
350350
});
351351
}
352352

353+
function handleAsyncFunction(snippet) {
354+
return modifyJSFunction(snippet, (args, body, async_, oneliner) => {
355+
if (!oneliner) {
356+
body = `{\n${body}\n}`;
357+
}
358+
return `\
359+
${async_}function(${args}) {
360+
let innerFunc = ${async_} () => ${body};
361+
return Asyncify.handleAsync(innerFunc);
362+
}\n`;
363+
});
364+
}
365+
353366
export async function runJSify(outputFile, symbolsOnly) {
354367
const libraryItems = [];
355368
const symbolDeps = {};
@@ -440,6 +453,11 @@ function(${args}) {
440453
compileTimeContext.i53ConversionDeps.forEach((d) => deps.push(d));
441454
}
442455

456+
const isAsyncFunction = LibraryManager.library[symbol + '__async'];
457+
if (ASYNCIFY && isAsyncFunction == 'auto') {
458+
snippet = handleAsyncFunction(snippet);
459+
}
460+
443461
const proxyingMode = LibraryManager.library[symbol + '__proxy'];
444462
if (proxyingMode) {
445463
if (!['sync', 'async', 'none'].includes(proxyingMode)) {

src/lib/libasync.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,8 @@ addToLibrary({
485485
emscripten_sleep: (ms) => Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)),
486486

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

504504
emscripten_scan_registers__deps: ['$safeSetTimeout'],
505505
emscripten_scan_registers__async: true,

src/lib/libidbstore.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,56 +92,56 @@ var LibraryIDBStore = {
9292
},
9393

9494
#if ASYNCIFY
95-
emscripten_idb_load__async: true,
95+
emscripten_idb_load__async: 'auto',
9696
emscripten_idb_load__deps: ['malloc'],
97-
emscripten_idb_load: (db, id, pbuffer, pnum, perror) => Asyncify.handleSleep((wakeUp) => {
97+
emscripten_idb_load: (db, id, pbuffer, pnum, perror) => new Promise((resolve) => {
9898
IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), (error, byteArray) => {
9999
if (error) {
100100
{{{ makeSetValue('perror', 0, '1', 'i32') }}};
101-
wakeUp();
101+
resolve();
102102
return;
103103
}
104104
var buffer = _malloc(byteArray.length); // must be freed by the caller!
105105
HEAPU8.set(byteArray, buffer);
106106
{{{ makeSetValue('pbuffer', 0, 'buffer', '*') }}};
107107
{{{ makeSetValue('pnum', 0, 'byteArray.length', 'i32') }}};
108108
{{{ makeSetValue('perror', 0, '0', 'i32') }}};
109-
wakeUp();
109+
resolve();
110110
});
111111
}),
112-
emscripten_idb_store__async: true,
113-
emscripten_idb_store: (db, id, ptr, num, perror) => Asyncify.handleSleep((wakeUp) => {
112+
emscripten_idb_store__async: 'auto',
113+
emscripten_idb_store: (db, id, ptr, num, perror) => new Promise((resolve) => {
114114
IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), (error) => {
115115
// Closure warns about storing booleans in TypedArrays.
116116
/** @suppress{checkTypes} */
117117
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
118-
wakeUp();
118+
resolve();
119119
});
120120
}),
121-
emscripten_idb_delete__async: true,
122-
emscripten_idb_delete: (db, id, perror) => Asyncify.handleSleep((wakeUp) => {
121+
emscripten_idb_delete__async: 'auto',
122+
emscripten_idb_delete: (db, id, perror) => new Promise((resolve) => {
123123
IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), (error) => {
124124
/** @suppress{checkTypes} */
125125
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
126-
wakeUp();
126+
resolve();
127127
});
128128
}),
129-
emscripten_idb_exists__async: true,
130-
emscripten_idb_exists: (db, id, pexists, perror) => Asyncify.handleSleep((wakeUp) => {
129+
emscripten_idb_exists__async: 'auto',
130+
emscripten_idb_exists: (db, id, pexists, perror) => new Promise((resolve) => {
131131
IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), (error, exists) => {
132132
/** @suppress{checkTypes} */
133133
{{{ makeSetValue('pexists', 0, '!!exists', 'i32') }}};
134134
/** @suppress{checkTypes} */
135135
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
136-
wakeUp();
136+
resolve();
137137
});
138138
}),
139-
emscripten_idb_clear__async: true,
140-
emscripten_idb_clear: (db, perror) => Asyncify.handleSleep((wakeUp) => {
139+
emscripten_idb_clear__async: 'auto',
140+
emscripten_idb_clear: (db, perror) => new Promise((resolve) => {
141141
IDBStore.clearStore(UTF8ToString(db), (error) => {
142142
/** @suppress{checkTypes} */
143143
{{{ makeSetValue('perror', 0, '!!error', 'i32') }}};
144-
wakeUp();
144+
resolve();
145145
});
146146
}),
147147
#else

src/lib/libpromise.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ addToLibrary({
257257
return id;
258258
},
259259
260-
emscripten_promise_await__async: true,
260+
emscripten_promise_await__async: 'auto',
261261
#if ASYNCIFY
262262
emscripten_promise_await__deps: ['$getPromise', '$setPromiseResult'],
263263
#endif
@@ -266,10 +266,10 @@ addToLibrary({
266266
#if RUNTIME_DEBUG
267267
dbg(`emscripten_promise_await: ${id}`);
268268
#endif
269-
return Asyncify.handleAsync(() => getPromise(id).then(
269+
return getPromise(id).then(
270270
value => setPromiseResult(returnValuePtr, true, value),
271271
error => setPromiseResult(returnValuePtr, false, error)
272-
));
272+
);
273273
#else
274274
abort('emscripten_promise_await is only available with ASYNCIFY');
275275
#endif

src/lib/libwasi.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,16 +540,16 @@ var WasiLibrary = {
540540
return 0;
541541
},
542542

543-
fd_sync__async: true,
544-
fd_sync: (fd) => {
543+
fd_sync__async: 'auto',
544+
fd_sync: {{{ asyncIf(ASYNCIFY) }}} (fd) => {
545545
#if SYSCALLS_REQUIRE_FILESYSTEM
546546
var stream = SYSCALLS.getStreamFromFD(fd);
547547
var rtn = stream.stream_ops?.fsync?.(stream);
548548
#if ASYNCIFY
549549
var mount = stream.node.mount;
550550
if (mount.type.syncfs) {
551-
return Asyncify.handleSleep((wakeUp) => {
552-
mount.type.syncfs(mount, false, (err) => wakeUp(err ? {{{ cDefs.EIO }}} : 0));
551+
return new Promise((resolve) => {
552+
mount.type.syncfs(mount, false, (err) => resolve(err ? {{{ cDefs.EIO }}} : 0));
553553
});
554554
}
555555
#endif // ASYNCIFY

src/utility.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,12 @@ export function mergeInto(obj, other, options = null) {
186186
__noleakcheck: 'boolean',
187187
__internal: 'boolean',
188188
__user: 'boolean',
189-
__async: 'boolean',
189+
__async: ['string', 'boolean'],
190190
__i53abi: 'boolean',
191191
};
192192
const expected = decoratorTypes[decoratorName];
193193
if (type !== expected && !expected.includes(type)) {
194-
error(`Decorator (${key}} has wrong type. Expected '${expected}' not '${type}'`);
194+
error(`Decorator (${key}) has wrong type. Expected '${expected}' not '${type}'`);
195195
}
196196
}
197197
}

test/test_jslib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,12 @@ def test_jslib_invalid_deps(self):
277277
def test_jslib_invalid_decorator(self):
278278
create_file('lib.js', r'''
279279
addToLibrary({
280-
jslibfunc__async: 'hello',
280+
jslibfunc__internal: 'hello',
281281
jslibfunc: (x) => {},
282282
});
283283
''')
284284
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'],
285-
"lib.js: Decorator (jslibfunc__async} has wrong type. Expected 'boolean' not 'string'")
285+
"lib.js: Decorator (jslibfunc__internal) has wrong type. Expected 'boolean' not 'string'")
286286

287287
@also_with_wasm64
288288
@also_without_bigint

0 commit comments

Comments
 (0)