Reputation: 1751
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:
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?)Upvotes: 10
Views: 1264
Reputation: 11
To demonstrate why the vtable must store the alignment of the value, we can look at Rc::<dyn Trait>::as_ref
associated function (i.e. dereference of Rc::<dyn Trait>
into &dyn Trait
).
A value of type Rc<dyn Trait>
is essentially two addresses: the address of RcBox
(which is a struct that contains reference counts and the object value) and the address of vtable corresponding to the object value. To obtain the address of the object value, we need to offset the address of RcBox
past the reference counts (two 8-byte numbers, assuming 64-bit machine). However, if the object value has alignment greater than 16, it must be offset further (to satisfy its alignment). This means that to obtain the address of the object value, we must know the alignment of the value.
Upvotes: 1
Reputation: 9851
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()
intrinsiclibrustc_codegen_llvm::intrinsic::codegen_intrinsic_call()
for implementing the min_align_of_val()
intrinsicI 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.
Upvotes: 11