Stack Allocated Trait Objects


#1

The title is a misnomer, considering trait objects are stack allocated, of course. What I am wondering is if it is possible to pass the implementing struct along with the vtable, by value, i.e. in

fn uses_trait(object: Trait)

the layout of the type Trait is not (*T, * Vtable) where T: Trait but rather (isize, *Vtable, T) where the isize determines how many bytes T occupies. This way, the function uses_trait knows exactly how many bytes to consume off of the stack at runtime. In fact, this can be used for any dynamically sized type, and not simply trait objects, although I would imagine that it is almost always better to pass an array by reference than value. I have never actually heard of this before, so it must be impossible for some very good reason, but on the surface it seems like a feasible thing to do and gets rid of one dereference. Does LLVM expose this kind of flexible function calling? What are the advantages and disadvantages? Is it even possible?


#2

By-value unsized types is a desirable feature, e.g. it is needed for FnOnce() trait objects to work most naturally. It’s covered by RFC issue 990. However, the only thing it can map to is a pointer (in general), one can’t just stuff an arbitrary number into a CPU register for a function call. E.g. calling a function fn foo(x: HugeStruct) is fairly similar to fn bar(x: &HugeStruct) on the machine: at least, the exact call instruction is essentially identical; the former gives the internals of foo more power than bar, but this likely comes at the cost of some set-up that the latter doesn’t need.


#3

See also the stack (stack-dst!) crate