mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
Translate _d_newarray{U,iT,T}
to a single template (#15299)
* druntime: Copy array allocation functions to `core.internal.array.utils` This copies `__setArrayAllocLength()`, `__arrayAlloc()` and moves `__arrayStart()` and `__arrayClearPad()` to `core.internal.array.utils.d`. This is needed because `_d_newarrayT()` calls these functions from `rt.lifetime.d`, but the file cannot be imported from `core.internal.array.creation.d`. Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com> * Translate `_d_newarray{U,iT,T}` to a single template This achieves the following: - Convert `_d_newarray{U,iT,T}` to a single template `_d_newarrayT` that handles arrays of elements that either have an init symbol or are zero-initialised. - Move compiler lowering to the semantic phase - Store lowered expression in `NewExp.lowering` Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com> --------- Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
This commit is contained in:
parent
8c7c9bead5
commit
fcff1b51ba
21 changed files with 510 additions and 57 deletions
|
@ -1251,15 +1251,8 @@ elem* toElem(Expression e, ref IRState irs)
|
|||
assert(ne.arguments && ne.arguments.length >= 1);
|
||||
if (ne.arguments.length == 1)
|
||||
{
|
||||
// Single dimension array allocations
|
||||
Expression arg = (*ne.arguments)[0]; // gives array length
|
||||
e = toElem(arg, irs);
|
||||
|
||||
// call _d_newT(ti, arg)
|
||||
e = el_param(e, getTypeInfo(ne, ne.type, irs));
|
||||
const rtl = tda.next.isZeroInit(Loc.initial) ? RTLSYM.NEWARRAYT : RTLSYM.NEWARRAYIT;
|
||||
e = el_bin(OPcall,TYdarray,el_var(getRtlsym(rtl)),e);
|
||||
toTraceGC(irs, e, ne.loc);
|
||||
assert(ne.lowering);
|
||||
e = toElem(ne.lowering, irs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1205,10 +1205,11 @@ extern (C++) abstract class Expression : ASTNode
|
|||
return false;
|
||||
if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
|
||||
return false;
|
||||
/* The original expression (`new S(...)`) will be verified instead. This
|
||||
* is to keep errors related to the original code and not the lowering.
|
||||
/* The original expressions (`new S(...)` or `new S[...]``) will be
|
||||
* verified instead. This is to keep errors related to the original code
|
||||
* and not the lowering.
|
||||
*/
|
||||
if (f.ident == Id._d_newitemT)
|
||||
if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT)
|
||||
return false;
|
||||
|
||||
if (!f.isNogc())
|
||||
|
|
|
@ -4406,6 +4406,58 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
(*exp.arguments)[i] = arg;
|
||||
tb = tb.isTypeDArray().next.toBasetype();
|
||||
}
|
||||
|
||||
if (nargs == 1)
|
||||
{
|
||||
if (global.params.betterC || !sc.needsCodegen())
|
||||
goto LskipNewArrayLowering;
|
||||
|
||||
/* Class types may inherit base classes that have errors.
|
||||
* This may leak errors from the base class to the derived one
|
||||
* and then to the hook. Semantic analysis is performed eagerly
|
||||
* to a void this.
|
||||
*/
|
||||
if (auto tc = exp.type.nextOf.isTypeClass())
|
||||
{
|
||||
tc.sym.dsymbolSemantic(sc);
|
||||
if (tc.sym.errors)
|
||||
goto LskipNewArrayLowering;
|
||||
}
|
||||
|
||||
auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
|
||||
if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
|
||||
goto LskipNewArrayLowering;
|
||||
|
||||
/* Lower the memory allocation and initialization of `new T[n]`
|
||||
* to `_d_newarrayT!T(n)`.
|
||||
*/
|
||||
Expression lowering = new IdentifierExp(exp.loc, Id.empty);
|
||||
lowering = new DotIdExp(exp.loc, lowering, Id.object);
|
||||
auto tiargs = new Objects();
|
||||
/* Remove `inout`, `const`, `immutable` and `shared` to reduce
|
||||
* the number of generated `_d_newarrayT` instances.
|
||||
*/
|
||||
const isShared = exp.type.nextOf.isShared();
|
||||
auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
|
||||
MODFlags.immutable_ | MODFlags.shared_);
|
||||
tiargs.push(t);
|
||||
lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
|
||||
|
||||
auto arguments = new Expressions();
|
||||
if (global.params.tracegc)
|
||||
{
|
||||
auto funcname = (sc.callsc && sc.callsc.func) ?
|
||||
sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
|
||||
arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
|
||||
arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
|
||||
arguments.push(new StringExp(exp.loc, funcname.toDString()));
|
||||
}
|
||||
arguments.push((*exp.arguments)[0]);
|
||||
arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
|
||||
|
||||
lowering = new CallExp(exp.loc, lowering, arguments);
|
||||
exp.lowering = lowering.expressionSemantic(sc);
|
||||
}
|
||||
}
|
||||
else if (tb.isscalar())
|
||||
{
|
||||
|
@ -4447,6 +4499,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return setError();
|
||||
}
|
||||
|
||||
LskipNewArrayLowering:
|
||||
//printf("NewExp: '%s'\n", toChars());
|
||||
//printf("NewExp:type '%s'\n", type.toChars());
|
||||
semanticTypeInfo(sc, exp.type);
|
||||
|
|
|
@ -8769,6 +8769,8 @@ struct Id final
|
|||
static Identifier* _d_newclassTTrace;
|
||||
static Identifier* _d_newitemT;
|
||||
static Identifier* _d_newitemTTrace;
|
||||
static Identifier* _d_newarrayT;
|
||||
static Identifier* _d_newarrayTTrace;
|
||||
static Identifier* _d_assert_fail;
|
||||
static Identifier* dup;
|
||||
static Identifier* _aaApply;
|
||||
|
|
|
@ -321,6 +321,8 @@ immutable Msgtable[] msgtable =
|
|||
{ "_d_newclassTTrace" },
|
||||
{ "_d_newitemT" },
|
||||
{ "_d_newitemTTrace" },
|
||||
{ "_d_newarrayT" },
|
||||
{ "_d_newarrayTTrace" },
|
||||
{ "_d_assert_fail" },
|
||||
{ "dup" },
|
||||
{ "_aaApply" },
|
||||
|
|
|
@ -724,9 +724,20 @@ public:
|
|||
{
|
||||
//printf("NewExp.doInlineAs!%s(): %s\n", Result.stringof.ptr, e.toChars());
|
||||
auto ne = e.copy().isNewExp();
|
||||
auto lowering = ne.lowering;
|
||||
if (lowering)
|
||||
if (auto ce = lowering.isCallExp())
|
||||
if (ce.f.ident == Id._d_newarrayT)
|
||||
{
|
||||
ne.lowering = doInlineAs!Expression(lowering, ids);
|
||||
goto LhasLowering;
|
||||
}
|
||||
|
||||
ne.thisexp = doInlineAs!Expression(e.thisexp, ids);
|
||||
ne.argprefix = doInlineAs!Expression(e.argprefix, ids);
|
||||
ne.arguments = arrayExpressionDoInline(e.arguments);
|
||||
|
||||
LhasLowering:
|
||||
result = ne;
|
||||
|
||||
semanticTypeInfo(null, e.type);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop`
|
||||
fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating
|
||||
fail_compilation/imports/foo10727a.d(31): instantiated from here: `Bar!(Foo)`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop`
|
||||
fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating
|
||||
fail_compilation/imports/foo10727b.d(22): instantiated from here: `Bar!(Foo)`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ REQUIRED_ARGS: -profile=gc
|
|||
RUN_OUTPUT:
|
||||
---
|
||||
bytes allocated, allocations, type, function, file:line
|
||||
96 1 ubyte[] D main runnable/profilegc_stdout.d:17
|
||||
96 1 ubyte D main runnable/profilegc_stdout.d:17
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -11,6 +11,11 @@ module core.internal.array.construction;
|
|||
|
||||
import core.internal.traits : Unqual;
|
||||
|
||||
debug(PRINTF)
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does array initialization (not assignment) from another array of the same element type.
|
||||
* Params:
|
||||
|
@ -319,3 +324,165 @@ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted
|
|||
assert(!didThrow);
|
||||
assert(counter == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an array with the garbage collector. Also initalize elements if
|
||||
* their type has an initializer. Otherwise, not zero-initialize the array.
|
||||
*
|
||||
* Has three variants:
|
||||
* `_d_newarrayU` leaves elements uninitialized
|
||||
* `_d_newarrayT` initializes to 0 or based on initializer
|
||||
*
|
||||
* Params:
|
||||
* length = `.length` of resulting array
|
||||
*
|
||||
* Returns:
|
||||
* newly allocated array
|
||||
*/
|
||||
T[] _d_newarrayU(T)(size_t length, bool isShared=false) pure nothrow @nogc @trusted
|
||||
{
|
||||
alias PureType = T[] function(size_t length, bool isShared) pure nothrow @nogc @trusted;
|
||||
return (cast(PureType) &_d_newarrayUImpl!T)(length, isShared);
|
||||
}
|
||||
|
||||
T[] _d_newarrayUImpl(T)(size_t length, bool isShared=false) @trusted
|
||||
{
|
||||
import core.exception : onOutOfMemoryError;
|
||||
import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc;
|
||||
|
||||
size_t elemSize = T.sizeof;
|
||||
size_t arraySize;
|
||||
|
||||
debug(PRINTF) printf("_d_newarrayU(length = x%zu, size = %zu)\n", length, elemSize);
|
||||
if (length == 0 || elemSize == 0)
|
||||
return null;
|
||||
|
||||
version (D_InlineAsm_X86)
|
||||
{
|
||||
asm pure nothrow @nogc
|
||||
{
|
||||
mov EAX, elemSize ;
|
||||
mul EAX, length ;
|
||||
mov arraySize, EAX ;
|
||||
jnc Lcontinue ;
|
||||
}
|
||||
}
|
||||
else version (D_InlineAsm_X86_64)
|
||||
{
|
||||
asm pure nothrow @nogc
|
||||
{
|
||||
mov RAX, elemSize ;
|
||||
mul RAX, length ;
|
||||
mov arraySize, RAX ;
|
||||
jnc Lcontinue ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
import core.checkedint : mulu;
|
||||
|
||||
bool overflow = false;
|
||||
arraySize = mulu(elemSize, length, overflow);
|
||||
if (!overflow)
|
||||
goto Lcontinue;
|
||||
}
|
||||
|
||||
Loverflow:
|
||||
onOutOfMemoryError();
|
||||
assert(0);
|
||||
|
||||
Lcontinue:
|
||||
auto info = __arrayAlloc!T(arraySize);
|
||||
if (!info.base)
|
||||
goto Loverflow;
|
||||
debug(PRINTF) printf("p = %p\n", info.base);
|
||||
|
||||
auto arrstart = __arrayStart(info);
|
||||
|
||||
__setArrayAllocLength!T(info, arraySize, isShared);
|
||||
|
||||
return (cast(T*) arrstart)[0 .. length];
|
||||
}
|
||||
|
||||
/// ditto
|
||||
T[] _d_newarrayT(T)(size_t length, bool isShared=false) @trusted
|
||||
{
|
||||
T[] result = _d_newarrayU!T(length, isShared);
|
||||
|
||||
static if (__traits(isZeroInit, T))
|
||||
{
|
||||
import core.stdc.string : memset;
|
||||
memset(result.ptr, 0, length * T.sizeof);
|
||||
}
|
||||
else
|
||||
{
|
||||
import core.internal.lifetime : emplaceInitializer;
|
||||
foreach (ref elem; result)
|
||||
emplaceInitializer(elem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
{
|
||||
// zero-initialization
|
||||
struct S { int x, y; }
|
||||
S[] s = _d_newarrayT!S(10);
|
||||
|
||||
assert(s !is null);
|
||||
assert(s.length == 10);
|
||||
foreach (ref elem; s)
|
||||
{
|
||||
assert(elem.x == 0);
|
||||
assert(elem.y == 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
// S.init
|
||||
struct S { int x = 2, y = 3; }
|
||||
S[] s = _d_newarrayT!S(10);
|
||||
|
||||
assert(s.length == 10);
|
||||
foreach (ref elem; s)
|
||||
{
|
||||
assert(elem.x == 2);
|
||||
assert(elem.y == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
int pblits;
|
||||
|
||||
struct S
|
||||
{
|
||||
this(this) { pblits++; }
|
||||
}
|
||||
|
||||
S[] s = _d_newarrayT!S(2);
|
||||
|
||||
assert(s.length == 2);
|
||||
assert(pblits == 0);
|
||||
}
|
||||
|
||||
version (D_ProfileGC)
|
||||
{
|
||||
/**
|
||||
* TraceGC wrapper around $(REF _d_newitemT, core,lifetime).
|
||||
*/
|
||||
T[] _d_newarrayTTrace(T)(string file, int line, string funcname, size_t length, bool isShared) @trusted
|
||||
{
|
||||
version (D_TypeInfo)
|
||||
{
|
||||
import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure;
|
||||
mixin(TraceHook!(T.stringof, "_d_newarrayT"));
|
||||
|
||||
return _d_newarrayT!T(length, isShared);
|
||||
}
|
||||
else
|
||||
assert(0, "Cannot create new array if compiling without support for runtime type information!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,25 @@
|
|||
module core.internal.array.utils;
|
||||
|
||||
import core.internal.traits : Parameters;
|
||||
import core.memory : GC;
|
||||
|
||||
alias BlkInfo = GC.BlkInfo;
|
||||
alias BlkAttr = GC.BlkAttr;
|
||||
|
||||
private
|
||||
{
|
||||
enum : size_t
|
||||
{
|
||||
PAGESIZE = 4096,
|
||||
BIGLENGTHMASK = ~(PAGESIZE - 1),
|
||||
SMALLPAD = 1,
|
||||
MEDPAD = ushort.sizeof,
|
||||
LARGEPREFIX = 16, // 16 bytes padding at the front of the array
|
||||
LARGEPAD = LARGEPREFIX + 1,
|
||||
MAXSMALLSIZE = 256-SMALLPAD,
|
||||
MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD
|
||||
}
|
||||
}
|
||||
|
||||
auto gcStatsPure() nothrow pure
|
||||
{
|
||||
|
@ -136,3 +155,220 @@ template isPostblitNoThrow(T) {
|
|||
else
|
||||
enum isPostblitNoThrow = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear padding that might not be zeroed by the GC (it assumes it is within the
|
||||
* requested size from the start, but it is actually at the end of the allocated
|
||||
* block).
|
||||
*
|
||||
* Params:
|
||||
* info = array allocation data
|
||||
* arrSize = size of the array in bytes
|
||||
* padSize = size of the padding in bytes
|
||||
*/
|
||||
void __arrayClearPad()(ref BlkInfo info, size_t arrSize, size_t padSize) nothrow pure
|
||||
{
|
||||
import core.stdc.string;
|
||||
if (padSize > MEDPAD && !(info.attr & BlkAttr.NO_SCAN) && info.base)
|
||||
{
|
||||
if (info.size < PAGESIZE)
|
||||
memset(info.base + arrSize, 0, padSize);
|
||||
else
|
||||
memset(info.base, 0, LARGEPREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an array memory block by applying the proper padding and assigning
|
||||
* block attributes if not inherited from the existing block.
|
||||
*
|
||||
* Params:
|
||||
* arrSize = size of the allocated array in bytes
|
||||
* Returns:
|
||||
* `BlkInfo` with allocation metadata
|
||||
*/
|
||||
BlkInfo __arrayAlloc(T)(size_t arrSize) @trusted
|
||||
{
|
||||
import core.checkedint;
|
||||
import core.lifetime : TypeInfoSize;
|
||||
import core.internal.traits : hasIndirections;
|
||||
|
||||
enum typeInfoSize = TypeInfoSize!T;
|
||||
BlkAttr attr = BlkAttr.APPENDABLE;
|
||||
|
||||
size_t padSize = arrSize > MAXMEDSIZE ?
|
||||
LARGEPAD :
|
||||
((arrSize > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + typeInfoSize);
|
||||
|
||||
bool overflow;
|
||||
auto paddedSize = addu(arrSize, padSize, overflow);
|
||||
|
||||
if (overflow)
|
||||
return BlkInfo();
|
||||
|
||||
/* `extern(C++)` classes don't have a classinfo pointer in their vtable,
|
||||
* so the GC can't finalize them.
|
||||
*/
|
||||
static if (typeInfoSize)
|
||||
attr |= BlkAttr.STRUCTFINAL | BlkAttr.FINALIZE;
|
||||
static if (!hasIndirections!T)
|
||||
attr |= BlkAttr.NO_SCAN;
|
||||
|
||||
auto bi = GC.qalloc(paddedSize, attr, typeid(T));
|
||||
__arrayClearPad(bi, arrSize, padSize);
|
||||
return bi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start of the array for the given block.
|
||||
*
|
||||
* Params:
|
||||
* info = array metadata
|
||||
* Returns:
|
||||
* pointer to the start of the array
|
||||
*/
|
||||
void *__arrayStart()(return scope BlkInfo info) nothrow pure
|
||||
{
|
||||
return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the allocated length of the array block. This is called when an array
|
||||
* is appended to or its length is set.
|
||||
*
|
||||
* The allocated block looks like this for blocks < PAGESIZE:
|
||||
* `|elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize|`
|
||||
*
|
||||
* The size of the allocated length at the end depends on the block size:
|
||||
* a block of 16 to 256 bytes has an 8-bit length.
|
||||
* a block with 512 to pagesize/2 bytes has a 16-bit length.
|
||||
*
|
||||
* For blocks >= pagesize, the length is a size_t and is at the beginning of the
|
||||
* block. The reason we have to do this is because the block can extend into
|
||||
* more pages, so we cannot trust the block length if it sits at the end of the
|
||||
* block, because it might have just been extended. If we can prove in the
|
||||
* future that the block is unshared, we may be able to change this, but I'm not
|
||||
* sure it's important.
|
||||
*
|
||||
* In order to do put the length at the front, we have to provide 16 bytes
|
||||
* buffer space in case the block has to be aligned properly. In x86, certain
|
||||
* SSE instructions will only work if the data is 16-byte aligned. In addition,
|
||||
* we need the sentinel byte to prevent accidental pointers to the next block.
|
||||
* Because of the extra overhead, we only do this for page size and above, where
|
||||
* the overhead is minimal compared to the block size.
|
||||
*
|
||||
* So for those blocks, it looks like:
|
||||
* `|N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte|``
|
||||
*
|
||||
* where `elem0` starts 16 bytes after the first byte.
|
||||
*/
|
||||
bool __setArrayAllocLength(T)(ref BlkInfo info, size_t newLength, bool isShared, size_t oldLength = ~0)
|
||||
{
|
||||
import core.atomic;
|
||||
import core.lifetime : TypeInfoSize;
|
||||
|
||||
size_t typeInfoSize = TypeInfoSize!T;
|
||||
|
||||
if (info.size <= 256)
|
||||
{
|
||||
import core.checkedint;
|
||||
|
||||
bool overflow;
|
||||
auto newLengthPadded = addu(newLength,
|
||||
addu(SMALLPAD, typeInfoSize, overflow),
|
||||
overflow);
|
||||
|
||||
if (newLengthPadded > info.size || overflow)
|
||||
// new size does not fit inside block
|
||||
return false;
|
||||
|
||||
auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
|
||||
if (oldLength != ~0)
|
||||
{
|
||||
if (isShared)
|
||||
{
|
||||
return cas(cast(shared)length, cast(ubyte)oldLength, cast(ubyte)newLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*length == cast(ubyte)oldLength)
|
||||
*length = cast(ubyte)newLength;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setting the initial length, no cas needed
|
||||
*length = cast(ubyte)newLength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
|
||||
*typeInfo = cast()typeid(T);
|
||||
}
|
||||
}
|
||||
else if (info.size < PAGESIZE)
|
||||
{
|
||||
if (newLength + MEDPAD + typeInfoSize > info.size)
|
||||
// new size does not fit inside block
|
||||
return false;
|
||||
auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
|
||||
if (oldLength != ~0)
|
||||
{
|
||||
if (isShared)
|
||||
{
|
||||
return cas(cast(shared)length, cast(ushort)oldLength, cast(ushort)newLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*length == oldLength)
|
||||
*length = cast(ushort)newLength;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setting the initial length, no cas needed
|
||||
*length = cast(ushort)newLength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
|
||||
*typeInfo = cast()typeid(T);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newLength + LARGEPAD > info.size)
|
||||
// new size does not fit inside block
|
||||
return false;
|
||||
auto length = cast(size_t *)(info.base);
|
||||
if (oldLength != ~0)
|
||||
{
|
||||
if (isShared)
|
||||
{
|
||||
return cas(cast(shared)length, cast(size_t)oldLength, cast(size_t)newLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*length == oldLength)
|
||||
*length = newLength;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setting the initial length, no cas needed
|
||||
*length = newLength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
|
||||
*typeInfo = cast()typeid(T);
|
||||
}
|
||||
}
|
||||
return true; // resize succeeded
|
||||
}
|
||||
|
|
|
@ -2731,7 +2731,8 @@ if (is(T == class))
|
|||
{
|
||||
import core.internal.traits : hasIndirections;
|
||||
import core.exception : onOutOfMemoryError;
|
||||
import core.memory : GC, pureMalloc;
|
||||
import core.memory : pureMalloc;
|
||||
import core.memory : GC;
|
||||
|
||||
alias BlkAttr = GC.BlkAttr;
|
||||
|
||||
|
@ -2820,11 +2821,11 @@ T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted
|
|||
T* _d_newitemT(T)() @trusted
|
||||
{
|
||||
import core.internal.lifetime : emplaceInitializer;
|
||||
import core.internal.traits : hasElaborateDestructor, hasIndirections;
|
||||
import core.internal.traits : hasIndirections;
|
||||
import core.memory : GC;
|
||||
|
||||
auto flags = !hasIndirections!T ? GC.BlkAttr.NO_SCAN : GC.BlkAttr.NONE;
|
||||
immutable tiSize = hasElaborateDestructor!T ? size_t.sizeof : 0;
|
||||
immutable tiSize = TypeInfoSize!T;
|
||||
immutable itemSize = T.sizeof;
|
||||
immutable totalSize = itemSize + tiSize;
|
||||
if (tiSize)
|
||||
|
@ -3004,3 +3005,9 @@ version (D_ProfileGC)
|
|||
assert(0, "Cannot create new `struct` if compiling without support for runtime type information!");
|
||||
}
|
||||
}
|
||||
|
||||
template TypeInfoSize(T)
|
||||
{
|
||||
import core.internal.traits : hasElaborateDestructor;
|
||||
enum TypeInfoSize = hasElaborateDestructor!T ? size_t.sizeof : 0;
|
||||
}
|
||||
|
|
|
@ -4668,6 +4668,7 @@ version (D_ProfileGC)
|
|||
public import core.internal.array.appending : _d_arrayappendTTrace;
|
||||
public import core.internal.array.concatenation : _d_arraycatnTXTrace;
|
||||
public import core.lifetime : _d_newitemTTrace;
|
||||
public import core.internal.array.construction : _d_newarrayTTrace;
|
||||
}
|
||||
public import core.internal.array.appending : _d_arrayappendcTXImpl;
|
||||
public import core.internal.array.comparison : __cmp;
|
||||
|
@ -4676,6 +4677,7 @@ public import core.internal.array.casting: __ArrayCast;
|
|||
public import core.internal.array.concatenation : _d_arraycatnTX;
|
||||
public import core.internal.array.construction : _d_arrayctor;
|
||||
public import core.internal.array.construction : _d_arraysetctor;
|
||||
public import core.internal.array.construction : _d_newarrayT;
|
||||
public import core.internal.array.arrayassign : _d_arrayassign_l;
|
||||
public import core.internal.array.arrayassign : _d_arrayassign_r;
|
||||
public import core.internal.array.arrayassign : _d_arraysetassign;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
module rt.lifetime;
|
||||
|
||||
import core.attribute : weak;
|
||||
import core.internal.array.utils : __arrayStart, __arrayClearPad;
|
||||
import core.memory;
|
||||
debug(PRINTF) import core.stdc.stdio;
|
||||
static import rt.tlsgc;
|
||||
|
@ -226,7 +227,6 @@ size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
|
|||
private class ArrayAllocLengthLock
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
Set the allocated length of the array block. This is called
|
||||
any time an array is appended to or its length is set.
|
||||
|
@ -386,14 +386,6 @@ private size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure
|
|||
return *cast(size_t *)(info.base);
|
||||
}
|
||||
|
||||
/**
|
||||
get the start of the array for the given block
|
||||
*/
|
||||
private void *__arrayStart(return scope BlkInfo info) nothrow pure
|
||||
{
|
||||
return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
get the padding required to allocate size bytes. Note that the padding is
|
||||
NOT included in the passed in size. Therefore, do NOT call this function
|
||||
|
@ -404,22 +396,6 @@ private size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trus
|
|||
return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + structTypeInfoSize(tinext));
|
||||
}
|
||||
|
||||
/**
|
||||
clear padding that might not be zeroed by the GC (it assumes it is within the
|
||||
requested size from the start, but it is actually at the end of the allocated block)
|
||||
*/
|
||||
private void __arrayClearPad(ref BlkInfo info, size_t arrsize, size_t padsize) nothrow pure
|
||||
{
|
||||
import core.stdc.string;
|
||||
if (padsize > MEDPAD && !(info.attr & BlkAttr.NO_SCAN) && info.base)
|
||||
{
|
||||
if (info.size < PAGESIZE)
|
||||
memset(info.base + arrsize, 0, padsize);
|
||||
else
|
||||
memset(info.base, 0, LARGEPREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
allocate an array memory block by applying the proper padding and
|
||||
assigning block attributes if not inherited from the existing block
|
||||
|
|
|
@ -17,9 +17,6 @@ module rt.tracegc;
|
|||
|
||||
// version = tracegc;
|
||||
|
||||
extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length);
|
||||
extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length);
|
||||
extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length);
|
||||
extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims);
|
||||
extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims);
|
||||
extern (C) void _d_callfinalizer(void* p);
|
||||
|
@ -59,6 +56,7 @@ extern (C) size_t gc_extend(void* p, size_t mx, size_t sz, const TypeInfo ti = n
|
|||
enum accumulator = q{
|
||||
import rt.profilegc : accumulate;
|
||||
import core.memory : GC;
|
||||
import core.stdc.string : strstr;
|
||||
|
||||
static if (is(typeof(ci)))
|
||||
string name = ci.name;
|
||||
|
@ -91,7 +89,8 @@ enum accumulator = q{
|
|||
scope(exit)
|
||||
{
|
||||
ulong size = GC.allocatedInCurrentThread - currentlyAllocated;
|
||||
if (size > 0)
|
||||
// Skip internal functions.
|
||||
if (size > 0 && strstr(funcname.ptr, "core.internal") is null)
|
||||
accumulate(file, line, funcname, name, size);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
|
@ -11,9 +11,9 @@ bytes allocated, allocations, type, function, file:line
|
|||
16 1 char[] D main src/profilegc.d:36
|
||||
16 1 closure profilegc.main.foo src/profilegc.d:45
|
||||
16 1 float D main src/profilegc.d:16
|
||||
16 1 float[] D main src/profilegc.d:17
|
||||
16 1 float D main src/profilegc.d:17
|
||||
16 1 int D main src/profilegc.d:13
|
||||
16 1 int[] D main src/profilegc.d:14
|
||||
16 1 int D main src/profilegc.d:14
|
||||
16 1 int[] D main src/profilegc.d:22
|
||||
16 1 int[] D main src/profilegc.d:37
|
||||
16 1 wchar[] D main src/profilegc.d:35
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue