Skip to content

Commit 10dda78

Browse files
committed
Remove almost all blockmeta/cache functionality from rt, using the GC
API instead.
1 parent caad83f commit 10dda78

File tree

5 files changed

+193
-346
lines changed

5 files changed

+193
-346
lines changed

druntime/src/core/internal/array/construction.d

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ T[] _d_newarrayU(T)(size_t length, bool isShared=false) @trusted
349349
{
350350
import core.exception : onOutOfMemoryError;
351351
import core.internal.traits : Unqual;
352-
import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc;
352+
import core.internal.array.utils : __arrayAlloc;
353353

354354
alias UnqT = Unqual!T;
355355

@@ -395,16 +395,11 @@ Loverflow:
395395
assert(0);
396396

397397
Lcontinue:
398-
auto info = __arrayAlloc!UnqT(arraySize);
399-
if (!info.base)
398+
auto arr = __arrayAlloc!UnqT(arraySize);
399+
if (!arr.ptr)
400400
goto Loverflow;
401-
debug(PRINTF) printf("p = %p\n", info.base);
402-
403-
auto arrstart = __arrayStart(info);
404-
405-
__setArrayAllocLength!UnqT(info, arraySize, isShared);
406-
407-
return (cast(T*) arrstart)[0 .. length];
401+
debug(PRINTF) printf("p = %p\n", arr.ptr);
402+
return (cast(T*) arr.ptr)[0 .. length];
408403
}
409404

410405
/// ditto
@@ -522,7 +517,7 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
522517

523518
void[] __allocateInnerArray(size_t[] dims)
524519
{
525-
import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc;
520+
import core.internal.array.utils : __arrayAlloc;
526521

527522
auto dim = dims[0];
528523

@@ -535,15 +530,13 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
535530

536531
auto allocSize = (void[]).sizeof * dim;
537532
// the array-of-arrays holds pointers! Don't use UnqT here!
538-
auto info = __arrayAlloc!(void[])(allocSize);
539-
__setArrayAllocLength!(void[])(info, allocSize, isShared);
540-
auto p = __arrayStart(info)[0 .. dim];
533+
auto arr = __arrayAlloc!(void[])(allocSize);
541534

542535
foreach (i; 0..dim)
543536
{
544-
(cast(void[]*)p.ptr)[i] = __allocateInnerArray(dims[1..$]);
537+
(cast(void[]*)arr.ptr)[i] = __allocateInnerArray(dims[1..$]);
545538
}
546-
return p;
539+
return arr;
547540
}
548541

549542
auto result = __allocateInnerArray(dims);

druntime/src/core/internal/array/utils.d

Lines changed: 7 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,8 @@ module core.internal.array.utils;
1212
import core.internal.traits : Parameters;
1313
import core.memory : GC;
1414

15-
alias BlkInfo = GC.BlkInfo;
1615
alias BlkAttr = GC.BlkAttr;
1716

