Stream: git-wasmtime

Topic: wasmtime / PR #14870 [DO NOT REVIEW] Support `BTreeMap`, ...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 19 2026 at 22:27):

jrandolf edited PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 20 2026 at 01:09):

github-actions[bot] added the label wasmtime:api on PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 20 2026 at 19:41):

jrandolf updated PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 20 2026 at 22:19):

jrandolf updated PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 20 2026 at 22:45):

jrandolf updated PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 20 2026 at 22:47):

jrandolf edited PR #14870:

This makes the typed API and bindgen! more flexible about which Rust type a map<K, V> maps to, and fixes the handle leak from duplicate keys. One commit each:

  1. More map types. ComponentType/Lift/Lower are now implemented for:

    • BTreeMap<K, V>, which works without std and lowers entries in sorted order. That gives embedders who care about deterministic execution a deterministic lowering order, unlike HashMap.
    • HashMap<K, V, S> with any hasher (lifting needs S: BuildHasher + Default).
    • A new MapEntries<K, V>, a newtype around Vec<(K, V)> that keeps entries in order, including duplicate keys.

    All of these share one lift and one lower helper, which validate the pointer and length before allocating, as #14835 made HashMap do.

  2. bindgen! map_type option, defaulting to BTreeMap. It picks the Rust type used for WIT maps, e.g. map_type: std::collections::HashMap or map_type: wasmtime::component::MapEntries. This mirrors the guest-side wit-bindgen option, including its BTreeMap default (see the discussion on #14837). BTreeMap is available without std, so the generated code no longer depends on the features Wasmtime is built with, which fixes #14830. It also makes additional_derives: [Hash, Ord, ...] work for records containing maps.

  3. Duplicate keys with handles (#14812). Lifting a map into a type that keeps one value per key (HashMap, BTreeMap) keeps the last value, as the spec allows. When the values contain handles, the replaced values' handles used to leak, e.g. a guest resource's destructor never ran. Now they're dropped as if the embedder had dropped them:

    • The keys can't contain handles, so they're all lifted first to find which values get replaced. Those values are lifted as Vals and discarded.
    • Discarded borrows are released right away, since that runs no code.
    • Other handles may run a destructor in a guest, which can't happen mid-lift, so they're queued in the store. The queue is drained after post-return for the results of a call, before a host function runs for its parameters, and on the event loop for concurrent calls and stream/future reads.

    MapEntries still gets every entry, and maps whose values don't contain handles are lifted as before. Whether the value type contains handles is computed once when the map type is built. The existing code in Linker::define_unknown_imports_as_default_values that drops every handle in a Val is now shared with this.

Some questions I'd appreciate input on:

The map snapshots from #14834 are updated for the new BTreeMap default. This overlaps with #14838 in the bindgen! map type formatting, so whichever lands second will need a small rebase.

Closes #14830
Closes #14832
Closes #14812

view this post on Zulip Wasmtime GitHub notifications bot (Oct 21 2026 at 18:23):

jrandolf updated PR #14870.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 21 2026 at 18:31):

jrandolf edited PR #14870:

This makes the typed API and bindgen! more flexible about which Rust type a map<K, V> maps to, and fixes the handle leak from duplicate keys. One commit each:

  1. More map types. ComponentType/Lift/Lower are now implemented for:

    • BTreeMap<K, V>, which works without std and lowers entries in sorted order. That gives embedders who care about deterministic execution a deterministic lowering order, unlike HashMap.
    • HashMap<K, V, S> with any hasher (lifting needs S: BuildHasher + Default).
    • A new MapEntries<K, V>, a newtype around Vec<(K, V)> that keeps entries in order, including duplicate keys.

    All of these share one lift and one lower helper, which validate the pointer and length before allocating, as #14835 made HashMap do.

  2. bindgen! map_type option, defaulting to BTreeMap. It picks the Rust type used for WIT maps, e.g. map_type: std::collections::HashMap or map_type: wasmtime::component::MapEntries. This mirrors the guest-side wit-bindgen option, including its BTreeMap default (see the discussion on #14837). BTreeMap is available without std, so the generated code no longer depends on the features Wasmtime is built with, which fixes #14830. It also makes additional_derives: [Hash, Ord, ...] work for records containing maps.

  3. Duplicate keys with handles (#14812). Lifting a map into a type that keeps one value per key (HashMap, BTreeMap) keeps the last value, as the spec allows. When the values contain handles, the replaced values' handles used to leak, e.g. a guest resource's destructor never ran. Now they're dropped as if the embedder had dropped them:

    • The keys can't contain handles, so they're all lifted first to find which values get replaced. Those values are lifted as Vals and discarded.
    • Discarded borrows are released right away, since that runs no code.
    • Other handles may run a destructor in a guest, which can't happen mid-lift, so they're queued in the store. The queue is drained after post-return for the results of a call, before a host function runs for its parameters, and on the event loop for concurrent calls and stream/future reads.

    MapEntries still gets every entry, and maps whose values don't contain handles are lifted as before. Whether the value type contains handles is computed once when the map type is built. The existing code in Linker::define_unknown_imports_as_default_values that drops every handle in a Val is now shared with this.

Some questions I'd appreciate input on:

The map snapshots from #14834 are updated for the new BTreeMap default.

Closes #14830
Closes #14832
Closes #14812


Last updated: Oct 31 2026 at 23:03 UTC