shithub: purgatorio

ref: a411870ee4640241e3c494367d922847da84f972
dir: purgatorio/appl/cmd/limbo/dis.b

View raw version

NAMELEN:	con 28;

cache:		array of byte;
ncached:	int;
ndatum:		int;
startoff:	int;
lastoff:	int;
lastkind:	int;

discon(val: int)
{
	if(val >= -64 && val <= 63){
		bout.putb(byte (val & ~16r80));
		return;
	}
	if(val >= -8192 && val <= 8191){
		bout.putb(byte ((val>>8) & ~16rC0 | 16r80));
		bout.putb(byte val);
		return;
	}
	if(val < 0 && ((val >> 29) & 7) != 7
	|| val > 0 && (val >> 29) != 0)
		fatal("overflow in constant 16r"+hex(val, 0));
	bout.putb(byte(val>>24 | 16rC0));
	bout.putb(byte(val>>16));
	bout.putb(byte(val>>8));
	bout.putb(byte val);
}

disword(w: int)
{
	bout.putb(byte(w >> 24));
	bout.putb(byte(w >> 16));
	bout.putb(byte(w >> 8));
	bout.putb(byte w);
}

disdata(kind, n: int)
{
	if(n < DMAX && n != 0)
		bout.putb(byte((kind << DBYTE) | n));
	else{
		bout.putb(byte kind << DBYTE);
		discon(n);
	}
}

