9

Rust's trait objects are fat pointers that contain 2 regular pointers: to data and to a vtable. The vtable is a structure containing a destructor function pointer, all trait method pointers and finally the size and alignment of the data.

What are the size and alignment fields for?

I couldn't find much:

  • Blog post A: it's for deallocating memory, but not used today, may be used by some future, more flexible mechanisms (What could it be? Does any exist yet?)
  • Blog post B: it's for deallocating type-erased boxed values, so they know how to release memory (Doesn't Box store location, size and alignment of its allocation? Every size variant of every DST can't get its own version of a vtable, can it?)
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
CodeSandwich
  • 1,601
  • 13
  • 23

1 Answers1

10

Here's what I've found so far:

The size & alignment properties in a vtable are loaded in the librustc_codegen_llvm::glue::size_and_align_of_dst() function which returns the size and alignment of a dynamically sized type. For ty::Dynamic(..) values (the compiler's internal way of describing trait objects), the size and alignment are read from the vtable:

match t.sty {
    ty::Dynamic(..) => {
        // load size/align from vtable
        let vtable = info.unwrap();
        (meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
    }
    ...
}

This function in turn is used in several places:

I didn't spot any places where these values are currently fed into the Rust deallocation function (__rust_dealloc()), but they could certainly be used for that in the future.

Wesley Wiser
  • 9,491
  • 4
  • 50
  • 69
  • 1
    Likely for forwards compatibility. – Peter Hall Aug 24 '18 at 20:45
  • @PeterHall Yes. Knowing the size & alignment of data is so fundamental & useful, there's little reason not to include it especially given that the storage overhead is once per type-vtable and it's just two `usize`s. – Wesley Wiser Aug 24 '18 at 20:47
  • Thank you for such a comprehensive answer! I have 1 more question: [Rustonomicon states](https://doc.rust-lang.org/nomicon/exotic-sizes.html) that DSTs pretty much boil down to slices. Slices have size unknown at compilation time. How do vtables handle size field of slices with different lengths? Does slice of 2 `u32`s have other vtable from slice of 3 `u32`s? After all one has size of 16 and other has 24 (simplification). – CodeSandwich Aug 24 '18 at 21:33
  • 2
    @CodeSandwich The Rustonomicon might be being unclear. There are certain DSTs which resemble slices - structs with a few sized fields then a slice (or other DST) as the final field. A pointer to any DST has to carry extra information in the form of an extra `usize`. For slices, or slice-like DSTs, the extra information is the size of the slice. For trait objects, it's a pointer to the vtable. – Peter Hall Aug 25 '18 at 08:34
  • So that's why it's not possible to cast different trait objects, slice objects and composed DSTs to trait objects. – CodeSandwich Aug 25 '18 at 12:11