Skip to content

Commit 2b03eba

Browse files
committed
reduce size of Array!T from 32 to 16 bytes
- allocates a maximum of uint.max entries - overlaps single entry with pointer to array
1 parent e0ef787 commit 2b03eba

3 files changed

Lines changed: 61 additions & 63 deletions

File tree

compiler/src/dmd/dinterpret.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6894,7 +6894,7 @@ private Expression interpret_aaDel(UnionExp* pue, InterState* istate, Expression
68946894
AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
68956895
Expressions* keysx = aae.keys;
68966896
Expressions* valuesx = aae.values;
6897-
size_t removed = 0;
6897+
uint removed = 0;
68986898
foreach (j, evalue; *valuesx)
68996899
{
69006900
Expression ekey = (*keysx)[j];

compiler/src/dmd/root/array.d

Lines changed: 58 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@ debug
2929

3030
extern (C++) struct Array(T)
3131
{
32-
size_t length;
32+
uint length;
3333

3434
private:
35-
T[] data;
3635
enum SMALLARRAYCAP = 1;
37-
T[SMALLARRAYCAP] smallarray; // inline storage for small arrays
36+
uint allocated = SMALLARRAYCAP;
37+
union
38+
{
39+
T[SMALLARRAYCAP] smallarray; // inline storage for small arrays
40+
T* _ptr;
41+
}
42+
extern(D) inout(T)* data() inout pure nothrow { return allocated <= SMALLARRAYCAP ? smallarray.ptr : _ptr; }
3843

3944
public:
4045
/*******************
@@ -44,7 +49,7 @@ public:
4449
this(size_t dim) pure nothrow scope
4550
{
4651
reserve(dim);
47-
this.length = dim;
52+
this.length = cast(uint)dim;
4853
}
4954

5055
@disable this(this);
@@ -53,13 +58,14 @@ public:
5358
{
5459
debug (stomp)
5560
{
56-
if (data.ptr)
57-
memset(data.ptr, 0xFF, data.length * T.sizeof);
61+
if (allocated > SMALLARRAYCAP)
62+
memset(_ptr, 0xFF, allocated * T.sizeof);
5863
}
59-
if (data.ptr && data.ptr != &smallarray[0])
60-
mem.xfree(data.ptr);
64+
if (allocated > SMALLARRAYCAP)
65+
mem.xfree(_ptr);
6166
}
6267

68+
@trusted:
6369
// this is using a template constraint because of ambiguity with this(size_t) when T is
6470
// int, and c++ header generation doesn't accept wrapping this in static if
6571
extern(D) this()(T[] elems ...) pure nothrow if (is(T == struct) || is(T == class))
@@ -141,18 +147,18 @@ public:
141147
return toString.ptr;
142148
}
143149

144-
ref Array push(T ptr) return pure nothrow
150+
ref Array push(T p) return pure nothrow
145151
{
146152
reserve(1);
147-
data[length++] = ptr;
153+
data[length++] = p;
148154
return this;
149155
}
150156

151157
extern (D) ref Array pushSlice(T[] a) return pure nothrow
152158
{
153159
const oldLength = length;
154160
setDim(oldLength + a.length);
155-
memcpy(data.ptr + oldLength, a.ptr, a.length * T.sizeof);
161+
memcpy(data + oldLength, a.ptr, a.length * T.sizeof);
156162
return this;
157163
}
158164

@@ -164,87 +170,82 @@ public:
164170

165171
void reserve(size_t nentries) pure nothrow
166172
{
167-
//printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", cast(int)length, cast(int)data.length, cast(int)nentries);
173+
//printf("Array::reserve: length = %d, data.allocated = %d, nentries = %d\n", cast(int)length, cast(int)data.allocated, cast(int)nentries);
168174

169175
// Cold path
170176
void enlarge(size_t nentries)
171177
{
178+
static if (uint.max < size_t.max)
179+
assert(length + nentries <= uint.max);
180+
172181
pragma(inline, false); // never inline cold path
173-
if (data.length == 0)
182+
if (allocated == 0)
174183
{
175184
// Not properly initialized, someone memset it to zero
176-
if (nentries <= SMALLARRAYCAP)
177-
{
178-
data = SMALLARRAYCAP ? smallarray[] : null;
179-
}
180-
else
185+
if (nentries > SMALLARRAYCAP)
181186
{
182187
auto p = cast(T*)mem.xmalloc(nentries * T.sizeof);
183-
data = p[0 .. nentries];
188+
_ptr = p;
184189
}
190+
allocated = cast(uint)nentries;
185191
}
186-
else if (data.length == SMALLARRAYCAP)
192+
else if (allocated <= SMALLARRAYCAP)
187193
{
188194
const allocdim = length + nentries;
189195
auto p = cast(T*)mem.xmalloc(allocdim * T.sizeof);
190196
memcpy(p, smallarray.ptr, length * T.sizeof);
191-
data = p[0 .. allocdim];
197+
_ptr = p;
198+
allocated = cast(uint)allocdim;
192199
}
193200
else
194201
{
195202
/* Increase size by 1.5x to avoid excessive memory fragmentation
196203
*/
197204
auto increment = length / 2;
198205
if (nentries > increment) // if 1.5 is not enough
199-
increment = nentries;
206+
increment = cast(uint)nentries;
200207
const allocdim = length + increment;
201208
debug (stomp)
202209
{
203210
// always move using allocate-copy-stomp-free
204211
auto p = cast(T*)mem.xmalloc(allocdim * T.sizeof);
205-
memcpy(p, data.ptr, length * T.sizeof);
206-
memset(data.ptr, 0xFF, data.length * T.sizeof);
207-
mem.xfree(data.ptr);
208-
data = p[0 .. allocdim];
212+
memcpy(p, _ptr, length * T.sizeof);
213+
memset(_ptr, 0xFF, allocated * T.sizeof);
214+
mem.xfree(_ptr);
209215
}
210216
else
211217
{
212-
auto p = cast(T*)mem.xrealloc(data.ptr, allocdim * T.sizeof);
213-
data = p[0 .. allocdim];
218+
auto p = cast(T*)mem.xrealloc(_ptr, allocdim * T.sizeof);
214219
}
220+
_ptr = p;
221+
allocated = cast(uint)allocdim;
215222
}
216223

217224
debug (stomp)
218225
{
219-
if (data.ptr)
220-
{
221-
if (length < data.length)
222-
memset(data.ptr + length, 0xFF, (data.length - length) * T.sizeof);
223-
}
226+
if (length < allocated)
227+
memset(data + length, 0xFF, (allocated - length) * T.sizeof);
224228
}
225229
else
226230
{
227231
if (mem.isGCEnabled)
228232
{
229-
if (data.ptr)
230-
{
231-
if (length < data.length)
232-
memset(data.ptr + length, 0xFF, (data.length - length) * T.sizeof);
233-
}
233+
if (length < allocated)
234+
memset(data + length, 0xFF, (allocated - length) * T.sizeof);
234235
}
235236
}
236237
}
237238

238-
if (data.length - length < nentries) // false means hot path
239+
if (allocated - length < nentries) // false means hot path
239240
enlarge(nentries);
240241
}
241242

