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