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); }
type *TypeFunction::toCtype() { type *t; if (ctype) return ctype; if (1) { param_t *paramtypes = NULL; size_t nparams = Parameter::dim(parameters); for (size_t i = 0; i < nparams; i++) { Parameter *arg = Parameter::getNth(parameters, i); type *tp = arg->type->toCtype(); if (arg->storageClass & (STCout | STCref)) { // C doesn't have reference types, so it's really a pointer // to the parameter type tp = type_allocn(TYref, tp); } param_append_type(¶mtypes,tp); } tym_t tyf = totym(); t = type_alloc(tyf); t->Tflags |= TFprototype; if (varargs != 1) t->Tflags |= TFfixed; ctype = t; assert(next); // function return type should exist t->Tnext = next->toCtype(); t->Tnext->Tcount++; t->Tparamtypes = paramtypes; } ctype = t; return t; }
type *TypeFunction::toCtype() { if (!ctype) { size_t nparams = Parameter::dim(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(parameters, i); type *tp = arg->type->toCtype(); if (arg->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); ptypes[i] = tp; } type* tnext = next ? next->toCtype() : tsvoid; ctype = type_function(totym(), ptypes, nparams, varargs == 1, tnext); if (nparams > 10) free(ptypes); } return ctype; }
type *Type::toCtype() { if (!ctype) { ctype = type_fake(totym()); ctype->Tcount++; } return ctype; }
type *TypePointer::toCtype() { type *tn; type *t; //printf("TypePointer::toCtype() %s\n", toChars()); if (ctype) return ctype; if (1 || global.params.symdebug) { /* Need to always do this, otherwise C++ name mangling * goes awry. */ t = type_alloc(TYnptr); ctype = t; tn = next->toCtype(); t->Tnext = tn; tn->Tcount++; } else t = type_fake(totym()); t->Tcount++; ctype = t; return t; }
unsigned totym(Type *tx) { unsigned t; switch (tx->ty) { case Tvoid: t = TYvoid; break; case Tint8: t = TYschar; break; case Tuns8: t = TYuchar; break; case Tint16: t = TYshort; break; case Tuns16: t = TYushort; break; case Tint32: t = TYint; break; case Tuns32: t = TYuint; break; case Tint64: t = TYllong; break; case Tuns64: t = TYullong; break; case Tfloat32: t = TYfloat; break; case Tfloat64: t = TYdouble; break; case Tfloat80: t = TYldouble; break; case Timaginary32: t = TYifloat; break; case Timaginary64: t = TYidouble; break; case Timaginary80: t = TYildouble; break; case Tcomplex32: t = TYcfloat; break; case Tcomplex64: t = TYcdouble; break; case Tcomplex80: t = TYcldouble; break; case Tbool: t = TYbool; break; case Tchar: t = TYchar; break; case Twchar: t = TYwchar_t; break; #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS case Tdchar: t = TYdchar; break; #else case Tdchar: t = (global.params.symdebug == 1) ? TYdchar : TYulong; break; #endif case Taarray: t = TYaarray; break; case Tclass: case Treference: case Tpointer: t = TYnptr; break; case Tdelegate: t = TYdelegate; break; case Tarray: t = TYdarray; break; case Tsarray: t = TYstruct; break; case Tstruct: t = TYstruct; if (tx->toDsymbol(NULL)->ident == Id::__c_long_double) t = TYdouble; break; case Tenum: t = totym(tx->toBasetype()); break; case Tident: case Ttypeof: #ifdef DEBUG printf("ty = %d, '%s'\n", tx->ty, tx->toChars()); #endif error(Loc(), "forward reference of %s", tx->toChars()); t = TYint; break; case Tnull: t = TYnptr; break; case Tvector: { TypeVector *tv = (TypeVector *)tx; TypeBasic *tb = tv->elementType(); switch (tb->ty) { case Tvoid: case Tint8: t = TYschar16; break; case Tuns8: t = TYuchar16; break; case Tint16: t = TYshort8; break; case Tuns16: t = TYushort8; break; case Tint32: t = TYlong4; break; case Tuns32: t = TYulong4; break; case Tint64: t = TYllong2; break; case Tuns64: t = TYullong2; break; case Tfloat32: t = TYfloat4; break; case Tfloat64: t = TYdouble2; break; default: assert(0); break; } assert(global.params.is64bit || global.params.isOSX); break; } case Tfunction: { TypeFunction *tf = (TypeFunction *)tx; switch (tf->linkage) { case LINKwindows: if (global.params.is64bit) goto Lc; t = (tf->varargs == 1) ? TYnfunc : TYnsfunc; break; case LINKpascal: t = (tf->varargs == 1) ? TYnfunc : TYnpfunc; break; case LINKc: case LINKcpp: Lc: t = TYnfunc; #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS if (I32 && retStyle(tf) == RETstack) t = TYhfunc; #endif break; case LINKd: t = (tf->varargs == 1) ? TYnfunc : TYjfunc; break; default: printf("linkage = %d\n", tf->linkage); assert(0); } if (tf->isnothrow) t |= mTYnothrow; return t; } default: #ifdef DEBUG printf("ty = %d, '%s'\n", tx->ty, tx->toChars()); halt(); #endif assert(0); } // Add modifiers switch (tx->mod) { case 0: break; case MODconst: case MODwild: case MODwildconst: t |= mTYconst; break; case MODshared: t |= mTYshared; break; case MODshared | MODconst: case MODshared | MODwild: case MODshared | MODwildconst: t |= mTYshared | mTYconst; break; case MODimmutable: t |= mTYimmutable; break; default: assert(0); } return t; }
/************************************* * 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(TryCatchStatement *s) { Blockx *blx = irs->blx; #if SEH if (!global.params.is64bit) nteh_declarvars(blx); #endif IRState mystate(irs, s); block *tryblock = block_goto(blx,BCgoto,NULL); int previndex = blx->scope_index; tryblock->Blast_index = previndex; blx->scope_index = tryblock->Bscope_index = blx->next_index++; // Set the current scope index setScopeIndex(blx,tryblock,tryblock->Bscope_index); // This is the catch variable tryblock->jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr)); blx->tryblock = tryblock; block *breakblock = block_calloc(blx); block_goto(blx,BC_try,NULL); if (s->_body) { Statement_toIR(s->_body, &mystate); } blx->tryblock = tryblock->Btry; // break block goes here block_goto(blx, BCgoto, breakblock); setScopeIndex(blx,blx->curblock, previndex); blx->scope_index = previndex; // create new break block that follows all the catches breakblock = block_calloc(blx); blx->curblock->appendSucc(breakblock); block_next(blx,BCgoto,NULL); assert(s->catches); for (size_t i = 0 ; i < s->catches->dim; i++) { Catch *cs = (*s->catches)[i]; if (cs->var) cs->var->csym = tryblock->jcatchvar; block *bcatch = blx->curblock; if (cs->type) bcatch->Bcatchtype = toSymbol(cs->type->toBasetype()); tryblock->appendSucc(bcatch); block_goto(blx, BCjcatch, NULL); if (cs->handler != NULL) { IRState catchState(irs, s); /* Append to block: * *(sclosure + cs.offset) = cs; */ if (cs->var && cs->var->offset) { tym_t tym = totym(cs->var->type); elem *ex = el_var(irs->sclosure); ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs->var->offset)); ex = el_una(OPind, tym, ex); ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs->var))); block_appendexp(catchState.blx->curblock, ex); } Statement_toIR(cs->handler, &catchState); } blx->curblock->appendSucc(breakblock); block_next(blx, BCgoto, NULL); } block_next(blx,(enum BC)blx->curblock->BC, breakblock); }
void visit(Type *t) { t->ctype = type_fake(totym(t)); t->ctype->Tcount++; }