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