## Manage module Data Section.# MP_INT,MP_LONG,MP_REAL,MP_STRING,MP_CASE,MP_GOTO: con iota; Datum_v: adt { ival: big; # MP_[INT|LONG] rval: real; # MP_REAL next: cyclic ref Datum.Pv;}; Datum_c: adt { # MP_CASE n: int; # number of cases in jmptbl jmptbl: array of int; # 3 words per case, plus default}; Datum_g: adt { # MP_GOTO (for finally blocks) n: int; # number of entries in gototbl gototbl:array of int;}; Datum: adt { kind: byte; # MP_INT, etc. offset: int; # byte offset in Data Section next: cyclic ref Datum; pick { Pv => v: ref Datum_v; # MP_[INT|LONG|REAL] Ps => s: string; # MP_STRING Pc => c: ref Datum_c; # MP_CASE Pg => g: ref Datum_g; # MP_GOTO }}; Hentry: adt { md: ref Datum.Ps; next: cyclic ref Hentry;}; htable := array [Hashsize] of ref Hentry;mpoff := IBY2WD; # skip first cell, as it's reserved for nil ptr mplist: ref Datum;mptail: ref Datum;llist: ref Datum.Pv;rlist: ref Datum.Pv; ## Append a module datum to mplist.# append(md: ref Datum){ if(mplist == nil) mplist = md; else mptail.next = md; mptail = md;} ## Add a 'byte', int 'word', or 'long'.# mpintegral(kind: int, ival: big): int{ size: int; md := ref Datum.Pv; md.v = ref Datum_v; md.v.ival = ival; case kind { MP_INT => md.kind = byte MP_INT; size = IBY2WD; mpoff = align(mpoff, IBY2WD); MP_LONG => md.kind = byte MP_LONG; size = IBY2LG; mpoff = align(mpoff, IBY2LG); md.v.next = llist; llist = md; } md.offset = mpoff; mpoff += size; append(md); return md.offset;} ## Add a 'word' (int).# mpint(ival: int): int{ return mpintegral(MP_INT, big ival);} ## Add a 'long'.# mplong(lval: big): int{ md: ref Datum.Pv; for(md = llist; md != nil; md = md.v.next) { if(lval == md.v.ival) return md.offset; } return mpintegral(MP_LONG, lval);} ## Add a 'real'.# mpreal(rval: real): int{ md: ref Datum.Pv; for(md = rlist; md != nil; md = md.v.next) { # distinguish 0.0 from -0.0 if(rval == md.v.rval && math->realbits64(rval) == math->realbits64(md.v.rval)) return md.offset; } md = ref Datum.Pv; md.kind = byte MP_REAL; md.v = ref Datum_v; md.v.rval = rval; md.v.next = rlist; rlist = md; mpoff = align(mpoff, IBY2FT); md.offset = mpoff; mpoff += IBY2FT; append(md); return md.offset;} ## Add a 'case' jump table.# mpcase(sz: int, jt: array of int): int{ md := ref Datum.Pc; md.kind = byte MP_CASE; mpoff = align(mpoff, IBY2WD); md.offset = mpoff; mpoff += (sz*3+2)*IBY2WD; md.c = ref Datum_c; md.c.n = sz; md.c.jmptbl = jt; append(md); return md.offset;} ## Add a 'goto' jump table; used for implementing finally blocks.# mpgoto(n: int, gototbl: array of int): int{ md := ref Datum.Pg; md.kind = byte MP_GOTO; mpoff = align(mpoff, IBY2WD); md.offset = mpoff; mpoff += (n+2)*IBY2WD; md.g = ref Datum_g; md.g.n = n; md.g.gototbl = gototbl; append(md); return md.offset+IBY2WD;} ## Hash table lookup function.# htlook(s: string): ref Hentry{ he: ref Hentry; for(he = htable[hashval(s)]; he != nil; he = he.next) if(s == he.md.s) return he; return nil;} ## Hash table enter function.# htenter(md: ref Datum.Ps): ref Hentry{ h: int; he: ref Hentry; h = hashval(md.s); he = ref Hentry(md, htable[h]); htable[h] = he; return he;} ## Add a 'string'.# mpstring(s: string): int{ he: ref Hentry; md: ref Datum.Ps; if((he = htlook(s)) != nil) return he.md.offset; md = ref Datum.Ps; md.kind = byte MP_STRING; md.s = s; mpoff = align(mpoff, IBY2WD); md.offset = mpoff; mpoff += IBY2WD; append(md); htenter(md); return md.offset;} ## Calculate the type descriptor for the Module Data section.# mpdesc(){ md: ref Datum; ltsize, rtsize, ln, mdsize: int; map: array of byte; ltsize = LTrelocsize(); # link-time reloc data mpoff = align(mpoff, IBY2WD); rtsize = RTrelocsize(); # run-time reloc data mdsize = ltsize + mpoff + rtsize; ln = mdsize / (8*IBY2WD) + (mdsize % (8*IBY2WD) != 0); map = array [ln] of { * => byte 0 }; LTrelocdesc(map); for(md = mplist; md != nil; md = md.next) { if(int md.kind == MP_STRING) setbit(map, ltsize + md.offset); } RTrelocdesc(map, ltsize + mpoff); RTfixoff(ltsize + mpoff); mpdescid(mdsize, ln, map);} asmprefix(off: int, s: string){ bout.puts("\t" + s + "\t@mp+" + string off + ",");} ## Begin an array initializer.# asmarray(off: int, tid: int, nelt: int, reloff: int){ asmprefix(off, "array"); bout.puts("$" + string tid + "," + string nelt + "\n"); asmprefix(off, "indir"); bout.puts(string reloff + "\n");} asmint(off: int, val: int){ asmprefix(off, "word"); bout.puts(string val + "\n");} asmlong(off: int, val: big){ asmprefix(off, "long"); bout.puts(string val + "\n");} asmreal(off: int, val: real){ asmprefix(off, "real"); bout.puts(string val + "\n");} asmstring(off: int, s: string){ asmprefix(off, "string"); bout.putc('"'); pstring(s); bout.puts("\"\n");} asmcase(off: int, md: ref Datum.Pc){ i: int; asmprefix(off, "word"); bout.puts(string md.c.n); for(i = 0; i < md.c.n; i++) { bout.puts("," + string md.c.jmptbl[i*3]); bout.puts("," + string md.c.jmptbl[i*3+1]); bout.puts("," + string md.c.jmptbl[i*3+2]); } bout.puts("," + string md.c.jmptbl[md.c.n*3] + "\n");} asmgoto(off: int, md: ref Datum.Pg){ i: int; asmprefix(off, "word"); bout.puts(string md.g.n); for(i = 0; i < md.g.n; i++) bout.puts("," + string md.g.gototbl[i]); bout.putc('\n');} ## Write Module Data to .s file.# asmvar(){ md: ref Datum; ltsize, rtsize, off: int; ltsize = LTrelocsize(); rtsize = RTrelocsize(); bout.puts("\tvar\t@mp," + string(ltsize + mpoff + rtsize) + "\n"); off = asmthisCreloc(0); asmint(off, mpoff + rtsize); off += IBY2WD; asmDreloc(off); off += IBY2WD; off = asmCreloc(off); off = align(off, 32); if(off != ltsize) fatal("asmvar: off " + string off + ", " + string ltsize); for(md = mplist; md != nil; md = md.next) { off = ltsize + md.offset; pick mdp := md { Pv => case int mdp.kind { MP_INT => asmint(off, int mdp.v.ival); MP_LONG => asmlong(off, mdp.v.ival); MP_REAL => asmreal(off, mdp.v.rval); } Ps => asmstring(off, mdp.s); Pc => asmcase(off, mdp); Pg => asmgoto(off, mdp); * => badpick("asmvar"); } } asmRTClass(ltsize + mpoff);} ## Put Module Data size into .dis Header.# disnvar(){ discon(LTrelocsize() + mpoff + RTrelocsize());} discase(off: int, md: ref Datum.Pc){ i: int; disint(off, md.c.n); off += IBY2WD; for(i = 0; i < md.c.n; i++) { disint(off, md.c.jmptbl[i*3]); off += IBY2WD; disint(off, md.c.jmptbl[i*3+1]); off += IBY2WD; disint(off, md.c.jmptbl[i*3+2]); off += IBY2WD; } disint(off, md.c.jmptbl[md.c.n*3]);} disgoto(off: int, md: ref Datum.Pg){ i: int; disint(off, md.g.n); for(i = 0; i < md.g.n; i++) { off += IBY2WD; disint(off, md.g.gototbl[i]); }} ## Write Module Data to .dis file.# disvar(){ md: ref Datum; ltsize, rtsize, off: int; ltsize = LTrelocsize(); rtsize = RTrelocsize(); off = disthisCreloc(0); disint(off, mpoff + rtsize); off += IBY2WD; disDreloc(off); off += IBY2WD; off = disCreloc(off); off = align(off, 32); if(off != ltsize) fatal("disvar: off " + string off + ", ltsize " + string ltsize); for(md = mplist; md != nil; md = md.next) { off = ltsize + md.offset; pick mdp := md { Pv => case int mdp.kind { MP_INT => disint(off, int mdp.v.ival); MP_LONG => dislong(off, mdp.v.ival); MP_REAL => disreal(off, mdp.v.rval); } Ps => disstring(off, mdp.s); Pc => discase(off, mdp); Pg => disgoto(off, mdp); * => badpick("disvar"); } } disRTClass(ltsize + mpoff); disflush(-1, -1, 0); bout.putb(byte 0);}
#
# Manage module Data Section.
#
MP_INT,
MP_LONG,
MP_REAL,
MP_STRING,
MP_CASE,
MP_GOTO: con iota;
Datum_v: adt {
ival: big; # MP_[INT|LONG]
rval: real; # MP_REAL
next: cyclic ref Datum.Pv;
};
Datum_c: adt { # MP_CASE
n: int; # number of cases in jmptbl
jmptbl: array of int; # 3 words per case, plus default
};
Datum_g: adt { # MP_GOTO (for finally blocks)
n: int; # number of entries in gototbl
gototbl:array of int;
};
Datum: adt {
kind: byte; # MP_INT, etc.
offset: int; # byte offset in Data Section
next: cyclic ref Datum;
pick {
Pv =>
v: ref Datum_v; # MP_[INT|LONG|REAL]
Ps =>
s: string; # MP_STRING
Pc =>
c: ref Datum_c; # MP_CASE
Pg =>
g: ref Datum_g; # MP_GOTO
}
};
Hentry: adt {
md: ref Datum.Ps;
next: cyclic ref Hentry;
};
htable := array [Hashsize] of ref Hentry;
mpoff := IBY2WD; # skip first cell, as it's reserved for nil ptr
mplist: ref Datum;
mptail: ref Datum;
llist: ref Datum.Pv;
rlist: ref Datum.Pv;
#
# Append a module datum to mplist.
#
append(md: ref Datum)
{
if(mplist == nil)
mplist = md;
else
mptail.next = md;
mptail = md;
}
#
# Add a 'byte', int 'word', or 'long'.
#
mpintegral(kind: int, ival: big): int
{
size: int;
md := ref Datum.Pv;
md.v = ref Datum_v;
md.v.ival = ival;
case kind {
MP_INT =>
md.kind = byte MP_INT;
size = IBY2WD;
mpoff = align(mpoff, IBY2WD);
MP_LONG =>
md.kind = byte MP_LONG;
size = IBY2LG;
mpoff = align(mpoff, IBY2LG);
md.v.next = llist;
llist = md;
}
md.offset = mpoff;
mpoff += size;
append(md);
return md.offset;
}
#
# Add a 'word' (int).
#
mpint(ival: int): int
{
return mpintegral(MP_INT, big ival);
}
#
# Add a 'long'.
#
mplong(lval: big): int
{
md: ref Datum.Pv;
for(md = llist; md != nil; md = md.v.next) {
if(lval == md.v.ival)
return md.offset;
}
return mpintegral(MP_LONG, lval);
}
#
# Add a 'real'.
#
mpreal(rval: real): int
{
md: ref Datum.Pv;
for(md = rlist; md != nil; md = md.v.next) {
# distinguish 0.0 from -0.0
if(rval == md.v.rval
&& math->realbits64(rval) == math->realbits64(md.v.rval))
return md.offset;
}
md = ref Datum.Pv;
md.kind = byte MP_REAL;
md.v = ref Datum_v;
md.v.rval = rval;
md.v.next = rlist;
rlist = md;
mpoff = align(mpoff, IBY2FT);
md.offset = mpoff;
mpoff += IBY2FT;
append(md);
return md.offset;
}
#
# Add a 'case' jump table.
#
mpcase(sz: int, jt: array of int): int
{
md := ref Datum.Pc;
md.kind = byte MP_CASE;
mpoff = align(mpoff, IBY2WD);
md.offset = mpoff;
mpoff += (sz*3+2)*IBY2WD;
md.c = ref Datum_c;
md.c.n = sz;
md.c.jmptbl = jt;
append(md);
return md.offset;
}
#
# Add a 'goto' jump table; used for implementing finally blocks.
#
mpgoto(n: int, gototbl: array of int): int
{
md := ref Datum.Pg;
md.kind = byte MP_GOTO;
mpoff = align(mpoff, IBY2WD);
md.offset = mpoff;
mpoff += (n+2)*IBY2WD;
md.g = ref Datum_g;
md.g.n = n;
md.g.gototbl = gototbl;
append(md);
return md.offset+IBY2WD;
}
#
# Hash table lookup function.
#
htlook(s: string): ref Hentry
{
he: ref Hentry;
for(he = htable[hashval(s)]; he != nil; he = he.next)
if(s == he.md.s)
return he;
return nil;
}
#
# Hash table enter function.
#
htenter(md: ref Datum.Ps): ref Hentry
{
h: int;
he: ref Hentry;
h = hashval(md.s);
he = ref Hentry(md, htable[h]);
htable[h] = he;
return he;
}
#
# Add a 'string'.
#
mpstring(s: string): int
{
he: ref Hentry;
md: ref Datum.Ps;
if((he = htlook(s)) != nil)
return he.md.offset;
md = ref Datum.Ps;
md.kind = byte MP_STRING;
md.s = s;
mpoff = align(mpoff, IBY2WD);
md.offset = mpoff;
mpoff += IBY2WD;
append(md);
htenter(md);
return md.offset;
}
#
# Calculate the type descriptor for the Module Data section.
#
mpdesc()
{
md: ref Datum;
ltsize, rtsize, ln, mdsize: int;
map: array of byte;
ltsize = LTrelocsize(); # link-time reloc data
mpoff = align(mpoff, IBY2WD);
rtsize = RTrelocsize(); # run-time reloc data
mdsize = ltsize + mpoff + rtsize;
ln = mdsize / (8*IBY2WD) + (mdsize % (8*IBY2WD) != 0);
map = array [ln] of { * => byte 0 };
LTrelocdesc(map);
for(md = mplist; md != nil; md = md.next) {
if(int md.kind == MP_STRING)
setbit(map, ltsize + md.offset);
}
RTrelocdesc(map, ltsize + mpoff);
RTfixoff(ltsize + mpoff);
mpdescid(mdsize, ln, map);
}
asmprefix(off: int, s: string)
{
bout.puts("\t" + s + "\t@mp+" + string off + ",");
}
#
# Begin an array initializer.
#
asmarray(off: int, tid: int, nelt: int, reloff: int)
{
asmprefix(off, "array");
bout.puts("$" + string tid + "," + string nelt + "\n");
asmprefix(off, "indir");
bout.puts(string reloff + "\n");
}
asmint(off: int, val: int)
{
asmprefix(off, "word");
bout.puts(string val + "\n");
}
asmlong(off: int, val: big)
{
asmprefix(off, "long");
bout.puts(string val + "\n");
}
asmreal(off: int, val: real)
{
asmprefix(off, "real");
bout.puts(string val + "\n");
}
asmstring(off: int, s: string)
{
asmprefix(off, "string");
bout.putc('"');
pstring(s);
bout.puts("\"\n");
}
asmcase(off: int, md: ref Datum.Pc)
{
i: int;
asmprefix(off, "word");
bout.puts(string md.c.n);
for(i = 0; i < md.c.n; i++) {
bout.puts("," + string md.c.jmptbl[i*3]);
bout.puts("," + string md.c.jmptbl[i*3+1]);
bout.puts("," + string md.c.jmptbl[i*3+2]);
}
bout.puts("," + string md.c.jmptbl[md.c.n*3] + "\n");
}
asmgoto(off: int, md: ref Datum.Pg)
{
i: int;
asmprefix(off, "word");
bout.puts(string md.g.n);
for(i = 0; i < md.g.n; i++)
bout.puts("," + string md.g.gototbl[i]);
bout.putc('\n');
}
#
# Write Module Data to .s file.
#
asmvar()
{
md: ref Datum;
ltsize, rtsize, off: int;
ltsize = LTrelocsize();
rtsize = RTrelocsize();
bout.puts("\tvar\t@mp," + string(ltsize + mpoff + rtsize) + "\n");
off = asmthisCreloc(0);
asmint(off, mpoff + rtsize);
off += IBY2WD;
asmDreloc(off);
off += IBY2WD;
off = asmCreloc(off);
off = align(off, 32);
if(off != ltsize)
fatal("asmvar: off " + string off + ", " + string ltsize);
for(md = mplist; md != nil; md = md.next) {
off = ltsize + md.offset;
pick mdp := md {
Pv =>
case int mdp.kind {
MP_INT =>
asmint(off, int mdp.v.ival);
MP_LONG =>
asmlong(off, mdp.v.ival);
MP_REAL =>
asmreal(off, mdp.v.rval);
}
Ps =>
asmstring(off, mdp.s);
Pc =>
asmcase(off, mdp);
Pg =>
asmgoto(off, mdp);
* =>
badpick("asmvar");
}
}
asmRTClass(ltsize + mpoff);
}
#
# Put Module Data size into .dis Header.
#
disnvar()
{
discon(LTrelocsize() + mpoff + RTrelocsize());
}
discase(off: int, md: ref Datum.Pc)
{
i: int;
disint(off, md.c.n);
off += IBY2WD;
for(i = 0; i < md.c.n; i++) {
disint(off, md.c.jmptbl[i*3]);
off += IBY2WD;
disint(off, md.c.jmptbl[i*3+1]);
off += IBY2WD;
disint(off, md.c.jmptbl[i*3+2]);
off += IBY2WD;
}
disint(off, md.c.jmptbl[md.c.n*3]);
}
disgoto(off: int, md: ref Datum.Pg)
{
i: int;
disint(off, md.g.n);
for(i = 0; i < md.g.n; i++) {
off += IBY2WD;
disint(off, md.g.gototbl[i]);
}
}
#
# Write Module Data to .dis file.
#
disvar()
{
md: ref Datum;
ltsize, rtsize, off: int;
ltsize = LTrelocsize();
rtsize = RTrelocsize();
off = disthisCreloc(0);
disint(off, mpoff + rtsize);
off += IBY2WD;
disDreloc(off);
off += IBY2WD;
off = disCreloc(off);
off = align(off, 32);
if(off != ltsize)
fatal("disvar: off " + string off + ", ltsize " + string ltsize);
for(md = mplist; md != nil; md = md.next) {
off = ltsize + md.offset;
pick mdp := md {
Pv =>
case int mdp.kind {
MP_INT =>
disint(off, int mdp.v.ival);
MP_LONG =>
dislong(off, mdp.v.ival);
MP_REAL =>
disreal(off, mdp.v.rval);
}
Ps =>
disstring(off, mdp.s);
Pc =>
discase(off, mdp);
Pg =>
disgoto(off, mdp);
* =>
badpick("disvar");
}
}
disRTClass(ltsize + mpoff);
disflush(-1, -1, 0);
bout.putb(byte 0);
}