1 /** 2 * Generate the object file for function declarations and critical sections. 3 * 4 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/glue.d, _glue.d) 8 * Documentation: $(LINK https://dlang.org/phobos/dmd_glue.html) 9 * Coverage: $(LINK https://codecov.io/gh/dlang/dmd/src/master/src/dmd/glue.d) 10 */ 11 12 module dmd.glue; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import core.stdc.stdlib; 17 18 import dmd.root.array; 19 import dmd.root.file; 20 import dmd.root.filename; 21 import dmd.root.outbuffer; 22 import dmd.root.rmem; 23 import dmd.root.string; 24 25 import dmd.backend.cdef; 26 import dmd.backend.cc; 27 import dmd.backend.code; 28 import dmd.backend.dt; 29 import dmd.backend.el; 30 import dmd.backend.global; 31 import dmd.backend.obj; 32 import dmd.backend.oper; 33 import dmd.backend.outbuf; 34 import dmd.backend.rtlsym; 35 import dmd.backend.symtab; 36 import dmd.backend.ty; 37 import dmd.backend.type; 38 39 import dmd.aggregate; 40 import dmd.arraytypes; 41 import dmd.blockexit; 42 import dmd.dclass; 43 import dmd.declaration; 44 import dmd.dmangle; 45 import dmd.dmodule; 46 import dmd.dstruct; 47 import dmd.dsymbol; 48 import dmd.dtemplate; 49 import dmd.e2ir; 50 import dmd.errors; 51 import dmd.expression; 52 import dmd.func; 53 import dmd.globals; 54 import dmd.identifier; 55 import dmd.id; 56 import dmd.lib; 57 import dmd.mtype; 58 import dmd.objc_glue; 59 import dmd.s2ir; 60 import dmd.statement; 61 import dmd.target; 62 import dmd.tocsym; 63 import dmd.toctype; 64 import dmd.toir; 65 import dmd.toobj; 66 import dmd.typesem; 67 import dmd.utils; 68 69 extern (C++): 70 71 alias symbols = Array!(Symbol*); 72 alias toSymbol = dmd.tocsym.toSymbol; 73 74 //extern 75 __gshared 76 { 77 elem *eictor; 78 Symbol *ictorlocalgot; 79 Symbol* bzeroSymbol; /// common location for immutable zeros 80 symbols sctors; 81 StaticDtorDeclarations ectorgates; 82 symbols sdtors; 83 symbols stests; 84 85 symbols ssharedctors; 86 SharedStaticDtorDeclarations esharedctorgates; 87 symbols sshareddtors; 88 89 const(char)* lastmname; 90 } 91 92 93 /************************************** 94 * Append s to list of object files to generate later. 95 */ 96 97 __gshared Dsymbols obj_symbols_towrite; 98 99 void obj_append(Dsymbol s) 100 { 101 //printf("deferred: %s\n", s.toChars()); 102 obj_symbols_towrite.push(s); 103 } 104 105 void obj_write_deferred(Library library) 106 { 107 for (size_t i = 0; i < obj_symbols_towrite.dim; i++) 108 { 109 Dsymbol s = obj_symbols_towrite[i]; 110 Module m = s.getModule(); 111 112 const(char)* mname; 113 if (m) 114 { 115 mname = m.srcfile.toChars(); 116 lastmname = mname; 117 } 118 else 119 { 120 //mname = s.ident.toChars(); 121 mname = lastmname; 122 assert(mname); 123 } 124 125 obj_start(mname); 126 127 __gshared int count; 128 count++; // sequence for generating names 129 130 /* Create a module that's a doppelganger of m, with just 131 * enough to be able to create the moduleinfo. 132 */ 133 OutBuffer idbuf; 134 idbuf.printf("%s.%d", m ? m.ident.toChars() : mname, count); 135 136 if (!m) 137 { 138 // it doesn't make sense to make up a module if we don't know where to put the symbol 139 // so output it into its own object file without ModuleInfo 140 objmod.initfile(idbuf.peekChars(), null, mname); 141 toObjFile(s, false); 142 objmod.termfile(); 143 } 144 else 145 { 146 Identifier id = Identifier.create(idbuf.extractChars()); 147 148 Module md = new Module(mname.toDString, id, 0, 0); 149 md.members = new Dsymbols(); 150 md.members.push(s); // its only 'member' is s 151 md.doppelganger = 1; // identify this module as doppelganger 152 md.md = m.md; 153 md.aimports.push(m); // it only 'imports' m 154 155 genObjFile(md, false); 156 } 157 158 /* Set object file name to be source name with sequence number, 159 * as mangled symbol names get way too long. 160 */ 161 const(char)* fname = FileName.removeExt(mname); 162 OutBuffer namebuf; 163 uint hash = 0; 164 for (const(char)* p = s.toChars(); *p; p++) 165 hash += *p; 166 namebuf.printf("%s_%x_%x.%.*s", fname, count, hash, 167 cast(int)global.obj_ext.length, global.obj_ext.ptr); 168 FileName.free(cast(char *)fname); 169 fname = namebuf.extractChars(); 170 171 //printf("writing '%s'\n", fname); 172 obj_end(library, fname); 173 } 174 obj_symbols_towrite.dim = 0; 175 } 176 177 178 /*********************************************** 179 * Generate function that calls array of functions and gates. 180 * Params: 181 * m = module symbol (for name mangling purposes) 182 * sctors = array of functions 183 * ectorgates = array of gates 184 * id = identifier string for generator function 185 * Returns: 186 * function Symbol generated 187 */ 188 189 private Symbol *callFuncsAndGates(Module m, symbols *sctors, StaticDtorDeclarations *ectorgates, 190 const(char)* id) 191 { 192 Symbol *sctor = null; 193 194 if ((sctors && sctors.dim) || 195 (ectorgates && ectorgates.dim)) 196 { 197 __gshared type *t; 198 if (!t) 199 { 200 /* t will be the type of the functions generated: 201 * extern (C) void func(); 202 */ 203 t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 204 t.Tmangle = mTYman_c; 205 } 206 207 localgot = null; 208 sctor = toSymbolX(m, id, SCglobal, t, "FZv"); 209 cstate.CSpsymtab = &sctor.Sfunc.Flocsym; 210 elem *ector = null; 211 212 if (ectorgates) 213 { 214 foreach (f; *ectorgates) 215 { 216 Symbol *s = toSymbol(f.vgate); 217 elem *e = el_var(s); 218 e = el_bin(OPaddass, TYint, e, el_long(TYint, 1)); 219 ector = el_combine(ector, e); 220 } 221 } 222 223 if (sctors) 224 { 225 foreach (s; *sctors) 226 { 227 elem *e = el_una(OPucall, TYvoid, el_var(s)); 228 ector = el_combine(ector, e); 229 } 230 } 231 232 block *b = block_calloc(); 233 b.BC = BCret; 234 b.Belem = ector; 235 sctor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 236 sctor.Sfunc.Fstartblock = b; 237 writefunc(sctor); 238 } 239 return sctor; 240 } 241 242 /************************************** 243 * Prepare for generating obj file. 244 */ 245 246 __gshared Outbuffer objbuf; 247 248 void obj_start(const(char)* srcfile) 249 { 250 //printf("obj_start()\n"); 251 252 bzeroSymbol = null; 253 rtlsym_reset(); 254 clearStringTab(); 255 256 version (Windows) 257 { 258 // Produce Ms COFF files for 64 bit code, OMF for 32 bit code 259 assert(objbuf.length() == 0); 260 objmod = global.params.mscoff ? MsCoffObj_init(&objbuf, srcfile, null) 261 : OmfObj_init(&objbuf, srcfile, null); 262 } 263 else 264 { 265 objmod = Obj.init(&objbuf, srcfile, null); 266 } 267 268 el_reset(); 269 cg87_reset(); 270 out_reset(); 271 objc.reset(); 272 } 273 274 275 void obj_end(Library library, const(char)* objfilename) 276 { 277 objmod.term(objfilename); 278 //delete objmod; 279 objmod = null; 280 281 if (library) 282 { 283 // Transfer ownership of image buffer to library 284 library.addObject(objfilename.toDString(), objbuf.extractSlice[]); 285 } 286 else 287 { 288 //printf("write obj %s\n", objfilename); 289 writeFile(Loc.initial, objfilename.toDString, objbuf[]); 290 } 291 objbuf.dtor(); 292 } 293 294 bool obj_includelib(const(char)* name) nothrow 295 { 296 return objmod.includelib(name); 297 } 298 299 extern(D) bool obj_includelib(const(char)[] name) nothrow 300 { 301 return name.toCStringThen!(n => obj_includelib(n.ptr)); 302 } 303 304 void obj_startaddress(Symbol *s) 305 { 306 return objmod.startaddress(s); 307 } 308 309 bool obj_linkerdirective(const(char)* directive) 310 { 311 return objmod.linkerdirective(directive); 312 } 313 314 315 /************************************** 316 * Generate .obj file for Module. 317 */ 318 319 void genObjFile(Module m, bool multiobj) 320 { 321 //EEcontext *ee = env.getEEcontext(); 322 323 //printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, m.toChars()); 324 325 lastmname = m.srcfile.toChars(); 326 327 objmod.initfile(lastmname, null, m.toPrettyChars()); 328 329 eictor = null; 330 ictorlocalgot = null; 331 sctors.setDim(0); 332 ectorgates.setDim(0); 333 sdtors.setDim(0); 334 ssharedctors.setDim(0); 335 esharedctorgates.setDim(0); 336 sshareddtors.setDim(0); 337 stests.setDim(0); 338 339 if (m.doppelganger) 340 { 341 /* Generate a reference to the moduleinfo, so the module constructors 342 * and destructors get linked in. 343 */ 344 Module mod = m.aimports[0]; 345 assert(mod); 346 if (mod.sictor || mod.sctor || mod.sdtor || mod.ssharedctor || mod.sshareddtor) 347 { 348 Symbol *s = toSymbol(mod); 349 //objextern(s); 350 //if (!s.Sxtrnnum) objextdef(s.Sident); 351 if (!s.Sxtrnnum) 352 { 353 //printf("%s\n", s.Sident); 354 //#if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ 355 // objextdef(s.Sident); 356 //#else 357 Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); 358 sref.Sfl = FLdata; 359 auto dtb = DtBuilder(0); 360 dtb.xoff(s, 0, TYnptr); 361 sref.Sdt = dtb.finish(); 362 outdata(sref); 363 //#endif 364 } 365 } 366 } 367 368 if (global.params.cov) 369 { 370 /* Create coverage identifier: 371 * uint[numlines] __coverage; 372 */ 373 m.cov = toSymbolX(m, "__coverage", SCstatic, type_fake(TYint), "Z"); 374 m.cov.Sflags |= SFLhidden; 375 m.cov.Stype.Tmangle = mTYman_d; 376 m.cov.Sfl = FLdata; 377 378 auto dtb = DtBuilder(0); 379 380 if (m.ctfe_cov) 381 { 382 // initalize the uint[] __coverage symbol with data from ctfe. 383 static extern (C) int comp_uints (const scope void* a, const scope void* b) 384 { return (*cast(uint*) a) - (*cast(uint*) b); } 385 386 uint[] sorted_lines = m.ctfe_cov.keys; 387 qsort(sorted_lines.ptr, sorted_lines.length, sorted_lines[0].sizeof, 388 &comp_uints); 389 390 uint lastLine = 0; 391 foreach (line;sorted_lines) 392 { 393 // zero fill from last line to line. 394 if (line) 395 { 396 assert(line > lastLine); 397 dtb.nzeros((line - lastLine - 1) * 4); 398 } 399 dtb.dword(m.ctfe_cov[line]); 400 lastLine = line; 401 } 402 // zero fill from last line to end 403 if (m.numlines > lastLine) 404 dtb.nzeros((m.numlines - lastLine) * 4); 405 } 406 else 407 { 408 dtb.nzeros(4 * m.numlines); 409 } 410 m.cov.Sdt = dtb.finish(); 411 412 outdata(m.cov); 413 414 m.covb = cast(uint *)calloc((m.numlines + 32) / 32, (*m.covb).sizeof); 415 } 416 417 for (int i = 0; i < m.members.dim; i++) 418 { 419 auto member = (*m.members)[i]; 420 //printf("toObjFile %s %s\n", member.kind(), member.toChars()); 421 toObjFile(member, multiobj); 422 } 423 424 if (global.params.cov) 425 { 426 /* Generate 427 * private bit[numlines] __bcoverage; 428 */ 429 Symbol *bcov = symbol_calloc("__bcoverage"); 430 bcov.Stype = type_fake(TYuint); 431 bcov.Stype.Tcount++; 432 bcov.Sclass = SCstatic; 433 bcov.Sfl = FLdata; 434 435 auto dtb = DtBuilder(0); 436 dtb.nbytes((m.numlines + 32) / 32 * (*m.covb).sizeof, cast(char *)m.covb); 437 bcov.Sdt = dtb.finish(); 438 439 outdata(bcov); 440 441 free(m.covb); 442 m.covb = null; 443 444 /* Generate: 445 * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); 446 * and prepend it to the static constructor. 447 */ 448 449 /* t will be the type of the functions generated: 450 * extern (C) void func(); 451 */ 452 type *t = type_function(TYnfunc, null, false, tstypes[TYvoid]); 453 t.Tmangle = mTYman_c; 454 455 m.sictor = toSymbolX(m, "__modictor", SCglobal, t, "FZv"); 456 cstate.CSpsymtab = &m.sictor.Sfunc.Flocsym; 457 localgot = ictorlocalgot; 458 459 elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(m.cov)); 460 elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m.numlines), el_ptr(bcov)); 461 462 if (global.params.targetOS == TargetOS.Windows && global.params.is64bit) 463 { 464 ecov = addressElem(ecov, Type.tvoid.arrayOf(), false); 465 ebcov = addressElem(ebcov, Type.tvoid.arrayOf(), false); 466 } 467 468 elem *efilename = toEfilename(m); 469 if (global.params.targetOS == TargetOS.Windows && global.params.is64bit) 470 efilename = addressElem(efilename, Type.tstring, true); 471 472 elem *e = el_params( 473 el_long(TYuchar, global.params.covPercent), 474 ecov, 475 ebcov, 476 efilename, 477 null); 478 e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_DCOVER2)), e); 479 eictor = el_combine(e, eictor); 480 ictorlocalgot = localgot; 481 } 482 483 // If coverage / static constructor / destructor / unittest calls 484 if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || 485 ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) 486 { 487 if (eictor) 488 { 489 localgot = ictorlocalgot; 490 491 block *b = block_calloc(); 492 b.BC = BCret; 493 b.Belem = eictor; 494 m.sictor.Sfunc.Fstartline.Sfilename = m.arg.xarraydup.ptr; 495 m.sictor.Sfunc.Fstartblock = b; 496 writefunc(m.sictor); 497 } 498 499 m.sctor = callFuncsAndGates(m, &sctors, &ectorgates, "__modctor"); 500 m.sdtor = callFuncsAndGates(m, &sdtors, null, "__moddtor"); 501 502 m.ssharedctor = callFuncsAndGates(m, &ssharedctors, cast(StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); 503 m.sshareddtor = callFuncsAndGates(m, &sshareddtors, null, "__modshareddtor"); 504 m.stest = callFuncsAndGates(m, &stests, null, "__modtest"); 505 506 if (m.doppelganger) 507 genModuleInfo(m); 508 } 509 510 if (m.doppelganger) 511 { 512 objc.generateModuleInfo(m); 513 objmod.termfile(); 514 return; 515 } 516 517 /* Generate module info for templates and -cov. 518 * Don't generate ModuleInfo if `object.ModuleInfo` is not declared or 519 * explicitly disabled through compiler switches such as `-betterC`. 520 */ 521 if (global.params.useModuleInfo && Module.moduleinfo /*|| needModuleInfo()*/) 522 genModuleInfo(m); 523 524 objmod.termfile(); 525 } 526 527 528 529 /* ================================================================== */ 530 531 private UnitTestDeclaration needsDeferredNested(FuncDeclaration fd) 532 { 533 while (fd && fd.isNested()) 534 { 535 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 536 if (!fdp) 537 break; 538 if (UnitTestDeclaration udp = fdp.isUnitTestDeclaration()) 539 return udp.semanticRun < PASS.obj ? udp : null; 540 fd = fdp; 541 } 542 return null; 543 } 544 545 546 void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj) 547 { 548 ClassDeclaration cd = fd.parent.isClassDeclaration(); 549 //printf("FuncDeclaration.toObjFile(%p, %s.%s)\n", fd, fd.parent.toChars(), fd.toChars()); 550 551 //if (type) printf("type = %s\n", type.toChars()); 552 version (none) 553 { 554 //printf("line = %d\n", getWhere() / LINEINC); 555 EEcontext *ee = env.getEEcontext(); 556 if (ee.EEcompile == 2) 557 { 558 if (ee.EElinnum < (getWhere() / LINEINC) || 559 ee.EElinnum > (endwhere / LINEINC) 560 ) 561 return; // don't compile this function 562 ee.EEfunc = toSymbol(this); 563 } 564 } 565 566 if (fd.semanticRun >= PASS.obj) // if toObjFile() already run 567 return; 568 569 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next is null) 570 return; 571 572 // If errors occurred compiling it, such as https://issues.dlang.org/show_bug.cgi?id=6118 573 if (fd.type && fd.type.ty == Tfunction && (cast(TypeFunction)fd.type).next.ty == Terror) 574 return; 575 576 if (fd.semantic3Errors) 577 return; 578 579 if (global.errors) 580 return; 581 582 if (!fd.fbody) 583 return; 584 585 UnitTestDeclaration ud = fd.isUnitTestDeclaration(); 586 if (ud && !global.params.useUnitTests) 587 return; 588 589 if (multiobj && !fd.isStaticDtorDeclaration() && !fd.isStaticCtorDeclaration() && !fd.isCrtCtorDtor) 590 { 591 obj_append(fd); 592 return; 593 } 594 595 if (fd.semanticRun == PASS.semanticdone) 596 { 597 /* What happened is this function failed semantic3() with errors, 598 * but the errors were gagged. 599 * Try to reproduce those errors, and then fail. 600 */ 601 fd.error("errors compiling the function"); 602 return; 603 } 604 assert(fd.semanticRun == PASS.semantic3done); 605 assert(fd.ident != Id.empty); 606 607 for (FuncDeclaration fd2 = fd; fd2; ) 608 { 609 if (fd2.inNonRoot()) 610 return; 611 if (fd2.isNested()) 612 fd2 = fd2.toParent2().isFuncDeclaration(); 613 else 614 break; 615 } 616 617 if (UnitTestDeclaration udp = needsDeferredNested(fd)) 618 { 619 /* Can't do unittest's out of order, they are order dependent in that their 620 * execution is done in lexical order. 621 */ 622 udp.deferredNested.push(fd); 623 //printf("%s @[%s]\n\t-. pushed to unittest @[%s]\n", 624 // fd.toPrettyChars(), fd.loc.toChars(), udp.loc.toChars()); 625 return; 626 } 627 628 // start code generation 629 fd.semanticRun = PASS.obj; 630 631 if (global.params.verbose) 632 message("function %s", fd.toPrettyChars()); 633 634 Symbol *s = toSymbol(fd); 635 func_t *f = s.Sfunc; 636 637 // tunnel type of "this" to debug info generation 638 if (AggregateDeclaration ad = fd.parent.isAggregateDeclaration()) 639 { 640 .type* t = Type_toCtype(ad.getType()); 641 if (cd) 642 t = t.Tnext; // skip reference 643 f.Fclass = cast(Classsym *)t; 644 } 645 646 /* This is done so that the 'this' pointer on the stack is the same 647 * distance away from the function parameters, so that an overriding 648 * function can call the nested fdensure or fdrequire of its overridden function 649 * and the stack offsets are the same. 650 */ 651 if (fd.isVirtual() && (fd.fensure || fd.frequire)) 652 f.Fflags3 |= Ffakeeh; 653 654 if (fd.eh_none) 655 // Same as config.ehmethod==EH_NONE, but only for this function 656 f.Fflags3 |= Feh_none; 657 658 s.Sclass = global.params.targetOS == TargetOS.OSX ? SCcomdat : SCglobal; 659 for (Dsymbol p = fd.parent; p; p = p.parent) 660 { 661 if (p.isTemplateInstance()) 662 { 663 // functions without D or C++ name mangling mixed in at global scope 664 // shouldn't have multiple definitions 665 if (p.isTemplateMixin() && (fd.linkage == LINK.c || fd.linkage == LINK.windows || 666 fd.linkage == LINK.objc)) 667 { 668 const q = p.toParent(); 669 if (q && q.isModule()) 670 { 671 s.Sclass = SCglobal; 672 break; 673 } 674 } 675 s.Sclass = SCcomdat; 676 break; 677 } 678 } 679 680 if (fd.inlinedNestedCallees) 681 { 682 /* https://issues.dlang.org/show_bug.cgi?id=15333 683 * If fd contains inlined expressions that come from 684 * nested function bodies, the enclosing of the functions must be 685 * generated first, in order to calculate correct frame pointer offset. 686 */ 687 foreach (fdc; *fd.inlinedNestedCallees) 688 { 689 FuncDeclaration fp = fdc.toParent2().isFuncDeclaration(); 690 if (fp && fp.semanticRun < PASS.obj) 691 { 692 toObjFile(fp, multiobj); 693 } 694 } 695 } 696 697 if (fd.isNested()) 698 { 699 //if (!(config.flags3 & CFG3pic)) 700 // s.Sclass = SCstatic; 701 f.Fflags3 |= Fnested; 702 703 /* The enclosing function must have its code generated first, 704 * in order to calculate correct frame pointer offset. 705 */ 706 FuncDeclaration fdp = fd.toParent2().isFuncDeclaration(); 707 if (fdp && fdp.semanticRun < PASS.obj) 708 { 709 toObjFile(fdp, multiobj); 710 } 711 } 712 else 713 { 714 specialFunctions(objmod, fd); 715 } 716 717 symtab_t *symtabsave = cstate.CSpsymtab; 718 cstate.CSpsymtab = &f.Flocsym; 719 720 // Find module m for this function 721 Module m = null; 722 for (Dsymbol p = fd.parent; p; p = p.parent) 723 { 724 m = p.isModule(); 725 if (m) 726 break; 727 } 728 729 Dsymbols deferToObj; // write these to OBJ file later 730 Array!(elem*) varsInScope; 731 Label*[void*] labels = null; 732 IRState irs = IRState(m, fd, &varsInScope, &deferToObj, &labels, &global.params); 733 734 Symbol *shidden = null; 735 Symbol *sthis = null; 736 tym_t tyf = tybasic(s.Stype.Tty); 737 //printf("linkage = %d, tyf = x%x\n", linkage, tyf); 738 int reverse = tyrevfunc(s.Stype.Tty); 739 740 assert(fd.type.ty == Tfunction); 741 TypeFunction tf = cast(TypeFunction)fd.type; 742 RET retmethod = retStyle(tf, fd.needThis()); 743 if (retmethod == RET.stack) 744 { 745 // If function returns a struct, put a pointer to that 746 // as the first argument 747 .type *thidden = Type_toCtype(tf.next.pointerTo()); 748 char[5 + 10 + 1] hiddenparam = void; 749 __gshared uint hiddenparami; // how many we've generated so far 750 751 const(char)* name; 752 if (fd.nrvo_can && fd.nrvo_var) 753 name = fd.nrvo_var.ident.toChars(); 754 else 755 { 756 sprintf(hiddenparam.ptr, "__HID%u", ++hiddenparami); 757 name = hiddenparam.ptr; 758 } 759 shidden = symbol_name(name, SCparameter, thidden); 760 shidden.Sflags |= SFLtrue | SFLfree; 761 if (fd.nrvo_can && fd.nrvo_var && fd.nrvo_var.nestedrefs.dim) 762 type_setcv(&shidden.Stype, shidden.Stype.Tty | mTYvolatile); 763 irs.shidden = shidden; 764 fd.shidden = shidden; 765 } 766 else 767 { 768 // Register return style cannot make nrvo. 769 // Auto functions keep the nrvo_can flag up to here, 770 // so we should eliminate it before entering backend. 771 fd.nrvo_can = 0; 772 } 773 774 if (fd.vthis) 775 { 776 assert(!fd.vthis.csym); 777 sthis = toSymbol(fd.vthis); 778 sthis.Stype = getParentClosureType(sthis, fd); 779 irs.sthis = sthis; 780 if (!(f.Fflags3 & Fnested)) 781 f.Fflags3 |= Fmember; 782 } 783 784 // Estimate number of parameters, pi 785 size_t pi = (fd.v_arguments !is null); 786 if (fd.parameters) 787 pi += fd.parameters.dim; 788 if (fd.objc.selector) 789 pi++; // Extra argument for Objective-C selector 790 // Create a temporary buffer, params[], to hold function parameters 791 Symbol*[10] paramsbuf = void; 792 Symbol **params = paramsbuf.ptr; // allocate on stack if possible 793 if (pi + 2 > paramsbuf.length) // allow extra 2 for sthis and shidden 794 { 795 params = cast(Symbol **)Mem.check(malloc((pi + 2) * (Symbol *).sizeof)); 796 } 797 798 // Get the actual number of parameters, pi, and fill in the params[] 799 pi = 0; 800 if (fd.v_arguments) 801 { 802 params[pi] = toSymbol(fd.v_arguments); 803 pi += 1; 804 } 805 if (fd.parameters) 806 { 807 foreach (i, v; *fd.parameters) 808 { 809 //printf("param[%d] = %p, %s\n", i, v, v.toChars()); 810 assert(!v.csym); 811 params[pi + i] = toSymbol(v); 812 } 813 pi += fd.parameters.dim; 814 } 815 816 if (reverse) 817 { 818 // Reverse params[] entries 819 foreach (i, sptmp; params[0 .. pi/2]) 820 { 821 params[i] = params[pi - 1 - i]; 822 params[pi - 1 - i] = sptmp; 823 } 824 } 825 826 if (shidden) 827 { 828 // shidden becomes last parameter 829 //params[pi] = shidden; 830 831 // shidden becomes first parameter 832 memmove(params + 1, params, pi * (params[0]).sizeof); 833 params[0] = shidden; 834 835 pi++; 836 } 837 838 pi = objc.addSelectorParameterSymbol(fd, params, pi); 839 840 if (sthis) 841 { 842 // sthis becomes last parameter 843 //params[pi] = sthis; 844 845 // sthis becomes first parameter 846 memmove(params + 1, params, pi * (params[0]).sizeof); 847 params[0] = sthis; 848 849 pi++; 850 } 851 852 if (target.isPOSIX && fd.linkage != LINK.d && shidden && sthis) 853 { 854 /* swap shidden and sthis 855 */ 856 Symbol *sp = params[0]; 857 params[0] = params[1]; 858 params[1] = sp; 859 } 860 861 foreach (sp; params[0 .. pi]) 862 { 863 sp.Sclass = SCparameter; 864 sp.Sflags &= ~SFLspill; 865 sp.Sfl = FLpara; 866 symbol_add(sp); 867 } 868 869 // Determine register assignments 870 if (pi) 871 { 872 FuncParamRegs fpr = FuncParamRegs.create(tyf); 873 874 foreach (sp; params[0 .. pi]) 875 { 876 if (fpr.alloc(sp.Stype, sp.Stype.Tty, &sp.Spreg, &sp.Spreg2)) 877 { 878 sp.Sclass = (global.params.targetOS == TargetOS.Windows && global.params.is64bit) ? SCshadowreg : SCfastpar; 879 sp.Sfl = (sp.Sclass == SCshadowreg) ? FLpara : FLfast; 880 } 881 } 882 } 883 884 // Done with params 885 if (params != paramsbuf.ptr) 886 free(params); 887 params = null; 888 889 localgot = null; 890 891 Statement sbody = fd.fbody; 892 893 Blockx bx; 894 bx.startblock = block_calloc(); 895 bx.curblock = bx.startblock; 896 bx.funcsym = s; 897 bx.scope_index = -1; 898 bx.classdec = cast(void*)cd; 899 bx.member = cast(void*)fd; 900 bx._module = cast(void*)fd.getModule(); 901 irs.blx = &bx; 902 903 // Initialize argptr 904 if (fd.v_argptr) 905 { 906 // Declare va_argsave 907 if (global.params.is64bit && 908 global.params.targetOS & TargetOS.Posix) 909 { 910 type *t = type_struct_class("__va_argsave_t", 16, 8 * 6 + 8 * 16 + 8 * 3, null, null, false, false, true, false); 911 // The backend will pick this up by name 912 Symbol *sv = symbol_name("__va_argsave", SCauto, t); 913 sv.Stype.Tty |= mTYvolatile; 914 symbol_add(sv); 915 } 916 917 Symbol *sa = toSymbol(fd.v_argptr); 918 symbol_add(sa); 919 elem *e = el_una(OPva_start, TYnptr, el_ptr(sa)); 920 block_appendexp(irs.blx.curblock, e); 921 } 922 923 /* Doing this in semantic3() caused all kinds of problems: 924 * 1. couldn't reliably get the final mangling of the function name due to fwd refs 925 * 2. impact on function inlining 926 * 3. what to do when writing out .di files, or other pretty printing 927 */ 928 if (global.params.trace && !fd.isCMain() && !fd.naked && !(fd.hasReturnExp & 8)) 929 { 930 /* The profiler requires TLS, and TLS may not be set up yet when C main() 931 * gets control (i.e. OSX), leading to a crash. 932 */ 933 /* Wrap the entire function body in: 934 * trace_pro("funcname"); 935 * try 936 * body; 937 * finally 938 * _c_trace_epi(); 939 */ 940 StringExp se = StringExp.create(Loc.initial, s.Sident.ptr); 941 se.type = Type.tstring; 942 se.type = se.type.typeSemantic(Loc.initial, null); 943 Expressions *exps = new Expressions(); 944 exps.push(se); 945 FuncDeclaration fdpro = FuncDeclaration.genCfunc(null, Type.tvoid, "trace_pro"); 946 Expression ec = VarExp.create(Loc.initial, fdpro); 947 Expression e = CallExp.create(Loc.initial, ec, exps); 948 e.type = Type.tvoid; 949 Statement sp = ExpStatement.create(fd.loc, e); 950 951 FuncDeclaration fdepi = FuncDeclaration.genCfunc(null, Type.tvoid, "_c_trace_epi"); 952 ec = VarExp.create(Loc.initial, fdepi); 953 e = CallExp.create(Loc.initial, ec); 954 e.type = Type.tvoid; 955 Statement sf = ExpStatement.create(fd.loc, e); 956 957 Statement stf; 958 if (sbody.blockExit(fd, false) == BE.fallthru) 959 stf = CompoundStatement.create(Loc.initial, sbody, sf); 960 else 961 stf = TryFinallyStatement.create(Loc.initial, sbody, sf); 962 sbody = CompoundStatement.create(Loc.initial, sp, stf); 963 } 964 965 if (fd.interfaceVirtual) 966 { 967 // Adjust the 'this' pointer instead of using a thunk 968 assert(irs.sthis); 969 elem *ethis = el_var(irs.sthis); 970 ethis = fixEthis2(ethis, fd); 971 elem *e = el_bin(OPminass, TYnptr, ethis, el_long(TYsize_t, fd.interfaceVirtual.offset)); 972 block_appendexp(irs.blx.curblock, e); 973 } 974 975 buildClosure(fd, &irs); 976 977 if (config.ehmethod == EHmethod.EH_WIN32 && fd.isSynchronized() && cd && 978 !fd.isStatic() && !sbody.usesEH() && !global.params.trace) 979 { 980 /* The "jmonitor" hack uses an optimized exception handling frame 981 * which is a little shorter than the more general EH frame. 982 */ 983 s.Sfunc.Fflags3 |= Fjmonitor; 984 } 985 986 Statement_toIR(sbody, &irs); 987 988 if (global.errors) 989 { 990 // Restore symbol table 991 cstate.CSpsymtab = symtabsave; 992 return; 993 } 994 995 bx.curblock.BC = BCret; 996 997 f.Fstartblock = bx.startblock; 998 // einit = el_combine(einit,bx.init); 999 1000 if (fd.isCtorDeclaration()) 1001 { 1002 assert(sthis); 1003 foreach (b; BlockRange(f.Fstartblock)) 1004 { 1005 if (b.BC == BCret) 1006 { 1007 elem *ethis = el_var(sthis); 1008 ethis = fixEthis2(ethis, fd); 1009 b.BC = BCretexp; 1010 b.Belem = el_combine(b.Belem, ethis); 1011 } 1012 } 1013 } 1014 if (config.ehmethod == EHmethod.EH_NONE || f.Fflags3 & Feh_none) 1015 insertFinallyBlockGotos(f.Fstartblock); 1016 else if (config.ehmethod == EHmethod.EH_DWARF) 1017 insertFinallyBlockCalls(f.Fstartblock); 1018 1019 // If static constructor 1020 if (fd.isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration 1021 { 1022 ssharedctors.push(s); 1023 } 1024 else if (fd.isStaticCtorDeclaration()) 1025 { 1026 sctors.push(s); 1027 } 1028 1029 // If static destructor 1030 if (fd.isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration 1031 { 1032 SharedStaticDtorDeclaration fs = fd.isSharedStaticDtorDeclaration(); 1033 assert(fs); 1034 if (fs.vgate) 1035 { 1036 /* Increment destructor's vgate at construction time 1037 */ 1038 esharedctorgates.push(fs); 1039 } 1040 1041 sshareddtors.shift(s); 1042 } 1043 else if (fd.isStaticDtorDeclaration()) 1044 { 1045 StaticDtorDeclaration fs = fd.isStaticDtorDeclaration(); 1046 assert(fs); 1047 if (fs.vgate) 1048 { 1049 /* Increment destructor's vgate at construction time 1050 */ 1051 ectorgates.push(fs); 1052 } 1053 1054 sdtors.shift(s); 1055 } 1056 1057 // If unit test 1058 if (ud) 1059 { 1060 stests.push(s); 1061 } 1062 1063 if (global.errors) 1064 { 1065 // Restore symbol table 1066 cstate.CSpsymtab = symtabsave; 1067 return; 1068 } 1069 1070 writefunc(s); 1071 1072 buildCapture(fd); 1073 1074 // Restore symbol table 1075 cstate.CSpsymtab = symtabsave; 1076 1077 if (fd.isExport()) 1078 objmod.export_symbol(s, cast(uint)Para.offset); 1079 1080 if (fd.isCrtCtorDtor & 1) 1081 objmod.setModuleCtorDtor(s, true); 1082 if (fd.isCrtCtorDtor & 2) 1083 objmod.setModuleCtorDtor(s, false); 1084 1085 foreach (sd; *irs.deferToObj) 1086 { 1087 toObjFile(sd, false); 1088 } 1089 1090 if (ud) 1091 { 1092 foreach (fdn; ud.deferredNested) 1093 { 1094 toObjFile(fdn, false); 1095 } 1096 } 1097 1098 if (irs.startaddress) 1099 { 1100 //printf("Setting start address\n"); 1101 objmod.startaddress(irs.startaddress); 1102 } 1103 } 1104 1105 1106 /******************************************* 1107 * Detect special functions like `main()` and do special handling for them, 1108 * like special mangling, including libraries, setting the storage class, etc. 1109 * `objmod` and `fd` are updated. 1110 * 1111 * Params: 1112 * objmod = object module 1113 * fd = function symbol 1114 */ 1115 private void specialFunctions(Obj objmod, FuncDeclaration fd) 1116 { 1117 const libname = global.finalDefaultlibname(); 1118 1119 Symbol* s = fd.toSymbol(); // backend symbol corresponding to fd 1120 1121 // Pull in RTL startup code (but only once) 1122 if (fd.isMain() && onlyOneMain(fd.loc)) 1123 { 1124 if (target.isPOSIX) 1125 { 1126 objmod.external_def("_main"); 1127 } 1128 else if (global.params.mscoff) 1129 { 1130 objmod.external_def("main"); 1131 } 1132 else if (global.params.targetOS == TargetOS.Windows && !global.params.is64bit) 1133 { 1134 objmod.external_def("_main"); 1135 objmod.external_def("__acrtused_con"); 1136 } 1137 if (libname) 1138 obj_includelib(libname); 1139 s.Sclass = SCglobal; 1140 } 1141 else if (fd.isRtInit()) 1142 { 1143 if (target.isPOSIX || global.params.mscoff) 1144 { 1145 objmod.ehsections(); // initialize exception handling sections 1146 } 1147 } 1148 else if (fd.isCMain()) 1149 { 1150 if (global.params.mscoff) 1151 { 1152 if (global.params.mscrtlib.length && global.params.mscrtlib[0]) 1153 obj_includelib(global.params.mscrtlib); 1154 objmod.includelib("OLDNAMES"); 1155 } 1156 else if (global.params.targetOS == TargetOS.Windows && !global.params.is64bit) 1157 { 1158 objmod.external_def("__acrtused_con"); // bring in C startup code 1159 objmod.includelib("snn.lib"); // bring in C runtime library 1160 } 1161 s.Sclass = SCglobal; 1162 } 1163 else if (global.params.targetOS == TargetOS.Windows && fd.isWinMain() && onlyOneMain(fd.loc)) 1164 { 1165 if (global.params.mscoff) 1166 { 1167 objmod.includelib("uuid"); 1168 if (global.params.mscrtlib.length && global.params.mscrtlib[0]) 1169 obj_includelib(global.params.mscrtlib); 1170 objmod.includelib("OLDNAMES"); 1171 } 1172 else 1173 { 1174 objmod.external_def("__acrtused"); 1175 } 1176 if (libname) 1177 obj_includelib(libname); 1178 s.Sclass = SCglobal; 1179 } 1180 1181 // Pull in RTL startup code 1182 else if (global.params.targetOS == TargetOS.Windows && fd.isDllMain() && onlyOneMain(fd.loc)) 1183 { 1184 if (global.params.mscoff) 1185 { 1186 objmod.includelib("uuid"); 1187 if (global.params.mscrtlib.length && global.params.mscrtlib[0]) 1188 obj_includelib(global.params.mscrtlib); 1189 objmod.includelib("OLDNAMES"); 1190 } 1191 else 1192 { 1193 objmod.external_def("__acrtused_dll"); 1194 } 1195 if (libname) 1196 obj_includelib(libname); 1197 s.Sclass = SCglobal; 1198 } 1199 } 1200 1201 1202 private bool onlyOneMain(Loc loc) 1203 { 1204 __gshared Loc lastLoc; 1205 __gshared bool hasMain = false; 1206 if (hasMain) 1207 { 1208 const(char)* msg = ""; 1209 if (global.params.addMain) 1210 msg = ", -main switch added another `main()`"; 1211 const(char)* otherMainNames = ""; 1212 if (global.params.targetOS == TargetOS.Windows) 1213 otherMainNames = ", `WinMain`, or `DllMain`"; 1214 error(loc, "only one `main`%s allowed%s. Previously found `main` at %s", 1215 otherMainNames, msg, lastLoc.toChars()); 1216 return false; 1217 } 1218 lastLoc = loc; 1219 hasMain = true; 1220 return true; 1221 } 1222 1223 /* ================================================================== */ 1224 1225 /***************************** 1226 * Return back end type corresponding to D front end type. 1227 */ 1228 1229 tym_t totym(Type tx) 1230 { 1231 tym_t t; 1232 switch (tx.ty) 1233 { 1234 case Tvoid: t = TYvoid; break; 1235 case Tint8: t = TYschar; break; 1236 case Tuns8: t = TYuchar; break; 1237 case Tint16: t = TYshort; break; 1238 case Tuns16: t = TYushort; break; 1239 case Tint32: t = TYint; break; 1240 case Tuns32: t = TYuint; break; 1241 case Tint64: t = TYllong; break; 1242 case Tuns64: t = TYullong; break; 1243 case Tfloat32: t = TYfloat; break; 1244 case Tfloat64: t = TYdouble; break; 1245 case Tfloat80: t = TYldouble; break; 1246 case Timaginary32: t = TYifloat; break; 1247 case Timaginary64: t = TYidouble; break; 1248 case Timaginary80: t = TYildouble; break; 1249 case Tcomplex32: t = TYcfloat; break; 1250 case Tcomplex64: t = TYcdouble; break; 1251 case Tcomplex80: t = TYcldouble; break; 1252 case Tbool: t = TYbool; break; 1253 case Tchar: t = TYchar; break; 1254 case Twchar: t = TYwchar_t; break; 1255 case Tdchar: 1256 t = (global.params.symdebug == 1 || global.params.targetOS & TargetOS.Posix) ? TYdchar : TYulong; 1257 break; 1258 1259 case Taarray: t = TYaarray; break; 1260 case Tclass: 1261 case Treference: 1262 case Tpointer: t = TYnptr; break; 1263 case Tdelegate: t = TYdelegate; break; 1264 case Tarray: t = TYdarray; break; 1265 case Tsarray: t = TYstruct; break; 1266 case Tnoreturn: t = TYvoid; break; 1267 1268 case Tstruct: 1269 t = TYstruct; 1270 break; 1271 1272 case Tenum: 1273 { 1274 Type tb = tx.toBasetype(); 1275 const id = tx.toDsymbol(null).ident; 1276 if (id == Id.__c_long) 1277 t = tb.ty == Tint32 ? TYlong : TYllong; 1278 else if (id == Id.__c_ulong) 1279 t = tb.ty == Tuns32 ? TYulong : TYullong; 1280 else if (id == Id.__c_long_double) 1281 t = TYdouble; 1282 else if (id == Id.__c_complex_float) 1283 t = TYcfloat; 1284 else if (id == Id.__c_complex_double) 1285 t = TYcdouble; 1286 else if (id == Id.__c_complex_real) 1287 t = TYcldouble; 1288 else 1289 t = totym(tb); 1290 break; 1291 } 1292 1293 case Tident: 1294 case Ttypeof: 1295 case Tmixin: 1296 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1297 error(Loc.initial, "forward reference of `%s`", tx.toChars()); 1298 t = TYint; 1299 break; 1300 1301 case Tnull: 1302 t = TYnptr; 1303 break; 1304 1305 case Tvector: 1306 { 1307 auto tv = cast(TypeVector)tx; 1308 const tb = tv.elementType(); 1309 const s32 = tv.alignsize() == 32; // if 32 byte, 256 bit vector 1310 switch (tb.ty) 1311 { 1312 case Tvoid: 1313 case Tint8: t = s32 ? TYschar32 : TYschar16; break; 1314 case Tuns8: t = s32 ? TYuchar32 : TYuchar16; break; 1315 case Tint16: t = s32 ? TYshort16 : TYshort8; break; 1316 case Tuns16: t = s32 ? TYushort16 : TYushort8; break; 1317 case Tint32: t = s32 ? TYlong8 : TYlong4; break; 1318 case Tuns32: t = s32 ? TYulong8 : TYulong4; break; 1319 case Tint64: t = s32 ? TYllong4 : TYllong2; break; 1320 case Tuns64: t = s32 ? TYullong4 : TYullong2; break; 1321 case Tfloat32: t = s32 ? TYfloat8 : TYfloat4; break; 1322 case Tfloat64: t = s32 ? TYdouble4 : TYdouble2; break; 1323 default: 1324 assert(0); 1325 } 1326 break; 1327 } 1328 1329 case Tfunction: 1330 { 1331 auto tf = cast(TypeFunction)tx; 1332 final switch (tf.linkage) 1333 { 1334 case LINK.windows: 1335 if (global.params.is64bit) 1336 goto case LINK.c; 1337 t = (tf.parameterList.varargs == VarArg.variadic) ? TYnfunc : TYnsfunc; 1338 break; 1339 1340 case LINK.c: 1341 case LINK.cpp: 1342 case LINK.objc: 1343 t = TYnfunc; 1344 if (global.params.targetOS == TargetOS.Windows) 1345 { 1346 } 1347 else if (!global.params.is64bit && retStyle(tf, false) == RET.stack) 1348 t = TYhfunc; 1349 break; 1350 1351 case LINK.d: 1352 t = (tf.parameterList.varargs == VarArg.variadic) ? TYnfunc : TYjfunc; 1353 break; 1354 1355 case LINK.default_: 1356 case LINK.system: 1357 printf("linkage = %d\n", tf.linkage); 1358 assert(0); 1359 } 1360 if (tf.isnothrow) 1361 t |= mTYnothrow; 1362 return t; 1363 } 1364 default: 1365 //printf("ty = %d, '%s'\n", tx.ty, tx.toChars()); 1366 assert(0); 1367 } 1368 1369 t |= modToTym(tx.mod); // Add modifiers 1370 1371 return t; 1372 } 1373 1374 /************************************** 1375 */ 1376 1377 Symbol *toSymbol(Type t) 1378 { 1379 if (t.ty == Tclass) 1380 { 1381 return toSymbol((cast(TypeClass)t).sym); 1382 } 1383 assert(0); 1384 } 1385 1386 /******************************************* 1387 * Generate readonly symbol that consists of a bunch of zeros. 1388 * Immutable Symbol instances can be mapped over it. 1389 * Only one is generated per object file. 1390 * Returns: 1391 * bzero symbol 1392 */ 1393 Symbol* getBzeroSymbol() 1394 { 1395 Symbol* s = bzeroSymbol; 1396 if (s) 1397 return s; 1398 1399 s = symbol_calloc("__bzeroBytes"); 1400 s.Stype = type_static_array(128, type_fake(TYuchar)); 1401 s.Stype.Tmangle = mTYman_c; 1402 s.Stype.Tcount++; 1403 s.Sclass = SCglobal; 1404 s.Sfl = FLdata; 1405 s.Sflags |= SFLnodebug; 1406 s.Salignment = 16; 1407 1408 auto dtb = DtBuilder(0); 1409 dtb.nzeros(128); 1410 s.Sdt = dtb.finish(); 1411 dt2common(&s.Sdt); 1412 1413 outdata(s); 1414 1415 bzeroSymbol = s; 1416 return s; 1417 } 1418 1419 1420 1421 /************************************** 1422 * Generate elem that is a dynamic array slice of the module file name. 1423 */ 1424 1425 private elem *toEfilename(Module m) 1426 { 1427 //printf("toEfilename(%s)\n", m.toChars()); 1428 const(char)* id = m.srcfile.toChars(); 1429 size_t len = strlen(id); 1430 1431 if (!m.sfilename) 1432 { 1433 // Put out as a static array 1434 m.sfilename = toStringSymbol(id, len, 1); 1435 } 1436 1437 // Turn static array into dynamic array 1438 return el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(m.sfilename)); 1439 } 1440 1441 // Used in e2ir.d 1442 elem *toEfilenamePtr(Module m) 1443 { 1444 //printf("toEfilenamePtr(%s)\n", m.toChars()); 1445 const(char)* id = m.srcfile.toChars(); 1446 size_t len = strlen(id); 1447 Symbol* s = toStringSymbol(id, len, 1); 1448 return el_ptr(s); 1449 }