Skip to content

Commit 398f0d5

Browse files
committed
Improve OutBuffer's allocation strategy
1 parent 86b117b commit 398f0d5

1 file changed

Lines changed: 70 additions & 60 deletions

File tree

src/dmd/backend/outbuf.d

Lines changed: 70 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ struct Outbuffer
2828
{
2929
@safe:
3030

31-
ubyte *buf; // the buffer itself
32-
ubyte *pend; // pointer past the end of the buffer
33-
private ubyte *p; // current position in buffer
31+
private ubyte *buf; // the buffer itself
32+
private ubyte *pend; // pointer past the end of the buffer
33+
private ubyte *p; // current position in buffer
3434

3535
nothrow:
3636
this(size_t initialSize)
@@ -43,26 +43,16 @@ struct Outbuffer
4343
@trusted
4444
void dtor()
4545
{
46-
if (auto slice = this.extractSlice())
47-
free(slice.ptr);
46+
free(buf);
47+
buf = p = pend = null;
4848
}
4949

50-
void reset()
50+
private void reset()
5151
{
5252
p = buf;
5353
}
5454

5555
// Returns: A slice to the data written so far
56-
extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout
57-
@trusted pure nothrow @nogc
58-
{
59-
assert(this.buf, "Attempt to dereference a null pointer");
60-
assert(from < to, "First index must be smaller than the second one");
61-
assert(this.length() <= (to - from), "Out of bound access");
62-
return this.buf[from .. to];
63-
}
64-
65-
/// Ditto
6656
extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc
6757
{
6858
return this.buf[0 .. this.p - this.buf];
@@ -75,13 +65,22 @@ struct Outbuffer
7565
return ret;
7666
}
7767

68+
private extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout
69+
@trusted pure nothrow @nogc
70+
{
71+
assert(this.buf, "Attempt to dereference a null pointer");
72+
assert(from < to, "First index must be smaller than the second one");
73+
assert(this.length() <= (to - from), "Out of bound access");
74+
return this.buf[from .. to];
75+
}
76+
7877
/********************
7978
* Make sure we have at least `nbytes` available for writing,
8079
* allocate more if necessary.
8180
* This is the inlinable fast path. Prefer `enlarge` if allocation
8281
* will always happen.
8382
*/
84-
void reserve(size_t nbytes)
83+
private void reserve(size_t nbytes)
8584
{
8685
// Keep small so it is inlined
8786
if (pend - p < nbytes)
@@ -90,34 +89,45 @@ struct Outbuffer
9089

9190
// Reserve nbytes in buffer
9291
@trusted
93-
void enlarge(size_t nbytes)
92+
private void enlarge(size_t nbytes)
9493
{
9594
pragma(inline, false); // do not inline slow path
96-
const size_t oldlen = pend - buf;
97-
const size_t used = p - buf;
98-
99-
size_t len = used + nbytes;
100-
// No need to reallocate
101-
if (nbytes < (pend - p))
102-
return;
10395

104-
const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5
105-
if (len < newlen)
106-
len = newlen;
107-
len = (len + 15) & ~15;
96+
debug assert(nbytes > pend - p, "You should call this function from reserve() only.");
10897

109-
buf = cast(ubyte*) realloc(buf,len);
98+
if (buf is null)
99+
{
100+
// Special-case the overwhelmingly most frequent situation
101+
if (nbytes < 64) nbytes = 64;
102+
p = buf = cast(ubyte*) malloc(nbytes);
103+
pend = buf + nbytes;
104+
}
105+
else
106+
{
107+
const size_t used = p - buf;
108+
const size_t oldlen = pend - buf;
109+
// Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes
110+
const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64));
111+
112+
size_t len = used + nbytes;
113+
if (len < minlen)
114+
len = minlen;
115+
// Round to cache line size
116+
len = (len + 63) & ~63;
117+
118+
auto newbuf = cast(ubyte*) realloc(buf, len);
119+
120+
pend = newbuf + len;
121+
p = newbuf + used;
122+
buf = newbuf;
123+
}
110124
if (!buf)
111125
err_nomem();
112-
113-
pend = buf + len;
114-
p = buf + used;
115126
}
116127