dismod(m: ref Decl)
{
	fileoff := bout.seek(big 0, 1);
	name := array of byte m.sym.name;
	n := len name;
	if(n > NAMELEN-1)
		n = NAMELEN-1;
	bout.write(name, n);
	bout.putb(byte 0);
	for(m = m.ty.tof.ids; m != nil; m = m.next){
		case m.store{
		Dglobal =>
			discon(-1);
			discon(-1);
			disword(sign(m));
			bout.puts(".mp");
			bout.putb(byte 0);
		Dfn =>
			discon(m.pc.pc);
			discon(m.desc.id);
			disword(sign(m));
			if(m.dot.ty.kind == Tadt){
				bout.puts(m.dot.sym.name);
				bout.putb(byte '.');
			}
			bout.puts(m.sym.name);
			bout.putb(byte 0);
		* =>
			fatal("unknown kind in dismod: "+declconv(m));
		}
	}
	if(debug['s'])
		print("%bd linkage bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
}

dispath()
{
	sp := array of byte srcpath();
	bout.write(sp, len sp);
	bout.putb(byte 0);
}

disentry(e: ref Decl)
{
	if(e == nil){
		discon(-1);
		discon(-1);
		return;
	}
	discon(e.pc.pc);
	discon(e.desc.id);
}

disdesc(d: ref Desc)
{
	fileoff := bout.seek(big 0, 1);
	for(; d != nil; d = d.next){
		discon(d.id);
		discon(d.size);
		discon(d.nmap);
		bout.write(d.map, d.nmap);
	}
	if(debug['s'])
		print("%bd type descriptor bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
}

disvar(nil: int, ids: ref Decl)
{
	fileoff := bout.seek(big 0, 1);
	lastkind = -1;
	ncached = 0;
	ndatum = 0;

	for(d := ids; d != nil; d = d.next)
		if(d.store == Dglobal && d.init != nil)
			disdatum(d.offset, d.init);

	disflush(-1, -1, 0);

	bout.putb(byte 0);

	if(debug['s'])
		print("%bd data bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
}

disldt(size: int, ds: ref Decl)
{
	if(0){
		discon(size);
		disvar(size, ds);
		return;
	}

	m := 0;
	for(d := ds; d != nil; d = d.next)
		if(d.store == Dglobal && d.init != nil)
			m++;
	discon(m);
	n: ref Node;
	for(d = ds; d != nil; d = d.next){
		if(d.store == Dglobal && d.init != nil){
			n = d.init;
			if(n.ty.kind != Tiface)
				nerror(n, "disldt: not Tiface");
			discon(int n.c.val);
			for(id := n.decl.ty.ids; id != nil; id = id.next){
				disword(sign(id));
				if(id.dot.ty.kind == Tadt){
					s := array of byte id.dot.sym.name;
					bout.write(s, len s);
					bout.putb(byte '.');
				}
				s := array of byte id.sym.name;
				bout.write(s, len s);
				bout.putb(byte 0);
			}
		}
	}
	discon(0);
}

disdatum(offset: int, n: ref Node)
{
	c: ref Case;
	lab: Label;
	id: ref Decl;
	wild: ref Node;
	i, e: int;

	case n.ty.kind{
	Tbyte =>
		disbyte(offset, byte n.c.val);
	Tint or
	Tfix =>
		disint(offset, int n.c.val);
	Tbig =>
		disbig(offset, n.c.val);
	Tstring =>
		disstring(offset, n.decl.sym);
	Treal =>
		disreal(offset, n.c.rval);
	Tadt or
	Tadtpick or
	Ttuple =>
		id = n.ty.ids;
		for(n = n.left; n != nil; n = n.right){
			disdatum(offset + id.offset, n.left);
			id = id.next;
		}
	Tany =>
		break;
	Tcase =>
		c = n.ty.cse;
		disint(offset, c.nlab);
		offset += IBY2WD;
		for(i = 0; i < c.nlab; i++){
			lab = c.labs[i];
			disint(offset, int lab.start.c.val);
			offset += IBY2WD;
			disint(offset, int lab.stop.c.val+1);
			offset += IBY2WD;
			disint(offset, lab.inst.pc);
			offset += IBY2WD;
		}
		if(c.iwild != nil)
			disint(offset, c.iwild.pc);
		else
			disint(offset, -1);
	Tcasel =>
		c = n.ty.cse;
		disint(offset, c.nlab);
		offset += 2*IBY2WD;
		for(i = 0; i < c.nlab; i++){
			lab = c.labs[i];
			disbig(offset, lab.start.c.val);
			offset += IBY2LG;
			disbig(offset, lab.stop.c.val+big 1);
			offset += IBY2LG;
			disint(offset, lab.inst.pc);
			offset += 2*IBY2WD;
		}
		if(c.iwild != nil)
			disint(offset, c.iwild.pc);
		else
			disint(offset, -1);
	Tcasec =>
		c = n.ty.cse;
		disint(offset, c.nlab);
		offset += IBY2WD;
		for(i = 0; i < c.nlab; i++){
			lab = c.labs[i];
			disstring(offset, lab.start.decl.sym);
			offset += IBY2WD;
			if(lab.stop != lab.start)
				disstring(offset, lab.stop.decl.sym);
			offset += IBY2WD;
			disint(offset, lab.inst.pc);
			offset += IBY2WD;
		}
		if(c.iwild != nil)
			disint(offset, c.iwild.pc);
		else
			disint(offset, -1);
	Tgoto =>
		c = n.ty.cse;
		disint(offset, n.ty.size/IBY2WD-1);
		offset += IBY2WD;
		for(i = 0; i < c.nlab; i++){
			disint(offset, c.labs[i].inst.pc);
			offset += IBY2WD;
		}
		if(c.iwild != nil)
			disint(offset, c.iwild.pc);
	Tarray =>
		disflush(-1, -1, 0);
		disdata(DEFA, 1);		# 1 is ignored
		discon(offset);
		disword(n.ty.tof.decl.desc.id);
		disword(int n.left.c.val);

		if(n.right == nil)
			break;

		disdata(DIND, 1);		# 1 is ignored
		discon(offset);
		disword(0);

		c = n.right.ty.cse;
		wild = nil;
		if(c.wild != nil)
			wild = c.wild.right;
		last := 0;
		esz := n.ty.tof.size;
		for(i = 0; i < c.nlab; i++){
			e = int c.labs[i].start.c.val;
			if(wild != nil){
				for(; last < e; last++)
					disdatum(esz * last, wild);
			}
			last = e;
			e = int c.labs[i].stop.c.val;
			elem := c.labs[i].node.right;
			for(; last <= e; last++)
				disdatum(esz * last, elem);
		}
		if(wild != nil)
			for(e = int n.left.c.val; last < e; last++)
				disdatum(esz * last, wild);

		disflush(-1, -1, 0);
		disdata(DAPOP, 1);		# 1 is ignored
		discon(0);
	Tiface =>
		disint(offset, int n.c.val);
		offset += IBY2WD;
		for(id = n.decl.ty.ids; id != nil; id = id.next){
			offset = align(offset, IBY2WD);
			disint(offset, sign(id));
			offset += IBY2WD;

			name: array of byte;
			if(id.dot.ty.kind == Tadt){
				name = array of byte id.dot.sym.name;
				disbytes(offset, name);
				offset += len name;
				disbyte(offset, byte '.');
				offset++;
			}
			name = array of byte id.sym.name;
			disbytes(offset, name);
			offset += len name;
			disbyte(offset, byte 0);
			offset++;
		}
	* =>
		fatal("can't gen global "+nodeconv(n));
	}
}

disexc(es: ref Except)
{
	e: ref Except;

	n := 0;
	for(e = es; e != nil; e = e.next)
		if(int e.p1.reach || int e.p2.reach)
			n++;
	discon(n);
	for(e = es; e != nil; e = e.next){
		if(!int e.p1.reach && !int e.p2.reach)
			continue;
		c := e.c;
		discon(e.d.offset);
		discon(getpc(e.p1));
		discon(getpc(e.p2));
		if(e.desc != nil)
			discon(e.desc.id);
		else
			discon(-1);
		discon(c.nlab|(e.ne<<16));
		for(i := 0; i < c.nlab; i++){
			lab := c.labs[i];
			d := lab.start.decl;
			if(lab.start.ty.kind == Texception)
				d = d.init.decl;
			bout.puts(d.sym.name);
			bout.putb(byte 0);
			discon(lab.inst.pc);
		}
		if(c.iwild == nil)
			discon(-1);
		else
			discon(c.iwild.pc);
	}
	discon(0);
}

disbyte(off: int, v: byte)
{
	disflush(DEFB, off, 1);
	cache[ncached++] = v;
	ndatum++;
}

disbytes(off: int, v: array of byte)
{
	n := len v;
	disflush(DEFB, off, n);
	cache[ncached:] = v;
	ncached += n;
	ndatum += n;
}

disint(off, v: int)
{
	disflush(DEFW, off, IBY2WD);
	cache[ncached++] = byte(v >> 24);
	cache[ncached++] = byte(v >> 16);
	cache[ncached++] = byte(v >> 8);
	cache[ncached++] = byte(v);
	ndatum++;
}

disbig(off: int, v: big)
{
	disflush(DEFL, off, IBY2LG);
	iv := int(v >> 32);
	cache[ncached++] = byte(iv >> 24);
	cache[ncached++] = byte(iv >> 16);
	cache[ncached++] = byte(iv >> 8);
	cache[ncached++] = byte(iv);
	iv = int v;
	cache[ncached++] = byte(iv >> 24);
	cache[ncached++] = byte(iv >> 16);
	cache[ncached++] = byte(iv >> 8);
	cache[ncached++] = byte(iv);
	ndatum++;
}

disreal(off: int, v: real)
{
	disflush(DEFF, off, IBY2LG);
	export_real(cache[ncached:ncached+8], array[] of {v});
	ncached += IBY2LG;
	ndatum++;
}

disstring(offset: int, sym: ref Sym)
{
	disflush(-1, -1, 0);
	d := array of byte sym.name;
	disdata(DEFS, len d);
	discon(offset);
	bout.write(d, len d);
}

disflush(kind, off, size: int)
{
	if(kind != lastkind || off != lastoff){
		if(lastkind != -1 && ncached){
			disdata(lastkind, ndatum);
			discon(startoff);
			bout.write(cache, ncached);
		}
		startoff = off;
		lastkind = kind;
		ncached = 0;
		ndatum = 0;
	}
	lastoff = off + size;
	while(kind >= 0 && ncached + size >= len cache){
		c := array[ncached + 1024] of byte;
		c[0:] = cache;
		cache = c;
	}
}

dismode := array[int Aend] of
{
	int Aimm =>	byte AIMM,
	int Amp =>	byte AMP,
	int Ampind =>	byte(AMP|AIND),
	int Afp =>	byte AFP,
	int Afpind =>	byte(AFP|AIND),
	int Apc =>	byte AIMM,
	int Adesc =>	byte AIMM,
	int Aoff =>	byte AIMM,
	int Anoff =>	byte AIMM,
	int Aerr =>	byte AXXX,
	int Anone =>	byte AXXX,
	int Aldt =>	byte AIMM,
};

disregmode := array[int Aend] of
{
	int Aimm =>	byte AXIMM,
	int Amp =>	byte AXINM,
	int Ampind =>	byte AXNON,
	int Afp =>	byte AXINF,
	int Afpind =>	byte AXNON,
	int Apc =>	byte AXIMM,
	int Adesc =>	byte AXIMM,
	int Aoff =>	byte AXIMM,
	int Anoff =>	byte AXIMM,
	int Aerr =>	byte AXNON,
	int Anone =>	byte AXNON,
	int Aldt =>	byte AXIMM,
};

MAXCON: con 4;
MAXADDR: con 2*MAXCON;
MAXINST: con 3*MAXADDR+2;
NIBUF: con 1024;

ibuf:	array of byte;
nibuf:	int;

disinst(in: ref Inst)
{
	fileoff := bout.seek(big 0, 1);
	ibuf = array[NIBUF] of byte;
	nibuf = 0;
	for(; in != nil; in = in.next){
		if(in.op == INOOP)
			continue;
		if(nibuf >= NIBUF-MAXINST){
			bout.write(ibuf, nibuf);
			nibuf = 0;
		}
		ibuf[nibuf++] = byte in.op;
		o := dismode[int in.sm] << SRC;
		o |= dismode[int in.dm] << DST;
		o |= disregmode[int in.mm];
		ibuf[nibuf++] = o;
		if(in.mm != Anone)
			disaddr(in.mm, in.m);
		if(in.sm != Anone)
			disaddr(in.sm, in.s);
		if(in.dm != Anone)
			disaddr(in.dm, in.d);
	}
	if(nibuf > 0)
		bout.write(ibuf, nibuf);
	ibuf = nil;

	if(debug['s'])
		print("%bd instruction bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
}

disaddr(m: byte, a: Addr)
{
	val := 0;
	case int m{
	int Aimm or
	int Apc or
	int Adesc =>
		val = a.offset;
	int Aoff =>
		val = a.decl.iface.offset;
	int Anoff =>
		val = -(a.decl.iface.offset+1);
	int Afp or
	int Amp or
	int Aldt =>
		val = a.reg;
	int Afpind or
	int Ampind =>
		disbcon(a.reg);
		val = a.offset;
	}
	disbcon(val);
}

disbcon(val: int)
{
	if(val >= -64 && val <= 63){
		ibuf[nibuf++] = byte(val & ~16r80);
		return;
	}
	if(val >= -8192 && val <= 8191){
		ibuf[nibuf++] = byte(val>>8 & ~16rC0 | 16r80);
		ibuf[nibuf++] = byte val;
		return;
	}
	if(val < 0 && ((val >> 29) & 7) != 7
	|| val > 0 && (val >> 29) != 0)
		fatal("overflow in constant 16r"+hex(val, 0));
	ibuf[nibuf++] = byte(val>>24 | 16rC0);
	ibuf[nibuf++] = byte(val>>16);
	ibuf[nibuf++] = byte(val>>8);
	ibuf[nibuf++] = byte val;
}