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 }