From 25ba7578460c8e58705901b34fcef4251ce4cdfd Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 27 Jun 2021 18:14:12 +0200 Subject: [PATCH 1/2] Use core.lifetime.emplace() building block instead of manual reinventions --- src/core/exception.d | 4 ++-- src/core/internal/container/common.d | 9 ++------- src/core/internal/gc/impl/conservative/gc.d | 14 ++++---------- src/core/internal/gc/impl/manual/gc.d | 13 ++++--------- src/core/sync/mutex.d | 10 +++------- src/core/thread/fiber.d | 7 +++---- src/core/thread/threadbase.d | 12 +++++------- src/rt/sections_elf_shared.d | 2 +- 8 files changed, 24 insertions(+), 47 deletions(-) diff --git a/src/core/exception.d b/src/core/exception.d index 423298a136..93be7fd331 100644 --- a/src/core/exception.d +++ b/src/core/exception.d @@ -655,11 +655,11 @@ private T staticError(T, Args...)(auto ref Args args) else auto store = &_store; - (*store)[0 .. __traits(classInstanceSize, T)] = typeid(T).initializer[]; return cast(T) store.ptr; } auto res = (cast(T function() @trusted pure nothrow @nogc) &get)(); - res.__ctor(args); + import core.lifetime : emplace; + emplace(res, args); return res; } diff --git a/src/core/internal/container/common.d b/src/core/internal/container/common.d index 2483252207..582d63ba2a 100644 --- a/src/core/internal/container/common.d +++ b/src/core/internal/container/common.d @@ -44,13 +44,8 @@ void destroy(T)(ref T t) if (!is(T == struct)) void initialize(T)(ref T t) if (is(T == struct)) { - import core.stdc.string; - static if (__traits(isPOD, T)) // implies !hasElaborateAssign!T && !hasElaborateDestructor!T - t = T.init; - else static if (__traits(isZeroInit, T)) - memset(&t, 0, T.sizeof); - else - memcpy(&t, typeid(T).initializer().ptr, T.sizeof); + import core.internal.lifetime : emplaceInitializer; + emplaceInitializer(t); } void initialize(T)(ref T t) if (!is(T == struct)) diff --git a/src/core/internal/gc/impl/conservative/gc.d b/src/core/internal/gc/impl/conservative/gc.d index 7d5f322ebd..d16c5737d3 100644 --- a/src/core/internal/gc/impl/conservative/gc.d +++ b/src/core/internal/gc/impl/conservative/gc.d @@ -115,19 +115,13 @@ extern(C) pragma(crt_constructor) void _d_register_precise_gc() private GC initialize() { - import core.stdc.string: memcpy; + import core.lifetime : emplace; - auto p = cstdlib.malloc(__traits(classInstanceSize, ConservativeGC)); - - if (!p) + auto gc = cast(ConservativeGC) cstdlib.malloc(__traits(classInstanceSize, ConservativeGC)); + if (!gc) onOutOfMemoryErrorNoGC(); - auto init = typeid(ConservativeGC).initializer(); - assert(init.length == __traits(classInstanceSize, ConservativeGC)); - auto instance = cast(ConservativeGC) memcpy(p, init.ptr, init.length); - instance.__ctor(); - - return instance; + return emplace(gc); } private GC initialize_precise() diff --git a/src/core/internal/gc/impl/manual/gc.d b/src/core/internal/gc/impl/manual/gc.d index 21f1c69f2b..38c9148e22 100644 --- a/src/core/internal/gc/impl/manual/gc.d +++ b/src/core/internal/gc/impl/manual/gc.d @@ -37,18 +37,13 @@ extern(C) pragma(crt_constructor) void _d_register_manual_gc() private GC initialize() { - import core.stdc.string: memcpy; + import core.lifetime : emplace; - auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC)); - if (!p) + auto gc = cast(ManualGC) cstdlib.malloc(__traits(classInstanceSize, ManualGC)); + if (!gc) onOutOfMemoryError(); - auto init = typeid(ManualGC).initializer(); - assert(init.length == __traits(classInstanceSize, ManualGC)); - auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length); - instance.__ctor(); - - return instance; + return emplace(gc); } class ManualGC : GC diff --git a/src/core/sync/mutex.d b/src/core/sync/mutex.d index 4c120bc9ee..b153ab9aef 100644 --- a/src/core/sync/mutex.d +++ b/src/core/sync/mutex.d @@ -345,14 +345,10 @@ unittest @system @nogc nothrow unittest { import core.stdc.stdlib : malloc, free; + import core.lifetime : emplace; - void* p = malloc(__traits(classInstanceSize, Mutex)); - - auto ti = typeid(Mutex); - p[0 .. ti.initializer.length] = ti.initializer[]; - - shared Mutex mtx = cast(shared(Mutex)) p; - mtx.__ctor(); + auto mtx = cast(shared Mutex) malloc(__traits(classInstanceSize, Mutex)); + emplace(mtx); mtx.lock_nothrow(); diff --git a/src/core/thread/fiber.d b/src/core/thread/fiber.d index 8f6d30c65f..5b8a842929 100644 --- a/src/core/thread/fiber.d +++ b/src/core/thread/fiber.d @@ -1916,11 +1916,10 @@ private: import core.stdc.stdlib : malloc; import core.thread.threadbase : ThreadException; enum threadExceptionSize = __traits(classInstanceSize, ThreadException); - if (void* p = malloc(threadExceptionSize)) + if (auto e = cast(ThreadException) malloc(threadExceptionSize)) { - p[0 .. threadExceptionSize] = typeid(ThreadException).initializer[]; - auto e = cast(ThreadException) p; - e.__ctor( + import core.lifetime : emplace; + emplace(e, "Migrating Fibers between Threads on this platform may lead " ~ "to incorrect thread local variable access. To allow " ~ "migration anyway, call Fiber.allowMigration()"); diff --git a/src/core/thread/threadbase.d b/src/core/thread/threadbase.d index c2c2333efe..eb2e71ee05 100644 --- a/src/core/thread/threadbase.d +++ b/src/core/thread/threadbase.d @@ -569,11 +569,9 @@ package(core.thread): static void initLocks() @nogc { - _slock[] = typeid(Mutex).initializer[]; - (cast(Mutex)_slock.ptr).__ctor(); - - _criticalRegionLock[] = typeid(Mutex).initializer[]; - (cast(Mutex)_criticalRegionLock.ptr).__ctor(); + import core.lifetime : emplace; + emplace!Mutex(_slock[]); + emplace!Mutex(_criticalRegionLock[]); } static void termLocks() @nogc @@ -1334,8 +1332,8 @@ package void initLowlevelThreads() @nogc { - ll_lock[] = typeid(Mutex).initializer[]; - lowlevelLock.__ctor(); + import core.lifetime : emplace; + emplace(lowlevelLock()); } void termLowlevelThreads() @nogc diff --git a/src/rt/sections_elf_shared.d b/src/rt/sections_elf_shared.d index 701b56d34d..4bdb009123 100644 --- a/src/rt/sections_elf_shared.d +++ b/src/rt/sections_elf_shared.d @@ -536,7 +536,7 @@ package extern(C) void _d_dso_registry(void* arg) if (firstDSO) initLocks(); DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof); - assert(typeid(DSO).initializer().ptr is null); + static assert(__traits(isZeroInit, DSO)); pdso._slot = data._slot; *data._slot = pdso; // store backlink in library record From 7946ce1cdf864025101b88243dd0c2eae5f014b5 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 27 Jun 2021 18:16:57 +0200 Subject: [PATCH 2/2] LDC: Prefer __traits(initSymbol) over TypeInfo.initializer() --- src/core/demangle.d | 9 +++++-- src/core/internal/lifetime.d | 50 +++++++++++++++--------------------- src/core/lifetime.d | 17 ++++++++++-- src/core/sync/mutex.d | 10 ++++++-- src/core/thread/osthread.d | 4 ++- src/core/thread/threadbase.d | 4 ++- src/object.d | 12 +++++++-- src/rt/aaA.d | 5 +++- 8 files changed, 71 insertions(+), 40 deletions(-) diff --git a/src/core/demangle.d b/src/core/demangle.d index 8e25d419ee..466b00fb9c 100644 --- a/src/core/demangle.d +++ b/src/core/demangle.d @@ -31,6 +31,9 @@ private struct NoHooks // static char[] parseType(ref Demangle, char[]) } +version (LDC) private enum isLDC = true; +else private enum isLDC = false; + private struct Demangle(Hooks = NoHooks) { // NOTE: This implementation currently only works with mangled function @@ -104,7 +107,8 @@ pure @safe: //throw new ParseException( msg ); debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); - throw __ctfe ? new ParseException(msg) + throw __ctfe ? new ParseException(msg) : + isLDC ? cast(ParseException) __traits(initSymbol, ParseException).ptr : cast(ParseException) cast(void*) typeid(ParseException).initializer; } @@ -116,7 +120,8 @@ pure @safe: //throw new OverflowException( msg ); debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); - throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer; + throw isLDC ? cast(OverflowException) __traits(initSymbol, OverflowException).ptr + : cast(OverflowException) cast(void*) typeid(OverflowException).initializer; } diff --git a/src/core/internal/lifetime.d b/src/core/internal/lifetime.d index 7e9b5f2ad4..2d61fb9e65 100644 --- a/src/core/internal/lifetime.d +++ b/src/core/internal/lifetime.d @@ -89,44 +89,36 @@ Emplaces T.init. In contrast to `emplaceRef(chunk)`, there are no checks for disabled default constructors etc. +/ -template emplaceInitializer(T) +// LDC: simplified via __traits(initSymbol) +void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted if (!is(T == const) && !is(T == immutable) && !is(T == inout)) { - import core.internal.traits : hasElaborateAssign, Unqual; + import core.internal.traits : hasElaborateAssign; - // Avoid stack allocation by hacking to get to the struct/union init symbol. - static if (is(T == struct) || is(T == union)) + static if (__traits(isZeroInit, T)) { - pragma(mangle, "_D" ~ Unqual!T.mangleof[1..$] ~ "6__initZ") - __gshared extern immutable T initializer; + import core.stdc.string : memset; + memset(cast(void*) &chunk, 0, T.sizeof); } - - void emplaceInitializer(scope ref T chunk) nothrow pure @trusted + else static if (__traits(isScalar, T) || + T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) { - static if (__traits(isZeroInit, T)) - { - import core.stdc.string : memset; - memset(cast(void*) &chunk, 0, T.sizeof); - } - else static if (__traits(isScalar, T) || - T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) - { - chunk = T.init; - } - else static if (__traits(isStaticArray, T)) - { - // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. - foreach (i; 0 .. T.length) - { - emplaceInitializer(chunk[i]); - } - } - else + chunk = T.init; + } + else static if (__traits(isStaticArray, T)) + { + // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. + foreach (i; 0 .. T.length) { - import core.stdc.string : memcpy; - memcpy(cast(void*)&chunk, &initializer, T.sizeof); + emplaceInitializer(chunk[i]); } } + else + { + import core.stdc.string : memcpy; + const initializer = __traits(initSymbol, T); + memcpy(cast(void*)&chunk, initializer.ptr, initializer.length); + } } @safe unittest diff --git a/src/core/lifetime.d b/src/core/lifetime.d index 2085b2fb44..61d562a85c 100644 --- a/src/core/lifetime.d +++ b/src/core/lifetime.d @@ -103,8 +103,19 @@ T emplace(T, Args...)(T chunk, auto ref Args args) " is abstract and it can't be emplaced"); // Initialize the object in its pre-ctor state - enum classSize = __traits(classInstanceSize, T); - (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])(); + version (LDC) + { + () @trusted + { + const initializer = __traits(initSymbol, T); + (cast(void*) chunk)[0 .. initializer.length] = initializer[]; + }(); + } + else + { + enum classSize = __traits(classInstanceSize, T); + (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])(); + } static if (isInnerClass!T) { @@ -2121,6 +2132,8 @@ private void moveEmplaceImpl(T)(ref T source, ref T target) static if (__traits(isZeroInit, T)) () @trusted { memset(&source, 0, sz); }(); + else version (LDC) + () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }(); else { auto init = typeid(T).initializer(); diff --git a/src/core/sync/mutex.d b/src/core/sync/mutex.d index b153ab9aef..e45bd4457e 100644 --- a/src/core/sync/mutex.d +++ b/src/core/sync/mutex.d @@ -189,7 +189,10 @@ class Mutex : if (pthread_mutex_lock(&m_hndl) == 0) return; - SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; + version (LDC) + SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr; + else + SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; syncErr.msg = "Unable to lock mutex."; throw syncErr; } @@ -227,7 +230,10 @@ class Mutex : if (pthread_mutex_unlock(&m_hndl) == 0) return; - SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; + version (LDC) + SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr; + else + SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; syncErr.msg = "Unable to unlock mutex."; throw syncErr; } diff --git a/src/core/thread/osthread.d b/src/core/thread/osthread.d index ad00598f82..512498886f 100644 --- a/src/core/thread/osthread.d +++ b/src/core/thread/osthread.d @@ -2205,7 +2205,9 @@ extern (C) void thread_init() @nogc status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } - if (typeid(Thread).initializer.ptr) + version (LDC) + _mainThreadStore[] = __traits(initSymbol, Thread)[]; + else if (typeid(Thread).initializer.ptr) _mainThreadStore[] = typeid(Thread).initializer[]; Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor()); } diff --git a/src/core/thread/threadbase.d b/src/core/thread/threadbase.d index eb2e71ee05..dc7df2870b 100644 --- a/src/core/thread/threadbase.d +++ b/src/core/thread/threadbase.d @@ -767,7 +767,9 @@ package void thread_term_tpl(ThreadT, MainThreadStore)(ref MainThreadStore _main // destruct manually as object.destroy is not @nogc (cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor(); _d_monitordelete_nogc(ThreadBase.sm_main); - if (typeid(ThreadT).initializer.ptr) + version (LDC) + _mainThreadStore[] = __traits(initSymbol, ThreadT)[]; + else if (typeid(ThreadT).initializer.ptr) _mainThreadStore[] = typeid(ThreadT).initializer[]; else (cast(ubyte[])_mainThreadStore)[] = 0; diff --git a/src/object.d b/src/object.d index 2f56d64767..f755fad42e 100644 --- a/src/object.d +++ b/src/object.d @@ -4021,8 +4021,16 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == class)) static if (initialize) { - enum classSize = __traits(classInstanceSize, T); - (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[]; + version (LDC) + { + const initializer = __traits(initSymbol, T); + (cast(void*)obj)[0 .. initializer.length] = initializer[]; + } + else + { + enum classSize = __traits(classInstanceSize, T); + (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[]; + } } } else diff --git a/src/rt/aaA.d b/src/rt/aaA.d index 1174835b0a..e887bc899e 100644 --- a/src/rt/aaA.d +++ b/src/rt/aaA.d @@ -301,7 +301,10 @@ TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo va void* p = GC.malloc(sizeti + (2 + rtisize) * (void*).sizeof); import core.stdc.string : memcpy; - memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti); + version (LDC) + memcpy(p, __traits(initSymbol, TypeInfo_Struct).ptr, sizeti); + else + memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti); auto ti = cast(TypeInfo_Struct) p; auto extra = cast(TypeInfo*)(p + sizeti);