Skip to content
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

Fix Rust values getting GC'd while still borrowed and not getting GC'd if created via. constructor #3940

Merged
merged 15 commits into from
Jun 1, 2024

Conversation

Liamolucko
Copy link
Collaborator

Fixes #3854.
Supersedes #3743.

This implements the alternative reference-counting based fix that I proposed in #3743.

I also added some tests for it. It turns out there was already an existing test around GC, which meant that Node's --expose-gc flag was already enabled for manually triggering garbage collection.

I ended up merging it together with my tests, and then running them sequentially since attempting to run multiple GCs in parallel seemed to make it flaky. It was still somewhat flaky after that point, though: the garbage collector just decided not to clean up the OwnedValues sometimes. For whatever reason, 'warming it up' by just running a bunch of pointless GCs before the tests seems to fix it; I might try and investigate why at some point, but for now it works.

At first I tried fixing them so that they didn't need to (giving each of them
their own `dropCount`), but running multiple GCs in parallel seems to be flaky.
I also discovered and fixed an extra bug while working on this, which
was that `LongRefFromWasmAbi` wasn't getting used for `self`: this bug
didn't cause any problems before, because the only type that had a
different `LongRefFromWasmAbi` impl than its `RefFromWasmAbi` impl was
`JsValue` which can't be the type of `self`.

It became a problem here because I made the new `LongRefFromWasmAbi`
impl for exported Rust types clone the `Rc`, whereas the
`RefFromWasmAbi` impl doesn't because garbage collection can't occur
during the synchronous call that the value has to live for.

I might actually change it so that both of the impls behave like the
current `LongRefFromWasmAbi` impl, though: cloning an `Rc` isn't
expensive and so having the second different impl just makes things more
complicated for no good reason. I just left it in this commit as
explanation for how I discovered the `LongRefFromWasmAbi` issue.
Now that borrowing a Rust value always clones its `Rc`, `Rc::into_inner`
is a sufficient check that the value isn't borrowed.
For some reason I was getting errors before without it, but that seems
to be fixed now. (It's probably something to do with having removed the
`borrow_mut`, but that only takes `&self`, so I still don't get it.)
Copy link
Collaborator

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

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

LGTM!

I couldn't try it out locally because I'm on vacation right now.

They seem to be far flakier in CI than locally for some reason, and I
don't see any way to solve it; so just turn them off. :(

I also got rid of the weird GC warmup hack because it doesn't do
anything anymore; I could've sworn it was a reproducible effect before,
but it seems to make no difference now.
@Liamolucko Liamolucko merged commit 88f8917 into rustwasm:main Jun 1, 2024
25 checks passed
@Liamolucko Liamolucko deleted the gc-fixes branch June 1, 2024 12:18
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.

FinalizationRegistry.register() call missing in exported rust types that define a constructor
2 participants