1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1999-2021 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  * Documentation:  https://dlang.org/phobos/dmd_backend_dt.html
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/dt.d
11  */
12 
13 module dmd.backend.dt;
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      * Params:
266      *  ty = pointer type
267      *  offset = to be added to offset of data generated
268      *  size = number of bytes pointed to by ptr
269      *  ptr = points to data bytes
270      *  nzeros = number of zero bytes to add to the end
271      *  _align = alignment of pointed-to data
272      */
273     void abytes(tym_t ty, uint offset, uint size, const(char)* ptr, uint nzeros, ubyte _align)
274     {
275         dt_t *dt = dt_calloc(DT_abytes);
276         dt.DTnbytes = size + nzeros;
277         dt.DTpbytes = cast(byte *) mem_malloc(size + nzeros);
278         dt.Dty = cast(ubyte)ty;
279         dt.DTalign = _align;
280         dt.DTabytes = offset;
281         memcpy(dt.DTpbytes,ptr,size);
282         if (nzeros)
283             memset(dt.DTpbytes + size, 0, nzeros);
284 
285         assert(!*pTail);
286         *pTail = dt;
287         pTail = &dt.DTnext;
288         assert(!*pTail);
289     }
290 
291     void abytes(uint offset, uint size, const(char)* ptr, uint nzeros, ubyte _align)
292     {
293         abytes(TYnptr, offset, size, ptr, nzeros, _align);
294     }
295 
296     /**************************************
297      * Write 4 bytes of value.
298      */
299     void dword(int value)
300     {
301         if (value == 0)
302         {
303             nzeros(4);
304             return;
305         }
306 
307         dt_t *dt = dt_calloc(DT_ibytes);
308         dt.DTn = 4;
309 
310         union U { char* cp; int* lp; }
311         U u = void;
312         u.cp = cast(char*)dt.DTdata.ptr;
313         *u.lp = value;
314 
315         assert(!*pTail);
316         *pTail = dt;
317         pTail = &dt.DTnext;
318         assert(!*pTail);
319     }
320 
321     /***********************
322      * Write a size_t value.
323      */
324     void size(ulong value)
325     {
326         if (value == 0)
327         {
328             nzeros(_tysize[TYnptr]);
329             return;
330         }
331         dt_t *dt = dt_calloc(DT_ibytes);
332         dt.DTn = _tysize[TYnptr];
333 
334         union U { char* cp; int* lp; }
335         U u = void;
336         u.cp = cast(char*)dt.DTdata.ptr;
337         *u.lp = cast(int)value;
338         if (_tysize[TYnptr] == 8)
339             u.lp[1] = cast(int)(value >> 32);
340 
341         assert(!*pTail);
342         *pTail = dt;
343         pTail = &dt.DTnext;
344         assert(!*pTail);
345     }
346 
347     /***********************
348      * Write a bunch of zeros
349      */
350     void nzeros(uint size)
351     {
352         if (!size)
353             return;
354         assert(cast(int) size > 0);
355 
356         dt_t *dt = dt_calloc(DT_azeros);
357         dt.DTazeros = size;
358 
359         assert(!*pTail);
360         *pTail = dt;
361         pTail = &dt.DTnext;
362         assert(!*pTail);
363     }
364 
365     /*************************
366      * Write a reference to s+offset
367      */
368     void xoff(Symbol *s, uint offset, tym_t ty)
369     {
370         dt_t *dt = dt_calloc(DT_xoff);
371         dt.DTsym = s;
372         dt.DToffset = offset;
373         dt.Dty = cast(ubyte)ty;
374 
375         assert(!*pTail);
376         *pTail = dt;
377         pTail = &dt.DTnext;
378         assert(!*pTail);
379     }
380 
381     /******************************
382      * Create reference to s+offset
383      */
384     void xoff(Symbol *s, uint offset)
385     {
386         xoff(s, offset, TYnptr);
387     }
388 
389     /*******************************
390      * Like xoff(), but returns handle with which to patch 'offset' value.
391      */
392     dt_t *xoffpatch(Symbol *s, uint offset, tym_t ty)
393     {
394         dt_t *dt = dt_calloc(DT_xoff);
395         dt.DTsym = s;
396         dt.DToffset = offset;
397         dt.Dty = cast(ubyte)ty;
398 
399         dt_t **pxoff = pTail;
400 
401         assert(!*pTail);
402         *pTail = dt;
403         pTail = &dt.DTnext;
404         assert(!*pTail);
405 
406         return *pxoff;
407     }
408 
409     /*************************************
410      * Create a reference to another dt.
411      * Returns: the internal symbol used for the other dt
412      */
413     Symbol *dtoff(dt_t *dt, uint offset)
414     {
415         type *t = type_alloc(TYint);
416         t.Tcount++;
417         Symbol *s = symbol_calloc("internal");
418         s.Sclass = SCstatic;
419         s.Sfl = FLextern;
420         s.Sflags |= SFLnodebug;
421         s.Stype = t;
422         s.Sdt = dt;
423         outdata(s);
424 
425         xoff(s, offset);
426         return s;
427     }
428 
429     /********************************
430      * Write reference to offset in code segment.
431      */
432     void coff(uint offset)
433     {
434         dt_t *dt = dt_calloc(DT_coff);
435 
436         if (config.exe & EX_segmented)
437             dt.Dty = TYcptr;
438         else
439             dt.Dty = TYnptr;
440 
441         dt.DToffset = offset;
442 
443         assert(!*pTail);
444         *pTail = dt;
445         pTail = &dt.DTnext;
446         assert(!*pTail);
447     }
448 
449 
450     /**********************
451      * Append dt to data.
452      */
453     void cat(dt_t *dt)
454     {
455         assert(!*pTail);
456         *pTail = dt;
457         pTail = &dt.DTnext;
458         while (*pTail)
459             pTail = &((*pTail).DTnext);
460         assert(!*pTail);
461     }
462 
463     /**********************
464      * Append dtb to data.
465      */
466     void cat(ref DtBuilder dtb)
467     {
468         assert(!*pTail);
469         *pTail = dtb.head;
470         pTail = dtb.pTail;
471         assert(!*pTail);
472     }
473 
474     /**************************************
475      * Repeat a list of dt_t's count times.
476      */
477     void repeat(dt_t *dt, size_t count)
478     {
479         if (!count)
480             return;
481 
482         uint size = dt_size(dt);
483         if (!size)
484             return;
485 
486         if (dtallzeros(dt))
487         {
488             if (head && dtallzeros(head))
489                 head.DTazeros += size * count;
490             else
491                 nzeros(cast(uint)(size * count));
492             return;
493         }
494 
495         if (dtpointers(dt))
496         {
497             dt_t *dtp = null;
498             dt_t **pdt = &dtp;
499             for (size_t i = 0; i < count; ++i)
500             {
501                 for (dt_t *dtn = dt; dtn; dtn = dtn.DTnext)
502                 {
503                     dt_t *dtx = dt_calloc(dtn.dt);
504                     *dtx = *dtn;
505                     dtx.DTnext = null;
506                     switch (dtx.dt)
507                     {
508                         case DT_abytes:
509                         case DT_nbytes:
510                             dtx.DTpbytes = cast(byte *) mem_malloc(dtx.DTnbytes);
511                             memcpy(dtx.DTpbytes, dtn.DTpbytes, dtx.DTnbytes);
512                             break;
513 
514                         default:
515                             break;
516                     }
517 
518                     *pdt = dtx;
519                     pdt = &dtx.DTnext;
520                 }
521             }
522             assert(!*pTail);
523             *pTail = dtp;
524             assert(*pdt == null);
525             pTail = pdt;
526             return;
527         }
528 
529         char *p = cast(char *)mem_malloc(size * count);
530         size_t offset = 0;
531 
532         for (dt_t *dtn = dt; dtn; dtn = dtn.DTnext)
533         {
534             switch (dtn.dt)
535             {
536                 case DT_nbytes:
537                     memcpy(p + offset, dtn.DTpbytes, dtn.DTnbytes);
538                     offset += dtn.DTnbytes;
539                     break;
540                 case DT_ibytes:
541                     memcpy(p + offset, dtn.DTdata.ptr, dtn.DTn);
542                     offset += dtn.DTn;
543                     break;
544                 case DT_azeros:
545                     memset(p + offset, 0, cast(uint)dtn.DTazeros);
546                     offset += dtn.DTazeros;
547                     break;
548                 default:
549                     debug printf("dt = %p, dt = %d\n",dt,dt.dt);
550                     assert(0);
551             }
552         }
553         assert(offset == size);
554 
555         for (size_t i = 1; i < count; ++i)
556         {
557             memcpy(p + offset, p, size);
558             offset += size;
559         }
560 
561         dt_t *dtx = dt_calloc(DT_nbytes);
562         dtx.DTnbytes = cast(uint)(size * count);
563         dtx.DTpbytes = cast(byte*)p;
564 
565 
566         assert(!*pTail);
567         *pTail = dtx;
568         pTail = &dtx.DTnext;
569         assert(!*pTail);
570     }
571 
572     /***************************
573      * Return size of data.
574      */
575     uint length()
576     {
577         return dt_size(head);
578     }
579 
580     /************************
581      * Return true if size of data is 0.
582      */
583     bool isZeroLength()
584     {
585         return head == null;
586     }
587 }
588 
589 private __gshared dt_t *dt_freelist;
590 
591 /**********************************************
592  * Allocate a data definition struct.
593  */
594 
595 private dt_t *dt_calloc(int dtx)
596 {
597     dt_t *dt = dt_freelist;
598     if (!dt)
599     {
600         const size_t n = 4096 / dt_t.sizeof;
601         dt_t *chunk = cast(dt_t *)mem_fmalloc(n * dt_t.sizeof);
602         for (size_t i = 0; i < n - 1; ++i)
603         {
604             chunk[i].DTnext = &chunk[i + 1];
605         }
606         chunk[n - 1].DTnext = null;
607         dt_freelist = chunk;
608         dt = chunk;
609     }
610 
611     dt_freelist = dt.DTnext;
612     debug memset(dt, 0xBE, (*dt).sizeof);
613     dt.DTnext = null;
614     dt.dt = cast(char)dtx;
615     return dt;
616 }
617 
618 
619 /******************************************
620  * Temporary hack to initialize a dt_t* for C.
621  */
622 
623 dt_t* dt_get_nzeros(uint n)
624 {
625     dt_t *dt = dt_calloc(DT_azeros);
626     dt.DTazeros = n;
627     return dt;
628 }