#include "limbo.h" static long stubalign(long offset, int a, char** b, char *e); static void pickadtstub(Type *t); void emit(Decl *globals) { Decl *m, *d, *id; for(m = globals; m != nil; m = m->next){ if(m->store != Dtype || m->ty->kind != Tmodule) continue; m->ty = usetype(m->ty); for(d = m->ty->ids; d != nil; d = d->next){ d->ty = usetype(d->ty); if(d->store == Dglobal || d->store == Dfn) modrefable(d->ty); if(d->store == Dtype && d->ty->kind == Tadt){ for(id = d->ty->ids; id != nil; id = id->next){ id->ty = usetype(id->ty); modrefable(d->ty); } } } } if(emitstub){ adtstub(globals); modstub(globals); } if(emittab != nil) modtab(globals); if(emitcode) modcode(globals); } static char* lowercase(char *f) { char *s = f; for( ; *s != 0; s++) if(*s >= 'A' && *s <= 'Z') *s += 'a' - 'A'; return f; } void modcode(Decl *globals) { Decl *d, *id; char buf[32]; if(emitdyn){ strcpy(buf, emitcode); lowercase(buf); print("#include \"%s.h\"\n", buf); } else{ print("#include \n"); print("#include \n"); print("#include \n"); print("#include \"%smod.h\"\n", emitcode); } print("\n"); for(d = globals; d != nil; d = d->next) if(d->store == Dtype && d->ty->kind == Tmodule && strcmp(d->sym->name, emitcode) == 0) break; if(d == nil) return; /* * stub types */ for(id = d->ty->ids; id != nil; id = id->next){ if(id->store == Dtype && id->ty->kind == Tadt){ id->ty = usetype(id->ty); print("Type*\tT_%s;\n", id->sym->name); } } /* * type maps */ if(emitdyn){ for(id = d->ty->ids; id != nil; id = id->next) if(id->store == Dtype && id->ty->kind == Tadt) print("uchar %s_map[] = %s_%s_map;\n", id->sym->name, emitcode, id->sym->name); } /* * heap allocation and garbage collection for a type */ if(emitdyn){ for(id = d->ty->ids; id != nil; id = id->next) if(id->store == Dtype && id->ty->kind == Tadt){ print("\n%s_%s*\n%salloc%s(void)\n{\n\tHeap *h;\n\n\th = heap(T_%s);\n\treturn H2D(%s_%s*, h);\n}\n", emitcode, id->sym->name, emitcode, id->sym->name, id->sym->name, emitcode, id->sym->name); print("\nvoid\n%sfree%s(Heap *h, int swept)\n{\n\t%s_%s *d;\n\n\td = H2D(%s_%s*, h);\n\tfreeheap(h, swept);\n}\n", emitcode, id->sym->name, emitcode, id->sym->name, emitcode, id->sym->name); } } /* * initialization function */ if(emitdyn) print("\nvoid\n%sinit(void)\n{\n", emitcode); else{ print("\nvoid\n%smodinit(void)\n{\n", emitcode); print("\tbuiltinmod(\"$%s\", %smodtab, %smodlen);\n", emitcode, emitcode, emitcode); } for(id = d->ty->ids; id != nil; id = id->next){ if(id->store == Dtype && id->ty->kind == Tadt){ if(emitdyn) print("\tT_%s = dtype(%sfree%s, %s_%s_size, %s_map, sizeof(%s_map));\n", id->sym->name, emitcode, id->sym->name, emitcode, id->sym->name, id->sym->name, id->sym->name); else print("\tT_%s = dtype(freeheap, sizeof(%s), %smap, sizeof(%smap));\n", id->sym->name, id->sym->name, id->sym->name, id->sym->name); } } print("}\n"); /* * end function */ if(emitdyn){ print("\nvoid\n%send(void)\n{\n", emitcode); for(id = d->ty->ids; id != nil; id = id->next) if(id->store == Dtype && id->ty->kind == Tadt) print("\tfreetype(T_%s);\n", id->sym->name); print("}\n"); } /* * stub functions */ for(id = d->ty->tof->ids; id != nil; id = id->next){ print("\nvoid\n%s_%s(void *fp)\n{\n\tF_%s_%s *f = fp;\n", id->dot->sym->name, id->sym->name, id->dot->sym->name, id->sym->name); if(id->ty->tof != tnone && tattr[id->ty->tof->kind].isptr){ print("\tvoid *r;\n"); print("\n\tr = *f->ret;\n\t*f->ret = H;\n\tdestroy(r);\n"); } print("}\n"); } if(emitdyn) print("\n#include \"%smod.h\"\n", buf); } void modtab(Decl *globals) { int n; Desc *md; Decl *d, *id; print("typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;\n"); for(d = globals; d != nil; d = d->next){ if(d->store == Dtype && d->ty->kind == Tmodule && strcmp(d->sym->name, emittab) == 0){ n = 0; print("Runtab %smodtab[]={\n", d->sym->name); for(id = d->ty->tof->ids; id != nil; id = id->next){ n++; print("\t\""); if(id->dot != d) print("%s.", id->dot->sym->name); print("%s\",0x%ux,%s_%s,", id->sym->name, sign(id), id->dot->sym->name, id->sym->name); if(id->ty->varargs) print("0,0,{0},"); else{ md = mkdesc(idoffsets(id->ty->ids, MaxTemp, MaxAlign), id->ty->ids); print("%ld,%ld,%M,", md->size, md->nmap, md); } print("\n"); } print("\t0\n};\n"); print("#define %smodlen %d\n", d->sym->name, n); } } } /* * produce activation records for all the functions in modules */ void modstub(Decl *globals) { Type *t; Decl *d, *id, *m; char buf[StrSize*2], *p; long offset; int arg; for(d = globals; d != nil; d = d->next){ if(d->store != Dtype || d->ty->kind != Tmodule) continue; arg = 0; for(id = d->ty->tof->ids; id != nil; id = id->next){ if(emitdyn && id->dot->dot != nil) seprint(buf, buf+sizeof(buf), "%s_%s_%s", id->dot->dot->sym->name, id->dot->sym->name, id->sym->name); else seprint(buf, buf+sizeof(buf), "%s_%s", id->dot->sym->name, id->sym->name); print("void %s(void*);\ntypedef struct F_%s F_%s;\nstruct F_%s\n{\n", buf, buf, buf, buf); print(" WORD regs[NREG-1];\n"); if(id->ty->tof != tnone) print(" %R* ret;\n", id->ty->tof); else print(" WORD noret;\n"); print(" uchar temps[%d];\n", MaxTemp-NREG*IBY2WD); offset = MaxTemp; for(m = id->ty->ids; m != nil; m = m->next){ if(m->sym != nil) p = m->sym->name; else{ seprint(buf, buf+sizeof(buf), "arg%d", arg); p = buf; } /* * explicit pads for structure alignment */ t = m->ty; offset = stubalign(offset, t->align, nil, nil); if(offset != m->offset) yyerror("module stub must not contain data objects"); // fatal("modstub bad offset"); print(" %R %s;\n", t, p); arg++; offset += t->size; } if(id->ty->varargs) print(" WORD vargs;\n"); print("};\n"); } for(id = d->ty->ids; id != nil; id = id->next) if(id->store == Dconst) constub(id); } } static void chanstub(char *in, Decl *id) { Desc *desc; print("typedef %R %s_%s;\n", id->ty->tof, in, id->sym->name); desc = mktdesc(id->ty->tof); print("#define %s_%s_size %ld\n", in, id->sym->name, desc->size); print("#define %s_%s_map %M\n", in, id->sym->name, desc); } /* * produce c structs for all adts */ void adtstub(Decl *globals) { Type *t, *tt; Desc *desc; Decl *m, *d, *id; char buf[2*StrSize]; long offset; for(m = globals; m != nil; m = m->next){ if(m->store != Dtype || m->ty->kind != Tmodule) continue; for(d = m->ty->ids; d != nil; d = d->next){ if(d->store != Dtype) continue; t = usetype(d->ty); d->ty = t; dotprint(buf, buf+sizeof(buf), d->ty->decl, '_'); switch(d->ty->kind){ case Tadt: print("typedef struct %s %s;\n", buf, buf); break; case Tint: case Tbyte: case Treal: case Tbig: case Tfix: print("typedef %T %s;\n", t, buf); break; } } } for(m = globals; m != nil; m = m->next){ if(m->store != Dtype || m->ty->kind != Tmodule) continue; for(d = m->ty->ids; d != nil; d = d->next){ if(d->store != Dtype) continue; t = d->ty; if(t->kind == Tadt || t->kind == Ttuple && t->decl->sym != anontupsym){ if(t->tags != nil){ pickadtstub(t); continue; } dotprint(buf, buf+sizeof(buf), t->decl, '_'); print("struct %s\n{\n", buf); offset = 0; for(id = t->ids; id != nil; id = id->next){ if(id->store == Dfield){ tt = id->ty; offset = stubalign(offset, tt->align, nil, nil); if(offset != id->offset) fatal("adtstub bad offset"); print(" %R %s;\n", tt, id->sym->name); offset += tt->size; } } if(t->ids == nil){ print(" char dummy[1];\n"); offset = 1; } offset = stubalign(offset, t->align, nil ,nil); offset = stubalign(offset, IBY2WD, nil , nil); if(offset != t->size && t->ids != nil) fatal("adtstub: bad size"); print("};\n"); for(id = t->ids; id != nil; id = id->next) if(id->store == Dconst) constub(id); for(id = t->ids; id != nil; id = id->next) if(id->ty->kind == Tchan) chanstub(buf, id); desc = mktdesc(t); if(offset != desc->size && t->ids != nil) fatal("adtstub: bad desc size"); print("#define %s_size %ld\n", buf, offset); print("#define %s_map %M\n", buf, desc); if(0) print("struct %s_check {int s[2*(sizeof(%s)==%s_size)-1];};\n", buf, buf, buf); }else if(t->kind == Tchan) chanstub(m->sym->name, d); } } } /* * emit an expicit pad field for aligning emitted c structs * according to limbo's definition */ static long stubalign(long offset, int a, char **buf, char *end) { long x; x = offset & (a-1); if(x == 0) return offset; x = a - x; if(buf == nil) print("\tuchar\t_pad%ld[%ld];\n", offset, x); else *buf = seprint(*buf, end, "uchar\t_pad%ld[%ld]; ", offset, x); offset += x; if((offset & (a-1)) || x >= a) fatal("compiler stub misalign"); return offset; } void constub(Decl *id) { char buf[StrSize*2]; seprint(buf, buf+sizeof(buf), "%s_%s", id->dot->sym->name, id->sym->name); switch(id->ty->kind){ case Tbyte: print("#define %s %d\n", buf, (int)id->init->val & 0xff); break; case Tint: case Tfix: print("#define %s %ld\n", buf, (long)id->init->val); break; case Tbig: print("#define %s %ld\n", buf, (long)id->init->val); break; case Treal: print("#define %s %g\n", buf, id->init->rval); break; case Tstring: print("#define %s \"%s\"\n", buf, id->init->decl->sym->name); break; } } int mapconv(Fmt *f) { Desc *d; char *s, *e, buf[1024]; int i; d = va_arg(f->args, Desc*); e = buf+sizeof(buf); s = buf; s = secpy(s, e, "{"); for(i = 0; i < d->nmap; i++) s = seprint(s, e, "0x%x,", d->map[i]); if(i == 0) s = seprint(s, e, "0"); seprint(s, e, "}"); return fmtstrcpy(f, buf); } char* dotprint(char *buf, char *end, Decl *d, int dot) { if(d->dot != nil){ buf = dotprint(buf, end, d->dot, dot); if(buf < end) *buf++ = dot; } if(d->sym == nil) return buf; return seprint(buf, end, "%s", d->sym->name); } char *ckindname[Tend] = { /* Tnone */ "void", /* Tadt */ "struct", /* Tadtpick */ "?adtpick?", /* Tarray */ "Array*", /* Tbig */ "LONG", /* Tbyte */ "BYTE", /* Tchan */ "Channel*", /* Treal */ "REAL", /* Tfn */ "?fn?", /* Tint */ "WORD", /* Tlist */ "List*", /* Tmodule */ "Modlink*", /* Tref */ "?ref?", /* Tstring */ "String*", /* Ttuple */ "?tuple?", /* Texception */ "?exception", /* Tfix */ "WORD", /* Tpoly */ "void*", /* Tainit */ "?ainit?", /* Talt */ "?alt?", /* Tany */ "void*", /* Tarrow */ "?arrow?", /* Tcase */ "?case?", /* Tcasel */ "?casel", /* Tcasec */ "?casec?", /* Tdot */ "?dot?", /* Terror */ "?error?", /* Tgoto */ "?goto?", /* Tid */ "?id?", /* Tiface */ "?iface?", /* Texcept */ "?except?", /* Tinst */ "?inst?", }; char* ctprint(char *buf, char *end, Type *t) { Decl *id; Type *tt; long offset; if(t == nil) return secpy(buf, end, "void"); switch(t->kind){ case Tref: return seprint(buf, end, "%R*", t->tof); case Tarray: case Tlist: case Tint: case Tbig: case Tstring: case Treal: case Tbyte: case Tnone: case Tany: case Tchan: case Tmodule: case Tfix: case Tpoly: return seprint(buf, end, "%s", ckindname[t->kind]); case Tadtpick: return ctprint(buf, end, t->decl->dot->ty); case Tadt: case Ttuple: if(t->decl->sym != anontupsym) return dotprint(buf, end, t->decl, '_'); offset = 0; buf = secpy(buf, end, "struct{ "); for(id = t->ids; id != nil; id = id->next){ tt = id->ty; offset = stubalign(offset, tt->align, &buf, end); if(offset != id->offset) fatal("ctypeconv tuple bad offset"); buf = seprint(buf, end, "%R %s; ", tt, id->sym->name); offset += tt->size; } offset = stubalign(offset, t->align, &buf, end); if(offset != t->size) fatal("ctypeconv tuple bad t=%T size=%ld offset=%ld", t, t->size, offset); return secpy(buf, end, "}"); default: if(t->kind >= Tend) yyerror("no C equivalent for type %d", t->kind); else yyerror("no C equivalent for type %s", kindname[t->kind]); break; } return buf; } static void pickadtstub(Type *t) { Type *tt; Desc *desc; Decl *id, *tg; char buf[2*StrSize]; int ok; long offset, tgoffset; dotprint(buf, buf+sizeof(buf), t->decl, '_'); offset = 0; for(tg = t->tags; tg != nil; tg = tg->next) print("#define %s_%s %ld\n", buf, tg->sym->name, offset++); print("struct %s\n{\n", buf); print(" WORD pick;\n"); offset = IBY2WD; for(id = t->ids; id != nil; id = id->next){ if(id->store == Dfield){ tt = id->ty; offset = stubalign(offset, tt->align, nil, nil); if(offset != id->offset) fatal("pickadtstub bad offset"); print(" %R %s;\n", tt, id->sym->name); offset += tt->size; } } print(" union{\n"); for(tg = t->tags; tg != nil; tg = tg->next){ tgoffset = offset; print(" struct{\n"); for(id = tg->ty->ids; id != nil; id = id->next){ if(id->store == Dfield){ tt = id->ty; tgoffset = stubalign(tgoffset, tt->align, nil, nil); if(tgoffset != id->offset) fatal("pickadtstub bad offset"); print(" %R %s;\n", tt, id->sym->name); tgoffset += tt->size; } } if(tg->ty->ids == nil) print(" char dummy[1];\n"); print(" } %s;\n", tg->sym->name); } print(" } u;\n"); print("};\n"); for(id = t->ids; id != nil; id = id->next) if(id->store == Dconst) constub(id); for(id = t->ids; id != nil; id = id->next) if(id->ty->kind == Tchan) chanstub(buf, id); for(tg = t->tags; tg != nil; tg = tg->next){ ok = tg->ty->tof->ok; tg->ty->tof->ok = OKverify; sizetype(tg->ty->tof); tg->ty->tof->ok = OKmask; desc = mktdesc(tg->ty->tof); tg->ty->tof->ok = ok; print("#define %s_%s_size %ld\n", buf, tg->sym->name, tg->ty->size); print("#define %s_%s_map %M\n", buf, tg->sym->name, desc); } }