ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /limbo/stubs.c/
#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 <lib9.h>\n");
print("#include <isa.h>\n");
print("#include <interp.h>\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%lux,%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(" int 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);
}
}