May 12, 2015
On Monday, 11 May 2015 at 20:53:40 UTC, Benjamin Thaut wrote:
> Am 11.05.2015 um 21:39 schrieb Laeeth Isharc:
>> On Monday, 11 May 2015 at 12:54:09 UTC, Benjamin Thaut wrote:
>>>> and why does it not map well to D ?
>>> D uses tons of templates everywhere. Even type information for non
>>> templated types is generated on demand and stored in comdats which can
>>> lead to duplicate symbols the same way it does for templates. In D the
>>> dynamic cast is basically the default and you have to force the
>>> compiler to not use a dynamic cast if you care for performance.
>>
>> Sorry for the rookie question, but my background is C rather than C++.
>> How do I force a static cast, and roughly order magnitude how big is the
>> cost of a dynamic cast ?
>>
>> Would you mean for example rather than casting a char[] to a string
>> taking the address and casting the pointer?
>
> Dynamic casts only apply to classes. They don't apply to basic types.
>
> Example
>
> object o = instance;
> SomeClass c = cast(SomeClass)instance; // dynamic cast, checks type info
> SomeClass c2 = cast(SomeClass)cast(void*)instance; // unsafe cast, simply assumes instance is SomeClass
>
> If you do the cast in a tight loop it can have quite some performance impact because it walks the type info chain. Walking the type info hirarchy may cause multiple cache misses and thus a significant performance impact. The unsafe cast literally does not anything besides copying the pointer.

aha - thank you.  I appreciate it.  Laeeth.
May 12, 2015
On Friday, 8 May 2015 at 05:26:01 UTC, Benjamin Thaut wrote:
> I personally would prefer option 2 because it would be easier to use and wouldn't cause lots of additional maintenance effort.
>
> Any opinions on this? As both options would be quite some work I don't wan't to start blindly with one and risking it being rejected later in the PR.
>
> Kind Regards
> Benjamin Thaut


(2) would be nice but how would

a.dll provides a.dll!q

b.dll links against a.dll, provides b.dll!w

c.dll provides c.dll!q

d.exe links against b.dll (b.lib) and c.dll (c.lib).

work?

q could be a completely different type in a.dll vs. c.dll. Please correct me if I am wrong, but my understanding of how import libs get used you can't detect this at build time and disallow it. Linking d.exe we have no reason to look at a.lib and notice the conflict, and even if we did there's no type information to go off of anyway and you could assume that they were the same.

Is your intent to only apply this unification to extern (D) symbols?

May 13, 2015
On Tuesday, 12 May 2015 at 17:48:50 UTC, Logan Capaldo wrote:
> q could be a completely different type in a.dll vs. c.dll. Please correct me if I am wrong, but my understanding of how import libs get used you can't detect this at build time and disallow it. Linking d.exe we have no reason to look at a.lib and notice the conflict, and even if we did there's no type information to go off of anyway and you could assume that they were the same.

No q can not be a different type in a.dll vs c.dll
Because of the mangling of the type it would be called a.q once and c.q so no conflict would arise.

If you define the same type within the same module but it behaves differently depending on where it is used (e.g. depending on compiler flags -version -debug etc), this is already an issue and will also explode with static libraries. So nothing new here. The user of the language has to ensure that all uses of a type see the same declaration of the type.

>
> Is your intent to only apply this unification to extern (D) symbols?
Why not? I can't think of anything special about extern (D) declarations. Just as a reminder, linux already does this for _all_ symbols. And it doesn't cause any issues there.
May 13, 2015
On Wednesday, 13 May 2015 at 06:17:36 UTC, Benjamin Thaut wrote:
> On Tuesday, 12 May 2015 at 17:48:50 UTC, Logan Capaldo wrote:
>> q could be a completely different type in a.dll vs. c.dll. Please correct me if I am wrong, but my understanding of how import libs get used you can't detect this at build time and disallow it. Linking d.exe we have no reason to look at a.lib and notice the conflict, and even if we did there's no type information to go off of anyway and you could assume that they were the same.
>
> No q can not be a different type in a.dll vs c.dll
> Because of the mangling of the type it would be called a.q once and c.q so no conflict would arise.
>

