diff options
| -rw-r--r-- | src/lib/runtime/runtime.c | 595 | ||||
| -rw-r--r-- | src/lib/runtime/runtime.h | 107 | 
2 files changed, 702 insertions, 0 deletions
| diff --git a/src/lib/runtime/runtime.c b/src/lib/runtime/runtime.c new file mode 100644 index 000000000..c99333ba7 --- /dev/null +++ b/src/lib/runtime/runtime.c @@ -0,0 +1,595 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" + +int32	debug	= 0; + +void +sys_printbool(bool v) +{ +	if(v) { +		sys_write(1, (byte*)"true", 4); +		return; +	} +	sys_write(1, (byte*)"false", 5); +} + +void +sys_printfloat(float64 v) +{ +	sys_write(1, "printfloat", 10); +} + +void +sys_printint(int64 v) +{ +	byte buf[100]; +	int32 i, s; + +	s = 0; +	if(v < 0) { +		v = -v; +		s = 1; +		if(v < 0) { +			sys_write(1, (byte*)"-oo", 3); +			return; +		} +	} + +	for(i=nelem(buf)-1; i>0; i--) { +		buf[i] = v%10 + '0'; +		if(v < 10) +			break; +		v = v/10; +	} +	if(s) { +		i--; +		buf[i] = '-'; +	} +	sys_write(1, buf+i, nelem(buf)-i); +} + +void +sys_printpointer(void *p) +{ +	uint64 v; +	byte buf[100]; +	int32 i; + +	v = (int64)p; +	for(i=nelem(buf)-1; i>0; i--) { +		buf[i] = v%16 + '0'; +		if(buf[i] > '9') +			buf[i] += 'a'-'0'-10; +		if(v < 16) +			break; +		v = v/16; +	} +	sys_write(1, buf+i, nelem(buf)-i); +} + +void +sys_panicl(int32 lno) +{ +	prints("\npanic on line "); +	sys_printint(lno); +	prints("\n"); +	*(int32*)0 = 0; +} + +void +sys_printstring(string v) +{ +	sys_write(1, v->str, v->len); +} + +int32 +strlen(int8 *s) +{ +	int32 l; + +	for(l=0; s[l]!=0; l++) +		; +	return l; +} + +void +prints(int8 *s) +{ +	sys_write(1, s, strlen(s)); +} + +dump(byte *p, int32 n) +{ +	uint32 v; +	int32 i; + +	for(i=0; i<n; i++) { +		sys_printpointer((byte*)(p[i]>>4)); +		sys_printpointer((byte*)(p[i]&0xf)); +		if((i&15) == 15) +			prints("\n"); +		else +			prints(" "); +	} +	if(n & 15) +		prints("\n"); +} + +static	uint8*	hunk; +static	uint32	nhunk; +static	uint64	nmmap; +static	uint64	nmal; +enum +{ +	NHUNK		= 20<<20, + +	PROT_NONE	= 0x00, +	PROT_READ	= 0x01, +	PROT_WRITE	= 0x02, +	PROT_EXEC	= 0x04, + +	MAP_FILE	= 0x0000, +	MAP_SHARED	= 0x0001, +	MAP_PRIVATE	= 0x0002, +	MAP_FIXED	= 0x0010, +	MAP_ANON	= 0x1000, +}; + +static void +throw(int8 *s) +{ +	prints("throw: "); +	prints(s); +	prints("\n"); +	sys_exit(1); +} + +static void +mcpy(byte *t, byte *f, uint32 n) +{ +	while(n > 0) { +		*t = *f; +		t++; +		f++; +		n--; +	} +} + +static byte* +brk(uint32 n) +{ +	byte* v; + +	v = sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); +	sys_memclr(v, n); +	nmmap += n; +	return v; +} + +static void* +mal(uint32 n) +{ +	byte* v; + +	// round to keep everything 64-bit alligned +	while(n & 7) +		n++; + +	nmal += n; + +	// do we have enough in contiguous hunk +	if(n > nhunk) { + +		// if it is big allocate it separately +		if(n > NHUNK) +			return brk(n); + +		// allocate a new contiguous hunk +		hunk = brk(NHUNK); +		nhunk = NHUNK; +	} + +	// allocate from the contiguous hunk +	v = hunk; +	hunk += n; +	nhunk -= n; +	return v; +} + +void +sys_mal(uint32 n, uint8 *ret) +{ +	ret = mal(n); +	FLUSH(&ret); +} + +void +sys_catstring(string s1, string s2, string s3) +{ +	uint32 l; + +	if(s1->len == 0) { +		s3 = s2; +		goto out; +	} +	if(s2->len == 0) { +		s3 = s1; +		goto out; +	} + +	l = s1->len + s2->len; + +	s3 = mal(sizeof(s3->len)+l); +	s3->len = l; +	mcpy(s3->str, s1->str, s1->len); +	mcpy(s3->str+s1->len, s2->str, s2->len); + +out: +	FLUSH(&s3); +} + +void +sys_cmpstring(string s1, string s2, int32 v) +{ +	uint32 i, l; +	byte c1, c2; + +	l = s1->len; +	if(s2->len < l) +		l = s2->len; +	for(i=0; i<l; i++) { +		c1 = s1->str[i]; +		c2 = s2->str[i]; +		if(c1 < c2) { +			v = -1; +			goto out; +		} +		if(c1 > c2) { +			v = +1; +			goto out; +		} +	} +	if(s1->len < s2->len) { +		v = -1; +		goto out; +	} +	if(s1->len > s2->len) { +		v = +1; +		goto out; +	} +	v = 0; + +out: +	FLUSH(&v); +} + +static int32 +strcmp(byte *s1, byte *s2) +{ +	uint32 i; +	byte c1, c2; + +	for(i=0;; i++) { +		c1 = s1[i]; +		c2 = s2[i]; +		if(c1 < c2) +			return -1; +		if(c1 > c2) +			return +1; +		if(c1 == 0) +			return 0; +	} +} + +static void +prbounds(int8* s, int32 a, int32 b, int32 c) +{ +	int32 i; + +	prints(s); +	prints(" "); +	sys_printint(a); +	prints("<"); +	sys_printint(b); +	prints(">"); +	sys_printint(c); +	prints("\n"); +	throw("bounds"); +} + +void +sys_slicestring(string si, int32 lindex, int32 hindex, string so) +{ +	string s, str; +	int32 l; + +	if(lindex < 0 || lindex > si->len || +	   hindex < lindex || hindex > si->len) +		prbounds("slice", lindex, si->len, hindex); + +	l = hindex-lindex; +	so = mal(sizeof(so->len)+l); +	so->len = l; +	mcpy(so->str, si->str+lindex, l); +	FLUSH(&so); +} + +void +sys_indexstring(string s, int32 i, byte b) +{ +	if(i < 0 || i >= s->len) +		prbounds("index", 0, i, s->len); + +	b = s->str[i]; +	FLUSH(&b); +} + +/* + * this is the plan9 runetochar + * extended for 36 bits in 7 bytes + * note that it truncates to 32 bits + * through the argument passing. + */ +static int32 +runetochar(byte *str, uint32 c) +{ +	int32 i, n; +	uint32 mask, mark; + +	/* +	 * one character in 7 bits +	 */ +	if(c <= 0x07FUL) { +		str[0] = c; +		return 1; +	} + +	/* +	 * every new character picks up 5 bits +	 * one less in the first byte and +	 * six more in an extension byte +	 */ +	mask = 0x7ffUL; +	mark = 0xC0UL; +	for(n=1;; n++) { +		if(c <= mask) +			break; +		mask = (mask<<5) | 0x1fUL; +		mark = (mark>>1) | 0x80UL; +	} + +	/* +	 * lay down the bytes backwards +	 * n is the number of extension bytes +	 * mask is the max codepoint +	 * mark is the zeroth byte indicator +	 */ +	for(i=n; i>0; i--) { +		str[i] = 0x80UL | (c&0x3fUL); +		c >>= 6; +	} + +	str[0] = mark|c; +	return n+1; +} + +void +sys_intstring(int64 v, string s) +{ +	int32 l; + +	s = mal(sizeof(s->len)+8); +	s->len = runetochar(s->str, v); +	FLUSH(&s); +} + +void +sys_byteastring(byte *a, int32 l, string s) +{ +	s = mal(sizeof(s->len)+l); +	s->len = l; +	mcpy(s->str, a, l); +	FLUSH(&s); +} + +static	Map*	hash[1009]; + +static Map* +hashmap(Sigi *si, Sigs *ss) +{ +	int32 ns, ni; +	uint32 ihash, h; +	byte *sname, *iname; +	Map *m; + +	h = ((uint32)si + (uint32)ss) % nelem(hash); +	for(m=hash[h]; m!=nil; m=m->link) { +		if(m->si == si && m->ss == ss) { +			if(m->bad) { +				throw("bad hashmap"); +				m = nil; +			} +			// prints("old hashmap\n"); +			return m; +		} +	} + +	ni = si[0].offset;	// first word has size +	m = mal(sizeof(*m) + ni*sizeof(m->fun[0])); +	m->si = si; +	m->ss = ss; + +	ni = 1;			// skip first word +	ns = 0; + +loop1: +	// pick up next name from +	// interface signature +	iname = si[ni].name; +	if(iname == nil) { +		m->link = hash[h]; +		hash[h] = m; +		// prints("new hashmap\n"); +		return m; +	} +	ihash = si[ni].hash; + +loop2: +	// pick up and comapre next name +	// from structure signature +	sname = ss[ns].name; +	if(sname == nil) { +		prints((int8*)iname); +		prints(": "); +		throw("hashmap: failed to find method"); +		m->bad = 1; +		m->link = hash[h]; +		hash[h] = m; +		return nil; +	} +	if(ihash != ss[ns].hash || +	   strcmp(sname, iname) != 0) { +		ns++; +		goto loop2; +	} + +	m->fun[si[ni].offset] = ss[ns].fun; +	ni++; +	goto loop1; +} + +void +sys_ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s) +{ + +	if(debug) { +		prints("s2i sigi="); +		sys_printpointer(si); +		prints(" sigs="); +		sys_printpointer(ss); +		prints(" s="); +		sys_printpointer(s); +	} + +	if(s == nil) { +		throw("ifaces2i: nil pointer"); +		m = nil; +		FLUSH(&m); +		return; +	} + +	m = hashmap(si, ss); + +	if(debug) { +		prints(" returning m="); +		sys_printpointer(m); +		prints(" s="); +		sys_printpointer(s); +		prints("\n"); +		dump((byte*)m, 64); +	} + +	FLUSH(&m); +} + +void +sys_ifacei2i(Sigi *si, Map *m, void *s) +{ + +	if(debug) { +		prints("i2i sigi="); +		sys_printpointer(si); +		prints(" m="); +		sys_printpointer(m); +		prints(" s="); +		sys_printpointer(s); +	} + +	if(m == nil) { +		throw("ifacei2i: nil map"); +		s = nil; +		FLUSH(&s); +		return; +	} + +	if(m->si == nil) { +		throw("ifacei2i: nil pointer"); +		return; +	} + +	if(m->si != si) { +		m = hashmap(si, m->ss); +		FLUSH(&m); +	} + +	if(debug) { +		prints(" returning m="); +		sys_printpointer(m); +		prints(" s="); +		sys_printpointer(s); +		prints("\n"); +		dump((byte*)m, 64); +	} +} + +void +sys_ifacei2s(Sigs *ss, Map *m, void *s) +{ + +	if(debug) { +		prints("i2s m="); +		sys_printpointer(m); +		prints(" s="); +		sys_printpointer(s); +		prints("\n"); +	} + +	if(m == nil) { +		throw("ifacei2s: nil map"); +		s = nil; +		FLUSH(&s); +		return; +	} + +	if(m->ss != ss) { +		dump((byte*)m, 64); +		throw("ifacei2s: wrong pointer"); +		s = nil; +		FLUSH(&s); +		return; +	} +} + +void +check(void) +{ +	int8 a; +	uint8 b; +	int16 c; +	uint16 d; +	int32 e; +	uint32 f; +	int64 g; +	uint64 h; +	float32 i; +	float64 j; +	void* k; +	uint16* l; + +	if(sizeof(a) != 1) throw("bad a"); +	if(sizeof(b) != 1) throw("bad b"); +	if(sizeof(c) != 2) throw("bad c"); +	if(sizeof(d) != 2) throw("bad d"); +	if(sizeof(e) != 4) throw("bad e"); +	if(sizeof(f) != 4) throw("bad f"); +	if(sizeof(g) != 8) throw("bad g"); +	if(sizeof(h) != 8) throw("bad h"); +	if(sizeof(i) != 4) throw("bad i"); +	if(sizeof(j) != 8) throw("bad j"); +	if(sizeof(k) != 8) throw("bad k"); +	if(sizeof(l) != 8) throw("bad l"); +//	prints(1"check ok\n"); +} diff --git a/src/lib/runtime/runtime.h b/src/lib/runtime/runtime.h new file mode 100644 index 000000000..65c3278e5 --- /dev/null +++ b/src/lib/runtime/runtime.h @@ -0,0 +1,107 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +/* + * basic types + */ +typedef	signed char		int8; +typedef	unsigned char		uint8; +typedef	signed short		int16; +typedef	unsigned short		uint16; +typedef	signed int		int32; +typedef	unsigned int		uint32; +typedef	signed long long int	int64; +typedef	unsigned long long int	uint64; +typedef	float			float32; +typedef	double			float64; + +/* + * get rid of C types + */ +#define	unsigned		XXunsigned +#define	signed			XXsigned +#define	char			XXchar +#define	short			XXshort +#define	int			XXint +#define	long			XXlong +#define	float			XXfloat +#define	double			XXdouble + +/* + * defined types + */ +typedef	uint8			bool; +typedef	uint8			byte; +typedef	struct +{ +	int32	len; +	byte	str[1]; +}				*string; +typedef	struct +{ +	byte*	name; +	uint32	hash; +	void	(*fun)(void); +}				Sigs; +typedef	struct +{ +	byte*	name; +	uint32	hash; +	uint32	offset; +}				Sigi; +typedef	struct	Map		Map; +struct	Map +{ +	Sigi*	si; +	Sigs*	ss; +	Map*	link; +	int32	bad; +	int32	unused; +	void	(*fun[])(void); +}; + +/* + * defined constants + */ +enum +{ +	true	= 1, +	false	= 0, +}; + +/* + * defined macros + *    you need super-goru privilege + *    to add this list. + */ +#define	nelem(x)	(sizeof(x)/sizeof((x)[0])) +#define	nil		((void*)0) + +/* + * very low level + */ +void	FLUSH(void*); +void	prints(int8*); +void	sys_exit(int32); +void	sys_write(int32, void*, int32); +void	sys_breakpoint(void); +uint8*	sys_mmap(byte*, uint32, int32, int32, int32, uint32); +void	sys_memclr(byte*, uint32); + +/* + * runtime + */ +void	sys_printbool(bool); +void	sys_printfloat(float64); +void	sys_printint(int64); +void	sys_printstring(string); +void	sys_catstring(string, string, string); +void	sys_cmpstring(string, string, int32); +void	sys_slicestring(string, int32, int32, string); +void	sys_indexstring(string, int32, byte); +void	sys_intstring(int64, string); +void	sys_ifaces2i(Sigi*, Sigs*, Map*, void*); +void	sys_ifacei2i(Sigi*, Map*, void*); +void	sys_ifacei2s(Sigs*, Map*, void*); | 