18-
private
19-
{
20-
enum : size_t
21-
{
22-
PAGESIZE = 4096,
23-
BIGLENGTHMASK = ~(PAGESIZE - 1),
24-
SMALLPAD = 1,
25-
MEDPAD = ushort.sizeof,
26-
LARGEPREFIX = 16, // 16 bytes padding at the front of the array
27-
LARGEPAD = LARGEPREFIX + 1,
28-
MAXSMALLSIZE = 256-SMALLPAD,
29-
MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD
30-
}
31-
}
32-
3317
auto gcStatsPure() nothrow pure
3418
{
3519
import core.memory : GC;
@@ -156,55 +140,21 @@ template isPostblitNoThrow(T) {
156140
}
157141

158142
/**
159-
* Clear padding that might not be zeroed by the GC (it assumes it is within the
160-
* requested size from the start, but it is actually at the end of the allocated
161-
* block).
162-
*
163-
* Params:
164-
* info = array allocation data
165-
* arrSize = size of the array in bytes
166-
* padSize = size of the padding in bytes
167-
*/
168-
void __arrayClearPad()(ref BlkInfo info, size_t arrSize, size_t padSize) nothrow pure
169-
{
170-
import core.stdc.string;
171-
if (padSize > MEDPAD && !(info.attr & BlkAttr.NO_SCAN) && info.base)
172-
{
173-
if (info.size < PAGESIZE)
174-
memset(info.base + arrSize, 0, padSize);
175-
else
176-
memset(info.base, 0, LARGEPREFIX);
177-
}
178-
}
179-
180-
/**
181-
* Allocate an array memory block by applying the proper padding and assigning
182-
* block attributes if not inherited from the existing block.
143+
* Allocate a memory block with appendable capabilities for array usage.
183144
*
184145
* Params:
185146
* arrSize = size of the allocated array in bytes
186147
* Returns:
187-
* `BlkInfo` with allocation metadata
148+
* `void[]` matching requested size on success, `null` on failure.
188149
*/
189-
BlkInfo __arrayAlloc(T)(size_t arrSize) @trusted
150+
void[] __arrayAlloc(T)(size_t arrSize) @trusted
190151
{
191-
import core.checkedint;
192152
import core.lifetime : TypeInfoSize;
193153
import core.internal.traits : hasIndirections;
194154

195155
enum typeInfoSize = TypeInfoSize!T;
196156
BlkAttr attr = BlkAttr.APPENDABLE;
197157

198-
size_t padSize = arrSize > MAXMEDSIZE ?
199-
LARGEPAD :
200-
((arrSize > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + typeInfoSize);
201-
202-
bool overflow;
203-
auto paddedSize = addu(arrSize, padSize, overflow);
204-
205-
if (overflow)
206-
return BlkInfo();
207-
208158
/* `extern(C++)` classes don't have a classinfo pointer in their vtable,
209159
* so the GC can't finalize them.
210160
*/
@@ -213,59 +163,8 @@ BlkInfo __arrayAlloc(T)(size_t arrSize) @trusted
213163
static if (!hasIndirections!T)
214164
attr |= BlkAttr.NO_SCAN;
215165

216-
auto bi = GC.qalloc(paddedSize, attr, typeid(T));
217-
__arrayClearPad(bi, arrSize, padSize);
218-
return bi;
219-
}
220-
221-
/**
222-
* Get the start of the array for the given block.
223-
*
224-
* Params:
225-
* info = array metadata
226-
* Returns:
227-
* pointer to the start of the array
228-
*/
229-
void *__arrayStart()(return scope BlkInfo info) nothrow pure
230-
{
231-
return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
232-
}
233-
234-
/**
235-
* Set the allocated length of the array block. This is called when an array
236-
* is appended to or its length is set.
237-
*
238-
* The allocated block looks like this for blocks < PAGESIZE:
239-
* `|elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize|`
240-
*
241-
* The size of the allocated length at the end depends on the block size:
242-
* a block of 16 to 256 bytes has an 8-bit length.
243-
* a block with 512 to pagesize/2 bytes has a 16-bit length.
244-
*
245-
* For blocks >= pagesize, the length is a size_t and is at the beginning of the
246-
* block. The reason we have to do this is because the block can extend into
247-
* more pages, so we cannot trust the block length if it sits at the end of the
248-
* block, because it might have just been extended. If we can prove in the
249-
* future that the block is unshared, we may be able to change this, but I'm not
250-
* sure it's important.
251-
*
252-
* In order to do put the length at the front, we have to provide 16 bytes
253-
* buffer space in case the block has to be aligned properly. In x86, certain
254-
* SSE instructions will only work if the data is 16-byte aligned. In addition,
255-
* we need the sentinel byte to prevent accidental pointers to the next block.
256-
* Because of the extra overhead, we only do this for page size and above, where
257-
* the overhead is minimal compared to the block size.
258-
*
259-
* So for those blocks, it looks like:
260-
* `|N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte|``
261-
*
262-
* where `elem0` starts 16 bytes after the first byte.
263-
*/
264-
bool __setArrayAllocLength(T)(ref BlkInfo info, size_t newLength, bool isShared, size_t oldLength = ~0)
265-
{
266-
import core.lifetime : TypeInfoSize;
267-
import core.internal.gc.blockmeta : __setArrayAllocLengthImpl, __setBlockFinalizerInfo;
268-
static if (TypeInfoSize!T)
269-
__setBlockFinalizerInfo(info, typeid(T));
270-
return __setArrayAllocLengthImpl(info, newLength, isShared, oldLength, TypeInfoSize!T);
166+
auto ptr = GC.malloc(arrSize, attr, typeid(T));
167+
if (ptr)
168+
return ptr[0 .. arrSize];
169+
return null;
271170
}

druntime/src/core/internal/gc/blockmeta.d

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,11 @@ size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
6969
7070
where elem0 starts 16 bytes after the first byte.
7171
*/
72-
bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = ~0) pure nothrow
72+
bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = size_t.max) pure nothrow
7373
{
74-
size_t typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
75-
if (typeInfoSize)
76-
__setBlockFinalizerInfo(info, tinext);
74+
__setBlockFinalizerInfo(info, tinext);
7775

76+
size_t typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
7877
return __setArrayAllocLengthImpl(info, newlength, isshared, oldlength, typeInfoSize);
7978
}
8079

@@ -97,7 +96,7 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
9796
return false;
9897

