mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-06 14:01:37 +00:00
D front-end changes: - Import latest fixes from v2.112.0-beta.1. - Associative array operations are now lowered to templates defined in `core.internal.newaa'. D runtime changes: - Import latest fixes from v2.112.0-beta.1. Phobos changes: - Import latest fixes from v2.112.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd e1f6680f50. * Make-lang.in (D_FRONTEND_OBJS): Remove d/gluelayer.o, d/iasm.o, d/iasmgcc.o. Add d/iasm-package.o, d/iasm-gcc.o. (d/iasm-%.o): New recipe. * d-convert.cc (convert_expr): Remove library call to dynamic_cast. * d-lang.cc (d_init_options): Set errorSupplementLimit parameter. * decl.cc (DeclVisitor::visit): Update for new front-end interface. * expr.cc (ExprVisitor::visit (EqualExp *)): Update for front-end lowering expression using templates. (ExprVisitor::visit (InExp *)): Likewise. (ExprVisitor::visit (IndexExp *)): Likewise. (ExprVisitor::visit (CastExp *)): Likewise. (ExprVisitor::visit (RemoveExp *)): Likewise. (ExprVisitor::visit (AddrExp *)): Likewise. (ExprVisitor::visit (NewExp *)): Likewise. (ExprVisitor::visit (ArrayLiteralExp *)): Likewise. (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise. * imports.cc (ImportVisitor::visit (AliasDeclaration *)): Update for new front-end interface. * runtime.def (DYNAMIC_CAST): Remove. (INTERFACE_CAST): Remove. (ARRAYLITERALTX): Remove. (ADEQ2): Remove. (ASSOCARRAYLITERALTX): Remove. (AANEW): Remove. (AAEQUAL): Remove. (AAINX): Remove. (AAGETY): Remove. (AAGETRVALUEX): Remove. (AADELX): Remove. * typeinfo.cc (TypeInfoVisitor::visit): Layout xopEquals and xtoHash in TypeInfo_AssociativeArray. (create_typeinfo): Add new fields to internal typeinfo. (check_typeinfo_type): Print instantiation trace of error. * types.cc (TypeVisitor::visit (TypeStruct *)): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e1f6680f50. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/cast_.d. Remove rt/aaA.d, rt/adi.d, rt/cast_.d. (DRUNTIME_DSOURCES_POSIX): Add core/sys/posix/endian.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos f87979028. * src/Makefile.am (PHOBOS_DSOURCES): Add std/internal/entropy.d. * src/Makefile.in: Regenerate. * testsuite/libphobos.aa/test_aa.d: Adjust test. * testsuite/libphobos.init_fini/custom_gc.d: Likewise. gcc/testsuite/ChangeLog: * gdc.dg/asm1.d: Adjust test. * gdc.dg/asm5.d: Likewise. * gdc.dg/pr100967.d: Likewise. * gdc.dg/rtti1.d: Likewise. * gdc.dg/rtti2.d: New test.
257 lines
7.5 KiB
D
257 lines
7.5 KiB
D
/**
|
|
BlkInfo thread-local cache. Used for array appending in the conservative GC to avoid the lock when possible.
|
|
|
|
Note: this used to be in rt.lifetime, but was moved here to allow GCs to take over array operations.
|
|
*/
|
|
module core.internal.gc.blkcache;
|
|
|
|
import core.memory;
|
|
import core.attribute;
|
|
|
|
debug (PRINTF) import core.stdc.stdio : printf;
|
|
|
|
alias BlkInfo = GC.BlkInfo;
|
|
alias BlkAttr = GC.BlkAttr;
|
|
|
|
/**
|
|
cache for the lookup of the block info
|
|
*/
|
|
private enum N_CACHE_BLOCKS = 8;
|
|
|
|
// note this is TLS, so no need to sync.
|
|
BlkInfo *__blkcache_storage;
|
|
|
|
static if (N_CACHE_BLOCKS == 1)
|
|
{
|
|
version=single_cache;
|
|
}
|
|
else
|
|
{
|
|
//version=simple_cache; // uncomment to test simple cache strategy
|
|
//version=random_cache; // uncomment to test random cache strategy
|
|
|
|
// ensure N_CACHE_BLOCKS is power of 2.
|
|
static assert(!((N_CACHE_BLOCKS - 1) & N_CACHE_BLOCKS));
|
|
|
|
version (random_cache)
|
|
{
|
|
int __nextRndNum = 0;
|
|
}
|
|
int __nextBlkIdx;
|
|
}
|
|
|
|
@property BlkInfo *__blkcache() nothrow @nogc
|
|
{
|
|
if (!__blkcache_storage)
|
|
{
|
|
import core.stdc.stdlib : calloc;
|
|
import core.thread.threadbase;
|
|
auto tBase = ThreadBase.getThis();
|
|
if (tBase is null)
|
|
// if we don't have a thread object, this is a detached thread, and
|
|
// this won't be properly maintained by the GC.
|
|
return null;
|
|
|
|
// allocate the block cache for the first time
|
|
immutable size = BlkInfo.sizeof * N_CACHE_BLOCKS;
|
|
// use C alloc, because this may become a detached thread, and the GC
|
|
// would then clean up the cache without zeroing this pointer.
|
|
__blkcache_storage = cast(BlkInfo*) calloc(size, 1);
|
|
tBase.tlsGCData = __blkcache_storage;
|
|
}
|
|
return __blkcache_storage;
|
|
}
|
|
|
|
// free the allocation on thread exit.
|
|
void cleanupBlkCache(void* storage) nothrow @nogc
|
|
{
|
|
if (storage)
|
|
{
|
|
// check if this is the same thread as the current running thread, and
|
|
// if so, make sure we don't leave a dangling pointer.
|
|
if (__blkcache_storage is storage)
|
|
__blkcache_storage = null;
|
|
import core.stdc.stdlib : free;
|
|
free(storage);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates whether an address has been marked by the GC.
|
|
*/
|
|
enum IsMarked : int
|
|
{
|
|
no, /// Address is not marked.
|
|
yes, /// Address is marked.
|
|
unknown, /// Address is not managed by the GC.
|
|
}
|
|
|
|
alias IsMarkedDg = IsMarked delegate(void* addr) nothrow; /// The isMarked callback function.
|
|
|
|
// we expect this to be called with the lock in place
|
|
void processGCMarks(void* data, scope IsMarkedDg isMarked) nothrow
|
|
{
|
|
if (!data)
|
|
return;
|
|
|
|
auto cache = cast(BlkInfo*) data;
|
|
// called after the mark routine to eliminate block cache data when it
|
|
// might be ready to sweep
|
|
|
|
debug(PRINTF) printf("processing GC Marks, %p\n", cache);
|
|
debug(PRINTF) foreach (i; 0 .. N_CACHE_BLOCKS)
|
|
{
|
|
printf("cache entry %d has base ptr %p\tsize %zd\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr);
|
|
}
|
|
auto cache_end = cache + N_CACHE_BLOCKS;
|
|
for (;cache < cache_end; ++cache)
|
|
{
|
|
if (cache.base != null && isMarked(cache.base) == IsMarked.no)
|
|
{
|
|
debug(PRINTF) printf("clearing cache entry at %p\n", cache.base);
|
|
cache.base = null; // clear that data.
|
|
}
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
// Bugzilla 10701 - segfault in GC
|
|
ubyte[] result; result.length = 4096;
|
|
GC.free(result.ptr);
|
|
GC.collect();
|
|
}
|
|
|
|
/**
|
|
Get the cached block info of an interior pointer. Returns null if the
|
|
interior pointer's block is not cached.
|
|
|
|
NOTE: The following note was not valid, but is retained for historical
|
|
purposes. The data cannot be cleared because the stack contains a
|
|
reference to the affected block (e.g. through `interior`). Therefore,
|
|
the element will not be collected, and the data will remain valid.
|
|
|
|
ORIGINAL: The base ptr in this struct can be cleared asynchronously by the GC,
|
|
so any use of the returned BlkInfo should copy it and then check the
|
|
base ptr of the copy before actually using it.
|
|
*/
|
|
BlkInfo *__getBlkInfo(void *interior) nothrow @nogc
|
|
{
|
|
BlkInfo *ptr = __blkcache;
|
|
if (ptr is null)
|
|
// if for some reason we don't have a cache, return null.
|
|
return null;
|
|
version (single_cache)
|
|
{
|
|
if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
|
|
return ptr;
|
|
return null; // not in cache.
|
|
}
|
|
else version (simple_cache)
|
|
{
|
|
foreach (i; 0..N_CACHE_BLOCKS)
|
|
{
|
|
if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
|
|
return ptr;
|
|
ptr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// try to do a smart lookup, using __nextBlkIdx as the "head"
|
|
auto curi = ptr + __nextBlkIdx;
|
|
for (auto i = curi; i >= ptr; --i)
|
|
{
|
|
if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
|
|
return i;
|
|
}
|
|
|
|
for (auto i = ptr + N_CACHE_BLOCKS - 1; i > curi; --i)
|
|
{
|
|
if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
|
|
return i;
|
|
}
|
|
}
|
|
return null; // not in cache.
|
|
}
|
|
|
|
void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow @nogc
|
|
{
|
|
auto cache = __blkcache;
|
|
if (cache is null)
|
|
// no cache to use.
|
|
return;
|
|
|
|
version (single_cache)
|
|
{
|
|
*cache = bi;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
version (simple_cache)
|
|
{
|
|
if (curpos)
|
|
*curpos = bi;
|
|
else
|
|
{
|
|
// note, this is a super-simple algorithm that does not care about
|
|
// most recently used. It simply uses a round-robin technique to
|
|
// cache block info. This means that the ordering of the cache
|
|
// doesn't mean anything. Certain patterns of allocation may
|
|
// render the cache near-useless.
|
|
cache[__nextBlkIdx] = bi;
|
|
__nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
|
|
}
|
|
}
|
|
else version (random_cache)
|
|
{
|
|
// strategy: if the block currently is in the cache, move the
|
|
// current block index to the a random element and evict that
|
|
// element.
|
|
if (!curpos)
|
|
{
|
|
__nextBlkIdx = (__nextRndNum = 1664525 * __nextRndNum + 1013904223) & (N_CACHE_BLOCKS - 1);
|
|
curpos = cache + __nextBlkIdx;
|
|
}
|
|
else
|
|
{
|
|
__nextBlkIdx = curpos - cache;
|
|
}
|
|
*curpos = bi;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// strategy: If the block currently is in the cache, swap it with
|
|
// the head element. Otherwise, move the head element up by one,
|
|
// and insert it there.
|
|
//
|
|
if (!curpos)
|
|
{
|
|
__nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
|
|
curpos = cache + __nextBlkIdx;
|
|
}
|
|
else if (curpos !is cache + __nextBlkIdx)
|
|
{
|
|
*curpos = cache[__nextBlkIdx];
|
|
curpos = cache + __nextBlkIdx;
|
|
}
|
|
*curpos = bi;
|
|
}
|
|
}
|
|
}
|
|
|
|
debug(PRINTF)
|
|
{
|
|
extern(C) void printArrayCache()
|
|
{
|
|
auto ptr = __blkcache;
|
|
printf("CACHE: \n");
|
|
foreach (i; 0 .. N_CACHE_BLOCKS)
|
|
{
|
|
printf(" %d\taddr:% .8p\tsize:% .10zd\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr);
|
|
}
|
|
}
|
|
}
|