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 }