wasm-core 0.2.15

Portable WebAssembly implementation
Documentation
use std::ptr::null_mut;
use std::cell::{Cell, RefCell};
use super::generic::*;

pub struct NativeMemoryManager {
    min: usize,
    max: usize,
    mem: Vec<u8>,
    mem_start: *mut u8,
    mem_len: usize
}

impl NativeMemoryManager {
    pub fn new(opts: MemInitOptions) -> NativeMemoryManager {
        let mut mem: Vec<u8> = vec! [ 0; opts.min ];
        let mem_start = &mut mem[0] as *mut u8;

        NativeMemoryManager {
            min: opts.min,
            max: opts.max,
            mem: mem,
            mem_start: mem_start,
            mem_len: opts.min
        }
    }

    pub fn protected_call<T, F: FnOnce(&mut Self) -> T>(&mut self, f: F) -> T {
        f(self)
    }
}

unsafe impl MemoryManager for NativeMemoryManager {
    fn grow(&mut self, len_inc: usize) {
        if self.mem.len().checked_add(len_inc).unwrap() > self.max {
            panic!("Memory limit exceeded");
        }
        self.mem.extend((0..len_inc).map(|_| 0));

        let mem_start = &mut self.mem[0] as *mut u8;
        self.mem_start = mem_start;
        self.mem_len = self.mem.len();
    }

    fn len(&self) -> usize {
        self.mem_len
    }

    fn get_ref(&self) -> &[u8] {
        &self.mem
    }

    fn get_ref_mut(&mut self) -> &mut [u8] {
        &mut self.mem
    }

    fn hints(&self) -> MemCodegenHints {
        MemCodegenHints {
            needs_bounds_check: true,
            address_mask: self.max.next_power_of_two() - 1,
            indirect_len_ptr: &self.mem_len,
            indirect_start_address_ptr: &self.mem_start,
            static_start_address: None
        }
    }

    fn start_address(&self) -> *mut u8 {
        self.mem_start
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_native_mm() {
        use std::panic::{catch_unwind, AssertUnwindSafe};

        let mut mm = NativeMemoryManager::new(MemInitOptions {
            min: 100000,
            max: 3221225472
        });

        let err = catch_unwind(AssertUnwindSafe(|| {
            let mem = mm.get_ref_mut();

            mem[0] = 1;
            mem[100] = 2;
            mem[99999] = 3;
        }));
        assert!(err.is_ok());

        let err = catch_unwind(AssertUnwindSafe(|| {
            let mem = mm.get_ref_mut();
            mem[100000] = 3;
        }));
        assert!(err.is_err());
    }

    #[test]
    fn test_native_mm_concurrent() {
        use std::panic::{catch_unwind, AssertUnwindSafe};

        let mut handles = Vec::new();

        for _ in 0..10000 {
            handles.push(::std::thread::spawn(|| {
                let mut mm = NativeMemoryManager::new(MemInitOptions {
                    min: 100000,
                    max: 3221225472
                });
                let err = catch_unwind(AssertUnwindSafe(|| {
                    let mem = mm.get_ref_mut();
                    mem[100000] = 42;
                }));
                assert!(err.is_err());
            }));
        }

        for h in handles {
            h.join().unwrap();
        }
    }
}