Browse Source

Fix handling of `Tunables` on cross-compiles (#7844)

* Fix handling of `Tunables` on cross-compiles

This commit fixes how Wasmtime handles `Tunables` when targetting
non-host platforms (or namely platforms with different pointer widths).
Previously the host's `Tunables` would always be used instead of the
target's tunables which meant that modules couldn't be loaded on the
other platform due to the host having differing tunables by default.

This commit updates tunables in `wasmtime::Config` to all be optional
and loading the actual `Tunables` is deferred until the target is known
during `Engine`-creation time.

* Fix warning
pull/7861/head
Alex Crichton 9 months ago
committed by GitHub
parent
commit
787e966161
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      crates/cranelift/src/builder.rs
  2. 2
      crates/environ/src/lib.rs
  3. 99
      crates/environ/src/tunables.rs
  4. 6
      crates/runtime/src/instance/allocator/pooling.rs
  5. 6
      crates/runtime/src/instance/allocator/pooling/memory_pool.rs
  6. 6
      crates/wasmtime/src/compile.rs
  7. 167
      crates/wasmtime/src/config.rs
  8. 34
      crates/wasmtime/src/engine.rs
  9. 4
      crates/wasmtime/src/engine/serialization.rs
  10. 2
      crates/wasmtime/src/runtime/memory.rs
  11. 2
      crates/wasmtime/src/runtime/module.rs
  12. 6
      crates/wasmtime/src/runtime/store.rs
  13. 5
      crates/wasmtime/src/runtime/trampoline/func.rs
  14. 2
      crates/wasmtime/src/runtime/trampoline/memory.rs
  15. 2
      crates/wasmtime/src/runtime/trampoline/table.rs
  16. 2
      winch/filetests/src/lib.rs
  17. 2
      winch/src/compile.rs

11
crates/cranelift/src/builder.rs

@ -16,7 +16,7 @@ use wasmtime_cranelift_shared::isa_builder::IsaBuilder;
use wasmtime_environ::{CacheStore, CompilerBuilder, Setting, Tunables};
struct Builder {
tunables: Tunables,
tunables: Option<Tunables>,
inner: IsaBuilder<CodegenResult<OwnedTargetIsa>>,
linkopts: LinkOptions,
cache_store: Option<Arc<dyn CacheStore>>,
@ -39,7 +39,7 @@ pub struct LinkOptions {
pub fn builder(triple: Option<Triple>) -> Result<Box<dyn CompilerBuilder>> {
Ok(Box::new(Builder {
tunables: Tunables::default(),
tunables: None,
inner: IsaBuilder::new(triple, |triple| isa::lookup(triple).map_err(|e| e.into()))?,
linkopts: LinkOptions::default(),
cache_store: None,
@ -82,14 +82,17 @@ impl CompilerBuilder for Builder {
}
fn set_tunables(&mut self, tunables: Tunables) -> Result<()> {
self.tunables = tunables;
self.tunables = Some(tunables);
Ok(())
}
fn build(&self) -> Result<Box<dyn wasmtime_environ::Compiler>> {
let isa = self.inner.build()?;
Ok(Box::new(crate::compiler::Compiler::new(
self.tunables.clone(),
self.tunables
.as_ref()
.expect("set_tunables not called")
.clone(),
isa,
self.cache_store.clone(),
self.linkopts.clone(),

2
crates/environ/src/lib.rs

@ -33,7 +33,7 @@ pub use crate::ref_bits::*;
pub use crate::scopevec::ScopeVec;
pub use crate::stack_map::StackMap;
pub use crate::trap_encoding::*;
pub use crate::tunables::Tunables;
pub use crate::tunables::*;
pub use crate::vmoffsets::*;
pub use object;

99
crates/environ/src/tunables.rs

@ -1,7 +1,7 @@
use serde_derive::{Deserialize, Serialize};
/// Tunable parameters for WebAssembly compilation.
#[derive(Clone, Hash, Serialize, Deserialize)]
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
pub struct Tunables {
/// For static heaps, the size in wasm pages of the heap protected by bounds
/// checking.
@ -56,62 +56,85 @@ pub struct Tunables {
pub tail_callable: bool,
}
impl Default for Tunables {
fn default() -> Self {
let (static_memory_bound, static_memory_offset_guard_size) = if cfg!(miri) {
impl Tunables {
/// Returns a `Tunables` configuration assumed for running code on the host.
pub fn default_host() -> Self {
if cfg!(miri) {
Tunables::default_miri()
} else if cfg!(target_pointer_width = "32") {
Tunables::default_u32()
} else if cfg!(target_pointer_width = "64") {
Tunables::default_u64()
} else {
panic!("unsupported target_pointer_width");
}
}
/// Returns the default set of tunables for running under MIRI.
pub fn default_miri() -> Tunables {
Tunables {
// No virtual memory tricks are available on miri so make these
// limits quite conservative.
((1 << 20) / crate::WASM_PAGE_SIZE as u64, 0)
} else if cfg!(target_pointer_width = "64") {
static_memory_bound: (1 << 20) / crate::WASM_PAGE_SIZE as u64,
static_memory_offset_guard_size: 0,
dynamic_memory_offset_guard_size: 0,
dynamic_memory_growth_reserve: 0,
// General options which have the same defaults regardless of
// architecture.
generate_native_debuginfo: false,
parse_wasm_debuginfo: true,
consume_fuel: false,
epoch_interruption: false,
static_memory_bound_is_maximum: false,
guard_before_linear_memory: true,
generate_address_map: true,
debug_adapter_modules: false,
relaxed_simd_deterministic: false,
tail_callable: false,
}
}
/// Returns the default set of tunables for running under a 32-bit host.
pub fn default_u32() -> Tunables {
Tunables {
// For 32-bit we scale way down to 10MB of reserved memory. This
// impacts performance severely but allows us to have more than a
// few instances running around.
static_memory_bound: (10 * (1 << 20)) / crate::WASM_PAGE_SIZE as u64,
static_memory_offset_guard_size: 0x1_0000,
dynamic_memory_offset_guard_size: 0x1_0000,
dynamic_memory_growth_reserve: 1 << 20, // 1MB
..Tunables::default_miri()
}
}
/// Returns the default set of tunables for running under a 64-bit host.
pub fn default_u64() -> Tunables {
Tunables {
// 64-bit has tons of address space to static memories can have 4gb
// address space reservations liberally by default, allowing us to
// help eliminate bounds checks.
//
// Coupled with a 2 GiB address space guard it lets us translate
// wasm offsets into x86 offsets as aggressively as we can.
(0x1_0000, 0x8000_0000)
} else if cfg!(target_pointer_width = "32") {
// For 32-bit we scale way down to 10MB of reserved memory. This
// impacts performance severely but allows us to have more than a
// few instances running around.
((10 * (1 << 20)) / crate::WASM_PAGE_SIZE as u64, 0x1_0000)
} else {
panic!("unsupported target_pointer_width");
};
Self {
static_memory_bound,
static_memory_offset_guard_size,
static_memory_bound: 0x1_0000,
static_memory_offset_guard_size: 0x8000_0000,
// Size in bytes of the offset guard for dynamic memories.
//
// Allocate a small guard to optimize common cases but without
// wasting too much memory.
dynamic_memory_offset_guard_size: if cfg!(miri) { 0 } else { 0x1_0000 },
dynamic_memory_offset_guard_size: 0x1_0000,
// We've got lots of address space on 64-bit so use a larger
// grow-into-this area, but on 32-bit we aren't as lucky. Miri is
// not exactly fast so reduce memory consumption instead of trying
// to avoid memory movement.
dynamic_memory_growth_reserve: if cfg!(miri) {
0
} else if cfg!(target_pointer_width = "64") {
2 << 30 // 2GB
} else if cfg!(target_pointer_width = "32") {
1 << 20 // 1MB
} else {
panic!("unsupported target_pointer_width");
},
dynamic_memory_growth_reserve: 2 << 30, // 2GB
generate_native_debuginfo: false,
parse_wasm_debuginfo: true,
consume_fuel: false,
epoch_interruption: false,
static_memory_bound_is_maximum: false,
guard_before_linear_memory: true,
generate_address_map: true,
debug_adapter_modules: false,
relaxed_simd_deterministic: false,
tail_callable: false,
..Tunables::default_miri()
}
}
}

6
crates/runtime/src/instance/allocator/pooling.rs

@ -579,7 +579,7 @@ mod test {
&config,
&Tunables {
static_memory_bound: 1,
..Tunables::default()
..Tunables::default_host()
},
)
.map_err(|e| e.to_string())
@ -603,7 +603,7 @@ mod test {
async_stack_zeroing: true,
..PoolingInstanceAllocatorConfig::default()
};
let allocator = PoolingInstanceAllocator::new(&config, &Tunables::default())?;
let allocator = PoolingInstanceAllocator::new(&config, &Tunables::default_host())?;
unsafe {
for _ in 0..255 {
@ -637,7 +637,7 @@ mod test {
async_stack_zeroing: false,
..PoolingInstanceAllocatorConfig::default()
};
let allocator = PoolingInstanceAllocator::new(&config, &Tunables::default())?;
let allocator = PoolingInstanceAllocator::new(&config, &Tunables::default_host())?;
unsafe {
for i in 0..255 {

6
crates/runtime/src/instance/allocator/pooling/memory_pool.rs

@ -774,7 +774,7 @@ mod tests {
&Tunables {
static_memory_bound: 1,
static_memory_offset_guard_size: 0,
..Tunables::default()
..Tunables::default_host()
},
)?;
@ -808,7 +808,7 @@ mod tests {
&Tunables {
static_memory_bound: 1,
static_memory_offset_guard_size: 0,
..Tunables::default()
..Tunables::default_host()
},
)
.unwrap();
@ -828,7 +828,7 @@ mod tests {
memory_protection_keys: MpkEnabled::Enable,
..PoolingInstanceAllocatorConfig::default()
};
let pool = MemoryPool::new(&config, &Tunables::default()).unwrap();
let pool = MemoryPool::new(&config, &Tunables::default_host()).unwrap();
assert!(pool.stripes.len() >= 2);
let max_memory_slots = config.limits.total_memories;

6
crates/wasmtime/src/compile.rs

@ -54,7 +54,7 @@ pub(crate) fn build_artifacts<T: FinishedObject>(
engine: &Engine,
wasm: &[u8],
) -> Result<(T, Option<(CompiledModuleInfo, ModuleTypes)>)> {
let tunables = &engine.config().tunables;
let tunables = engine.tunables();
// First a `ModuleEnvironment` is created which records type information
// about the wasm module. This is where the WebAssembly is parsed and
@ -117,7 +117,7 @@ pub(crate) fn build_component_artifacts<T: FinishedObject>(
use wasmtime_environ::component::{CompiledComponentInfo, ComponentArtifacts};
use wasmtime_environ::ScopeVec;
let tunables = &engine.config().tunables;
let tunables = engine.tunables();
let compiler = engine.compiler();
let scope = ScopeVec::new();
@ -610,7 +610,7 @@ impl FunctionIndices {
// `symbol_ids_and_locs[i]` is the symbol ID and function location of
// `compiled_funcs[i]`.
let compiler = engine.compiler();
let tunables = &engine.config().tunables;
let tunables = engine.tunables();
let symbol_ids_and_locs = compiler.append_code(
&mut obj,
&compiled_funcs,

167
crates/wasmtime/src/config.rs

@ -6,7 +6,7 @@ use std::fmt;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use target_lexicon::Architecture;
use target_lexicon::{Architecture, PointerWidth};
use wasmparser::WasmFeatures;
#[cfg(feature = "cache")]
use wasmtime_cache::CacheConfig;
@ -103,8 +103,8 @@ pub struct Config {
#[cfg(any(feature = "cranelift", feature = "winch"))]
compiler_config: CompilerConfig,
profiling_strategy: ProfilingStrategy,
tunables: ConfigTunables,
pub(crate) tunables: Tunables,
#[cfg(feature = "cache")]
pub(crate) cache_config: CacheConfig,
#[cfg(feature = "runtime")]
@ -130,6 +130,24 @@ pub struct Config {
pub(crate) macos_use_mach_ports: bool,
}
#[derive(Default, Clone)]
struct ConfigTunables {
static_memory_bound: Option<u64>,
static_memory_offset_guard_size: Option<u64>,
dynamic_memory_offset_guard_size: Option<u64>,
dynamic_memory_growth_reserve: Option<u64>,
generate_native_debuginfo: Option<bool>,
parse_wasm_debuginfo: Option<bool>,
consume_fuel: Option<bool>,
epoch_interruption: Option<bool>,
static_memory_bound_is_maximum: Option<bool>,
guard_before_linear_memory: Option<bool>,
generate_address_map: Option<bool>,
debug_adapter_modules: Option<bool>,
relaxed_simd_deterministic: Option<bool>,
tail_callable: Option<bool>,
}
/// User-provided configuration for the compiler.
#[cfg(any(feature = "cranelift", feature = "winch"))]
#[derive(Debug, Clone)]
@ -190,7 +208,7 @@ impl Config {
/// specified.
pub fn new() -> Self {
let mut ret = Self {
tunables: Tunables::default(),
tunables: ConfigTunables::default(),
#[cfg(any(feature = "cranelift", feature = "winch"))]
compiler_config: CompilerConfig::default(),
#[cfg(feature = "cache")]
@ -386,7 +404,7 @@ impl Config {
///
/// By default this option is `false`.
pub fn debug_info(&mut self, enable: bool) -> &mut Self {
self.tunables.generate_native_debuginfo = enable;
self.tunables.generate_native_debuginfo = Some(enable);
self
}
@ -433,13 +451,13 @@ impl Config {
pub fn wasm_backtrace_details(&mut self, enable: WasmBacktraceDetails) -> &mut Self {
self.wasm_backtrace_details_env_used = false;
self.tunables.parse_wasm_debuginfo = match enable {
WasmBacktraceDetails::Enable => true,
WasmBacktraceDetails::Disable => false,
WasmBacktraceDetails::Enable => Some(true),
WasmBacktraceDetails::Disable => Some(false),
WasmBacktraceDetails::Environment => {
self.wasm_backtrace_details_env_used = true;
std::env::var("WASMTIME_BACKTRACE_DETAILS")
.map(|s| s == "1")
.unwrap_or(false)
.map(|s| Some(s == "1"))
.unwrap_or(Some(false))
}
};
self
@ -482,7 +500,7 @@ impl Config {
///
/// [`Store`]: crate::Store
pub fn consume_fuel(&mut self, enable: bool) -> &mut Self {
self.tunables.consume_fuel = enable;
self.tunables.consume_fuel = Some(enable);
self
}
@ -576,7 +594,7 @@ impl Config {
/// - [`Store::epoch_deadline_callback`](crate::Store::epoch_deadline_callback)
/// - [`Store::epoch_deadline_async_yield_and_update`](crate::Store::epoch_deadline_async_yield_and_update)
pub fn epoch_interruption(&mut self, enable: bool) -> &mut Self {
self.tunables.epoch_interruption = enable;
self.tunables.epoch_interruption = Some(enable);
self
}
@ -667,7 +685,7 @@ impl Config {
/// [WebAssembly tail calls proposal]: https://github.com/WebAssembly/tail-call
pub fn wasm_tail_call(&mut self, enable: bool) -> &mut Self {
self.features.tail_call = enable;
self.tunables.tail_callable = enable;
self.tunables.tail_callable = Some(enable);
self
}
@ -794,7 +812,7 @@ impl Config {
///
/// [proposal]: https://github.com/webassembly/relaxed-simd
pub fn relaxed_simd_deterministic(&mut self, enable: bool) -> &mut Self {
self.tunables.relaxed_simd_deterministic = enable;
self.tunables.relaxed_simd_deterministic = Some(enable);
self
}
@ -1239,7 +1257,7 @@ impl Config {
/// `PoolingAllocatorConfig::memory_protection_keys` for details.
pub fn static_memory_maximum_size(&mut self, max_size: u64) -> &mut Self {
let max_pages = max_size / u64::from(wasmtime_environ::WASM_PAGE_SIZE);
self.tunables.static_memory_bound = max_pages;
self.tunables.static_memory_bound = Some(max_pages);
self
}
@ -1255,7 +1273,7 @@ impl Config {
/// For the difference between static and dynamic memories, see the
/// [`Config::static_memory_maximum_size`].
pub fn static_memory_forced(&mut self, force: bool) -> &mut Self {
self.tunables.static_memory_bound_is_maximum = force;
self.tunables.static_memory_bound_is_maximum = Some(force);
self
}
@ -1311,7 +1329,7 @@ impl Config {
/// than the value configured for [`Config::dynamic_memory_guard_size`].
pub fn static_memory_guard_size(&mut self, guard_size: u64) -> &mut Self {
let guard_size = round_up_to_pages(guard_size);
self.tunables.static_memory_offset_guard_size = guard_size;
self.tunables.static_memory_offset_guard_size = Some(guard_size);
self
}
@ -1344,7 +1362,7 @@ impl Config {
/// than the value configured for [`Config::static_memory_guard_size`].
pub fn dynamic_memory_guard_size(&mut self, guard_size: u64) -> &mut Self {
let guard_size = round_up_to_pages(guard_size);
self.tunables.dynamic_memory_offset_guard_size = guard_size;
self.tunables.dynamic_memory_offset_guard_size = Some(guard_size);
self
}
@ -1383,7 +1401,7 @@ impl Config {
/// For 64-bit platforms this defaults to 2GB, and for 32-bit platforms this
/// defaults to 1MB.
pub fn dynamic_memory_reserved_for_growth(&mut self, reserved: u64) -> &mut Self {
self.tunables.dynamic_memory_growth_reserve = round_up_to_pages(reserved);
self.tunables.dynamic_memory_growth_reserve = Some(round_up_to_pages(reserved));
self
}
@ -1408,7 +1426,7 @@ impl Config {
///
/// This value defaults to `true`.
pub fn guard_before_linear_memory(&mut self, guard: bool) -> &mut Self {
self.tunables.guard_before_linear_memory = guard;
self.tunables.guard_before_linear_memory = Some(guard);
self
}
@ -1455,7 +1473,7 @@ impl Config {
/// numbers if so configured as well (and the original wasm module has DWARF
/// debugging information present).
pub fn generate_address_map(&mut self, generate: bool) -> &mut Self {
self.tunables.generate_address_map = generate;
self.tunables.generate_address_map = Some(generate);
self
}
@ -1589,7 +1607,7 @@ impl Config {
self
}
pub(crate) fn validate(&self) -> Result<()> {
pub(crate) fn validate(&self) -> Result<Tunables> {
if self.features.reference_types && !self.features.bulk_memory {
bail!("feature 'reference_types' requires 'bulk_memory' to be enabled");
}
@ -1603,27 +1621,73 @@ impl Config {
if self.max_wasm_stack == 0 {
bail!("max_wasm_stack size cannot be zero");
}
if self.tunables.static_memory_offset_guard_size
< self.tunables.dynamic_memory_offset_guard_size
{
bail!("static memory guard size cannot be smaller than dynamic memory guard size");
}
#[cfg(not(feature = "wmemcheck"))]
if self.wmemcheck {
bail!("wmemcheck (memory checker) was requested but is not enabled in this build");
}
Ok(())
#[cfg(not(any(feature = "cranelift", feature = "winch")))]
let mut tunables = Tunables::default_host();
#[cfg(any(feature = "cranelift", feature = "winch"))]
let mut tunables = match &self.compiler_config.target.as_ref() {
Some(target) => match target.pointer_width() {
Ok(PointerWidth::U32) => Tunables::default_u32(),
Ok(PointerWidth::U64) => Tunables::default_u64(),
_ => bail!("unknown pointer width"),
},
None => Tunables::default_host(),
};
macro_rules! set_fields {
($($field:ident)*) => (
let ConfigTunables {
$($field,)*
} = &self.tunables;
$(
if let Some(e) = $field {
tunables.$field = *e;
}
)*
)
}
set_fields! {
static_memory_bound
static_memory_offset_guard_size
dynamic_memory_offset_guard_size
dynamic_memory_growth_reserve
generate_native_debuginfo
parse_wasm_debuginfo
consume_fuel
epoch_interruption
static_memory_bound_is_maximum
guard_before_linear_memory
generate_address_map
debug_adapter_modules
relaxed_simd_deterministic
tail_callable
}
if tunables.static_memory_offset_guard_size < tunables.dynamic_memory_offset_guard_size {
bail!("static memory guard size cannot be smaller than dynamic memory guard size");
}
Ok(tunables)
}
#[cfg(feature = "runtime")]
pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator + Send + Sync>> {
pub(crate) fn build_allocator(
&self,
tunables: &Tunables,
) -> Result<Box<dyn InstanceAllocator + Send + Sync>> {
#[cfg(feature = "async")]
let stack_size = self.async_stack_size;
#[cfg(not(feature = "async"))]
let stack_size = 0;
let _ = tunables;
match &self.allocation_strategy {
InstanceAllocationStrategy::OnDemand => {
#[allow(unused_mut)]
@ -1642,8 +1706,7 @@ impl Config {
let mut config = config.config;
config.stack_size = stack_size;
Ok(Box::new(wasmtime_runtime::PoolingInstanceAllocator::new(
&config,
&self.tunables,
&config, tunables,
)?))
}
}
@ -1660,7 +1723,10 @@ impl Config {
}
#[cfg(any(feature = "cranelift", feature = "winch"))]
pub(crate) fn build_compiler(mut self) -> Result<(Self, Box<dyn wasmtime_environ::Compiler>)> {
pub(crate) fn build_compiler(
mut self,
tunables: &Tunables,
) -> Result<(Self, Box<dyn wasmtime_environ::Compiler>)> {
let target = self.compiler_config.target.clone();
let mut compiler = match self.compiler_config.strategy {
@ -1767,7 +1833,7 @@ impl Config {
compiler.enable_incremental_compilation(cache_store.clone())?;
}
compiler.set_tunables(self.tunables.clone())?;
compiler.set_tunables(tunables.clone())?;
compiler.wmemcheck(self.compiler_config.wmemcheck);
Ok((self, compiler.build()?))
@ -1778,7 +1844,7 @@ impl Config {
/// then are necessary.
#[cfg(feature = "component-model")]
pub fn debug_adapter_modules(&mut self, debug: bool) -> &mut Self {
self.tunables.debug_adapter_modules = debug;
self.tunables.debug_adapter_modules = Some(debug);
self
}
@ -1849,7 +1915,6 @@ impl fmt::Debug for Config {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_struct("Config");
f.field("debug_info", &self.tunables.generate_native_debuginfo)
.field("parse_wasm_debuginfo", &self.tunables.parse_wasm_debuginfo)
.field("wasm_threads", &self.features.threads)
.field("wasm_reference_types", &self.features.reference_types)
.field(
@ -1860,28 +1925,30 @@ impl fmt::Debug for Config {
.field("wasm_simd", &self.features.simd)
.field("wasm_relaxed_simd", &self.features.relaxed_simd)
.field("wasm_multi_value", &self.features.multi_value)
.field(
"static_memory_maximum_size",
&(u64::from(self.tunables.static_memory_bound)
* u64::from(wasmtime_environ::WASM_PAGE_SIZE)),
)
.field(
"static_memory_guard_size",
&self.tunables.static_memory_offset_guard_size,
)
.field(
"dynamic_memory_guard_size",
&self.tunables.dynamic_memory_offset_guard_size,
)
.field(
"guard_before_linear_memory",
&self.tunables.guard_before_linear_memory,
)
.field("parallel_compilation", &self.parallel_compilation);
#[cfg(any(feature = "cranelift", feature = "winch"))]
{
f.field("compiler_config", &self.compiler_config);
}
if let Some(enable) = self.tunables.parse_wasm_debuginfo {
f.field("parse_wasm_debuginfo", &enable);
}
if let Some(size) = self.tunables.static_memory_bound {
f.field(
"static_memory_maximum_size",
&(u64::from(size) * u64::from(wasmtime_environ::WASM_PAGE_SIZE)),
);
}
if let Some(size) = self.tunables.static_memory_offset_guard_size {
f.field("static_memory_guard_size", &size);
}
if let Some(size) = self.tunables.dynamic_memory_offset_guard_size {
f.field("dynamic_memory_guard_size", &size);
}
if let Some(enable) = self.tunables.guard_before_linear_memory {
f.field("guard_before_linear_memory", &enable);
}
f.finish()
}
}

34
crates/wasmtime/src/engine.rs

@ -9,7 +9,7 @@ use std::path::Path;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use wasmtime_environ::obj;
use wasmtime_environ::{FlagValue, ObjectKind};
use wasmtime_environ::{FlagValue, ObjectKind, Tunables};
mod serialization;
@ -37,27 +37,28 @@ mod serialization;
/// default settings.
#[derive(Clone)]
pub struct Engine {
pub(crate) inner: Arc<EngineInner>,
inner: Arc<EngineInner>,
}
pub(crate) struct EngineInner {
pub(crate) config: Config,
struct EngineInner {
config: Config,
tunables: Tunables,
#[cfg(any(feature = "cranelift", feature = "winch"))]
pub(crate) compiler: Box<dyn wasmtime_environ::Compiler>,
compiler: Box<dyn wasmtime_environ::Compiler>,
#[cfg(feature = "runtime")]
pub(crate) allocator: Box<dyn wasmtime_runtime::InstanceAllocator + Send + Sync>,
allocator: Box<dyn wasmtime_runtime::InstanceAllocator + Send + Sync>,
#[cfg(feature = "runtime")]
pub(crate) profiler: Box<dyn crate::profiling_agent::ProfilingAgent>,
profiler: Box<dyn crate::profiling_agent::ProfilingAgent>,
#[cfg(feature = "runtime")]
pub(crate) signatures: TypeRegistry,
signatures: TypeRegistry,
#[cfg(feature = "runtime")]
pub(crate) epoch: AtomicU64,
epoch: AtomicU64,
#[cfg(feature = "runtime")]
pub(crate) unique_id_allocator: wasmtime_runtime::CompiledModuleIdAllocator,
unique_id_allocator: wasmtime_runtime::CompiledModuleIdAllocator,
/// One-time check of whether the compiler's settings, if present, are
/// compatible with the native host.
pub(crate) compatible_with_native_host: OnceCell<Result<(), String>>,
compatible_with_native_host: OnceCell<Result<(), String>>,
}
impl Default for Engine {
@ -94,17 +95,17 @@ impl Engine {
}
let config = config.clone();
config.validate()?;
let tunables = config.validate()?;
#[cfg(any(feature = "cranelift", feature = "winch"))]
let (config, compiler) = config.build_compiler()?;
let (config, compiler) = config.build_compiler(&tunables)?;
Ok(Engine {
inner: Arc::new(EngineInner {
#[cfg(any(feature = "cranelift", feature = "winch"))]
compiler,
#[cfg(feature = "runtime")]
allocator: config.build_allocator()?,
allocator: config.build_allocator(&tunables)?,
#[cfg(feature = "runtime")]
profiler: config.build_profiler()?,
#[cfg(feature = "runtime")]
@ -115,6 +116,7 @@ impl Engine {
unique_id_allocator: wasmtime_runtime::CompiledModuleIdAllocator::new(),
compatible_with_native_host: OnceCell::new(),
config,
tunables,
}),
})
}
@ -161,6 +163,10 @@ impl Engine {
}
}
pub(crate) fn tunables(&self) -> &Tunables {
&self.inner.tunables
}
/// Returns whether the engine `a` and `b` refer to the same configuration.
pub fn same(a: &Engine, b: &Engine) -> bool {
Arc::ptr_eq(&a.inner, &b.inner)

4
crates/wasmtime/src/engine/serialization.rs

@ -231,7 +231,7 @@ impl Metadata<'_> {
target: engine.compiler().triple().to_string(),
shared_flags: engine.compiler().flags(),
isa_flags: engine.compiler().isa_flags(),
tunables: engine.config().tunables.clone(),
tunables: engine.tunables().clone(),
features: WasmFeatures {
reference_types,
multi_value,
@ -254,7 +254,7 @@ impl Metadata<'_> {
self.check_triple(engine)?;
self.check_shared_flags(engine)?;
self.check_isa_flags(engine)?;
self.check_tunables(&engine.config().tunables)?;
self.check_tunables(&engine.tunables())?;
self.check_features(&engine.config().features)?;
Ok(())
}

2
crates/wasmtime/src/runtime/memory.rs

@ -732,7 +732,7 @@ impl SharedMemory {
}
debug_assert!(ty.maximum().is_some());
let tunables = &engine.config().tunables;
let tunables = engine.tunables();
let plan = MemoryPlan::for_memory(ty.wasmtime_memory().clone(), tunables);
let memory = wasmtime_runtime::SharedMemory::new(plan)?;
Ok(Self(memory, engine.clone()))

2
crates/wasmtime/src/runtime/module.rs

@ -1105,7 +1105,7 @@ impl std::hash::Hash for HashedEngineCompileEnv<'_> {
// Hash configuration state read for compilation
let config = self.0.config();
config.tunables.hash(hasher);
self.0.tunables().hash(hasher);
config.features.hash(hasher);
config.wmemcheck.hash(hasher);

6
crates/wasmtime/src/runtime/store.rs

@ -1390,7 +1390,7 @@ impl StoreOpaque {
pub fn get_fuel(&self) -> Result<u64> {
anyhow::ensure!(
self.engine().config().tunables.consume_fuel,
self.engine().tunables().consume_fuel,
"fuel is not configured in this store"
);
let injected_fuel = unsafe { *self.runtime_limits.fuel_consumed.get() };
@ -1408,7 +1408,7 @@ impl StoreOpaque {
pub fn set_fuel(&mut self, fuel: u64) -> Result<()> {
anyhow::ensure!(
self.engine().config().tunables.consume_fuel,
self.engine().tunables().consume_fuel,
"fuel is not configured in this store"
);
let injected_fuel = unsafe { &mut *self.runtime_limits.fuel_consumed.get() };
@ -1423,7 +1423,7 @@ impl StoreOpaque {
pub fn fuel_async_yield_interval(&mut self, interval: Option<u64>) -> Result<()> {
anyhow::ensure!(
self.engine().config().tunables.consume_fuel,
self.engine().tunables().consume_fuel,
"fuel is not configured in this store"
);
anyhow::ensure!(

5
crates/wasmtime/src/runtime/trampoline/func.rs

@ -94,10 +94,7 @@ where
&mut obj,
)?;
engine.append_bti(&mut obj);
let obj = finish_object(wasmtime_environ::ObjectBuilder::new(
obj,
&engine.config().tunables,
))?;
let obj = finish_object(wasmtime_environ::ObjectBuilder::new(obj, engine.tunables()))?;
// Copy the results of JIT compilation into executable memory, and this will
// also take care of unwind table registration.

2
crates/wasmtime/src/runtime/trampoline/memory.rs

@ -40,7 +40,7 @@ pub fn create_memory(
// preallocated (i.e., shared memory) or allocated manually below.
let plan = wasmtime_environ::MemoryPlan::for_memory(
memory_ty.wasmtime_memory().clone(),
&store.engine().config().tunables,
store.engine().tunables(),
);
let memory_id = module.memory_plans.push(plan.clone());

2
crates/wasmtime/src/runtime/trampoline/table.rs

@ -8,7 +8,7 @@ pub fn create_table(store: &mut StoreOpaque, table: &TableType) -> Result<Instan
let mut module = Module::new();
let table_plan = wasmtime_environ::TablePlan::for_table(
table.wasmtime_table().clone(),
&store.engine().config().tunables,
store.engine().tunables(),
);
let table_id = module.table_plans.push(table_plan);
// TODO: can this `exports.insert` get removed?

2
winch/filetests/src/lib.rs

@ -104,7 +104,7 @@ mod test {
let mut validator = Validator::new();
let parser = WasmParser::new(0);
let mut types = Default::default();
let tunables = Tunables::default();
let tunables = Tunables::default_host();
let mut translation = ModuleEnvironment::new(&tunables, &mut validator, &mut types)
.translate(parser, &wasm)
.context("Failed to translate WebAssembly module")

2
winch/src/compile.rs

@ -32,7 +32,7 @@ pub fn run(opt: &Options) -> Result<()> {
let mut validator = Validator::new();
let parser = WasmParser::new(0);
let mut types = Default::default();
let tunables = Tunables::default();
let tunables = Tunables::default_host();
let mut translation = ModuleEnvironment::new(&tunables, &mut validator, &mut types)
.translate(parser, &bytes)
.context("Failed to translate WebAssembly module")?;

Loading…
Cancel
Save