1 /** 2 * Put initializers and objects created from CTFE into a `dt_t` data structure 3 * so the backend puts them into the data segment. 4 * 5 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/todt.d, _todt.d) 9 * Documentation: https://dlang.org/phobos/dmd_todt.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/todt.d 11 */ 12 13 module dmd.todt; 14 15 import core.stdc.stdio; 16 import core.stdc.string; 17 18 import dmd.root.array; 19 import dmd.root.complex; 20 import dmd.root.rmem; 21 22 import dmd.aggregate; 23 import dmd.arraytypes; 24 import dmd.astenums; 25 import dmd.backend.type; 26 import dmd.ctfeexpr; 27 import dmd.declaration; 28 import dmd.dclass; 29 import dmd.denum; 30 import dmd.dstruct; 31 import dmd.dsymbol; 32 import dmd.dtemplate; 33 import dmd.errors; 34 import dmd.expression; 35 import dmd.func; 36 import dmd.globals; 37 import dmd.glue; 38 import dmd.init; 39 import dmd.location; 40 import dmd.mtype; 41 import dmd.target; 42 import dmd.tokens; 43 import dmd.tocsym; 44 import dmd.toobj; 45 import dmd.typesem; 46 import dmd.visitor; 47 48 import dmd.backend.cc; 49 import dmd.backend.dt; 50 51 /* A dt_t is a simple structure representing data to be added 52 * to the data segment of the output object file. As such, 53 * it is a list of initialized bytes, 0 data, and offsets from 54 * other symbols. 55 * Each D symbol and type can be converted into a dt_t so it can 56 * be written to the data segment. 57 */ 58 59 alias Dts = Array!(dt_t*); 60 61 /* ================================================================ */ 62 63 extern (C++) void Initializer_toDt(Initializer init, ref DtBuilder dtb, bool isCfile) 64 { 65 void visitError(ErrorInitializer) 66 { 67 assert(0); 68 } 69 70 void visitVoid(VoidInitializer vi) 71 { 72 /* Void initializers are set to 0, just because we need something 73 * to set them to in the static data segment. 74 */ 75 dtb.nzeros(cast(uint)vi.type.size()); 76 } 77 78 void visitStruct(StructInitializer si) 79 { 80 /* The StructInitializer was converted to a StructLiteralExp, 81 * which is converted to dtb by membersToDt() 82 */ 83 //printf("StructInitializer.toDt('%s')\n", si.toChars()); 84 assert(0); 85 } 86 87 void visitArray(ArrayInitializer ai) 88 { 89 //printf("ArrayInitializer.toDt('%s')\n", ai.toChars()); 90 Type tb = ai.type.toBasetype(); 91 if (tb.ty == Tvector) 92 tb = (cast(TypeVector)tb).basetype; 93 94 Type tn = tb.nextOf().toBasetype(); 95 96 //printf("\tdim = %d\n", ai.dim); 97 Dts dts = Dts(ai.dim); 98 dts.zero(); 99 100 uint size = cast(uint)tn.size(); 101 102 uint length = 0; 103 foreach (i, idx; ai.index) 104 { 105 if (idx) 106 length = cast(uint)idx.toInteger(); 107 //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, ai.dim); 108 109 assert(length < ai.dim); 110 auto dtb = DtBuilder(0); 111 Initializer_toDt(ai.value[i], dtb, isCfile); 112 if (dts[length] && !ai.isCarray) 113 error(ai.loc, "duplicate initializations for index `%d`", length); 114 dts[length] = dtb.finish(); 115 length++; 116 } 117 118 Expression edefault = tb.nextOf().defaultInit(Loc.initial, isCfile); 119 120 const n = tn.numberOfElems(ai.loc); 121 122 dt_t* dtdefault = null; 123 124 auto dtbarray = DtBuilder(0); 125 foreach (dt; dts) 126 { 127 if (dt) 128 dtbarray.cat(dt); 129 else 130 { 131 if (!dtdefault) 132 { 133 auto dtb = DtBuilder(0); 134 Expression_toDt(edefault, dtb); 135 dtdefault = dtb.finish(); 136 } 137 dtbarray.repeat(dtdefault, n); 138 } 139 } 140 switch (tb.ty) 141 { 142 case Tsarray: 143 { 144 TypeSArray ta = cast(TypeSArray)tb; 145 size_t tadim = cast(size_t)ta.dim.toInteger(); 146 if (ai.dim < tadim) 147 { 148 if (edefault.toBool().hasValue(false)) 149 { 150 // pad out end of array 151 dtbarray.nzeros(cast(uint)(size * (tadim - ai.dim))); 152 } 153 else 154 { 155 if (!dtdefault) 156 { 157 auto dtb = DtBuilder(0); 158 Expression_toDt(edefault, dtb); 159 dtdefault = dtb.finish(); 160 } 161 162 const m = n * (tadim - ai.dim); 163 assert(m <= uint.max); 164 dtbarray.repeat(dtdefault, cast(uint)m); 165 } 166 } 167 else if (ai.dim > tadim) 168 { 169 error(ai.loc, "too many initializers, %u, for array[%llu]", ai.dim, cast(ulong) tadim); 170 } 171 dtb.cat(dtbarray); 172 break; 173 } 174 175 case Tpointer: 176 case Tarray: 177 { 178 if (tb.ty == Tarray) 179 dtb.size(ai.dim); 180 Symbol* s = dtb.dtoff(dtbarray.finish(), 0); 181 if (tn.isMutable()) 182 foreach (i; 0 .. ai.dim) 183 write_pointers(tn, s, size * cast(int)i); 184 break; 185 } 186 187 default: 188 assert(0); 189 } 190 dt_free(dtdefault); 191 } 192 193 void visitExp(ExpInitializer ei) 194 { 195 //printf("ExpInitializer.toDt() %s\n", ei.exp.toChars()); 196 ei.exp = ei.exp.optimize(WANTvalue); 197 Expression_toDt(ei.exp, dtb); 198 } 199 200 void visitC(CInitializer ci) 201 { 202 /* Should have been rewritten to Exp/Struct/ArrayInitializer by semantic() 203 */ 204 assert(0); 205 } 206 207 mixin VisitInitializer!void visit; 208 visit.VisitInitializer(init); 209 } 210 211 /* ================================================================ */ 212 213 extern (C++) void Expression_toDt(Expression e, ref DtBuilder dtb) 214 { 215 dtb.checkInitialized(); 216 217 void nonConstExpError(Expression e) 218 { 219 version (none) 220 { 221 printf("Expression.toDt() op = %d e = %s \n", e.op, e.toChars()); 222 } 223 error(e.loc, "non-constant expression `%s`", e.toChars()); 224 dtb.nzeros(1); 225 } 226 227 void visitSlice(SliceExp e) 228 { 229 version (none) 230 { 231 printf("SliceExp.toDt() %d from %s to %s\n", e.op, e.e1.type.toChars(), e.type.toChars()); 232 } 233 if (!e.lwr && !e.upr) 234 return Expression_toDt(e.e1, dtb); 235 if (auto strExp = e.e1.isStringExp()) 236 { 237 auto lwr = e.lwr.isIntegerExp(); 238 auto upr = e.upr.isIntegerExp(); 239 if (lwr && upr && lwr.toInteger() == 0 && upr.toInteger() == strExp.len) 240 return Expression_toDt(e.e1, dtb); 241 } 242 243 nonConstExpError(e); 244 } 245 246 void visitCast(CastExp e) 247 { 248 version (none) 249 { 250 printf("CastExp.toDt() %d from %s to %s\n", e.op, e.e1.type.toChars(), e.type.toChars()); 251 } 252 if (e.e1.type.ty == Tclass) 253 { 254 if (auto toc = e.type.isTypeClass()) 255 { 256 if (auto toi = toc.sym.isInterfaceDeclaration()) // casting from class to interface 257 { 258 auto cre1 = e.e1.isClassReferenceExp(); 259 ClassDeclaration from = cre1.originalClass(); 260 int off = 0; 261 const isbase = toi.isBaseOf(from, &off); 262 assert(isbase); 263 ClassReferenceExp_toDt(cre1, dtb, off); 264 } 265 else //casting from class to class 266 { 267 Expression_toDt(e.e1, dtb); 268 } 269 return; 270 } 271 } 272 nonConstExpError(e); 273 } 274 275 void visitAddr(AddrExp e) 276 { 277 version (none) 278 { 279 printf("AddrExp.toDt() %d\n", e.op); 280 } 281 if (auto sl = e.e1.isStructLiteralExp()) 282 { 283 Symbol* s = toSymbol(sl); 284 dtb.xoff(s, 0); 285 if (sl.type.isMutable()) 286 write_pointers(sl.type, s, 0); 287 return; 288 } 289 nonConstExpError(e); 290 } 291 292 void visitInteger(IntegerExp e) 293 { 294 //printf("IntegerExp.toDt() %d\n", e.op); 295 const sz = cast(uint)e.type.size(); 296 if (auto value = e.getInteger()) 297 dtb.nbytes(sz, cast(char*)&value); 298 else 299 dtb.nzeros(sz); 300 } 301 302 void visitReal(RealExp e) 303 { 304 //printf("RealExp.toDt(%Lg)\n", e.value); 305 switch (e.type.toBasetype().ty) 306 { 307 case Tfloat32: 308 case Timaginary32: 309 { 310 auto fvalue = cast(float)e.value; 311 dtb.nbytes(4, cast(char*)&fvalue); 312 break; 313 } 314 315 case Tfloat64: 316 case Timaginary64: 317 { 318 auto dvalue = cast(double)e.value; 319 dtb.nbytes(8, cast(char*)&dvalue); 320 break; 321 } 322 323 case Tfloat80: 324 case Timaginary80: 325 { 326 auto evalue = e.value; 327 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 328 dtb.nzeros(target.realpad); 329 break; 330 } 331 332 default: 333 printf("%s, e.type=%s\n", e.toChars(), e.type.toChars()); 334 assert(0); 335 } 336 } 337 338 void visitComplex(ComplexExp e) 339 { 340 //printf("ComplexExp.toDt() '%s'\n", e.toChars()); 341 switch (e.type.toBasetype().ty) 342 { 343 case Tcomplex32: 344 { 345 auto fvalue = cast(float)creall(e.value); 346 dtb.nbytes(4, cast(char*)&fvalue); 347 fvalue = cast(float)cimagl(e.value); 348 dtb.nbytes(4, cast(char*)&fvalue); 349 break; 350 } 351 352 case Tcomplex64: 353 { 354 auto dvalue = cast(double)creall(e.value); 355 dtb.nbytes(8, cast(char*)&dvalue); 356 dvalue = cast(double)cimagl(e.value); 357 dtb.nbytes(8, cast(char*)&dvalue); 358 break; 359 } 360 361 case Tcomplex80: 362 { 363 auto evalue = creall(e.value); 364 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 365 dtb.nzeros(target.realpad); 366 evalue = cimagl(e.value); 367 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 368 dtb.nzeros(target.realpad); 369 break; 370 } 371 372 default: 373 assert(0); 374 } 375 } 376 377 void visitNull(NullExp e) 378 { 379 assert(e.type); 380 dtb.nzeros(cast(uint)e.type.size()); 381 } 382 383 void visitString(StringExp e) 384 { 385 //printf("StringExp.toDt() '%s', type = %s\n", e.toChars(), e.type.toChars()); 386 Type t = e.type.toBasetype(); 387 388 // BUG: should implement some form of static string pooling 389 const n = cast(int)e.numberOfCodeUnits(); 390 const(char)* p; 391 char* q; 392 if (e.sz == 1) 393 p = e.peekString().ptr; 394 else 395 { 396 q = cast(char*)mem.xmalloc(n * e.sz); 397 e.writeTo(q, false); 398 p = q; 399 } 400 401 switch (t.ty) 402 { 403 case Tarray: 404 dtb.size(n); 405 goto case Tpointer; 406 407 case Tpointer: 408 if (e.sz == 1) 409 { 410 import dmd.e2ir : toStringSymbol; 411 import dmd.glue : totym; 412 Symbol* s = toStringSymbol(p, n, e.sz); 413 dtb.xoff(s, 0); 414 } 415 else 416 { 417 ubyte pow2 = e.sz == 4 ? 2 : 1; 418 dtb.abytes(0, n * e.sz, p, cast(uint)e.sz, pow2); 419 } 420 break; 421 422 case Tsarray: 423 { 424 auto tsa = t.isTypeSArray(); 425 426 dtb.nbytes(n * e.sz, p); 427 if (tsa.dim) 428 { 429 dinteger_t dim = tsa.dim.toInteger(); 430 if (n < dim) 431 { 432 // Pad remainder with 0 433 dtb.nzeros(cast(uint)((dim - n) * tsa.next.size())); 434 } 435 } 436 break; 437 } 438 439 default: 440 printf("StringExp.toDt(type = %s)\n", e.type.toChars()); 441 assert(0); 442 } 443 mem.xfree(q); 444 } 445 446 void visitArrayLiteral(ArrayLiteralExp e) 447 { 448 //printf("ArrayLiteralExp.toDt() '%s', type = %s\n", e.toChars(), e.type.toChars()); 449 450 auto dtbarray = DtBuilder(0); 451 foreach (i; 0 .. e.elements.length) 452 { 453 Expression_toDt(e[i], dtbarray); 454 } 455 456 Type t = e.type.toBasetype(); 457 switch (t.ty) 458 { 459 case Tsarray: 460 dtb.cat(dtbarray); 461 break; 462 463 case Tarray: 464 dtb.size(e.elements.length); 465 goto case Tpointer; 466 467 case Tpointer: 468 { 469 if (auto d = dtbarray.finish()) 470 dtb.dtoff(d, 0); 471 else 472 dtb.size(0); 473 474 break; 475 } 476 477 default: 478 assert(0); 479 } 480 } 481 482 /* https://issues.dlang.org/show_bug.cgi?id=12652 483 Non-constant hash initializers should have a special-case diagnostic 484 */ 485 void visitAssocArrayLiteral(AssocArrayLiteralExp e) 486 { 487 if (!e.lowering) 488 { 489 error(e.loc, "internal compiler error: failed to detect static initialization of associative array"); 490 assert(0); 491 } 492 Expression_toDt(e.lowering, dtb); 493 return; 494 } 495 496 void visitStructLiteral(StructLiteralExp sle) 497 { 498 //printf("StructLiteralExp.toDt() %s, ctfe = %d\n", sle.toChars(), sle.ownedByCtfe); 499 assert(sle.sd.nonHiddenFields() <= sle.elements.length); 500 membersToDt(sle.sd, dtb, sle.elements, 0, null, null); 501 } 502 503 void visitSymOff(SymOffExp e) 504 { 505 //printf("SymOffExp.toDt('%s')\n", e.var.toChars()); 506 assert(e.var); 507 if (!(e.var.isDataseg() || e.var.isCodeseg()) || 508 e.var.isThreadlocal()) 509 { 510 return nonConstExpError(e); 511 } 512 dtb.xoff(toSymbol(e.var), cast(uint)e.offset); 513 } 514 515 void visitVar(VarExp e) 516 { 517 //printf("VarExp.toDt() %d\n", e.op); 518 519 if (auto v = e.var.isVarDeclaration()) 520 { 521 if ((v.isConst() || v.isImmutable()) && 522 e.type.toBasetype().ty != Tsarray && v._init) 523 { 524 error(e.loc, "recursive reference `%s`", e.toChars()); 525 return; 526 } 527 v.inuse++; 528 Initializer_toDt(v._init, dtb, v.isCsymbol()); 529 v.inuse--; 530 return; 531 } 532 533 if (auto sd = e.var.isSymbolDeclaration()) 534 { 535 if (sd.dsym) 536 { 537 538 if (auto s = sd.dsym.isStructDeclaration()) 539 StructDeclaration_toDt(s, dtb); 540 else if (auto c = sd.dsym.isClassDeclaration()) 541 // Should be unreachable ATM, but just to be sure 542 ClassDeclaration_toDt(c, dtb); 543 else 544 assert(false); 545 return; 546 } 547 } 548 549 return nonConstExpError(e); 550 } 551 552 void visitFunc(FuncExp e) 553 { 554 //printf("FuncExp.toDt() %d\n", e.op); 555 if (e.fd.tok == TOK.reserved && e.type.ty == Tpointer) 556 { 557 // change to non-nested 558 e.fd.tok = TOK.function_; 559 e.fd.vthis = null; 560 } 561 Symbol *s = toSymbol(e.fd); 562 toObjFile(e.fd, false); 563 if (e.fd.tok == TOK.delegate_) 564 dtb.size(0); 565 dtb.xoff(s, 0); 566 } 567 568 void visitVector(VectorExp e) 569 { 570 //printf("VectorExp.toDt() %s\n", e.toChars()); 571 foreach (i; 0 .. e.dim) 572 { 573 Expression elem; 574 if (auto ale = e.e1.isArrayLiteralExp()) 575 elem = ale[i]; 576 else 577 elem = e.e1; 578 Expression_toDt(elem, dtb); 579 } 580 } 581 582 void visitClassReference(ClassReferenceExp e) 583 { 584 auto to = e.type.toBasetype().isTypeClass().sym.isInterfaceDeclaration(); 585 586 if (to) //Static typeof this literal is an interface. We must add offset to symbol 587 { 588 ClassDeclaration from = e.originalClass(); 589 int off = 0; 590 const isbase = to.isBaseOf(from, &off); 591 assert(isbase); 592 ClassReferenceExp_toDt(e, dtb, off); 593 } 594 else 595 ClassReferenceExp_toDt(e, dtb, 0); 596 } 597 598 void visitTypeid(TypeidExp e) 599 { 600 if (Type t = isType(e.obj)) 601 { 602 TypeInfo_toObjFile(e, e.loc, t); 603 Symbol *s = toSymbol(t.vtinfo); 604 dtb.xoff(s, 0); 605 return; 606 } 607 assert(0); 608 } 609 610 void visitNoreturn(Expression e) 611 { 612 // Noreturn field with default initializer 613 assert(e); 614 } 615 616 switch (e.op) 617 { 618 default: return nonConstExpError(e); 619 case EXP.cast_: return visitCast (e.isCastExp()); 620 case EXP.address: return visitAddr (e.isAddrExp()); 621 case EXP.int64: return visitInteger (e.isIntegerExp()); 622 case EXP.float64: return visitReal (e.isRealExp()); 623 case EXP.complex80: return visitComplex (e.isComplexExp()); 624 case EXP.null_: return visitNull (e.isNullExp()); 625 case EXP.string_: return visitString (e.isStringExp()); 626 case EXP.arrayLiteral: return visitArrayLiteral (e.isArrayLiteralExp()); 627 case EXP.structLiteral: return visitStructLiteral (e.isStructLiteralExp()); 628 case EXP.symbolOffset: return visitSymOff (e.isSymOffExp()); 629 case EXP.variable: return visitVar (e.isVarExp()); 630 case EXP.function_: return visitFunc (e.isFuncExp()); 631 case EXP.vector: return visitVector (e.isVectorExp()); 632 case EXP.classReference: return visitClassReference(e.isClassReferenceExp()); 633 case EXP.typeid_: return visitTypeid (e.isTypeidExp()); 634 case EXP.assert_: return visitNoreturn (e); 635 case EXP.slice: return visitSlice (e.isSliceExp()); 636 case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); 637 } 638 } 639 640 /* ================================================================= */ 641 642 // Generate the data for the static initializer. 643 644 extern (C++) void ClassDeclaration_toDt(ClassDeclaration cd, ref DtBuilder dtb) 645 { 646 //printf("ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 647 648 membersToDt(cd, dtb, null, 0, cd, null); 649 650 //printf("-ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 651 } 652 653 extern (C++) void StructDeclaration_toDt(StructDeclaration sd, ref DtBuilder dtb) 654 { 655 //printf("+StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 656 membersToDt(sd, dtb, null, 0, null, null); 657 658 //printf("-StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 659 } 660 661 /****************************** 662 * Generate data for instance of __cpp_type_info_ptr that refers 663 * to the C++ RTTI symbol for cd. 664 * Params: 665 * cd = C++ class 666 * dtb = data table builder 667 */ 668 extern (C++) void cpp_type_info_ptr_toDt(ClassDeclaration cd, ref DtBuilder dtb) 669 { 670 //printf("cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 671 assert(cd.isCPPclass()); 672 673 // Put in first two members, the vtbl[] and the monitor 674 dtb.xoff(toVtblSymbol(ClassDeclaration.cpp_type_info_ptr), 0); 675 if (ClassDeclaration.cpp_type_info_ptr.hasMonitor()) 676 dtb.size(0); // monitor 677 678 // Create symbol for C++ type info 679 Symbol *s = toSymbolCppTypeInfo(cd); 680 681 // Put in address of cd's C++ type info 682 dtb.xoff(s, 0); 683 684 //printf("-cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 685 } 686 687 /**************************************************** 688 * Put out initializers of ad.fields[]. 689 * Although this is consistent with the elements[] version, we 690 * have to use this optimized version to reduce memory footprint. 691 * Params: 692 * ad = aggregate with members 693 * dtb = initializer list to append initialized data to 694 * elements = values to use as initializers, null means use default initializers 695 * firstFieldIndex = starting place in elements[firstFieldIndex]; always 0 for structs 696 * concreteType = structs: null, classes: most derived class 697 * ppb = pointer that moves through BaseClass[] from most derived class 698 * Returns: 699 * updated tail of dt_t list 700 */ 701 702 private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb, 703 Expressions* elements, size_t firstFieldIndex, 704 ClassDeclaration concreteType, 705 BaseClass*** ppb) 706 { 707 ClassDeclaration cd = ad.isClassDeclaration(); 708 const bool isCtype = ad.isCsymbol(); 709 version (none) 710 { 711 printf("membersToDt(ad = '%s', concrete = '%s', ppb = %p)\n", ad.toChars(), concreteType ? concreteType.toChars() : "null", ppb); 712 version (none) 713 { 714 printf(" interfaces.length = %d\n", cast(int)cd.interfaces.length); 715 foreach (i, b; cd.vtblInterfaces[]) 716 { 717 printf(" vbtblInterfaces[%d] b = %p, b.sym = %s\n", cast(int)i, b, b.sym.toChars()); 718 } 719 } 720 version (all) 721 { 722 foreach (i, field; ad.fields) 723 { 724 if (auto bf = field.isBitFieldDeclaration()) 725 printf(" fields[%d]: %s %2d bitoffset %2d width %2d\n", cast(int)i, bf.toChars(), bf.offset, bf.bitOffset, bf.fieldWidth); 726 else 727 printf(" fields[%d]: %s %2d\n", cast(int)i, field.toChars(), field.offset); 728 } 729 } 730 version (none) 731 { 732 printf(" firstFieldIndex: %d\n", cast(int)firstFieldIndex); 733 foreach (i; 0 .. elements.length) 734 { 735 auto e = (*elements)[i]; 736 printf(" elements[%d]: %s\n", cast(int)i, e ? e.toChars() : "null"); 737 } 738 } 739 } 740 dtb.checkInitialized(); 741 //printf("+dtb.length: %d\n", dtb.length); 742 743 /* Order: 744 * { base class } or { __vptr, __monitor } 745 * interfaces 746 * fields 747 */ 748 749 uint offset; 750 if (cd) 751 { 752 const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo; 753 const bool genclassinfo = gentypeinfo || !(cd.isCPPclass || cd.isCOMclass); 754 755 if (ClassDeclaration cdb = cd.baseClass) 756 { 757 // Insert { base class } 758 size_t index = 0; 759 for (ClassDeclaration c = cdb.baseClass; c; c = c.baseClass) 760 index += c.fields.length; 761 membersToDt(cdb, dtb, elements, index, concreteType, null); 762 offset = cdb.structsize; 763 } 764 else if (InterfaceDeclaration id = cd.isInterfaceDeclaration()) 765 { 766 offset = (**ppb).offset; 767 if (id.vtblInterfaces.length == 0 && genclassinfo) 768 { 769 BaseClass* b = **ppb; 770 //printf(" Interface %s, b = %p\n", id.toChars(), b); 771 ++(*ppb); 772 for (ClassDeclaration cd2 = concreteType; 1; cd2 = cd2.baseClass) 773 { 774 assert(cd2); 775 uint csymoffset = baseVtblOffset(cd2, b); 776 //printf(" cd2 %s csymoffset = x%x\n", cd2 ? cd2.toChars() : "null", csymoffset); 777 if (csymoffset != ~0) 778 { 779 dtb.xoff(toSymbol(cd2), csymoffset); 780 offset += target.ptrsize; 781 break; 782 } 783 } 784 } 785 } 786 else 787 { 788 // Insert { __vptr, __monitor } 789 dtb.xoff(toVtblSymbol(concreteType), 0); // __vptr 790 offset = target.ptrsize; 791 if (cd.hasMonitor()) 792 { 793 dtb.size(0); // __monitor 794 offset += target.ptrsize; 795 } 796 } 797 798 // Interface vptr initializations 799 if (genclassinfo) 800 { 801 toSymbol(cd); // define csym 802 } 803 804 BaseClass** pb; 805 if (!ppb) 806 { 807 pb = (*cd.vtblInterfaces)[].ptr; 808 ppb = &pb; 809 } 810 811 foreach (si; cd.interfaces[]) 812 { 813 BaseClass* b = **ppb; 814 if (offset < b.offset) 815 dtb.nzeros(b.offset - offset); 816 membersToDt(si.sym, dtb, elements, firstFieldIndex, concreteType, ppb); 817 //printf("b.offset = %d, b.sym.structsize = %d\n", cast(int)b.offset, cast(int)b.sym.structsize); 818 offset = b.offset + b.sym.structsize; 819 } 820 } 821 else 822 offset = 0; 823 // `offset` now is where the fields start 824 825 assert(!elements || 826 firstFieldIndex <= elements.length && 827 firstFieldIndex + ad.fields.length <= elements.length); 828 829 uint bitByteOffset = 0; // byte offset of bit field 830 uint bitOffset = 0; // starting bit number 831 ulong bitFieldValue = 0; // in-flight bit field value 832 uint bitFieldSize; // in-flight size in bytes of bit field 833 834 void finishInFlightBitField() 835 { 836 if (bitOffset) 837 { 838 //printf("finishInFlightBitField() offset %d bitOffset %d bitFieldSize %d bitFieldValue x%llx\n", offset, bitOffset, bitFieldSize, bitFieldValue); 839 assert(bitFieldSize); 840 841 // advance to start of bit field 842 if (offset < bitByteOffset) 843 { 844 dtb.nzeros(bitByteOffset - offset); 845 offset = bitByteOffset; 846 } 847 848 dtb.nbytes(bitFieldSize, cast(char*)&bitFieldValue); 849 offset += bitFieldSize; 850 bitOffset = 0; 851 bitFieldValue = 0; 852 bitFieldSize = 0; 853 } 854 } 855 856 static if (0) 857 { 858 foreach (i, field; ad.fields) 859 { 860 if (elements && !(*elements)[firstFieldIndex + i]) 861 continue; // no element for this field 862 863 if (!elements || !(*elements)[firstFieldIndex + i]) 864 { 865 if (field._init && field._init.isVoidInitializer()) 866 continue; // void initializer for this field 867 } 868 869 VarDeclaration vd = field; 870 auto bf = vd.isBitFieldDeclaration(); 871 if (bf) 872 printf("%s\t offset: %d width: %u bit: %u\n", bf.toChars(), bf.offset, bf.fieldWidth, bf.bitOffset); 873 else 874 printf("%s\t offset: %d\n", vd.toChars(), vd.offset); 875 } 876 } 877 878 foreach (i, field; ad.fields) 879 { 880 // skip if no element for this field 881 if (elements && !(*elements)[firstFieldIndex + i]) 882 continue; 883 884 // If void initializer 885 if (!elements || !(*elements)[firstFieldIndex + i]) 886 { 887 if (field._init && field._init.isVoidInitializer()) 888 continue; 889 } 890 891 /* This loop finds vd, the closest field that starts at `offset + bitOffset` or later 892 */ 893 VarDeclaration vd; 894 // Cache some extra information about vd 895 BitFieldDeclaration bf; // bit field version of vd 896 size_t k; // field index of vd 897 uint vdBitOffset; // starting bit number of vd; 0 if not a bit field 898 foreach (j; i .. ad.fields.length) 899 { 900 VarDeclaration v2 = ad.fields[j]; 901 if (v2.offset < offset) 902 continue; 903 904 if (elements && !(*elements)[firstFieldIndex + j]) 905 continue; 906 907 if (!elements || !(*elements)[firstFieldIndex + j]) 908 { 909 if (v2._init && v2._init.isVoidInitializer()) 910 continue; 911 } 912 //printf(" checking v2 %s %d\n", v2.toChars(), v2.offset); 913 914 auto bf2 = v2.isBitFieldDeclaration(); 915 uint v2BitOffset = bf2 ? bf2.bitOffset : 0; 916 917 if (v2.offset * 8 + v2BitOffset < offset * 8 + vdBitOffset) 918 continue; 919 920 // find the nearest field 921 if (!vd || 922 v2.offset * 8 + v2BitOffset < vd.offset * 8 + vdBitOffset) 923 { 924 // v2 is nearer, so remember the details 925 //printf(" v2 %s is nearer\n", v2.toChars()); 926 vd = v2; 927 bf = bf2; 928 vdBitOffset = v2BitOffset; 929 k = j; 930 } 931 } 932 if (!vd) 933 { 934 continue; 935 } 936 937 if (!bf || bf.offset != offset) 938 { 939 finishInFlightBitField(); 940 } 941 if (bf) 942 { 943 switch (target.c.bitFieldStyle) 944 { 945 case TargetC.BitFieldStyle.Gcc_Clang: 946 bitFieldSize = (bf.bitOffset + bf.fieldWidth + 7) / 8; 947 break; 948 949 case TargetC.BitFieldStyle.DM: 950 case TargetC.BitFieldStyle.MS: 951 // This relies on all bit fields in the same storage location have the same type 952 bitFieldSize = cast(uint)vd.type.size(); 953 break; 954 955 default: 956 assert(0); 957 } 958 } 959 960 //printf("offset: %u, vd: %s vd.offset: %u\n", offset, vd.toChars(), vd.offset); 961 if (vd.offset < offset) 962 continue; // a union field 963 if (offset < vd.offset) 964 { 965 dtb.nzeros(vd.offset - offset); 966 offset = vd.offset; 967 } 968 969 auto dtbx = DtBuilder(0); 970 if (elements) 971 { 972 Expression e = (*elements)[firstFieldIndex + k]; 973 //printf("elements initializer %s\n", e.toChars()); 974 if (auto tsa = vd.type.toBasetype().isTypeSArray()) 975 toDtElem(tsa, dtbx, e, isCtype); 976 else if (bf) 977 { 978 auto ie = e.isIntegerExp(); 979 assert(ie); 980 auto value = ie.getInteger(); 981 const width = bf.fieldWidth; 982 const mask = (1L << width) - 1; 983 bitFieldValue = (bitFieldValue & ~(mask << bitOffset)) | ((value & mask) << bitOffset); 984 //printf("bitFieldValue x%llx\n", bitFieldValue); 985 } 986 else 987 Expression_toDt(e, dtbx); // convert e to an initializer dt 988 } 989 else if (!bf) 990 { 991 if (Initializer init = vd._init) 992 { 993 //printf("\t\t%s has initializer %s\n", vd.toChars(), init.toChars()); 994 if (init.isVoidInitializer()) 995 continue; 996 997 assert(vd.semanticRun >= PASS.semantic2done); 998 999 auto ei = init.isExpInitializer(); 1000 auto tsa = vd.type.toBasetype().isTypeSArray(); 1001 if (ei && tsa) 1002 toDtElem(tsa, dtbx, ei.exp, isCtype); 1003 else 1004 Initializer_toDt(init, dtbx, isCtype); 1005 } 1006 else if (offset <= vd.offset) 1007 { 1008 //printf("\t\tdefault initializer\n"); 1009 Type_toDt(vd.type, dtbx); 1010 } 1011 if (dtbx.isZeroLength()) 1012 continue; 1013 } 1014 1015 if (!dtbx.isZeroLength()) 1016 dtb.cat(dtbx); 1017 if (bf) 1018 { 1019 bitByteOffset = bf.offset; 1020 bitOffset = bf.bitOffset + bf.fieldWidth; 1021 } 1022 else 1023 { 1024 offset = cast(uint)(vd.offset + vd.type.size()); 1025 } 1026 } 1027 1028 finishInFlightBitField(); 1029 1030 if (offset < ad.structsize) 1031 dtb.nzeros(ad.structsize - offset); 1032 //printf("-dtb.length: %d\n", dtb.length); 1033 } 1034 1035 1036 /* ================================================================= */ 1037 1038 extern (C++) void Type_toDt(Type t, ref DtBuilder dtb, bool isCtype = false) 1039 { 1040 switch (t.ty) 1041 { 1042 case Tvector: 1043 toDtElem(t.isTypeVector().basetype.isTypeSArray(), dtb, null, isCtype); 1044 break; 1045 1046 case Tsarray: 1047 toDtElem(t.isTypeSArray(), dtb, null, isCtype); 1048 break; 1049 1050 case Tstruct: 1051 StructDeclaration_toDt(t.isTypeStruct().sym, dtb); 1052 break; 1053 1054 default: 1055 Expression_toDt(t.defaultInit(Loc.initial, isCtype), dtb); 1056 break; 1057 } 1058 } 1059 1060 private void toDtElem(TypeSArray tsa, ref DtBuilder dtb, Expression e, bool isCtype) 1061 { 1062 //printf("TypeSArray.toDtElem() tsa = %s\n", tsa.toChars()); 1063 if (tsa.size(Loc.initial) == 0) 1064 { 1065 dtb.nzeros(0); 1066 } 1067 else 1068 { 1069 size_t len = cast(size_t)tsa.dim.toInteger(); 1070 assert(len); 1071 Type tnext = tsa.next; 1072 Type tbn = tnext.toBasetype(); 1073 Type ten = e ? e.type : null; 1074 if (ten && (ten.ty == Tsarray || ten.ty == Tarray)) 1075 ten = ten.nextOf(); 1076 while (tbn.ty == Tsarray && (!e || !tbn.equivalent(ten))) 1077 { 1078 len *= tbn.isTypeSArray().dim.toInteger(); 1079 tnext = tbn.nextOf(); 1080 tbn = tnext.toBasetype(); 1081 } 1082 if (!e) // if not already supplied 1083 e = tsa.defaultInit(Loc.initial, isCtype); // use default initializer 1084 1085 if (!e.type.implicitConvTo(tnext)) // https://issues.dlang.org/show_bug.cgi?id=14996 1086 { 1087 // https://issues.dlang.org/show_bug.cgi?id=1914 1088 // https://issues.dlang.org/show_bug.cgi?id=3198 1089 if (auto se = e.isStringExp()) 1090 len /= se.numberOfCodeUnits(); 1091 else if (auto ae = e.isArrayLiteralExp()) 1092 len /= ae.elements.length; 1093 } 1094 1095 auto dtb2 = DtBuilder(0); 1096 Expression_toDt(e, dtb2); 1097 dt_t* dt2 = dtb2.finish(); 1098 assert(len <= uint.max); 1099 dtb.repeat(dt2, cast(uint)len); 1100 } 1101 } 1102 1103 /*****************************************************/ 1104 /* CTFE stuff */ 1105 /*****************************************************/ 1106 1107 private void ClassReferenceExp_toDt(ClassReferenceExp e, ref DtBuilder dtb, int off) 1108 { 1109 //printf("ClassReferenceExp.toDt() %d\n", e.op); 1110 Symbol* s = toSymbol(e); 1111 dtb.xoff(s, off); 1112 if (e.type.isMutable()) 1113 write_instance_pointers(e.type, s, 0); 1114 } 1115 1116 extern (C++) void ClassReferenceExp_toInstanceDt(ClassReferenceExp ce, ref DtBuilder dtb) 1117 { 1118 //printf("ClassReferenceExp.toInstanceDt() %d\n", ce.op); 1119 ClassDeclaration cd = ce.originalClass(); 1120 1121 // Put in the rest 1122 size_t firstFieldIndex = 0; 1123 for (ClassDeclaration c = cd.baseClass; c; c = c.baseClass) 1124 firstFieldIndex += c.fields.length; 1125 membersToDt(cd, dtb, ce.value.elements, firstFieldIndex, cd, null); 1126 } 1127 1128 /**************************************************** 1129 */ 1130 private extern (C++) class TypeInfoDtVisitor : Visitor 1131 { 1132 DtBuilder* dtb; 1133 1134 /* 1135 * Used in TypeInfo*.toDt to verify the runtime TypeInfo sizes 1136 */ 1137 static void verifyStructSize(ClassDeclaration typeclass, size_t expected) 1138 { 1139 if (typeclass.structsize != expected) 1140 { 1141 debug 1142 { 1143 printf("expected = x%x, %s.structsize = x%x\n", cast(uint)expected, 1144 typeclass.toChars(), cast(uint)typeclass.structsize); 1145 } 1146 error(typeclass.loc, "`%s`: mismatch between compiler (%d bytes) and object.d or object.di (%d bytes) found. Check installation and import paths with -v compiler switch.", 1147 typeclass.toChars(), cast(uint)expected, cast(uint)typeclass.structsize); 1148 fatal(); 1149 } 1150 } 1151 1152 this(ref DtBuilder dtb) scope 1153 { 1154 this.dtb = &dtb; 1155 } 1156 1157 alias visit = Visitor.visit; 1158 1159 override void visit(TypeInfoDeclaration d) 1160 { 1161 //printf("TypeInfoDeclaration.toDt() %s\n", toChars()); 1162 verifyStructSize(Type.dtypeinfo, 2 * target.ptrsize); 1163 1164 dtb.xoff(toVtblSymbol(Type.dtypeinfo), 0); // vtbl for TypeInfo 1165 if (Type.dtypeinfo.hasMonitor()) 1166 dtb.size(0); // monitor 1167 } 1168 1169 override void visit(TypeInfoConstDeclaration d) 1170 { 1171 //printf("TypeInfoConstDeclaration.toDt() %s\n", toChars()); 1172 verifyStructSize(Type.typeinfoconst, 3 * target.ptrsize); 1173 1174 dtb.xoff(toVtblSymbol(Type.typeinfoconst), 0); // vtbl for TypeInfo_Const 1175 if (Type.typeinfoconst.hasMonitor()) 1176 dtb.size(0); // monitor 1177 Type tm = d.tinfo.mutableOf(); 1178 tm = tm.merge(); 1179 TypeInfo_toObjFile(null, d.loc, tm); 1180 dtb.xoff(toSymbol(tm.vtinfo), 0); 1181 } 1182 1183 override void visit(TypeInfoInvariantDeclaration d) 1184 { 1185 //printf("TypeInfoInvariantDeclaration.toDt() %s\n", toChars()); 1186 verifyStructSize(Type.typeinfoinvariant, 3 * target.ptrsize); 1187 1188 dtb.xoff(toVtblSymbol(Type.typeinfoinvariant), 0); // vtbl for TypeInfo_Invariant 1189 if (Type.typeinfoinvariant.hasMonitor()) 1190 dtb.size(0); // monitor 1191 Type tm = d.tinfo.mutableOf(); 1192 tm = tm.merge(); 1193 TypeInfo_toObjFile(null, d.loc, tm); 1194 dtb.xoff(toSymbol(tm.vtinfo), 0); 1195 } 1196 1197 override void visit(TypeInfoSharedDeclaration d) 1198 { 1199 //printf("TypeInfoSharedDeclaration.toDt() %s\n", toChars()); 1200 verifyStructSize(Type.typeinfoshared, 3 * target.ptrsize); 1201 1202 dtb.xoff(toVtblSymbol(Type.typeinfoshared), 0); // vtbl for TypeInfo_Shared 1203 if (Type.typeinfoshared.hasMonitor()) 1204 dtb.size(0); // monitor 1205 Type tm = d.tinfo.unSharedOf(); 1206 tm = tm.merge(); 1207 TypeInfo_toObjFile(null, d.loc, tm); 1208 dtb.xoff(toSymbol(tm.vtinfo), 0); 1209 } 1210 1211 override void visit(TypeInfoWildDeclaration d) 1212 { 1213 //printf("TypeInfoWildDeclaration.toDt() %s\n", toChars()); 1214 verifyStructSize(Type.typeinfowild, 3 * target.ptrsize); 1215 1216 dtb.xoff(toVtblSymbol(Type.typeinfowild), 0); // vtbl for TypeInfo_Wild 1217 if (Type.typeinfowild.hasMonitor()) 1218 dtb.size(0); // monitor 1219 Type tm = d.tinfo.mutableOf(); 1220 tm = tm.merge(); 1221 TypeInfo_toObjFile(null, d.loc, tm); 1222 dtb.xoff(toSymbol(tm.vtinfo), 0); 1223 } 1224 1225 override void visit(TypeInfoEnumDeclaration d) 1226 { 1227 //printf("TypeInfoEnumDeclaration.toDt()\n"); 1228 verifyStructSize(Type.typeinfoenum, 7 * target.ptrsize); 1229 1230 dtb.xoff(toVtblSymbol(Type.typeinfoenum), 0); // vtbl for TypeInfo_Enum 1231 if (Type.typeinfoenum.hasMonitor()) 1232 dtb.size(0); // monitor 1233 1234 assert(d.tinfo.ty == Tenum); 1235 1236 TypeEnum tc = cast(TypeEnum)d.tinfo; 1237 EnumDeclaration sd = tc.sym; 1238 1239 /* Put out: 1240 * TypeInfo base; 1241 * string name; 1242 * void[] m_init; 1243 */ 1244 1245 // TypeInfo for enum members 1246 if (sd.memtype) 1247 { 1248 TypeInfo_toObjFile(null, d.loc, sd.memtype); 1249 dtb.xoff(toSymbol(sd.memtype.vtinfo), 0); 1250 } 1251 else 1252 dtb.size(0); 1253 1254 // string name; 1255 const(char)* name = sd.toPrettyChars(); 1256 size_t namelen = strlen(name); 1257 dtb.size(namelen); 1258 dtb.xoff(d.csym, Type.typeinfoenum.structsize); 1259 1260 // void[] init; 1261 if (!sd.members || d.tinfo.isZeroInit(Loc.initial)) 1262 { 1263 // 0 initializer, or the same as the base type 1264 dtb.size(0); // init.length 1265 dtb.size(0); // init.ptr 1266 } 1267 else 1268 { 1269 dtb.size(sd.type.size()); // init.length 1270 dtb.xoff(toInitializer(sd), 0); // init.ptr 1271 } 1272 1273 // Put out name[] immediately following TypeInfo_Enum 1274 dtb.nbytes(cast(uint)(namelen + 1), name); 1275 } 1276 1277 override void visit(TypeInfoPointerDeclaration d) 1278 { 1279 //printf("TypeInfoPointerDeclaration.toDt()\n"); 1280 verifyStructSize(Type.typeinfopointer, 3 * target.ptrsize); 1281 1282 dtb.xoff(toVtblSymbol(Type.typeinfopointer), 0); // vtbl for TypeInfo_Pointer 1283 if (Type.typeinfopointer.hasMonitor()) 1284 dtb.size(0); // monitor 1285 1286 auto tc = d.tinfo.isTypePointer(); 1287 1288 TypeInfo_toObjFile(null, d.loc, tc.next); 1289 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for type being pointed to 1290 } 1291 1292 override void visit(TypeInfoArrayDeclaration d) 1293 { 1294 //printf("TypeInfoArrayDeclaration.toDt()\n"); 1295 verifyStructSize(Type.typeinfoarray, 3 * target.ptrsize); 1296 1297 dtb.xoff(toVtblSymbol(Type.typeinfoarray), 0); // vtbl for TypeInfo_Array 1298 if (Type.typeinfoarray.hasMonitor()) 1299 dtb.size(0); // monitor 1300 1301 auto tc = d.tinfo.isTypeDArray(); 1302 1303 TypeInfo_toObjFile(null, d.loc, tc.next); 1304 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1305 } 1306 1307 override void visit(TypeInfoStaticArrayDeclaration d) 1308 { 1309 //printf("TypeInfoStaticArrayDeclaration.toDt()\n"); 1310 verifyStructSize(Type.typeinfostaticarray, 4 * target.ptrsize); 1311 1312 dtb.xoff(toVtblSymbol(Type.typeinfostaticarray), 0); // vtbl for TypeInfo_StaticArray 1313 if (Type.typeinfostaticarray.hasMonitor()) 1314 dtb.size(0); // monitor 1315 1316 auto tc = d.tinfo.isTypeSArray(); 1317 1318 TypeInfo_toObjFile(null, d.loc, tc.next); 1319 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1320 1321 dtb.size(tc.dim.toInteger()); // length 1322 } 1323 1324 override void visit(TypeInfoVectorDeclaration d) 1325 { 1326 //printf("TypeInfoVectorDeclaration.toDt()\n"); 1327 verifyStructSize(Type.typeinfovector, 3 * target.ptrsize); 1328 1329 dtb.xoff(toVtblSymbol(Type.typeinfovector), 0); // vtbl for TypeInfo_Vector 1330 if (Type.typeinfovector.hasMonitor()) 1331 dtb.size(0); // monitor 1332 1333 auto tc = d.tinfo.isTypeVector(); 1334 1335 TypeInfo_toObjFile(null, d.loc, tc.basetype); 1336 dtb.xoff(toSymbol(tc.basetype.vtinfo), 0); // TypeInfo for equivalent static array 1337 } 1338 1339 override void visit(TypeInfoAssociativeArrayDeclaration d) 1340 { 1341 //printf("TypeInfoAssociativeArrayDeclaration.toDt()\n"); 1342 verifyStructSize(Type.typeinfoassociativearray, 4 * target.ptrsize); 1343 1344 dtb.xoff(toVtblSymbol(Type.typeinfoassociativearray), 0); // vtbl for TypeInfo_AssociativeArray 1345 if (Type.typeinfoassociativearray.hasMonitor()) 1346 dtb.size(0); // monitor 1347 1348 auto tc = d.tinfo.isTypeAArray(); 1349 1350 TypeInfo_toObjFile(null, d.loc, tc.next); 1351 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1352 1353 TypeInfo_toObjFile(null, d.loc, tc.index); 1354 dtb.xoff(toSymbol(tc.index.vtinfo), 0); // TypeInfo for array of type 1355 } 1356 1357 override void visit(TypeInfoFunctionDeclaration d) 1358 { 1359 //printf("TypeInfoFunctionDeclaration.toDt()\n"); 1360 verifyStructSize(Type.typeinfofunction, 5 * target.ptrsize); 1361 1362 dtb.xoff(toVtblSymbol(Type.typeinfofunction), 0); // vtbl for TypeInfo_Function 1363 if (Type.typeinfofunction.hasMonitor()) 1364 dtb.size(0); // monitor 1365 1366 auto tc = d.tinfo.isTypeFunction(); 1367 1368 TypeInfo_toObjFile(null, d.loc, tc.next); 1369 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for function return value 1370 1371 const name = d.tinfo.deco; 1372 assert(name); 1373 const namelen = strlen(name); 1374 dtb.size(namelen); 1375 dtb.xoff(d.csym, Type.typeinfofunction.structsize); 1376 1377 // Put out name[] immediately following TypeInfo_Function 1378 dtb.nbytes(cast(uint)(namelen + 1), name); 1379 } 1380 1381 override void visit(TypeInfoDelegateDeclaration d) 1382 { 1383 //printf("TypeInfoDelegateDeclaration.toDt()\n"); 1384 verifyStructSize(Type.typeinfodelegate, 5 * target.ptrsize); 1385 1386 dtb.xoff(toVtblSymbol(Type.typeinfodelegate), 0); // vtbl for TypeInfo_Delegate 1387 if (Type.typeinfodelegate.hasMonitor()) 1388 dtb.size(0); // monitor 1389 1390 auto tc = d.tinfo.isTypeDelegate(); 1391 1392 TypeInfo_toObjFile(null, d.loc, tc.next.nextOf()); 1393 dtb.xoff(toSymbol(tc.next.nextOf().vtinfo), 0); // TypeInfo for delegate return value 1394 1395 const name = d.tinfo.deco; 1396 assert(name); 1397 const namelen = strlen(name); 1398 dtb.size(namelen); 1399 dtb.xoff(d.csym, Type.typeinfodelegate.structsize); 1400 1401 // Put out name[] immediately following TypeInfo_Delegate 1402 dtb.nbytes(cast(uint)(namelen + 1), name); 1403 } 1404 1405 override void visit(TypeInfoStructDeclaration d) 1406 { 1407 //printf("TypeInfoStructDeclaration.toDt() '%s'\n", d.toChars()); 1408 if (target.isX86_64) 1409 verifyStructSize(Type.typeinfostruct, 17 * target.ptrsize); 1410 else 1411 verifyStructSize(Type.typeinfostruct, 15 * target.ptrsize); 1412 1413 dtb.xoff(toVtblSymbol(Type.typeinfostruct), 0); // vtbl for TypeInfo_Struct 1414 if (Type.typeinfostruct.hasMonitor()) 1415 dtb.size(0); // monitor 1416 1417 auto tc = d.tinfo.isTypeStruct(); 1418 StructDeclaration sd = tc.sym; 1419 1420 if (!sd.members) 1421 return; 1422 1423 if (TemplateInstance ti = sd.isInstantiated()) 1424 { 1425 if (!ti.needsCodegen()) 1426 { 1427 assert(ti.minst || sd.requestTypeInfo); 1428 1429 /* ti.toObjFile() won't get called. So, store these 1430 * member functions into object file in here. 1431 */ 1432 if (sd.xeq && sd.xeq != StructDeclaration.xerreq) 1433 toObjFile(sd.xeq, global.params.multiobj); 1434 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) 1435 toObjFile(sd.xcmp, global.params.multiobj); 1436 if (FuncDeclaration ftostr = search_toString(sd)) 1437 toObjFile(ftostr, global.params.multiobj); 1438 if (sd.xhash) 1439 toObjFile(sd.xhash, global.params.multiobj); 1440 if (sd.postblit) 1441 toObjFile(sd.postblit, global.params.multiobj); 1442 if (sd.dtor) 1443 toObjFile(sd.dtor, global.params.multiobj); 1444 } 1445 } 1446 1447 /* Put out: 1448 * char[] mangledName; 1449 * void[] init; 1450 * hash_t function(in void*) xtoHash; 1451 * bool function(in void*, in void*) xopEquals; 1452 * int function(in void*, in void*) xopCmp; 1453 * string function(const(void)*) xtoString; 1454 * StructFlags m_flags; 1455 * //xgetMembers; 1456 * xdtor; 1457 * xpostblit; 1458 * uint m_align; 1459 * version (X86_64) 1460 * TypeInfo m_arg1; 1461 * TypeInfo m_arg2; 1462 * xgetRTInfo 1463 */ 1464 1465 const mangledName = tc.deco; 1466 const mangledNameLen = strlen(mangledName); 1467 dtb.size(mangledNameLen); 1468 dtb.xoff(d.csym, Type.typeinfostruct.structsize); 1469 1470 // void[] init; 1471 dtb.size(sd.structsize); // init.length 1472 if (sd.zeroInit) 1473 dtb.size(0); // null for 0 initialization 1474 else 1475 dtb.xoff(toInitializer(sd), 0); // init.ptr 1476 1477 if (FuncDeclaration fd = sd.xhash) 1478 { 1479 dtb.xoff(toSymbol(fd), 0); 1480 TypeFunction tf = cast(TypeFunction)fd.type; 1481 assert(tf.ty == Tfunction); 1482 } 1483 else 1484 dtb.size(0); 1485 1486 if (sd.xeq) 1487 dtb.xoff(toSymbol(sd.xeq), 0); 1488 else 1489 dtb.size(0); 1490 1491 if (sd.xcmp) 1492 dtb.xoff(toSymbol(sd.xcmp), 0); 1493 else 1494 dtb.size(0); 1495 1496 if (FuncDeclaration fd = search_toString(sd)) 1497 { 1498 dtb.xoff(toSymbol(fd), 0); 1499 } 1500 else 1501 dtb.size(0); 1502 1503 // StructFlags m_flags; 1504 StructFlags m_flags = StructFlags.none; 1505 if (tc.hasPointers()) m_flags |= StructFlags.hasPointers; 1506 dtb.size(m_flags); 1507 1508 version (none) 1509 { 1510 // xgetMembers 1511 if (auto sgetmembers = sd.findGetMembers()) 1512 dtb.xoff(toSymbol(sgetmembers), 0); 1513 else 1514 dtb.size(0); // xgetMembers 1515 } 1516 1517 // xdtor 1518 if (auto sdtor = sd.tidtor) 1519 dtb.xoff(toSymbol(sdtor), 0); 1520 else 1521 dtb.size(0); // xdtor 1522 1523 // xpostblit 1524 FuncDeclaration spostblit = sd.postblit; 1525 if (spostblit && !(spostblit.storage_class & STC.disable)) 1526 dtb.xoff(toSymbol(spostblit), 0); 1527 else 1528 dtb.size(0); // xpostblit 1529 1530 // uint m_align; 1531 dtb.size(tc.alignsize()); 1532 1533 if (target.isX86_64) 1534 { 1535 foreach (i; 0 .. 2) 1536 { 1537 // m_argi 1538 if (auto t = sd.argType(i)) 1539 { 1540 TypeInfo_toObjFile(null, d.loc, t); 1541 dtb.xoff(toSymbol(t.vtinfo), 0); 1542 } 1543 else 1544 dtb.size(0); 1545 } 1546 } 1547 1548 // xgetRTInfo 1549 if (sd.getRTInfo) 1550 { 1551 Expression_toDt(sd.getRTInfo, *dtb); 1552 } 1553 else if (m_flags & StructFlags.hasPointers) 1554 dtb.size(1); 1555 else 1556 dtb.size(0); 1557 1558 // Put out mangledName[] immediately following TypeInfo_Struct 1559 dtb.nbytes(cast(uint)(mangledNameLen + 1), mangledName); 1560 } 1561 1562 override void visit(TypeInfoClassDeclaration d) 1563 { 1564 //printf("TypeInfoClassDeclaration.toDt() %s\n", tinfo.toChars()); 1565 assert(0); 1566 } 1567 1568 override void visit(TypeInfoInterfaceDeclaration d) 1569 { 1570 //printf("TypeInfoInterfaceDeclaration.toDt() %s\n", tinfo.toChars()); 1571 verifyStructSize(Type.typeinfointerface, 3 * target.ptrsize); 1572 1573 dtb.xoff(toVtblSymbol(Type.typeinfointerface), 0); // vtbl for TypeInfoInterface 1574 if (Type.typeinfointerface.hasMonitor()) 1575 dtb.size(0); // monitor 1576 1577 auto tc = d.tinfo.isTypeClass(); 1578 1579 if (!tc.sym.vclassinfo) 1580 tc.sym.vclassinfo = TypeInfoClassDeclaration.create(tc); 1581 auto s = toSymbol(tc.sym.vclassinfo); 1582 dtb.xoff(s, 0); // ClassInfo for tinfo 1583 } 1584 1585 override void visit(TypeInfoTupleDeclaration d) 1586 { 1587 //printf("TypeInfoTupleDeclaration.toDt() %s\n", tinfo.toChars()); 1588 verifyStructSize(Type.typeinfotypelist, 4 * target.ptrsize); 1589 1590 dtb.xoff(toVtblSymbol(Type.typeinfotypelist), 0); // vtbl for TypeInfoInterface 1591 if (Type.typeinfotypelist.hasMonitor()) 1592 dtb.size(0); // monitor 1593 1594 auto tu = d.tinfo.isTypeTuple(); 1595 1596 const dim = tu.arguments.length; 1597 dtb.size(dim); // elements.length 1598 1599 auto dtbargs = DtBuilder(0); 1600 foreach (arg; *tu.arguments) 1601 { 1602 TypeInfo_toObjFile(null, d.loc, arg.type); 1603 Symbol* s = toSymbol(arg.type.vtinfo); 1604 dtbargs.xoff(s, 0); 1605 } 1606 1607 dtb.dtoff(dtbargs.finish(), 0); // elements.ptr 1608 } 1609 } 1610 1611 extern (C++) void TypeInfo_toDt(ref DtBuilder dtb, TypeInfoDeclaration d) 1612 { 1613 scope v = new TypeInfoDtVisitor(dtb); 1614 d.accept(v); 1615 }