Not if q is extern C or extern C++.

>>
>> Is your intent to only apply this unification to extern (D) symbols?
> Why not? I can't think of anything special about extern (D) declarations. Just as a reminder, linux already does this for _all_ symbols. And it doesn't cause any issues there.

The thing that is special about extern (D) symbols is that the module mangling sidesteps my 'q' example.

It does cause issues on Linux actually. I've seen it multiple times, usually when first party code and third party both unbeknownst to each other both embed different versions of a popular source only library.

If my program only links against DLLs written in D, sure this is no worse than the static library/version flag situation. But one of D's features is C and C++ interop. For instance if I link against a DLL that happens to provide COM objects am I going to start getting weird behaviors because all the DllGetClassObjects are 'unified' and we just pick one?

May 13, 2015
On Wednesday, 13 May 2015 at 07:41:27 UTC, Logan Capaldo wrote:
>
> If my program only links against DLLs written in D, sure this is no worse than the static library/version flag situation. But one of D's features is C and C++ interop. For instance if I link against a DLL that happens to provide COM objects am I going to start getting weird behaviors because all the DllGetClassObjects are 'unified' and we just pick one?

Well this unification will only happen for D libraries. Its not going to do that for non D shared libraries (e.g. written in C or C++). The unification is also only going to happen for things that are linked in via a import library. So if you load the stuff manually with GetProcAddress you still get the "real" thing. All in all the summary is, if it breaks with static libraries it will break with shared libraries as well. If you have multiple static libraries that all define a symbol called "DllGetClassObjects" then it won't even link.
May 13, 2015
On Wednesday, 13 May 2015 at 07:49:26 UTC, Benjamin Thaut wrote:
> On Wednesday, 13 May 2015 at 07:41:27 UTC, Logan Capaldo wrote:
>>
>> If my program only links against DLLs written in D, sure this is no worse than the static library/version flag situation. But one of D's features is C and C++ interop. For instance if I link against a DLL that happens to provide COM objects am I going to start getting weird behaviors because all the DllGetClassObjects are 'unified' and we just pick one?
>
> Well this unification will only happen for D libraries. Its not going to do that for non D shared libraries (e.g. written in C or C++).

And for shared libraries written in a mix of D and C++ or C, or shared libraries written in D but that expose extern (C) or extern (C++) symbols?

Yes it won't happen for explicit LoadLibrary's and GetProcAddresses, but COM or other plugin systems is an example of a situation where many DLLs may expose the same named symbols with different definitions, and there may be situations where people link to those DLLs directly to get other things they provide.
May 13, 2015
On Wednesday, 13 May 2015 at 11:27:18 UTC, Logan Capaldo wrote:
>
> Yes it won't happen for explicit LoadLibrary's and GetProcAddresses, but COM or other plugin systems is an example of a situation where many DLLs may expose the same named symbols with different definitions, and there may be situations where people link to those DLLs directly to get other things they provide.

Once again, I'm going to patch the import table. The import table gets only generated for symbosl which are _imported_ by a import library. This only happens for things that get imported by D libraries / executables. Linking against multiple dlls via a import library which export the same symbol doesn't work no matter if I do the patching or not. So nothing changes in that regard. Your COM Dlls are not going to break even if each COM dll exports the same symbol. Because these COM specific symbols will not be imported by a D library via a import library, so nothing changes. The problems you think exist do not exist because I only patch the importing table and not the dlls that export the symbols. Even if you mix D with C++ you are not going to have that problem, because you can't link against multiple libraries with the same symbol with C++ either.
May 13, 2015
On Wednesday, 13 May 2015 at 11:41:27 UTC, Benjamin Thaut wrote:
> On Wednesday, 13 May 2015 at 11:27:18 UTC, Logan Capaldo wrote:
>>
>> Yes it won't happen for explicit LoadLibrary's and GetProcAddresses, but COM or other plugin systems is an example of a situation where many DLLs may expose the same named symbols with different definitions, and there may be situations where people link to those DLLs directly to get other things they provide.
>
> Once again, I'm going to patch the import table. The import table gets only generated for symbosl which are _imported_ by a import library. This only happens for things that get imported by D libraries / executables. Linking against multiple dlls via a import library which export the same symbol doesn't work no matter if I do the patching or not. So nothing changes in that regard. Your COM Dlls are not going to break even if each COM dll exports the same symbol. Because these COM specific symbols will not be imported by a D library via a import library, so nothing changes. The problems you think exist do not exist because I only patch the importing table and not the dlls that export the symbols. Even if you mix D with C++ you are not going to have that problem, because you can't link against multiple libraries with the same symbol with C++ either.

