1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 1994-1998 by Symantec 6 * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/outbuf.d, backend/outbuf.d) 10 * Documentation: https://dlang.org/phobos/dmd_backend_outbuf.html 11 */ 12 13 module dmd.backend.outbuf; 14 15 import core.stdc.stdio; 16 import core.stdc.stdlib; 17 import core.stdc.string; 18 19 // Output buffer 20 21 // (This used to be called OutBuffer, renamed to avoid name conflicts with Mars.) 22 23 extern (C++): 24 25 private nothrow void err_nomem(); 26 27 struct Outbuffer 28 { 29 ubyte *buf; // the buffer itself 30 ubyte *pend; // pointer past the end of the buffer 31 private ubyte *p; // current position in buffer 32 33 nothrow: 34 this(size_t initialSize) 35 { 36 reserve(initialSize); 37 } 38 39 //~this() { dtor(); } 40 41 void dtor() 42 { 43 if (auto slice = this.extractSlice()) 44 free(slice.ptr); 45 } 46 47 void reset() 48 { 49 p = buf; 50 } 51 52 // Returns: A slice to the data written so far 53 extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout 54 @trusted pure nothrow @nogc 55 { 56 assert(this.buf, "Attempt to dereference a null pointer"); 57 assert(from < to, "First index must be smaller than the second one"); 58 assert(this.length() <= (to - from), "Out of bound access"); 59 return this.buf[from .. to]; 60 } 61 62 /// Ditto 63 extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc 64 { 65 return this.buf[0 .. this.p - this.buf]; 66 } 67 68 extern(D) ubyte[] extractSlice() @safe pure nothrow @nogc 69 { 70 auto ret = this[]; 71 this.buf = this.p = this.pend = null; 72 return ret; 73 } 74 75 /******************** 76 * Make sure we have at least `nbytes` available for writing, 77 * allocate more if necessary. 78 * This is the inlinable fast path. Prefer `enlarge` if allocation 79 * will always happen. 80 */ 81 void reserve(size_t nbytes) 82 { 83 // Keep small so it is inlined 84 if (pend - p < nbytes) 85 enlarge(nbytes); 86 } 87 88 // Reserve nbytes in buffer 89 void enlarge(size_t nbytes) 90 { 91 pragma(inline, false); // do not inline slow path 92 const size_t oldlen = pend - buf; 93 const size_t used = p - buf; 94 95 size_t len = used + nbytes; 96 // No need to reallocate 97 if (nbytes < (pend - p)) 98 return; 99 100 const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5 101 if (len < newlen) 102 len = newlen; 103 len = (len + 15) & ~15; 104 105 buf = cast(ubyte*) realloc(buf,len); 106 if (!buf) 107 err_nomem(); 108 109 pend = buf + len; 110 p = buf + used; 111 } 112 113 114 // Write n zeros; return pointer to start of zeros 115 void *writezeros(size_t n) 116 { 117 reserve(n); 118 void *pstart = memset(p,0,n); 119 p += n; 120 return pstart; 121 } 122 123 // Position buffer to accept the specified number of bytes at offset 124 void position(size_t offset, size_t nbytes) 125 { 126 if (offset + nbytes > pend - buf) 127 { 128 reserve(offset + nbytes - (p - buf)); 129 } 130 p = buf + offset; 131 132 debug assert(buf <= p); 133 debug assert(p <= pend); 134 debug assert(p + nbytes <= pend); 135 } 136 137 // Write an array to the buffer, no reserve check 138 void writen(const void *b, size_t len) 139 { 140 memcpy(p,b,len); 141 p += len; 142 } 143 144 // Write an array to the buffer. 145 extern (D) 146 void write(const(void)[] b) 147 { 148 reserve(b.length); 149 memcpy(p, b.ptr, b.length); 150 p += b.length; 151 } 152 153 void write(const(void)* b, size_t len) 154 { 155 write(b[0 .. len]); 156 } 157 158 /** 159 * Writes an 8 bit byte, no reserve check. 160 */ 161 void writeByten(ubyte v) 162 { 163 *p++ = v; 164 } 165 166 /** 167 * Writes an 8 bit byte. 168 */ 169 void writeByte(int v) 170 { 171 reserve(1); 172 *p++ = cast(ubyte)v; 173 } 174 175 /** 176 * Writes a 16 bit value, no reserve check. 177 */ 178 void write16n(int v) 179 { 180 *(cast(ushort *) p) = cast(ushort)v; 181 p += 2; 182 } 183 184 185 /** 186 * Writes a 16 bit value. 187 */ 188 void write16(int v) 189 { 190 reserve(2); 191 write16n(v); 192 } 193 194 /** 195 * Writes a 32 bit int. 196 */ 197 void write32(int v) 198 { 199 reserve(4); 200 *cast(int *)p = v; 201 p += 4; 202 } 203 204 /** 205 * Writes a 64 bit long. 206 */ 207 void write64(long v) 208 { 209 reserve(8); 210 *cast(long *)p = v; 211 p += 8; 212 } 213 214 215 /** 216 * Writes a 32 bit float. 217 */ 218 void writeFloat(float v) 219 { 220 reserve(float.sizeof); 221 *cast(float *)p = v; 222 p += float.sizeof; 223 } 224 225 /** 226 * Writes a 64 bit double. 227 */ 228 void writeDouble(double v) 229 { 230 reserve(double.sizeof); 231 *cast(double *)p = v; 232 p += double.sizeof; 233 } 234 235 /** 236 * Writes a String as a sequence of bytes. 237 */ 238 void write(const(char)* s) 239 { 240 write(s[0 .. strlen(s)]); 241 } 242 243 /** 244 * Writes a 0 terminated String 245 */ 246 void writeString(const(char)* s) 247 { 248 write(s[0 .. strlen(s)+1]); 249 } 250 251 /// Ditto 252 extern(D) void writeString(const(char)[] s) 253 { 254 write(s); 255 writeByte(0); 256 } 257 258 /// Disembiguation for `string` 259 extern(D) void writeString(string s) 260 { 261 writeString(cast(const(char)[])(s)); 262 } 263 264 /** 265 * Inserts string at beginning of buffer. 266 */ 267 void prependBytes(const(char)* s) 268 { 269 prepend(s, strlen(s)); 270 } 271 272 /** 273 * Inserts bytes at beginning of buffer. 274 */ 275 void prepend(const(void)* b, size_t len) 276 { 277 reserve(len); 278 memmove(buf + len,buf,p - buf); 279 memcpy(buf,b,len); 280 p += len; 281 } 282 283 /** 284 * Bracket buffer contents with c1 and c2. 285 */ 286 void bracket(char c1,char c2) 287 { 288 reserve(2); 289 memmove(buf + 1,buf,p - buf); 290 buf[0] = c1; 291 p[1] = c2; 292 p += 2; 293 } 294 295 /** 296 * Returns the number of bytes written. 297 */ 298 size_t length() const @safe pure nothrow @nogc 299 { 300 return p - buf; 301 } 302 303 /** 304 * Set current size of buffer. 305 */ 306 307 void setsize(size_t size) 308 { 309 p = buf + size; 310 //debug assert(buf <= p); 311 //debug assert(p <= pend); 312 } 313 314 void writesLEB128(int value) 315 { 316 while (1) 317 { 318 ubyte b = value & 0x7F; 319 320 value >>= 7; // arithmetic right shift 321 if (value == 0 && !(b & 0x40) || 322 value == -1 && (b & 0x40)) 323 { 324 writeByte(b); 325 break; 326 } 327 writeByte(b | 0x80); 328 } 329 } 330 331 void writeuLEB128(uint value) 332 { 333 do 334 { 335 ubyte b = value & 0x7F; 336 337 value >>= 7; 338 if (value) 339 b |= 0x80; 340 writeByte(b); 341 } while (value); 342 } 343 }