117-
118128
// Write n zeros; return pointer to start of zeros
119129
@trusted
120-
void *writezeros(size_t n)
130+
private void *writezeros(size_t n)
121131
{
122132
reserve(n);
123133
void *pstart = memset(p,0,n);
@@ -127,7 +137,7 @@ struct Outbuffer
127137

128138
// Position buffer to accept the specified number of bytes at offset
129139
@trusted
130-
void position(size_t offset, size_t nbytes)
140+
private void position(size_t offset, size_t nbytes)
131141
{
132142
if (offset + nbytes > pend - buf)
133143
{
@@ -142,7 +152,7 @@ struct Outbuffer
142152

143153
// Write an array to the buffer, no reserve check
144154
@trusted
145-
void writen(const void *b, size_t len)
155+
private void writen(const void *b, size_t len)
146156
{
147157
memcpy(p,b,len);
148158
p += len;
@@ -151,15 +161,15 @@ struct Outbuffer
151161
// Write an array to the buffer.
152162
@trusted
153163
extern (D)
154-
void write(const(void)[] b)
164+
private void write(const(void)[] b)
155165
{
156166
reserve(b.length);
157167
memcpy(p, b.ptr, b.length);
158168
p += b.length;
159169
}
160170

161171
@trusted
162-
void write(const(void)* b, size_t len)
172+
private void write(const(void)* b, size_t len)
163173
{
164174
write(b[0 .. len]);
165175
}
@@ -168,7 +178,7 @@ struct Outbuffer
168178
* Writes an 8 bit byte, no reserve check.
169179
*/
170180
@trusted
171-
void writeByten(int v)
181+
private void writeByten(int v)
172182
{
173183
*p++ = cast(ubyte)v;
174184
}
@@ -177,7 +187,7 @@ struct Outbuffer
177187
* Writes an 8 bit byte.
178188
*/
179189
@trusted
180-
void writeByte(int v)
190+
private void writeByte(int v)
181191
{
182192
reserve(1);
183193
writeByten(v);
@@ -187,7 +197,7 @@ struct Outbuffer
187197
* Writes a 16 bit value, no reserve check.
188198
*/
189199
@trusted
190-
void write16n(int v)
200+
private void write16n(int v)
191201
{
192202
*(cast(ushort *) p) = cast(ushort)v;
193203
p += 2;
@@ -197,7 +207,7 @@ struct Outbuffer
197207
/**
198208
* Writes a 16 bit value.
199209
*/
200-
void write16(int v)
210+
private void write16(int v)
201211
{
202212
reserve(2);
203213
write16n(v);
@@ -207,7 +217,7 @@ struct Outbuffer
207217
* Writes a 32 bit int, no reserve check.
208218
*/
209219
@trusted
210-
void write32n(int v)
220+
private void write32n(int v)
211221
{
212222
*cast(int *)p = v;
213223
p += 4;
@@ -216,7 +226,7 @@ struct Outbuffer
216226
/**
217227
* Writes a 32 bit int.
218228
*/
219-
void write32(int v)
229+
private void write32(int v)
220230
{
221231
reserve(4);
222232
write32n(v);
@@ -226,7 +236,7 @@ struct Outbuffer
226236
* Writes a 64 bit long, no reserve check
227237
*/
228238
@trusted
229-
void write64n(long v)
239+
private void write64n(long v)
230240
{
231241
*cast(long *)p = v;
232242
p += 8;
@@ -235,7 +245,7 @@ struct Outbuffer
235245
/**
236246
* Writes a 64 bit long.
237247
*/
238-
void write64(long v)
248+
private void write64(long v)
239249
{
240250
reserve(8);
241251
write64n(v);
@@ -245,7 +255,7 @@ struct Outbuffer
245255
* Writes a 32 bit float.
246256
*/
247257
@trusted
248-
void writeFloat(float v)
258+
private void writeFloat(float v)
249259
{
250260
reserve(float.sizeof);
251261
*cast(float *)p = v;
@@ -256,7 +266,7 @@ struct Outbuffer
256266
* Writes a 64 bit double.
257267
*/
258268
@trusted
259-
void writeDouble(double v)
269+
private void writeDouble(double v)
260270
{
261271
reserve(double.sizeof);
262272
*cast(double *)p = v;
@@ -267,7 +277,7 @@ struct Outbuffer
267277
* Writes a String as a sequence of bytes.
268278
*/
269279
@trusted
270-
void write(const(char)* s)
280+
private void write(const(char)* s)
271281
{
272282
write(s[0 .. strlen(s)]);
273283
}
@@ -276,20 +286,20 @@ struct Outbuffer
276286
* Writes a 0 terminated String
277287
*/
278288
@trusted
279-
void writeString(const(char)* s)
289+
private void writeString(const(char)* s)
280290
{
281291
write(s[0 .. strlen(s)+1]);
282292
}
283293

284294
/// Ditto
285-
extern(D) void writeString(const(char)[] s)
295+
private extern(D) void writeString(const(char)[] s)
286296
{
287297
write(s);
288298
writeByte(0);
289299
}
290300

291301
/// Disembiguation for `string`
292-
extern(D) void writeString(string s)
302+
private extern(D) void writeString(string s)
293303
{
294304
writeString(cast(const(char)[])(s));
295305
}
@@ -298,7 +308,7 @@ struct Outbuffer
298308
* Inserts string at beginning of buffer.
299309
*/
300310
@trusted
301-
void prependBytes(const(char)* s)
311+
private void prependBytes(const(char)* s)
302312
{
303313
prepend(s, strlen(s));
304314
}
@@ -307,7 +317,7 @@ struct Outbuffer
307317
* Inserts bytes at beginning of buffer.
308318
*/
309319
@trusted
310-
void prepend(const(void)* b, size_t len)
320+
private void prepend(const(void)* b, size_t len)
311321
{
312322
reserve(len);
313323
memmove(buf + len,buf,p - buf);
@@ -319,7 +329,7 @@ struct Outbuffer
319329
* Bracket buffer contents with c1 and c2.
320330
*/
321331
@trusted
322-
void bracket(char c1,char c2)
332+
private void bracket(char c1,char c2)
323333
{
324334
reserve(2);
325335
memmove(buf + 1,buf,p - buf);
@@ -331,7 +341,7 @@ struct Outbuffer
331341
/**
332342
* Returns the number of bytes written.
333343
*/
334-
size_t length() const @safe pure nothrow @nogc
344+
private size_t length() const @safe pure nothrow @nogc
335345
{
336346
return p - buf;
337347
}
@@ -340,14 +350,14 @@ struct Outbuffer
340350
* Set current size of buffer.
341351
*/
342352
@trusted
343-
void setsize(size_t size)
353+
private void setsize(size_t size)
344354
{
345355
p = buf + size;
346356
//debug assert(buf <= p);
347357
//debug assert(p <= pend);
348358
}
349359

350-
void writesLEB128(int value)
360+
private void writesLEB128(int value)
351361
{
352362
while (1)
353363
{
@@ -364,7 +374,7 @@ struct Outbuffer
364374
}
365375
}
366376

367-
void writeuLEB128(uint value)
377+
private void writeuLEB128(uint value)
368378
{
369379
do
370380
{

0 commit comments

Comments
 (0)