externref: Share more Layout-computing code

This commit is contained in:
Nick Fitzgerald
2020-06-01 13:51:08 -07:00
parent a8ee0554a9
commit 25548d7fbe

View File

@@ -183,6 +183,30 @@ impl Drop for VMExternRef {
}
impl VMExternData {
/// Get the `Layout` for a value with the given size and alignment, and the
/// offset within that layout where the `VMExternData` footer resides.
///
/// This doesn't take a `value: &T` because `VMExternRef::new_with` hasn't
/// constructed a `T` value yet, and it isn't generic over `T` because
/// `VMExternData::drop_and_dealloc` doesn't know what `T` to use, and has
/// to use `std::mem::{size,align}_of_val` instead.
unsafe fn layout_for(value_size: usize, value_align: usize) -> (Layout, usize) {
let extern_data_size = mem::size_of::<VMExternData>();
let extern_data_align = mem::align_of::<VMExternData>();
let value_and_padding_size = round_up_to_align(value_size, extern_data_align).unwrap();
let alloc_align = std::cmp::max(value_align, extern_data_align);
let alloc_size = value_and_padding_size + extern_data_size;
debug_assert!(Layout::from_size_align(alloc_size, alloc_align).is_ok());
(
Layout::from_size_align_unchecked(alloc_size, alloc_align),
value_and_padding_size,
)
}
/// Drop the inner value and then free this `VMExternData` heap allocation.
unsafe fn drop_and_dealloc(mut data: NonNull<VMExternData>) {
// Note: we introduce a block scope so that we drop the live
// reference to the data before we free the heap allocation it
@@ -193,23 +217,9 @@ impl VMExternData {
// Same thing, but for the dropping the reference to `value` before
// we drop it itself.
let layout = {
let (layout, _) = {
let value = data.value_ptr.as_ref();
let value_size = mem::size_of_val(value);
let value_align = mem::align_of_val(value);
let extern_data_size = mem::size_of::<VMExternData>();
let extern_data_align = mem::align_of::<VMExternData>();
let value_and_padding_size = round_up_to_align(value_size, extern_data_align)
.unwrap_or_else(|| unreachable!());
let alloc_align = std::cmp::max(value_align, extern_data_align);
let alloc_size = value_and_padding_size + extern_data_size;
debug_assert!(Layout::from_size_align(alloc_size, alloc_align).is_ok());
Layout::from_size_align_unchecked(alloc_size, alloc_align)
Self::layout_for(mem::size_of_val(value), mem::align_of_val(value))
};
ptr::drop_in_place(data.value_ptr.as_ptr());
@@ -265,25 +275,9 @@ impl VMExternRef {
where
T: 'static + Any,
{
let value_size = mem::size_of::<T>();
let value_align = mem::align_of::<T>();
let extern_data_align = mem::align_of::<VMExternData>();
let extern_data_size = mem::size_of::<VMExternData>();
let value_and_padding_size = round_up_to_align(value_size, extern_data_align)
.unwrap_or_else(|| {
Self::alloc_failure();
});
let alloc_align = std::cmp::max(value_align, extern_data_align);
let alloc_size = value_and_padding_size
.checked_add(extern_data_size)
.unwrap_or_else(|| Self::alloc_failure());
unsafe {
debug_assert!(Layout::from_size_align(alloc_size, alloc_align).is_ok());
let layout = Layout::from_size_align_unchecked(alloc_size, alloc_align);
let (layout, footer_offset) =
VMExternData::layout_for(mem::size_of::<T>(), mem::align_of::<T>());
let alloc_ptr = std::alloc::alloc(layout);
let alloc_ptr = NonNull::new(alloc_ptr).unwrap_or_else(|| {
@@ -300,7 +294,7 @@ impl VMExternRef {
let value_ptr = NonNull::new_unchecked(value_ptr);
let extern_data_ptr =
alloc_ptr.cast::<u8>().as_ptr().add(value_and_padding_size) as *mut VMExternData;
alloc_ptr.cast::<u8>().as_ptr().add(footer_offset) as *mut VMExternData;
ptr::write(
extern_data_ptr,
VMExternData {