summaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-02-28 15:47:52 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-02-28 17:49:01 +0100
commit1027dc459204894f4503f713a3d73826e4bbab15 (patch)
tree606564b15e0978c77c76d0e618c00c25a78aaf38 /libphobos
parent430c89274d7f82810724126637ffdc5507d442f0 (diff)
d: Merge upstream dmd cf63dd8e5, druntime caf14b0f, phobos 41aaf8c26.
D front-end changes: - Import dmd v2.099.0-rc.1. - The `main' can now return type `noreturn' and supports return inference. D Runtime changes: - Import druntime v2.099.0-rc.1. - C bindings for stat_t on powerpc-linux has been fixed. Phobos changes: - Import phobos v2.099.0-rc.1. gcc/d/ChangeLog: * d-target.cc (Target::_init): Initialize C type size fields. * dmd/MERGE: Merge upstream dmd cf63dd8e5. * dmd/VERSION: Update version to v2.099.0-rc.1. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime caf14b0f. * src/MERGE: Merge upstream phobos 41aaf8c26. gcc/testsuite/ChangeLog: * gdc.dg/torture/simd7413a.d: Update. * gdc.dg/ubsan/pr88957.d: Update. * gdc.dg/simd18489.d: New test. * gdc.dg/torture/simd21727.d: New test.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/core/gc/gcinterface.d4
-rw-r--r--libphobos/libdruntime/core/internal/gc/bits.d12
-rw-r--r--libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d257
-rw-r--r--libphobos/libdruntime/core/internal/gc/pooltable.d29
-rw-r--r--libphobos/libdruntime/core/internal/gc/proxy.d4
-rw-r--r--libphobos/libdruntime/core/memory.d4
-rw-r--r--libphobos/libdruntime/core/stdcpp/string.d8
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/stat.d85
-rw-r--r--libphobos/libdruntime/core/time.d158
-rw-r--r--libphobos/libdruntime/object.d13
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/file.d4
-rw-r--r--libphobos/src/std/getopt.d8
-rw-r--r--libphobos/src/std/range/primitives.d11
-rw-r--r--libphobos/src/std/sumtype.d108
16 files changed, 439 insertions, 270 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 49f6ae282e0..7c0bb573e2b 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-55528bd1e963d858eaa63901fc818b957c349fbc
+caf14b0f4ebbae4157aac89368d6278332ee2aa1
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/core/gc/gcinterface.d b/libphobos/libdruntime/core/gc/gcinterface.d
index e8cdf1109ad..5560c6229ca 100644
--- a/libphobos/libdruntime/core/gc/gcinterface.d
+++ b/libphobos/libdruntime/core/gc/gcinterface.d
@@ -141,13 +141,13 @@ interface GC
* Retrieve statistics about garbage collection.
* Useful for debugging and tuning.
*/
- core.memory.GC.Stats stats() nothrow;
+ core.memory.GC.Stats stats() @safe nothrow @nogc;
/**
* Retrieve profile statistics about garbage collection.
* Useful for debugging and tuning.
*/
- core.memory.GC.ProfileStats profileStats() nothrow @safe;
+ core.memory.GC.ProfileStats profileStats() @safe nothrow @nogc;
/**
* add p to list of roots
diff --git a/libphobos/libdruntime/core/internal/gc/bits.d b/libphobos/libdruntime/core/internal/gc/bits.d
index d50c38f0d21..3c1bb543460 100644
--- a/libphobos/libdruntime/core/internal/gc/bits.d
+++ b/libphobos/libdruntime/core/internal/gc/bits.d
@@ -60,7 +60,7 @@ struct GCBits
onOutOfMemoryError();
}
- wordtype test(size_t i) const nothrow
+ wordtype test(size_t i) const scope @trusted pure nothrow @nogc
in
{
assert(i < nbits);
@@ -70,7 +70,7 @@ struct GCBits
return core.bitop.bt(data, i);
}
- int set(size_t i) nothrow
+ int set(size_t i) scope @trusted pure nothrow @nogc
in
{
assert(i < nbits);
@@ -80,7 +80,7 @@ struct GCBits
return core.bitop.bts(data, i);
}
- int clear(size_t i) nothrow
+ int clear(size_t i) scope @trusted pure nothrow @nogc
in
{
assert(i <= nbits);
@@ -91,7 +91,7 @@ struct GCBits
}
// return non-zero if bit already set
- size_t setLocked(size_t i) nothrow
+ size_t setLocked(size_t i) scope @trusted pure nothrow @nogc
{
version (GNU)
{
@@ -112,7 +112,7 @@ struct GCBits
}
else version (D_InlineAsm_X86)
{
- asm @nogc nothrow {
+ asm pure @nogc nothrow {
mov EAX, this;
mov ECX, data[EAX];
mov EDX, i;
@@ -123,7 +123,7 @@ struct GCBits
}
else version (D_InlineAsm_X86_64)
{
- asm @nogc nothrow {
+ asm pure @nogc nothrow {
mov RAX, this;
mov RAX, data[RAX];
mov RDX, i;
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index 87c45fb2872..aa51867fc2c 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -38,6 +38,8 @@ import core.gc.config;
import core.gc.gcinterface;
import core.internal.container.treap;
+import core.internal.spinlock;
+import core.internal.gc.pooltable;
import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
import core.stdc.string : memcpy, memset, memmove;
@@ -145,7 +147,6 @@ class ConservativeGC : GC
Gcx *gcx; // implementation
- import core.internal.spinlock;
static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.lengthy);
static bool _inFinalizer;
__gshared bool isPrecise = false;
@@ -155,7 +156,7 @@ class ConservativeGC : GC
*
* Throws: InvalidMemoryOperationError on recursive locking during finalization.
*/
- static void lockNR() @nogc nothrow
+ static void lockNR() @safe @nogc nothrow
{
if (_inFinalizer)
onInvalidMemoryOperationError();
@@ -685,7 +686,7 @@ class ConservativeGC : GC
else if (pagenum + newsz <= pool.npages)
{
// Attempt to expand in place (TODO: merge with extend)
- if (lpool.pagetable[pagenum + psz] != B_FREE)
+ if (lpool.pagetable[pagenum + psz] != Bins.B_FREE)
return doMalloc();
auto newPages = newsz - psz;
@@ -695,7 +696,7 @@ class ConservativeGC : GC
debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
debug (PRINTF) printFreeInfo(pool);
- memset(&lpool.pagetable[pagenum + psz], B_PAGEPLUS, newPages);
+ memset(&lpool.pagetable[pagenum + psz], Bins.B_PAGEPLUS, newPages);
lpool.bPageOffsets[pagenum] = cast(uint) newsz;
for (auto offset = psz; offset < newsz; offset++)
lpool.bPageOffsets[pagenum + offset] = cast(uint) offset;
@@ -766,7 +767,7 @@ class ConservativeGC : GC
auto lpool = cast(LargeObjectPool*) pool;
size_t pagenum = lpool.pagenumOf(p);
- if (lpool.pagetable[pagenum] != B_PAGE)
+ if (lpool.pagetable[pagenum] != Bins.B_PAGE)
return 0;
size_t psz = lpool.bPageOffsets[pagenum];
@@ -777,7 +778,7 @@ class ConservativeGC : GC
if (pagenum + psz >= lpool.npages)
return 0;
- if (lpool.pagetable[pagenum + psz] != B_FREE)
+ if (lpool.pagetable[pagenum + psz] != Bins.B_FREE)
return 0;
size_t freesz = lpool.bPageOffsets[pagenum + psz];
@@ -785,7 +786,7 @@ class ConservativeGC : GC
return 0;
size_t sz = freesz > maxsz ? maxsz : freesz;
debug (MEMSTOMP) memset(pool.baseAddr + (pagenum + psz) * PAGESIZE, 0xF0, sz * PAGESIZE);
- memset(lpool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
+ memset(lpool.pagetable + pagenum + psz, Bins.B_PAGEPLUS, sz);
lpool.bPageOffsets[pagenum] = cast(uint) (psz + sz);
for (auto offset = psz; offset < psz + sz; offset++)
lpool.bPageOffsets[pagenum + offset] = cast(uint) offset;
@@ -874,11 +875,11 @@ class ConservativeGC : GC
debug(PRINTF) printf("pool base = %p, PAGENUM = %d of %d, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]);
debug(PRINTF) if (pool.isLargeObject) printf("Block size = %d\n", pool.bPageOffsets[pagenum]);
- bin = cast(Bins)pool.pagetable[pagenum];
+ bin = pool.pagetable[pagenum];
// Verify that the pointer is at the beginning of a block,
// no action should be taken if p is an interior pointer
- if (bin > B_PAGE) // B_PAGEPLUS or B_FREE
+ if (bin > Bins.B_PAGE) // B_PAGEPLUS or B_FREE
return;
size_t off = (sentinel_sub(p) - pool.baseAddr);
size_t base = baseOffset(off, bin);
@@ -893,7 +894,7 @@ class ConservativeGC : GC
if (pool.isLargeObject) // if large alloc
{
biti = cast(size_t)(p - pool.baseAddr) >> pool.ShiftBy.Large;
- assert(bin == B_PAGE);
+ assert(bin == Bins.B_PAGE);
auto lpool = cast(LargeObjectPool*) pool;
// Free pages
@@ -1094,13 +1095,13 @@ class ConservativeGC : GC
pool = gcx.findPool(p);
assert(pool);
pagenum = pool.pagenumOf(p);
- bin = cast(Bins)pool.pagetable[pagenum];
- assert(bin <= B_PAGE);
+ bin = pool.pagetable[pagenum];
+ assert(bin <= Bins.B_PAGE);
assert(p == cast(void*)baseOffset(cast(size_t)p, bin));
debug (PTRCHECK2)
{
- if (bin < B_PAGE)
+ if (bin < Bins.B_PAGE)
{
// Check that p is not on a free list
List *list;
@@ -1299,7 +1300,7 @@ class ConservativeGC : GC
}
- core.memory.GC.Stats stats() nothrow
+ core.memory.GC.Stats stats() @safe nothrow @nogc
{
typeof(return) ret;
@@ -1332,13 +1333,20 @@ class ConservativeGC : GC
//
// Implementation of getStats
//
- private void getStatsNoSync(out core.memory.GC.Stats stats) nothrow
+ private void getStatsNoSync(out core.memory.GC.Stats stats) @trusted nothrow @nogc
{
- foreach (pool; gcx.pooltable[0 .. gcx.npools])
+ // This function is trusted for two reasons: `pool.pagetable` is a pointer,
+ // which is being sliced in the below foreach, and so is `binPageChain`,
+ // also sliced a bit later in this function.
+ // However, both usages are safe as long as the assumption that `npools`
+ // defines the limit for `pagetable`'s length holds true (see allocation).
+ // The slicing happens at __LINE__ + 4 and __LINE__ + 24.
+ // `@trusted` delegates are not used to prevent any performance issue.
+ foreach (pool; gcx.pooltable[])
{
foreach (bin; pool.pagetable[0 .. pool.npages])
{
- if (bin == B_FREE)
+ if (bin == Bins.B_FREE)
stats.freeSize += PAGESIZE;
else
stats.usedSize += PAGESIZE;
@@ -1346,13 +1354,13 @@ class ConservativeGC : GC
}
size_t freeListSize;
- foreach (n; 0 .. B_PAGE)
+ foreach (n; 0 .. Bins.B_PAGE)
{
immutable sz = binsize[n];
for (List *list = gcx.bucket[n]; list; list = list.next)
freeListSize += sz;
- foreach (pool; gcx.pooltable[0 .. gcx.npools])
+ foreach (pool; gcx.pooltable[])
{
if (pool.isLargeObject)
continue;
@@ -1381,7 +1389,7 @@ enum
}
-enum
+enum Bins : ubyte
{
B_16,
B_32,
@@ -1405,10 +1413,6 @@ enum
B_MAX,
}
-
-alias ubyte Bins;
-
-
struct List
{
List *next;
@@ -1416,12 +1420,12 @@ struct List
}
// non power of two sizes optimized for small remainder within page (<= 64 bytes)
-immutable short[B_NUMSMALL + 1] binsize = [ 16, 32, 48, 64, 96, 128, 176, 256, 368, 512, 816, 1024, 1360, 2048, 4096 ];
-immutable short[PAGESIZE / 16][B_NUMSMALL + 1] binbase = calcBinBase();
+immutable short[Bins.B_NUMSMALL + 1] binsize = [ 16, 32, 48, 64, 96, 128, 176, 256, 368, 512, 816, 1024, 1360, 2048, 4096 ];
+immutable short[PAGESIZE / 16][Bins.B_NUMSMALL + 1] binbase = calcBinBase();
-short[PAGESIZE / 16][B_NUMSMALL + 1] calcBinBase()
+short[PAGESIZE / 16][Bins.B_NUMSMALL + 1] calcBinBase()
{
- short[PAGESIZE / 16][B_NUMSMALL + 1] bin;
+ short[PAGESIZE / 16][Bins.B_NUMSMALL + 1] bin;
foreach (i, size; binsize)
{
@@ -1440,7 +1444,7 @@ short[PAGESIZE / 16][B_NUMSMALL + 1] calcBinBase()
size_t baseOffset(size_t offset, Bins bin) @nogc nothrow
{
- assert(bin <= B_PAGE);
+ assert(bin <= Bins.B_PAGE);
return (offset & ~(PAGESIZE - 1)) + binbase[bin][(offset & (PAGESIZE - 1)) >> 4];
}
@@ -1448,9 +1452,9 @@ alias PageBits = GCBits.wordtype[PAGESIZE / 16 / GCBits.BITS_PER_WORD];
static assert(PAGESIZE % (GCBits.BITS_PER_WORD * 16) == 0);
// bitmask with bits set at base offsets of objects
-immutable PageBits[B_NUMSMALL] baseOffsetBits = (){
- PageBits[B_NUMSMALL] bits;
- foreach (bin; 0..B_NUMSMALL)
+immutable PageBits[Bins.B_NUMSMALL] baseOffsetBits = (){
+ PageBits[Bins.B_NUMSMALL] bits;
+ foreach (bin; 0 .. Bins.B_NUMSMALL)
{
size_t size = binsize[bin];
const top = PAGESIZE - size + 1; // ensure <size> bytes available even if unaligned
@@ -1475,7 +1479,6 @@ private void set(ref PageBits bits, size_t i) @nogc pure nothrow
struct Gcx
{
- import core.internal.spinlock;
auto rootsLock = shared(AlignedSpinLock)(SpinLock.Contention.brief);
auto rangesLock = shared(AlignedSpinLock)(SpinLock.Contention.brief);
Treap!Root roots;
@@ -1491,11 +1494,9 @@ struct Gcx
debug(INVARIANT) bool inCollection;
uint disabled; // turn off collections if >0
- import core.internal.gc.pooltable;
- private @property size_t npools() pure const nothrow { return pooltable.length; }
PoolTable!Pool pooltable;
- List*[B_NUMSMALL] bucket; // free list for each small size
+ List*[Bins.B_NUMSMALL] bucket; // free list for each small size
// run a collection when reaching those thresholds (number of used pages)
float smallCollectThreshold, largeCollectThreshold;
@@ -1508,7 +1509,7 @@ struct Gcx
else
alias leakDetector = LeakDetector;
- SmallObjectPool*[B_NUMSMALL] recoverPool;
+ SmallObjectPool*[Bins.B_NUMSMALL] recoverPool;
version (Posix) __gshared Gcx* instance;
void initialize()
@@ -1592,9 +1593,8 @@ struct Gcx
debug(INVARIANT) initialized = false;
- for (size_t i = 0; i < npools; i++)
+ foreach (Pool* pool; this.pooltable[])
{
- Pool *pool = pooltable[i];
mappedPages -= pool.npages;
pool.Dtor();
cstdlib.free(pool);
@@ -1635,7 +1635,7 @@ struct Gcx
if (!inCollection)
(cast()rangesLock).unlock();
- for (size_t i = 0; i < B_NUMSMALL; i++)
+ for (size_t i = 0; i < Bins.B_NUMSMALL; i++)
{
size_t j = 0;
List* prev, pprev, ppprev; // keep a short history to inspect in the debugger
@@ -1752,7 +1752,7 @@ struct Gcx
ConservativeGC._inFinalizer = true;
scope (failure) ConservativeGC._inFinalizer = false;
- foreach (pool; pooltable[0 .. npools])
+ foreach (pool; this.pooltable[])
{
if (!pool.finals.nbits) continue;
@@ -1816,18 +1816,18 @@ struct Gcx
/**
* Computes the bin table using CTFE.
*/
- static byte[2049] ctfeBins() nothrow
+ static Bins[2049] ctfeBins() nothrow
{
- byte[2049] ret;
+ Bins[2049] ret;
size_t p = 0;
- for (Bins b = B_16; b <= B_2048; b++)
+ for (Bins b = Bins.B_16; b <= Bins.B_2048; b++)
for ( ; p <= binsize[b]; p++)
ret[p] = b;
return ret;
}
- static const byte[2049] binTable = ctfeBins();
+ static immutable Bins[2049] binTable = ctfeBins();
/**
* Allocate a new pool of at least size bytes.
@@ -1994,7 +1994,7 @@ struct Gcx
bool tryAlloc() nothrow
{
- foreach (p; pooltable[0 .. npools])
+ foreach (p; this.pooltable[])
{
if (!p.isLargeObject || p.freepages < npages)
continue;
@@ -2094,10 +2094,11 @@ struct Gcx
}
// Allocate successively larger pools up to 8 megs
- if (npools)
- { size_t n;
+ if (this.pooltable.length)
+ {
+ size_t n;
- n = config.minPoolSize + config.incPoolSize * npools;
+ n = config.minPoolSize + config.incPoolSize * this.pooltable.length;
if (n > config.maxPoolSize)
n = config.maxPoolSize; // cap pool size
n /= PAGESIZE; // convert bytes to pages
@@ -2139,9 +2140,8 @@ struct Gcx
List* allocPage(Bins bin) nothrow
{
//debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin);
- for (size_t n = 0; n < npools; n++)
+ foreach (Pool* pool; this.pooltable[])
{
- Pool* pool = pooltable[n];
if (pool.isLargeObject)
continue;
if (List* p = (cast(SmallObjectPool*)pool).allocPage(bin))
@@ -2275,7 +2275,7 @@ struct Gcx
// let dmd allocate a register for this.pools
auto pools = pooltable.pools;
- const highpool = pooltable.npools - 1;
+ const highpool = pooltable.length - 1;
const minAddr = pooltable.minAddr;
size_t memSize = pooltable.maxAddr - minAddr;
Pool* pool = null;
@@ -2300,7 +2300,6 @@ struct Gcx
bitpos -= rng.bmplength;
rng.pbase += rng.bmplength;
}
- import core.bitop;
if (!core.bitop.bt(rng.ptrbmp, bitpos))
{
debug(MARK_PRINTF) printf("\t\tskipping non-pointer\n");
@@ -2335,7 +2334,7 @@ struct Gcx
printf("\t\tfound pool %p, base=%p, pn = %lld, bin = %d\n", pool, pool.baseAddr, cast(long)pn, bin);
// Adjust bit to be at start of allocated memory block
- if (bin < B_PAGE)
+ if (bin < Bins.B_PAGE)
{
// We don't care abou setting pointsToBase correctly
// because it's ignored for small object pools anyhow.
@@ -2356,7 +2355,7 @@ struct Gcx
goto LaddRange;
}
}
- else if (bin == B_PAGE)
+ else if (bin == Bins.B_PAGE)
{
biti = offset >> Pool.ShiftBy.Large;
//debug(PRINTF) printf("\t\tbiti = x%x\n", biti);
@@ -2376,7 +2375,7 @@ struct Gcx
goto LaddLargeRange;
}
}
- else if (bin == B_PAGEPLUS)
+ else if (bin == Bins.B_PAGEPLUS)
{
pn -= pool.bPageOffsets[pn];
biti = pn * (PAGESIZE >> Pool.ShiftBy.Large);
@@ -2429,7 +2428,7 @@ struct Gcx
else
{
// Don't mark bits in B_FREE pages
- assert(bin == B_FREE);
+ assert(bin == Bins.B_FREE);
}
}
LnextPtr:
@@ -2526,9 +2525,8 @@ struct Gcx
{
debug(COLLECT_PRINTF) printf("preparing mark.\n");
- for (size_t n = 0; n < npools; n++)
+ foreach (Pool* pool; this.pooltable[])
{
- Pool* pool = pooltable[n];
if (pool.isLargeObject)
pool.mark.zero();
else
@@ -2598,10 +2596,9 @@ struct Gcx
size_t freedLargePages;
size_t freedSmallPages;
size_t freed;
- for (size_t n = 0; n < npools; n++)
+ foreach (Pool* pool; this.pooltable[])
{
size_t pn;
- Pool* pool = pooltable[n];
if (pool.isLargeObject)
{
@@ -2612,12 +2609,12 @@ struct Gcx
{
npages = pool.bPageOffsets[pn];
Bins bin = cast(Bins)pool.pagetable[pn];
- if (bin == B_FREE)
+ if (bin == Bins.B_FREE)
{
numFree += npages;
continue;
}
- assert(bin == B_PAGE);
+ assert(bin == Bins.B_PAGE);
size_t biti = pn;
if (!pool.mark.test(biti))
@@ -2637,7 +2634,7 @@ struct Gcx
debug(COLLECT_PRINTF) printf("\tcollecting big %p\n", p);
leakDetector.log_free(q, sentinel_size(q, npages * PAGESIZE - SENTINEL_EXTRA));
- pool.pagetable[pn..pn+npages] = B_FREE;
+ pool.pagetable[pn..pn+npages] = Bins.B_FREE;
if (pn < pool.searchStart) pool.searchStart = pn;
freedLargePages += npages;
pool.freepages += npages;
@@ -2671,7 +2668,7 @@ struct Gcx
{
Bins bin = cast(Bins)pool.pagetable[pn];
- if (bin < B_PAGE)
+ if (bin < Bins.B_PAGE)
{
auto freebitsdata = pool.freebits.data + pn * PageBits.length;
auto markdata = pool.mark.data + pn * PageBits.length;
@@ -2767,7 +2764,7 @@ struct Gcx
{
pool.freeAllPageBits(pn);
- pool.pagetable[pn] = B_FREE;
+ pool.pagetable[pn] = Bins.B_FREE;
// add to free chain
pool.binPageChain[pn] = cast(uint) pool.searchStart;
pool.searchStart = pn;
@@ -2789,7 +2786,8 @@ struct Gcx
assert(freedLargePages <= usedLargePages);
usedLargePages -= freedLargePages;
- debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedLargePages, npools);
+ debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n",
+ freed, freedLargePages, this.pooltable.length);
assert(freedSmallPages <= usedSmallPages);
usedSmallPages -= freedSmallPages;
@@ -2854,12 +2852,12 @@ struct Gcx
private SmallObjectPool* setNextRecoverPool(Bins bin, size_t poolIndex) nothrow
{
Pool* pool;
- while (poolIndex < npools &&
- ((pool = pooltable[poolIndex]).isLargeObject ||
+ while (poolIndex < this.pooltable.length &&
+ ((pool = this.pooltable[poolIndex]).isLargeObject ||
pool.recoverPageFirst[bin] >= pool.npages))
poolIndex++;
- return recoverPool[bin] = poolIndex < npools ? cast(SmallObjectPool*)pool : null;
+ return recoverPool[bin] = poolIndex < this.pooltable.length ? cast(SmallObjectPool*)pool : null;
}
version (COLLECT_FORK)
@@ -2928,7 +2926,6 @@ struct Gcx
import core.stdc.stdlib : _Exit;
debug (PRINTF_TO_FILE)
{
- import core.stdc.stdio : fflush;
fflush(null); // avoid duplicated FILE* output
}
version (OSX)
@@ -3153,7 +3150,7 @@ Lmark:
// init bucket lists
bucket[] = null;
- foreach (Bins bin; 0..B_NUMSMALL)
+ foreach (Bins bin; Bins.B_16 .. Bins.B_NUMSMALL)
setNextRecoverPool(bin, 0);
stop = currTime;
@@ -3188,24 +3185,24 @@ Lmark:
auto pn = offset / PAGESIZE;
auto bins = cast(Bins)pool.pagetable[pn];
size_t biti = void;
- if (bins < B_PAGE)
+ if (bins < Bins.B_PAGE)
{
biti = baseOffset(offset, bins) >> pool.ShiftBy.Small;
// doesn't need to check freebits because no pointer must exist
// to a block that was free before starting the collection
}
- else if (bins == B_PAGE)
+ else if (bins == Bins.B_PAGE)
{
biti = pn * (PAGESIZE >> pool.ShiftBy.Large);
}
- else if (bins == B_PAGEPLUS)
+ else if (bins == Bins.B_PAGEPLUS)
{
pn -= pool.bPageOffsets[pn];
biti = pn * (PAGESIZE >> pool.ShiftBy.Large);
}
- else // bins == B_FREE
+ else // bins == Bins.B_FREE
{
- assert(bins == B_FREE);
+ assert(bins == Bins.B_FREE);
return IsMarked.no;
}
return pool.mark.test(biti) ? IsMarked.yes : IsMarked.no;
@@ -3262,8 +3259,11 @@ Lmark:
/* ============================ Parallel scanning =============================== */
version (COLLECT_PARALLEL):
- import core.sync.event;
+
import core.atomic;
+ import core.cpuid;
+ import core.sync.event;
+
private: // disable invariants for background threads
static struct ScanThreadData
@@ -3334,7 +3334,6 @@ Lmark:
int maxParallelThreads() nothrow
{
- import core.cpuid;
auto threads = threadsPerCPU();
if (threads == 0)
@@ -3512,7 +3511,7 @@ struct Pool
GCBits is_pointer; // precise GC only: per-word, not per-block like the rest of them (SmallObjectPool only)
size_t npages;
size_t freepages; // The number of pages not in use.
- ubyte* pagetable;
+ Bins* pagetable;
bool isLargeObject;
@@ -3541,7 +3540,7 @@ struct Pool
enum PageRecovered = uint.max;
// first of chain of pages to recover (SmallObjectPool only)
- uint[B_NUMSMALL] recoverPageFirst;
+ uint[Bins.B_NUMSMALL] recoverPageFirst;
// precise GC: TypeInfo.rtInfo for allocation (LargeObjectPool only)
immutable(size_t)** rtinfo;
@@ -3611,7 +3610,7 @@ struct Pool
noscan.alloc(nbits);
appendable.alloc(nbits);
- pagetable = cast(ubyte*)cstdlib.malloc(npages);
+ pagetable = cast(Bins*)cstdlib.malloc(npages * Bins.sizeof);
if (!pagetable)
onOutOfMemoryErrorNoGC();
@@ -3635,7 +3634,7 @@ struct Pool
}
}
- memset(pagetable, B_FREE, npages);
+ memset(pagetable, Bins.B_FREE, npages);
this.npages = npages;
this.freepages = npages;
@@ -3852,7 +3851,7 @@ struct Pool
}
public
- @property bool isFree() const pure nothrow
+ @property bool isFree() const scope @safe pure nothrow @nogc
{
return npages == freepages;
}
@@ -3883,10 +3882,10 @@ struct Pool
{
size_t offset = cast(size_t)(p - baseAddr);
size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pagetable[pn];
+ Bins bin = pagetable[pn];
// Adjust bit to be at start of allocated memory block
- if (bin < B_NUMSMALL)
+ if (bin < Bins.B_NUMSMALL)
{
auto baseOff = baseOffset(offset, bin);
const biti = baseOff >> Pool.ShiftBy.Small;
@@ -3894,11 +3893,11 @@ struct Pool
return null;
return baseAddr + baseOff;
}
- if (bin == B_PAGE)
+ if (bin == Bins.B_PAGE)
{
return baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
}
- if (bin == B_PAGEPLUS)
+ if (bin == Bins.B_PAGEPLUS)
{
size_t pageOffset = bPageOffsets[pn];
offset -= pageOffset * PAGESIZE;
@@ -3907,7 +3906,7 @@ struct Pool
return baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
}
// we are in a B_FREE page
- assert(bin == B_FREE);
+ assert(bin == Bins.B_FREE);
return null;
}
@@ -3944,8 +3943,8 @@ struct Pool
{
for (size_t i = 0; i < npages; i++)
{
- Bins bin = cast(Bins)pagetable[i];
- assert(bin < B_MAX);
+ Bins bin = pagetable[i];
+ assert(bin < Bins.B_MAX);
}
}
}
@@ -4053,19 +4052,19 @@ struct LargeObjectPool
uint np = bPageOffsets[n];
assert(np > 0 && np <= npages - n);
- if (pagetable[n] == B_PAGE)
+ if (pagetable[n] == Bins.B_PAGE)
{
for (uint p = 1; p < np; p++)
{
- assert(pagetable[n + p] == B_PAGEPLUS);
+ assert(pagetable[n + p] == Bins.B_PAGEPLUS);
assert(bPageOffsets[n + p] == p);
}
}
- else if (pagetable[n] == B_FREE)
+ else if (pagetable[n] == Bins.B_FREE)
{
for (uint p = 1; p < np; p++)
{
- assert(pagetable[n + p] == B_FREE);
+ assert(pagetable[n + p] == Bins.B_FREE);
}
assert(bPageOffsets[n + np - 1] == np);
}
@@ -4086,17 +4085,17 @@ struct LargeObjectPool
//debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n);
size_t largest = 0;
- if (pagetable[searchStart] == B_PAGEPLUS)
+ if (pagetable[searchStart] == Bins.B_PAGEPLUS)
{
searchStart -= bPageOffsets[searchStart]; // jump to B_PAGE
searchStart += bPageOffsets[searchStart];
}
- while (searchStart < npages && pagetable[searchStart] == B_PAGE)
+ while (searchStart < npages && pagetable[searchStart] == Bins.B_PAGE)
searchStart += bPageOffsets[searchStart];
for (size_t i = searchStart; i < npages; )
{
- assert(pagetable[i] == B_FREE);
+ assert(pagetable[i] == Bins.B_FREE);
auto p = bPageOffsets[i];
if (p > n)
@@ -4107,11 +4106,11 @@ struct LargeObjectPool
if (p == n)
{
L_found:
- pagetable[i] = B_PAGE;
+ pagetable[i] = Bins.B_PAGE;
bPageOffsets[i] = cast(uint) n;
if (n > 1)
{
- memset(&pagetable[i + 1], B_PAGEPLUS, n - 1);
+ memset(&pagetable[i + 1], Bins.B_PAGEPLUS, n - 1);
for (auto offset = 1; offset < n; offset++)
bPageOffsets[i + offset] = cast(uint) offset;
}
@@ -4122,7 +4121,7 @@ struct LargeObjectPool
largest = p;
i += p;
- while (i < npages && pagetable[i] == B_PAGE)
+ while (i < npages && pagetable[i] == Bins.B_PAGE)
{
// we have the size information, so we skip a whole bunch of pages.
i += bPageOffsets[i];
@@ -4145,8 +4144,8 @@ struct LargeObjectPool
for (size_t i = pagenum; i < npages + pagenum; i++)
{
- assert(pagetable[i] < B_FREE);
- pagetable[i] = B_FREE;
+ assert(pagetable[i] < Bins.B_FREE);
+ pagetable[i] = Bins.B_FREE;
}
freepages += npages;
largestFree = freepages; // invalidate
@@ -4157,8 +4156,8 @@ struct LargeObjectPool
*/
void setFreePageOffsets(size_t page, size_t num) nothrow @nogc
{
- assert(pagetable[page] == B_FREE);
- assert(pagetable[page + num - 1] == B_FREE);
+ assert(pagetable[page] == Bins.B_FREE);
+ assert(pagetable[page + num - 1] == Bins.B_FREE);
bPageOffsets[page] = cast(uint)num;
if (num > 1)
bPageOffsets[page + num - 1] = cast(uint)num;
@@ -4168,7 +4167,7 @@ struct LargeObjectPool
{
static if (bwd)
{
- if (page > 0 && pagetable[page - 1] == B_FREE)
+ if (page > 0 && pagetable[page - 1] == Bins.B_FREE)
{
auto sz = bPageOffsets[page - 1];
page -= sz;
@@ -4177,7 +4176,7 @@ struct LargeObjectPool
}
static if (fwd)
{
- if (page + num < npages && pagetable[page + num] == B_FREE)
+ if (page + num < npages && pagetable[page + num] == Bins.B_FREE)
num += bPageOffsets[page + num];
}
setFreePageOffsets(page, num);
@@ -4197,8 +4196,8 @@ struct LargeObjectPool
if (cast(size_t)p & (PAGESIZE - 1)) // check for interior pointer
return 0;
size_t pagenum = pagenumOf(p);
- Bins bin = cast(Bins)pagetable[pagenum];
- if (bin != B_PAGE)
+ Bins bin = pagetable[pagenum];
+ if (bin != Bins.B_PAGE)
return 0;
return bPageOffsets[pagenum];
}
@@ -4208,7 +4207,7 @@ struct LargeObjectPool
*/
size_t getSize(size_t pn) const nothrow @nogc
{
- assert(pagetable[pn] == B_PAGE);
+ assert(pagetable[pn] == Bins.B_PAGE);
return cast(size_t) bPageOffsets[pn] * PAGESIZE;
}
@@ -4221,11 +4220,11 @@ struct LargeObjectPool
size_t offset = cast(size_t)(p - baseAddr);
size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pagetable[pn];
+ Bins bin = pagetable[pn];
- if (bin == B_PAGEPLUS)
+ if (bin == Bins.B_PAGEPLUS)
pn -= bPageOffsets[pn];
- else if (bin != B_PAGE)
+ else if (bin != Bins.B_PAGE)
return info; // no info for free pages
info.base = baseAddr + pn * PAGESIZE;
@@ -4238,8 +4237,8 @@ struct LargeObjectPool
{
foreach (pn; 0 .. npages)
{
- Bins bin = cast(Bins)pagetable[pn];
- if (bin > B_PAGE)
+ Bins bin = pagetable[pn];
+ if (bin > Bins.B_PAGE)
continue;
size_t biti = pn;
@@ -4265,7 +4264,7 @@ struct LargeObjectPool
size_t n = 1;
for (; pn + n < npages; ++n)
- if (pagetable[pn + n] != B_PAGEPLUS)
+ if (pagetable[pn + n] != Bins.B_PAGEPLUS)
break;
debug (MEMSTOMP) memset(baseAddr + pn * PAGESIZE, 0xF3, n * PAGESIZE);
freePages(pn, n);
@@ -4285,7 +4284,7 @@ struct SmallObjectPool
{
//base.Invariant();
uint cntRecover = 0;
- foreach (Bins bin; 0 .. B_NUMSMALL)
+ foreach (Bins bin; Bins.B_16 .. Bins.B_NUMSMALL)
{
for (auto pn = recoverPageFirst[bin]; pn < npages; pn = binPageChain[pn])
{
@@ -4296,7 +4295,7 @@ struct SmallObjectPool
uint cntFree = 0;
for (auto pn = searchStart; pn < npages; pn = binPageChain[pn])
{
- assert(pagetable[pn] == B_FREE);
+ assert(pagetable[pn] == Bins.B_FREE);
cntFree++;
}
assert(cntFree == freepages);
@@ -4315,8 +4314,8 @@ struct SmallObjectPool
do
{
size_t pagenum = pagenumOf(p);
- Bins bin = cast(Bins)pagetable[pagenum];
- assert(bin < B_PAGE);
+ Bins bin = pagetable[pagenum];
+ assert(bin < Bins.B_PAGE);
if (p != cast(void*)baseOffset(cast(size_t)p, bin)) // check for interior pointer
return 0;
const biti = cast(size_t)(p - baseAddr) >> ShiftBy.Small;
@@ -4330,9 +4329,9 @@ struct SmallObjectPool
BlkInfo info;
size_t offset = cast(size_t)(p - baseAddr);
size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pagetable[pn];
+ Bins bin = pagetable[pn];
- if (bin >= B_PAGE)
+ if (bin >= Bins.B_PAGE)
return info;
auto base = cast(void*)baseOffset(cast(size_t)p, bin);
@@ -4352,8 +4351,8 @@ struct SmallObjectPool
{
foreach (pn; 0 .. npages)
{
- Bins bin = cast(Bins)pagetable[pn];
- if (bin >= B_PAGE)
+ Bins bin = pagetable[pn];
+ if (bin >= Bins.B_PAGE)
continue;
immutable size = binsize[bin];
@@ -4404,13 +4403,13 @@ struct SmallObjectPool
if (searchStart >= npages)
return null;
- assert(pagetable[searchStart] == B_FREE);
+ assert(pagetable[searchStart] == Bins.B_FREE);
L1:
size_t pn = searchStart;
searchStart = binPageChain[searchStart];
binPageChain[pn] = Pool.PageRecovered;
- pagetable[pn] = cast(ubyte)bin;
+ pagetable[pn] = bin;
freepages--;
// Convert page to free list
@@ -4537,7 +4536,7 @@ debug(PRINTF) void printFreeInfo(Pool* pool) nothrow
{
uint nReallyFree;
foreach (i; 0..pool.npages) {
- if (pool.pagetable[i] >= B_FREE) nReallyFree++;
+ if (pool.pagetable[i] >= Bins.B_FREE) nReallyFree++;
}
printf("Pool %p: %d really free, %d supposedly free\n", pool, nReallyFree, pool.freepages);
@@ -4770,7 +4769,7 @@ debug (LOGGING)
size_t offset = cast(size_t)(p - pool.baseAddr);
size_t biti;
size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pool.pagetable[pn];
+ Bins bin = pool.pagetable[pn];
biti = (offset & (PAGESIZE - 1)) >> pool.shiftBy;
debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti);
}
@@ -4921,7 +4920,7 @@ unittest
assert(p + (260 << 20) == q);
assert(q + (65 << 20) == r);
GC.free(q);
- // should trigger "assert(bin == B_FREE);" in mark due to dangling pointer q:
+ // should trigger "assert(bin == Bins.B_FREE);" in mark due to dangling pointer q:
GC.collect();
// should trigger "break;" in extendNoSync:
size_t sz = GC.extend(p, 64 << 20, 66 << 20); // trigger size after p large enough (but limited)
diff --git a/libphobos/libdruntime/core/internal/gc/pooltable.d b/libphobos/libdruntime/core/internal/gc/pooltable.d
index 5924f9c1a55..096633825a2 100644
--- a/libphobos/libdruntime/core/internal/gc/pooltable.d
+++ b/libphobos/libdruntime/core/internal/gc/pooltable.d
@@ -13,15 +13,14 @@ struct PoolTable(Pool)
{
import core.stdc.string : memmove;
-nothrow:
- void Dtor()
+ void Dtor() nothrow @nogc
{
cstdlib.free(pools);
pools = null;
npools = 0;
}
- bool insert(Pool* pool)
+ bool insert(Pool* pool) nothrow @nogc
{
auto newpools = cast(Pool **)cstdlib.realloc(pools, (npools + 1) * pools[0].sizeof);
if (!newpools)
@@ -51,25 +50,31 @@ nothrow:
return true;
}
- @property size_t length() pure const
+ @property size_t length() const scope @safe pure nothrow @nogc
{
return npools;
}
- ref inout(Pool*) opIndex(size_t idx) inout pure
+ ref inout(Pool*) opIndex(size_t idx) inout return @trusted pure nothrow @nogc
in { assert(idx < length); }
do
{
return pools[idx];
}
- inout(Pool*)[] opSlice(size_t a, size_t b) inout pure
+ inout(Pool*)[] opSlice(size_t a, size_t b) inout return @trusted pure nothrow @nogc
in { assert(a <= length && b <= length); }
do
{
return pools[a .. b];
}
+ /// Returns: A slice over all pools in this `PoolTable`
+ inout(Pool*)[] opSlice() inout return @trusted pure nothrow @nogc
+ {
+ return this.pools[0 .. this.length];
+ }
+
alias opDollar = length;
/**
@@ -77,7 +82,7 @@ nothrow:
* Return null if not in a Pool.
* Assume pooltable[] is sorted.
*/
- Pool *findPool(void *p) nothrow
+ Pool *findPool(void *p) nothrow @nogc
{
if (p >= minAddr && p < maxAddr)
{
@@ -109,7 +114,7 @@ nothrow:
}
// semi-stable partition, returns right half for which pred is false
- Pool*[] minimize() pure
+ Pool*[] minimize() pure nothrow @nogc
{
static void swap(ref Pool* a, ref Pool* b)
{
@@ -151,7 +156,7 @@ nothrow:
return pools[npools .. len];
}
- void Invariant() const
+ void Invariant() const nothrow @nogc
{
if (!npools) return;
@@ -165,8 +170,8 @@ nothrow:
assert(_maxAddr == pools[npools - 1].topAddr);
}
- @property const(void)* minAddr() pure const { return _minAddr; }
- @property const(void)* maxAddr() pure const { return _maxAddr; }
+ @property const(void)* minAddr() const @safe pure nothrow @nogc { return _minAddr; }
+ @property const(void)* maxAddr() const @safe pure nothrow @nogc { return _maxAddr; }
package:
Pool** pools;
@@ -184,7 +189,7 @@ unittest
{
byte* baseAddr, topAddr;
size_t freepages, npages, ptIndex;
- @property bool isFree() const pure nothrow { return freepages == npages; }
+ @property bool isFree() const scope pure nothrow @nogc { return freepages == npages; }
}
PoolTable!MockPool pooltable;
diff --git a/libphobos/libdruntime/core/internal/gc/proxy.d b/libphobos/libdruntime/core/internal/gc/proxy.d
index 2c89472a558..695ef061a81 100644
--- a/libphobos/libdruntime/core/internal/gc/proxy.d
+++ b/libphobos/libdruntime/core/internal/gc/proxy.d
@@ -209,12 +209,12 @@ extern (C)
return instance.query( p );
}
- core.memory.GC.Stats gc_stats() nothrow
+ core.memory.GC.Stats gc_stats() @safe nothrow @nogc
{
return instance.stats();
}
- core.memory.GC.ProfileStats gc_profileStats() nothrow @safe
+ core.memory.GC.ProfileStats gc_profileStats() @safe nothrow @nogc
{
return instance.profileStats();
}
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index 6ba569a241c..f25ba6f1d46 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -133,7 +133,7 @@ private
}
extern (C) BlkInfo_ gc_query(return scope void* p) pure nothrow;
- extern (C) GC.Stats gc_stats ( ) nothrow @nogc;
+ extern (C) GC.Stats gc_stats ( ) @safe nothrow @nogc;
extern (C) GC.ProfileStats gc_profileStats ( ) nothrow @nogc @safe;
}
@@ -766,7 +766,7 @@ extern(D):
* Returns runtime stats for currently active GC implementation
* See `core.memory.GC.Stats` for list of available metrics.
*/
- static Stats stats() nothrow
+ static Stats stats() @safe nothrow @nogc
{
return gc_stats();
}
diff --git a/libphobos/libdruntime/core/stdcpp/string.d b/libphobos/libdruntime/core/stdcpp/string.d
index 1cdb0f40952..dfec1ec9f7e 100644
--- a/libphobos/libdruntime/core/stdcpp/string.d
+++ b/libphobos/libdruntime/core/stdcpp/string.d
@@ -343,7 +343,7 @@ extern(D):
///
inout(T)* data() inout @safe { return _Get_data()._Myptr; }
///
- inout(T)[] as_array() inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
+ inout(T)[] as_array() return scope inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize][i]; }
@@ -1920,7 +1920,7 @@ extern(D):
///
inout(T)* data() inout @safe { return __get_pointer(); }
///
- inout(T)[] as_array() inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
+ inout(T)[] as_array() return scope inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return __get_pointer()[0 .. size()][i]; }
@@ -2497,8 +2497,8 @@ extern(C++, (StdNamespace)):
extern(D) @safe @nogc:
pragma(inline, true)
{
- ref inout(Alloc) _Getal() inout pure nothrow { return _Mypair._Myval1; }
- ref inout(ValTy) _Get_data() inout pure nothrow { return _Mypair._Myval2; }
+ ref inout(Alloc) _Getal() return inout pure nothrow { return _Mypair._Myval1; }
+ ref inout(ValTy) _Get_data() return inout pure nothrow { return _Mypair._Myval2; }
}
void _Orphan_all() nothrow { _Get_data._Base._Orphan_all(); }
diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d
index 22f4df66455..1fb4e44cbbf 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/stat.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d
@@ -388,50 +388,93 @@ version (linux)
{
struct stat_t
{
- c_ulong st_dev;
- ino_t st_ino;
+ dev_t st_dev;
+ static if (!__USE_FILE_OFFSET64)
+ {
+ ushort __pad1;
+ ino_t st_ino;
+ }
+ else
+ ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
- c_ulong st_rdev;
+ dev_t st_rdev;
+ ushort __pad2;
off_t st_size;
- c_ulong st_blksize;
- c_ulong st_blocks;
- c_ulong st_atime;
- c_ulong st_atime_nsec;
- c_ulong st_mtime;
- c_ulong st_mtime_nsec;
- c_ulong st_ctime;
- c_ulong st_ctime_nsec;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+ static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700)
+ {
+ timespec st_atim;
+ timespec st_mtim;
+ timespec st_ctim;
+ extern(D) @safe @property inout pure nothrow
+ {
+ ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
+ ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
+ ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
+ }
+ }
+ else
+ {
+ time_t st_atime;
+ c_ulong st_atimensec;
+ time_t st_mtime;
+ c_ulong st_mtimensec;
+ time_t st_ctime;
+ c_ulong st_ctimensec;
+ }
c_ulong __unused4;
c_ulong __unused5;
}
+ static if (__USE_FILE_OFFSET64)
+ static assert(stat_t.sizeof == 104);
+ else
+ static assert(stat_t.sizeof == 88);
}
else version (PPC64)
{
struct stat_t
{
- c_ulong st_dev;
+ dev_t st_dev;
ino_t st_ino;
nlink_t st_nlink;
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
- c_ulong st_rdev;
+ int __pad2;
+ dev_t st_rdev;
off_t st_size;
- c_ulong st_blksize;
- c_ulong st_blocks;
- c_ulong st_atime;
- c_ulong st_atime_nsec;
- c_ulong st_mtime;
- c_ulong st_mtime_nsec;
- c_ulong st_ctime;
- c_ulong st_ctime_nsec;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+ static if (_DEFAULT_SOURCE || _XOPEN_SOURCE >= 700)
+ {
+ timespec st_atim;
+ timespec st_mtim;
+ timespec st_ctim;
+ extern(D) @safe @property inout pure nothrow
+ {
+ ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
+ ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
+ ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
+ }
+ }
+ else
+ {
+ time_t st_atime;
+ c_ulong st_atimensec;
+ time_t st_mtime;
+ c_ulong st_mtimensec;
+ time_t st_ctime;
+ c_ulong st_ctimensec;
+ }
c_ulong __unused4;
c_ulong __unused5;
c_ulong __unused6;
}
+ static assert(stat_t.sizeof == 144);
}
else version (RISCV_Any)
{
diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d
index 0ddf62f478c..91f218e27fb 100644
--- a/libphobos/libdruntime/core/time.d
+++ b/libphobos/libdruntime/core/time.d
@@ -496,6 +496,81 @@ assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
+/
struct Duration
{
+ /++
+ Converts this `Duration` to a `string`.
+
+ The string is meant to be human readable, not machine parseable (e.g.
+ whether there is an `'s'` on the end of the unit name usually depends on
+ whether it's plural or not, and empty units are not included unless the
+ Duration is `zero`). Any code needing a specific string format should
+ use `total` or `split` to get the units needed to create the desired
+ string format and create the string itself.
+
+ The format returned by toString may or may not change in the future.
+
+ Params:
+ sink = A sink object, expected to be a delegate or aggregate
+ implementing `opCall` that accepts a `scope const(char)[]`
+ as argument.
+ +/
+ void toString (SinkT) (scope SinkT sink) const scope
+ {
+ static immutable units = [
+ "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs"
+ ];
+
+ static void appListSep(SinkT sink, uint pos, bool last)
+ {
+ if (pos == 0)
+ return;
+ if (!last)
+ sink(", ");
+ else
+ sink(pos == 1 ? " and " : ", and ");
+ }
+
+ static void appUnitVal(string units)(SinkT sink, long val)
+ {
+ immutable plural = val != 1;
+ string unit;
+ static if (units == "seconds")
+ unit = plural ? "secs" : "sec";
+ else static if (units == "msecs")
+ unit = "ms";
+ else static if (units == "usecs")
+ unit = "μs";
+ else
+ unit = plural ? units : units[0 .. $-1];
+ sink(signedToTempString(val));
+ sink(" ");
+ sink(unit);
+ }
+
+ if (_hnsecs == 0)
+ {
+ sink("0 hnsecs");
+ return;
+ }
+
+ long hnsecs = _hnsecs;
+ uint pos;
+ static foreach (unit; units)
+ {
+ if (auto val = splitUnitsFromHNSecs!unit(hnsecs))
+ {
+ appListSep(sink, pos++, hnsecs == 0);
+ appUnitVal!unit(sink, val);
+ }
+ if (hnsecs == 0)
+ return;
+ }
+ if (hnsecs != 0)
+ {
+ appListSep(sink, pos++, true);
+ appUnitVal!"hnsecs"(sink, hnsecs);
+ }
+ }
+
@safe pure:
public:
@@ -1539,71 +1614,12 @@ public:
}
}
-
- /++
- Converts this `Duration` to a `string`.
-
- The string is meant to be human readable, not machine parseable (e.g.
- whether there is an `'s'` on the end of the unit name usually depends on
- whether it's plural or not, and empty units are not included unless the
- Duration is `zero`). Any code needing a specific string format should
- use `total` or `split` to get the units needed to create the desired
- string format and create the string itself.
-
- The format returned by toString may or may not change in the future.
- +/
- string toString() const nothrow pure @safe
+ /// Ditto
+ string toString() const scope nothrow
{
- static void appListSep(ref string res, uint pos, bool last)
- {
- if (pos == 0)
- return;
- if (!last)
- res ~= ", ";
- else
- res ~= pos == 1 ? " and " : ", and ";
- }
-
- static void appUnitVal(string units)(ref string res, long val)
- {
- immutable plural = val != 1;
- string unit;
- static if (units == "seconds")
- unit = plural ? "secs" : "sec";
- else static if (units == "msecs")
- unit = "ms";
- else static if (units == "usecs")
- unit = "μs";
- else
- unit = plural ? units : units[0 .. $-1];
- res ~= signedToTempString(val);
- res ~= " ";
- res ~= unit;
- }
-
- if (_hnsecs == 0)
- return "0 hnsecs";
-
- template TT(T...) { alias T TT; }
- alias units = TT!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs");
-
- long hnsecs = _hnsecs; string res; uint pos;
- foreach (unit; units)
- {
- if (auto val = splitUnitsFromHNSecs!unit(hnsecs))
- {
- appListSep(res, pos++, hnsecs == 0);
- appUnitVal!unit(res, val);
- }
- if (hnsecs == 0)
- break;
- }
- if (hnsecs != 0)
- {
- appListSep(res, pos++, true);
- appUnitVal!"hnsecs"(res, hnsecs);
- }
- return res;
+ string result;
+ this.toString((in char[] data) { result ~= data; });
+ return result;
}
///
@@ -1731,6 +1747,20 @@ unittest
assert(myTime == 123.msecs);
}
+// Ensure `toString` doesn't allocate if the sink doesn't
+version (CoreUnittest) @safe pure nothrow @nogc unittest
+{
+ char[256] buffer; size_t len;
+ scope sink = (in char[] data) {
+ assert(data.length + len <= buffer.length);
+ buffer[len .. len + data.length] = data[];
+ len += data.length;
+ };
+ auto dur = Duration(-12_096_020_900_003);
+ dur.toString(sink);
+ assert(buffer[0 .. len] == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs");
+}
+
/++
Converts a $(D TickDuration) to the given units as either an integral
value or a floating point value.
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index cf7cf967aa6..56a2efe735a 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -2649,13 +2649,18 @@ class Throwable : Object
/**
* Get the message describing the error.
- * Base behavior is to return the `Throwable.msg` field.
- * Override to return some other error message.
+ *
+ * This getter is an alternative way to access the Exception's message,
+ * with the added advantage of being override-able in subclasses.
+ * Subclasses are hence free to do their own memory managements without
+ * being tied to the requirement of providing a `string` in a field.
+ *
+ * The default behavior is to return the `Throwable.msg` field.
*
* Returns:
- * Error message
+ * A message representing the cause of the `Throwable`
*/
- @__future const(char)[] message() const
+ @__future const(char)[] message() const @safe nothrow
{
return this.msg;
}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index b5b939f41b3..e15541e181d 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-1a3e80ec25afab6123cdcfe20186f36f006b68bb
+41aaf8c2636df0e2e3ad39933b321d2b4cd231fa
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index a99c5170afb..b09b82ab85e 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -425,10 +425,10 @@ version (Windows) private void[] readImpl(scope const(char)[] name, scope const(
fileSize = makeUlong(sizeLow, sizeHigh);
return result;
}
- static trustedReadFile(HANDLE hFile, void *lpBuffer, ulong nNumberOfBytesToRead)
+ static trustedReadFile(HANDLE hFile, void *lpBuffer, size_t nNumberOfBytesToRead)
{
// Read by chunks of size < 4GB (Windows API limit)
- ulong totalNumRead = 0;
+ size_t totalNumRead = 0;
while (totalNumRead != nNumberOfBytesToRead)
{
const uint chunkSize = min(nNumberOfBytesToRead - totalNumRead, 0xffff_0000);
diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d
index 482aae6306a..c1c5cd2b36e 100644
--- a/libphobos/src/std/getopt.d
+++ b/libphobos/src/std/getopt.d
@@ -438,7 +438,7 @@ GetoptResult getopt(T...)(ref string[] args, T opts)
}
///
-@system unittest
+@safe unittest
{
auto args = ["prog", "--foo", "-b"];
@@ -1646,11 +1646,13 @@ Params:
text = The text to printed at the beginning of the help output.
opt = The `Option` extracted from the `getopt` parameter.
*/
-void defaultGetoptPrinter(string text, Option[] opt)
+void defaultGetoptPrinter(string text, Option[] opt) @safe
{
import std.stdio : stdout;
+ // stdout global __gshared is trusted with a locked text writer
+ auto w = (() @trusted => stdout.lockingTextWriter())();
- defaultGetoptFormatter(stdout.lockingTextWriter(), text, opt);
+ defaultGetoptFormatter(w, text, opt);
}
/** This function writes the passed text and `Option` into an output range
diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d
index c092a9d0946..31f58fa5fa9 100644
--- a/libphobos/src/std/range/primitives.d
+++ b/libphobos/src/std/range/primitives.d
@@ -2055,9 +2055,14 @@ if (isBidirectionalRange!Range)
}
/**
- Moves the front of `r` out and returns it. Leaves `r.front` in a
- destroyable state that does not allocate any resources (usually equal
- to its `.init` value).
+ Moves the front of `r` out and returns it.
+
+ If `r.front` is a struct with a destructor or copy constructor defined, it
+ is reset to its `.init` value after its value is moved. Otherwise, it is
+ left unchanged.
+
+ In either case, `r.front` is left in a destroyable state that does not
+ allocate any resources.
*/
ElementType!R moveFront(R)(R r)
{
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 5e35a6b9cd5..0dd636ea67b 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -533,15 +533,35 @@ public:
/**
* Assigns a value to a `SumType`.
*
- * Assigning to a `SumType` is `@system` if any of the
- * `SumType`'s members contain pointers or references, since
- * those members may be reachable through external references,
- * and overwriting them could therefore lead to memory
- * corruption.
+ * If any of the `SumType`'s members other than the one being assigned
+ * to contain pointers or references, it is possible for the assignment
+ * to cause memory corruption (see the
+ * ["Memory corruption" example](#memory-corruption) below for an
+ * illustration of how). Therefore, such assignments are considered
+ * `@system`.
*
* An individual assignment can be `@trusted` if the caller can
- * guarantee that there are no outstanding references to $(I any)
- * of the `SumType`'s members when the assignment occurs.
+ * guarantee that there are no outstanding references to any `SumType`
+ * members that contain pointers or references at the time the
+ * assignment occurs.
+ *
+ * Examples:
+ *
+ * $(DIVID memory-corruption, $(H3 Memory corruption))
+ *
+ * This example shows how assignment to a `SumType` can be used to
+ * cause memory corruption in `@system` code. In `@safe` code, the
+ * assignment `s = 123` would not be allowed.
+ *
+ * ---
+ * SumType!(int*, int) s = new int;
+ * s.tryMatch!(
+ * (ref int* p) {
+ * s = 123; // overwrites `p`
+ * return *p; // undefined behavior
+ * }
+ * );
+ * ---
*/
ref SumType opAssign(T rhs);
}
@@ -553,14 +573,35 @@ public:
/**
* Assigns a value to a `SumType`.
*
- * Assigning to a `SumType` is `@system` if any of the `SumType`'s
- * $(I other) members contain pointers or references, since those
- * members may be reachable through external references, and
- * overwriting them could therefore lead to memory corruption.
+ * If any of the `SumType`'s members other than the one being assigned
+ * to contain pointers or references, it is possible for the assignment
+ * to cause memory corruption (see the
+ * ["Memory corruption" example](#memory-corruption) below for an
+ * illustration of how). Therefore, such assignments are considered
+ * `@system`.
*
* An individual assignment can be `@trusted` if the caller can
- * guarantee that, when the assignment occurs, there are no
- * outstanding references to any such members.
+ * guarantee that there are no outstanding references to any `SumType`
+ * members that contain pointers or references at the time the
+ * assignment occurs.
+ *
+ * Examples:
+ *
+ * $(DIVID memory-corruption, $(H3 Memory corruption))
+ *
+ * This example shows how assignment to a `SumType` can be used to
+ * cause memory corruption in `@system` code. In `@safe` code, the
+ * assignment `s = 123` would not be allowed.
+ *
+ * ---
+ * SumType!(int*, int) s = new int;
+ * s.tryMatch!(
+ * (ref int* p) {
+ * s = 123; // overwrites `p`
+ * return *p; // undefined behavior
+ * }
+ * );
+ * ---
*/
ref SumType opAssign(T rhs)
{
@@ -1528,7 +1569,27 @@ private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
}
/// True if `T` is a [SumType] or implicitly converts to one, otherwise false.
-enum bool isSumType(T) = is(T : SumType!Args, Args...);
+template isSumType(T)
+{
+ static if (is(T : SumType!Args, Args...))
+ {
+ enum isSumType = true;
+ }
+ else static if (is(T == struct) && __traits(getAliasThis, T).length > 0)
+ {
+ // Workaround for https://issues.dlang.org/show_bug.cgi?id=21975
+ import std.traits : ReturnType;
+
+ alias AliasThisType = ReturnType!((T t) =>
+ __traits(getMember, t, __traits(getAliasThis, T)[0])
+ );
+ enum isSumType = .isSumType!AliasThisType;
+ }
+ else
+ {
+ enum isSumType = false;
+ }
+}
///
@safe unittest
@@ -1549,6 +1610,25 @@ enum bool isSumType(T) = is(T : SumType!Args, Args...);
assert(!isSumType!ContainsSumType);
}
+@safe unittest
+{
+ static struct AliasThisVar(T)
+ {
+ SumType!T payload;
+ alias payload this;
+ }
+
+ static struct AliasThisFunc(T)
+ {
+ SumType!T payload;
+ ref get() { return payload; }
+ alias get this;
+ }
+
+ static assert(isSumType!(AliasThisVar!int));
+ static assert(isSumType!(AliasThisFunc!int));
+}
+
/**
* Calls a type-appropriate function with the value held in a [SumType].
*