Repository navigation
Free the parameter block of async exports in every generator - #1758
Draft
Aditya1404Sal wants to merge 3 commits into
Draft
Aditya1404Sal wants to merge 3 commits into
Aditya1404Sal wants to merge 3 commits into
Conversation
This was referenced Oct 27, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This fixes the leak from #1757 in every generator
When an async export's params don't fit in 16 flat values they arrive in a block the callee owns, and nothing ever freed it, so every call leaked it. Sync exports free it after the call, but core can't do that for async: the code after the call can end up in another function, or never run when the task is cancelled. So
CallInterfacenow hasparams_block: Option<(size, align)>. When it's set, the block pointer is the last operand and the generator frees the block itself. Sync exports are unchanged.That's a change to the public
Instructionenum: aBindgenoutside this repo that matches onCallInterfaceneeds..in its pattern now, and if it generates async exports it has to pop that operand and free the block.Where each generator frees it:
.await, so a call that gets cancelled while waiting frees it too.return ret;in the export wrapper.var task = XAsync(...);, since the arguments are already managed copies by then.Unpin()releases; it just drops the extra operand.Two more fixes I needed along the way:
Deque::pop_frontleaves the slot filled, and each coroutine points back at the queue's lane), so the whole task stayed alive in a cycle.finish_waitablesetnow callsshrink_to_fit()on the run queue.The new runtime test
async-many-argumentshas a Rust runner and components in Rust, C, C#, MoonBit and Go. The runner makes 2000 calls to warm up, reads a heap mark, makes 2000 more and checks that the mark didn't move. It covers 9 strings, option/result payloads, one big record, calls cancelled while waiting, and a case with no block. That case uses 15 flat values, since Go can't compile an async export with 16. Asupports-cancelexport lets a component opt out of the cancel case. C# returns false because its async support doesn't handle a cancelled export yet, so the runner skips only that case for C#. There's also a codegen test with lists, a record and an async resource method; it joins the two async WITs thatcrates/test/src/go.rsexpects to fail the c-shared link on stock Go.I ran the test without the fix in Rust, C, MoonBit and C#, and it fails in all four:
memory.size, 4 → 6 pages.memory.size, 4 → 8 pages.sbrk(0), +131072 B.Go measures
HeapAllocafterruntime.GC(); it runs only in CI, which has the patched Go.MoonBit isn't in CI's language matrix at the moment, so I checked the MoonBit generator and runtime changes locally with moon 0.1.20261023 (moonc v0.10.17).
Fixes #1757