Skip to content

Commit

Permalink
Merge pull request #3178 from wasmerio/feat_enhanced_tinytunable_test
Browse files Browse the repository at this point in the history
Feat enhanced tinytunable test
  • Loading branch information
syrusakbary authored Oct 10, 2022
2 parents 19e7e7a + 742d8a4 commit 06300d3
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 45 deletions.
106 changes: 87 additions & 19 deletions lib/api/src/sys/tunables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,38 +178,48 @@ mod tests {
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use wasmer_types::{MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE};
use wasmer_vm::{LinearMemory, MaybeInstanceOwned};
use wasmer_vm::LinearMemory;

#[derive(Debug)]
struct VMTinyMemory {
mem: [u8; WASM_PAGE_SIZE],
mem: Vec<u8>,
memory_definition: Option<UnsafeCell<VMMemoryDefinition>>,
}

unsafe impl Send for VMTinyMemory {}
unsafe impl Sync for VMTinyMemory {}

impl VMTinyMemory {
pub fn new() -> Result<Self, MemoryError> {
Ok(VMTinyMemory {
mem: [0; WASM_PAGE_SIZE],
})
let sz = 18 * WASM_PAGE_SIZE;
let mut memory = Vec::new();
memory.resize(sz, 0);
let mut ret = VMTinyMemory {
mem: memory,
memory_definition: None,
};
ret.memory_definition = Some(UnsafeCell::new(VMMemoryDefinition {
base: ret.mem.as_ptr() as _,
current_length: sz,
}));
Ok(ret)
}
}

impl LinearMemory for VMTinyMemory {
fn ty(&self) -> MemoryType {
MemoryType {
minimum: Pages::from(1u32),
maximum: Some(Pages::from(1u32)),
minimum: Pages::from(18u32),
maximum: Some(Pages::from(18u32)),
shared: false,
}
}
fn size(&self) -> Pages {
Pages::from(1u32)
Pages::from(18u32)
}
fn style(&self) -> MemoryStyle {
MemoryStyle::Static {
bound: Pages::from(1u32),
bound: Pages::from(18u32),
offset_guard_size: 0,
}
}
Expand All @@ -220,15 +230,28 @@ mod tests {
})
}
fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
base: self.mem.as_ptr() as _,
current_length: WASM_PAGE_SIZE,
})))
.as_ptr()
unsafe {
NonNull::new(
self.memory_definition
.as_ref()
.unwrap()
.get()
.as_mut()
.unwrap() as _,
)
.unwrap()
}
}
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
None
}
/*
// this code allow custom memory to be ignoring init_memory
use wasmer_vm::Trap;
unsafe fn initialize_with_data(&self, _start: usize, _data: &[u8]) -> Result<(), Trap> {
Ok(())
}
*/
}

