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 }