Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 24269b8

Browse files
committed
Fix code bloat regressions wrt. core.internal.lifetime.emplaceInitializer
This partially reverts #2883. The problem is that for every template instantiation, i.e., emplaced type, 2 new structs are generated, each of which comes with its TypeInfo etc. And that includes all types, incl. primitive types and zero-initialized ones. So as before that PR, try to handle the trivial cases first, and only use a (simplified) union version if that's not possible. [The union version in #2883 is probably an improvement over the previously used static constant.] And as Suleyman mentioned that it's code copied from object.d, I went the other way and use emplaceInitializer in object.d to get rid of needless code duplication.
1 parent ce26f60 commit 24269b8

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

src/core/internal/lifetime.d

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,44 @@ if (is(UT == core.internal.traits.Unqual!UT))
8484
emplaceRef!(UT, UT)(chunk, forward!args);
8585
}
8686

87-
//emplace helper functions
88-
private nothrow pure @trusted
87+
/+
88+
Emplaces T.init.
89+
In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
90+
constructors etc.
91+
+/
92+
nothrow pure @trusted
8993
void emplaceInitializer(T)(scope ref T chunk)
9094
{
91-
// Emplace T.init.
92-
// Previously, an immutable static and memcpy were used to hold an initializer.
93-
// With improved unions, this is no longer needed.
94-
union UntypedInit
95+
import core.internal.traits : hasElaborateAssign;
96+
97+
static if (!hasElaborateAssign!T && __traits(compiles, chunk = T.init))
9598
{
96-
T dummy;
99+
chunk = T.init;
97100
}
98-
static struct UntypedStorage
101+
else
99102
{
100-
align(T.alignof) void[T.sizeof] dummy;
101-
}
103+
static if (__traits(isZeroInit, T))
104+
{
105+
static if (is(T U == shared U))
106+
alias Unshared = U;
107+
else
108+
alias Unshared = T;
102109

103-
() @trusted {
104-
*cast(UntypedStorage*) &chunk = cast(UntypedStorage) UntypedInit.init;
105-
} ();
110+
import core.stdc.string : memset;
111+
memset(cast(Unshared*) &chunk, 0, T.sizeof);
112+
}
113+
else
114+
{
115+
// emplace T.init (an rvalue) without extra variable (and according destruction)
116+
alias RawBytes = void[T.sizeof];
117+
118+
static union U
119+
{
120+
T dummy = T.init; // U.init corresponds to T.init
121+
RawBytes data;
122+
}
123+
124+
*cast(RawBytes*) &chunk = U.init.data;
125+
}
126+
}
106127
}

src/object.d

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,21 +3394,8 @@ void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct))
33943394

33953395
static if (initialize)
33963396
{
3397-
// We need to re-initialize `obj`. Previously, an immutable static
3398-
// and memcpy were used to hold an initializer. With improved unions, this is no longer
3399-
// needed.
3400-
union UntypedInit
3401-
{
3402-
T dummy;
3403-
}
3404-
static struct UntypedStorage
3405-
{
3406-
align(T.alignof) void[T.sizeof] dummy;
3407-
}
3408-
3409-
() @trusted {
3410-
*cast(UntypedStorage*) &obj = cast(UntypedStorage) UntypedInit.init;
3411-
} ();
3397+
import core.internal.lifetime : emplaceInitializer;
3398+
emplaceInitializer(obj); // emplace T.init
34123399
}
34133400
}
34143401

0 commit comments

Comments
 (0)