242243
void remove(size_t i) pure nothrow @nogc
243244
{
244245
if (length - i - 1)
245-
memmove(data.ptr + i, data.ptr + i + 1, (length - i - 1) * T.sizeof);
246+
memmove(data + i, data + i + 1, (length - i - 1) * T.sizeof);
246247
length--;
247-
debug (stomp) memset(data.ptr + length, 0xFF, T.sizeof);
248+
debug (stomp) memset(data + length, 0xFF, T.sizeof);
248249
}
249250

250251
void insert(size_t index, typeof(this)* a) pure nothrow
@@ -254,8 +255,8 @@ public:
254255
size_t d = a.length;
255256
reserve(d);
256257
if (length != index)
257-
memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof);
258-
memcpy(data.ptr + index, a.data.ptr, d * T.sizeof);
258+
memmove(data + index + d, data + index, (length - index) * T.sizeof);
259+
memcpy(data + index, a.data, d * T.sizeof);
259260
length += d;
260261
}
261262
}
@@ -265,16 +266,16 @@ public:
265266
size_t d = a.length;
266267
reserve(d);
267268
if (length != index)
268-
memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof);
269-
memcpy(data.ptr + index, a.ptr, d * T.sizeof);
269+
memmove(data + index + d, data + index, (length - index) * T.sizeof);
270+
memcpy(data + index, a.ptr, d * T.sizeof);
270271
length += d;
271272
}
272273

