@@ -12,7 +12,6 @@ C++ code interact with **asynchronous** JavaScript. This allows things like:
1212 * A synchronous call in C that waits for an asynchronous operation in JS to
1313 complete.
1414
15-
1615In general the two options are very similar, but rely on different underlying
1716mechanisms to work.
1817
@@ -162,6 +161,45 @@ You will see something like this:
162161That shows that the C code only continued to execute after the async JS
163162completed.
164163
164+ Marking JS library functions as async
165+ #####################################
166+
167+ If you mark a JS library function as async using the ``__async `` decorator then
168+ the compiler will take a care of all the details of using the ``Asyncify `` API
169+ for you. The function will also automatically be incldued in
170+ :ref: `ASYNCIFY_IMPORTS `. All you need to do is write normal async JS function
171+ (either using the explict ``async `` JS keyword or returning a ``Promise ``
172+ object). For example:
173+
174+ .. code-block :: js
175+
176+ addToLibrary ({
177+ fetch_v1__async: ' auto' ,
178+ fetch_v2: async (url ) => {
179+ const response = await fetch (UTF8ToString (url);
180+ const json_data = await response .json ();
181+ return stringToNewUTF8 (json_data);
182+ },
183+
184+ fetch_v2__async: ' auto' ,
185+ fetch_v2 : (url ) => {
186+ return fetch (UTF8ToString (url))
187+ .then ((rsp ) => response .json ())
188+ .then ((json_data ) => stringToNewUTF8 (json_data));
189+ },
190+ });
191+
192+ This JS library file contains two JS functions (` ` fetch_v1` ` and ` ` fetch_v2` ` )
193+ which do exactly the same thing, one using the JS ` ` async ` ` keyword and one
194+ using promise chaining . They are both marked as ` ` __async: ' auto' ` ` which means
195+ they will automatically suspend Wasm executation when called and resume when the
196+ resulting promise resolves.
197+
198+ You can use ` ` __async: 1 ` ` if you just want to include the function in
199+ :ref:`ASYNCIFY_IMPORTS` or ``__async: 'auto'`` if you also want the function to
200+ wrapper in ``Asyncify.handleAsync``.
201+
202+
165203Ways to use Asyncify APIs in older engines
166204##########################################
167205
@@ -184,8 +222,9 @@ directly with ``EM_JS`` and ``Asyncify.handleAsync`` instead:
184222
185223When using this form, the compiler doesn't statically know that ``do_fetch`` is
186224asynchronous anymore. Instead, you must tell the compiler that ``do_fetch()``
187- can do an asynchronous operation using ``ASYNCIFY_IMPORTS ``, otherwise it won't
188- instrument the code to allow pausing and resuming (see more details later down):
225+ can do an asynchronous operation using :ref:`ASYNCIFY_IMPORTS`, otherwise it
226+ won't instrument the code to allow pausing and resuming (see more details later
227+ down):
189228
190229::
191230
@@ -219,10 +258,10 @@ More on ``ASYNCIFY_IMPORTS``
219258
220259As in the above example, you can add JS functions that do an async operation but
221260look synchronous from the perspective of C. If you don' t use ` ` EM_ASYNC_JS ` ` ,
222- it's vital to add such methods to `` ASYNCIFY_IMPORTS `` . That list of imports is
223- the list of imports to the Wasm module that the Asyncify instrumentation must be
224- aware of. Giving it that list tells it that all other JS calls will **not ** do
225- an async operation, which lets it not add overhead where it isn't needed.
261+ it' s vital to add such methods to :ref:` ASYNCIFY_IMPORTS`. That list of imports
262+ is the list of imports to the Wasm module that the Asyncify instrumentation must
263+ be aware of. Giving it that list tells it that all other JS calls will **not**
264+ do an async operation, which lets it not add overhead where it isn' t needed.
226265
227266.. note :: If the import is not inside ` ` env` ` the full path must be specified, for example, ` ` ASYNCIFY_IMPORTS=wasi_snapshot_preview1.fd_write` `
228267
@@ -231,7 +270,7 @@ Asyncify with Dynamic Linking
231270
232271If you want to use Asyncify in dynamic libraries, those methods which are imported
233272from other linked modules (and that will be on the stack in an async operation)
234- should be listed in `` ASYNCIFY_IMPORTS ` `.
273+ should be listed in : ref : ` ASYNCIFY_IMPORTS` .
235274
236275.. code - block:: cpp
237276
@@ -262,8 +301,8 @@ linking manner:
262301 }
263302
264303In the main module , the compiler doesn’t statically know that ` ` sleep_for_seconds` ` is
265- asynchronous. Therefore, you must add ``sleep_for_seconds `` to the `` ASYNCIFY_IMPORTS ``
266- list.
304+ asynchronous . Therefore , you must add ` ` sleep_for_seconds` ` to the
305+ : ref : ` ASYNCIFY_IMPORTS ` list.
267306
268307::
269308
@@ -281,9 +320,9 @@ and want to ``await`` a dynamically retrieved ``Promise``, you can call an
281320 val my_object = /* ... */;
282321 val result = my_object.call<val>("someAsyncMethod").await();
283322
284- In this case you don't need to worry about `` ASYNCIFY_IMPORTS ` ` or
285- `` JSPI_IMPORTS `` , since it's an internal implementation detail of `` val::await ``
286- and Emscripten takes care of it automatically.
323+ In this case you don' t need to worry about : ref : ` ASYNCIFY_IMPORTS` or
324+ : ref : ` JSPI_IMPORTS` , since it' s an internal implementation detail of
325+ ``val::await`` and Emscripten takes care of it automatically.
287326
288327Note that when using Embind exports, Asyncify and JSPI behave differently. When
289328Asyncify is used with Embind and the code is invoked from JavaScript, then the
@@ -373,9 +412,9 @@ Differences Between Asyncify and JSPI
373412Besides using different underlying mechanisms, Asyncify and JSPI also handle
374413async imports and exports differently. Asyncify will automatically determine
375414what exports will become async based on what could potentially call an
376- an async import (`` ASYNCIFY_IMPORTS ` `). However, with JSPI, the async imports
377- and exports must be explicitly set using `` JSPI_IMPORTS `` and `` JSPI_EXPORTS ``
378- settings.
415+ an async import (:ref:` ASYNCIFY_IMPORTS`). However, with JSPI, the async imports
416+ and exports must be explicitly set using :ref:` JSPI_IMPORTS` and
417+ :ref:`JSPI_EXPORTS` settings.
379418
380419.. note:: ``<JSPI/ASYNCIFY>_IMPORTS`` and ``JSPI_EXPORTS`` aren' t needed when
381420 using various helpers mentioned above such as: ` ` EM_ASYNC_JS ` ` ,
@@ -394,39 +433,39 @@ code to allow unwinding and rewinding. That overhead is usually not extreme,
394433something like 50% or so. Asyncify achieves that by doing a whole-program
395434analysis to find functions need to be instrumented and which do not -
396435basically, which can call something that reaches one of
397- `` ASYNCIFY_IMPORTS ` `. That analysis avoids a lot of unnecessary overhead,
436+ :ref:` ASYNCIFY_IMPORTS`. That analysis avoids a lot of unnecessary overhead,
398437however, it is limited by **indirect calls**, since it can' t tell where
399438they go - it could be anything in the function table (with the same type ).
400439
401440If you know that indirect calls are never on the stack when unwinding, then
402441you can tell Asyncify to ignore indirect calls using
403- `` ASYNCIFY_IGNORE_INDIRECT ` `.
442+ :ref:` ASYNCIFY_IGNORE_INDIRECT`.
404443
405444If you know that some indirect calls matter and others do not, then you
406445can provide a manual list of functions to Asyncify:
407446
408- * `` ASYNCIFY_REMOVE ` ` is a list of functions that do not unwind the stack.
447+ * :ref:` ASYNCIFY_REMOVE` is a list of functions that do not unwind the stack.
409448 As Asyncify processes the call tree, functions in this list will be removed,
410449 and neither they nor their callers will be instrumented (unless their callers
411450 need to be instrumented for other reasons.)
412- * `` ASYNCIFY_ADD ` ` is a list of functions that do unwind the stack, and will be
451+ * :ref:` ASYNCIFY_ADD` is a list of functions that do unwind the stack, and will be
413452 processed like the imports. This is mostly useful
414- if you use `` ASYNCIFY_IGNORE_INDIRECT ` ` but want to also mark some additional
415- functions that need to unwind. If the `` ASYNCIFY_PROPAGATE_ADD ` ` setting is
453+ if you use :ref:` ASYNCIFY_IGNORE_INDIRECT` but want to also mark some additional
454+ functions that need to unwind. If the :ref:` ASYNCIFY_PROPAGATE_ADD` setting is
416455 disabled however, then this list will only be added after the whole-program
417- analysis. If `` ASYNCIFY_PROPAGATE_ADD ` ` is disabled then you must also add
456+ analysis. If :ref:` ASYNCIFY_PROPAGATE_ADD` is disabled then you must also add
418457 their callers, their callers' callers, and so on.
419- * `` ASYNCIFY_ONLY ` ` is a list of the **only ** functions that can unwind
458+ * :ref:` ASYNCIFY_ONLY` is a list of the **only** functions that can unwind
420459 the stack. Asyncify will instrument exactly those and no others.
421460
422- You can enable the `` ASYNCIFY_ADVISE ` ` setting, which will tell the compiler to
461+ You can enable the :ref:` ASYNCIFY_ADVISE` setting, which will tell the compiler to
423462output which functions it is currently instrumenting and why. You can then
424- determine whether you should add any functions to `` ASYNCIFY_REMOVE ` ` or
425- whether it would be safe to enable `` ASYNCIFY_IGNORE_INDIRECT ` `. Note that this
463+ determine whether you should add any functions to :ref:` ASYNCIFY_REMOVE` or
464+ whether it would be safe to enable :ref:` ASYNCIFY_IGNORE_INDIRECT`. Note that this
426465phase of the compiler happens after many optimization phases, and several
427466functions maybe be inlined already. To be safe, run it with `-O0`.
428467
429- For more details see `` settings.js ` `. Note that the manual settings
468+ For more details see :ref:` settings-reference `. Note that the manual settings
430469mentioned here are error-prone - if you don't get things exactly right,
431470your application can break. If you don't absolutely need maximal performance,
432471it's usually ok to use the defaults.
@@ -439,7 +478,7 @@ Stack overflows (Asyncify)
439478
440479If you see an exception thrown from an ``asyncify_*`` API, then it may be
441480a stack overflow. You can increase the stack size with the
442- `` ASYNCIFY_STACK_SIZE ` ` option.
481+ :ref:` ASYNCIFY_STACK_SIZE` option.
443482
444483Reentrancy
445484**********
@@ -467,7 +506,7 @@ The examples above show `wakeUp()` being called from JS (after a callback,
467506typically), and without any compiled code on the stack. If there *were* compiled
468507code on the stack, then that could interfere with properly rewinding and
469508resuming execution, in confusing ways, and therefore an assertion will be
470- thrown in a build with `` ASSERTIONS ` `.
509+ thrown in a build with :ref:` ASSERTIONS`.
471510
472511(Specifically, the problem there is that while rewinding will work properly,
473512if you later unwind again, that unwinding will also unwind through that extra
0 commit comments