summaryrefslogtreecommitdiff
path: root/libinterp/xec.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libinterp/xec.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libinterp/xec.c')
-rw-r--r--libinterp/xec.c1692
1 files changed, 1692 insertions, 0 deletions
diff --git a/libinterp/xec.c b/libinterp/xec.c
new file mode 100644
index 00000000..9f6792e9
--- /dev/null
+++ b/libinterp/xec.c
@@ -0,0 +1,1692 @@
+#include <lib9.h>
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+REG R; /* Virtual Machine registers */
+String snil; /* String known to be zero length */
+
+#define Stmp *((WORD*)(R.FP+NREG*IBY2WD))
+#define Dtmp *((WORD*)(R.FP+(NREG+2)*IBY2WD))
+
+#define OP(fn) void fn(void)
+#define B(r) *((BYTE*)(R.r))
+#define W(r) *((WORD*)(R.r))
+#define UW(r) *((UWORD*)(R.r))
+#define F(r) *((REAL*)(R.r))
+#define V(r) *((LONG*)(R.r))
+#define UV(r) *((ULONG*)(R.r))
+#define S(r) *((String**)(R.r))
+#define A(r) *((Array**)(R.r))
+#define L(r) *((List**)(R.r))
+#define P(r) *((WORD**)(R.r))
+#define C(r) *((Channel**)(R.r))
+#define T(r) *((void**)(R.r))
+#define JMP(r) R.PC = *(Inst**)(R.r)
+#define SH(r) *((SHORT*)(R.r))
+#define SR(r) *((SREAL*)(R.r))
+
+OP(runt) {}
+OP(negf) { F(d) = -F(s); }
+OP(jmp) { JMP(d); }
+OP(movpc){ T(d) = &R.M->prog[W(s)]; }
+OP(movm) { memmove(R.d, R.s, W(m)); }
+OP(lea) { W(d) = (WORD)R.s; }
+OP(movb) { B(d) = B(s); }
+OP(movw) { W(d) = W(s); }
+OP(movf) { F(d) = F(s); }
+OP(movl) { V(d) = V(s); }
+OP(cvtbw){ W(d) = B(s); }
+OP(cvtwb){ B(d) = W(s); }
+OP(cvtrf){ F(d) = SR(s); }
+OP(cvtfr){ SR(d) = F(s); }
+OP(cvtws){ SH(d) = W(s); }
+OP(cvtsw){ W(d) = SH(s); }
+OP(cvtwf){ F(d) = W(s); }
+OP(addb) { B(d) = B(m) + B(s); }
+OP(addw) { W(d) = W(m) + W(s); }
+OP(addl) { V(d) = V(m) + V(s); }
+OP(addf) { F(d) = F(m) + F(s); }
+OP(subb) { B(d) = B(m) - B(s); }
+OP(subw) { W(d) = W(m) - W(s); }
+OP(subl) { V(d) = V(m) - V(s); }
+OP(subf) { F(d) = F(m) - F(s); }
+OP(divb) { B(d) = B(m) / B(s); }
+OP(divw) { W(d) = W(m) / W(s); }
+OP(divl) { V(d) = V(m) / V(s); }
+OP(divf) { F(d) = F(m) / F(s); }
+OP(modb) { B(d) = B(m) % B(s); }
+OP(modw) { W(d) = W(m) % W(s); }
+OP(modl) { V(d) = V(m) % V(s); }
+OP(mulb) { B(d) = B(m) * B(s); }
+OP(mulw) { W(d) = W(m) * W(s); }
+OP(mull) { V(d) = V(m) * V(s); }
+OP(mulf) { F(d) = F(m) * F(s); }
+OP(andb) { B(d) = B(m) & B(s); }
+OP(andw) { W(d) = W(m) & W(s); }
+OP(andl) { V(d) = V(m) & V(s); }
+OP(xorb) { B(d) = B(m) ^ B(s); }
+OP(xorw) { W(d) = W(m) ^ W(s); }
+OP(xorl) { V(d) = V(m) ^ V(s); }
+OP(orb) { B(d) = B(m) | B(s); }
+OP(orw) { W(d) = W(m) | W(s); }
+OP(orl) { V(d) = V(m) | V(s); }
+OP(shlb) { B(d) = B(m) << W(s); }
+OP(shlw) { W(d) = W(m) << W(s); }
+OP(shll) { V(d) = V(m) << W(s); }
+OP(shrb) { B(d) = B(m) >> W(s); }
+OP(shrw) { W(d) = W(m) >> W(s); }
+OP(shrl) { V(d) = V(m) >> W(s); }
+OP(lsrw) { W(d) = UW(m) >> W(s); }
+OP(lsrl) { V(d) = UV(m) >> W(s); }
+OP(beqb) { if(B(s) == B(m)) JMP(d); }
+OP(bneb) { if(B(s) != B(m)) JMP(d); }
+OP(bltb) { if(B(s) < B(m)) JMP(d); }
+OP(bleb) { if(B(s) <= B(m)) JMP(d); }
+OP(bgtb) { if(B(s) > B(m)) JMP(d); }
+OP(bgeb) { if(B(s) >= B(m)) JMP(d); }
+OP(beqw) { if(W(s) == W(m)) JMP(d); }
+OP(bnew) { if(W(s) != W(m)) JMP(d); }
+OP(bltw) { if(W(s) < W(m)) JMP(d); }
+OP(blew) { if(W(s) <= W(m)) JMP(d); }
+OP(bgtw) { if(W(s) > W(m)) JMP(d); }
+OP(bgew) { if(W(s) >= W(m)) JMP(d); }
+OP(beql) { if(V(s) == V(m)) JMP(d); }
+OP(bnel) { if(V(s) != V(m)) JMP(d); }
+OP(bltl) { if(V(s) < V(m)) JMP(d); }
+OP(blel) { if(V(s) <= V(m)) JMP(d); }
+OP(bgtl) { if(V(s) > V(m)) JMP(d); }
+OP(bgel) { if(V(s) >= V(m)) JMP(d); }
+OP(beqf) { if(F(s) == F(m)) JMP(d); }
+OP(bnef) { if(F(s) != F(m)) JMP(d); }
+OP(bltf) { if(F(s) < F(m)) JMP(d); }
+OP(blef) { if(F(s) <= F(m)) JMP(d); }
+OP(bgtf) { if(F(s) > F(m)) JMP(d); }
+OP(bgef) { if(F(s) >= F(m)) JMP(d); }
+OP(beqc) { if(stringcmp(S(s), S(m)) == 0) JMP(d); }
+OP(bnec) { if(stringcmp(S(s), S(m)) != 0) JMP(d); }
+OP(bltc) { if(stringcmp(S(s), S(m)) < 0) JMP(d); }
+OP(blec) { if(stringcmp(S(s), S(m)) <= 0) JMP(d); }
+OP(bgtc) { if(stringcmp(S(s), S(m)) > 0) JMP(d); }
+OP(bgec) { if(stringcmp(S(s), S(m)) >= 0) JMP(d); }
+OP(iexit){ error(""); }
+OP(cvtwl){ V(d) = W(s); }
+OP(cvtlw){ W(d) = V(s); }
+OP(cvtlf){ F(d) = V(s); }
+OP(cvtfl)
+{
+ REAL f;
+
+ f = F(s);
+ V(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtfw)
+{
+ REAL f;
+
+ f = F(s);
+ W(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtcl)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ V(d) = 0;
+ else
+ V(d) = strtoll(string2c(s), nil, 10);
+}
+OP(iexpw)
+{
+ int inv;
+ WORD x, n, r;
+
+ x = W(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ W(d) = r;
+}
+OP(iexpl)
+{
+ int inv;
+ WORD n;
+ LONG x, r;
+
+ x = V(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ V(d) = r;
+}
+OP(iexpf)
+{
+ int inv;
+ WORD n;
+ REAL x, r;
+
+ x = F(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ F(d) = r;
+}
+OP(indx)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*a->t->size);
+}
+OP(indw)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(WORD));
+}
+OP(indf)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(REAL));
+}
+OP(indl)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(LONG));
+}
+OP(indb)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(BYTE));
+}
+OP(movp)
+{
+ Heap *h;
+ WORD *dv, *sv;
+
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ dv = P(d);
+ P(d) = sv;
+ destroy(dv);
+}
+OP(movmp)
+{
+ Type *t;
+
+ t = R.M->type[W(m)];
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+OP(new)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heap(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(newz)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heapz(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(mnewz)
+{
+ Heap *h;
+ WORD **wp, *t;
+ Modlink *ml;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+ h = heapz(ml->type[W(m)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(frame)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = R.M->type[W(s)];
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+OP(mframe)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+
+ o = W(m);
+ if(o >= 0){
+ if(o >= ml->nlinks)
+ error("invalid mframe");
+ t = ml->links[o].frame;
+ }
+ else
+ t = ml->m->ext[-o-1].frame;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+void
+acheck(int tsz, int sz)
+{
+ if(sz < 0)
+ error(exNegsize);
+ /* test for overflow; assumes sz >>> tsz */
+ if((int)(sizeof(Array) + sizeof(Heap) + tsz*sz) < sz && tsz != 0)
+ error(exHeap);
+}
+OP(newa)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+OP(newaz)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ memset(a->data, 0, t->size*sz);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+Channel*
+cnewc(Type *t, void (*mover)(void), int len)
+{
+ Heap *h;
+ Channel *c;
+
+ h = heap(&Tchannel);
+ c = H2D(Channel*, h);
+ c->send = (Progq*)malloc(sizeof(Progq));
+ c->recv = (Progq*)malloc(sizeof(Progq));
+ if(c->send == nil || c->recv == nil){
+ free(c->send);
+ free(c->recv);
+ error(exNomem);
+ }
+ c->send->prog = c->recv->prog = nil;
+ c->send->next = c->recv->next = nil;
+ c->mover = mover;
+ c->buf = H;
+ if(len > 0)
+ c->buf = H2D(Array*, heaparray(t, len));
+ c->front = 0;
+ c->size = 0;
+ if(mover == movtmp){
+ c->mid.t = t;
+ t->ref++;
+ }
+ return c;
+}
+Channel*
+newc(Type *t, void (*mover)(void))
+{
+ Channel **cp, *oldc;
+ WORD len;
+
+ len = 0;
+ if(R.m != R.d){
+ len = W(m);
+ if(len < 0)
+ error(exNegsize);
+ }
+ cp = R.d;
+ oldc = *cp;
+ *cp = cnewc(t, mover, len);
+ destroy(oldc);
+ return *cp;
+}
+OP(newcl) { newc(&Tlong, movl); }
+OP(newcb) { newc(&Tbyte, movb); }
+OP(newcw) { newc(&Tword, movw); }
+OP(newcf) { newc(&Treal, movf); }
+OP(newcp) { newc(&Tptr, movp); }
+OP(newcm)
+{
+ Channel *c;
+ Type *t;
+
+ t = nil;
+ if(R.m != R.d && W(m) > 0)
+ t = dtype(nil, W(s), nil, 0);
+ c = newc(t, movm);
+ c->mid.w = W(s);
+ if(t != nil)
+ freetype(t);
+}
+OP(newcmp)
+{
+ newc(R.M->type[W(s)], movtmp);
+}
+OP(icase)
+{
+ WORD v, *t, *l, d, n, n2;
+
+ v = W(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ d = t[n*3];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*3;
+ if(v < l[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= l[1]) {
+ t = l+3;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[2];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casel)
+{
+ WORD *t, *l, d, n, n2;
+ LONG v;
+
+ v = V(s);
+ t = (WORD*)((WORD)R.d + 2*IBY2WD);
+ n = t[-2];
+ d = t[n*6];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*6;
+ if(v < ((LONG*)l)[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= ((LONG*)l)[1]) {
+ t = l+6;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[4];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casec)
+{
+ WORD *l, *t, *e, n, n2, r;
+ String *sl, *sh, *sv;
+
+ sv = S(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ e = t + n*3;
+ if(n > 2){
+ while(n > 0){
+ n2 = n>>1;
+ l = t + n2*3;
+ sl = (String*)l[0];
+ r = stringcmp(sv, sl);
+ if(r == 0){
+ e = &l[2];
+ break;
+ }
+ if(r < 0){
+ n = n2;
+ continue;
+ }
+ sh = (String*)l[1];
+ if(sh == H || stringcmp(sv, sh) > 0){
+ t = l+3;
+ n -= n2+1;
+ continue;
+ }
+ e = &l[2];
+ break;
+ }
+ t = e;
+ }
+ else{
+ while(t < e) {
+ sl = (String*)t[0];
+ sh = (String*)t[1];
+ if(sh == H) {
+ if(stringcmp(sl, sv) == 0) {
+ t = &t[2];
+ goto found;
+ }
+ }
+ else
+ if(stringcmp(sl, sv) <= 0 && stringcmp(sh, sv) >= 0) {
+ t = &t[2];
+ goto found;
+ }
+ t += 3;
+ }
+ }
+found:
+ if(R.M->compiled) {
+ R.PC = (Inst*)*t;
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(igoto)
+{
+ WORD *t;
+
+ t = (WORD*)((WORD)R.d + (W(s) * IBY2WD));
+ if(R.M->compiled) {
+ R.PC = (Inst*)t[0];
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(call)
+{
+ Frame *f;
+
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ R.FP = (uchar*)f;
+ JMP(d);
+}
+OP(spawn)
+{
+ Prog *p;
+
+ p = newprog(currun(), R.M);
+ p->R.PC = *(Inst**)R.d;
+ newstack(p);
+ unframe();
+}
+OP(mspawn)
+{
+ Prog *p;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ if(ml->prog == nil)
+ error(exSpawn);
+ p = newprog(currun(), ml);
+ o = W(m);
+ if(o >= 0)
+ p->R.PC = ml->links[o].u.pc;
+ else
+ p->R.PC = ml->m->ext[-o-1].u.pc;
+ newstack(p);
+ unframe();
+}
+OP(ret)
+{
+ Frame *f;
+ Modlink *m;
+
+ f = (Frame*)R.FP;
+ R.FP = f->fp;
+ if(R.FP == nil) {
+ R.FP = (uchar*)f;
+ error("");
+ }
+ R.SP = (uchar*)f;
+ R.PC = f->lr;
+ m = f->mr;
+
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+
+ if(m != nil) {
+ if(R.M->compiled != m->compiled) {
+ R.IC = 1;
+ R.t = 1;
+ }
+ destroy(R.M);
+ R.M = m;
+ R.MP = m->MP;
+ }
+}
+OP(iload)
+{
+ char *n;
+ Import *ldt;
+ Module *m;
+ Modlink *ml, **mp, *t;
+
+ n = string2c(S(s));
+ m = R.M->m;
+ if(m->rt & HASLDT)
+ ldt = m->ldt[W(m)];
+ else{
+ ldt = nil;
+ error("obsolete dis");
+ }
+
+ if(strcmp(n, "$self") == 0) {
+ m->ref++;
+ ml = linkmod(m, ldt, 0);
+ if(ml != H) {
+ ml->MP = R.M->MP;
+ D2H(ml->MP)->ref++;
+ }
+ }
+ else {
+ m = readmod(n, lookmod(n), 1);
+ ml = linkmod(m, ldt, 1);
+ }
+
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+OP(mcall)
+{
+ Heap *h;
+ Prog *p;
+ Frame *f;
+ Linkpc *l;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ f->mr = R.M;
+
+ R.FP = (uchar*)f;
+ R.M = ml;
+ h = D2H(ml);
+ h->ref++;
+
+ o = W(m);
+ if(o >= 0)
+ l = &ml->links[o].u;
+ else
+ l = &ml->m->ext[-o-1].u;
+ if(ml->prog == nil) {
+ l->runt(f);
+ h->ref--;
+ R.M = f->mr;
+ R.SP = R.FP;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+ R.t = 0;
+ return;
+ }
+ R.MP = R.M->MP;
+ R.PC = l->pc;
+ R.t = 1;
+
+ if(f->mr->compiled != R.M->compiled)
+ R.IC = 1;
+}
+OP(lena)
+{
+ WORD l;
+ Array *a;
+
+ a = A(s);
+ l = 0;
+ if(a != H)
+ l = a->len;
+ W(d) = l;
+}
+OP(lenl)
+{
+ WORD l;
+ List *a;
+
+ a = L(s);
+ l = 0;
+ while(a != H) {
+ l++;
+ a = a->tail;
+ }
+ W(d) = l;
+}
+static int
+cgetb(Channel *c, void *v)
+{
+ Array *a;
+ void *w;
+
+ if((a = c->buf) == H)
+ return 0;
+ if(c->size > 0){
+ w = a->data+c->front*a->t->size;
+ c->front++;
+ if(c->front == c->buf->len)
+ c->front = 0;
+ c->size--;
+ R.s = w;
+ R.m = &c->mid;
+ R.d = v;
+ c->mover();
+ if(a->t->np){
+ freeptrs(w, a->t);
+ initmem(a->t, w);
+ }
+ return 1;
+ }
+ return 0;
+}
+static int
+cputb(Channel *c, void *v)
+{
+ Array *a;
+ WORD len, r;
+
+ if((a = c->buf) == H)
+ return 0;
+ len = c->buf->len;
+ if(c->size < len){
+ r = c->front+c->size;
+ if(r >= len)
+ r -= len;
+ c->size++;
+ R.s = v;
+ R.m = &c->mid;
+ R.d = a->data+r*a->t->size;
+ c->mover();
+ return 1;
+ }
+ return 0;
+}
+/*
+int
+cqsize(Progq *q)
+{
+ int n;
+
+ n = 0;
+ for( ; q != nil; q = q->next)
+ if(q->prog != nil)
+ n++;
+ return n;
+}
+*/
+void
+cqadd(Progq **q, Prog *p)
+{
+ Progq *n;
+
+ if((*q)->prog == nil){
+ (*q)->prog = p;
+ return;
+ }
+ n = (Progq*)malloc(sizeof(Progq));
+ if(n == nil)
+ error(exNomem);
+ n->prog = p;
+ n->next = nil;
+ for( ; *q != nil; q = &(*q)->next)
+ ;
+ *q = n;
+}
+void
+cqdel(Progq **q)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ (*q)->prog = nil;
+ return;
+ }
+ f = *q;
+ *q = f->next;
+ free(f);
+}
+void
+cqdelp(Progq **q, Prog *p)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ if((*q)->prog == p)
+ (*q)->prog = nil;
+ return;
+ }
+ for( ; *q != nil; ){
+ if((*q)->prog == p){
+ f = *q;
+ *q = (*q)->next;
+ free(f);
+ }
+ else
+ q = &(*q)->next;
+ }
+}
+OP(isend)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(d);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->recv->prog) == nil) {
+ if(c->buf != H && cputb(c, R.s))
+ return;
+ p = delrun(Psend);
+ p->ptr = R.s;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->send, p);
+ return;
+ }
+
+ if(c->buf != H && c->size > 0)
+ print("non-empty buffer in isend\n");
+
+ cqdel(&c->recv);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 1);
+
+ R.m = &c->mid;
+ R.d = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ addrun(p);
+ R.t = 0;
+}
+OP(irecv)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(s);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->send->prog) == nil) {
+ if(c->buf != H && cgetb(c, R.d))
+ return;
+ p = delrun(Precv);
+ p->ptr = R.d;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->recv, p);
+ return;
+ }
+
+ if(c->buf != H && c->size != c->buf->len)
+ print("non-full buffer in irecv\n");
+
+ cqdel(&c->send);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 0);
+
+ if(c->buf != H){
+ cgetb(c, R.d);
+ cputb(c, p->ptr);
+ p->ptr = nil;
+ }
+ else{
+ R.m = &c->mid;
+ R.s = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ }
+ addrun(p);
+ R.t = 0;
+}
+int
+csendalt(Channel *c, void *ip, Type *t, int len)
+{
+ REG rsav;
+
+ if(c == H)
+ error(exNilref);
+
+ if(c->recv->prog == nil && (c->buf == H || c->size == c->buf->len)){
+ if(c->buf != H){
+ print("csendalt failed\n");
+ freeptrs(ip, t);
+ return 0;
+ }
+ c->buf = H2D(Array*, heaparray(t, len));
+ }
+
+ rsav = R;
+ R.s = ip;
+ R.d = &c;
+ isend();
+ R = rsav;
+ freeptrs(ip, t);
+ return 1;
+}
+
+List*
+cons(ulong size, List **lp)
+{
+ Heap *h;
+ List *lv, *l;
+
+ h = nheap(sizeof(List) + size - sizeof(((List*)0)->data));
+ h->t = &Tlist;
+ Tlist.ref++;
+ l = H2D(List*, h);
+ l->t = nil;
+
+ lv = *lp;
+ if(lv != H) {
+ h = D2H(lv);
+ Setmark(h);
+ }
+ l->tail = lv;
+ *lp = l;
+ return l;
+}
+OP(consb)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(BYTE*)l->data = B(s);
+}
+OP(consw)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(WORD*)l->data = W(s);
+}
+OP(consl)
+{
+ List *l;
+
+ l = cons(IBY2LG, R.d);
+ *(LONG*)l->data = V(s);
+}
+OP(consp)
+{
+ List *l;
+ Heap *h;
+ WORD *sv;
+
+ l = cons(IBY2WD, R.d);
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ l->t = &Tptr;
+ Tptr.ref++;
+ *(WORD**)l->data = sv;
+}
+OP(consf)
+{
+ List *l;
+
+ l = cons(sizeof(REAL), R.d);
+ *(REAL*)l->data = F(s);
+}
+OP(consm)
+{
+ int v;
+ List *l;
+
+ v = W(m);
+ l = cons(v, R.d);
+ memmove(l->data, R.s, v);
+}
+OP(consmp)
+{
+ List *l;
+ Type *t;
+
+ t = R.M->type[W(m)];
+ l = cons(t->size, R.d);
+ incmem(R.s, t);
+ memmove(l->data, R.s, t->size);
+ l->t = t;
+ t->ref++;
+}
+OP(headb)
+{
+ List *l;
+
+ l = L(s);
+ B(d) = *(BYTE*)l->data;
+}
+OP(headw)
+{
+ List *l;
+
+ l = L(s);
+ W(d) = *(WORD*)l->data;
+}
+OP(headl)
+{
+ List *l;
+
+ l = L(s);
+ V(d) = *(LONG*)l->data;
+}
+OP(headp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movp();
+}
+OP(headf)
+{
+ List *l;
+
+ l = L(s);
+ F(d) = *(REAL*)l->data;
+}
+OP(headm)
+{
+ List *l;
+
+ l = L(s);
+ memmove(R.d, l->data, W(m));
+}
+OP(headmp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movmp();
+}
+OP(tail)
+{
+ List *l;
+
+ l = L(s);
+ R.s = &l->tail;
+ movp();
+}
+OP(slicea)
+{
+ Type *t;
+ Heap *h;
+ Array *at, *ss, *ds;
+ int v, n, start;
+
+ v = W(m);
+ start = W(s);
+ n = v - start;
+ ds = A(d);
+
+ if(ds == H) {
+ if(n == 0)
+ return;
+ error(exNilref);
+ }
+ if(n < 0 || (ulong)start > ds->len || (ulong)v > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ h = heap(&Tarray);
+ ss = H2D(Array*, h);
+ ss->len = n;
+ ss->data = ds->data + start*t->size;
+ ss->t = t;
+ t->ref++;
+
+ if(ds->root != H) { /* slicing a slice */
+ ds = ds->root;
+ h = D2H(ds);
+ h->ref++;
+ at = A(d);
+ A(d) = ss;
+ ss->root = ds;
+ destroy(at);
+ }
+ else {
+ h = D2H(ds);
+ ss->root = ds;
+ A(d) = ss;
+ }
+ Setmark(h);
+}
+OP(slicela)
+{
+ Type *t;
+ int l, dl;
+ Array *ss, *ds;
+ uchar *sp, *dp, *ep;
+
+ ss = A(s);
+ dl = W(m);
+ ds = A(d);
+ if(ss == H)
+ return;
+ if(ds == H)
+ error(exNilref);
+ if(dl < 0 || dl+ss->len > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ if(t->np == 0) {
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+ return;
+ }
+ sp = ss->data;
+ dp = ds->data+dl*t->size;
+
+ if(dp > sp) {
+ l = ss->len * t->size;
+ sp = ss->data + l;
+ ep = dp + l;
+ while(ep > dp) {
+ ep -= t->size;
+ sp -= t->size;
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(ep, t);
+ }
+ }
+ else {
+ ep = dp + ss->len*t->size;
+ while(dp < ep) {
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(dp, t);
+ dp += t->size;
+ sp += t->size;
+ }
+ }
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+}
+OP(alt)
+{
+ R.t = 0;
+ xecalt(1);
+}
+OP(nbalt)
+{
+ xecalt(0);
+}
+OP(tcmp)
+{
+ void *s, *d;
+
+ s = T(s);
+ d = T(d);
+ if(s != H && (d == H || D2H(s)->t != D2H(d)->t))
+ error(exTcheck);
+}
+OP(eclr)
+{
+ /* spare slot */
+}
+OP(badop)
+{
+ error(exOp);
+}
+OP(iraise)
+{
+ void *v;
+ Heap *h;
+ Prog *p;
+
+ p = currun();
+ v = T(s);
+ if(v == H)
+ error(exNilref);
+ p->exval = v;
+ h = D2H(v);
+ h->ref++;
+ if(h->t == &Tstring)
+ error(string2c((String*)v));
+ else
+ error(string2c(*(String**)v));
+}
+OP(mulx)
+{
+ WORD p;
+ LONG r;
+
+ p = Dtmp;
+ r = (LONG)W(m)*(LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(divx)
+{
+ WORD p;
+ LONG s;
+
+ p = Dtmp;
+ s = (LONG)W(m);
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)W(s);
+ W(d) = (WORD)s;
+}
+OP(cvtxx)
+{
+ WORD p;
+ LONG r;
+
+ p = W(m);
+ r = (LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(mulx0)
+{
+ WORD x, y, p, a;
+ LONG r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x*(LONG)y;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx0)
+{
+ WORD x, y, p, b;
+ LONG s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ s = (LONG)b*(LONG)x;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s;
+}
+OP(cvtxx0)
+{
+ WORD x, p, a;
+ LONG r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(mulx1)
+{
+ WORD x, y, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if((!vnz && (x > 0 && y < 0 || x < 0 && y > 0)) ||
+ (vnz && (x > 0 && y > 0 || x < 0 && y < 0)))
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x*(LONG)y + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx1)
+{
+ WORD x, y, p, b, v;
+ int vnz, wnz;
+ LONG w, s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = 1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if(x <= 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ s = (LONG)b*(LONG)x + w;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s + v;
+}
+OP(cvtxx1)
+{
+ WORD x, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x < 0)
+ v = -v;
+ }
+ if(wnz){
+ if(!vnz && x < 0 || vnz && x > 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+/*
+OP(cvtxx)
+{
+ REAL v;
+
+ v = (REAL)W(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+*/
+OP(cvtfx)
+{
+ REAL v;
+
+ v = F(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+OP(cvtxf)
+{
+ F(d) = (REAL)W(s)*F(m);
+}
+
+OP(self)
+{
+ Modlink *ml, **mp, *t;
+
+ ml = R.M;
+ D2H(ml)->ref++;
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+
+void
+destroystack(REG *reg)
+{
+ Type *t;
+ Frame *f, *fp;
+ Modlink *m;
+ Stkext *sx;
+ uchar *ex;
+
+ ex = reg->EX;
+ reg->EX = nil;
+ while(ex != nil) {
+ sx = (Stkext*)ex;
+ fp = sx->reg.tos.fr;
+ do {
+ f = (Frame*)reg->FP;
+ if(f == nil)
+ break;
+ reg->FP = f->fp;
+ t = f->t;
+ if(t == nil)
+ t = sx->reg.TR;
+ m = f->mr;
+ if (t->np)
+ freeptrs(f, t);
+ if(m != nil) {
+ destroy(reg->M);
+ reg->M = m;
+ }
+ } while(f != fp);
+ ex = sx->reg.EX;
+ free(sx);
+ }
+ destroy(reg->M);
+ reg->M = H; /* for devprof */
+}
+
+Prog*
+isave(void)
+{
+ Prog *p;
+
+ p = delrun(Prelease);
+ p->R = R;
+ return p;
+}
+
+void
+irestore(Prog *p)
+{
+ R = p->R;
+ R.IC = 1;
+}
+
+void
+movtmp(void) /* Used by send & receive */
+{
+ Type *t;
+
+ t = (Type*)W(m);
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+
+extern OP(cvtca);
+extern OP(cvtac);
+extern OP(cvtwc);
+extern OP(cvtcw);
+extern OP(cvtfc);
+extern OP(cvtcf);
+extern OP(insc);
+extern OP(indc);
+extern OP(addc);
+extern OP(lenc);
+extern OP(slicec);
+extern OP(cvtlc);
+
+#include "optab.h"
+
+void
+opinit(void)
+{
+ int i;
+
+ for(i = 0; i < 256; i++)
+ if(optab[i] == nil)
+ optab[i] = badop;
+}
+
+void
+xec(Prog *p)
+{
+ int op;
+
+ R = p->R;
+ R.MP = R.M->MP;
+ R.IC = p->quanta;
+
+ if(p->kill != nil) {
+ char *m;
+ m = p->kill;
+ p->kill = nil;
+ error(m);
+ }
+
+// print("%lux %lux %lux %lux %lux\n", (ulong)&R, R.xpc, R.FP, R.MP, R.PC);
+
+ if(R.M->compiled)
+ comvec();
+ else do {
+ dec[R.PC->add]();
+ op = R.PC->op;
+ R.PC++;
+ optab[op]();
+ } while(--R.IC != 0);
+
+ p->R = R;
+}