9998
auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
100-
if (oldlength != ~0)
99+
if (oldlength != size_t.max)
101100
{
102101
if (isshared)
103102
{
@@ -123,7 +122,7 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
123122
// new size does not fit inside block
124123
return false;
125124
auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
126-
if (oldlength != ~0)
125+
if (oldlength != size_t.max)
127126
{
128127
if (isshared)
129128
{
@@ -149,7 +148,7 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
149148
// new size does not fit inside block
150149
return false;
151150
auto length = cast(size_t *)(info.base);
152-
if (oldlength != ~0)
151+
if (oldlength != size_t.max)
153152
{
154153
if (isshared)
155154
{
@@ -176,24 +175,44 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
176175
The block finalizer info is set separately from the array length, as that is
177176
only needed on the initial setup of the block. No shared is needed, since
178177
this should only happen when the block is new.
178+
If the STRUCTFINAL bit is not set, no finalizer is stored (but if needed the
179+
slot is zeroed)
179180
*/
180181
void __setBlockFinalizerInfo(ref BlkInfo info, const TypeInfo ti) pure nothrow
181182
{
182183
if ((info.attr & BlkAttr.APPENDABLE) && info.size >= PAGESIZE)
183184
{
185+
// if the structfinal bit is not set, we don't have a finalizer. But we
186+
// should still zero out the finalizer slot.
187+
auto context = (info.attr & BlkAttr.STRUCTFINAL) ? cast(void*)ti : null;
188+
184189
// array used size goes at the beginning. We can stuff the typeinfo
185190
// right after it, as we need to use 16 bytes anyway.
186-
auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
187-
*typeInfo = cast() ti;
191+
//
192+
auto typeInfo = cast(void**)info.base + 1;
193+
*typeInfo = context;
188194
}
189-
else
195+
else if(info.attr & BlkAttr.STRUCTFINAL)
190196
{
191197
// all other cases the typeinfo gets put at the end of the block
192-
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
193-
*typeInfo = cast() ti;
198+
auto typeInfo = cast(void**)(info.base + info.size) - 1;
199+
*typeInfo = cast(void*) ti;
194200
}
195201
}
196202

203+
/**
204+
Get the finalizer info from the block (typeinfo).
205+
Must be called on a block with STRUCTFINAL set.
206+
*/
207+
const(TypeInfo) __getBlockFinalizerInfo(ref BlkInfo info) pure nothrow
208+
{
209+
bool isLargeArray = (info.attr & BlkAttr.APPENDABLE) && info.size >= PAGESIZE;
210+
auto typeInfo = isLargeArray ?
211+
info.base + size_t.sizeof :
212+
info.base + info.size - size_t.sizeof;
213+
return *cast(TypeInfo*)typeInfo;
214+
}
215+
197216
/**
198217
get the used size of the array for the given block
199218
*/
@@ -263,8 +282,22 @@ size_t __allocPad(size_t size, uint bits) nothrow pure @trusted
263282
{
264283
if (size > MAXMEDSIZE - finalizerSize)
265284
return LARGEPAD;
266-
return size > MAXSMALLSIZE - finalizerSize ? MEDPAD : SMALLPAD;
285+
auto pad = (size > MAXSMALLSIZE - finalizerSize) ? MEDPAD : SMALLPAD;
286+
return pad + finalizerSize;
267287
}
268288

269289
return finalizerSize;
270290
}
291+
292+
/**
293+
* Get the start of the array for the given block.
294+
*
295+
* Params:
296+
* info = array metadata
297+
* Returns:
298+
* pointer to the start of the array
299+
*/
300+
void *__arrayStart()(return scope BlkInfo info) nothrow pure
301+
{
302+
return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
303+
}

druntime/src/core/internal/gc/impl/conservative/gc.d

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,14 @@ class ConservativeGC : GC
485485
adjustAttrs(bits, ti);
486486

487487
immutable padding = __allocPad(size, bits);
488-
immutable needed = size + padding;
488+
489+
bool overflow;
490+
import core.checkedint : addu;
491+
immutable needed = addu(size, padding, overflow);
492+
if (overflow)
493+
{
494+
return null;
495+
}
489496

490497
size_t localAllocSize = void;
491498

@@ -585,7 +592,14 @@ class ConservativeGC : GC
585592
adjustAttrs(bits, ti);
586593

587594
immutable padding = __allocPad(size, bits);
588-
immutable needed = size + __allocPad(size, bits);
595+
bool overflow;
596+
import core.checkedint : addu;
597+
immutable needed = addu(size, padding, overflow);
598+
if (overflow)
599+
{
600+
return null;
601+
}
602+
589603

590604
size_t localAllocSize = void;
591605

@@ -5405,13 +5419,13 @@ private void[] setupMetadata(void[] block, uint bits, size_t padding, size_t use
54055419
size: block.length
54065420
);
54075421

5408-
auto typeInfoSize = (bits & BlkAttr.STRUCTFINAL) ? (void*).sizeof : 0;
54095422

5410-
if (typeInfoSize)
5411-
__setBlockFinalizerInfo(info, ti);
5423+
__setBlockFinalizerInfo(info, ti);
54125424

54135425
if (bits & BlkAttr.APPENDABLE) {
5414-
__setArrayAllocLengthImpl(info, used, false, ~0, typeInfoSize);
5426+
auto typeInfoSize = (bits & BlkAttr.STRUCTFINAL) ? (void*).sizeof : 0;
5427+
auto success = __setArrayAllocLengthImpl(info, used, false, size_t.max, typeInfoSize);
5428+
assert(success);
54155429
return __arrayStart(info)[0 .. block.length - padding];
54165430
}
54175431

0 commit comments

Comments
 (0)