Purpose of 'BoxSlice'?

Link: wasmtime/module.rs at main · bytecodealliance/wasmtime · GitHub

Code:

struct BoxSlice<T> {
    len: usize,
    ptr: *mut T,
}

impl<T> From<Box<[T]>> for BoxSlice<T> {
    fn from(mut other: Box<[T]>) -> Self {
        let out = BoxSlice {
            len: other.len(),
            ptr: other.as_mut_ptr(),
        };
        mem::forget(other);
        out
    }
}

unsafe impl<T: Send> Send for BoxSlice<T> {}
unsafe impl<T: Sync> Sync for BoxSlice<T> {}

impl<T> Drop for BoxSlice<T> {
    fn drop(&mut self) {
        unsafe { Vec::from_raw_parts(self.ptr, self.len, self.len) };
    }
}

Context: Lightbeam is a wasm -> dynasm/x86_64 JIT.

Question: what is the purpose of BoxSlice ? compared to a plain [T] ?

seems like they need acccess to the internal repr of Box<[T]>, to get relative offsets to two parts of the wide pointer.

3 Likes

Do we guarantee that Vec uses the global allocation functions and has a stable, known heap layout the way we do for Box? I see they're into_rawing the Box but from_rawing a Vec; I'd expect Box::from_raw(ptr::slice_from_raw_parts(_, _)) instead.

(I can complain about mem::forgetting the value technically potentially invalidating the derived pointer since it moves the Box and needing to use ManuallyDrop or Box::into_raw instead, but that's more draconian than I think we'll want to actually settle on, given e.g. StableDeref and wanting to allow that.)

3 Likes

Yes, the Vec docs guarantee:

If a Vec has allocated memory, then the memory it points to is on the heap (as defined by the allocator Rust is configured to use by default), and its pointer points to len initialized, contiguous elements in order (what you would see if you coerced it to a slice), followed by capacity - len logically uninitialized, contiguous elements.

1 Like