Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #84189
| 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> |
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 | Next — Previous in thread | Next in thread | Find similar | Unroll 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