Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #84189

Re: Function pointer size (was Re: nullptr is not 0)

From Andrey Tarasevich <andreytarasevich@hotmail.com>
Newsgroups comp.lang.c++
Subject Re: Function pointer size (was Re: nullptr is not 0)
Date 2022-05-19 09:35 -0700
Organization A noiseless patient Spider
Message-ID <t65rkf$5q3$1@dont-email.me> (permalink)
References (3 earlier) <66geK.6522$lQq1.6208@fx43.iad> <t610ls$8r7$1@dont-email.me> <t61tn1$1gd6$1@gioia.aioe.org> <t62ddu$41b$1@dont-email.me> <t65lls$1nug$1@gioia.aioe.org>

Show all headers | View raw


On 5/19/2022 7:53 AM, Juha Nieminen wrote:
> Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>>> If you have a reference or pointer to an object of type class A, and a
>>> member pointer to a member function of class A, which is virtual, if
>>> the actual object pointed to is of some derived type B which has its
>>> own specialization of that virtual function, calling the function using
>>> the pointer will call the derived implementation not, the one in class A.
>>>
>>> For this to be possible the pointer to member function needs additional
>>> data.
>>
>> No, that's incorrect.
>>
>> This has nothing to do with virtual functions. On the contrary,
>> pointers-to-virtual-functions are "easy": regular virtual call mechanism
>> itself is already required to incorporate all necessary mechanics to
>> properly invoke virtual functions across the entire hierarchy of
>> classes. This mechanics is already present in "regular" virtual calls
>> (without involving any pointers-to-members).
> 
> I'm not sure that's correct.

I am.

> When you have a pointer-to-member, in the location of the call the compiler
> doesn't know *which* member function it's pointing to. It only knows its
> signature, not its name. The class may have several differently-named
> member fuctions with the same signature. I don't think the compiler can
> even know (from the source code alone) if the pointed-to function is
> virtual or not.

That's true. However, some implementations do use different internal 
pointer representations for pointers that happen to point to virtual 
functions, while some other implementations don't. It depends on the 
chosen approach.

* In GCC on x86 (x64) the lower 8-byte word of a pointer that happens to 
point a regular function is simply a pointer. At the same time a pointer 
that happens to point to a virtual function represents an offset into 
virtual table +1. These are two completely different representations.

GCC distinguishes the former from the latter by fact that the former is 
always even and the latter is always odd, i.e. it uses the lowest bit as 
a distinguishing flag. It can do that because function entry points on 
x86 are always even.

This means that GCC cannot just "call" the "address" stored in such a 
pointer. Every time it makes a call through such a pointer, GCC has to 
analyze the pointer's value every and branch to a proper dispatch method.

This is a strange approach, but apparently GCC likes it.

Here's an example for you

   http://coliru.stacked-crooked.com/a/568ab87c2741f22e

See the output

   01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   02 0d 40 00 00 00 00 00 00 00 00 00 00 00 00 00

The first one is 1 (odd) represents virtual function `foo` with offset 
1-1=0 in the VMT.
The second one is 9 (odd) represents virtual function `baz` with offset 
9-1=8 in the VMT.
The third one (even) represents regular function `bar`. This is just a 
callable address.

Note that in all cases the upper 8-byte word is zero. The upper word is 
not used to distinguish "virtual" pointers from "regular" ones.

* MSVC uses a completely different approach. The lower 8-byte word of a 
pointer to a member function is always simply a pointer to an entry 
point into "some" function. It can always be called right away.

MSVC generates non-virtual middle-man caller stubs for each virtual 
function. A pointer to a virtual member function will point to that stub 
instead of pointing to the virtual function itself. In MSVC a pointer to 
a member function always physically points to some non-virtual function.

This is a different approach and MSVC sticks to it.

Here's a sketch: every time you write something like this

   struct S
   {
     virtual int foo() { ... }
   };

   int (S::*p) = &S::foo;

