From 6a0b3817636819711d7ca411eb9d6bc1b0fe5777 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Nov 2021 09:14:18 +0000 Subject: [PATCH 1/2] Support 32-bit memories with 65536 pages Fixes #2187 --- lib/api/src/sys/externals/memory.rs | 2 +- lib/compiler-llvm/src/trampoline/wasm.rs | 10 ++++++---- lib/compiler-llvm/src/translator/code.rs | 5 +++-- .../src/translator/intrinsics.rs | 19 ++++++++++++++++--- lib/compiler-singlepass/src/codegen_x64.rs | 2 +- lib/vm/src/instance/mod.rs | 6 +++--- lib/vm/src/vmcontext.rs | 16 +++++----------- tests/wast/wasmer/max_size_of_memory.wast | 1 + 8 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 tests/wast/wasmer/max_size_of_memory.wast diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index 4fa3a9ba3cc..2403c212fe5 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -131,7 +131,7 @@ impl Memory { pub fn data_size(&self) -> u64 { let definition = self.vm_memory.from.vmmemory(); let def = unsafe { definition.as_ref() }; - def.current_length.into() + def.current_length.try_into().unwrap() } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index ad5bb7cee54..81557c98fb4 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -48,9 +48,10 @@ impl FuncTrampoline { let module = self.ctx.create_module(""); let target_machine = &self.target_machine; let target_triple = target_machine.get_triple(); + let target_data = target_machine.get_target_data(); module.set_triple(&target_triple); - module.set_data_layout(&target_machine.get_target_data().get_data_layout()); - let intrinsics = Intrinsics::declare(&module, &self.ctx); + module.set_data_layout(&target_data.get_data_layout()); + let intrinsics = Intrinsics::declare(&module, &self.ctx, &target_data); let (callee_ty, callee_attrs) = self.abi @@ -177,10 +178,11 @@ impl FuncTrampoline { let function = CompiledKind::DynamicFunctionTrampoline(ty.clone()); let module = self.ctx.create_module(""); let target_machine = &self.target_machine; + let target_data = target_machine.get_target_data(); let target_triple = target_machine.get_triple(); module.set_triple(&target_triple); - module.set_data_layout(&target_machine.get_target_data().get_data_layout()); - let intrinsics = Intrinsics::declare(&module, &self.ctx); + module.set_data_layout(&target_data.get_data_layout()); + let intrinsics = Intrinsics::declare(&module, &self.ctx, &target_data); let (trampoline_ty, trampoline_attrs) = self.abi diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 38ee001c913..c5cc3dfe64d 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -83,8 +83,9 @@ impl FuncTranslator { let target_machine = &self.target_machine; let target_triple = target_machine.get_triple(); + let target_data = target_machine.get_target_data(); module.set_triple(&target_triple); - module.set_data_layout(&target_machine.get_target_data().get_data_layout()); + module.set_data_layout(&target_data.get_data_layout()); let wasm_fn_type = wasm_module .signatures .get(wasm_module.functions[func_index]) @@ -92,7 +93,7 @@ impl FuncTranslator { // TODO: pointer width let offsets = VMOffsets::new(8, &wasm_module); - let intrinsics = Intrinsics::declare(&module, &self.ctx); + let intrinsics = Intrinsics::declare(&module, &self.ctx, &target_data); let (func_type, func_attrs) = self.abi .func_type_to_llvm(&self.ctx, &intrinsics, Some(&offsets), wasm_fn_type)?; diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 7a827fdcacc..48f176f45a6 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -11,6 +11,7 @@ use inkwell::{ builder::Builder, context::Context, module::{Linkage, Module}, + targets::TargetData, types::{ BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, PointerType, StructType, VectorType, VoidType, @@ -168,6 +169,7 @@ pub struct Intrinsics<'ctx> { pub i32_ty: IntType<'ctx>, pub i64_ty: IntType<'ctx>, pub i128_ty: IntType<'ctx>, + pub isize_ty: IntType<'ctx>, pub f32_ty: FloatType<'ctx>, pub f64_ty: FloatType<'ctx>, @@ -185,6 +187,7 @@ pub struct Intrinsics<'ctx> { pub i32_ptr_ty: PointerType<'ctx>, pub i64_ptr_ty: PointerType<'ctx>, pub i128_ptr_ty: PointerType<'ctx>, + pub isize_ptr_ty: PointerType<'ctx>, pub f32_ptr_ty: PointerType<'ctx>, pub f64_ptr_ty: PointerType<'ctx>, @@ -199,6 +202,7 @@ pub struct Intrinsics<'ctx> { pub i32_zero: IntValue<'ctx>, pub i64_zero: IntValue<'ctx>, pub i128_zero: IntValue<'ctx>, + pub isize_zero: IntValue<'ctx>, pub f32_zero: FloatValue<'ctx>, pub f64_zero: FloatValue<'ctx>, pub f32x4_zero: VectorValue<'ctx>, @@ -260,7 +264,11 @@ pub struct Intrinsics<'ctx> { impl<'ctx> Intrinsics<'ctx> { /// Create an [`Intrinsics`] for the given [`Context`]. - pub fn declare(module: &Module<'ctx>, context: &'ctx Context) -> Self { + pub fn declare( + module: &Module<'ctx>, + context: &'ctx Context, + target_data: &TargetData, + ) -> Self { let void_ty = context.void_type(); let i1_ty = context.bool_type(); let i2_ty = context.custom_width_int_type(2); @@ -270,6 +278,7 @@ impl<'ctx> Intrinsics<'ctx> { let i32_ty = context.i32_type(); let i64_ty = context.i64_type(); let i128_ty = context.i128_type(); + let isize_ty = context.ptr_sized_int_type(target_data, None); let f32_ty = context.f32_type(); let f64_ty = context.f64_type(); @@ -289,6 +298,7 @@ impl<'ctx> Intrinsics<'ctx> { let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic); let i64_ptr_ty = i64_ty.ptr_type(AddressSpace::Generic); let i128_ptr_ty = i128_ty.ptr_type(AddressSpace::Generic); + let isize_ptr_ty = isize_ty.ptr_type(AddressSpace::Generic); let f32_ptr_ty = f32_ty.ptr_type(AddressSpace::Generic); let f64_ptr_ty = f64_ty.ptr_type(AddressSpace::Generic); @@ -297,6 +307,7 @@ impl<'ctx> Intrinsics<'ctx> { let i32_zero = i32_ty.const_int(0, false); let i64_zero = i64_ty.const_int(0, false); let i128_zero = i128_ty.const_int(0, false); + let isize_zero = isize_ty.const_int(0, false); let f32_zero = f32_ty.const_float(0.0); let f64_zero = f64_ty.const_float(0.0); let f32x4_zero = f32x4_ty.const_zero(); @@ -703,6 +714,7 @@ impl<'ctx> Intrinsics<'ctx> { i32_ty, i64_ty, i128_ty, + isize_ty, f32_ty, f64_ty, @@ -720,6 +732,7 @@ impl<'ctx> Intrinsics<'ctx> { i32_ptr_ty, i64_ptr_ty, i128_ptr_ty, + isize_ptr_ty, f32_ptr_ty, f64_ptr_ty, @@ -734,6 +747,7 @@ impl<'ctx> Intrinsics<'ctx> { i32_zero, i64_zero, i128_zero, + isize_zero, f32_zero, f64_zero, f32x4_zero, @@ -1001,9 +1015,8 @@ impl<'ctx> Intrinsics<'ctx> { vmfunction_import_body_element: 0, vmfunction_import_vmctx_element: 1, - // TODO: this i64 is actually a rust usize vmmemory_definition_ptr_ty: context - .struct_type(&[i8_ptr_ty_basic, i32_ty.into()], false) + .struct_type(&[i8_ptr_ty_basic, isize_ty.into()], false) .ptr_type(AddressSpace::Generic), vmmemory_definition_base_element: 0, vmmemory_definition_current_length_element: 1, diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index 66f1f96ea05..beaefaaf389 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -1290,7 +1290,7 @@ impl<'a> FuncGen<'a> { // Load bound into temporary register, if needed. if need_check { self.assembler - .emit_mov(Size::S32, bound_loc, Location::GPR(tmp_bound)); + .emit_mov(Size::S64, bound_loc, Location::GPR(tmp_bound)); // Wasm -> Effective. // Assuming we never underflow - should always be true on Linux/macOS and Windows >=8, diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index ac827ee4d97..19da2289df4 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -813,9 +813,9 @@ impl Instance { if src .checked_add(len) .map_or(true, |n| n as usize > data.len()) - || dst - .checked_add(len) - .map_or(true, |m| m > memory.current_length) + || dst.checked_add(len).map_or(true, |m| { + usize::try_from(m).unwrap() > memory.current_length + }) { return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index e969df11218..eae9d02d614 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -345,7 +345,7 @@ pub struct VMMemoryDefinition { pub base: *mut u8, /// The current logical size of this linear memory in bytes. - pub current_length: u32, + pub current_length: usize, } /// # Safety @@ -362,7 +362,7 @@ unsafe impl Sync for VMMemoryDefinition {} impl MemoryUsage for VMMemoryDefinition { fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize { if tracker.track(self.base as *const _ as *const ()) { - POINTER_BYTE_SIZE * (self.current_length as usize) + POINTER_BYTE_SIZE * self.current_length } else { 0 } @@ -384,10 +384,10 @@ impl VMMemoryDefinition { // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy if src .checked_add(len) - .map_or(true, |n| n > self.current_length) + .map_or(true, |n| usize::try_from(n).unwrap() > self.current_length) || dst .checked_add(len) - .map_or(true, |m| m > self.current_length) + .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) { return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } @@ -417,7 +417,7 @@ impl VMMemoryDefinition { pub(crate) unsafe fn memory_fill(&self, dst: u32, val: u32, len: u32) -> Result<(), Trap> { if dst .checked_add(len) - .map_or(true, |m| m > self.current_length) + .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) { return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } @@ -458,12 +458,6 @@ mod test_vmmemory_definition { offset_of!(VMMemoryDefinition, current_length), usize::from(offsets.vmmemory_definition_current_length()) ); - /* TODO: Assert that the size of `current_length` matches. - assert_eq!( - size_of::(), - usize::from(offsets.size_of_vmmemory_definition_current_length()) - ); - */ } } diff --git a/tests/wast/wasmer/max_size_of_memory.wast b/tests/wast/wasmer/max_size_of_memory.wast new file mode 100644 index 00000000000..99116d1e729 --- /dev/null +++ b/tests/wast/wasmer/max_size_of_memory.wast @@ -0,0 +1 @@ +(module (memory 65536)) From dd16575c47b0ed4517626302e9de7e1089708116 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Nov 2021 15:45:14 +0000 Subject: [PATCH 2/2] Ignore test on Windows --- tests/ignores.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ignores.txt b/tests/ignores.txt index 7669d0ea026..4661fe0493b 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -69,6 +69,9 @@ cranelift spec::simd::simd_i64x2_extmul_i32x4 cranelift spec::simd::simd_i8x16_arith2 cranelift spec::simd::simd_int_to_int_extend +# Windows doesn't overcommit and fails to allocate 4GB of memory +windows wast::wasmer::max_size_of_memory + # Frontends ## WASI