summaryrefslogtreecommitdiff
path: root/appl/cmd/limbo/stubs.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/limbo/stubs.b')
-rw-r--r--appl/cmd/limbo/stubs.b575
1 files changed, 575 insertions, 0 deletions
diff --git a/appl/cmd/limbo/stubs.b b/appl/cmd/limbo/stubs.b
new file mode 100644
index 00000000..acb24b81
--- /dev/null
+++ b/appl/cmd/limbo/stubs.b
@@ -0,0 +1,575 @@
+#
+# write out some stub C code for limbo modules
+#
+emit(globals: ref Decl)
+{
+ 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){
+ print("#pragma hjdicks x4\n");
+ print("#pragma pack x4\n");
+ adtstub(globals);
+ modstub(globals);
+ print("#pragma pack off\n");
+ print("#pragma hjdicks off\n");
+ }
+ if(emittab != nil)
+ modtab(globals);
+ if(emitcode != nil)
+ modcode(globals);
+ if(emitsbl != nil)
+ modsbl(globals);
+}
+
+modsbl(globals: ref Decl)
+{
+ for(d := globals; d != nil; d = d.next)
+ if(d.store == Dtype && d.ty.kind == Tmodule && d.sym.name == emitsbl)
+ break;
+
+ if(d == nil)
+ return;
+ bsym = bufio->fopen(sys->fildes(1), Bufio->OWRITE);
+
+ sblmod(d);
+ sblfiles();
+ n := 0;
+ genstart();
+ for(id := d.ty.tof.ids; id != nil; id = id.next){
+ if(id.sym.name == ".mp")
+ continue;
+ pushblock();
+ id.pc = genrawop(id.src, INOP, nil, nil, nil);
+ id.pc.pc = n++;
+ popblock();
+ }
+ firstinst = firstinst.next;
+ sblinst(firstinst, n);
+# (adts, nadts) := findadts(globals);
+ sblty(adts, nadts);
+ fs := array[n] of ref Decl;
+ n = 0;
+ for(id = d.ty.tof.ids; id != nil; id = id.next){
+ if(id.sym.name == ".mp")
+ continue;
+ fs[n] = id;
+ n++;
+ }
+ sblfn(fs, n);
+ sblvar(nil);
+}
+
+lowercase(f: string): string
+{
+ for(i := 0; i < len f; i++)
+ if(f[i] >= 'A' && f[i] <= 'Z')
+ f[i] += 'a' - 'A';
+ return f;
+}
+
+modcode(globals: ref Decl)
+{
+ buf: string;
+
+ if(emitdyn){
+ buf = lowercase(emitcode);
+ 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 && d.sym.name == emitcode)
+ 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);\n", 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("\n\tdestroy(*f->ret);\n\t*f->ret = H;\n");
+ print("}\n");
+ }
+
+ if(emitdyn)
+ print("\n#include \"%smod.h\"\n", buf);
+}
+
+modtab(globals: ref Decl)
+{
+ 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 && d.sym.name == emittab){
+ 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 != byte 0)
+ print("0,0,{0},");
+ else{
+ md := mkdesc(idoffsets(id.ty.ids, MaxTemp, MaxAlign), id.ty.ids);
+ print("%d,%d,%s,", md.size, md.nmap, mapconv(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
+#
+modstub(globals: ref Decl)
+{
+ 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){
+ s := id.dot.sym.name + "_" + id.sym.name;
+ if(emitdyn && id.dot.dot != nil)
+ s = id.dot.dot.sym.name + "_" + s;
+ print("void %s(void*);\ntypedef struct F_%s F_%s;\nstruct F_%s\n{\n",
+ s, s, s, s);
+ print(" WORD regs[NREG-1];\n");
+ if(id.ty.tof != tnone)
+ print(" %s* ret;\n", ctypeconv(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){
+ p := "";
+ if(m.sym != nil)
+ p = m.sym.name;
+ else
+ p = "arg"+string arg;
+
+ #
+ # explicit pads for structure alignment
+ #
+ t := m.ty;
+ (offset, nil) = stubalign(offset, t.align, nil);
+ if(offset != m.offset)
+ yyerror("module stub must not contain data objects");
+ # fatal("modstub bad offset");
+ print(" %s %s;\n", ctypeconv(t), p);
+ arg++;
+ offset += t.size;
+#ZZZ need to align?
+ }
+ if(id.ty.varargs != byte 0)
+ print(" WORD vargs;\n");
+ print("};\n");
+ }
+ for(id = d.ty.ids; id != nil; id = id.next)
+ if(id.store == Dconst)
+ constub(id);
+ }
+}
+
+chanstub(in: string, id: ref Decl)
+{
+ print("typedef %s %s_%s;\n", ctypeconv(id.ty.tof), in, id.sym.name);
+ desc := mktdesc(id.ty.tof);
+ print("#define %s_%s_size %d\n", in, id.sym.name, desc.size);
+ print("#define %s_%s_map %s\n", in, id.sym.name, mapconv(desc));
+}
+
+#
+# produce c structs for all adts
+#
+adtstub(globals: ref Decl)
+{
+ t, tt: ref Type;
+ m, d, id: ref Decl;
+
+ 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;
+ s := dotprint(d.ty.decl, '_');
+ case d.ty.kind{
+ Tadt =>
+ print("typedef struct %s %s;\n", s, s);
+ Tint or
+ Tbyte or
+ Treal or
+ Tbig or
+ Tfix =>
+ print("typedef %s %s;\n", ctypeconv(t), s);
+ }
+ }
+ }
+ 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;
+ }
+ s := dotprint(t.decl, '_');
+ print("struct %s\n{\n", s);
+
+ offset := 0;
+ for(id = t.ids; id != nil; id = id.next){
+ if(id.store == Dfield){
+ tt = id.ty;
+ (offset, nil) = stubalign(offset, tt.align, nil);
+ if(offset != id.offset)
+ fatal("adtstub bad offset");
+ print(" %s %s;\n", ctypeconv(tt), id.sym.name);
+ offset += tt.size;
+ }
+ }
+ if(t.ids == nil){
+ print(" char dummy[1];\n");
+ offset = 1;
+ }
+ (offset, nil)= stubalign(offset, t.align, nil);
+#ZZZ
+(offset, nil) = stubalign(offset, IBY2WD, 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(s, id);
+
+ desc := mktdesc(t);
+ if(offset != desc.size && t.ids != nil)
+ fatal("adtstub: bad desc size");
+ print("#define %s_size %d\n", s, offset);
+ print("#define %s_map %s\n", s, mapconv(desc));
+#ZZZ
+if(0)
+ print("struct %s_check {int s[2*(sizeof(%s)==%s_size)-1];};\n", s, s, s);
+ }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
+#
+stubalign(offset: int, a: int, s: string): (int, string)
+{
+ x := offset & (a-1);
+ if(x == 0)
+ return (offset, s);
+ x = a - x;
+ if(s != nil)
+ s += sprint("uchar\t_pad%d[%d]; ", offset, x);
+ else
+ print("\tuchar\t_pad%d[%d];\n", offset, x);
+ offset += x;
+ if((offset & (a-1)) || x >= a)
+ fatal("compiler stub misalign");
+ return (offset, s);
+}
+
+constub(id: ref Decl)
+{
+ s := id.dot.sym.name + "_" + id.sym.name;
+ case id.ty.kind{
+ Tbyte =>
+ print("#define %s %d\n", s, int id.init.c.val & 16rff);
+ Tint or
+ Tfix =>
+ print("#define %s %d\n", s, int id.init.c.val);
+ Tbig =>
+ print("#define %s %bd\n", s, id.init.c.val);
+ Treal =>
+ print("#define %s %g\n", s, id.init.c.rval);
+ Tstring =>
+ print("#define %s \"%s\"\n", s, id.init.decl.sym.name);
+ }
+}
+
+mapconv(d: ref Desc): string
+{
+ s := "{";
+ for(i := 0; i < d.nmap; i++)
+ s += "0x" + hex(int d.map[i], 0) + ",";
+ if(i == 0)
+ s += "0";
+ s += "}";
+ return s;
+}
+
+dotprint(d: ref Decl, dot: int): string
+{
+ s : string;
+ if(d.dot != nil){
+ s = dotprint(d.dot, dot);
+ s[len s] = dot;
+ }
+ if(d.sym == nil)
+ return s;
+ return s + d.sym.name;
+}
+
+ckindname := array[Tend] of
+{
+ 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?",
+};
+
+ctypeconv(t: ref Type): string
+{
+ if(t == nil)
+ return "void";
+ s := "";
+ case t.kind{
+ Terror =>
+ return "type error";
+ Tref =>
+ s = ctypeconv(t.tof);
+ s += "*";
+ Tarray or
+ Tlist or
+ Tint or
+ Tbig or
+ Tstring or
+ Treal or
+ Tbyte or
+ Tnone or
+ Tany or
+ Tchan or
+ Tmodule or
+ Tfix or
+ Tpoly =>
+ return ckindname[t.kind];
+ Tadt or
+ Ttuple =>
+ if(t.decl.sym != anontupsym)
+ return dotprint(t.decl, '_');
+ s += "struct{ ";
+ offset := 0;
+ for(id := t.ids; id != nil; id = id.next){
+ tt := id.ty;
+ (offset, s) = stubalign(offset, tt.align, s);
+ if(offset != id.offset)
+ fatal("ctypeconv tuple bad offset");
+ s += ctypeconv(tt);
+ s += " ";
+ s += id.sym.name;
+ s += "; ";
+ offset += tt.size;
+ }
+ (offset, s) = stubalign(offset, t.align, s);
+ if(offset != t.size)
+ fatal(sprint("ctypeconv tuple bad t=%s size=%d offset=%d", typeconv(t), t.size, offset));
+ s += "}";
+ * =>
+ fatal("no C equivalent for type " + string t.kind);
+ }
+ return s;
+}
+
+pickadtstub(t: ref Type)
+{
+ tt: ref Type;
+ desc: ref Desc;
+ id, tg: ref Decl;
+ ok: byte;
+ offset, tgoffset: int;
+
+ buf := dotprint(t.decl, '_');
+ offset = 0;
+ for(tg = t.tags; tg != nil; tg = tg.next)
+ print("#define %s_%s %d\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, nil) = stubalign(offset, tt.align, nil);
+ if(offset != id.offset)
+ fatal("pickadtstub bad offset");
+ print(" %s %s;\n", ctypeconv(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, nil) = stubalign(tgoffset, tt.align, nil);
+ if(tgoffset != id.offset)
+ fatal("pickadtstub bad offset");
+ print(" %s %s;\n", ctypeconv(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 %d\n", buf, tg.sym.name, tg.ty.size);
+ print("#define %s_%s_map %s\n", buf, tg.sym.name, mapconv(desc));
+ }
+}