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; }
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; }