Home > front end >  Why can't the compiler ever elide the vtable?
Why can't the compiler ever elide the vtable?

Time:04-27

Sometimes I create an abstract class merely for implementation hiding, as an alternative to the pimpl idiom. If there is only one descendant and no public visibility outside the library that I'm building, why can't the linker remove the vtable?

I tried some experiments with clang and -Os. I added this to the constructor of one of my private impl classes:

printf("%p vs %p\n", this, &_first_member_field);

I always see an 8-byte difference between these two pointers, which I assume is the vtable pointer since I'm on a 64-bit arch. I also tried:

-no-rtti -flto=full -fvirtual-function-elimination -fstrict-vtable-pointers

But those 8 bytes never go away. Is this due to spec compliance?

CodePudding user response:

Proving that (safely deriived) pointers to instances of your class are never passed to any code the compiler cannot examine is insanely hard.

Once such a pointer is in any code the compiler cannot examine, it must provide a vtable pointer to support RTTI and dynamic dispatch. And this must be ABI compatible with someone else who inherits from your API and implements a different implementation.

You intend there to be exactly one implementation of this interface. But you cannot communicate this to your compiler, so it does not know this.

An example of this is the fact you passed the pointer to printf above. The implementation of printf is opaque to your C compiler (at some level of iteration); as far as your compiler knows, the value is cast back to the interface pointer and examined using RTTI. Or passed to some function that consumes the abstract API you specified, and other code passes a different implementation.

Devirtualization, removal of virtual dispatch, and object elimination are things that C compilers do when optimizing code. It is plausible such a set of operations could occur; amusingly, attempting to detect offsets of members is the kind of thing that would block these optimizations.

I can write code where created objects don't exist jn the output assembly, and vtable calls are skipped. They aren't going to be fiddling with raw memory, however, because that kind of operation makes optimizers give up.

  •  Tags:  
  • c
  • Related