// 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; static int32 empty = 0; static string emptystring = (string)∅ 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·printstring(string v) { if(v != nil) sys·write(1, v->str, v->len); } int32 findnull(int8 *s) { int32 l; for(l=0; s[l]!=0; l++) ; return l; } void prints(int8 *s) { sys·write(1, s, findnull(s)); } void sys·printpc(void *p) { prints("PC=0x"); sys·printpointer(sys·getcallerpc(p)); } /*BUG: move traceback code to architecture-dependent runtime */ void sys·panicl(int32 lno) { uint8 *sp; prints("\npanic on line "); sys·printint(lno); prints(" "); sys·printpc(&lno); prints("\n"); sp = (uint8*)&lno; traceback(sys·getcallerpc(&lno), sp); sys·breakpoint(); sys·exit(2); } dump(byte *p, int32 n) { uint32 v; int32 i; for(i=0; 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, }; void throw(int8 *s) { prints("throw: "); prints(s); prints("\n"); *(int32*)0 = 0; sys·exit(1); } 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, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); sys·memclr(v, n); nmmap += n; return v; } void* mal(uint32 n) { byte* v; // round to keep everything 64-bit aligned n = (n+7) & ~7; 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; } uint32 cmpstring(string s1, string s2) { uint32 i, l; byte c1, c2; if(s1 == nil) s1 = emptystring; if(s2 == nil) s2 = emptystring; l = s1->len; if(s2->len < l) l = s2->len; for(i=0; istr[i]; c2 = s2->str[i]; if(c1 < c2) return -1; if(c1 > c2) return +1; } if(s1->len < s2->len) return -1; if(s1->len > s2->len) return +1; return 0; } 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 == nil || s1->len == 0) { s3 = s2; goto out; } if(s2 == nil || 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) { v = cmpstring(s1, s2); 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(si == nil) si = emptystring; if(lindex < 0 || lindex > si->len || hindex < lindex || hindex > si->len) { sys·printpc(&si); prints(" "); 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(s == nil) s = emptystring; if(i < 0 || i >= s->len) { sys·printpc(&s); prints(" "); 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; } } enum { NANEXP = 2047<<20, NANMASK = 2047<<20, NANSIGN = 1<<31, }; static uint64 uvnan = 0x7FF0000000000001; static uint64 uvinf = 0x7FF0000000000000; static uint64 uvneginf = 0xFFF0000000000000; static int32 isInf(float64 d, int32 sign) { uint64 x; x = *(uint64*)&d; if(sign == 0) { if(x == uvinf || x == uvneginf) return 1; return 0; } if(sign > 0) { if(x == uvinf) return 1; return 0; } if(x == uvneginf) return 1; return 0; } static float64 NaN(void) { return *(float64*)&uvnan; } static int32 isNaN(float64 d) { uint64 x; x = *(uint64*)&d; return ((uint32)x>>32)==0x7FF00000 && !isInf(d, 0); } static float64 Inf(int32 sign) { if(sign < 0) return *(float64*)&uvinf; else return *(float64*)&uvneginf; } enum { MASK = 0x7ffL, SHIFT = 64-11-1, BIAS = 1022L, }; static float64 frexp(float64 d, int32 *ep) { uint64 x; if(d == 0) { *ep = 0; return 0; } x = *(uint64*)&d; *ep = (int32)((x >> SHIFT) & MASK) - BIAS; x &= ~((uint64)MASK << SHIFT); x |= (uint64)BIAS << SHIFT; return *(float64*)&x; } static float64 ldexp(float64 d, int32 e) { uint64 x; if(d == 0) return 0; x = *(uint64*)&d; e += (int32)(x >> SHIFT) & MASK; if(e <= 0) return 0; /* underflow */ if(e >= MASK){ /* overflow */ if(d < 0) return Inf(-1); return Inf(1); } x &= ~((uint64)MASK << SHIFT); x |= (uint64)e << SHIFT; return *(float64*)&x; } static float64 modf(float64 d, float64 *ip) { float64 dd; uint64 x; int32 e; if(d < 1) { if(d < 0) { d = modf(-d, ip); *ip = -*ip; return -d; } *ip = 0; return d; } x = *(uint64*)&d; e = (int32)((x >> SHIFT) & MASK) - BIAS; /* * Keep the top 11+e bits; clear the rest. */ if(e <= 64-11) x &= ~((uint64)1 << (64-11-e))-1; dd = *(float64*)&x; *ip = dd; return d - dd; } // func frexp(float64) (int32, float64); // break fp into exp,fract void sys·frexp(float64 din, int32 iou, float64 dou) { dou = frexp(din, &iou); FLUSH(&dou); } //func ldexp(int32, float64) float64; // make fp from exp,fract void sys·ldexp(float64 din, int32 ein, float64 dou) { dou = ldexp(din, ein); FLUSH(&dou); } //func modf(float64) (float64, float64); // break fp into double+double float64 sys·modf(float64 din, float64 dou1, float64 dou2) { dou1 = modf(din, &dou2); FLUSH(&dou2); } static int32 argc; static uint8** argv; static int32 envc; static uint8** envv; void args(int32 c, uint8 **v) { argc = c; argv = v; envv = v + argc + 1; // skip 0 at end of argv for (envc = 0; envv[envc] != 0; envc++) ; } //func argc() int32; // return number of arguments void sys·argc(int32 v) { v = argc; FLUSH(&v); } //func envc() int32; // return number of environment variables void sys·envc(int32 v) { v = envc; FLUSH(&v); } //func argv(i) string; // return argument i void sys·argv(int32 i, string s) { uint8* str; int32 l; if(i < 0 || i >= argc) { s = emptystring; goto out; } str = argv[i]; l = findnull((int8*)str); s = mal(sizeof(s->len)+l); s->len = l; mcpy(s->str, str, l); out: FLUSH(&s); } //func envv(i) string; // return argument i void sys·envv(int32 i, string s) { uint8* str; int32 l; if(i < 0 || i >= envc) { s = emptystring; goto out; } str = envv[i]; l = findnull((int8*)str); s = mal(sizeof(s->len)+l); s->len = l; mcpy(s->str, str, l); out: FLUSH(&s); } 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"); initsig(); } typedef struct Link Link; typedef struct Hmap Hmap; typedef struct Alg Alg; struct Alg { uint64 (*hash)(uint32, void*); uint32 (*equal)(uint32, void*, void*); void (*print)(uint32, void*); void (*copy)(uint32, void*, void*); }; struct Link { Link* link; byte data[8]; }; struct Hmap { uint32 len; // must be first uint32 keysize; uint32 valsize; uint32 hint; Alg* keyalg; Alg* valalg; uint32 valoffset; uint32 ko; uint32 vo; uint32 po; Link* link; }; static uint64 memhash(uint32 s, void *a) { prints("memhash\n"); return 0x12345; } static uint32 memequal(uint32 s, void *a, void *b) { byte *ba, *bb; uint32 i; ba = a; bb = b; for(i=0; i= 2 || valalg >= 3) { prints("0<="); sys·printint(keyalg); prints("<"); sys·printint(nelem(algarray)); prints("\n0<="); sys·printint(valalg); prints("<"); sys·printint(nelem(algarray)); prints("\n"); throw("sys·newmap: key/val algorithm out of range"); } m = mal(sizeof(*m)); m->len = 0; m->keysize = keysize; m->valsize = valsize; m->keyalg = &algarray[keyalg]; m->valalg = &algarray[valalg]; m->hint = hint; // these calculations are compiler dependent m->valoffset = rnd(keysize, valsize); m->ko = rnd(sizeof(m), keysize); m->vo = rnd(m->ko+keysize, valsize); m->po = rnd(m->vo+valsize, 1); ret = m; FLUSH(&ret); if(debug) { prints("newmap: map="); sys·printpointer(m); prints("; keysize="); sys·printint(keysize); prints("; valsize="); sys·printint(valsize); prints("; keyalg="); sys·printint(keyalg); prints("; valalg="); sys·printint(valalg); prints("; valoffset="); sys·printint(m->valoffset); prints("; ko="); sys·printint(m->ko); prints("; vo="); sys·printint(m->vo); prints("; po="); sys·printint(m->po); prints("\n"); } } // mapaccess1(hmap *map[any]any, key any) (val any); void sys·mapaccess1(Hmap *m, ...) { Link *l; byte *ak, *av; ak = (byte*)&m + m->ko; av = (byte*)&m + m->vo; for(l=m->link; l!=nil; l=l->link) { if(m->keyalg->equal(m->keysize, ak, l->data)) { m->valalg->copy(m->valsize, av, l->data+m->valoffset); goto out; } } m->valalg->copy(m->valsize, av, 0); out: if(debug) { prints("sys·mapaccess1: map="); sys·printpointer(m); prints("; key="); m->keyalg->print(m->keysize, ak); prints("; val="); m->valalg->print(m->valsize, av); prints("\n"); } } // mapaccess2(hmap *map[any]any, key any) (val any, pres bool); void sys·mapaccess2(Hmap *m, ...) { Link *l; byte *ak, *av, *ap; ak = (byte*)&m + m->ko; av = (byte*)&m + m->vo; ap = (byte*)&m + m->po; for(l=m->link; l!=nil; l=l->link) { if(m->keyalg->equal(m->keysize, ak, l->data)) { *ap = true; m->valalg->copy(m->valsize, av, l->data+m->valoffset); goto out; } } *ap = false; m->valalg->copy(m->valsize, av, nil); out: if(debug) { prints("sys·mapaccess2: map="); sys·printpointer(m); prints("; key="); m->keyalg->print(m->keysize, ak); prints("; val="); m->valalg->print(m->valsize, av); prints("; pres="); sys·printbool(*ap); prints("\n"); } } static void sys·mapassign(Hmap *m, byte *ak, byte *av) { Link *l; // mapassign(hmap *map[any]any, key any, val any); for(l=m->link; l!=nil; l=l->link) { if(m->keyalg->equal(m->keysize, ak, l->data)) goto out; } l = mal((sizeof(*l)-8) + m->keysize + m->valsize); l->link = m->link; m->link = l; m->keyalg->copy(m->keysize, l->data, ak); m->len++; out: m->valalg->copy(m->valsize, l->data+m->valoffset, av); if(debug) { prints("mapassign: map="); sys·printpointer(m); prints("; key="); m->keyalg->print(m->keysize, ak); prints("; val="); m->valalg->print(m->valsize, av); prints("\n"); } } // mapassign1(hmap *map[any]any, key any, val any); void sys·mapassign1(Hmap *m, ...) { Link **ll; byte *ak, *av; ak = (byte*)&m + m->ko; av = (byte*)&m + m->vo; sys·mapassign(m, ak, av); } // mapassign2(hmap *map[any]any, key any, val any, pres bool); void sys·mapassign2(Hmap *m, ...) { Link **ll; byte *ak, *av, *ap; ak = (byte*)&m + m->ko; av = (byte*)&m + m->vo; ap = (byte*)&m + m->po; if(*ap == true) { // assign sys·mapassign(m, ak, av); return; } // delete for(ll=&m->link; (*ll)!=nil; ll=&(*ll)->link) { if(m->keyalg->equal(m->keysize, ak, (*ll)->data)) { m->valalg->copy(m->valsize, (*ll)->data+m->valoffset, nil); (*ll) = (*ll)->link; m->len--; if(debug) { prints("mapdelete (found): map="); sys·printpointer(m); prints("; key="); m->keyalg->print(m->keysize, ak); prints("\n"); } return; } } if(debug) { prints("mapdelete (not found): map="); sys·printpointer(m); prints("; key="); m->keyalg->print(m->keysize, ak); prints(" *** not found\n"); } }