pub struct Config { /* private fields */ }
Expand description
Global configuration options used to create an Engine
and customize its behavior.
This structure exposed a builder-like interface and is primarily consumed by
Engine::new()
.
The validation of Config
is deferred until the engine is being built, thus
a problematic config may cause Engine::new
to fail.
Implementations§
source§impl Config
impl Config
sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new configuration object with the default configuration specified.
sourcepub fn target(&mut self, target: &str) -> Result<&mut Self>
pub fn target(&mut self, target: &str) -> Result<&mut Self>
Sets the target triple for the Config
.
By default, the host target triple is used for the Config
.
This method can be used to change the target triple.
Cranelift flags will not be inferred for the given target and any existing target-specific Cranelift flags will be cleared.
§Errors
This method will error if the given target triple is not supported.
sourcepub fn debug_info(&mut self, enable: bool) -> &mut Self
pub fn debug_info(&mut self, enable: bool) -> &mut Self
Configures whether DWARF debug information will be emitted during compilation.
By default this option is false
.
sourcepub fn wasm_backtrace(&mut self, enable: bool) -> &mut Self
pub fn wasm_backtrace(&mut self, enable: bool) -> &mut Self
Configures whether WasmBacktrace
will be present in the context of
errors returned from Wasmtime.
A backtrace may be collected whenever an error is returned from a host function call through to WebAssembly or when WebAssembly itself hits a trap condition, such as an out-of-bounds memory access. This flag indicates, in these conditions, whether the backtrace is collected or not.
Currently wasm backtraces are implemented through frame pointer walking. This means that collecting a backtrace is expected to be a fast and relatively cheap operation. Additionally backtrace collection is suitable in concurrent environments since one thread capturing a backtrace won’t block other threads.
Collected backtraces are attached via anyhow::Error::context
to
errors returned from host functions. The WasmBacktrace
type can be
acquired via anyhow::Error::downcast_ref
to inspect the backtrace.
When this option is disabled then this context is never applied to
errors coming out of wasm.
This option is true
by default.
sourcepub fn wasm_backtrace_details(
&mut self,
enable: WasmBacktraceDetails,
) -> &mut Self
pub fn wasm_backtrace_details( &mut self, enable: WasmBacktraceDetails, ) -> &mut Self
Configures whether backtraces in Trap
will parse debug info in the wasm file to
have filename/line number information.
When enabled this will causes modules to retain debugging information found in wasm binaries. This debug information will be used when a trap happens to symbolicate each stack frame and attempt to print a filename/line number for each wasm frame in the stack trace.
By default this option is WasmBacktraceDetails::Environment
, meaning
that wasm will read WASMTIME_BACKTRACE_DETAILS
to indicate whether details
should be parsed.
sourcepub fn native_unwind_info(&mut self, enable: bool) -> &mut Self
pub fn native_unwind_info(&mut self, enable: bool) -> &mut Self
Configures whether to generate native unwind information
(e.g. .eh_frame
on Linux).
This configuration option only exists to help third-party stack
capturing mechanisms, such as the system’s unwinder or the backtrace
crate, determine how to unwind through Wasm frames. It does not affect
whether Wasmtime can capture Wasm backtraces or not. The presence of
WasmBacktrace
is controlled by the Config::wasm_backtrace
option.
Note that native unwind information is always generated when targeting Windows, since the Windows ABI requires it.
This option defaults to true
.
sourcepub fn consume_fuel(&mut self, enable: bool) -> &mut Self
pub fn consume_fuel(&mut self, enable: bool) -> &mut Self
Configures whether execution of WebAssembly will “consume fuel” to either halt or yield execution as desired.
This can be used to deterministically prevent infinitely-executing
WebAssembly code by instrumenting generated code to consume fuel as it
executes. When fuel runs out the behavior is defined by configuration
within a Store
, and by default a trap is raised.
Note that a Store
starts with no fuel, so if you enable this option
you’ll have to be sure to pour some fuel into Store
before
executing some code.
By default this option is false
.
sourcepub fn epoch_interruption(&mut self, enable: bool) -> &mut Self
pub fn epoch_interruption(&mut self, enable: bool) -> &mut Self
Enables epoch-based interruption.
When executing code in async mode, we sometimes want to
implement a form of cooperative timeslicing: long-running Wasm
guest code should periodically yield to the executor
loop. This yielding could be implemented by using “fuel” (see
consume_fuel
). However, fuel
instrumentation is somewhat expensive: it modifies the
compiled form of the Wasm code so that it maintains a precise
instruction count, frequently checking this count against the
remaining fuel. If one does not need this precise count or
deterministic interruptions, and only needs a periodic
interrupt of some form, then It would be better to have a more
lightweight mechanism.
Epoch-based interruption is that mechanism. There is a global
“epoch”, which is a counter that divides time into arbitrary
periods (or epochs). This counter lives on the
Engine
and can be incremented by calling
Engine::increment_epoch
.
Epoch-based instrumentation works by setting a “deadline
epoch”. The compiled code knows the deadline, and at certain
points, checks the current epoch against that deadline. It
will yield if the deadline has been reached.
The idea is that checking an infrequently-changing counter is cheaper than counting and frequently storing a precise metric (instructions executed) locally. The interruptions are not deterministic, but if the embedder increments the epoch in a periodic way (say, every regular timer tick by a thread or signal handler), then we can ensure that all async code will yield to the executor within a bounded time.
The deadline check cannot be avoided by malicious wasm code. It is safe to use epoch deadlines to limit the execution time of untrusted code.
The Store
tracks the deadline, and controls
what happens when the deadline is reached during
execution. Several behaviors are possible:
-
Trap if code is executing when the epoch deadline is met. See
Store::epoch_deadline_trap
. -
Call an arbitrary function. This function may chose to trap or increment the epoch. See
Store::epoch_deadline_callback
. -
Yield to the executor loop, then resume when the future is next polled. See
Store::epoch_deadline_async_yield_and_update
.
Trapping is the default. The yielding behaviour may be used for the timeslicing behavior described above.
This feature is available with or without async support. However, without async support, the timeslicing behaviour is not available. This means epoch-based interruption can only serve as a simple external-interruption mechanism.
An initial deadline must be set before executing code by calling
Store::set_epoch_deadline
. If this
deadline is not configured then wasm will immediately trap.
§When to use fuel vs. epochs
In general, epoch-based interruption results in faster execution. This difference is sometimes significant: in some measurements, up to 2-3x. This is because epoch-based interruption does less work: it only watches for a global rarely-changing counter to increment, rather than keeping a local frequently-changing counter and comparing it to a deadline.
Fuel, in contrast, should be used when deterministic yielding or trapping is needed. For example, if it is required that the same function call with the same starting state will always either complete or trap with an out-of-fuel error, deterministically, then fuel with a fixed bound should be used.
§See Also
sourcepub fn max_wasm_stack(&mut self, size: usize) -> &mut Self
pub fn max_wasm_stack(&mut self, size: usize) -> &mut Self
Configures the maximum amount of stack space available for executing WebAssembly code.
WebAssembly has well-defined semantics on stack overflow. This is intended to be a knob which can help configure how much stack space wasm execution is allowed to consume. Note that the number here is not super-precise, but rather wasm will take at most “pretty close to this much” stack space.
If a wasm call (or series of nested wasm calls) take more stack space
than the size
specified then a stack overflow trap will be raised.
Caveat: this knob only limits the stack space consumed by wasm code. More importantly, it does not ensure that this much stack space is available on the calling thread stack. Exhausting the thread stack typically leads to an abort of the process.
Here are some examples of how that could happen:
-
Let’s assume this option is set to 2 MiB and then a thread that has a stack with 512 KiB left.
If wasm code consumes more than 512 KiB then the process will be aborted.
-
Assuming the same conditions, but this time wasm code does not consume any stack but calls into a host function. The host function consumes more than 512 KiB of stack space. The process will be aborted.
There’s another gotcha related to recursive calling into wasm: the stack space consumed by a host function is counted towards this limit. The host functions are not prevented from consuming more than this limit. However, if the host function that used more than this limit and called back into wasm, then the execution will trap immediatelly because of stack overflow.
When the async
feature is enabled, this value cannot exceed the
async_stack_size
option. Be careful not to set this value too close
to async_stack_size
as doing so may limit how much stack space
is available for host functions.
By default this option is 512 KiB.
§Errors
The Engine::new
method will fail if the size
specified here is
either 0 or larger than the [Config::async_stack_size
] configuration.
sourcepub fn wasm_threads(&mut self, enable: bool) -> &mut Self
pub fn wasm_threads(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly threads proposal will be enabled for compilation.
The WebAssembly threads proposal is not currently fully standardized and is undergoing development. Additionally the support in wasmtime itself is still being worked on. Support for this feature can be enabled through this method for appropriate wasm modules.
This feature gates items such as shared memories and atomic instructions. Note that the threads feature depends on the bulk memory feature, which is enabled by default.
This is false
by default.
Note: Wasmtime does not implement everything for the wasm threads spec at this time, so bugs, panics, and possibly segfaults should be expected. This should not be enabled in a production setting right now.
§Errors
The validation of this feature are deferred until the engine is being built,
and thus may cause Engine::new
fail if the bulk_memory
feature is disabled.
sourcepub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self
pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly reference types proposal will be enabled for compilation.
This feature gates items such as the externref
and funcref
types as
well as allowing a module to define multiple tables.
Note that the reference types proposal depends on the bulk memory proposal.
This feature is true
by default.
§Errors
The validation of this feature are deferred until the engine is being built,
and thus may cause Engine::new
fail if the bulk_memory
feature is disabled.
sourcepub fn wasm_simd(&mut self, enable: bool) -> &mut Self
pub fn wasm_simd(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly SIMD proposal will be enabled for compilation.
The WebAssembly SIMD proposal. This feature gates items such
as the v128
type and all of its operators being in a module. Note that
this does not enable the relaxed simd proposal as that is not
implemented in Wasmtime at this time.
On x86_64 platforms note that enabling this feature requires SSE 4.2 and below to be available on the target platform. Compilation will fail if the compile target does not include SSE 4.2.
This is true
by default.
sourcepub fn wasm_relaxed_simd(&mut self, enable: bool) -> &mut Self
pub fn wasm_relaxed_simd(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly Relaxed SIMD proposal will be enabled for compilation.
The WebAssembly Relaxed SIMD proposal is not, at the time of this writing, at stage 4. The relaxed SIMD proposal adds new instructions to WebAssembly which, for some specific inputs, are allowed to produce different results on different hosts. More-or-less this proposal enables exposing platform-specific semantics of SIMD instructions in a controlled fashion to a WebAssembly program. From an embedder’s perspective this means that WebAssembly programs may execute differently depending on whether the host is x86_64 or AArch64, for example.
By default Wasmtime lowers relaxed SIMD instructions to the fastest
lowering for the platform it’s running on. This means that, by default,
some relaxed SIMD instructions may have different results for the same
inputs across x86_64 and AArch64. This behavior can be disabled through
the Config::relaxed_simd_deterministic
option which will force
deterministic behavior across all platforms, as classified by the
specification, at the cost of performance.
This is false
by default.
sourcepub fn relaxed_simd_deterministic(&mut self, enable: bool) -> &mut Self
pub fn relaxed_simd_deterministic(&mut self, enable: bool) -> &mut Self
This option can be used to control the behavior of the relaxed SIMD proposal’s instructions.
The relaxed SIMD proposal introduces instructions that are allowed to have different behavior on different architectures, primarily to afford an efficient implementation on all architectures. This means, however, that the same module may execute differently on one host than another, which typically is not otherwise the case. This option is provided to force Wasmtime to generate deterministic code for all relaxed simd instructions, at the cost of performance, for all architectures. When this option is enabled then the deterministic behavior of all instructions in the relaxed SIMD proposal is selected.
This is false
by default.
sourcepub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self
pub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly bulk memory operations proposal will be enabled for compilation.
This feature gates items such as the memory.copy
instruction, passive
data/table segments, etc, being in a module.
This is true
by default.
Feature reference_types
, which is also true
by default, requires
this feature to be enabled. Thus disabling this feature must also disable
reference_types
as well using wasm_reference_types
.
§Errors
Disabling this feature without disabling reference_types
will cause
Engine::new
to fail.
sourcepub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self
pub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly multi-value proposal will be enabled for compilation.
This feature gates functions and blocks returning multiple values in a module, for example.
This is true
by default.
sourcepub fn wasm_multi_memory(&mut self, enable: bool) -> &mut Self
pub fn wasm_multi_memory(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly multi-memory proposal will be enabled for compilation.
This feature gates modules having more than one linear memory declaration or import.
This is false
by default.
sourcepub fn wasm_memory64(&mut self, enable: bool) -> &mut Self
pub fn wasm_memory64(&mut self, enable: bool) -> &mut Self
Configures whether the WebAssembly memory64 proposal will be enabled for compilation.
Note that this the upstream specification is not finalized and Wasmtime may also have bugs for this feature since it hasn’t been exercised much.
This is false
by default.
sourcepub fn strategy(&mut self, strategy: Strategy) -> &mut Self
pub fn strategy(&mut self, strategy: Strategy) -> &mut Self
Configures which compilation strategy will be used for wasm modules.
This method can be used to configure which compiler is used for wasm
modules, and for more documentation consult the Strategy
enumeration
and its documentation.
The default value for this is Strategy::Auto
.
sourcepub fn profiler(&mut self, profile: ProfilingStrategy) -> &mut Self
pub fn profiler(&mut self, profile: ProfilingStrategy) -> &mut Self
Creates a default profiler based on the profiling strategy chosen.
Profiler creation calls the type’s default initializer where the purpose is really just to put in place the type used for profiling.
Some ProfilingStrategy
require specific platforms or particular feature
to be enabled, such as ProfilingStrategy::JitDump
requires the jitdump
feature.
§Errors
The validation of this field is deferred until the engine is being built, and thus may
cause Engine::new
fail if the required feature is disabled, or the platform is not
supported.
sourcepub fn cranelift_debug_verifier(&mut self, enable: bool) -> &mut Self
pub fn cranelift_debug_verifier(&mut self, enable: bool) -> &mut Self
Configures whether the debug verifier of Cranelift is enabled or not.
When Cranelift is used as a code generation backend this will configure
it to have the enable_verifier
flag which will enable a number of debug
checks inside of Cranelift. This is largely only useful for the
developers of wasmtime itself.
The default value for this is false
sourcepub fn cranelift_opt_level(&mut self, level: OptLevel) -> &mut Self
pub fn cranelift_opt_level(&mut self, level: OptLevel) -> &mut Self
Configures the Cranelift code generator optimization level.
When the Cranelift code generator is used you can configure the
optimization level used for generated code in a few various ways. For
more information see the documentation of OptLevel
.
The default value for this is OptLevel::None
.
sourcepub fn cranelift_use_egraphs(&mut self, enable: bool) -> &mut Self
👎Deprecated since 5.0.0: egraphs will be the default and this method will be removed in a future version.
pub fn cranelift_use_egraphs(&mut self, enable: bool) -> &mut Self
Configures the Cranelift code generator to use its “egraph”-based mid-end optimizer.
This optimizer has replaced the compiler’s more traditional pipeline of optimization passes with a unified code-rewriting system. It is on by default, but the traditional optimization pass structure is still available for now (it is deprecrated and will be removed in a future version).
The default value for this is true
.
sourcepub fn cranelift_nan_canonicalization(&mut self, enable: bool) -> &mut Self
pub fn cranelift_nan_canonicalization(&mut self, enable: bool) -> &mut Self
Configures whether Cranelift should perform a NaN-canonicalization pass.
When Cranelift is used as a code generation backend this will configure it to replace NaNs with a single canonical value. This is useful for users requiring entirely deterministic WebAssembly computation. This is not required by the WebAssembly spec, so it is not enabled by default.
The default value for this is false
sourcepub unsafe fn cranelift_flag_enable(&mut self, flag: &str) -> &mut Self
pub unsafe fn cranelift_flag_enable(&mut self, flag: &str) -> &mut Self
Allows setting a Cranelift boolean flag or preset. This allows fine-tuning of Cranelift settings.
Since Cranelift flags may be unstable, this method should not be considered to be stable
either; other Config
functions should be preferred for stability.
§Safety
This is marked as unsafe, because setting the wrong flag might break invariants, resulting in execution hazards.
§Errors
The validation of the flags are deferred until the engine is being built, and thus may
cause Engine::new
fail if the flag’s name does not exist, or the value is not appropriate
for the flag type.
sourcepub unsafe fn cranelift_flag_set(
&mut self,
name: &str,
value: &str,
) -> &mut Self
pub unsafe fn cranelift_flag_set( &mut self, name: &str, value: &str, ) -> &mut Self
Allows settings another Cranelift flag defined by a flag name and value. This allows fine-tuning of Cranelift settings.
Since Cranelift flags may be unstable, this method should not be considered to be stable
either; other Config
functions should be preferred for stability.
§Safety
This is marked as unsafe, because setting the wrong flag might break invariants, resulting in execution hazards.
§Errors
The validation of the flags are deferred until the engine is being built, and thus may
cause Engine::new
fail if the flag’s name does not exist, or incompatible with other
settings.
For example, feature wasm_backtrace
will set unwind_info
to true
, but if it’s
manually set to false then it will fail.
sourcepub fn cache_config_load(&mut self, path: impl AsRef<Path>) -> Result<&mut Self>
pub fn cache_config_load(&mut self, path: impl AsRef<Path>) -> Result<&mut Self>
Loads cache configuration specified at path
.
This method will read the file specified by path
on the filesystem and
attempt to load cache configuration from it. This method can also fail
due to I/O errors, misconfiguration, syntax errors, etc. For expected
syntax in the configuration file see the documentation online.
By default cache configuration is not enabled or loaded.
This method is only available when the cache
feature of this crate is
enabled.
§Errors
This method can fail due to any error that happens when loading the file
pointed to by path
and attempting to load the cache configuration.
sourcepub fn disable_cache(&mut self) -> &mut Self
pub fn disable_cache(&mut self) -> &mut Self
Disable caching.
Every call to Module::new(my_wasm)
will
recompile my_wasm
, even when it is unchanged.
By default, new configs do not have caching enabled. This method is only useful for disabling a previous cache configuration.
This method is only available when the cache
feature of this crate is
enabled.
sourcepub fn cache_config_load_default(&mut self) -> Result<&mut Self>
pub fn cache_config_load_default(&mut self) -> Result<&mut Self>
Loads cache configuration from the system default path.
This commit is the same as Config::cache_config_load
except that it
does not take a path argument and instead loads the default
configuration present on the system. This is located, for example, on
Unix at $HOME/.config/wasmtime/config.toml
and is typically created
with the wasmtime config new
command.
By default cache configuration is not enabled or loaded.
This method is only available when the cache
feature of this crate is
enabled.
§Errors
This method can fail due to any error that happens when loading the default system configuration. Note that it is not an error if the default config file does not exist, in which case the default settings for an enabled cache are applied.
sourcepub fn with_host_memory(
&mut self,
mem_creator: Arc<dyn MemoryCreator>,
) -> &mut Self
pub fn with_host_memory( &mut self, mem_creator: Arc<dyn MemoryCreator>, ) -> &mut Self
Sets a custom memory creator.
Custom memory creators are used when creating host Memory
objects or when
creating instance linear memories for the on-demand instance allocation strategy.
sourcepub fn allocation_strategy(
&mut self,
strategy: InstanceAllocationStrategy,
) -> &mut Self
pub fn allocation_strategy( &mut self, strategy: InstanceAllocationStrategy, ) -> &mut Self
Sets the instance allocation strategy to use.
When using the pooling instance allocation strategy, all linear memories
will be created as “static” and the
Config::static_memory_maximum_size
and
Config::static_memory_guard_size
options will be used to configure
the virtual memory allocations of linear memories.
sourcepub fn static_memory_maximum_size(&mut self, max_size: u64) -> &mut Self
pub fn static_memory_maximum_size(&mut self, max_size: u64) -> &mut Self
Configures the maximum size, in bytes, where a linear memory is considered static, above which it’ll be considered dynamic.
Note: this value has important performance ramifications, be sure to understand what this value does before tweaking it and benchmarking.
This function configures the threshold for wasm memories whether they’re
implemented as a dynamically relocatable chunk of memory or a statically
located chunk of memory. The max_size
parameter here is the size, in
bytes, where if the maximum size of a linear memory is below max_size
then it will be statically allocated with enough space to never have to
move. If the maximum size of a linear memory is larger than max_size
then wasm memory will be dynamically located and may move in memory
through growth operations.
Specifying a max_size
of 0 means that all memories will be dynamic and
may be relocated through memory.grow
. Also note that if any wasm
memory’s maximum size is below max_size
then it will still reserve
max_size
bytes in the virtual memory space.
§Static vs Dynamic Memory
Linear memories represent contiguous arrays of bytes, but they can also be grown through the API and wasm instructions. When memory is grown if space hasn’t been preallocated then growth may involve relocating the base pointer in memory. Memories in Wasmtime are classified in two different ways:
-
static - these memories preallocate all space necessary they’ll ever need, meaning that the base pointer of these memories is never moved. Static memories may take more virtual memory space because of pre-reserving space for memories.
-
dynamic - these memories are not preallocated and may move during growth operations. Dynamic memories consume less virtual memory space because they don’t need to preallocate space for future growth.
Static memories can be optimized better in JIT code because once the
base address is loaded in a function it’s known that we never need to
reload it because it never changes, memory.grow
is generally a pretty
fast operation because the wasm memory is never relocated, and under
some conditions bounds checks can be elided on memory accesses.
Dynamic memories can’t be quite as heavily optimized because the base
address may need to be reloaded more often, they may require relocating
lots of data on memory.grow
, and dynamic memories require
unconditional bounds checks on all memory accesses.
§Should you use static or dynamic memory?
In general you probably don’t need to change the value of this property. The defaults here are optimized for each target platform to consume a reasonable amount of physical memory while also generating speedy machine code.
One of the main reasons you may want to configure this today is if your environment can’t reserve virtual memory space for each wasm linear memory. On 64-bit platforms wasm memories require a 6GB reservation by default, and system limits may prevent this in some scenarios. In this case you may wish to force memories to be allocated dynamically meaning that the virtual memory footprint of creating a wasm memory should be exactly what’s used by the wasm itself.
For 32-bit memories a static memory must contain at least 4GB of reserved address space plus a guard page to elide any bounds checks at all. Smaller static memories will use similar bounds checks as dynamic memories.
§Default
The default value for this property depends on the host platform. For 64-bit platforms there’s lots of address space available, so the default configured here is 4GB. WebAssembly linear memories currently max out at 4GB which means that on 64-bit platforms Wasmtime by default always uses a static memory. This, coupled with a sufficiently sized guard region, should produce the fastest JIT code on 64-bit platforms, but does require a large address space reservation for each wasm memory.
For 32-bit platforms this value defaults to 1GB. This means that wasm memories whose maximum size is less than 1GB will be allocated statically, otherwise they’ll be considered dynamic.
§Static Memory and Pooled Instance Allocation
When using the pooling instance allocator memories are considered to always be static memories, they are never dynamic. This setting configures the size of linear memory to reserve for each memory in the pooling allocator.
sourcepub fn static_memory_forced(&mut self, force: bool) -> &mut Self
pub fn static_memory_forced(&mut self, force: bool) -> &mut Self
Indicates that the “static” style of memory should always be used.
This configuration option enables selecting the “static” option for all
linear memories created within this Config
. This means that all
memories will be allocated up-front and will never move. Additionally
this means that all memories are synthetically limited by the
Config::static_memory_maximum_size
option, irregardless of what the
actual maximum size is on the memory’s original type.
For the difference between static and dynamic memories, see the
Config::static_memory_maximum_size
.
sourcepub fn static_memory_guard_size(&mut self, guard_size: u64) -> &mut Self
pub fn static_memory_guard_size(&mut self, guard_size: u64) -> &mut Self
Configures the size, in bytes, of the guard region used at the end of a static memory’s address space reservation.
Note: this value has important performance ramifications, be sure to understand what this value does before tweaking it and benchmarking.
All WebAssembly loads/stores are bounds-checked and generate a trap if they’re out-of-bounds. Loads and stores are often very performance critical, so we want the bounds check to be as fast as possible! Accelerating these memory accesses is the motivation for a guard after a memory allocation.
Memories (both static and dynamic) can be configured with a guard at the end of them which consists of unmapped virtual memory. This unmapped memory will trigger a memory access violation (e.g. segfault) if accessed. This allows JIT code to elide bounds checks if it can prove that an access, if out of bounds, would hit the guard region. This means that having such a guard of unmapped memory can remove the need for bounds checks in JIT code.
For the difference between static and dynamic memories, see the
Config::static_memory_maximum_size
.
§How big should the guard be?
In general, like with configuring static_memory_maximum_size
, you
probably don’t want to change this value from the defaults. Otherwise,
though, the size of the guard region affects the number of bounds checks
needed for generated wasm code. More specifically, loads/stores with
immediate offsets will generate bounds checks based on how big the guard
page is.
For 32-bit memories a 4GB static memory is required to even start removing bounds checks. A 4GB guard size will guarantee that the module has zero bounds checks for memory accesses. A 2GB guard size will eliminate all bounds checks with an immediate offset less than 2GB. A guard size of zero means that all memory accesses will still have bounds checks.
§Default
The default value for this property is 2GB on 64-bit platforms. This allows eliminating almost all bounds checks on loads/stores with an immediate offset of less than 2GB. On 32-bit platforms this defaults to 64KB.
§Errors
The Engine::new
method will return an error if this option is smaller
than the value configured for Config::dynamic_memory_guard_size
.
sourcepub fn dynamic_memory_guard_size(&mut self, guard_size: u64) -> &mut Self
pub fn dynamic_memory_guard_size(&mut self, guard_size: u64) -> &mut Self
Configures the size, in bytes, of the guard region used at the end of a dynamic memory’s address space reservation.
For the difference between static and dynamic memories, see the
Config::static_memory_maximum_size
For more information about what a guard is, see the documentation on
Config::static_memory_guard_size
.
Note that the size of the guard region for dynamic memories is not super critical for performance. Making it reasonably-sized can improve generated code slightly, but for maximum performance you’ll want to lean towards static memories rather than dynamic anyway.
Also note that the dynamic memory guard size must be smaller than the static memory guard size, so if a large dynamic memory guard is specified then the static memory guard size will also be automatically increased.
§Default
This value defaults to 64KB.
§Errors
The Engine::new
method will return an error if this option is larger
than the value configured for Config::static_memory_guard_size
.
sourcepub fn dynamic_memory_reserved_for_growth(&mut self, reserved: u64) -> &mut Self
pub fn dynamic_memory_reserved_for_growth(&mut self, reserved: u64) -> &mut Self
Configures the size, in bytes, of the extra virtual memory space reserved after a “dynamic” memory for growing into.
For the difference between static and dynamic memories, see the
Config::static_memory_maximum_size
Dynamic memories can be relocated in the process’s virtual address space on growth and do not always reserve their entire space up-front. This means that a growth of the memory may require movement in the address space, which in the worst case can copy a large number of bytes from one region to another.
This setting configures how many bytes are reserved after the initial
reservation for a dynamic memory for growing into. A value of 0 here
means that no extra bytes are reserved and all calls to memory.grow
will need to relocate the wasm linear memory (copying all the bytes). A
value of 1 megabyte, however, means that memory.grow
can allocate up
to a megabyte of extra memory before the memory needs to be moved in
linear memory.
Note that this is a currently simple heuristic for optimizing the growth of dynamic memories, primarily implemented for the memory64 proposal where all memories are currently “dynamic”. This is unlikely to be a one-size-fits-all style approach and if you’re an embedder running into issues with dynamic memories and growth and are interested in having other growth strategies available here please feel free to open an issue on the Wasmtime repository!
§Default
For 64-bit platforms this defaults to 2GB, and for 32-bit platforms this defaults to 1MB.
sourcepub fn guard_before_linear_memory(&mut self, guard: bool) -> &mut Self
pub fn guard_before_linear_memory(&mut self, guard: bool) -> &mut Self
Indicates whether a guard region is present before allocations of linear memory.
Guard regions before linear memories are never used during normal operation of WebAssembly modules, even if they have out-of-bounds loads. The only purpose for a preceding guard region in linear memory is extra protection against possible bugs in code generators like Cranelift. This setting does not affect performance in any way, but will result in larger virtual memory reservations for linear memories (it won’t actually ever use more memory, just use more of the address space).
The size of the guard region before linear memory is the same as the
guard size that comes after linear memory, which is configured by
Config::static_memory_guard_size
and
Config::dynamic_memory_guard_size
.
§Default
This value defaults to true
.
sourcepub fn module_version(
&mut self,
strategy: ModuleVersionStrategy,
) -> Result<&mut Self>
pub fn module_version( &mut self, strategy: ModuleVersionStrategy, ) -> Result<&mut Self>
Configure the version information used in serialized and deserialzied crate::Module
s.
This effects the behavior of crate::Module::serialize()
, as well as
crate::Module::deserialize()
and related functions.
The default strategy is to use the wasmtime crate’s Cargo package version.
sourcepub fn parallel_compilation(&mut self, parallel: bool) -> &mut Self
pub fn parallel_compilation(&mut self, parallel: bool) -> &mut Self
Configure wether wasmtime should compile a module using multiple threads.
Disabling this will result in a single thread being used to compile the wasm bytecode.
By default parallel compilation is enabled.
sourcepub fn generate_address_map(&mut self, generate: bool) -> &mut Self
pub fn generate_address_map(&mut self, generate: bool) -> &mut Self
Configures whether compiled artifacts will contain information to map native program addresses back to the original wasm module.
This configuration option is true
by default and, if enabled,
generates the appropriate tables in compiled modules to map from native
address back to wasm source addresses. This is used for displaying wasm
program counters in backtraces as well as generating filenames/line
numbers if so configured as well (and the original wasm module has DWARF
debugging information present).
sourcepub fn memory_init_cow(&mut self, enable: bool) -> &mut Self
pub fn memory_init_cow(&mut self, enable: bool) -> &mut Self
Configures whether copy-on-write memory-mapped data is used to initialize a linear memory.
Initializing linear memory via a copy-on-write mapping can drastically improve instantiation costs of a WebAssembly module because copying memory is deferred. Additionally if a page of memory is only ever read from WebAssembly and never written too then the same underlying page of data will be reused between all instantiations of a module meaning that if a module is instantiated many times this can lower the overall memory required needed to run that module.
This feature is only applicable when a WebAssembly module meets specific criteria to be initialized in this fashion, such as:
- Only memories defined in the module can be initialized this way.
- Data segments for memory must use statically known offsets.
- Data segments for memory must all be in-bounds.
Modules which do not meet these criteria will fall back to initialization of linear memory based on copying memory.
This feature of Wasmtime is also platform-specific:
- Linux - this feature is supported for all instances of
Module
. Modules backed by an existing mmap (such as those created byModule::deserialize_file
) will reuse that mmap to cow-initialize memory. Other instance ofModule
may use thememfd_create
syscall to create an initialization image tommap
. - Unix (not Linux) - this feature is only supported when loading modules
from a precompiled file via
Module::deserialize_file
where there is a file descriptor to use to map data into the process. Note that the module must have been compiled with this setting enabled as well. - Windows - there is no support for this feature at this time. Memory initialization will always copy bytes.
By default this option is enabled.
sourcepub fn force_memory_init_memfd(&mut self, enable: bool) -> &mut Self
pub fn force_memory_init_memfd(&mut self, enable: bool) -> &mut Self
A configuration option to force the usage of memfd_create
on Linux to
be used as the backing source for a module’s initial memory image.
When Config::memory_init_cow
is enabled, which is enabled by
default, module memory initialization images are taken from a module’s
original mmap if possible. If a precompiled module was loaded from disk
this means that the disk’s file is used as an mmap source for the
initial linear memory contents. This option can be used to force, on
Linux, that instead of using the original file on disk a new in-memory
file is created with memfd_create
to hold the contents of the initial
image.
This option can be used to avoid possibly loading the contents of memory
from disk through a page fault. Instead with memfd_create
the contents
of memory are always in RAM, meaning that even page faults which
initially populate a wasm linear memory will only work with RAM instead
of ever hitting the disk that the original precompiled module is stored
on.
This option is disabled by default.
sourcepub fn memory_guaranteed_dense_image_size(
&mut self,
size_in_bytes: u64,
) -> &mut Self
pub fn memory_guaranteed_dense_image_size( &mut self, size_in_bytes: u64, ) -> &mut Self
Configures the “guaranteed dense image size” for copy-on-write initialized memories.
When using the Config::memory_init_cow
feature to initialize memory
efficiently (which is enabled by default), compiled modules contain an
image of the module’s initial heap. If the module has a fairly sparse
initial heap, with just a few data segments at very different offsets,
this could result in a large region of zero bytes in the image. In
other words, it’s not very memory-efficient.
We normally use a heuristic to avoid this: if less than half of the initialized range (first non-zero to last non-zero byte) of any memory in the module has pages with nonzero bytes, then we avoid creating a memory image for the entire module.
However, if the embedder always needs the instantiation-time efficiency of copy-on-write initialization, and is otherwise carefully controlling parameters of the modules (for example, by limiting the maximum heap size of the modules), then it may be desirable to ensure a memory image is created even if this could go against the heuristic above. Thus, we add another condition: there is a size of initialized data region up to which we always allow a memory image. The embedder can set this to a known maximum heap size if they desire to always get the benefits of copy-on-write images.
In the future we may implement a “best of both worlds” solution where we have a dense image up to some limit, and then support a sparse list of initializers beyond that; this would get most of the benefit of copy-on-write and pay the incremental cost of eager initialization only for those bits of memory that are out-of-bounds. However, for now, an embedder desiring fast instantiation should ensure that this setting is as large as the maximum module initial memory content size.
By default this value is 16 MiB.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Config
impl !RefUnwindSafe for Config
impl Send for Config
impl Sync for Config
impl Unpin for Config
impl !UnwindSafe for Config
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more