externref: Share more Layout-computing code
This commit is contained in:
@@ -183,6 +183,30 @@ impl Drop for VMExternRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VMExternData {
|
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>) {
|
unsafe fn drop_and_dealloc(mut data: NonNull<VMExternData>) {
|
||||||
// Note: we introduce a block scope so that we drop the live
|
// Note: we introduce a block scope so that we drop the live
|
||||||
// reference to the data before we free the heap allocation it
|
// 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
|
// Same thing, but for the dropping the reference to `value` before
|
||||||
// we drop it itself.
|
// we drop it itself.
|
||||||
let layout = {
|
let (layout, _) = {
|
||||||
let value = data.value_ptr.as_ref();
|
let value = data.value_ptr.as_ref();
|
||||||
|
Self::layout_for(mem::size_of_val(value), mem::align_of_val(value))
|
||||||
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)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ptr::drop_in_place(data.value_ptr.as_ptr());
|
ptr::drop_in_place(data.value_ptr.as_ptr());
|
||||||
@@ -265,25 +275,9 @@ impl VMExternRef {
|
|||||||
where
|
where
|
||||||
T: 'static + Any,
|
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 {
|
unsafe {
|
||||||
debug_assert!(Layout::from_size_align(alloc_size, alloc_align).is_ok());
|
let (layout, footer_offset) =
|
||||||
let layout = Layout::from_size_align_unchecked(alloc_size, alloc_align);
|
VMExternData::layout_for(mem::size_of::<T>(), mem::align_of::<T>());
|
||||||
|
|
||||||
let alloc_ptr = std::alloc::alloc(layout);
|
let alloc_ptr = std::alloc::alloc(layout);
|
||||||
let alloc_ptr = NonNull::new(alloc_ptr).unwrap_or_else(|| {
|
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 value_ptr = NonNull::new_unchecked(value_ptr);
|
||||||
|
|
||||||
let extern_data_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(
|
ptr::write(
|
||||||
extern_data_ptr,
|
extern_data_ptr,
|
||||||
VMExternData {
|
VMExternData {
|
||||||
|
|||||||
Reference in New Issue
Block a user