C++ Logo

sg15

Advanced search

Re: [isocpp-sg15] P3470R0: Interface-Unit-Only Module Library Support

From: Nathan Sidwell <nathan_at_[hidden]>
Date: Mon, 21 Oct 2024 12:07:46 -0400
On 20/10/2024 20:00, Iain Sandoe via SG15 wrote:
>
>
>> On 20 Oct 2024, at 23:55, Nathan Sidwell via SG15 <sg15_at_[hidden]> wrote:
>>
>> FWIW, we did consider a different scheme. Namely interface units emit the the standard constructor function that is called via .init_array. But, give the ctor a priority related to the depth of the interface unit's import graph. Thus the initializers of any imported interface are run before the initializer of the importer. (there's a bit of finessing with partitions, but fairly obvious).
>>
>> IIRC we rejected that as it relied on knowlege of the import graph -- but the scheme we have does that too. It has the advantage of not needing idempotent initializers -- they're executed exactly once by design
>
> I thought (modulo the complaint about calling empty fns) what we had was quite tidy - in that it guaranteed that the init order was correct, but only requires that a given module knows its own imports (no global knowledge of the import graph, and no change for multiple uses or uses in different graphs).

The specification permits implementations to make use of the complete graph
though -- and they must know it, because each module must know the set of its
direct imports.

>
> Was I mis-remembering, or did you have a proposed scheme to elide the redundant calls when an importer could determine that its imports had no inits?

It says more than that.

>
> We certainly already elide any unnecessary guards etc.
>
>> . It does rely on constructor priorities, but I'm going to presume that any system implementing the itanium ABI supports them.
>
> That is not the case, AFAIK there’s at least one Itanium platform that does not.

That's, um, unfortunate.

>
> Might that not also force more rebuilding of MIUs if they occupy different positions in the graph in different uses?

That cannot happen. The depth I refer to above is the height from the interface
unit generating the constructor above its farthest leaf import. How it is
itself imported is irrelevant. 'height' or 'depth' depends on whether you
consider trees growing up or down I guess.

>
> Iain
>
>>
>> Perhaps we should change?
>>
>> nathan
>>
>>
>> On 20/10/2024 17:26, Gabriel Dos Reis via SG15 wrote:
>>> [Jason]
>>> * But if the interface unit doesn't have any dynamic initialization, which I
>>> would expect to be by far the majority of MIUs, forcing all importers to
>>> call an empty function seems like an undesirable pessimization to startup.
>>> Exactly.
>>> The MSVC implementation doesn’t have this unnecessary compulsory complication.
>>> -- Gaby
>>> *From:*SG15 <sg15-bounces_at_[hidden]> *On Behalf Of *Jason Merrill via SG15
>>> *Sent:* Friday, October 18, 2024 2:40 PM
>>> *To:* sg15_at_[hidden]
>>> *Cc:* Jason Merrill <jason_at_[hidden]>; Nathan Sidwell <nathan_at_[hidden]>
>>> *Subject:* Re: [isocpp-sg15] P3470R0: Interface-Unit-Only Module Library Support
>>> On Thu, Oct 17, 2024 at 2:27 PM Daniel Ruoso via SG15 <sg15_at_[hidden]<mailto:sg15_at_[hidden]>> wrote:
>>> Em qua., 16 de out. de 2024 às 19:28, Nathan Sidwell via SG15
>>> <sg15_at_[hidden] <mailto:sg15_at_[hidden]>> escreveu:
>>> > It is important to note that, in the Itanium ABI, even if the module
>>> doesn’t currently have
>>> > anything that needs static initialization, the translation unit
>>> importing that module will still
>>> > generate the code to call the initializer, because we don’t want the
>>> addition of a static initializer
>>> > to a shared object to result in an ABI break
>>> this is false.
>>> Interesting. That is the current implementation in clang, IIUC.
>>> We probably need to clarify that point, because it is indeed problematic if
>>> adding a new static initializer means an ABI breakage for the library.
>>> This would be the proposed
>>> https://github.com/itanium-cxx-abi/cxx-abi/pull/144/files#diff-b803017e5afd1b6dfe35e5e0e719d895559129c35b93f056074a72928269ae23R5034 <https:// github.com/itanium-cxx-abi/cxx-abi/pull/144/files#diff-b803017e5afd1b6dfe35e5e0e719d895559129c35b93f056074a72928269ae23R5034>
>>> It's not clear to me why calling this initializer would be necessary for a shared object anyway, since loading the shared object will run its initialization before that of the executable.
>>> I think this was intended to make the <iostream> __ioinit trick work in a modules world; with that trick, any TU that included the file got a static initializer that runs before anything else. So similarly, if you import an interface unit with a static initializer, you need to run it first. But if the interface unit doesn't have any dynamic initialization, which I would expect to be by far the majority of MIUs, forcing all importers to call an empty function seems like an undesirable pessimization to startup.
>>> The ABI break is not on adding a static initializer to a shared object; it's on adding a static initializer to a module interface unit that isn't in a shared object, and even then you only lose the order of initialization guarantee (unless you use attribute init_priority). This seems acceptable to me.
>>> Jason
>>> _______________________________________________
>>> SG15 mailing list
>>> SG15_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/sg15
>>
>>
>> --
>> Nathan Sidwell
>> _______________________________________________
>> SG15 mailing list
>> SG15_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/sg15
>
> _______________________________________________
> SG15 mailing list
> SG15_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg15


-- 
Nathan Sidwell

Received on 2024-10-21 16:07:53