diff --git a/crates/cranelift/src/alias_region.rs b/crates/cranelift/src/alias_region.rs index 873f34b7a21b..04ceea02d730 100644 --- a/crates/cranelift/src/alias_region.rs +++ b/crates/cranelift/src/alias_region.rs @@ -808,23 +808,6 @@ where ) } - fn vmctx_store( - &mut self, - cursor: &mut FuncCursor<'_>, - base_flags: ir::MemFlagsData, - vmctx: ir::Value, - offset: u32, - val: ir::Value, - ) { - let region = self.vmctx_region(cursor.func, offset); - cursor.ins().store( - base_flags.with_alias_region(Some(region)), - val, - vmctx, - i32::try_from(offset).unwrap(), - ); - } - /// Load the `VMContext::magic` field. pub fn vmctx_magic(&mut self, cursor: &mut FuncCursor<'_>, vmctx: ir::Value) -> ir::Value { self.vmctx_load( @@ -1244,6 +1227,12 @@ impl AliasRegions> { } } + // The runtime data arrays get one alias region each, keyed by the array's + // start, rather than one region per element: module startup initializes + // every data segment in one function, and a region per element gives a + // module with more than ~32k data segments more distinct `MemFlags` than + // a function can hold (`MemFlagsSetOverflow`). + /// Load the base of the given runtime data out of the `*mut VMContext`. pub fn vmctx_runtime_data_base( &mut self, @@ -1251,12 +1240,13 @@ impl AliasRegions> { vmctx: ir::Value, runtime_data: RuntimeDataIndex, ) -> ir::Value { - self.vmctx_load( - cursor, + let region = self.vmctx_region(cursor.func, self.offsets.vmctx_runtime_data_bases_begin()); + let offset = self.offsets.vmctx_runtime_data_base(runtime_data); + cursor.ins().load( self.pointer_type, - ir::MemFlagsData::trusted(), + ir::MemFlagsData::trusted().with_alias_region(Some(region)), vmctx, - self.offsets.vmctx_runtime_data_base(runtime_data), + i32::try_from(offset).unwrap(), ) } @@ -1267,12 +1257,14 @@ impl AliasRegions> { vmctx: ir::Value, runtime_data: RuntimeDataIndex, ) -> ir::Value { - self.vmctx_load( - cursor, + let region = + self.vmctx_region(cursor.func, self.offsets.vmctx_runtime_data_lengths_begin()); + let offset = self.offsets.vmctx_runtime_data_length(runtime_data); + cursor.ins().load( ir::types::I32, - ir::MemFlagsData::trusted(), + ir::MemFlagsData::trusted().with_alias_region(Some(region)), vmctx, - self.offsets.vmctx_runtime_data_length(runtime_data), + i32::try_from(offset).unwrap(), ) } @@ -1284,13 +1276,15 @@ impl AliasRegions> { runtime_data: RuntimeDataIndex, new_length: ir::Value, ) { - self.vmctx_store( - cursor, - ir::MemFlagsData::trusted(), - vmctx, - self.offsets.vmctx_runtime_data_length(runtime_data), + let region = + self.vmctx_region(cursor.func, self.offsets.vmctx_runtime_data_lengths_begin()); + let offset = self.offsets.vmctx_runtime_data_length(runtime_data); + cursor.ins().store( + ir::MemFlagsData::trusted().with_alias_region(Some(region)), new_length, - ) + vmctx, + i32::try_from(offset).unwrap(), + ); } } diff --git a/tests/all/module.rs b/tests/all/module.rs index 6a4daff1a78b..b0d937a9fad1 100644 --- a/tests/all/module.rs +++ b/tests/all/module.rs @@ -265,6 +265,27 @@ fn large_add_chain_no_stack_overflow() -> Result<()> { Ok(()) } +#[test] +#[cfg_attr(miri, ignore)] +fn many_data_segments_without_cow() -> Result<()> { + // Without CoW initialization every data segment is initialized by the + // module startup function, which once gave each segment's base and + // length its own alias region and overflowed the function's `MemFlags` + // past ~32k segments. + let mut config = Config::new(); + config.memory_init_cow(false); + let engine = Engine::new(&config)?; + let mut wat = String::from("(module (memory 1)\n"); + for i in 0..40_000 { + wat.push_str(&format!("(data (i32.const {}) \"x\")\n", i % 65536)); + } + wat.push_str(")"); + let module = Module::new(&engine, &wat)?; + let mut store = Store::new(&engine, ()); + Instance::new(&mut store, &module, &[])?; + Ok(()) +} + #[test] fn compile_a_component() -> Result<()> { let engine = Engine::default();