type *TypeClass::toCtype() { //printf("TypeClass::toCtype() %s\n", toChars()); if (ctype) return ctype; type *t = type_struct_class(sym->toPrettyChars(), sym->alignsize, sym->structsize, NULL, NULL, false, true, true); ctype = type_pointer(t); /* Add in fields of the class * (after setting ctype to avoid infinite recursion) */ if (global.params.symdebug) for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields[i]; symbol_struct_addField(t->Ttag, v->ident->toChars(), v->type->toCtype(), v->offset); } if (0 && global.params.symdebug) sym->toDebug(); return ctype; }
Classsym *fake_classsym(Identifier *id) { TYPE *t = type_struct_class(id->toChars(),8,0, NULL,NULL, false, false, true); t->Ttag->Sstruct->Sflags = STRglobal; t->Tflags |= TFsizeunknown | TFforward; assert(t->Tmangle == 0); t->Tmangle = mTYman_d; return t->Ttag; }
void visit(TypeClass *t) { //printf("TypeClass::toCtype() %s\n", toChars()); type *tc = type_struct_class(t->sym->toPrettyChars(true), t->sym->alignsize, t->sym->structsize, NULL, NULL, false, true, true); t->ctype = type_pointer(tc); /* Add in fields of the class * (after setting ctype to avoid infinite recursion) */ if (global.params.symdebug) { for (size_t i = 0; i < t->sym->fields.dim; i++) { VarDeclaration *v = t->sym->fields[i]; symbol_struct_addField(tc->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset); } } }
/************************************* * Closures are implemented by taking the local variables that * need to survive the scope of the function, and copying them * into a gc allocated chuck of memory. That chunk, called the * closure here, is inserted into the linked list of stack * frames instead of the usual stack frame. * * buildClosure() inserts code just after the function prolog * is complete. It allocates memory for the closure, allocates * a local variable (sclosure) to point to it, inserts into it * the link to the enclosing frame, and copies into it the parameters * that are referred to in nested functions. * In VarExp::toElem and SymOffExp::toElem, when referring to a * variable that is in a closure, takes the offset from sclosure rather * than from the frame pointer. * * getEthis() and NewExp::toElem need to use sclosure, if set, rather * than the current frame pointer. */ void buildClosure(FuncDeclaration *fd, IRState *irs) { if (fd->needsClosure()) { // Generate closure on the heap // BUG: doesn't capture variadic arguments passed to this function /* BUG: doesn't handle destructors for the local variables. * The way to do it is to make the closure variables the fields * of a class object: * class Closure { * vtbl[] * monitor * ptr to destructor * sthis * ... closure variables ... * ~this() { call destructor } * } */ //printf("FuncDeclaration::buildClosure() %s\n", toChars()); /* Generate type name for closure struct */ const char *name1 = "CLOSURE."; const char *name2 = fd->toPrettyChars(); size_t namesize = strlen(name1)+strlen(name2)+1; char *closname = (char *) calloc(namesize, sizeof(char)); strcat(strcat(closname, name1), name2); /* Build type for closure */ type *Closstru = type_struct_class(closname, Target::ptrsize, 0, NULL, NULL, false, false, true); symbol_struct_addField(Closstru->Ttag, "__chain", Type_toCtype(Type::tvoidptr), 0); Symbol *sclosure; sclosure = symbol_name("__closptr", SCauto, type_pointer(Closstru)); sclosure->Sflags |= SFLtrue | SFLfree; symbol_add(sclosure); irs->sclosure = sclosure; unsigned offset = Target::ptrsize; // leave room for previous sthis for (size_t i = 0; i < fd->closureVars.dim; i++) { VarDeclaration *v = fd->closureVars[i]; //printf("closure var %s\n", v->toChars()); assert(v->isVarDeclaration()); if (v->needsAutoDtor()) { /* Because the value needs to survive the end of the scope! */ v->error("has scoped destruction, cannot build closure"); } if (v->isargptr) { /* See Bugzilla 2479 * This is actually a bug, but better to produce a nice * message at compile time rather than memory corruption at runtime */ v->error("cannot reference variadic arguments from closure"); } /* Align and allocate space for v in the closure * just like AggregateDeclaration::addField() does. */ unsigned memsize; unsigned memalignsize; structalign_t xalign; if (v->storage_class & STClazy) { /* Lazy variables are really delegates, * so give same answers that TypeDelegate would */ memsize = Target::ptrsize * 2; memalignsize = memsize; xalign = STRUCTALIGN_DEFAULT; } else if (ISWIN64REF(v)) { memsize = v->type->size(); memalignsize = v->type->alignsize(); xalign = v->alignment; } else if (ISREF(v, NULL)) { // reference parameters are just pointers memsize = Target::ptrsize; memalignsize = memsize; xalign = STRUCTALIGN_DEFAULT; } else { memsize = v->type->size(); memalignsize = v->type->alignsize(); xalign = v->alignment; } AggregateDeclaration::alignmember(xalign, memalignsize, &offset); v->offset = offset; offset += memsize; /* Set Sscope to closure */ Symbol *vsym = toSymbol(v); assert(vsym->Sscope == NULL); vsym->Sscope = sclosure; /* Add variable as closure type member */ symbol_struct_addField(Closstru->Ttag, vsym->Sident, vsym->Stype, v->offset); //printf("closure field %s: memalignsize: %i, offset: %i\n", vsym->Sident, memalignsize, v->offset); /* Can't do nrvo if the variable is put in a closure, since * what the shidden points to may no longer exist. */ if (fd->nrvo_can && fd->nrvo_var == v) { fd->nrvo_can = 0; } } // offset is now the size of the closure Closstru->Ttag->Sstruct->Sstructsize = offset; // Allocate memory for the closure elem *e = el_long(TYsize_t, offset); e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM_ALLOCMEMORY)), e); toTraceGC(irs, e, &fd->loc); // Assign block of memory to sclosure // sclosure = allocmemory(sz); e = el_bin(OPeq, TYvoid, el_var(sclosure), e); // Set the first element to sthis // *(sclosure + 0) = sthis; elem *ethis; if (irs->sthis) ethis = el_var(irs->sthis); else ethis = el_long(TYnptr, 0); elem *ex = el_una(OPind, TYnptr, el_var(sclosure)); ex = el_bin(OPeq, TYnptr, ex, ethis); e = el_combine(e, ex); // Copy function parameters into closure for (size_t i = 0; i < fd->closureVars.dim; i++) { VarDeclaration *v = fd->closureVars[i]; if (!v->isParameter()) continue; tym_t tym = totym(v->type); bool win64ref = ISWIN64REF(v); if (win64ref) { if (v->storage_class & STClazy) tym = TYdelegate; } else if (ISREF(v, NULL)) tym = TYnptr; // reference parameters are just pointers else if (v->storage_class & STClazy) tym = TYdelegate; ex = el_bin(OPadd, TYnptr, el_var(sclosure), el_long(TYsize_t, v->offset)); ex = el_una(OPind, tym, ex); elem *ev = el_var(toSymbol(v)); if (win64ref) { ev->Ety = TYnptr; ev = el_una(OPind, tym, ev); if (tybasic(ev->Ety) == TYstruct || tybasic(ev->Ety) == TYarray) ev->ET = Type_toCtype(v->type); } if (tybasic(ex->Ety) == TYstruct || tybasic(ex->Ety) == TYarray) { ::type *t = Type_toCtype(v->type); ex->ET = t; ex = el_bin(OPstreq, tym, ex, ev); ex->ET = t; } else ex = el_bin(OPeq, tym, ex, ev); e = el_combine(e, ex); } block_appendexp(irs->blx->curblock, e); } }
void visit(TypeStruct *t) { //printf("TypeStruct::toCtype() '%s'\n", t->sym->toChars()); Type *tm = t->mutableOf(); if (tm->ctype) { t->ctype = type_alloc(tybasic(tm->ctype->Tty)); t->ctype->Tcount++; if (t->ctype->Tty == TYstruct) { Symbol *s = tm->ctype->Ttag; t->ctype->Ttag = (Classsym *)s; // structure tag name } // Add modifiers switch (t->mod) { case 0: assert(0); break; case MODconst: case MODwild: case MODwildconst: t->ctype->Tty |= mTYconst; break; case MODshared: t->ctype->Tty |= mTYshared; break; case MODshared | MODconst: case MODshared | MODwild: case MODshared | MODwildconst: t->ctype->Tty |= mTYshared | mTYconst; break; case MODimmutable: t->ctype->Tty |= mTYimmutable; break; default: assert(0); } } else { StructDeclaration *sym = t->sym; if (sym->ident == Id::__c_long_double) { t->ctype = type_fake(TYdouble); t->ctype->Tcount++; return; } t->ctype = type_struct_class(sym->toPrettyChars(true), sym->alignsize, sym->structsize, sym->arg1type ? Type_toCtype(sym->arg1type) : NULL, sym->arg2type ? Type_toCtype(sym->arg2type) : NULL, sym->isUnionDeclaration() != 0, false, sym->isPOD() != 0); tm->ctype = t->ctype; /* Add in fields of the struct * (after setting ctype to avoid infinite recursion) */ if (global.params.symdebug) { for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields[i]; symbol_struct_addField(t->ctype->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset); } } } //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags); }
type *TypeStruct::toCtype() { if (ctype) return ctype; //printf("TypeStruct::toCtype() '%s'\n", sym->toChars()); Type *tm = mutableOf(); if (tm->ctype) { Symbol *s = tm->ctype->Ttag; type *t = type_alloc(TYstruct); t->Ttag = (Classsym *)s; // structure tag name t->Tcount++; // Add modifiers switch (mod) { case 0: assert(0); break; case MODconst: case MODwild: t->Tty |= mTYconst; break; case MODimmutable: t->Tty |= mTYimmutable; break; case MODshared: t->Tty |= mTYshared; break; case MODshared | MODwild: case MODshared | MODconst: t->Tty |= mTYshared | mTYconst; break; default: assert(0); } ctype = t; } else { type *t = type_struct_class(sym->toPrettyChars(), sym->alignsize, sym->structsize, sym->arg1type ? sym->arg1type->toCtype() : NULL, sym->arg2type ? sym->arg2type->toCtype() : NULL, sym->isUnionDeclaration() != 0, false, sym->isPOD() != 0); tm->ctype = t; ctype = t; /* Add in fields of the struct * (after setting ctype to avoid infinite recursion) */ if (global.params.symdebug) for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields[i]; symbol_struct_addField(t->Ttag, v->ident->toChars(), v->type->toCtype(), v->offset); } } if (0 && global.params.symdebug) sym->toDebug(); //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags); return ctype; }
void FuncDeclaration_toObjFile(FuncDeclaration *fd, bool multiobj) { ClassDeclaration *cd = fd->parent->isClassDeclaration(); //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", fd, fd->parent->toChars(), fd->toChars()); //if (type) printf("type = %s\n", type->toChars()); #if 0 //printf("line = %d\n", getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (getWhere() / LINEINC) || ee->EElinnum > (endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = toSymbol(this); } #endif if (fd->semanticRun >= PASSobj) // if toObjFile() already run return; if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next == NULL) return; // If errors occurred compiling it, such as bugzilla 6118 if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next->ty == Terror) return; if (fd->semantic3Errors) return; if (global.errors) return; if (!fd->fbody) return; UnitTestDeclaration *ud = fd->isUnitTestDeclaration(); if (ud && !global.params.useUnitTests) return; if (multiobj && !fd->isStaticDtorDeclaration() && !fd->isStaticCtorDeclaration()) { obj_append(fd); return; } if (fd->semanticRun == PASSsemanticdone) { /* What happened is this function failed semantic3() with errors, * but the errors were gagged. * Try to reproduce those errors, and then fail. */ fd->error("errors compiling the function"); return; } assert(fd->semanticRun == PASSsemantic3done); assert(fd->ident != Id::empty); for (FuncDeclaration *fd2 = fd; fd2; ) { if (fd2->inNonRoot()) return; if (fd2->isNested()) fd2 = fd2->toParent2()->isFuncDeclaration(); else break; } if (UnitTestDeclaration *udp = needsDeferredNested(fd)) { /* Can't do unittest's out of order, they are order dependent in that their * execution is done in lexical order. */ udp->deferredNested.push(fd); //printf("%s @[%s]\n\t--> pushed to unittest @[%s]\n", // fd->toPrettyChars(), fd->loc.toChars(), udp->loc.toChars()); return; } if (fd->isArrayOp && isDruntimeArrayOp(fd->ident)) { // Implementation is in druntime return; } // start code generation fd->semanticRun = PASSobj; if (global.params.verbose) fprintf(global.stdmsg, "function %s\n", fd->toPrettyChars()); Symbol *s = toSymbol(fd); func_t *f = s->Sfunc; // tunnel type of "this" to debug info generation if (AggregateDeclaration* ad = fd->parent->isAggregateDeclaration()) { ::type* t = Type_toCtype(ad->getType()); if (cd) t = t->Tnext; // skip reference f->Fclass = (Classsym *)t; } /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (fd->isVirtual() && (fd->fensure || fd->frequire)) f->Fflags3 |= Ffakeeh; #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = fd->parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } /* Vector operations should be comdat's */ if (fd->isArrayOp) s->Sclass = SCcomdat; if (fd->inlinedNestedCallees) { /* Bugzilla 15333: If fd contains inlined expressions that come from * nested function bodies, the enclosing of the functions must be * generated first, in order to calculate correct frame pointer offset. */ for (size_t i = 0; i < fd->inlinedNestedCallees->dim; i++) { FuncDeclaration *f = (*fd->inlinedNestedCallees)[i]; FuncDeclaration *fp = f->toParent2()->isFuncDeclaration();; if (fp && fp->semanticRun < PASSobj) { toObjFile(fp, multiobj); } } } if (fd->isNested()) { //if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; /* The enclosing function must have its code generated first, * in order to calculate correct frame pointer offset. */ FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fdp && fdp->semanticRun < PASSobj) { toObjFile(fdp, multiobj); } } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code (but only once) if (fd->isMain() && onlyOneMain(fd->loc)) { #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS objmod->external_def("_main"); objmod->ehsections(); // initialize exception handling sections #endif if (global.params.mscoff) { objmod->external_def("main"); objmod->ehsections(); // initialize exception handling sections } else if (config.exe == EX_WIN32) { objmod->external_def("_main"); objmod->external_def("__acrtused_con"); } objmod->includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && fd->linkage == LINKc) { if (global.params.mscoff) { objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); } else if (config.exe == EX_WIN32) { objmod->external_def("__acrtused_con"); // bring in C startup code objmod->includelib("snn.lib"); // bring in C runtime library } s->Sclass = SCglobal; } #if TARGET_WINDOS else if (fd->isWinMain() && onlyOneMain(fd->loc)) { if (global.params.mscoff) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused"); } objmod->includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (fd->isDllMain() && onlyOneMain(fd->loc)) { if (global.params.mscoff) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused_dll"); } objmod->includelib(libname); s->Sclass = SCglobal; } #endif } symtab_t *symtabsave = cstate.CSpsymtab; cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = fd->parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, fd); Dsymbols deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; void *labels = NULL; irs.labels = &labels; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); int reverse = tyrevfunc(s->Stype->Tty); assert(fd->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)fd->type; RET retmethod = retStyle(tf); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = Type_toCtype(tf->next->pointerTo()); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; if (fd->nrvo_can && fd->nrvo_var && fd->nrvo_var->nestedrefs.dim) type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; fd->shidden = shidden; } else { // Register return style cannot make nrvo. // Auto functions keep the nrvo_can flag up to here, // so we should eliminate it before entering backend. fd->nrvo_can = 0; } if (fd->vthis) { assert(!fd->vthis->csym); sthis = toSymbol(fd->vthis); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } // Estimate number of parameters, pi size_t pi = (fd->v_arguments != NULL); if (fd->parameters) pi += fd->parameters->dim; // Create a temporary buffer, params[], to hold function parameters Symbol *paramsbuf[10]; Symbol **params = paramsbuf; // allocate on stack if possible if (pi + 2 > 10) // allow extra 2 for sthis and shidden { params = (Symbol **)malloc((pi + 2) * sizeof(Symbol *)); assert(params); } // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (fd->v_arguments) { params[pi] = toSymbol(fd->v_arguments); pi += 1; } if (fd->parameters) { for (size_t i = 0; i < fd->parameters->dim; i++) { VarDeclaration *v = (*fd->parameters)[i]; //printf("param[%d] = %p, %s\n", i, v, v->toChars()); assert(!v->csym); params[pi + i] = toSymbol(v); } pi += fd->parameters->dim; } if (reverse) { // Reverse params[] entries for (size_t i = 0; i < pi/2; i++) { Symbol *sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && fd->linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // Determine register assignments if (pi) { FuncParamRegs fpr(tyf); for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2)) { sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; } } } // Done with params if (params != paramsbuf) free(params); params = NULL; if (fd->fbody) { localgot = NULL; Statement *sbody = fd->fbody; Blockx bx; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = fd; bx.module = fd->getModule(); irs.blx = &bx; // Initialize argptr if (fd->v_argptr) { // Declare va_argsave if (global.params.is64bit && !global.params.isWindows) { type *t = type_struct_class("__va_argsave_t", 16, 8 * 6 + 8 * 16 + 8 * 3, NULL, NULL, false, false, true); // The backend will pick this up by name Symbol *s = symbol_name("__va_argsave", SCauto, t); s->Stype->Tty |= mTYvolatile; symbol_add(s); } Symbol *s = toSymbol(fd->v_argptr); symbol_add(s); elem *e = el_una(OPva_start, TYnptr, el_ptr(s)); block_appendexp(irs.blx->curblock, e); } /* Doing this in semantic3() caused all kinds of problems: * 1. couldn't reliably get the final mangling of the function name due to fwd refs * 2. impact on function inlining * 3. what to do when writing out .di files, or other pretty printing */ if (global.params.trace && !fd->isCMain()) { /* The profiler requires TLS, and TLS may not be set up yet when C main() * gets control (i.e. OSX), leading to a crash. */ /* Wrap the entire function body in: * trace_pro("funcname"); * try * body; * finally * _c_trace_epi(); */ StringExp *se = StringExp::create(Loc(), s->Sident); se->type = Type::tstring; se->type = se->type->semantic(Loc(), NULL); Expressions *exps = Expressions_create(); exps->push(se); FuncDeclaration *fdpro = FuncDeclaration::genCfunc(NULL, Type::tvoid, "trace_pro"); Expression *ec = VarExp::create(Loc(), fdpro); Expression *e = CallExp::create(Loc(), ec, exps); e->type = Type::tvoid; Statement *sp = ExpStatement::create(fd->loc, e); FuncDeclaration *fdepi = FuncDeclaration::genCfunc(NULL, Type::tvoid, "_c_trace_epi"); ec = VarExp::create(Loc(), fdepi); e = CallExp::create(Loc(), ec); e->type = Type::tvoid; Statement *sf = ExpStatement::create(fd->loc, e); Statement *stf; if (sbody->blockExit(fd, false) == BEfallthru) stf = CompoundStatement::create(Loc(), sbody, sf); else stf = TryFinallyStatement::create(Loc(), sbody, sf); sbody = CompoundStatement::create(Loc(), sp, stf); } if (fd->interfaceVirtual) { // Adjust the 'this' pointer instead of using a thunk assert(irs.sthis); elem *ethis = el_var(irs.sthis); elem *e = el_bin(OPminass, TYnptr, ethis, el_long(TYsize_t, fd->interfaceVirtual->offset)); block_appendexp(irs.blx->curblock, e); } buildClosure(fd, &irs); if (config.ehmethod == EH_WIN32 && fd->isSynchronized() && cd && !fd->isStatic() && !sbody->usesEH() && !global.params.trace) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } Statement_toIR(sbody, &irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (fd->isCtorDeclaration()) { assert(sthis); for (block *b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } insertFinallyBlockCalls(f->Fstartblock); } // If static constructor if (fd->isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration { ssharedctors.push(s); } else if (fd->isStaticCtorDeclaration()) { sctors.push(s); } // If static destructor if (fd->isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration { SharedStaticDtorDeclaration *f = fd->isSharedStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ esharedctorgates.push(f); } sshareddtors.shift(s); } else if (fd->isStaticDtorDeclaration()) { StaticDtorDeclaration *f = fd->isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } sdtors.shift(s); } // If unit test if (ud) { stests.push(s); } if (global.errors) { // Restore symbol table cstate.CSpsymtab = symtabsave; return; } writefunc(s); // Restore symbol table cstate.CSpsymtab = symtabsave; if (fd->isExport()) objmod->export_symbol(s, Para.offset); for (size_t i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (*irs.deferToObj)[i]; toObjFile(s, false); } if (ud) { for (size_t i = 0; i < ud->deferredNested.dim; i++) { FuncDeclaration *fd = ud->deferredNested[i]; toObjFile(fd, false); } } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (fd->ident && memcmp(fd->ident->toChars(), "_STD", 4) == 0) objmod->staticdtor(s); #endif if (irs.startaddress) { //printf("Setting start address\n"); objmod->startaddress(irs.startaddress); } }