Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do trait object vtables contain size and alignment?

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?)
like image 668
CodeSandwich Avatar asked Aug 24 '18 20:08

CodeSandwich


People also ask

What is trait object in Rust?

A trait object is an opaque value of another type that implements a set of traits. The set of traits is made up of an object safe base trait plus any number of auto traits. Trait objects implement the base trait, its auto traits, and any supertraits of the base trait.

Does rust use Vtables?

(Also, as more anecdotal evidence: the Rust compiler is known to generate multiple vtables for the same type if they happen to be needed in separate codegen units.)

What is object safety in Rust?

Object Safety A trait is object safe if it has the following qualities (defined in RFC 255): All supertraits must also be object safe. Sized must not be a supertrait. In other words, it must not require Self: Sized . It must not have any associated constants.

What is dynamic dispatch in rust?

Dynamic dispatch. Rust provides dynamic dispatch through a feature called 'trait objects'. Trait objects, like &Foo or Box<Foo> , are normal values that store a value of any type that implements the given trait, where the precise type can only be known at runtime.


1 Answers

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:

  • librustc_codegen_llvm::operand::store_unsized() for allocating enough storage space on the stack for the storing the unboxed value.
  • librustc_codegen_llvm::intrinsic::codegen_intrinsic_call() for implementing the size_of_val() intrinsic
  • librustc_codegen_llvm::intrinsic::codegen_intrinsic_call() for implementing the min_align_of_val() intrinsic

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.

like image 51
Wesley Wiser Avatar answered Sep 28 '22 19:09

Wesley Wiser