Date: Sun, 14 Jan 2024 23:27:56 +0000
On Sat, Jan 13, 2024 at 7:04 PM Jarrad Waterloo wrote:
>
> I really think this needs to be a language feature that is portable.
I agree that it should be a portable language feature in C++26, but
for the time being I'm having fun trying to implement it on different
compilers.
As I mentioned in a post a few days ago, I already got it working on GNU g++:
https://godbolt.org/z/TvK5Y7aWh
but that was made easy by the GNU compiler extension that allows you
to get the memory address of a virtual function (see here:
https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html )
It's easy to get the address of any class's vtable if you have an
object of the class, for example with the following function:
template<typename T>
void (*GetVtable(T const &arg))(void)
{
static T obj;
return *static_cast<void (*const *)(void)>(static_cast<void
const *>(&arg));
}
So then when you get a pointer to a member function, you can extract
the vtable offset and add it to the address of the vtable -- but what
if T doesn't have a default constructor? Or what if T is an abstract
class? Or what if T doesn't have any accessible constructors? The
above function will fail to compile if it can't create an object of
type T.
But I have another idea. The mangled linker symbol for the vtable for
any class is: _ZTV5Name
So if the class is called 'Donkey', then the vtable linker symbol is
'_ZTV5Donkey'.
So I rewrote the 'NonVirtual' macro to use the vtable's linker symbol:
#define NonVirtual(Class,Member)
\
([]() -> decltype(&Class::Member)
\
{
\
auto pmf = &Class::Member;
\
extern void (*const _ZTV5##Class)(void);
\
void (*const *const &vtable)(void) = &_ZTV5##Class;
\
auto &n =
*static_cast<std::uintptr_t*>(static_cast<void*>(&pmf)); \
if ( 0u == (n & 1u) ) return pmf; /* no need to
devirtualise */ \
void (*const pf)(void) = vtable[1u + n];
\
std::memcpy(&pmf,&pf,sizeof pf);
\
return pmf;
\
}())
And then I tried it out with LLVM clang++ and also the Intel compiler:
https://godbolt.org/z/WdT5MMcG3
And while I'm talking . . . maybe it would be worth mentioning that
name mangling should be standardised too?
>
> I really think this needs to be a language feature that is portable.
I agree that it should be a portable language feature in C++26, but
for the time being I'm having fun trying to implement it on different
compilers.
As I mentioned in a post a few days ago, I already got it working on GNU g++:
https://godbolt.org/z/TvK5Y7aWh
but that was made easy by the GNU compiler extension that allows you
to get the memory address of a virtual function (see here:
https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html )
It's easy to get the address of any class's vtable if you have an
object of the class, for example with the following function:
template<typename T>
void (*GetVtable(T const &arg))(void)
{
static T obj;
return *static_cast<void (*const *)(void)>(static_cast<void
const *>(&arg));
}
So then when you get a pointer to a member function, you can extract
the vtable offset and add it to the address of the vtable -- but what
if T doesn't have a default constructor? Or what if T is an abstract
class? Or what if T doesn't have any accessible constructors? The
above function will fail to compile if it can't create an object of
type T.
But I have another idea. The mangled linker symbol for the vtable for
any class is: _ZTV5Name
So if the class is called 'Donkey', then the vtable linker symbol is
'_ZTV5Donkey'.
So I rewrote the 'NonVirtual' macro to use the vtable's linker symbol:
#define NonVirtual(Class,Member)
\
([]() -> decltype(&Class::Member)
\
{
\
auto pmf = &Class::Member;
\
extern void (*const _ZTV5##Class)(void);
\
void (*const *const &vtable)(void) = &_ZTV5##Class;
\
auto &n =
*static_cast<std::uintptr_t*>(static_cast<void*>(&pmf)); \
if ( 0u == (n & 1u) ) return pmf; /* no need to
devirtualise */ \
void (*const pf)(void) = vtable[1u + n];
\
std::memcpy(&pmf,&pf,sizeof pf);
\
return pmf;
\
}())
And then I tried it out with LLVM clang++ and also the Intel compiler:
https://godbolt.org/z/WdT5MMcG3
And while I'm talking . . . maybe it would be worth mentioning that
name mangling should be standardised too?
Received on 2024-01-14 23:28:04