C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Allow conversion of memfunc pointers to func pointers

From: Thiago Macieira <thiago_at_[hidden]>
Date: Fri, 19 Jan 2024 12:14:06 -0800
On Friday, 19 January 2024 04:46:39 PST Frederick Virchanza Gotham via Std-
Proposals wrote:
> On Thursday, January 18, 2024, Thiago Macieira wrote:
> > Still can't be implemented: there's no link from the type_info object back
> > to
> > the vtable. The link is one-way and it's from the vtable to the TI.
>
> Just throwing ideas up in the air here, but the compiler could keep a
> sorted global array mapping type_info hash codes to vtables:

Then stop throwing ideas without trying to understand the problem.

If you require the compiler to do something it isn't doing right now, then
it's not backwards compatible with code that was already compiled. If it can
detect when the data is of the old format, then the function in question needs
to be able to fail. If it can't detect, then the function or operations after
it may crash hard.

In the case of a global mapping back, it could detect the missing data and
fail.

But just how is it going to populate that global map in the first place?

> array< pair<size_t, void const*>, 2u > const g_vtables = {
> { typeid(MyClass).hash_code(), &_ZTI7MyClass },
> { typeid(YourClass).hash_code(), &_ZTI9YourClass },
> };
>
> The standard library function 'std::get_polymorphic_facilitator' would
> perform a binary search through this array. So if a massive program like
> Chromium has 6,000 classes, then a worst case binary search would be about
> 13 checks. On a desktop PC that's less than a microsecond.

If that thing is sorted by pointer address, then it must have been constructed
at runtime. That means a mutex or rwlock around the accesses. And just where
do you propose the compiler insert the code that updates this array with new
entries?

If it's not sorted by pointer, it could be statically generated (per DSO/DLL
at least), but then look ups are slow. It can't be sorted in statically
generated maps (even per DSO) because the pointers in question may point to
entities in other libraries, whose positions in memory are arbitrary. Vtables
and typeinfos are Vague-linkage symbols on ELF and Mach-O systems.

Ignoring the rest because I don't see this ever being implemented.

> > This request smells like the X-Y problem: in order to do X (the
> > devirtualiser), you think you need Y so you're trying to standardise Y. We
> > should be talking about X instead. And especially because this X function
> > that
> > uses Y would need to exist inside the standard library anyway because it's
> > not
> > portable.
>
> I don't think that there's anything wrong with the generic idea of
> standardising Y so that X can be implemented in standard-compliant code,
> especially if it means that A, B and C can also be implemented alongside X,
> taking advantage of Y. Therefore I would strive to make Y as flexible and
> as versatile as possible.

That's fair, except that X in this case can't be implemented in a standard
manner in the first place. The contents of the vtable are entirely ABI (and
often psABI) dependent and so are the concrete forms of PMFs.

So what are A, B, and C that would also use this functionality?

> So far, the only use I've suggested for 'get_polymorphic_facilitator' is to
> turn virtual pointers into direct pointers. I haven't come up with a second
> use for it yet but I have a feeling somebody will. Having a pre-compiled
> list of use cases isn't the be-all and end-all of engineering; back when
> folks were designing the C programming language, switch statements and
> loops were designed with very loose restrictions a long time before Thomas
> Duff ever came up with his 'Duff's Device'. I'm in favour of keeping things
> loose in order to accommodate unforeseen use cases.

Indeed there are many things that weren't envisioned or thought of when
something was designed. Template Meta Programming comes to mind too.

That doesn't obviate the need to give *some* possible ideas for this
functionality. There's a high cost to what you're asking for, so there had
better be some important use-cases that cannot be otherwise implemented. If
the proponent of this idea can't come up with those use-cases to justify the
feature, it won't get added.

Please also note that the functionality you've described above does not need
to start from the type_info. You could start from object of a given type or
the type itself. So we actually have an X, Y and Z case here:

X = devirtualise a PMF to virtual member
Y = need access to the virtual table to do that
Z = need to get the virtual table from the type_info pointer

X is your real want. Y is indeed required in the implementation when doing
this on an object instead of on a static type. Z is not needed at all and is
the unimplementable portion.

> If we tell compiler vendors that 'get_polymorphic_facilitator' should
> return a pointer to whatever is used to make sure that the correct virtual
> function is called -- without explicitly stating 'It gives you the vtable
> pointer', then it doesn't restrict how compilers implement virtual
> functions.

But if we don't restrict what that pointer points to, dereferencing is
impossible in standard code. We have features that return platform-dependent
content (q.v. all the "native_handle()" functions), but this does reduce the
area of what one could use the functionality for.

> I'm tempted to do what Arthur did and fork the GNU linker, try to make a
> list of all the vtables and all the type_info's, and then create the
> aforementioned sorted map in order to implement 'void const
> *std::get_polymorphic_facilitator(type_info const &)'.

Go ahead. This will either tell you that the cost is too high or will show a
solution I haven't thought of. But see above: I don't think you need this at
all (X-Y-Z case).

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DCAI Cloud Engineering

Received on 2024-01-19 20:14:09