code *nteh_monitor_epilog(regm_t retregs) { /* * CALL _d_monitor_epilog * POP FS:__except_list */ assert(config.exe == EX_WIN32); // BUG: figure out how to implement for other EX's Symbol *s = getRtlsym(RTLSYM_MONITOR_EPILOG); //desregs = ~s->Sregsaved & ALLREGS; regm_t desregs = 0; code *cs1; code *cs2; gensaverestore(retregs& desregs,&cs1,&cs2); CodeBuilder cdb(getregs(desregs)); cdb.gencs(0xE8,0,FLfunc,s); // CALL __d_monitor_epilog CodeBuilder cdb1(cs1); CodeBuilder cdb2(cs2); cdb1.append(cdb, cdb2); code cs; cs.Iop = 0x8F; cs.Irm = modregrm(0,0,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; cdb1.gen(&cs); // POP FS:__except_list return cdb1.finish(); }
static void genhelpers(Module *m) { // If module assert for (int i = 0; i < 3; i++) { Symbol *ma; unsigned rt; unsigned bc; switch (i) { case 0: ma = toModuleArray(m); rt = RTLSYM_DARRAY; bc = BCexit; break; case 1: ma = toModuleAssert(m); rt = RTLSYM_DASSERT; bc = BCexit; break; case 2: ma = toModuleUnittest(m); rt = RTLSYM_DUNITTEST; bc = BCret; break; default: assert(0); } if (!ma) continue; localgot = NULL; // Call dassert(filename, line) // Get sole parameter, linnum Symbol *sp = symbol_calloc("linnum"); sp->Stype = type_fake(TYint); sp->Stype->Tcount++; sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; FuncParamRegs fpr(TYjfunc); fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2); sp->Sflags &= ~SFLspill; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; cstate.CSpsymtab = &ma->Sfunc->Flocsym; symbol_add(sp); elem *elinnum = el_var(sp); elem *efilename = toEfilename(m); if (config.exe == EX_WIN64) efilename = addressElem(efilename, Type::tstring, true); elem *e = el_var(getRtlsym(rt)); e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename)); block *b = block_calloc(); b->BC = bc; b->Belem = e; ma->Sfunc->Fstartline.Sfilename = m->arg; ma->Sfunc->Fstartblock = b; ma->Sclass = SCglobal; ma->Sfl = 0; ma->Sflags |= getRtlsym(rt)->Sflags & SFLexit; writefunc(ma); } }
code *nteh_monitor_prolog(Symbol *shandle) { /* * PUSH handle * PUSH offset _d_monitor_handler * PUSH FS:__except_list * MOV FS:__except_list,ESP * CALL _d_monitor_prolog */ CodeBuilder cdb1; CodeBuilder cdb; assert(config.exe == EX_WIN32); // BUG: figure out how to implement for other EX's if (shandle->Sclass == SCfastpar) { assert(shandle->Spreg != DX); assert(shandle->Spreg2 == NOREG); cdb.gen1(0x50 + shandle->Spreg); // PUSH shandle } else { // PUSH shandle useregs(mCX); cdb.genc1(0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); cdb.last()->Isib = modregrm(0,4,SP); cdb.gen1(0x50 + CX); // PUSH ECX } Symbol *smh = getRtlsym(RTLSYM_MONITOR_HANDLER); cdb.gencs(0x68,0,FLextern,smh); // PUSH offset _d_monitor_handler makeitextern(smh); code cs; useregs(mDX); cs.Iop = 0x8B; cs.Irm = modregrm(0,DX,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; cdb1.gen(&cs); // MOV EDX,FS:__except_list cdb.gen1(0x50 + DX); // PUSH EDX Symbol *s = getRtlsym(RTLSYM_MONITOR_PROLOG); regm_t desregs = ~s->Sregsaved & ALLREGS; cdb.append(getregs(desregs)); cdb.gencs(0xE8,0,FLfunc,s); // CALL _d_monitor_prolog cs.Iop = 0x89; NEWREG(cs.Irm,SP); cdb.gen(&cs); // MOV FS:__except_list,ESP cdb1.append(cdb); return cdb1.finish(); }
code *nteh_unwind(regm_t retregs,unsigned index) { code cs; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; code *cs1; code *cs2; gensaverestore(retregs & desregs,&cs1,&cs2); CodeBuilder cdb(getregs(desregs)); cs.Iop = 0x8D; cs.Irm = modregrm(2,reg,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLconst; // EBP offset of __context.prev cs.IEV1.Vint = nteh_EBPoffset_prev(); cdb.gen(&cs); // LEA ECX,contextsym cdb.genc2(0x68,0,index); // PUSH index cdb.gen1(0x50 + reg); // PUSH ECX #if MARS //cdb.gencs(0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table cdb.gencs(0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cdb.append(cod3_stackadj(NULL, -12)); #else cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cdb.append(cod3_stackadj(NULL, -8)); #endif CodeBuilder cdb1(cs1); CodeBuilder cdb2(cs2); cdb1.append(cdb, cdb2); return cdb1.finish(); }
code *nteh_unwind(regm_t retregs,unsigned index) { code *c; code cs; code *cs1; code *cs2; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; gensaverestore(retregs & desregs,&cs1,&cs2); c = getregs(desregs); cs.Iop = 0x8D; cs.Irm = modregrm(2,reg,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLconst; // EBP offset of __context.prev cs.IEV1.Vint = nteh_EBPoffset_prev(); c = gen(c,&cs); // LEA ECX,contextsym genc2(c,0x68,0,index); // PUSH index gen1(c,0x50 + reg); // PUSH ECX #if MARS //gencs(c,0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cod3_stackadj(c, -12); #else gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cod3_stackadj(c, -8); #endif c = cat4(cs1,c,cs2,NULL); return c; }
code *linux_unwind(regm_t retregs,unsigned index) { int i; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; code *cs1; code *cs2; gensaverestore(retregs & desregs,&cs1,&cs2); CodeBuilder cdb(getregs(desregs)); cdb.genc2(0x68,0,index); // PUSH index #if MARS // cdb.gencs(0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cdb.append(cod3_stackadj(NULL, -4)); #else cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cdb.append(cod3_stackadj(NULL, -8)); #endif CodeBuilder cdb1(cs1); CodeBuilder cdb2(cs2); cdb1.append(cdb, cdb2); return cdb1.finish(); }
void visit(SwitchErrorStatement *s) { Blockx *blx = irs->blx; //printf("SwitchErrorStatement::toIR()\n"); elem *efilename = el_ptr(toSymbol(blx->module)); elem *elinnum = el_long(TYint, s->loc.linnum); elem *e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_DSWITCHERR)), el_param(elinnum, efilename)); block_appendexp(blx->curblock, e); }
void visit(ThrowStatement *s) { // throw(exp) Blockx *blx = irs->blx; incUsage(irs, s->loc); elem *e = toElemDtor(s->exp, irs); e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_THROWC)),e); block_appendexp(blx->curblock, e); }
void nteh_framehandler(symbol *scopetable) { // Generate: // MOV EAX,&scope_table // JMP __cpp_framehandler if (scopetable) { symbol_debug(scopetable); code *c = gencs(NULL,0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table #if MARS gencs(c,0xE9,0,FLfunc,getRtlsym(RTLSYM_D_HANDLER)); // JMP _d_framehandler #else gencs(c,0xE9,0,FLfunc,getRtlsym(RTLSYM_CPP_HANDLER)); // JMP __cpp_framehandler #endif pinholeopt(c,NULL); codout(c); code_free(c); } }
code *linux_unwind(regm_t retregs,unsigned index) { code *c; code *cs1; code *cs2; int i; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; gensaverestore(retregs & desregs,&cs1,&cs2); c = getregs(desregs); c = genc2(c,0x68,0,index); // PUSH index #if MARS // gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cod3_stackadj(c, -4); #else gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cod3_stackadj(c, -8); #endif c = cat4(cs1,c,cs2,NULL); return c; }
void nteh_framehandler(Symbol *sfunc, Symbol *scopetable) { // Generate: // MOV EAX,&scope_table // JMP __cpp_framehandler if (scopetable) { symbol_debug(scopetable); CodeBuilder cdb; cdb.gencs(0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table #if MARS cdb.gencs(0xE9,0,FLfunc,getRtlsym(RTLSYM_D_HANDLER)); // JMP _d_framehandler #else cdb.gencs(0xE9,0,FLfunc,getRtlsym(RTLSYM_CPP_HANDLER)); // JMP __cpp_framehandler #endif code *c = cdb.finish(); pinholeopt(c,NULL); codout(sfunc->Sseg,c); code_free(c); } }
code *nteh_monitor_epilog(regm_t retregs) { /* * CALL _d_monitor_epilog * POP FS:__except_list */ code cs; code *c; code *cs1; code *cs2; code *cpop; regm_t desregs; Symbol *s; assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's s = getRtlsym(RTLSYM_MONITOR_EPILOG); //desregs = ~s->Sregsaved & ALLREGS; desregs = 0; gensaverestore(retregs & desregs,&cs1,&cs2); c = getregs(desregs); c = gencs(c,0xE8,0,FLfunc,s); // CALL __d_monitor_epilog cs.Iop = 0x8F; cs.Irm = modregrm(0,0,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; cpop = gen(NULL,&cs); // POP FS:__except_list c = cat4(cs1,c,cs2,cpop); return c; }
code *nteh_epilog() { if (config.exe != EX_WIN32) return NULL; /* Generate: mov ECX,__context[EBP].prev mov FS:__except_list,ECX */ code cs; CodeBuilder cdb; unsigned reg; #if MARS reg = CX; #else reg = (tybasic(funcsym_p->Stype->Tnext->Tty) == TYvoid) ? AX : CX; #endif useregs(mask[reg]); cs.Iop = 0x8B; cs.Irm = modregrm(2,reg,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLconst; // EBP offset of __context.prev cs.IEV1.Vint = nteh_EBPoffset_prev(); cdb.gen(&cs); cs.Iop = 0x89; cs.Irm = modregrm(0,reg,BPRM); cs.Iflags |= CFfs; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; cdb.gen(&cs); return cdb.finish(); }
/************************************* * 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 genObjFile(Module *m, bool multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, m->toChars()); if (m->ident == Id::entrypoint) { bool v = global.params.verbose; global.params.verbose = false; for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, global.params.multiobj); } global.params.verbose = v; return; } lastmname = (char*)m->srcfile->toChars(); objmod->initfile(lastmname, NULL, m->toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); if (m->doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *mod = m->aimports[0]; assert(mod); if (mod->sictor || mod->sctor || mod->sdtor || mod->ssharedctor || mod->sshareddtor) { Symbol *s = toSymbol(mod); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); sref->Sfl = FLdata; DtBuilder dtb; dtb.xoff(s, 0, TYnptr); sref->Sdt = dtb.finish(); outdata(sref); #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ m->cov = symbol_calloc("__coverage"); m->cov->Stype = type_fake(TYint); m->cov->Stype->Tmangle = mTYman_c; m->cov->Stype->Tcount++; m->cov->Sclass = SCstatic; m->cov->Sfl = FLdata; DtBuilder dtb; dtb.nzeros(4 * m->numlines); m->cov->Sdt = dtb.finish(); outdata(m->cov); m->covb = (unsigned *)calloc((m->numlines + 32) / 32, sizeof(*m->covb)); } for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, multiobj); } if (global.params.cov) { /* Generate * private bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; DtBuilder dtb; dtb.nbytes((m->numlines + 32) / 32 * sizeof(*m->covb), (char *)m->covb); bcov->Sdt = dtb.finish(); outdata(bcov); free(m->covb); m->covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; m->sictor = toSymbolX(m, "__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &m->sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(m->cov)); elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(bcov)); if (config.exe == EX_WIN64) { ecov = addressElem(ecov, Type::tvoid->arrayOf(), false); ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false); } elem *efilename = toEfilename(m); if (config.exe == EX_WIN64) efilename = addressElem(efilename, Type::tstring, true); elem *e = el_params( el_long(TYuchar, global.params.covPercent), ecov, ebcov, efilename, NULL); e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_DCOVER2)), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; m->sictor->Sfunc->Fstartline.Sfilename = m->arg; m->sictor->Sfunc->Fstartblock = b; writefunc(m->sictor); } m->sctor = callFuncsAndGates(m, &sctors, &ectorgates, "__modctor"); m->sdtor = callFuncsAndGates(m, &sdtors, NULL, "__moddtor"); m->ssharedctor = callFuncsAndGates(m, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); m->sshareddtor = callFuncsAndGates(m, &sshareddtors, NULL, "__modshareddtor"); m->stest = callFuncsAndGates(m, &stests, NULL, "__modtest"); if (m->doppelganger) genModuleInfo(m); } if (m->doppelganger) { objc_Module_genmoduleinfo_classes(); objmod->termfile(); return; } /* Always generate module info, because of templates and -cov. * But module info needs the runtime library, so disable it for betterC. */ if (!global.params.betterC /*|| needModuleInfo()*/) genModuleInfo(m); /* Always generate helper functions b/c of later templates instantiations * with different -release/-debug/-boundscheck/-unittest flags. */ if (!global.params.betterC) genhelpers(m); objmod->termfile(); }
code *nteh_prolog() { code cs; code *c1; code *c; if (usednteh & NTEHpassthru) { /* An sindex value of -2 is a magic value that tells the * stack unwinder to skip this frame. */ assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64 | EX_OPENBSD | EX_OPENBSD64)); cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = -2; return gen(CNIL,&cs); // PUSH -2 } /* Generate instance of struct __nt_context on stack frame: [ ] // previous ebp already there push -1 // sindex mov EDX,FS:__except_list push offset FLAT:scope_table // stable (not for MARS or C++) push offset FLAT:__except_handler3 // handler push EDX // prev mov FS:__except_list,ESP sub ESP,8 // info, esp for __except support */ // useregs(mAX); // What is this for? cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = -1; c1 = gen(CNIL,&cs); // PUSH -1 if (MARS || (usednteh & NTEHcpp)) { // PUSH &framehandler cs.IFL2 = FLframehandler; #if MARS nteh_scopetable(); #endif } else { // Do stable cs.Iflags |= CFoff; cs.IFL2 = FLextern; cs.IEVsym2 = nteh_scopetable(); cs.IEVoffset2 = 0; c1 = gen(c1,&cs); // PUSH &scope_table cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_EXCEPT_HANDLER3); makeitextern(getRtlsym(RTLSYM_EXCEPT_HANDLER3)); } c = gen(NULL,&cs); // PUSH &__except_handler3 if (config.exe == EX_WIN32) { makeitextern(getRtlsym(RTLSYM_EXCEPT_LIST)); #if 0 cs.Iop = 0xFF; cs.Irm = modregrm(0,6,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; gen(c,&cs); // PUSH FS:__except_list #else useregs(mDX); cs.Iop = 0x8B; cs.Irm = modregrm(0,DX,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; gen(c1,&cs); // MOV EDX,FS:__except_list gen1(c,0x50 + DX); // PUSH EDX #endif cs.Iop = 0x89; NEWREG(cs.Irm,SP); gen(c,&cs); // MOV FS:__except_list,ESP } c = cod3_stackadj(c, 8); return cat(c1,c); }
void visit(SwitchStatement *s) { int string; Blockx *blx = irs->blx; //printf("SwitchStatement::toIR()\n"); IRState mystate(irs,s); mystate.switchBlock = blx->curblock; /* Block for where "break" goes to */ mystate.breakBlock = block_calloc(blx); /* Block for where "default" goes to. * If there is a default statement, then that is where default goes. * If not, then do: * default: break; * by making the default block the same as the break block. */ mystate.defaultBlock = s->sdefault ? block_calloc(blx) : mystate.breakBlock; size_t numcases = 0; if (s->cases) numcases = s->cases->dim; incUsage(irs, s->loc); elem *econd = toElemDtor(s->condition, &mystate); if (s->hasVars) { /* Generate a sequence of if-then-else blocks for the cases. */ if (econd->Eoper != OPvar) { elem *e = exp2_copytotemp(econd); block_appendexp(mystate.switchBlock, e); econd = e->E2; } for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; elem *ecase = toElemDtor(cs->exp, &mystate); elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase); block *b = blx->curblock; block_appendexp(b, e); Label *clabel = getLabel(irs, blx, cs); block_next(blx, BCiftrue, NULL); b->appendSucc(clabel->lblock); b->appendSucc(blx->curblock); } /* The final 'else' clause goes to the default */ block *b = blx->curblock; block_next(blx, BCgoto, NULL); b->appendSucc(mystate.defaultBlock); Statement_toIR(s->_body, &mystate); /* Have the end of the switch body fall through to the block * following the switch statement. */ block_goto(blx, BCgoto, mystate.breakBlock); return; } if (s->condition->type->isString()) { // Number the cases so we can unscramble things after the sort() for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; cs->index = i; } s->cases->sort(); /* Create a sorted array of the case strings, and si * will be the symbol for it. */ dt_t *dt = NULL; Symbol *si = symbol_generate(SCstatic,type_fake(TYdarray)); dtsize_t(&dt, numcases); dtxoff(&dt, si, Target::ptrsize * 2, TYnptr); for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; if (cs->exp->op != TOKstring) { s->error("case '%s' is not a string", cs->exp->toChars()); // BUG: this should be an assert } else { StringExp *se = (StringExp *)(cs->exp); Symbol *si = toStringSymbol((char *)se->string, se->len, se->sz); dtsize_t(&dt, se->len); dtxoff(&dt, si, 0); } } si->Sdt = dt; si->Sfl = FLdata; outdata(si); /* Call: * _d_switch_string(string[] si, string econd) */ if (config.exe == EX_WIN64) econd = addressElem(econd, s->condition->type, true); elem *eparam = el_param(econd, (config.exe == EX_WIN64) ? el_ptr(si) : el_var(si)); switch (s->condition->type->nextOf()->ty) { case Tchar: econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_STRING)), eparam); break; case Twchar: econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_USTRING)), eparam); break; case Tdchar: // BUG: implement econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_DSTRING)), eparam); break; default: assert(0); } elem_setLoc(econd, s->loc); string = 1; } else string = 0; block_appendexp(mystate.switchBlock, econd); block_next(blx,BCswitch,NULL); // Corresponding free is in block_free targ_llong *pu = (targ_llong *) ::malloc(sizeof(*pu) * (numcases + 1)); mystate.switchBlock->BS.Bswitch = pu; /* First pair is the number of cases, and the default block */ *pu++ = numcases; mystate.switchBlock->appendSucc(mystate.defaultBlock); /* Fill in the first entry in each pair, which is the case value. * CaseStatement::toIR() will fill in * the second entry for each pair with the block. */ for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; if (string) { pu[cs->index] = i; } else { pu[i] = cs->exp->toInteger(); } } Statement_toIR(s->_body, &mystate); /* Have the end of the switch body fall through to the block * following the switch statement. */ block_goto(blx, BCgoto, mystate.breakBlock); }
code *cdsetjmp(elem *e,regm_t *pretregs) { code cs; code *c; regm_t retregs; unsigned stackpushsave; unsigned flag; c = NULL; stackpushsave = stackpush; #if SCPP if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp)) { /* If in C++ try block If the frame that is calling setjmp has a try,catch block then the call to setjmp3 is as follows: __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata); __cpp_longjmp_unwind is a routine in the RTL. This is a stdcall routine that will deal with unwinding for CPP Frames. trylevel is the value that gets incremented at each catch, constructor invocation. funcdata is the same value that you put into EAX prior to cppframehandler getting called. */ symbol *s; s = except_gensym(); if (!s) goto L1; c = gencs(c,0x68,0,FLextern,s); // PUSH &scope_table stackpush += 4; genadjesp(c,4); c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4); // PUSH trylevel stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_CPP_LONGJMP); cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_cpp_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 3; } else #endif if (funcsym_p->Sfunc->Fflags3 & Fnteh) { /* If in NT SEH try block If the frame that is calling setjmp has a try, except block then the call to setjmp3 is as follows: __setjmp3(environment,2,__seh_longjmp_unwind,trylevel); __seth_longjmp_unwind is supplied by the RTL and is a stdcall function. It is the name that MSOFT uses, we should probably use the same one. trylevel is the value that you increment at each try and decrement at the close of the try. This corresponds to the index field of the ehrec. */ int sindex_off; sindex_off = 20; // offset of __context.sindex cs.Iop = 0xFF; cs.Irm = modregrm(2,6,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLbprel; cs.IEVsym1 = nteh_contextsym(); cs.IEVoffset1 = sindex_off; c = gen(c,&cs); // PUSH scope_index stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_LONGJMP); cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_seh_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 2; } else { /* If the frame calling setjmp has neither a try..except, nor a try..catch, then call setjmp3 as follows: _setjmp3(environment,0) */ L1: flag = 0; } cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = flag; c = gen(c,&cs); // PUSH flag stackpush += 4; genadjesp(c,4); c = cat(c,pushParams(e->E1,REGSIZE)); c = cat(c,getregs(~getRtlsym(RTLSYM_SETJMP3)->Sregsaved & (ALLREGS | mES))); gencs(c,0xE8,0,FLfunc,getRtlsym(RTLSYM_SETJMP3)); // CALL __setjmp3 c = cod3_stackadj(c, -(stackpush - stackpushsave)); genadjesp(c,-(stackpush - stackpushsave)); stackpush = stackpushsave; retregs = regmask(e->Ety, TYnfunc); return cat(c,fixresult(e,retregs,pretregs)); }
code *nteh_monitor_prolog(Symbol *shandle) { /* * PUSH handle * PUSH offset _d_monitor_handler * PUSH FS:__except_list * MOV FS:__except_list,ESP * CALL _d_monitor_prolog */ code *c1 = NULL; code *c; code cs; Symbol *s; regm_t desregs; assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's if (shandle->Sclass == SCfastpar) { assert(shandle->Spreg != DX); assert(shandle->Spreg2 == NOREG); c = gen1(NULL,0x50 + shandle->Spreg); // PUSH shandle } else { // PUSH shandle #if 0 c = genc1(NULL,0xFF,modregrm(2,6,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); c->Isib = modregrm(0,4,SP); #else useregs(mCX); c = genc1(NULL,0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); c->Isib = modregrm(0,4,SP); gen1(c,0x50 + CX); // PUSH ECX #endif } s = getRtlsym(RTLSYM_MONITOR_HANDLER); c = gencs(c,0x68,0,FLextern,s); // PUSH offset _d_monitor_handler makeitextern(s); #if 0 cs.Iop = 0xFF; cs.Irm = modregrm(0,6,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; gen(c,&cs); // PUSH FS:__except_list #else useregs(mDX); cs.Iop = 0x8B; cs.Irm = modregrm(0,DX,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; c1 = gen(c1,&cs); // MOV EDX,FS:__except_list gen1(c,0x50 + DX); // PUSH EDX #endif s = getRtlsym(RTLSYM_MONITOR_PROLOG); desregs = ~s->Sregsaved & ALLREGS; c = cat(c,getregs(desregs)); c = gencs(c,0xE8,0,FLfunc,s); // CALL _d_monitor_prolog cs.Iop = 0x89; NEWREG(cs.Irm,SP); gen(c,&cs); // MOV FS:__except_list,ESP return cat(c1,c); }