How does Rust call a &dyn Fn?

Viewed 109

I have this Rust function:

pub fn abc(x: &dyn Fn()) {
    x()
}

When I compile it with Rust 1.63.0 on Godbolt Compiler Explorer I get this generated x86-64 assembly code:

example::abc:
        push    rax
        call    qword ptr [rsi + 40]
        pop     rax
        ret

Where is the offset 40 coming from? I want to get an underlying understanding of this generated assembly code.

1 Answers

&dyn Fn is stored as pair of (data, vtable). The vtable contains:

  1. A function pointer to drop_in_place::<Type>, used to drop the type in e.g. Box<dyn Trait> (function pointer sized, usize on x86).

  2. The size of the data (usize).

  3. The alignment of the data (usize).

  4. A list of function pointers to the trait methods, including supertraits. For Fn they are:

    1. FnOnce::call_once().
    2. FnMut::call_mut().
    3. Fn::call(), which is what we are calling in your code.

So Fn::call() is at offset drop_in_place (8 bytes) + size (8 bytes) + alignment (8 bytes) + call_once (8 bytes) + call_mut (8 bytes) = 40 bytes.

Related