Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasmtime: Make table lazy-init configurable #8531

Merged
merged 2 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ wasmtime_option_group! {
/// linear memories.
pub guard_before_linear_memory: Option<bool>,

/// Whether to initialize tables lazily, so that instantiation is
/// fast but indirect calls are a little slower. If no, tables are
/// initialized eagerly from any active element segments that apply to
/// them during instantiation. (default: yes)
pub table_lazy_init: Option<bool>,

/// Enable the pooling allocator, in place of the on-demand allocator.
pub pooling_allocator: Option<bool>,

Expand Down Expand Up @@ -544,6 +550,9 @@ impl CommonOptions {
if let Some(enable) = self.opts.guard_before_linear_memory {
config.guard_before_linear_memory(enable);
}
if let Some(enable) = self.opts.table_lazy_init {
config.table_lazy_init(enable);
}

// If fuel has been configured, set the `consume fuel` flag on the config.
if self.wasm.fuel.is_some() {
Expand Down
34 changes: 26 additions & 8 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
table_index: TableIndex,
index: ir::Value,
cold_blocks: bool,
lazy_init: bool,
) -> ir::Value {
let pointer_type = self.pointer_type();
self.ensure_table_exists(builder.func, table_index);
Expand All @@ -833,6 +834,11 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
self.isa.flags().enable_table_access_spectre_mitigation(),
);
let value = builder.ins().load(pointer_type, flags, table_entry_addr, 0);

if !lazy_init {
return value;
}

// Mask off the "initialized bit". See documentation on
// FUNCREF_INIT_BIT in crates/environ/src/ref_bits.rs for more
// details. Note that `FUNCREF_MASK` has type `usize` which may not be
Expand Down Expand Up @@ -1354,11 +1360,14 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
cold_blocks: bool,
) -> WasmResult<Option<(ir::Value, ir::Value)>> {
// Get the funcref pointer from the table.
let table = &self.env.module.table_plans[table_index];
let TableStyle::CallerChecksSignature { lazy_init } = table.style;
let funcref_ptr = self.env.get_or_init_func_ref_table_elem(
self.builder,
table_index,
callee,
cold_blocks,
lazy_init,
);

// If necessary, check the signature.
Expand Down Expand Up @@ -1407,7 +1416,7 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {

// Generate a rustc compile error here if more styles are added in
// the future as the following code is tailored to just this style.
let TableStyle::CallerChecksSignature = table.style;
let TableStyle::CallerChecksSignature { .. } = table.style;

// Test if a type check is necessary for this table. If this table is a
// table of typed functions and that type matches `ty_index`, then
Expand Down Expand Up @@ -1747,9 +1756,14 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m

// Function types.
WasmHeapTopType::Func => match plan.style {
TableStyle::CallerChecksSignature => {
Ok(self.get_or_init_func_ref_table_elem(builder, table_index, index, false))
}
TableStyle::CallerChecksSignature { lazy_init } => Ok(self
.get_or_init_func_ref_table_elem(
builder,
table_index,
index,
false,
lazy_init,
)),
},
}
}
Expand Down Expand Up @@ -1800,7 +1814,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
// Function types.
WasmHeapTopType::Func => {
match plan.style {
TableStyle::CallerChecksSignature => {
TableStyle::CallerChecksSignature { lazy_init } => {
let (elem_addr, flags) = table_data.prepare_table_addr(
builder,
index,
Expand All @@ -1810,9 +1824,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
// Set the "initialized bit". See doc-comment on
// `FUNCREF_INIT_BIT` in
// crates/environ/src/ref_bits.rs for details.
let value_with_init_bit = builder
.ins()
.bor_imm(value, Imm64::from(FUNCREF_INIT_BIT as i64));
let value_with_init_bit = if lazy_init {
builder
.ins()
.bor_imm(value, Imm64::from(FUNCREF_INIT_BIT as i64))
} else {
value
};
builder
.ins()
.store(flags, value_with_init_bit, elem_addr, 0);
Expand Down
12 changes: 9 additions & 3 deletions crates/environ/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,19 @@ pub trait InitMemory {
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub enum TableStyle {
/// Signatures are stored in the table and checked in the caller.
CallerChecksSignature,
CallerChecksSignature {
/// Whether this table is initialized lazily and requires an
/// initialization check on every access.
lazy_init: bool,
},
}

impl TableStyle {
/// Decide on an implementation style for the given `Table`.
pub fn for_table(_table: Table, _tunables: &Tunables) -> Self {
Self::CallerChecksSignature
pub fn for_table(_table: Table, tunables: &Tunables) -> Self {
Self::CallerChecksSignature {
lazy_init: tunables.table_lazy_init,
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions crates/environ/src/tunables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ pub struct Tunables {
/// beginning of the allocation in addition to the end.
pub guard_before_linear_memory: bool,

/// Whether to initialize tables lazily, so that instantiation is fast but
/// indirect calls are a little slower. If false, tables are initialized
/// eagerly from any active element segments that apply to them during
/// instantiation.
pub table_lazy_init: bool,

/// Indicates whether an address map from compiled native code back to wasm
/// offsets in the original file is generated.
pub generate_address_map: bool,
Expand Down Expand Up @@ -113,6 +119,7 @@ impl Tunables {
epoch_interruption: false,
static_memory_bound_is_maximum: false,
guard_before_linear_memory: true,
table_lazy_init: true,
generate_address_map: true,
debug_adapter_modules: false,
relaxed_simd_deterministic: false,
Expand Down
4 changes: 4 additions & 0 deletions crates/fuzzing/src/generators/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ impl Config {
}

cfg.cranelift_pcc(pcc);

// Eager init is currently only supported on Cranelift, not Winch.
cfg.table_lazy_init(self.wasmtime.table_lazy_init);
}

self.wasmtime.async_config.configure(&mut cfg);
Expand Down Expand Up @@ -483,6 +486,7 @@ pub struct WasmtimeConfig {
cache_call_indirects: bool,
/// The maximum number of call-indirect cache slots.
max_call_indirect_cache_slots: usize,
table_lazy_init: bool,

/// Whether or not fuzzing should enable PCC.
pcc: bool,
Expand Down
4 changes: 3 additions & 1 deletion crates/wasmtime/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,9 @@ impl FunctionIndices {
// Attempt to convert table initializer segments to
// FuncTable representation where possible, to enable
// table lazy init.
translation.try_func_table_init();
if engine.tunables().table_lazy_init {
translation.try_func_table_init();
}

let funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo> =
wasm_functions_for_module(&mut wasm_functions, module)
Expand Down
19 changes: 19 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ struct ConfigTunables {
epoch_interruption: Option<bool>,
static_memory_bound_is_maximum: Option<bool>,
guard_before_linear_memory: Option<bool>,
table_lazy_init: Option<bool>,
generate_address_map: Option<bool>,
debug_adapter_modules: Option<bool>,
relaxed_simd_deterministic: Option<bool>,
Expand Down Expand Up @@ -1541,6 +1542,19 @@ impl Config {
self
}

/// Indicates whether to initialize tables lazily, so that instantiation
/// is fast but indirect calls are a little slower. If false, tables
/// are initialized eagerly during instantiation from any active element
/// segments that apply to them.
///
/// ## Default
///
/// This value defaults to `true`.
pub fn table_lazy_init(&mut self, table_lazy_init: bool) -> &mut Self {
self.tunables.table_lazy_init = Some(table_lazy_init);
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.
Expand Down Expand Up @@ -1810,6 +1824,7 @@ impl Config {
epoch_interruption
static_memory_bound_is_maximum
guard_before_linear_memory
table_lazy_init
generate_address_map
debug_adapter_modules
relaxed_simd_deterministic
Expand All @@ -1830,6 +1845,10 @@ impl Config {
if tunables.winch_callable && tunables.tail_callable {
bail!("Winch does not support the WebAssembly tail call proposal");
}

if tunables.winch_callable && !tunables.table_lazy_init {
bail!("Winch requires the table-lazy-init configuration option");
}
}

if tunables.static_memory_offset_guard_size < tunables.dynamic_memory_offset_guard_size {
Expand Down
2 changes: 2 additions & 0 deletions crates/wasmtime/src/engine/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ impl Metadata<'_> {
epoch_interruption,
static_memory_bound_is_maximum,
guard_before_linear_memory,
table_lazy_init,
relaxed_simd_deterministic,
tail_callable,
winch_callable,
Expand Down Expand Up @@ -415,6 +416,7 @@ impl Metadata<'_> {
other.guard_before_linear_memory,
"guard before linear memory",
)?;
Self::check_bool(table_lazy_init, other.table_lazy_init, "table lazy init")?;
Self::check_bool(
relaxed_simd_deterministic,
other.relaxed_simd_deterministic,
Expand Down
Loading