void visit(TypeFunction *t) { size_t nparams = Parameter::dim(t->parameters); type *tmp[10]; type **ptypes = tmp; if (nparams > 10) ptypes = (type **)malloc(sizeof(type*) * nparams); for (size_t i = 0; i < nparams; i++) { Parameter *p = Parameter::getNth(t->parameters, i); type *tp = Type_toCtype(p->type); if (p->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); else if (p->storageClass & STClazy) { // Mangle as delegate type *tf = type_function(TYnfunc, NULL, 0, false, tp); tp = type_delegate(tf); } ptypes[i] = tp; } t->ctype = type_function(totym(t), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next)); if (nparams > 10) free(ptypes); }
void visit(TypeEnum *t) { //printf("TypeEnum::toCtype() '%s'\n", t->sym->toChars()); Type *tm = t->mutableOf(); if (tm->ctype && tybasic(tm->ctype->Tty) == TYenum) { Symbol *s = tm->ctype->Ttag; assert(s); t->ctype = type_alloc(TYenum); t->ctype->Ttag = (Classsym *)s; // enum tag name t->ctype->Tcount++; t->ctype->Tnext = tm->ctype->Tnext; t->ctype->Tnext->Tcount++; // 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 if (!t->sym->memtype) { // Bugzilla 13792 t->ctype = Type_toCtype(Type::tvoid); } else if (t->sym->memtype->toBasetype()->ty == Tint32) { t->ctype = type_enum(t->sym->toPrettyChars(true), Type_toCtype(t->sym->memtype)); tm->ctype = t->ctype; } else { t->ctype = Type_toCtype(t->sym->memtype); } //printf("t = %p, Tflags = x%x\n", t, t->Tflags); }
void visit(TypeFunction *t) { size_t nparams = Parameter::dim(t->parameters); type *tmp[10]; type **ptypes = tmp; if (nparams > 10) ptypes = (type **)malloc(sizeof(type*) * nparams); for (size_t i = 0; i < nparams; i++) { Parameter *arg = Parameter::getNth(t->parameters, i); type *tp = Type_toCtype(arg->type); if (arg->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); ptypes[i] = tp; } t->ctype = type_function(t->totym(), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next)); if (nparams > 10) free(ptypes); }
Symbol *aaGetSymbol(TypeAArray *taa, const char *func, int flags) { #ifdef DEBUG assert((flags & ~1) == 0); #endif // Dumb linear symbol table - should use associative array! static Symbols *sarray = NULL; //printf("aaGetSymbol(func = '%s', flags = %d, key = %p)\n", func, flags, key); char *id = (char *)alloca(3 + strlen(func) + 1); sprintf(id, "_aa%s", func); if (!sarray) sarray = Symbols_create(); // See if symbol is already in sarray for (size_t i = 0; i < sarray->dim; i++) { Symbol *s = (*sarray)[i]; if (strcmp(id, s->Sident) == 0) { #ifdef DEBUG assert(s); #endif return s; // use existing Symbol } } // Create new Symbol Symbol *s = symbol_calloc(id); slist_add(s); s->Sclass = SCextern; s->Ssymnum = -1; symbol_func(s); type *t = type_function(TYnfunc, NULL, 0, false, Type_toCtype(taa->next)); t->Tmangle = mTYman_c; s->Stype = t; sarray->push(s); // remember it return s; }
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); } } }
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 (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; } FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fd->isNested()) { if (fdp && fdp->semanticRun < PASSobj) { if (fdp->semantic3Errors) return; /* Can't do unittest's out of order, they are order dependent in that their * execution is done in lexical order. */ if (UnitTestDeclaration *udp = fdp->isUnitTestDeclaration()) { udp->deferredNested.push(fd); 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; } #if TARGET_WINDOS /* 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; #endif #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->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. */ 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 TARGET_WINDOS if (global.params.mscoff) { objmod->external_def("main"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("_main"); objmod->external_def("__acrtused_con"); } #endif objmod->includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && fd->linkage == LINKc) { #if TARGET_WINDOS if (global.params.mscoff) { objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); } else { objmod->external_def("__acrtused_con"); // bring in C startup code objmod->includelib("snn.lib"); // bring in C runtime library } #endif 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; 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; /* 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); } buildClosure(fd, &irs); #if TARGET_WINDOS if (fd->isSynchronized() && cd && config.flags2 & CFG2seh && !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; } #endif 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)); } } } } // 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); } }
void visit(VarDeclaration *vd) { //printf("VarDeclaration::cvMember(p = %p) '%s'\n", p, vd->toChars()); if (vd->type->toBasetype()->ty == Ttuple) return; char *id = vd->toChars(); if (!p) { if (vd->isField()) { if (config.fulltypes == CV8) result += 2; result += 6 + cv_stringbytes(id); result += cv4_numericbytes(vd->offset); } else if (vd->isStatic()) { if (config.fulltypes == CV8) result += 2; result += 6 + cv_stringbytes(id); } result = cv_align(NULL, result); } else { idx_t typidx = cv_typidx(Type_toCtype(vd->type)); unsigned attribute = PROTtoATTR(vd->prot()); assert((attribute & ~3) == 0); switch (config.fulltypes) { case CV8: if (vd->isField()) { TOWORD(p,LF_MEMBER_V3); TOWORD(p + 2,attribute); TOLONG(p + 4,typidx); cv4_storenumeric(p + 8, vd->offset); result = 8 + cv4_numericbytes(vd->offset); result += cv_namestring(p + result, id); } else if (vd->isStatic()) { TOWORD(p,LF_STMEMBER_V3); TOWORD(p + 2,attribute); TOLONG(p + 4,typidx); result = 8; result += cv_namestring(p + result, id); } break; case CV4: if (vd->isField()) { TOWORD(p,LF_MEMBER); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); cv4_storenumeric(p + 6, vd->offset); result = 6 + cv4_numericbytes(vd->offset); result += cv_namestring(p + result, id); } else if (vd->isStatic()) { TOWORD(p,LF_STMEMBER); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); result = 6; result += cv_namestring(p + result, id); } break; default: assert(0); } result = cv_align(p + result, result); #ifdef DEBUG int save = result; result = 0; p = NULL; visit(vd); assert(result == save); #endif } }
unsigned cv4_memfunctypidx(FuncDeclaration *fd) { //printf("cv4_memfunctypidx(fd = '%s')\n", fd->toChars()); type *t = Type_toCtype(fd->type); AggregateDeclaration *ad = fd->isMember2(); if (ad) { // It's a member function, which gets a special type record idx_t thisidx; if (fd->isStatic()) thisidx = dttab4[TYvoid]; else { assert(ad->handleType()); thisidx = cv4_typidx(Type_toCtype(ad->handleType())); } unsigned nparam; idx_t paramidx = cv4_arglist(t,&nparam); unsigned char call = cv4_callconv(t); debtyp_t *d; switch (config.fulltypes) { case CV4: { d = debtyp_alloc(18); unsigned char *p = d->data; TOWORD(p,LF_MFUNCTION); TOWORD(p + 2,cv4_typidx(t->Tnext)); TOWORD(p + 4,cv4_typidx(Type_toCtype(ad->type))); TOWORD(p + 6,thisidx); p[8] = call; p[9] = 0; // reserved TOWORD(p + 10,nparam); TOWORD(p + 12,paramidx); TOLONG(p + 14,0); // thisadjust break; } case CV8: { d = debtyp_alloc(26); unsigned char *p = d->data; TOWORD(p,0x1009); TOLONG(p + 2,cv4_typidx(t->Tnext)); TOLONG(p + 6,cv4_typidx(Type_toCtype(ad->type))); TOLONG(p + 10,thisidx); p[14] = call; p[15] = 0; // reserved TOWORD(p + 16,nparam); TOLONG(p + 18,paramidx); TOLONG(p + 22,0); // thisadjust break; } default: assert(0); } return cv_debtyp(d); } return cv4_typidx(t); }
void toDebug(ClassDeclaration *cd) { idx_t typidx = 0; //printf("ClassDeclaration::toDebug('%s')\n", cd->toChars()); assert(config.fulltypes >= CV4); if (cd->isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference targ_size_t size; unsigned property = 0; if (!cd->members) { size = 0; property |= 0x80; // forward reference } else size = cd->structsize; if (cd->parent->isAggregateDeclaration()) // if class is nested property |= 8; if (cd->ctor || cd->dtors.dim) property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment const char *id = cd->isCPPinterface() ? cd->ident->toChars() : cd->toPrettyChars(true); unsigned leaf = config.fulltypes == CV8 ? LF_CLASS_V3 : LF_CLASS; unsigned numidx = (leaf == LF_CLASS_V3) ? 18 : 12; unsigned len = numidx + cv4_numericbytes(size); debtyp_t *d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); idx_t vshapeidx = 0; if (1) { size_t n = cd->vtbl.dim; // number of virtual functions if (n) { // 4 bits per descriptor debtyp_t *vshape = debtyp_alloc(4 + (n + 1) / 2); TOWORD(vshape->data,LF_VTSHAPE); TOWORD(vshape->data + 2,n); n = 0; unsigned char descriptor = 0; for (size_t i = 0; i < cd->vtbl.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)cd->vtbl[i]; //if (intsize == 4) descriptor |= 5; vshape->data[4 + n / 2] = descriptor; descriptor <<= 4; n++; } vshapeidx = cv_debtyp(vshape); } } if (leaf == LF_CLASS) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,vshapeidx); } else if (leaf == LF_CLASS_V3) { TOLONG(d->data + 10,0); // dList TOLONG(d->data + 14,vshapeidx); } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. unsigned length_save = d->length; d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = length_save; // restore length if (!cd->members) // if reference only { if (leaf == LF_CLASS_V3) { TOWORD(d->data + 2,0); // count: number of fields is 0 TOLONG(d->data + 6,0); // field list is 0 TOWORD(d->data + 4,property); } else { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); } return /*typidx*/; } // Compute the number of fields (nfields), and the length of the fieldlist record (fnamelen) CvMemberCount mc; mc.nfields = 0; mc.fnamelen = 2; /* Adding in the base classes causes VS 2010 debugger to refuse to display any * of the fields. I have not been able to determine why. * (Could it be because the base class is "forward referenced"?) * It does work with VS 2012. */ bool addInBaseClasses = true; if (addInBaseClasses) { // Add in base classes for (size_t i = 0; i < cd->baseclasses->dim; i++) { BaseClass *bc = (*cd->baseclasses)[i]; mc.nfields++; unsigned elementlen = 4 + cgcv.sz_idx + cv4_numericbytes(bc->offset); elementlen = cv_align(NULL, elementlen); mc.fnamelen += elementlen; } } for (size_t i = 0; i < cd->members->dim; i++) { Dsymbol *s = (*cd->members)[i]; s->apply(&cv_mem_count, &mc); } if (config.fulltypes != CV8 && mc.fnamelen > CV4_NAMELENMAX) { // Too long, fail gracefully mc.nfields = 0; mc.fnamelen = 2; } unsigned nfields = mc.nfields; unsigned fnamelen = mc.fnamelen; int count = nfields; TOWORD(d->data + 2,count); // Generate fieldlist type record debtyp_t *dt = debtyp_alloc(fnamelen); unsigned char *p = dt->data; // And fill it in TOWORD(p,config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); p += 2; if (nfields) // if we didn't overflow { if (addInBaseClasses) { // Add in base classes for (size_t i = 0; i < cd->baseclasses->dim; i++) { BaseClass *bc = (*cd->baseclasses)[i]; idx_t typidx = cv4_typidx(Type_toCtype(bc->sym->type)->Tnext); unsigned attribute = PROTtoATTR(bc->protection); unsigned elementlen; switch (config.fulltypes) { case CV8: TOWORD(p, LF_BCLASS_V2); TOWORD(p + 2,attribute); TOLONG(p + 4,typidx); elementlen = 8; break; case CV4: TOWORD(p, LF_BCLASS); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); elementlen = 6; break; } cv4_storenumeric(p + elementlen, bc->offset); elementlen += cv4_numericbytes(bc->offset); elementlen = cv_align(p + elementlen, elementlen); p += elementlen; } } for (size_t i = 0; i < cd->members->dim; i++) { Dsymbol *s = (*cd->members)[i]; s->apply(&cv_mem_p, &p); } } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); idx_t fieldlist = cv_debtyp(dt); TOWORD(d->data + 2,count); if (config.fulltypes == CV8) { TOWORD(d->data + 4,property); TOLONG(d->data + 6,fieldlist); } else { TOWORD(d->data + 4,fieldlist); TOWORD(d->data + 6,property); } // cv4_outsym(s); if (config.fulltypes == CV8) cv8_udt(id, typidx); else { size_t idlen = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + idlen); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); unsigned length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + idlen); objmod->write_bytes(SegData[DEBSYM],length,debsym); } // return typidx; }
unsigned cv4_Denum(EnumDeclaration *e) { //dbg_printf("cv4_Denum(%s)\n", e->toChars()); unsigned property = 0; if (!e->members || !e->memtype || !e->memtype->isintegral()) property |= 0x80; // enum is forward referenced or non-integer // Compute the number of fields, and the length of the fieldlist record unsigned nfields = 0; unsigned fnamelen = 2; if (!property) { for (size_t i = 0; i < e->members->dim; i++) { EnumMember *sf = (*e->members)[i]->isEnumMember(); if (sf) { dinteger_t value = sf->value->toInteger(); unsigned fnamelen1 = fnamelen; // store only member's simple name fnamelen += 4 + cv4_numericbytes(value) + cv_stringbytes(sf->toChars()); if (config.fulltypes != CV8) { /* Optlink dies on longer ones, so just truncate */ if (fnamelen > CV4_NAMELENMAX) { fnamelen = fnamelen1; // back up break; // and skip the rest } } nfields++; } } } const char *id = e->toPrettyChars(); unsigned len; debtyp_t *d; unsigned memtype = e->memtype ? cv4_typidx(Type_toCtype(e->memtype)) : 0; switch (config.fulltypes) { case CV8: len = 14; d = debtyp_alloc(len + cv_stringbytes(id)); TOWORD(d->data,LF_ENUM_V3); TOLONG(d->data + 6,memtype); TOWORD(d->data + 4,property); len += cv_namestring(d->data + len,id); break; case CV4: len = 10; d = debtyp_alloc(len + cv_stringbytes(id)); TOWORD(d->data,LF_ENUM); TOWORD(d->data + 4,memtype); TOWORD(d->data + 8,property); len += cv_namestring(d->data + len,id); break; default: assert(0); } unsigned length_save = d->length; d->length = 0; // so cv_debtyp() will allocate new idx_t typidx = cv_debtyp(d); d->length = length_save; // restore length TOWORD(d->data + 2,nfields); unsigned fieldlist = 0; if (!property) // if forward reference, then fieldlist is 0 { // Generate fieldlist type record debtyp_t *dt = debtyp_alloc(fnamelen); TOWORD(dt->data,(config.fulltypes == CV8) ? LF_FIELDLIST_V2 : LF_FIELDLIST); // And fill it in unsigned j = 2; unsigned fieldi = 0; for (size_t i = 0; i < e->members->dim; i++) { EnumMember *sf = (*e->members)[i]->isEnumMember(); if (sf) { fieldi++; if (fieldi > nfields) break; // chop off the rest dinteger_t value = sf->value->toInteger(); TOWORD(dt->data + j,(config.fulltypes == CV8) ? LF_ENUMERATE_V3 : LF_ENUMERATE); unsigned attribute = 0; TOWORD(dt->data + j + 2,attribute); cv4_storenumeric(dt->data + j + 4,value); j += 4 + cv4_numericbytes(value); // store only member's simple name j += cv_namestring(dt->data + j, sf->toChars()); // If enum is not a member of a class, output enum members as constants // if (!isclassmember(s)) // { // cv4_outsym(sf); // } } } assert(j == fnamelen); fieldlist = cv_debtyp(dt); } if (config.fulltypes == CV8) TOLONG(d->data + 10,fieldlist); else TOWORD(d->data + 6,fieldlist); // cv4_outsym(s); return typidx; }
void visit(FuncDeclaration *fd) { if (!fd->csym) { const char *id = mangleExact(fd); //printf("FuncDeclaration::toSymbol(%s %s)\n", fd->kind(), fd->toChars()); //printf("\tid = '%s'\n", id); //printf("\ttype = %s\n", fd->type->toChars()); Symbol *s = symbol_calloc(id); slist_add(s); s->prettyIdent = fd->toPrettyChars(); s->Sclass = SCglobal; symbol_func(s); func_t *f = s->Sfunc; if (fd->isVirtual() && fd->vtblIndex != -1) f->Fflags |= Fvirtual; else if (fd->isMember2() && fd->isStatic()) f->Fflags |= Fstatic; f->Fstartline.Slinnum = fd->loc.linnum; f->Fstartline.Scharnum = fd->loc.charnum; f->Fstartline.Sfilename = (char *)fd->loc.filename; if (fd->endloc.linnum) { f->Fendline.Slinnum = fd->endloc.linnum; f->Fendline.Scharnum = fd->endloc.charnum; f->Fendline.Sfilename = (char *)fd->endloc.filename; } else { f->Fendline.Slinnum = fd->loc.linnum; f->Fendline.Scharnum = fd->loc.charnum; f->Fendline.Sfilename = (char *)fd->loc.filename; } TYPE *t = Type_toCtype(fd->type); mangle_t msave = t->Tmangle; if (fd->isMain()) { t->Tty = TYnfunc; t->Tmangle = mTYman_c; } else { switch (fd->linkage) { case LINKwindows: t->Tmangle = mTYman_std; break; case LINKpascal: t->Tty = TYnpfunc; t->Tmangle = mTYman_pas; break; case LINKc: t->Tmangle = mTYman_c; break; case LINKd: t->Tmangle = mTYman_d; break; case LINKcpp: s->Sflags |= SFLpublic; if (fd->isThis() && !global.params.is64bit && global.params.isWindows) { if (((TypeFunction *)fd->type)->varargs == 1) { t->Tty = TYnfunc; } else { t->Tty = TYmfunc; } } t->Tmangle = mTYman_d; break; default: printf("linkage = %d\n", fd->linkage); assert(0); } } if (msave) assert(msave == t->Tmangle); //printf("Tty = %x, mangle = x%x\n", t->Tty, t->Tmangle); t->Tcount++; s->Stype = t; //s->Sfielddef = this; fd->csym = s; } result = fd->csym; }
void visit(VarDeclaration *vd) { //printf("VarDeclaration::toSymbol(%s)\n", vd->toChars()); assert(!vd->needThis()); if (!vd->csym) { const char *id; if (vd->isDataseg()) id = mangle(vd); else id = vd->ident->toChars(); Symbol *s = symbol_calloc(id); s->Salignment = vd->alignment; if (vd->storage_class & STCtemp) s->Sflags |= SFLartifical; TYPE *t; if (vd->storage_class & (STCout | STCref)) { // should be TYref, but problems in back end t = type_pointer(Type_toCtype(vd->type)); } else if (vd->storage_class & STClazy) { if (config.exe == EX_WIN64 && vd->isParameter()) t = type_fake(TYnptr); else t = type_fake(TYdelegate); // Tdelegate as C type t->Tcount++; } else if (vd->isParameter()) { if (config.exe == EX_WIN64 && vd->type->size(Loc()) > REGSIZE) { // should be TYref, but problems in back end t = type_pointer(Type_toCtype(vd->type)); } else { t = Type_toCtype(vd->type); t->Tcount++; } } else { t = Type_toCtype(vd->type); t->Tcount++; } if (vd->isDataseg()) { if (vd->isThreadlocal()) { /* Thread local storage */ TYPE *ts = t; ts->Tcount++; // make sure a different t is allocated type_setty(&t, t->Tty | mTYthread); ts->Tcount--; if (global.params.vtls) { char *p = vd->loc.toChars(); fprintf(global.stdmsg, "%s: %s is thread local\n", p ? p : "", vd->toChars()); if (p) mem.free(p); } } s->Sclass = SCextern; s->Sfl = FLextern; slist_add(s); /* if it's global or static, then it needs to have a qualified but unmangled name. * This gives some explanation of the separation in treating name mangling. * It applies to PDB format, but should apply to CV as PDB derives from CV. * http://msdn.microsoft.com/en-us/library/ff553493(VS.85).aspx */ s->prettyIdent = vd->toPrettyChars(); } else { s->Sclass = SCauto; s->Sfl = FLauto; if (vd->nestedrefs.dim) { /* Symbol is accessed by a nested function. Make sure * it is not put in a register, and that the optimizer * assumes it is modified across function calls and pointer * dereferences. */ //printf("\tnested ref, not register\n"); type_setcv(&t, t->Tty | mTYvolatile); } } if (vd->ident == Id::va_argsave) { /* __va_argsave is set outside of the realm of the optimizer, * so we tell the optimizer to leave it alone */ type_setcv(&t, t->Tty | mTYvolatile); } mangle_t m = 0; switch (vd->linkage) { case LINKwindows: m = mTYman_std; break; case LINKpascal: m = mTYman_pas; break; case LINKc: m = mTYman_c; break; case LINKd: m = mTYman_d; break; case LINKcpp: s->Sflags |= SFLpublic; m = mTYman_d; break; default: printf("linkage = %d\n", vd->linkage); assert(0); } type_setmangle(&t, m); s->Stype = t; vd->csym = s; } result = vd->csym; }
/************************************* * 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(ReturnStatement *s) { Blockx *blx = irs->blx; enum BC bc; incUsage(irs, s->loc); if (s->exp) { elem *e; FuncDeclaration *func = irs->getFunc(); assert(func); assert(func->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)(func->type); RET retmethod = retStyle(tf); if (retmethod == RETstack) { elem *es; /* If returning struct literal, write result * directly into return value */ if (s->exp->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)s->exp; char save[sizeof(StructLiteralExp)]; memcpy(save, (void*)se, sizeof(StructLiteralExp)); se->sym = irs->shidden; se->soffset = 0; se->fillHoles = 1; e = toElemDtor(s->exp, irs); memcpy((void*)se, save, sizeof(StructLiteralExp)); } else e = toElemDtor(s->exp, irs); assert(e); if (s->exp->op == TOKstructliteral || (func->nrvo_can && func->nrvo_var)) { // Return value via hidden pointer passed as parameter // Write exp; return shidden; es = e; } else { // Return value via hidden pointer passed as parameter // Write *shidden=exp; return shidden; int op; tym_t ety; ety = e->Ety; es = el_una(OPind,ety,el_var(irs->shidden)); op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq; es = el_bin(op, ety, es, e); if (op == OPstreq) es->ET = Type_toCtype(s->exp->type); } e = el_var(irs->shidden); e = el_bin(OPcomma, e->Ety, es, e); } else if (tf->isref) { // Reference return, so convert to a pointer e = toElemDtor(s->exp, irs); e = addressElem(e, s->exp->type->pointerTo()); } else { e = toElemDtor(s->exp, irs); assert(e); } elem_setLoc(e, s->loc); block_appendexp(blx->curblock, e); bc = BCretexp; } else bc = BCret; if (block *finallyBlock = irs->getFinallyBlock()) { assert(finallyBlock->BC == BC_finally); blx->curblock->appendSucc(finallyBlock); } block_next(blx, bc, NULL); }