MSVC compiler actually generates something like this

   struct S
   {
     virtual int foo() { ... }
     int foo_dispatch() { return foo(); }
   };

   int (S::*p) = &S::foo_dispatch();

See? Everything works as it is supposed to, yet there's no need to take 
any extra steps to distinguish virtual pointers from non-virtual ones, 
because such pointers always physically point to "regular" functions.

> Thus, the compiler needs to create code that somehow figures out if
> that member function is virtual, and which function it is, 

No, it depends on the chosen approach. See above. In GCC it does. In 
MSVC it doesn't.

> and then
> use the vtable as normal to jump to the actual most-derived implementation.

But that is how a virtual call always works. This is already built into 
the virtual call mechanism. There's no need to do anything additional 
for pointers to members, as long as you know how to piggyback on the 
already-existing virtual call mechanism "for free". And that is exactly 
what MSVC's approach takes advantage of.

> I don't think it can do this without the extra data in the pointer.

Yes, you can.

As I have shown above, GCC does need "extra data" in the pointer to tell 
one representation from the other. But since all function addresses on 
x86 are even, it can use the lowest bit of the lower 8-byte word for 
that. I.e. it stuffs that data into the original "pointer". No need to 
increase the pointer size.

Meanwhile, MSVC does not need that extra data at all.

> Please correct me if I'm wrong.

As I have already explained in my other answer in this thread, the upper 
8-byte word in member function pointer is used for offsetting `this` 
pointer before the call in situations when offsetting is necessary. This 
is needed with multiple inheritance (and some other more niche cases). 
If `this` pointer needs no offsetting, the upper 8-byte word is zero.

So, again, the upper 8-byte word has nothing to do with implementing 
calls to virtual functions.

This all is, of course, implementation details. I have outlined the most 
popular practical approaches. Some other implementation might invent 
something else.

-- 
Best regards,
Andrey

Back to comp.lang.c++ | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

nullptr is not 0 Sam <sam@email-scan.com> - 2022-05-08 09:45 -0400
  Re: nullptr is not 0 "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-05-08 16:21 +0200
  Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-08 10:00 -0700
  Re: nullptr is not 0 Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-09 06:38 +0200
  Re: nullptr is not 0 Juha Nieminen <nospam@thanks.invalid> - 2022-05-09 05:06 +0000
    Re: nullptr is not 0 Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-09 21:46 +0100
      Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-09 13:57 -0700
        Re: nullptr is not 0 Juha Nieminen <nospam@thanks.invalid> - 2022-05-10 05:04 +0000
          Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-09 22:33 -0700
      Re: nullptr is not 0 scott@slp53.sl.home (Scott Lurndal) - 2022-05-09 21:56 +0000
        Function pointer size (was Re: nullptr is not 0) Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-17 21:30 +0100
          Re: Function pointer size (was Re: nullptr is not 0) scott@slp53.sl.home (Scott Lurndal) - 2022-05-17 21:00 +0000
            Re: Function pointer size (was Re: nullptr is not 0) Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-19 21:52 +0100
            Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 14:08 -0700
          Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-17 17:05 -0700
          Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-18 04:46 +0000
            Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-18 02:14 -0700
              Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-19 14:53 +0000
                Re: Function pointer size (was Re: nullptr is not 0) "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-05-19 17:19 +0200
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 10:14 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 13:45 -0400
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 11:31 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-20 06:58 +0000
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-20 00:11 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 12:27 -0400
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 09:47 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 13:36 -0400
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 11:24 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 21:32 -0400
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 20:28 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-20 10:57 -0400
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 09:35 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 10:10 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-20 07:15 +0000
          Re: Function pointer size (was Re: nullptr is not 0) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-05-18 11:50 -0700
            Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-18 15:46 -0700
              Re: Function pointer size (was Re: nullptr is not 0) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-05-19 20:52 -0700

csiph-web