Skip to content

Fix references passed to async functions #3188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 12, 2022

Conversation

Liamolucko
Copy link
Collaborator

Fixes #3167

#3167 was happening because references to JsValues work by pushing the JS value onto the JS stack, and then popping it off again when the function returns. This breaks for async functions, because the JsValue needs to remain valid for the lifetime of the future, not just the initial synchronous call.

To fix this, I introduced a new descriptor, LONGREF, which is used instead of REF in async functions and marks that the reference can't be invalidated after the function returns. I then made a LONGREF to a JsValue behave the same as an owned JsValue, while working like a regular REF for everything else.

I also had to add a new version of RefFromWasmAbi, LongRefFromWasmAbi, to accomodate for LONGREFs to JsValues requiring that the JsValue is destroyed from the Rust side.

While working on that, I also noticed that mutable references to slices were broken in async functions. They work by copying the data from JS to Rust, and then copying it back after the function returns to apply the changes. For async functions, that means that it's copied back before the future is actually finished, and so the changes won't be applied properly. To fix that, I changed it so that the data is copied back from the Rust side when the anchor is dropped, which happens when the future resolves for async functions.

I also bumped the schema version, since this is a breaking change in the interface between the macro and the CLI, even though the schema itself is unchanged.

Fixes rustwasm#3167

rustwasm#3167 was happening because references to `JsValue`s work by pushing the JS value onto the JS stack, and then popping it off again when the function returns. This breaks for async functions, because the `JsValue` needs to remain valid for the lifetime of the future, not just the initial synchronous call.

To fix this, I introduced a new descriptor, `LONGREF`, which is used instead of `REF` in async functions and marks that the reference can't be invalidated after the function returns. I then made a `LONGREF` to a `JsValue` behave the same as an owned `JsValue`, while working like a regular `REF` for everything else.

I also had to add a new version of `RefFromWasmAbi`, `LongRefFromWasmAbi`, to accomodate for `LONGREF`s to `JsValue`s requiring that the `JsValue` is destroyed from the Rust side.

While working on that, I also noticed that mutable references to slices were broken in async functions. They work by copying the data from JS to Rust, and then copying it back after the function returns to apply the changes. For async functions, that means that it's copied back before the future is actually finished, and so the changes won't be applied properly. To fix that, I changed it so that the data is copied back from the Rust side when the anchor is dropped, which happens when the future resolves for async functions.

I also bumped the schema version, since this is a breaking change in the interface between the macro and the CLI, even though the schema itself is unchanged.
`Instruction::MutableSliceToMemory` previously manually lowered the reference to the type array using `addHeapObject`, but that broke when reference types were enabled. The most direct solution would have been to check whether reference types were enabled and use `addToExternrefTable` instead if so, but using a separate instruction means that it gets picked up by `wasm-bindgen-externref-xform`, and an `externref` is passed directly to wasm.
Copy link
Contributor

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

All seems reasonable to me, thanks for this!

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.

js_sys::Function argument to async fn is undefined
2 participants