impl From<VMTinyMemory> for wasmer_vm::VMMemory {
Expand All @@ -241,7 +264,7 @@ mod tests {
impl Tunables for TinyTunables {
fn memory_style(&self, _memory: &MemoryType) -> MemoryStyle {
MemoryStyle::Static {
bound: Pages::from(1u32),
bound: Pages::from(18u32),
offset_guard_size: 0,
}
}
Expand All @@ -262,9 +285,16 @@ mod tests {
&self,
_ty: &MemoryType,
_style: &MemoryStyle,
_vm_definition_location: NonNull<VMMemoryDefinition>,
vm_definition_location: NonNull<VMMemoryDefinition>,
) -> Result<VMMemory, MemoryError> {
let memory = VMTinyMemory::new().unwrap();
// now, it's important to update vm_definition_location with the memory information!
let mut ptr = vm_definition_location;
let md = ptr.as_mut();
let unsafecell = memory.memory_definition.as_ref().unwrap();
let def = unsafecell.get().as_ref().unwrap();
md.base = def.base;
md.current_length = def.current_length;
Ok(memory.into())
}

Expand Down Expand Up @@ -293,13 +323,13 @@ mod tests {
let vmmemory = tunables.create_host_memory(
&MemoryType::new(1u32, Some(100u32), true),
&MemoryStyle::Static {
bound: Pages::from(1u32),
bound: Pages::from(18u32),
offset_guard_size: 0u64,
},
);
let mut vmmemory = vmmemory.unwrap();
assert!(vmmemory.grow(Pages::from(2u32)).is_err());
assert_eq!(vmmemory.size(), Pages::from(1u32));
assert!(vmmemory.grow(Pages::from(50u32)).is_err());
assert_eq!(vmmemory.size(), Pages::from(18u32));
assert_eq!(
vmmemory.grow(Pages::from(0u32)).err().unwrap(),
MemoryError::CouldNotGrow {
Expand All @@ -308,4 +338,42 @@ mod tests {
}
);
}

#[test]
fn check_customtunables() -> Result<(), Box<dyn std::error::Error>> {
use crate::{imports, wat2wasm, Instance, Memory, Module, Store};
use wasmer_compiler_cranelift::Cranelift;

let wasm_bytes = wat2wasm(
br#"(module
(memory (;0;) 18)
(global (;0;) (mut i32) i32.const 1048576)
(export "memory" (memory 0))
(data (;0;) (i32.const 1048576) "*\00\00\00")
)"#,
)?;
let compiler = Cranelift::default();

let tunables = TinyTunables {};
let mut store = Store::new_with_tunables(compiler, tunables);
//let mut store = Store::new(compiler);
let module = Module::new(&store, wasm_bytes)?;
let import_object = imports! {};
let instance = Instance::new(&mut store, &module, &import_object)?;

let mut memories: Vec<Memory> = instance
.exports
.iter()
.memories()
.map(|pair| pair.1.clone())
.collect();
assert_eq!(memories.len(), 1);
let first_memory = memories.pop().unwrap();
assert_eq!(first_memory.ty(&store).maximum.unwrap(), Pages(18));
let view = first_memory.view(&store);
let x = unsafe { view.data_unchecked_mut() }[0];
assert_eq!(x, 0);

Ok(())
}
}
57 changes: 32 additions & 25 deletions lib/vm/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ impl Instance {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
}

#[allow(dead_code)]
/// Get a locally defined or imported memory.
fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition {
if let Some(local_index) = self.module.local_memory_index(index) {
Expand Down Expand Up @@ -240,6 +241,21 @@ impl Instance {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
}

/// Get a locally defined or imported memory.
fn get_vmmemory(&self, index: MemoryIndex) -> &VMMemory {
if let Some(local_index) = self.module.local_memory_index(index) {
unsafe {
self.memories
.get(local_index)
.unwrap()
.get(self.context.as_ref().unwrap())
}
} else {
let import = self.imported_memory(index);
unsafe { import.handle.get(self.context.as_ref().unwrap()) }
}
}

/// Return the indexed `VMGlobalDefinition`.
fn global(&self, index: LocalGlobalIndex) -> VMGlobalDefinition {
unsafe { self.global_ptr(index).as_ref().clone() }
Expand Down Expand Up @@ -701,29 +717,22 @@ impl Instance {
) -> Result<(), Trap> {
// https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init

let memory = self.get_memory(memory_index);
let memory = self.get_vmmemory(memory_index);
let passive_data = self.passive_data.borrow();
let data = passive_data.get(&data_index).map_or(&[][..], |d| &**d);

let current_length = unsafe { memory.vmmemory().as_ref().current_length };
if src
.checked_add(len)
.map_or(true, |n| n as usize > data.len())
|| dst.checked_add(len).map_or(true, |m| {
usize::try_from(m).unwrap() > memory.current_length
})
|| dst
.checked_add(len)
.map_or(true, |m| usize::try_from(m).unwrap() > current_length)
{
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
}

let src_slice = &data[src as usize..(src + len) as usize];

unsafe {
let dst_start = memory.base.add(dst as usize);
let dst_slice = slice::from_raw_parts_mut(dst_start, len as usize);
dst_slice.copy_from_slice(src_slice);
}

Ok(())
unsafe { memory.initialize_with_data(dst as usize, src_slice) }
}

/// Drop the given data segment, truncating its length to zero.
Expand Down Expand Up @@ -1147,6 +1156,7 @@ fn get_memory_init_start(init: &DataInitializer<'_>, instance: &Instance) -> usi
}

#[allow(clippy::mut_from_ref)]
#[allow(dead_code)]
/// Return a byte-slice view of a memory's data.
unsafe fn get_memory_slice<'instance>(
init: &DataInitializer<'_>,
Expand Down Expand Up @@ -1242,21 +1252,18 @@ fn initialize_memories(
data_initializers: &[DataInitializer<'_>],
) -> Result<(), Trap> {
for init in data_initializers {
let memory = instance.get_memory(init.location.memory_index);
let memory = instance.get_vmmemory(init.location.memory_index);

let start = get_memory_init_start(init, instance);
if start
.checked_add(init.data.len())
.map_or(true, |end| end > memory.current_length)
{
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
}

unsafe {
let mem_slice = get_memory_slice(init, instance);
let end = start + init.data.len();
let to_init = &mut mem_slice[start..end];
to_init.copy_from_slice(init.data);
let current_length = memory.vmmemory().as_ref().current_length;
if start
.checked_add(init.data.len())
.map_or(true, |end| end > current_length)
{
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
}
memory.initialize_with_data(start, init.data)?;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub use crate::function_env::VMFunctionEnvironment;
pub use crate::global::*;
pub use crate::imports::Imports;
pub use crate::instance::{InstanceAllocator, InstanceHandle};
pub use crate::memory::{LinearMemory, VMMemory};
pub use crate::memory::{initialize_memory_with_data, LinearMemory, VMMemory};
pub use crate::mmap::Mmap;
pub use crate::probestack::PROBESTACK;
pub use crate::sig_registry::SignatureRegistry;
Expand Down
32 changes: 32 additions & 0 deletions lib/vm/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
//!
//! `Memory` is to WebAssembly linear memories what `Table` is to WebAssembly tables.
use crate::trap::Trap;
use crate::{mmap::Mmap, store::MaybeInstanceOwned, vmcontext::VMMemoryDefinition};
use more_asserts::assert_ge;
use std::cell::UnsafeCell;
use std::convert::TryInto;
use std::ptr::NonNull;
use std::slice;
use wasmer_types::{Bytes, MemoryError, MemoryStyle, MemoryType, Pages};

// The memory mapped area
Expand Down Expand Up @@ -342,6 +344,11 @@ impl LinearMemory for VMMemory {
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
self.0.try_clone()
}

/// Initialize memory with data
unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
self.0.initialize_with_data(start, data)
}
}

impl VMMemory {
Expand Down Expand Up @@ -385,6 +392,21 @@ impl VMMemory {
}
}

#[doc(hidden)]
/// Default implementation to initialize memory with data
pub unsafe fn initialize_memory_with_data(
memory: &VMMemoryDefinition,
start: usize,
data: &[u8],
) -> Result<(), Trap> {
let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
let end = start + data.len();
let to_init = &mut mem_slice[start..end];
to_init.copy_from_slice(data);

Ok(())
}

/// Represents memory that is used by the WebAsssembly module
pub trait LinearMemory
where
Expand All @@ -410,4 +432,14 @@ where

/// Attempts to clone this memory (if its clonable)
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>>;

#[doc(hidden)]
/// # Safety
/// This function is unsafe because WebAssembly specification requires that data is always set at initialization time.
/// It should be the implementors responsibility to make sure this respects the spec
unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
let memory = self.vmmemory().as_ref();

initialize_memory_with_data(memory, start, data)
}
}

0 comments on commit 06300d3

Please sign in to comment.