1 /**
2 * Compiler implementation of the
3 * $(LINK2 http://www.dlang.org, D programming language).
4 *
5 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8 * Source: https://github.com/dlang/dmd/blob/master/src/dmd/backend/dt.d
9 */
10
11 module dmd.backend.dt;
12
13 // Online documentation: https://dlang.org/phobos/dmd_backend_dt.html
14
15 import core.stdc.stdio;
16 import core.stdc.stdlib;
17 import core.stdc..string;
18
19 import dmd.backend.cc;
20 import dmd.backend.cdef;
21 import dmd.backend.global;
22 import dmd.backend.mem;
23 import dmd.backend.ty;
24 import dmd.backend.type;
25
26 nothrow:
27 @nogc:
28
29 extern (C++):
30
31 /**********************************************
32 * Free a data definition struct.
33 */
34
35 void dt_free(dt_t *dt)
36 {
37 if (dt)
38 {
39 dt_t *dtn = dt;
40 while (1)
41 {
42 switch (dtn.dt)
43 {
44 case DT_abytes:
45 case DT_nbytes:
46 mem_free(dtn.DTpbytes);
47 break;
48
49 default:
50 break;
51 }
52 dt_t *dtnext = dtn.DTnext;
53 if (!dtnext)
54 break;
55 dtn = dtnext;
56 }
57 dtn.DTnext = dt_freelist;
58 dt_freelist = dt;
59 }
60 }
61
62 /*********************************
63 * Free free list.
64 */
65
66 void dt_term()
67 {
68 static if (0 && TERMCODE)
69 {
70 dt_t *dtn;
71
72 while (dt_freelist)
73 { dtn = dt_freelist.DTnext;
74 mem_ffree(dt_freelist);
75 dt_freelist = dtn;
76 }
77 }
78 }
79
80 dt_t **dtend(dt_t **pdtend)
81 {
82 while (*pdtend)
83 pdtend = &((*pdtend).DTnext);
84 return pdtend;
85 }
86
87
88 /*********************************
89 */
90 void dtpatchoffset(dt_t *dt, uint offset)
91 {
92 dt.DToffset = offset;
93 }
94
95 /**************************
96 * Make a common block for s.
97 */
98
99 void init_common(Symbol *s)
100 {
101 //printf("init_common('%s')\n", s.Sident);
102
103 uint size = cast(uint)type_size(s.Stype);
104 if (size)
105 {
106 dt_t *dt = dt_calloc(DT_common);
107 dt.DTazeros = size;
108 s.Sdt = dt;
109 }
110 }
111
112 /**********************************
113 * Compute size of a dt
114 */
115
116 uint dt_size(const(dt_t)* dtstart)
117 {
118 uint datasize = 0;
119 for (auto dt = dtstart; dt; dt = dt.DTnext)
120 {
121 switch (dt.dt)
122 {
123 case DT_abytes:
124 datasize += size(dt.Dty);
125 break;
126 case DT_ibytes:
127 datasize += dt.DTn;
128 break;
129 case DT_nbytes:
130 datasize += dt.DTnbytes;
131 break;
132 case DT_azeros:
133 datasize += dt.DTazeros;
134 break;
135 case DT_common:
136 break;
137 case DT_xoff:
138 case DT_coff:
139 datasize += size(dt.Dty);
140 break;
141 default:
142 debug printf("dt = %p, dt = %d\n",dt,dt.dt);
143 assert(0);
144 }
145 }
146 return datasize;
147 }
148
149 /************************************
150 * Return true if dt is all zeros.
151 */
152
153 bool dtallzeros(const(dt_t)* dt)
154 {
155 return dt.dt == DT_azeros && !dt.DTnext;
156 }
157
158 /************************************
159 * Return true if dt contains pointers (requires relocations).
160 */
161
162 bool dtpointers(const(dt_t)* dtstart)
163 {
164 for (auto dt = dtstart; dt; dt = dt.DTnext)
165 {
166 switch (dt.dt)
167 {
168 case DT_abytes:
169 case DT_xoff:
170 case DT_coff:
171 return true;
172
173 default:
174 break;
175 }
176 }
177 return false;
178 }
179
180 /***********************************
181 * Turn DT_azeros into DTcommon
182 */
183
184 void dt2common(dt_t **pdt)
185 {
186 assert((*pdt).dt == DT_azeros);
187 (*pdt).dt = DT_common;
188 }
189
190 /**********************************************************/
191
192 struct DtBuilder
193 {
194 private:
195
196 dt_t* head;
197 dt_t** pTail;
198
199 public:
200 nothrow:
201 @nogc:
202 this(int dummy)
203 {
204 pTail = &head;
205 }
206
207 /*************************
208 * Finish and return completed data structure.
209 */
210 dt_t *finish()
211 {
212 /* Merge all the 0s at the start of the list
213 * so we can later check for dtallzeros()
214 */
215 if (head && head.dt == DT_azeros)
216 {
217 while (1)
218 {
219 dt_t *dtn = head.DTnext;
220 if (!(dtn && dtn.dt == DT_azeros))
221 break;
222
223 // combine head and dtn
224 head.DTazeros += dtn.DTazeros;
225 head.DTnext = dtn.DTnext;
226 dtn.DTnext = null;
227 dt_free(dtn);
228 }
229 }
230
231 return head;
232 }
233
234 /***********************
235 * Append data represented by ptr[0..size]
236 */
237 void nbytes(uint size, const(char)* ptr)
238 {
239 if (!size)
240 return;
241
242 dt_t *dt;
243
244 if (size < dt_t.DTibytesMax)
245 { dt = dt_calloc(DT_ibytes);
246 dt.DTn = cast(ubyte)size;
247 memcpy(dt.DTdata.ptr,ptr,size);
248 }
249 else
250 {
251 dt = dt_calloc(DT_nbytes);
252 dt.DTnbytes = size;
253 dt.DTpbytes = cast(byte *) mem_malloc(size);
254 memcpy(dt.DTpbytes,ptr,size);
255 }
256
257 assert(!*pTail);
258 *pTail = dt;
259 pTail = &dt.DTnext;
260 assert(!*pTail);
261 }
262
263 /*****************************************
264 * Write a reference to the data ptr[0..size+nzeros]
265 */
266 void abytes(tym_t ty, uint offset, uint size, const(char)* ptr, uint nzeros)
267 {
268 dt_t *dt = dt_calloc(DT_abytes);
269 dt.DTnbytes = size + nzeros;
270 dt.DTpbytes = cast(byte *) mem_malloc(size + nzeros);
271 dt.Dty = cast(ubyte)ty;
272 dt.DTabytes = offset;
273 memcpy(dt.DTpbytes,ptr,size);
274 if (nzeros)
275 memset(dt.DTpbytes + size, 0, nzeros);
276
277 assert(!*pTail);
278 *pTail = dt;
279 pTail = &dt.DTnext;
280 assert(!*pTail);
281 }
282
283 void abytes(uint offset, uint size, const(char)* ptr, uint nzeros)
284 {
285 abytes(TYnptr, offset, size, ptr, nzeros);
286 }
287
288 /**************************************
289 * Write 4 bytes of value.
290 */
291 void dword(int value)
292 {
293 if (value == 0)
294 {
295 nzeros(4);
296 return;
297 }
298
299 dt_t *dt = dt_calloc(DT_ibytes);
300 dt.DTn = 4;
301
302 union U { char* cp; int* lp; }
303 U u = void;
304 u.cp = cast(char*)dt.DTdata.ptr;
305 *u.lp = value;
306
307 assert(!*pTail);
308 *pTail = dt;
309 pTail = &dt.DTnext;
310 assert(!*pTail);
311 }
312
313 /***********************
314 * Write a size_t value.
315 */
316 void size(ulong value)
317 {
318 if (value == 0)
319 {
320 nzeros(_tysize[TYnptr]);
321 return;
322 }
323 dt_t *dt = dt_calloc(DT_ibytes);
324 dt.DTn = _tysize[TYnptr];
325
326 union U { char* cp; int* lp; }
327 U u = void;
328 u.cp = cast(char*)dt.DTdata.ptr;
329 *u.lp = cast(int)value;
330 if (_tysize[TYnptr] == 8)
331 u.lp[1] = cast(int)(value >> 32);
332
333 assert(!*pTail);
334 *pTail = dt;
335 pTail = &dt.DTnext;
336 assert(!*pTail);
337 }
338
339 /***********************
340 * Write a bunch of zeros
341 */
342 void nzeros(uint size)
343 {
344 if (!size)
345 return;
346 assert(cast(int) size > 0);
347
348 dt_t *dt = dt_calloc(DT_azeros);
349 dt.DTazeros = size;
350
351 assert(!*pTail);
352 *pTail = dt;
353 pTail = &dt.DTnext;
354 assert(!*pTail);
355 }
356
357 /*************************
358 * Write a reference to s+offset
359 */
360 void xoff(Symbol *s, uint offset, tym_t ty)
361 {
362 dt_t *dt = dt_calloc(DT_xoff);
363 dt.DTsym = s;
364 dt.DToffset = offset;
365 dt.Dty = cast(ubyte)ty;
366
367 assert(!*pTail);
368 *pTail = dt;
369 pTail = &dt.DTnext;
370 assert(!*pTail);
371 }
372
373 /******************************
374 * Create reference to s+offset
375 */
376 void xoff(Symbol *s, uint offset)
377 {
378 xoff(s, offset, TYnptr);
379 }
380
381 /*******************************
382 * Like xoff(), but returns handle with which to patch 'offset' value.
383 */
384 dt_t *xoffpatch(Symbol *s, uint offset, tym_t ty)
385 {
386 dt_t *dt = dt_calloc(DT_xoff);
387 dt.DTsym = s;
388 dt.DToffset = offset;
389 dt.Dty = cast(ubyte)ty;
390
391 dt_t **pxoff = pTail;
392
393 assert(!*pTail);
394 *pTail = dt;
395 pTail = &dt.DTnext;
396 assert(!*pTail);
397
398 return *pxoff;
399 }
400
401 /*************************************
402 * Create a reference to another dt.
403 * Returns: the internal symbol used for the other dt
404 */
405 Symbol *dtoff(dt_t *dt, uint offset)
406 {
407 type *t = type_alloc(TYint);
408 t.Tcount++;
409 Symbol *s = symbol_calloc("internal");
410 s.Sclass = SCstatic;
411 s.Sfl = FLextern;
412 s.Sflags |= SFLnodebug;
413 s.Stype = t;
414 s.Sdt = dt;
415 outdata(s);
416
417 xoff(s, offset);
418 return s;
419 }
420
421 /********************************
422 * Write reference to offset in code segment.
423 */
424 void coff(uint offset)
425 {
426 dt_t *dt = dt_calloc(DT_coff);
427
428 static if (TARGET_SEGMENTED)
429 dt.Dty = TYcptr;
430 else
431 dt.Dty = TYnptr;
432
433 dt.DToffset = offset;
434
435 assert(!*pTail);
436 *pTail = dt;
437 pTail = &dt.DTnext;
438 assert(!*pTail);
439 }
440
441
442 /**********************
443 * Append dt to data.
444 */
445 void cat(dt_t *dt)
446 {
447 assert(!*pTail);
448 *pTail = dt;
449 pTail = &dt.DTnext;
450 while (*pTail)
451 pTail = &((*pTail).DTnext);
452 assert(!*pTail);
453 }
454
455 /**********************
456 * Append dtb to data.
457 */
458 void cat(ref DtBuilder dtb)
459 {
460 assert(!*pTail);
461 *pTail = dtb.head;
462 pTail = dtb.pTail;
463 assert(!*pTail);
464 }
465
466 /**************************************
467 * Repeat a list of dt_t's count times.
468 */
469 void repeat(dt_t *dt, size_t count)
470 {
471 if (!count)
472 return;
473
474 uint size = dt_size(dt);
475 if (!size)
476 return;
477
478 if (dtallzeros(dt))
479 {
480 if (head && dtallzeros(head))
481 head.DTazeros += size * count;
482 else
483 nzeros(cast(uint)(size * count));
484 return;
485 }
486
487 if (dtpointers(dt))
488 {
489 dt_t *dtp = null;
490 dt_t **pdt = &dtp;
491 for (size_t i = 0; i < count; ++i)
492 {
493 for (dt_t *dtn = dt; dtn; dtn = dtn.DTnext)
494 {
495 dt_t *dtx = dt_calloc(dtn.dt);
496 *dtx = *dtn;
497 dtx.DTnext = null;
498 switch (dtx.dt)
499 {
500 case DT_abytes:
501 case DT_nbytes:
502 dtx.DTpbytes = cast(byte *) mem_malloc(dtx.DTnbytes);
503 memcpy(dtx.DTpbytes, dtn.DTpbytes, dtx.DTnbytes);
504 break;
505
506 default:
507 break;
508 }
509
510 *pdt = dtx;
511 pdt = &dtx.DTnext;
512 }
513 }
514 assert(!*pTail);
515 *pTail = dtp;
516 assert(*pdt == null);
517 pTail = pdt;
518 return;
519 }
520
521 char *p = cast(char *)mem_malloc(size * count);
522 size_t offset = 0;
523
524 for (dt_t *dtn = dt; dtn; dtn = dtn.DTnext)
525 {
526 switch (dtn.dt)
527 {
528 case DT_nbytes:
529 memcpy(p + offset, dtn.DTpbytes, dtn.DTnbytes);
530 offset += dtn.DTnbytes;
531 break;
532 case DT_ibytes:
533 memcpy(p + offset, dtn.DTdata.ptr, dtn.DTn);
534 offset += dtn.DTn;
535 break;
536 case DT_azeros:
537 memset(p + offset, 0, cast(uint)dtn.DTazeros);
538 offset += dtn.DTazeros;
539 break;
540 default:
541 debug printf("dt = %p, dt = %d\n",dt,dt.dt);
542 assert(0);
543 }
544 }
545 assert(offset == size);
546
547 for (size_t i = 1; i < count; ++i)
548 {
549 memcpy(p + offset, p, size);
550 offset += size;
551 }
552
553 dt_t *dtx = dt_calloc(DT_nbytes);
554 dtx.DTnbytes = cast(uint)(size * count);
555 dtx.DTpbytes = cast(byte*)p;
556
557
558 assert(!*pTail);
559 *pTail = dtx;
560 pTail = &dtx.DTnext;
561 assert(!*pTail);
562 }
563
564 /***************************
565 * Return size of data.
566 */
567 uint length()
568 {
569 return dt_size(head);
570 }
571
572 /************************
573 * Return true if size of data is 0.
574 */
575 bool isZeroLength()
576 {
577 return head == null;
578 }
579 }
580
581 private __gshared dt_t *dt_freelist;
582
583 /**********************************************
584 * Allocate a data definition struct.
585 */
586
587 private dt_t *dt_calloc(int dtx)
588 {
589 dt_t *dt = dt_freelist;
590 if (!dt)
591 {
592 const size_t n = 4096 / dt_t.sizeof;
593 dt_t *chunk = cast(dt_t *)mem_fmalloc(n * dt_t.sizeof);
594 for (size_t i = 0; i < n - 1; ++i)
595 {
596 chunk[i].DTnext = &chunk[i + 1];
597 }
598 chunk[n - 1].DTnext = null;
599 dt_freelist = chunk;
600 dt = chunk;
601 }
602
603 dt_freelist = dt.DTnext;
604 debug memset(dt, 0xBE, (*dt).sizeof);
605 dt.DTnext = null;
606 dt.dt = cast(char)dtx;
607 return dt;
608 }
609
610
611 /******************************************
612 * Temporary hack to initialize a dt_t* for C.
613 */
614
615 dt_t* dt_get_nzeros(uint n)
616 {
617 dt_t *dt = dt_calloc(DT_azeros);
618 dt.DTazeros = n;
619 return dt;
620 }