273-
void insert(size_t index, T ptr) pure nothrow
274+
void insert(size_t index, T p) pure nothrow
274275
{
275276
reserve(1);
276-
memmove(data.ptr + index + 1, data.ptr + index, (length - index) * T.sizeof);
277-
data[index] = ptr;
277+
memmove(data + index + 1, data + index, (length - index) * T.sizeof);
278+
data[index] = p;
278279
length++;
279280
}
280281

@@ -285,7 +286,7 @@ public:
285286
return;
286287
reserve(count);
287288
if (length != index)
288-
memmove(data.ptr + index + count, data.ptr + index, (length - index) * T.sizeof);
289+
memmove(data + index + count, data + index, (length - index) * T.sizeof);
289290
data[index .. index + count] = value;
290291
length += count;
291292
}
@@ -296,13 +297,13 @@ public:
296297
{
297298
reserve(newdim - length);
298299
}
299-
length = newdim;
300+
length = cast(uint)newdim;
300301
}
301302

302303
size_t find(T ptr) const nothrow pure
303304
{
304305
foreach (i; 0 .. length)
305-
if (data[i] is ptr)
306+
if (this[i] is ptr)
306307
return i;
307308
return size_t.max;
308309
}
@@ -314,30 +315,27 @@ public:
314315

315316
ref inout(T) opIndex(size_t i) inout nothrow pure
316317
{
317-
debug
318-
// This is called so often the array bounds become expensive
319-
return data[i];
320-
else
321-
return data.ptr[i];
318+
debug assert(i < length);
319+
return allocated <= SMALLARRAYCAP ? smallarray.ptr[i] : _ptr[i];
322320
}
323321

324322
inout(T)* tdata() inout pure nothrow @nogc @trusted
325323
{
326-
return data.ptr;
324+
return data;
327325
}
328326

329327
Array!T* copy() const pure nothrow
330328
{
331329
auto a = new Array!T();
332330
a.setDim(length);
333-
memcpy(a.data.ptr, data.ptr, length * T.sizeof);
331+
memcpy(a.data, data, length * T.sizeof);
334332
return a;
335333
}
336334

337335
void shift(T ptr) pure nothrow
338336
{
339337
reserve(1);
340-
memmove(data.ptr + 1, data.ptr, length * T.sizeof);
338+
memmove(data + 1, data, length * T.sizeof);
341339
data[0] = ptr;
342340
length++;
343341
}
@@ -390,7 +388,7 @@ public:
390388
{
391389
if (this.length < 2)
392390
return this;
393-
qsort(this.data.ptr, this.length, T.sizeof, &arraySortWrapper!(T, pred));
391+
qsort(this.data, this.length, T.sizeof, &arraySortWrapper!(T, pred));
394392
return this;
395393
}
396394

compiler/src/dmd/templatesem.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6688,9 +6688,9 @@ private MATCH deduceParentInstance(Scope* sc, Dsymbol sym, TypeInstance tpi,
66886688
if (!tparent)
66896689
return MATCH.nomatch;
66906690

6691-
tpi.idents.length--;
6691+
tpi.idents.pop();
66926692
auto m = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
6693-
tpi.idents.length++;
6693+
tpi.idents.push(id);
66946694
return m;
66956695
}
66966696

0 commit comments

Comments
 (0)