a.dll provides symbol s1
b.dll provides symbol s1

c.dll imports symbol s1 from a.dll, provides symbol s2
d.dll imports symbol s1 from b.dll, provides symbol s3

e.exe imports symbol s2 from c.dll, imports symbol s3 from d.dll. e.exe only needs the import libs from c.dll and d.dll.

You're patching the import tables at runtime correct?. If you patch c and d's import tables their s1 import is going to end up pointing at the same symbol.

I can build a.dll and c.dll completely independently of d.dll and b.dll. There's no opportunity to prevent this at compile time. Likewise e.exe doesn't know or care s1 exists so it builds fine as well. You don't need a.lib or b.lib to build e.exe.
May 13, 2015
On Wednesday, 13 May 2015 at 12:57:35 UTC, Logan Capaldo wrote:
>
> a.dll provides symbol s1
> b.dll provides symbol s1
>
> c.dll imports symbol s1 from a.dll, provides symbol s2
> d.dll imports symbol s1 from b.dll, provides symbol s3
>
> e.exe imports symbol s2 from c.dll, imports symbol s3 from d.dll. e.exe only needs the import libs from c.dll and d.dll.
>
> You're patching the import tables at runtime correct?. If you patch c and d's import tables their s1 import is going to end up pointing at the same symbol.
>
> I can build a.dll and c.dll completely independently of d.dll and b.dll. There's no opportunity to prevent this at compile time. Likewise e.exe doesn't know or care s1 exists so it builds fine as well. You don't need a.lib or b.lib to build e.exe.

Yes, but exactly the same behavior is currently in place on linux. Also your example is quite a corner case, the usual use case where you wan't symbols of multiple instances of the same template to be merged is more common. I don't see any real use case in D where it would be important that the duplicated s1 symbols are not merged. Non D dlls will not be touched and if you really need that behavior you can always put your non D code in a seperate Dll to avoid this behavior.
May 13, 2015
On Wednesday, 13 May 2015 at 13:31:15 UTC, Benjamin Thaut wrote:
> On Wednesday, 13 May 2015 at 12:57:35 UTC, Logan Capaldo wrote:
>>
>> a.dll provides symbol s1
>> b.dll provides symbol s1
>>
>> c.dll imports symbol s1 from a.dll, provides symbol s2
>> d.dll imports symbol s1 from b.dll, provides symbol s3
>>
>> e.exe imports symbol s2 from c.dll, imports symbol s3 from d.dll. e.exe only needs the import libs from c.dll and d.dll.
>>
>> You're patching the import tables at runtime correct?. If you patch c and d's import tables their s1 import is going to end up pointing at the same symbol.
>>
>> I can build a.dll and c.dll completely independently of d.dll and b.dll. There's no opportunity to prevent this at compile time. Likewise e.exe doesn't know or care s1 exists so it builds fine as well. You don't need a.lib or b.lib to build e.exe.
>
> Yes, but exactly the same behavior is currently in place on linux. Also your example is quite a corner case, the usual use case where you wan't symbols of multiple instances of the same template to be merged is more common.

Imagine a is msvcr90.dll and b is msvcr100.dll. Or a is msvcrt.dll. Or a is mfc100u.dll and b is mfc110u.dll. This happens all the time, and all we need is for c and d to have a little bit of D in them.

Linux (thankfully) doesn't typically have N versions of libc floating around.

I _think_ if you only do this for D-mangled symbols you'll get 99% of the benefits (doing the right things for templates etc.) without causing problems for the "corner cases".