Skip to content

Conversation

brendandahl
Copy link
Collaborator

The _emval_await library function is marked _emval_await__async: true, but the js function is not async. With memory64 enabled we auto convert to bigint and look for the async keyword (which is missing) to apply the await before creating the BigInt. With my changes __async will require an async js function, which signals the function is used with JSPI and the appropriate awaits are then inserted.

Fixes #25468


import assert from 'node:assert';
import * as fs from 'node:fs/promises';
import { isAsyncFunction } from 'node:util/types';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh.. interesting. TIL about this.

emscripten_sleep__deps: ['$safeSetTimeout'],
emscripten_sleep__async: true,
emscripten_sleep: (ms) => Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)),
emscripten_sleep: async (ms) => Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does flagging this async gain here? (it costs code size)

I understand the rationale for async is that one can await for the return value, but for functions that return void, isn't the async keyword dead code?

Though Asyncify and JSPI build modes itself do not need the functions to be flagged async do they? (in WebGPU JSPI support I went with this)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It really doesn't add anything here, but consistency. We have a few spots where we auto modify the library js (e.g. memory 64). It's much easier in those wrapper functions to assume we're in a async function and emit await code (also the await code is usually shorter).

@brendandahl brendandahl force-pushed the jspi-async-decorator branch 2 times, most recently from f8b8c87 to c8e1794 Compare October 6, 2025 22:07
@brendandahl brendandahl requested a review from sbc100 October 7, 2025 18:18
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

lgtm % @juj's comment

@poretga99
Copy link

Can this PR proceed? We'd be more than happy if this landed in the main branch. We're currently patching released Emscripten manually.

The `_emval_await` library function is marked `_emval_await__async: true`,
but the js function is not async. With memory64 enabled we auto convert to
bigint and look for the async keyword (which is missing) to apply the await
before creating the BigInt. With my changes __async will require an
async js function, which signals the function is used with JSPI and the
appropriate awaits are then inserted.
This is an automatic change generated by tools/maint/rebaseline_tests.py.

The following (1) test expectation files were updated by
running the tests with `--rebaseline`:

```
codesize/test_codesize_hello_dylink_all.json: 843553 => 843558 [+5 bytes / +0.00%]

Average change: +0.00% (+0.00% - +0.00%)
```
@brendandahl brendandahl enabled auto-merge (squash) October 14, 2025 23:01
@curiousdannii
Copy link
Contributor

It's perfectly legitimate to return a promise instead, and sometimes that would result in cleaner code. This should be at most a warning, not a requirement.

@sbc100
Copy link
Collaborator

sbc100 commented Oct 16, 2025

It's perfectly legitimate to return a promise instead, and sometimes that would result in cleaner code. This should be at most a warning, not a requirement.

Right, but there is no harm in doing both, right? async functions can do return somepromise just fine right?

@curiousdannii
Copy link
Contributor

I guess.. though I think it would be slightly lower performance (probably not noticeable unless it's a really hot function.)

Hmm. If you did require async functions to be AsyncFunctions, then could you do away with the __async decorator?

@sbc100
Copy link
Collaborator

sbc100 commented Oct 16, 2025

I guess.. though I think it would be slightly lower performance (probably not noticeable unless it's a really hot function.)

According to AI there is not any extra overhead: Returning a promise from an async function in JavaScript does not create a second promise in the sense of a new, distinct promise object being generated on top of the one you explicitly return. Instead, the async function's inherent promise-returning nature integrates with the promise you return.

Take that with as many grains of salt as you like ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Embind + MEMORY64: Cannot convert Promise to a BigInt

5 participants