V0ldek opened issue #14989:
Building on #14885, I'd like to tackle the other half of the linear memory traits. This is already a FIXME in the memory code:
Since it involves a breaking public API change I thought I'd first go through an issue before I go into slashing the codebase.
Feature
The change would remove
RuntimeMemoryCreatorandMemoryCreatorProxy. TheDefaultMemoryCreatorstruct would be implemented wholly in terms of the publicMemoryCreatortrait.This requires a breaking change to the
MemoryCreator. First, theDefaultMemoryCreatorreceivesreservation_for_growth, which is currently not present on the public trait'snew_memory. Second, more minor, the current trait requires to return aResult<_, String>instead of the standard wasmtime error type, so fidelity would be lost as theDefaultMemoryCreatorwould convert all strongly-typed errors to string.Benefit
Simplifies the code base, fixes an outstanding FIXME, avoids running into issues similar to #10740 because of a mismatch of how the user can implement the memory backend from the outside and internal-only shortcuts.
Implementation
My proposal would be to change the public API so that
new_memorytask a single parameter,MemoryRequest. That way things can be added as functions on the type without breaking current implementations. Public accessors on the request would return all things the creator needs to serve the request:impl<'a> MemoryRequest<'a> { pub fn ty(&self) -> MemoryType; pub fn minimum(&self) -> usize; pub fn maximum(&self) -> Option<usize>; pub fn reserved_size_in_bytes(&self) -> Option<usize>; pub fn guard_size_in_bytes(&self) -> usize; }The return type turns into the standard wasmtime Error. This is not really an issue, a user of
wasmtimealready has to cope with the wasmtime Error anywhere, I don't think there's any advantage to allowingResult<_, String>as it currently is.Internally,
RuntimeMemoryCreatoris gone, as isMemoryCreatorProxy.Configholds anArc<dyn MemoryCreator>instead. The implementation that creates memory invm::Memorywill construct aMemoryRequestand route it to the creator.Not all things are exposed publicly, I don't necessarily want to increase the public API surface here. The
DefaultMemoryCreatorneedsMemoryTunablesfor some of the config as well asty: &wasmtime_environ::Memory. These are not public types, so I'd keep them onMemoryRequestexposed aspub(crate), but not to the outside.Alternatives
There's a few things one could consider changing:
- The documentation now doesn't mention that, but the custom creator is also used for GC heaps. An implementation might want to serve these differently, because their purpose and access patterns are different, but currently there's no way to distinguish that from the public parameters. A simple
pub fn kind(&self)returning a non-exhaustingMemoryKindenum withLinearMemoryandGcHeapfixes this.- The other parameters are passed via tunables and not exposed. For example,
MmapMemoryusesreservation_for_growthandguard_before_linear_memory, plussignals_based_trapsandmemory_init_cowto decide whether to use Mmap or Malloc-backed memory.I also have one open question:
reserved_size_in_bytesis anOption<usize>, but the engine always passesSome, withSome(0)meaning "no reservation". Is there any reason for this? What would be the semantic difference betweenSome(0)andNone? Can we just make it ausize?
alexcrichton added the wasmtime:api label to Issue #14989.
alexcrichton commented on issue #14989:
This all sounds reasonable to me, thanks for working on this!
For
MemoryRequest<'a>one downside of that approach is the loss of compiler warnings if you forget to take into account some parameter/field. Not a deal-breaker per-se and it's nice to not break the API when new functionality is added, but in this situation I think it's probably more important to expose all the parameters since if we add one we probably do want to break all downstream consumers as they'll need to update to account for it.For
reserved_size_in_bytesthat might just be a historical artifact beingOption-vs-not, and if it's alwaysSomefeel free to unwrap it.
V0ldek commented on issue #14989:
The problem with passing arguments directly is that then we cannot hide internal parameters. The alternative would be to expose
MemoryTunablesandwasmtime_environ::Memoryas parameters of thenew_memoryfunction, but neither of those types are part of the public API ofwasmtimecurrently.
V0ldek edited a comment on issue #14989:
The problem with passing arguments directly is that then we cannot hide internal parameters. The alternative would be to expose
MemoryTunablesandwasmtime_environ::Memoryas parameters of thenew_memoryfunction, but neither of those types are part of the public API ofwasmtimecurrently.I guess the question here is whether we want to keep hiding things, or do we want full parity (i.e. an outside user could build exactly the
wasmtime::DefaultMemoryCreator). We could expose just the parameters that are actively used (reservation_for_growth,guard_before_linear_memory,signals_based_traps,memory_init_cow).
alexcrichton commented on issue #14989:
Ah sorry I missed that part of the OP here, and good point! In tha tcase seems reasonable to me to have a
MemoryRequest<'_>and we can tweak the documentation over time of what's required vs what isn't
Last updated: Oct 31 2026 at 23:03 UTC