diff options
Diffstat (limited to 'src/lib/runtime')
75 files changed, 0 insertions, 14781 deletions
diff --git a/src/lib/runtime/386/asm.s b/src/lib/runtime/386/asm.s deleted file mode 100644 index 5d3c4261a..000000000 --- a/src/lib/runtime/386/asm.s +++ /dev/null @@ -1,217 +0,0 @@ -// 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. - -TEXT _rt0_386(SB),7,$0 - // copy arguments forward on an even stack - MOVL 0(SP), AX // argc - LEAL 4(SP), BX // argv - SUBL $128, SP // plenty of scratch - ANDL $~7, SP - MOVL AX, 120(SP) // save argc, argv away - MOVL BX, 124(SP) - -/* - // write "go386\n" - PUSHL $6 - PUSHL $hello(SB) - PUSHL $1 - CALL sys·write(SB) - POPL AX - POPL AX - POPL AX -*/ - - CALL ldt0setup(SB) - - // set up %fs to refer to that ldt entry - MOVL $(7*8+7), AX - MOVW AX, FS - - // store through it, to make sure it works - MOVL $0x123, 0(FS) - MOVL tls0(SB), AX - CMPL AX, $0x123 - JEQ ok - MOVL AX, 0 -ok: - - // set up m and g "registers" - // g is 0(FS), m is 4(FS) - LEAL g0(SB), CX - MOVL CX, 0(FS) - LEAL m0(SB), AX - MOVL AX, 4(FS) - - // save m->g0 = g0 - MOVL CX, 0(AX) - - // create istack out of the OS stack - LEAL (-8192+104)(SP), AX // TODO: 104? - MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) - MOVL SP, 4(CX) // 12(g) is base - CALL emptyfunc(SB) // fault if stack check is wrong - - // convention is D is always cleared - CLD - - CALL check(SB) - - // saved argc, argv - MOVL 120(SP), AX - MOVL AX, 0(SP) - MOVL 124(SP), AX - MOVL AX, 4(SP) - CALL args(SB) - CALL osinit(SB) - CALL schedinit(SB) - - // create a new goroutine to start program - PUSHL $mainstart(SB) // entry - PUSHL $8 // arg size - CALL sys·newproc(SB) - POPL AX - POPL AX - - // start this M - CALL mstart(SB) - - INT $3 - RET - -TEXT mainstart(SB),7,$0 - CALL main·init(SB) - CALL initdone(SB) - CALL main·main(SB) - PUSHL $0 - CALL exit(SB) - POPL AX - INT $3 - RET - -TEXT breakpoint(SB),7,$0 - BYTE $0xcc - RET - -// go-routine -TEXT gogo(SB), 7, $0 - MOVL 4(SP), AX // gobuf - MOVL 0(AX), SP // restore SP - MOVL 4(AX), AX - MOVL AX, 0(SP) // put PC on the stack - MOVL $1, AX - RET - -TEXT gosave(SB), 7, $0 - MOVL 4(SP), AX // gobuf - MOVL SP, 0(AX) // save SP - MOVL 0(SP), BX - MOVL BX, 4(AX) // save PC - MOVL $0, AX // return 0 - RET - -// support for morestack - -// return point when leaving new stack. -// save AX, jmp to lesstack to switch back -TEXT retfromnewstack(SB),7,$0 - MOVL 4(FS), BX // m - MOVL AX, 12(BX) // save AX in m->cret - JMP lessstack(SB) - -// gogo, returning 2nd arg instead of 1 -TEXT gogoret(SB), 7, $0 - MOVL 8(SP), AX // return 2nd arg - MOVL 4(SP), BX // gobuf - MOVL 0(BX), SP // restore SP - MOVL 4(BX), BX - MOVL BX, 0(SP) // put PC on the stack - RET - -TEXT setspgoto(SB), 7, $0 - MOVL 4(SP), AX // SP - MOVL 8(SP), BX // fn to call - MOVL 12(SP), CX // fn to return - MOVL AX, SP - PUSHL CX - JMP BX - POPL AX // not reached - RET - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// }else -// return 0; -TEXT cas(SB), 7, $0 - MOVL 4(SP), BX - MOVL 8(SP), AX - MOVL 12(SP), CX - LOCK - CMPXCHGL CX, 0(BX) - JZ 3(PC) - MOVL $0, AX - RET - MOVL $1, AX - RET - -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes from the callers return -// 3. jmp to the argument -TEXT jmpdefer(SB), 7, $0 - MOVL 4(SP), AX // fn - MOVL 8(SP), BX // caller sp - LEAL -4(BX), SP // caller sp after CALL - SUBL $5, (SP) // return to CALL again - JMP AX // but first run the deferred function - -TEXT sys·memclr(SB),7,$0 - MOVL 4(SP), DI // arg 1 addr - MOVL 8(SP), CX // arg 2 count - ADDL $3, CX - SHRL $2, CX - MOVL $0, AX - CLD - REP - STOSL - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVL x+0(FP),AX // addr of first arg - MOVL -4(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(SB),7,$0 - MOVL x+0(FP),AX // addr of first arg - MOVL x+4(FP), BX - MOVL BX, -4(AX) // set calling pc - RET - -TEXT ldt0setup(SB),7,$16 - // set up ldt 7 to point at tls0 - // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go. - MOVL $7, 0(SP) - LEAL tls0(SB), AX - MOVL AX, 4(SP) - MOVL $32, 8(SP) // sizeof(tls array) - CALL setldt(SB) - RET - -GLOBL m0+0(SB), $1024 -GLOBL g0+0(SB), $1024 - -GLOBL tls0+0(SB), $32 - -TEXT emptyfunc(SB),0,$0 - RET - -TEXT abort(SB),7,$0 - INT $0x3 - -DATA hello+0(SB)/8, $"go386\n\z\z" -GLOBL hello+0(SB), $8 - diff --git a/src/lib/runtime/386/closure.c b/src/lib/runtime/386/closure.c deleted file mode 100644 index 6ccbe3b8b..000000000 --- a/src/lib/runtime/386/closure.c +++ /dev/null @@ -1,104 +0,0 @@ -// 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" - -#pragma textflag 7 -// func closure(siz int32, -// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy, -// arg0, arg1, arg2 *ptr) (func(xxx) yyy) -void -sys·closure(int32 siz, byte *fn, byte *arg0) -{ - byte *p, *q, **ret; - int32 i, n; - int32 pcrel; - - if(siz < 0 || siz%4 != 0) - throw("bad closure size"); - - ret = (byte**)((byte*)&arg0 + siz); - - if(siz > 100) { - // TODO(rsc): implement stack growth preamble? - throw("closure too big"); - } - - // compute size of new fn. - // must match code laid out below. - n = 6+5+2+1; // SUBL MOVL MOVL CLD - if(siz <= 4*4) - n += 1*siz/4; // MOVSL MOVSL... - else - n += 6+2; // MOVL REP MOVSL - n += 5; // CALL - n += 6+1; // ADDL RET - - // store args aligned after code, so gc can find them. - n += siz; - if(n%4) - n += 4 - n%4; - - p = mal(n); - *ret = p; - q = p + n - siz; - mcpy(q, (byte*)&arg0, siz); - - // SUBL $siz, SP - *p++ = 0x81; - *p++ = 0xec; - *(uint32*)p = siz; - p += 4; - - // MOVL $q, SI - *p++ = 0xbe; - *(byte**)p = q; - p += 4; - - // MOVL SP, DI - *p++ = 0x89; - *p++ = 0xe7; - - // CLD - *p++ = 0xfc; - - if(siz <= 4*4) { - for(i=0; i<siz; i+=4) { - // MOVSL - *p++ = 0xa5; - } - } else { - // MOVL $(siz/4), CX [32-bit immediate siz/4] - *p++ = 0xc7; - *p++ = 0xc1; - *(uint32*)p = siz/4; - p += 4; - - // REP; MOVSL - *p++ = 0xf3; - *p++ = 0xa5; - } - - // call fn - pcrel = fn - (p+5); - // direct call with pc-relative offset - // CALL fn - *p++ = 0xe8; - *(int32*)p = pcrel; - p += 4; - - // ADDL $siz, SP - *p++ = 0x81; - *p++ = 0xc4; - *(uint32*)p = siz; - p += 4; - - // RET - *p++ = 0xc3; - - if(p > q) - throw("bad math in sys.closure"); -} - - diff --git a/src/lib/runtime/386/traceback.c b/src/lib/runtime/386/traceback.c deleted file mode 100644 index 05724d9ac..000000000 --- a/src/lib/runtime/386/traceback.c +++ /dev/null @@ -1,148 +0,0 @@ -// 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" - -// TODO(rsc): Move this into portable code, with calls to a -// machine-dependent isclosure() function. - -void -traceback(byte *pc0, byte *sp, G *g) -{ - Stktop *stk; - uintptr pc; - int32 i, n; - Func *f; - byte *p; - - pc = (uintptr)pc0; - - // If the PC is zero, it's likely a nil function call. - // Start in the caller's frame. - if(pc == 0) { - pc = *(uintptr*)sp; - sp += sizeof(uintptr); - } - - stk = (Stktop*)g->stackbase; - for(n=0; n<100; n++) { - while(pc == (uintptr)retfromnewstack) { - // pop to earlier stack block - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uintptr*)(sp+sizeof(uintptr)); - sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call - } - f = findfunc(pc); - if(f == nil) { - // dangerous, but poke around to see if it is a closure - p = (byte*)pc; - // ADDL $xxx, SP; RET - if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { - sp += *(uint32*)(p+2) + 8; - pc = *(uintptr*)(sp - 8); - if(pc <= 0x1000) - return; - continue; - } - printf("%p unknown pc\n", pc); - return; - } - if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie - sp += sizeof(uintptr); - else - sp += f->frame; - - // print this frame - // main+0xf /home/rsc/go/src/runtime/x.go:23 - // main(0x1, 0x2, 0x3) - printf("%S", f->name); - if(pc > f->entry) - printf("+%p", (uintptr)(pc - f->entry)); - printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. - printf("\t%S(", f->name); - for(i = 0; i < f->args; i++) { - if(i != 0) - prints(", "); - sys·printhex(((uint32*)sp)[i]); - if(i >= 4) { - prints(", ..."); - break; - } - } - prints(")\n"); - - pc = *(uintptr*)(sp-sizeof(uintptr)); - if(pc <= 0x1000) - return; - } - prints("...\n"); -} - -// func caller(n int) (pc uintptr, file string, line int, ok bool) -void -runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool) -{ - uintptr pc; - byte *sp; - byte *p; - Stktop *stk; - Func *f; - - // our caller's pc, sp. - sp = (byte*)&n; - pc = *((uintptr*)sp - 1); - if((f = findfunc(pc)) == nil) { - error: - retpc = 0; - retline = 0; - retfile = emptystring; - retbool = false; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); - return; - } - - // now unwind n levels - stk = (Stktop*)g->stackbase; - while(n-- > 0) { - while(pc == (uintptr)retfromnewstack) { - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *((uintptr*)sp + 1); - sp += 2*sizeof(uintptr); - } - - if(f->frame < sizeof(uintptr)) // assembly functions lie - sp += sizeof(uintptr); - else - sp += f->frame; - - loop: - pc = *((uintptr*)sp - 1); - if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { - // dangerous, but let's try this. - // see if it is a closure. - p = (byte*)pc; - // ADDL $xxx, SP; RET - if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { - sp += *(uint32*)(p+2) + sizeof(uintptr); - goto loop; - } - goto error; - } - } - - retpc = pc; - retfile = f->src; - retline = funcline(f, pc-1); - retbool = true; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); -} - diff --git a/src/lib/runtime/386/vlop.s b/src/lib/runtime/386/vlop.s deleted file mode 100755 index 803276ce2..000000000 --- a/src/lib/runtime/386/vlop.s +++ /dev/null @@ -1,48 +0,0 @@ -// Inferno's libkern/vlop-386.s -// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. -// Portions Copyright 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/* - * C runtime for 64-bit divide. - */ - -TEXT _mul64by32(SB), 7, $0 - MOVL r+0(FP), CX - MOVL a+4(FP), AX - MULL b+12(FP) - MOVL AX, 0(CX) - MOVL DX, BX - MOVL a+8(FP), AX - MULL b+12(FP) - ADDL AX, BX - MOVL BX, 4(CX) - RET - -TEXT _div64by32(SB), 7, $0 - MOVL r+12(FP), CX - MOVL a+0(FP), AX - MOVL a+4(FP), DX - DIVL b+8(FP) - MOVL DX, 0(CX) - RET diff --git a/src/lib/runtime/386/vlrt.c b/src/lib/runtime/386/vlrt.c deleted file mode 100755 index 093cca70d..000000000 --- a/src/lib/runtime/386/vlrt.c +++ /dev/null @@ -1,815 +0,0 @@ -// Inferno's libkern/vlrt-386.c -// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. -// Portions Copyright 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/* - * C runtime for 64-bit divide, others. - * - * TODO(rsc): The simple functions are dregs--8c knows how - * to generate the code directly now. Find and remove. - */ - -typedef unsigned long ulong; -typedef unsigned int uint; -typedef unsigned short ushort; -typedef unsigned char uchar; -typedef signed char schar; - -#define SIGN(n) (1UL<<(n-1)) - -typedef struct Vlong Vlong; -struct Vlong -{ - union - { - long long v; - struct - { - ulong lo; - ulong hi; - }; - struct - { - ushort lols; - ushort loms; - ushort hils; - ushort hims; - }; - }; -}; - -void abort(void); - -void -_d2v(Vlong *y, double d) -{ - union { double d; struct Vlong; } x; - ulong xhi, xlo, ylo, yhi; - int sh; - - x.d = d; - - xhi = (x.hi & 0xfffff) | 0x100000; - xlo = x.lo; - sh = 1075 - ((x.hi >> 20) & 0x7ff); - - ylo = 0; - yhi = 0; - if(sh >= 0) { - /* v = (hi||lo) >> sh */ - if(sh < 32) { - if(sh == 0) { - ylo = xlo; - yhi = xhi; - } else { - ylo = (xlo >> sh) | (xhi << (32-sh)); - yhi = xhi >> sh; - } - } else { - if(sh == 32) { - ylo = xhi; - } else - if(sh < 64) { - ylo = xhi >> (sh-32); - } - } - } else { - /* v = (hi||lo) << -sh */ - sh = -sh; - if(sh <= 10) { - ylo = xlo << sh; - yhi = (xhi << sh) | (xlo >> (32-sh)); - } else { - /* overflow */ - yhi = d; /* causes something awful */ - } - } - if(x.hi & SIGN(32)) { - if(ylo != 0) { - ylo = -ylo; - yhi = ~yhi; - } else - yhi = -yhi; - } - - y->hi = yhi; - y->lo = ylo; -} - -void -_f2v(Vlong *y, float f) -{ - - _d2v(y, f); -} - -double -_v2d(Vlong x) -{ - if(x.hi & SIGN(32)) { - if(x.lo) { - x.lo = -x.lo; - x.hi = ~x.hi; - } else - x.hi = -x.hi; - return -((long)x.hi*4294967296. + x.lo); - } - return (long)x.hi*4294967296. + x.lo; -} - -float -_v2f(Vlong x) -{ - return _v2d(x); -} - -ulong _div64by32(Vlong, ulong, ulong*); -void _mul64by32(Vlong*, Vlong, ulong); - -static void -slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) -{ - ulong numlo, numhi, denhi, denlo, quohi, quolo, t; - int i; - - numhi = num.hi; - numlo = num.lo; - denhi = den.hi; - denlo = den.lo; - - /* - * get a divide by zero - */ - if(denlo==0 && denhi==0) { - numlo = numlo / denlo; - } - - /* - * set up the divisor and find the number of iterations needed - */ - if(numhi >= SIGN(32)) { - quohi = SIGN(32); - quolo = 0; - } else { - quohi = numhi; - quolo = numlo; - } - i = 0; - while(denhi < quohi || (denhi == quohi && denlo < quolo)) { - denhi = (denhi<<1) | (denlo>>31); - denlo <<= 1; - i++; - } - - quohi = 0; - quolo = 0; - for(; i >= 0; i--) { - quohi = (quohi<<1) | (quolo>>31); - quolo <<= 1; - if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { - t = numlo; - numlo -= denlo; - if(numlo > t) - numhi--; - numhi -= denhi; - quolo |= 1; - } - denlo = (denlo>>1) | (denhi<<31); - denhi >>= 1; - } - - if(q) { - q->lo = quolo; - q->hi = quohi; - } - if(r) { - r->lo = numlo; - r->hi = numhi; - } -} - -static void -dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) -{ - ulong n; - Vlong x, q, r; - - if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ - if(qp) { - qp->hi = 0; - qp->lo = 0; - } - if(rp) { - rp->hi = num.hi; - rp->lo = num.lo; - } - return; - } - - if(den.hi != 0){ - q.hi = 0; - n = num.hi/den.hi; - _mul64by32(&x, den, n); - if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) - slowdodiv(num, den, &q, &r); - else { - q.lo = n; - r.v = num.v - x.v; - } - } else { - if(num.hi >= den.lo){ - q.hi = n = num.hi/den.lo; - num.hi -= den.lo*n; - } else { - q.hi = 0; - } - q.lo = _div64by32(num, den.lo, &r.lo); - r.hi = 0; - } - if(qp) { - qp->lo = q.lo; - qp->hi = q.hi; - } - if(rp) { - rp->lo = r.lo; - rp->hi = r.hi; - } -} - -void -_divvu(Vlong *q, Vlong n, Vlong d) -{ - - if(n.hi == 0 && d.hi == 0) { - q->hi = 0; - q->lo = n.lo / d.lo; - return; - } - dodiv(n, d, q, 0); -} - -void -sys·uint64div(Vlong n, Vlong d, Vlong q) -{ - _divvu(&q, n, d); -} - -void -_modvu(Vlong *r, Vlong n, Vlong d) -{ - - if(n.hi == 0 && d.hi == 0) { - r->hi = 0; - r->lo = n.lo % d.lo; - return; - } - dodiv(n, d, 0, r); -} - -void -sys·uint64mod(Vlong n, Vlong d, Vlong q) -{ - _modvu(&q, n, d); -} - -static void -vneg(Vlong *v) -{ - - if(v->lo == 0) { - v->hi = -v->hi; - return; - } - v->lo = -v->lo; - v->hi = ~v->hi; -} - -void -_divv(Vlong *q, Vlong n, Vlong d) -{ - long nneg, dneg; - - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - if((long)n.lo == -0x80000000 && (long)d.lo == -1) { - // special case: 32-bit -0x80000000 / -1 causes divide error, - // but it's okay in this 64-bit context. - q->lo = 0x80000000; - q->hi = 0; - return; - } - q->lo = (long)n.lo / (long)d.lo; - q->hi = ((long)q->lo) >> 31; - return; - } - nneg = n.hi >> 31; - if(nneg) - vneg(&n); - dneg = d.hi >> 31; - if(dneg) - vneg(&d); - dodiv(n, d, q, 0); - if(nneg != dneg) - vneg(q); -} - -void -sys·int64div(Vlong n, Vlong d, Vlong q) -{ - _divv(&q, n, d); -} - -void -_modv(Vlong *r, Vlong n, Vlong d) -{ - long nneg, dneg; - - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - if((long)n.lo == -0x80000000 && (long)d.lo == -1) { - // special case: 32-bit -0x80000000 % -1 causes divide error, - // but it's okay in this 64-bit context. - r->lo = 0; - r->hi = 0; - return; - } - r->lo = (long)n.lo % (long)d.lo; - r->hi = ((long)r->lo) >> 31; - return; - } - nneg = n.hi >> 31; - if(nneg) - vneg(&n); - dneg = d.hi >> 31; - if(dneg) - vneg(&d); - dodiv(n, d, 0, r); - if(nneg) - vneg(r); -} - -void -sys·int64mod(Vlong n, Vlong d, Vlong q) -{ - _modv(&q, n, d); -} - -void -_rshav(Vlong *r, Vlong a, int b) -{ - long t; - - t = a.hi; - if(b >= 32) { - r->hi = t>>31; - if(b >= 64) { - /* this is illegal re C standard */ - r->lo = t>>31; - return; - } - r->lo = t >> (b-32); - return; - } - if(b <= 0) { - r->hi = t; - r->lo = a.lo; - return; - } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); -} - -void -_rshlv(Vlong *r, Vlong a, int b) -{ - ulong t; - - t = a.hi; - if(b >= 32) { - r->hi = 0; - if(b >= 64) { - /* this is illegal re C standard */ - r->lo = 0; - return; - } - r->lo = t >> (b-32); - return; - } - if(b <= 0) { - r->hi = t; - r->lo = a.lo; - return; - } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); -} - -void -_lshv(Vlong *r, Vlong a, int b) -{ - ulong t; - - t = a.lo; - if(b >= 32) { - r->lo = 0; - if(b >= 64) { - /* this is illegal re C standard */ - r->hi = 0; - return; - } - r->hi = t << (b-32); - return; - } - if(b <= 0) { - r->lo = t; - r->hi = a.hi; - return; - } - r->lo = t << b; - r->hi = (t >> (32-b)) | (a.hi << b); -} - -void -_andv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi & b.hi; - r->lo = a.lo & b.lo; -} - -void -_orv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi | b.hi; - r->lo = a.lo | b.lo; -} - -void -_xorv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi ^ b.hi; - r->lo = a.lo ^ b.lo; -} - -void -_vpp(Vlong *l, Vlong *r) -{ - - l->hi = r->hi; - l->lo = r->lo; - r->lo++; - if(r->lo == 0) - r->hi++; -} - -void -_vmm(Vlong *l, Vlong *r) -{ - - l->hi = r->hi; - l->lo = r->lo; - if(r->lo == 0) - r->hi--; - r->lo--; -} - -void -_ppv(Vlong *l, Vlong *r) -{ - - r->lo++; - if(r->lo == 0) - r->hi++; - l->hi = r->hi; - l->lo = r->lo; -} - -void -_mmv(Vlong *l, Vlong *r) -{ - - if(r->lo == 0) - r->hi--; - r->lo--; - l->hi = r->hi; - l->lo = r->lo; -} - -void -_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) -{ - Vlong t, u; - - u.lo = 0; - u.hi = 0; - switch(type) { - default: - abort(); - break; - - case 1: /* schar */ - t.lo = *(schar*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(schar*)lv = u.lo; - break; - - case 2: /* uchar */ - t.lo = *(uchar*)lv; - t.hi = 0; - fn(&u, t, rv); - *(uchar*)lv = u.lo; - break; - - case 3: /* short */ - t.lo = *(short*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(short*)lv = u.lo; - break; - - case 4: /* ushort */ - t.lo = *(ushort*)lv; - t.hi = 0; - fn(&u, t, rv); - *(ushort*)lv = u.lo; - break; - - case 9: /* int */ - t.lo = *(int*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(int*)lv = u.lo; - break; - - case 10: /* uint */ - t.lo = *(uint*)lv; - t.hi = 0; - fn(&u, t, rv); - *(uint*)lv = u.lo; - break; - - case 5: /* long */ - t.lo = *(long*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(long*)lv = u.lo; - break; - - case 6: /* ulong */ - t.lo = *(ulong*)lv; - t.hi = 0; - fn(&u, t, rv); - *(ulong*)lv = u.lo; - break; - - case 7: /* vlong */ - case 8: /* uvlong */ - fn(&u, *(Vlong*)lv, rv); - *(Vlong*)lv = u; - break; - } - *ret = u; -} - -void -_p2v(Vlong *ret, void *p) -{ - long t; - - t = (ulong)p; - ret->lo = t; - ret->hi = 0; -} - -void -_sl2v(Vlong *ret, long sl) -{ - long t; - - t = sl; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_ul2v(Vlong *ret, ulong ul) -{ - long t; - - t = ul; - ret->lo = t; - ret->hi = 0; -} - -void -_si2v(Vlong *ret, int si) -{ - long t; - - t = si; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_ui2v(Vlong *ret, uint ui) -{ - long t; - - t = ui; - ret->lo = t; - ret->hi = 0; -} - -void -_sh2v(Vlong *ret, long sh) -{ - long t; - - t = (sh << 16) >> 16; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_uh2v(Vlong *ret, ulong ul) -{ - long t; - - t = ul & 0xffff; - ret->lo = t; - ret->hi = 0; -} - -void -_sc2v(Vlong *ret, long uc) -{ - long t; - - t = (uc << 24) >> 24; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_uc2v(Vlong *ret, ulong ul) -{ - long t; - - t = ul & 0xff; - ret->lo = t; - ret->hi = 0; -} - -long -_v2sc(Vlong rv) -{ - long t; - - t = rv.lo & 0xff; - return (t << 24) >> 24; -} - -long -_v2uc(Vlong rv) -{ - - return rv.lo & 0xff; -} - -long -_v2sh(Vlong rv) -{ - long t; - - t = rv.lo & 0xffff; - return (t << 16) >> 16; -} - -long -_v2uh(Vlong rv) -{ - - return rv.lo & 0xffff; -} - -long -_v2sl(Vlong rv) -{ - - return rv.lo; -} - -long -_v2ul(Vlong rv) -{ - - return rv.lo; -} - -long -_v2si(Vlong rv) -{ - - return rv.lo; -} - -long -_v2ui(Vlong rv) -{ - - return rv.lo; -} - -int -_testv(Vlong rv) -{ - return rv.lo || rv.hi; -} - -int -_eqv(Vlong lv, Vlong rv) -{ - return lv.lo == rv.lo && lv.hi == rv.hi; -} - -int -_nev(Vlong lv, Vlong rv) -{ - return lv.lo != rv.lo || lv.hi != rv.hi; -} - -int -_ltv(Vlong lv, Vlong rv) -{ - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); -} - -int -_lev(Vlong lv, Vlong rv) -{ - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); -} - -int -_gtv(Vlong lv, Vlong rv) -{ - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); -} - -int -_gev(Vlong lv, Vlong rv) -{ - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); -} - -int -_lov(Vlong lv, Vlong rv) -{ - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); -} - -int -_lsv(Vlong lv, Vlong rv) -{ - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); -} - -int -_hiv(Vlong lv, Vlong rv) -{ - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); -} - -int -_hsv(Vlong lv, Vlong rv) -{ - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); -} diff --git a/src/lib/runtime/Makefile b/src/lib/runtime/Makefile deleted file mode 100644 index 5a5ace9c5..000000000 --- a/src/lib/runtime/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -# 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. - -# Set SIZE to 32 or 64. -SIZE_386=32 -SIZE_amd64=64 -SIZE_arm=32 -SIZE=$(SIZE_$(GOARCH)) - -# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry). -CFLAGS_64=-D_64BIT -CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) - -# Set O to right letter. -O_386=8 -O_amd64=6 -O_arm=5 -O=$(O_$(GOARCH)) - -# Tools -CC=$(O)c -GC=$(O)g -AS=$(O)a -AR=gopack - -LIB=runtime.a - -# 386-specific object files -OFILES_386=\ - vlop.$O\ - vlrt.$O\ - -OFILES=\ - array.$O\ - asm.$O\ - chan.$O\ - closure.$O\ - extern.$O\ - float.$O\ - float_go.$O\ - hashmap.$O\ - iface.$O\ - malloc.$O\ - malloc_go.$O\ - mcache.$O\ - mcentral.$O\ - mem.$O\ - mfixalloc.$O\ - mgc0.$O\ - mheap.$O\ - mheapmap$(SIZE).$O\ - msize.$O\ - print.$O\ - proc.$O\ - rune.$O\ - runtime.$O\ - rt0.$O\ - sema.$O\ - sema_go.$O\ - signal.$O\ - string.$O\ - symtab.$O\ - sys.$O\ - thread.$O\ - traceback.$O\ - $(OFILES_$(GOARCH))\ - -HFILES=\ - runtime.h\ - hashmap.h\ - malloc.h\ - $(GOOS)/os.h\ - $(GOOS)/$(GOARCH)/defs.h\ - -install: $(LIB) runtime.acid - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH) - cp $(LIB) $(GOROOT)/pkg/$(GOOS)_$(GOARCH)/$(LIB) - cp runtime.acid $(GOROOT)/acid/runtime.acid - -$(LIB): $(OFILES) - $(AR) grc $(LIB) $(OFILES) - -$(OFILES): $(HFILES) - -nuke: - rm -f *.[568] *.a $(GOROOT)/lib/$(LIB) - -clean: - rm -f *.[568] *.a runtime.acid cgo2c - -%.$O: %.go - $(GC) $< - -%.$O: %.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOARCH)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/$(GOARCH)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOARCH)/%.s - $(AS) $< - -%.$O: $(GOOS)/$(GOARCH)/%.s - $(AS) $< - -cgo2c: cgo2c.c - quietgcc -o $@ $< - -%.c: %.cgo cgo2c - ./cgo2c $< > $@.tmp - mv -f $@.tmp $@ - -runtime.acid: runtime.h proc.c - $(CC) -a proc.c >runtime.acid - -chan.acid: runtime.h chan.c - $(CC) -a chan.c >chan.acid - diff --git a/src/lib/runtime/amd64/asm.s b/src/lib/runtime/amd64/asm.s deleted file mode 100644 index 6fc01bbc9..000000000 --- a/src/lib/runtime/amd64/asm.s +++ /dev/null @@ -1,207 +0,0 @@ -// 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. - - -TEXT _rt0_amd64(SB),7,$-8 - - // copy arguments forward on an even stack - - MOVQ 0(SP), AX // argc - LEAQ 8(SP), BX // argv - SUBQ $(4*8+7), SP // 2args 2auto - ANDQ $~7, SP - MOVQ AX, 16(SP) - MOVQ BX, 24(SP) - - // set the per-goroutine and per-mach registers - - LEAQ m0(SB), R14 // dedicated m. register - LEAQ g0(SB), R15 // dedicated g. register - MOVQ R15, 0(R14) // m has pointer to its g0 - - // create istack out of the given (operating system) stack - - LEAQ (-8192+104)(SP), AX - MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard) - MOVQ SP, 8(R15) // 8(R15) is base - - CLD // convention is D is always left cleared - CALL check(SB) - - MOVL 16(SP), AX // copy argc - MOVL AX, 0(SP) - MOVQ 24(SP), AX // copy argv - MOVQ AX, 8(SP) - CALL args(SB) - CALL osinit(SB) - CALL schedinit(SB) - - // create a new goroutine to start program - PUSHQ $mainstart(SB) // entry - PUSHQ $16 // arg size - CALL sys·newproc(SB) - POPQ AX - POPQ AX - - // start this M - CALL mstart(SB) - - CALL notok(SB) // never returns - RET - -TEXT mainstart(SB),7,$0 - CALL main·init(SB) - CALL initdone(SB) - CALL main·main(SB) - PUSHQ $0 - CALL exit(SB) - POPQ AX - CALL notok(SB) - RET - -TEXT breakpoint(SB),7,$0 - BYTE $0xcc - RET - -/* - * go-routine - */ -TEXT gogo(SB), 7, $0 - MOVQ 8(SP), AX // gobuf - MOVQ 0(AX), SP // restore SP - MOVQ 8(AX), AX - MOVQ AX, 0(SP) // put PC on the stack - MOVL $1, AX // return 1 - RET - -TEXT gosave(SB), 7, $0 - MOVQ 8(SP), AX // gobuf - MOVQ SP, 0(AX) // save SP - MOVQ 0(SP), BX - MOVQ BX, 8(AX) // save PC - MOVL $0, AX // return 0 - RET - -/* - * support for morestack - */ - -// morestack trampolines -TEXT sys·morestack00+0(SB),7,$0 - MOVQ $0, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack01+0(SB),7,$0 - SHLQ $32, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack10+0(SB),7,$0 - MOVLQZX AX, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack11+0(SB),7,$0 - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestackx(SB),7,$0 - POPQ AX - SHLQ $35, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack(SB), AX - JMP AX - -// subcases of morestack01 -// with const of 8,16,...48 -TEXT sys·morestack8(SB),7,$0 - PUSHQ $1 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack16(SB),7,$0 - PUSHQ $2 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack24(SB),7,$0 - PUSHQ $3 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack32(SB),7,$0 - PUSHQ $4 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack40(SB),7,$0 - PUSHQ $5 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack48(SB),7,$0 - PUSHQ $6 - MOVQ $sys·morestackx(SB), AX - JMP AX - -// return point when leaving new stack. save AX, jmp to lessstack to switch back -TEXT retfromnewstack(SB), 7, $0 - MOVQ AX, 16(R14) // save AX in m->cret - MOVQ $lessstack(SB), AX - JMP AX - -// gogo, returning 2nd arg instead of 1 -TEXT gogoret(SB), 7, $0 - MOVQ 16(SP), AX // return 2nd arg - MOVQ 8(SP), BX // gobuf - MOVQ 0(BX), SP // restore SP - MOVQ 8(BX), BX - MOVQ BX, 0(SP) // put PC on the stack - RET - -TEXT setspgoto(SB), 7, $0 - MOVQ 8(SP), AX // SP - MOVQ 16(SP), BX // fn to call - MOVQ 24(SP), CX // fn to return - MOVQ AX, SP - PUSHQ CX - JMP BX - POPQ AX // not reached - RET - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// } else -// return 0; -TEXT cas(SB), 7, $0 - MOVQ 8(SP), BX - MOVL 16(SP), AX - MOVL 20(SP), CX - LOCK - CMPXCHGL CX, 0(BX) - JZ 3(PC) - MOVL $0, AX - RET - MOVL $1, AX - RET - -// void jmpdefer(fn, sp); -// called from deferreturn. -// 1. pop the caller -// 2. sub 5 bytes from the callers return -// 3. jmp to the argument -TEXT jmpdefer(SB), 7, $0 - MOVQ 8(SP), AX // fn - MOVQ 16(SP), BX // caller sp - LEAQ -8(BX), SP // caller sp after CALL - SUBQ $5, (SP) // return to CALL again - JMP AX // but first run the deferred function diff --git a/src/lib/runtime/amd64/closure.c b/src/lib/runtime/amd64/closure.c deleted file mode 100644 index 5717d3c5e..000000000 --- a/src/lib/runtime/amd64/closure.c +++ /dev/null @@ -1,121 +0,0 @@ -// 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" - -#pragma textflag 7 -// func closure(siz int32, -// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy, -// arg0, arg1, arg2 *ptr) (func(xxx) yyy) -void -sys·closure(int32 siz, byte *fn, byte *arg0) -{ - byte *p, *q, **ret; - int32 i, n; - int64 pcrel; - - if(siz < 0 || siz%8 != 0) - throw("bad closure size"); - - ret = (byte**)((byte*)&arg0 + siz); - - if(siz > 100) { - // TODO(rsc): implement stack growth preamble? - throw("closure too big"); - } - - // compute size of new fn. - // must match code laid out below. - n = 7+10+3; // SUBQ MOVQ MOVQ - if(siz <= 4*8) - n += 2*siz/8; // MOVSQ MOVSQ... - else - n += 7+3; // MOVQ REP MOVSQ - n += 12; // CALL worst case; sometimes only 5 - n += 7+1; // ADDQ RET - - // store args aligned after code, so gc can find them. - n += siz; - if(n%8) - n += 8 - n%8; - - p = mal(n); - *ret = p; - q = p + n - siz; - mcpy(q, (byte*)&arg0, siz); - - // SUBQ $siz, SP - *p++ = 0x48; - *p++ = 0x81; - *p++ = 0xec; - *(uint32*)p = siz; - p += 4; - - // MOVQ $q, SI - *p++ = 0x48; - *p++ = 0xbe; - *(byte**)p = q; - p += 8; - - // MOVQ SP, DI - *p++ = 0x48; - *p++ = 0x89; - *p++ = 0xe7; - - if(siz <= 4*8) { - for(i=0; i<siz; i+=8) { - // MOVSQ - *p++ = 0x48; - *p++ = 0xa5; - } - } else { - // MOVQ $(siz/8), CX [32-bit immediate siz/8] - *p++ = 0x48; - *p++ = 0xc7; - *p++ = 0xc1; - *(uint32*)p = siz/8; - p += 4; - - // REP; MOVSQ - *p++ = 0xf3; - *p++ = 0x48; - *p++ = 0xa5; - } - - - // call fn - pcrel = fn - (p+5); - if((int32)pcrel == pcrel) { - // can use direct call with pc-relative offset - // CALL fn - *p++ = 0xe8; - *(int32*)p = pcrel; - p += 4; - } else { - // MOVQ $fn, CX [64-bit immediate fn] - *p++ = 0x48; - *p++ = 0xb9; - *(byte**)p = fn; - p += 8; - - // CALL *CX - *p++ = 0xff; - *p++ = 0xd1; - } - - // ADDQ $siz, SP - *p++ = 0x48; - *p++ = 0x81; - *p++ = 0xc4; - *(uint32*)p = siz; - p += 4; - - // RET - *p++ = 0xc3; - - if(p > q) - throw("bad math in sys.closure"); -} - - diff --git a/src/lib/runtime/amd64/traceback.c b/src/lib/runtime/amd64/traceback.c deleted file mode 100644 index 16d7bed72..000000000 --- a/src/lib/runtime/amd64/traceback.c +++ /dev/null @@ -1,146 +0,0 @@ -// 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" - -void -traceback(byte *pc0, byte *sp, G *g) -{ - Stktop *stk; - uint64 pc; - int32 i, n; - Func *f; - byte *p; - - pc = (uint64)pc0; - - // If the PC is zero, it's likely a nil function call. - // Start in the caller's frame. - if(pc == 0) { - pc = *(uint64*)sp; - sp += 8; - } - - stk = (Stktop*)g->stackbase; - for(n=0; n<100; n++) { - while(pc == (uint64)retfromnewstack) { - // pop to earlier stack block - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uint64*)(sp+8); - sp += 16; // two irrelevant calls on stack: morestack plus its call - } - f = findfunc(pc); - if(f == nil) { - // dangerous, but poke around to see if it is a closure - p = (byte*)pc; - // ADDQ $xxx, SP; RET - if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - pc = *(uint64*)(sp - 8); - if(pc <= 0x1000) - return; - continue; - } - printf("%p unknown pc\n", pc); - return; - } - if(f->frame < 8) // assembly funcs say 0 but lie - sp += 8; - else - sp += f->frame; - - // print this frame - // main+0xf /home/rsc/go/src/runtime/x.go:23 - // main(0x1, 0x2, 0x3) - printf("%S", f->name); - if(pc > f->entry) - printf("+%X", pc - f->entry); - printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. - printf("\t%S(", f->name); - for(i = 0; i < f->args; i++) { - if(i != 0) - prints(", "); - sys·printhex(((uint32*)sp)[i]); - if(i >= 4) { - prints(", ..."); - break; - } - } - prints(")\n"); - - pc = *(uint64*)(sp-8); - if(pc <= 0x1000) - return; - } - prints("...\n"); -} - -// func caller(n int) (pc uint64, file string, line int, ok bool) -void -runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool) -{ - uint64 pc; - byte *sp; - byte *p; - Stktop *stk; - Func *f; - - // our caller's pc, sp. - sp = (byte*)&n; - pc = *(uint64*)(sp-8); - if((f = findfunc(pc)) == nil) { - error: - retpc = 0; - retline = 0; - retfile = emptystring; - retbool = false; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); - return; - } - - // now unwind n levels - stk = (Stktop*)g->stackbase; - while(n-- > 0) { - while(pc == (uint64)retfromnewstack) { - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uint64*)(sp+8); - sp += 16; - } - - if(f->frame < 8) // assembly functions lie - sp += 8; - else - sp += f->frame; - - loop: - pc = *(uint64*)(sp-8); - if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { - // dangerous, but let's try this. - // see if it is a closure. - p = (byte*)pc; - // ADDQ $xxx, SP; RET - if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - goto loop; - } - goto error; - } - } - - retpc = pc; - retfile = f->src; - retline = funcline(f, pc-1); - retbool = true; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); -} - - diff --git a/src/lib/runtime/arm/asm.s b/src/lib/runtime/arm/asm.s deleted file mode 100644 index 232ab4ddf..000000000 --- a/src/lib/runtime/arm/asm.s +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -TEXT _rt0_arm(SB),7,$0 - // copy arguments forward on an even stack - // MOVW $0(SP), R0 - // MOVL 0(SP), R1 // argc -// LEAL 4(SP), R1 // argv -// SUBL $128, SP // plenty of scratch -// ANDL $~7, SP -// MOVL AX, 120(SP) // save argc, argv away -// MOVL BX, 124(SP) - - -// // write "go386\n" -// PUSHL $6 -// PUSHL $hello(SB) -// PUSHL $1 -// CALL sys·write(SB) -// POPL AX -// POPL AX -// POPL AX - - -// CALL ldt0setup(SB) - - // set up %fs to refer to that ldt entry -// MOVL $(7*8+7), AX -// MOVW AX, FS - -// // store through it, to make sure it works -// MOVL $0x123, 0(FS) -// MOVL tls0(SB), AX -// CMPL AX, $0x123 -// JEQ ok -// MOVL AX, 0 -// ok: - -// // set up m and g "registers" -// // g is 0(FS), m is 4(FS) -// LEAL g0(SB), CX -// MOVL CX, 0(FS) -// LEAL m0(SB), AX -// MOVL AX, 4(FS) - -// // save m->g0 = g0 -// MOVL CX, 0(AX) - -// // create istack out of the OS stack -// LEAL (-8192+104)(SP), AX // TODO: 104? -// MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) -// MOVL SP, 4(CX) // 12(g) is base -// CALL emptyfunc(SB) // fault if stack check is wrong - -// // convention is D is always cleared -// CLD - -// CALL check(SB) - -// // saved argc, argv -// MOVL 120(SP), AX -// MOVL AX, 0(SP) -// MOVL 124(SP), AX -// MOVL AX, 4(SP) -// CALL args(SB) -// CALL osinit(SB) -// CALL schedinit(SB) - -// // create a new goroutine to start program -// PUSHL $mainstart(SB) // entry -// PUSHL $8 // arg size -// CALL sys·newproc(SB) -// POPL AX -// POPL AX - -// // start this M -// CALL mstart(SB) - - BL main�main(SB) - MOVW $99, R0 - SWI $0x00900001 - diff --git a/src/lib/runtime/arm/closure.c b/src/lib/runtime/arm/closure.c deleted file mode 100644 index 024018d5a..000000000 --- a/src/lib/runtime/arm/closure.c +++ /dev/null @@ -1,4 +0,0 @@ -// 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. - diff --git a/src/lib/runtime/arm/traceback.s b/src/lib/runtime/arm/traceback.s deleted file mode 100644 index e69de29bb..000000000 --- a/src/lib/runtime/arm/traceback.s +++ /dev/null diff --git a/src/lib/runtime/array.c b/src/lib/runtime/array.c deleted file mode 100644 index bbd57b03e..000000000 --- a/src/lib/runtime/array.c +++ /dev/null @@ -1,175 +0,0 @@ -// 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" - -static int32 debug = 0; - -// newarray(nel int, cap int, width int) (ary []any); -void -sys·newarray(uint32 nel, uint32 cap, uint32 width, Array ret) -{ - uint64 size; - - if(cap < nel) - cap = nel; - size = cap*width; - - ret.nel = nel; - ret.cap = cap; - ret.array = mal(size); - - FLUSH(&ret); - - if(debug) { - prints("newarray: nel="); - sys·printint(nel); - prints("; cap="); - sys·printint(cap); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -static void -throwslice(uint32 lb, uint32 hb, uint32 n) -{ - prints("slice["); - sys·printint(lb); - prints(":"); - sys·printint(hb); - prints("] of ["); - sys·printint(n); - prints("] array\n"); - throw("array slice"); -} - -// arraysliced(old []any, lb int, hb int, width int) (ary []any); -void -sys·arraysliced(Array old, uint32 lb, uint32 hb, uint32 width, Array ret) -{ - - if(hb > old.cap || lb > hb) { - if(debug) { - prints("sys·arraysliced: old="); - sys·printarray(old); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("\n"); - - prints("oldarray: nel="); - sys·printint(old.nel); - prints("; cap="); - sys·printint(old.cap); - prints("\n"); - } - throwslice(lb, hb, old.cap); - } - - // new array is inside old array - ret.nel = hb-lb; - ret.cap = old.cap - lb; - ret.array = old.array + lb*width; - - FLUSH(&ret); - - if(debug) { - prints("sys·arraysliced: old="); - sys·printarray(old); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any); -void -sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array ret) -{ - - if(hb > nel || lb > hb) { - if(debug) { - prints("sys·arrayslices: old="); - sys·printpointer(old); - prints("; nel="); - sys·printint(nel); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("\n"); - } - throwslice(lb, hb, nel); - } - - // new array is inside old array - ret.nel = hb-lb; - ret.cap = nel-lb; - ret.array = old + lb*width; - - FLUSH(&ret); - - if(debug) { - prints("sys·arrayslices: old="); - sys·printpointer(old); - prints("; nel="); - sys·printint(nel); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -// arrays2d(old *any, nel int) (ary []any) -void -sys·arrays2d(byte* old, uint32 nel, Array ret) -{ - - // new dope to old array - ret.nel = nel; - ret.cap = nel; - ret.array = old; - - FLUSH(&ret); - - if(debug) { - prints("sys·arrays2d: old="); - sys·printpointer(old); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -void -sys·printarray(Array a) -{ - prints("["); - sys·printint(a.nel); - prints("/"); - sys·printint(a.cap); - prints("]"); - sys·printpointer(a.array); -} diff --git a/src/lib/runtime/cgo2c.c b/src/lib/runtime/cgo2c.c deleted file mode 100644 index 3905f7e6d..000000000 --- a/src/lib/runtime/cgo2c.c +++ /dev/null @@ -1,602 +0,0 @@ -// 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. - -/* Translate a .cgo file into a .c file. A .cgo file is a combination - of a limited form of Go with C. */ - -/* - package PACKAGENAME - {# line} - func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{ - C code with proper brace nesting - \} -*/ - -/* We generate C code which implements the function such that it can - be called from Go and executes the C code. */ - -#include <assert.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -/* Whether we're emitting for gcc */ -static int gcc; - -/* File and line number */ -static const char *file; -static unsigned int lineno; - -/* List of names and types. */ -struct params { - struct params *next; - char *name; - char *type; -}; - -/* Unexpected EOF. */ -static void -bad_eof(void) -{ - fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno); - exit(1); -} - -/* Out of memory. */ -static void -bad_mem(void) -{ - fprintf(stderr, "%s:%u: out of memory\n", file, lineno); - exit(1); -} - -/* Allocate memory without fail. */ -static void * -xmalloc(unsigned int size) -{ - void *ret = malloc(size); - if (ret == NULL) - bad_mem(); - return ret; -} - -/* Reallocate memory without fail. */ -static void* -xrealloc(void *buf, unsigned int size) -{ - void *ret = realloc(buf, size); - if (ret == NULL) - bad_mem(); - return ret; -} - -/* Free a list of parameters. */ -static void -free_params(struct params *p) -{ - while (p != NULL) { - struct params *next; - - next = p->next; - free(p->name); - free(p->type); - free(p); - p = next; - } -} - -/* Read a character, tracking lineno. */ -static int -getchar_update_lineno(void) -{ - int c; - - c = getchar(); - if (c == '\n') - ++lineno; - return c; -} - -/* Read a character, giving an error on EOF, tracking lineno. */ -static int -getchar_no_eof(void) -{ - int c; - - c = getchar_update_lineno(); - if (c == EOF) - bad_eof(); - return c; -} - -/* Read a character, skipping comments. */ -static int -getchar_skipping_comments(void) -{ - int c; - - while (1) { - c = getchar_update_lineno(); - if (c != '/') - return c; - - c = getchar(); - if (c == '/') { - do { - c = getchar_update_lineno(); - } while (c != EOF && c != '\n'); - return c; - } else if (c == '*') { - while (1) { - c = getchar_update_lineno(); - if (c == EOF) - return EOF; - if (c == '*') { - do { - c = getchar_update_lineno(); - } while (c == '*'); - if (c == '/') - break; - } - } - } else { - ungetc(c, stdin); - return '/'; - } - } -} - -/* Read and return a token. Tokens are delimited by whitespace or by - [(),{}]. The latter are all returned as single characters. */ -static char * -read_token(void) -{ - int c; - char *buf; - unsigned int alc, off; - const char* delims = "(),{}"; - - while (1) { - c = getchar_skipping_comments(); - if (c == EOF) - return NULL; - if (!isspace(c)) - break; - } - alc = 16; - buf = xmalloc(alc + 1); - off = 0; - if (strchr(delims, c) != NULL) { - buf[off] = c; - ++off; - } else { - while (1) { - if (off >= alc) { - alc *= 2; - buf = xrealloc(buf, alc + 1); - } - buf[off] = c; - ++off; - c = getchar_skipping_comments(); - if (c == EOF) - break; - if (isspace(c) || strchr(delims, c) != NULL) { - ungetc(c, stdin); - break; - } - } - } - buf[off] = '\0'; - return buf; -} - -/* Read a token, giving an error on EOF. */ -static char * -read_token_no_eof(void) -{ - char *token = read_token(); - if (token == NULL) - bad_eof(); - return token; -} - -/* Read the package clause, and return the package name. */ -static char * -read_package(void) -{ - char *token; - - token = read_token_no_eof(); - if (strcmp(token, "package") != 0) { - fprintf(stderr, - "%s:%u: expected \"package\", got \"%s\"\n", - file, lineno, token); - exit(1); - } - return read_token_no_eof(); -} - -/* Read and copy preprocessor lines. */ -static void -read_preprocessor_lines(void) -{ - while (1) { - int c; - - do { - c = getchar_skipping_comments(); - } while (isspace(c)); - if (c != '#') { - ungetc(c, stdin); - return; - } - putchar(c); - do { - c = getchar_update_lineno(); - putchar(c); - } while (c != '\n'); - } -} - -/* Read a type in Go syntax and return a type in C syntax. We only - permit basic types and pointers. */ -static char * -read_type(void) -{ - char *p, *op, *q; - int pointer_count; - unsigned int len; - - p = read_token_no_eof(); - if (*p != '*') - return p; - op = p; - pointer_count = 0; - while (*p == '*') { - ++pointer_count; - ++p; - } - len = strlen(p); - q = xmalloc(len + pointer_count + 1); - memcpy(q, p, len); - while (pointer_count > 0) { - q[len] = '*'; - ++len; - --pointer_count; - } - q[len] = '\0'; - free(op); - return q; -} - -/* Read a list of parameters. Each parameter is a name and a type. - The list ends with a ')'. We have already read the '('. */ -static struct params * -read_params(void) -{ - char *token; - struct params *ret, **pp; - - ret = NULL; - pp = &ret; - token = read_token_no_eof(); - if (strcmp(token, ")") != 0) { - while (1) { - *pp = xmalloc(sizeof(struct params)); - (*pp)->name = token; - (*pp)->type = read_type(); - pp = &(*pp)->next; - *pp = NULL; - - token = read_token_no_eof(); - if (strcmp(token, ",") != 0) - break; - token = read_token_no_eof(); - } - } - if (strcmp(token, ")") != 0) { - fprintf(stderr, "%s:%u: expected '('\n", - file, lineno); - exit(1); - } - return ret; -} - -/* Read a function header. This reads up to and including the initial - '{' character. Returns 1 if it read a header, 0 at EOF. */ -static int -read_func_header(char **name, struct params **params, struct params **rets) -{ - char *token; - - token = read_token(); - if (token == NULL) - return 0; - if (strcmp(token, "func") != 0) { - fprintf(stderr, "%s:%u: expected \"func\"\n", - file, lineno); - exit(1); - } - *name = read_token_no_eof(); - - token = read_token(); - if (token == NULL || strcmp(token, "(") != 0) { - fprintf(stderr, "%s:%u: expected \"(\"\n", - file, lineno); - exit(1); - } - *params = read_params(); - - token = read_token(); - if (token == NULL || strcmp(token, "(") != 0) - *rets = NULL; - else { - *rets = read_params(); - token = read_token(); - } - if (token == NULL || strcmp(token, "{") != 0) { - fprintf(stderr, "%s:%u: expected \"{\"\n", - file, lineno); - exit(1); - } - return 1; -} - -/* Write out parameters. */ -static void -write_params(struct params *params, int *first) -{ - struct params *p; - - for (p = params; p != NULL; p = p->next) { - if (*first) - *first = 0; - else - printf(", "); - printf("%s %s", p->type, p->name); - } -} - -/* Write a 6g function header. */ -static void -write_6g_func_header(char *package, char *name, struct params *params, - struct params *rets) -{ - int first; - - printf("void\n%s·%s(", package, name); - first = 1; - write_params(params, &first); - write_params(rets, &first); - printf(")\n{\n"); -} - -/* Write a 6g function trailer. */ -static void -write_6g_func_trailer(struct params *rets) -{ - struct params *p; - - for (p = rets; p != NULL; p = p->next) - printf("\tFLUSH(&%s);\n", p->name); - printf("}\n"); -} - -/* Define the gcc function return type if necessary. */ -static void -define_gcc_return_type(char *package, char *name, struct params *rets) -{ - struct params *p; - - if (rets == NULL || rets->next == NULL) - return; - printf("struct %s_%s_ret {\n", package, name); - for (p = rets; p != NULL; p = p->next) - printf(" %s %s;\n", p->type, p->name); - printf("};\n"); -} - -/* Write out the gcc function return type. */ -static void -write_gcc_return_type(char *package, char *name, struct params *rets) -{ - if (rets == NULL) - printf("void"); - else if (rets->next == NULL) - printf("%s", rets->type); - else - printf("struct %s_%s_ret", package, name); -} - -/* Write out a gcc function header. */ -static void -write_gcc_func_header(char *package, char *name, struct params *params, - struct params *rets) -{ - int first; - struct params *p; - - define_gcc_return_type(package, name, rets); - write_gcc_return_type(package, name, rets); - printf(" %s_%s(", package, name); - first = 1; - write_params(params, &first); - printf(") asm (\"%s.%s\");\n", package, name); - write_gcc_return_type(package, name, rets); - printf(" %s_%s(", package, name); - first = 1; - write_params(params, &first); - printf(")\n{\n"); - for (p = rets; p != NULL; p = p->next) - printf(" %s %s;\n", p->type, p->name); -} - -/* Write out a gcc function trailer. */ -static void -write_gcc_func_trailer(char *package, char *name, struct params *rets) -{ - if (rets == NULL) - ; - else if (rets->next == NULL) - printf("return %s;\n", rets->name); - else { - struct params *p; - - printf(" {\n struct %s_%s_ret __ret;\n", package, name); - for (p = rets; p != NULL; p = p->next) - printf(" __ret.%s = %s;\n", p->name, p->name); - printf(" return __ret;\n }\n"); - } - printf("}\n"); -} - -/* Write out a function header. */ -static void -write_func_header(char *package, char *name, - struct params *params, struct params *rets) -{ - if (gcc) - write_gcc_func_header(package, name, params, rets); - else - write_6g_func_header(package, name, params, rets); - printf("#line %d \"%s\"\n", lineno, file); -} - -/* Write out a function trailer. */ -static void -write_func_trailer(char *package, char *name, - struct params *rets) -{ - if (gcc) - write_gcc_func_trailer(package, name, rets); - else - write_6g_func_trailer(rets); -} - -/* Read and write the body of the function, ending in an unnested } - (which is read but not written). */ -static void -copy_body(void) -{ - int nesting = 0; - while (1) { - int c; - - c = getchar_no_eof(); - if (c == '}' && nesting == 0) - return; - putchar(c); - switch (c) { - default: - break; - case '{': - ++nesting; - break; - case '}': - --nesting; - break; - case '/': - c = getchar_update_lineno(); - putchar(c); - if (c == '/') { - do { - c = getchar_no_eof(); - putchar(c); - } while (c != '\n'); - } else if (c == '*') { - while (1) { - c = getchar_no_eof(); - putchar(c); - if (c == '*') { - do { - c = getchar_no_eof(); - putchar(c); - } while (c == '*'); - if (c == '/') - break; - } - } - } - break; - case '"': - case '\'': - { - int delim = c; - do { - c = getchar_no_eof(); - putchar(c); - if (c == '\\') { - c = getchar_no_eof(); - putchar(c); - c = '\0'; - } - } while (c != delim); - } - break; - } - } -} - -/* Process the entire file. */ -static void -process_file(void) -{ - char *package, *name; - struct params *params, *rets; - - package = read_package(); - read_preprocessor_lines(); - while (read_func_header(&name, ¶ms, &rets)) { - write_func_header(package, name, params, rets); - copy_body(); - write_func_trailer(package, name, rets); - free(name); - free_params(params); - free_params(rets); - } - free(package); -} - -static void -usage(void) -{ - fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n"); - exit(1); -} - -int -main(int argc, char **argv) -{ - while(argc > 1 && argv[1][0] == '-') { - if(strcmp(argv[1], "-") == 0) - break; - if(strcmp(argv[1], "--6g") == 0) - gcc = 0; - else if(strcmp(argv[1], "--gcc") == 0) - gcc = 1; - else - usage(); - argc--; - argv++; - } - - if(argc <= 1 || strcmp(argv[1], "-") == 0) { - file = "<stdin>"; - process_file(); - return 0; - } - - if(argc > 2) - usage(); - - file = argv[1]; - if(freopen(file, "r", stdin) == 0) { - fprintf(stderr, "open %s: %s\n", file, strerror(errno)); - exit(1); - } - process_file(); - return 0; -} diff --git a/src/lib/runtime/chan.c b/src/lib/runtime/chan.c deleted file mode 100644 index be65bcbc1..000000000 --- a/src/lib/runtime/chan.c +++ /dev/null @@ -1,1024 +0,0 @@ -// 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" - -static int32 debug = 0; -static Lock chanlock; - -enum -{ - Wclosed = 0x0001, // writer has closed - Rclosed = 0x0002, // reader has seen close - Eincr = 0x0004, // increment errors - Emax = 0x0800, // error limit before throw -}; - -typedef struct Hchan Hchan; -typedef struct Link Link; -typedef struct WaitQ WaitQ; -typedef struct SudoG SudoG; -typedef struct Select Select; -typedef struct Scase Scase; - -struct SudoG -{ - G* g; // g and selgen constitute - int32 selgen; // a weak pointer to g - int16 offset; // offset of case number - int8 isfree; // offset of case number - SudoG* link; - byte elem[8]; // synch data element (+ more) -}; - -struct WaitQ -{ - SudoG* first; - SudoG* last; -}; - -struct Hchan -{ - uint16 elemsize; - uint16 closed; // Wclosed Rclosed errorcount - uint32 dataqsiz; // size of the circular q - uint32 qcount; // total data in the q - Alg* elemalg; // interface for element type - Link* senddataq; // pointer for sender - Link* recvdataq; // pointer for receiver - WaitQ recvq; // list of recv waiters - WaitQ sendq; // list of send waiters - SudoG* free; // freelist -}; - -struct Link -{ - Link* link; // asynch queue circular linked list - byte elem[8]; // asynch queue data element (+ more) -}; - -struct Scase -{ - Hchan* chan; // chan - byte* pc; // return pc - uint16 send; // 0-recv 1-send 2-default - uint16 so; // vararg of selected bool - union { - byte elem[8]; // element (send) - byte* elemp; // pointer to element (recv) - } u; -}; - -struct Select -{ - uint16 tcase; // total count of scase[] - uint16 ncase; // currently filled scase[] - Select* link; // for freelist - Scase* scase[1]; // one per case -}; - -static Select* selfree[20]; - -static SudoG* dequeue(WaitQ*, Hchan*); -static void enqueue(WaitQ*, SudoG*); -static SudoG* allocsg(Hchan*); -static void freesg(Hchan*, SudoG*); -static uint32 gcd(uint32, uint32); -static uint32 fastrand1(void); -static uint32 fastrand2(void); - -// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any); -void -sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint, - Hchan* ret) -{ - Hchan *c; - int32 i; - - if(elemalg >= nelem(algarray)) { - printf("chan(alg=%d)\n", elemalg); - throw("sys·newchan: unsupported elem type"); - } - - c = mal(sizeof(*c)); - - c->elemsize = elemsize; - c->elemalg = &algarray[elemalg]; - - if(hint > 0) { - Link *d, *b, *e; - - // make a circular q - b = nil; - e = nil; - for(i=0; i<hint; i++) { - d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem)); - if(e == nil) - e = d; - d->link = b; - b = d; - } - e->link = b; - c->recvdataq = b; - c->senddataq = b; - c->qcount = 0; - c->dataqsiz = hint; - } - - ret = c; - FLUSH(&ret); - - if(debug) { - prints("newchan: chan="); - sys·printpointer(c); - prints("; elemsize="); - sys·printint(elemsize); - prints("; elemalg="); - sys·printint(elemalg); - prints("; dataqsiz="); - sys·printint(c->dataqsiz); - prints("\n"); - } -} - -static void -incerr(Hchan* c) -{ - c->closed += Eincr; - if(c->closed & Emax) { - unlock(&chanlock); - throw("too many operations on a closed channel"); - } -} - -/* - * generic single channel send/recv - * if the bool pointer is nil, - * then the full exchange will - * occur. if pres is not nil, - * then the protocol will not - * sleep but return if it could - * not complete - */ -void -sendchan(Hchan *c, byte *ep, bool *pres) -{ - SudoG *sg; - G* gp; - - if(debug) { - prints("chansend: chan="); - sys·printpointer(c); - prints("; elem="); - c->elemalg->print(c->elemsize, ep); - prints("\n"); - } - - lock(&chanlock); -loop: - if(c->closed & Wclosed) - goto closed; - - if(c->dataqsiz > 0) - goto asynch; - - sg = dequeue(&c->recvq, c); - if(sg != nil) { - if(ep != nil) - c->elemalg->copy(c->elemsize, sg->elem, ep); - - gp = sg->g; - gp->param = sg; - unlock(&chanlock); - ready(gp); - - if(pres != nil) - *pres = true; - return; - } - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - - sg = allocsg(c); - if(ep != nil) - c->elemalg->copy(c->elemsize, sg->elem, ep); - g->param = nil; - g->status = Gwaiting; - enqueue(&c->sendq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - freesg(c, sg); - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -asynch: - if(c->closed & Wclosed) - goto closed; - - if(c->qcount >= c->dataqsiz) { - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - sg = allocsg(c); - g->status = Gwaiting; - enqueue(&c->sendq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - goto asynch; - } - if(ep != nil) - c->elemalg->copy(c->elemsize, c->senddataq->elem, ep); - c->senddataq = c->senddataq->link; - c->qcount++; - - sg = dequeue(&c->recvq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - unlock(&chanlock); - ready(gp); - } else - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -closed: - incerr(c); - if(pres != nil) - *pres = true; - unlock(&chanlock); -} - -static void -chanrecv(Hchan* c, byte *ep, bool* pres) -{ - SudoG *sg; - G *gp; - - if(debug) { - prints("chanrecv: chan="); - sys·printpointer(c); - prints("\n"); - } - - lock(&chanlock); -loop: - if(c->dataqsiz > 0) - goto asynch; - - if(c->closed & Wclosed) - goto closed; - - sg = dequeue(&c->sendq, c); - if(sg != nil) { - c->elemalg->copy(c->elemsize, ep, sg->elem); - - gp = sg->g; - gp->param = sg; - unlock(&chanlock); - ready(gp); - - if(pres != nil) - *pres = true; - return; - } - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - - sg = allocsg(c); - g->param = nil; - g->status = Gwaiting; - enqueue(&c->recvq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - - c->elemalg->copy(c->elemsize, ep, sg->elem); - freesg(c, sg); - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -asynch: - if(c->qcount <= 0) { - if(c->closed & Wclosed) - goto closed; - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - sg = allocsg(c); - g->status = Gwaiting; - enqueue(&c->recvq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - goto asynch; - } - c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); - c->recvdataq = c->recvdataq->link; - c->qcount--; - sg = dequeue(&c->sendq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - unlock(&chanlock); - ready(gp); - if(pres != nil) - *pres = true; - return; - } - - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -closed: - c->elemalg->copy(c->elemsize, ep, nil); - c->closed |= Rclosed; - incerr(c); - if(pres != nil) - *pres = true; - unlock(&chanlock); -} - -// chansend1(hchan *chan any, elem any); -void -sys·chansend1(Hchan* c, ...) -{ - int32 o; - byte *ae; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - sendchan(c, ae, nil); -} - -// chansend2(hchan *chan any, elem any) (pres bool); -void -sys·chansend2(Hchan* c, ...) -{ - int32 o; - byte *ae, *ap; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - o = rnd(o+c->elemsize, 1); - ap = (byte*)&c + o; - - sendchan(c, ae, ap); -} - -// chanrecv1(hchan *chan any) (elem any); -void -sys·chanrecv1(Hchan* c, ...) -{ - int32 o; - byte *ae; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - - chanrecv(c, ae, nil); -} - -// chanrecv2(hchan *chan any) (elem any, pres bool); -void -sys·chanrecv2(Hchan* c, ...) -{ - int32 o; - byte *ae, *ap; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - o = rnd(o+c->elemsize, 1); - ap = (byte*)&c + o; - - chanrecv(c, ae, ap); -} - -// chanrecv3(hchan *chan any, elem *any) (pres bool); -void -sys·chanrecv3(Hchan* c, byte* ep, byte pres) -{ - chanrecv(c, ep, &pres); -} - -// newselect(size uint32) (sel *byte); -void -sys·newselect(int32 size, Select *sel) -{ - int32 n; - - n = 0; - if(size > 1) - n = size-1; - - lock(&chanlock); - sel = nil; - if(size >= 1 && size < nelem(selfree)) { - sel = selfree[size]; - if(sel != nil) - selfree[size] = sel->link; - } - unlock(&chanlock); - if(sel == nil) - sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0])); - - sel->tcase = size; - sel->ncase = 0; - FLUSH(&sel); - if(debug) { - prints("newselect s="); - sys·printpointer(sel); - prints(" size="); - sys·printint(size); - prints("\n"); - } -} - -// selectsend(sel *byte, hchan *chan any, elem any) (selected bool); -void -sys·selectsend(Select *sel, Hchan *c, ...) -{ - int32 i, eo; - Scase *cas; - byte *ae; - - // nil cases do not compete - if(c == nil) - return; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectsend: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); - sel->scase[i] = cas; - } - - cas->pc = sys·getcallerpc(&sel); - cas->chan = c; - - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), c->elemsize); - cas->so = rnd(eo+c->elemsize, 1); - cas->send = 1; - - ae = (byte*)&sel + eo; - c->elemalg->copy(c->elemsize, cas->u.elem, ae); - - if(debug) { - prints("selectsend s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" chan="); - sys·printpointer(cas->chan); - prints(" po="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - -// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); -void -sys·selectrecv(Select *sel, Hchan *c, ...) -{ - int32 i, eo; - Scase *cas; - - // nil cases do not compete - if(c == nil) - return; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectrecv: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas); - sel->scase[i] = cas; - } - cas->pc = sys·getcallerpc(&sel); - cas->chan = c; - - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), sizeof(byte*)); - cas->so = rnd(eo+sizeof(byte*), 1); - cas->send = 0; - cas->u.elemp = *(byte**)((byte*)&sel + eo); - - if(debug) { - prints("selectrecv s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" chan="); - sys·printpointer(cas->chan); - prints(" so="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - - -// selectdefaul(sel *byte) (selected bool); -void -sys·selectdefault(Select *sel, ...) -{ - int32 i; - Scase *cas; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectdefault: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas); - sel->scase[i] = cas; - } - cas->pc = sys·getcallerpc(&sel); - cas->chan = nil; - - cas->so = rnd(sizeof(sel), 1); - cas->send = 2; - cas->u.elemp = nil; - - if(debug) { - prints("selectdefault s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" so="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - -// selectgo(sel *byte); -void -sys·selectgo(Select *sel) -{ - uint32 p, o, i; - Scase *cas, *dfl; - Hchan *c; - SudoG *sg; - G *gp; - byte *as; - - if(debug) { - prints("selectgo: sel="); - sys·printpointer(sel); - prints("\n"); - } - - if(sel->ncase < 2) { - if(sel->ncase < 1) - throw("selectgo: no cases"); - // make special case of one. - } - - // select a (relative) prime - for(i=0;; i++) { - p = fastrand1(); - if(gcd(p, sel->ncase) == 1) - break; - if(i > 1000) { - throw("selectgo: failed to select prime"); - } - } - - // select an initial offset - o = fastrand2(); - - p %= sel->ncase; - o %= sel->ncase; - - lock(&chanlock); - -loop: - // pass 1 - look for something already waiting - dfl = nil; - for(i=0; i<sel->ncase; i++) { - cas = sel->scase[o]; - - if(cas->send == 2) { // default - dfl = cas; - goto next1; - } - - c = cas->chan; - if(c->dataqsiz > 0) { - if(cas->send) { - if(c->closed & Wclosed) - goto sclose; - if(c->qcount < c->dataqsiz) - goto asyns; - goto next1; - } - if(c->qcount > 0) - goto asynr; - if(c->closed & Wclosed) - goto rclose; - goto next1; - } - - if(cas->send) { - if(c->closed & Wclosed) - goto sclose; - sg = dequeue(&c->recvq, c); - if(sg != nil) - goto gots; - goto next1; - } - sg = dequeue(&c->sendq, c); - if(sg != nil) - goto gotr; - if(c->closed & Wclosed) - goto rclose; - - next1: - o += p; - if(o >= sel->ncase) - o -= sel->ncase; - } - - if(dfl != nil) { - cas = dfl; - goto retc; - } - - - // pass 2 - enqueue on all chans - for(i=0; i<sel->ncase; i++) { - cas = sel->scase[o]; - c = cas->chan; - - if(c->dataqsiz > 0) { - if(cas->send) { - if(c->qcount < c->dataqsiz) { - prints("selectgo: pass 2 async send\n"); - goto asyns; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->sendq, sg); - goto next2; - } - if(c->qcount > 0) { - prints("selectgo: pass 2 async recv\n"); - goto asynr; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->recvq, sg); - goto next2; - } - - if(cas->send) { - sg = dequeue(&c->recvq, c); - if(sg != nil) { - prints("selectgo: pass 2 sync send\n"); - g->selgen++; - goto gots; - } - sg = allocsg(c); - sg->offset = o; - c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); - enqueue(&c->sendq, sg); - goto next2; - } - sg = dequeue(&c->sendq, c); - if(sg != nil) { - prints("selectgo: pass 2 sync recv\n"); - g->selgen++; - goto gotr; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->recvq, sg); - - next2: - o += p; - if(o >= sel->ncase) - o -= sel->ncase; - } - - g->param = nil; - g->status = Gwaiting; - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - - o = sg->offset; - cas = sel->scase[o]; - c = cas->chan; - - if(c->dataqsiz > 0) { -// prints("shouldnt happen\n"); - goto loop; - } - - if(debug) { - prints("wait-return: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" cas="); - sys·printpointer(cas); - prints(" send="); - sys·printint(cas->send); - prints(" o="); - sys·printint(o); - prints("\n"); - } - - if(!cas->send) { - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); - } - - freesg(c, sg); - goto retc; - -asynr: - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem); - c->recvdataq = c->recvdataq->link; - c->qcount--; - sg = dequeue(&c->sendq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - ready(gp); - } - goto retc; - -asyns: - if(cas->u.elem != nil) - c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem); - c->senddataq = c->senddataq->link; - c->qcount++; - sg = dequeue(&c->recvq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - ready(gp); - } - goto retc; - -gotr: - // recv path to wakeup the sender (sg) - if(debug) { - prints("gotr: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" o="); - sys·printint(o); - prints("\n"); - } - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); - gp = sg->g; - gp->param = sg; - ready(gp); - goto retc; - -rclose: - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, nil); - c->closed |= Rclosed; - incerr(c); - goto retc; - -gots: - // send path to wakeup the receiver (sg) - if(debug) { - prints("gots: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" o="); - sys·printint(o); - prints("\n"); - } - if(c->closed & Wclosed) - goto sclose; - c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); - gp = sg->g; - gp->param = sg; - ready(gp); - goto retc; - -sclose: - incerr(c); - goto retc; - -retc: - if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) { - sel->link = selfree[sel->ncase]; - selfree[sel->ncase] = sel; - } - unlock(&chanlock); - - sys·setcallerpc(&sel, cas->pc); - as = (byte*)&sel + cas->so; - *as = true; -} - -// closechan(sel *byte); -void -sys·closechan(Hchan *c) -{ - SudoG *sg; - G* gp; - - lock(&chanlock); - incerr(c); - c->closed |= Wclosed; - - // release all readers - for(;;) { - sg = dequeue(&c->recvq, c); - if(sg == nil) - break; - gp = sg->g; - gp->param = nil; - freesg(c, sg); - ready(gp); - } - - // release all writers - for(;;) { - sg = dequeue(&c->sendq, c); - if(sg == nil) - break; - gp = sg->g; - gp->param = nil; - freesg(c, sg); - ready(gp); - } - - unlock(&chanlock); -} - -// closedchan(sel *byte) bool; -void -sys·closedchan(Hchan *c, bool closed) -{ - // test Rclosed - closed = 0; - if(c->closed & Rclosed) - closed = 1; - FLUSH(&closed); -} - -static SudoG* -dequeue(WaitQ *q, Hchan *c) -{ - SudoG *sgp; - -loop: - sgp = q->first; - if(sgp == nil) - return nil; - q->first = sgp->link; - - // if sgp is stale, ignore it - if(sgp->selgen != sgp->g->selgen) { - //prints("INVALID PSEUDOG POINTER\n"); - freesg(c, sgp); - goto loop; - } - - // invalidate any others - sgp->g->selgen++; - return sgp; -} - -static void -enqueue(WaitQ *q, SudoG *sgp) -{ - sgp->link = nil; - if(q->first == nil) { - q->first = sgp; - q->last = sgp; - return; - } - q->last->link = sgp; - q->last = sgp; -} - -static SudoG* -allocsg(Hchan *c) -{ - SudoG* sg; - - sg = c->free; - if(sg != nil) { - c->free = sg->link; - } else - sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem)); - sg->selgen = g->selgen; - sg->g = g; - sg->offset = 0; - sg->isfree = 0; - - return sg; -} - -static void -freesg(Hchan *c, SudoG *sg) -{ - if(sg != nil) { - if(sg->isfree) - throw("chan.freesg: already free"); - sg->isfree = 1; - sg->link = c->free; - c->free = sg; - } -} - -static uint32 -gcd(uint32 u, uint32 v) -{ - for(;;) { - if(u > v) { - if(v == 0) - return u; - u = u%v; - continue; - } - if(u == 0) - return v; - v = v%u; - } -} - -static uint32 -fastrand1(void) -{ - static uint32 x = 0x49f6428aUL; - - x += x; - if(x & 0x80000000L) - x ^= 0x88888eefUL; - return x; -} - -static uint32 -fastrand2(void) -{ - static uint32 x = 0x49f6428aUL; - - x += x; - if(x & 0x80000000L) - x ^= 0xfafd871bUL; - return x; -} diff --git a/src/lib/runtime/darwin/386/defs.h b/src/lib/runtime/darwin/386/defs.h deleted file mode 100644 index b66a5d8b4..000000000 --- a/src/lib/runtime/darwin/386/defs.h +++ /dev/null @@ -1,229 +0,0 @@ -// godefs -f -m32 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, - MACH_MSG_TYPE_MOVE_SEND = 0x11, - MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, - MACH_MSG_TYPE_COPY_SEND = 0x13, - MACH_MSG_TYPE_MAKE_SEND = 0x14, - MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, - MACH_MSG_TYPE_COPY_RECEIVE = 0x16, - MACH_MSG_PORT_DESCRIPTOR = 0, - MACH_MSG_OOL_DESCRIPTOR = 0x1, - MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, - MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, - MACH_MSGH_BITS_COMPLEX = 0x80000000, - MACH_SEND_MSG = 0x1, - MACH_RCV_MSG = 0x2, - MACH_RCV_LARGE = 0x4, - MACH_SEND_TIMEOUT = 0x10, - MACH_SEND_INTERRUPT = 0x40, - MACH_SEND_CANCEL = 0x80, - MACH_SEND_ALWAYS = 0x10000, - MACH_SEND_TRAILER = 0x20000, - MACH_RCV_TIMEOUT = 0x100, - MACH_RCV_NOTIFY = 0x200, - MACH_RCV_INTERRUPT = 0x400, - MACH_RCV_OVERWRITE = 0x1000, - NDR_PROTOCOL_2_0 = 0, - NDR_INT_BIG_ENDIAN = 0, - NDR_INT_LITTLE_ENDIAN = 0x1, - NDR_FLOAT_IEEE = 0, - NDR_CHAR_ASCII = 0, - SA_SIGINFO = 0x40, - SA_RESTART = 0x2, - SA_ONSTACK = 0x1, - SA_USERTRAMP = 0x100, - SA_64REGSET = 0x200, -}; - -// Types -#pragma pack on - -typedef struct MachBody MachBody; -struct MachBody { - uint32 msgh_descriptor_count; -}; - -typedef struct MachHeader MachHeader; -struct MachHeader { - uint32 msgh_bits; - uint32 msgh_size; - uint32 msgh_remote_port; - uint32 msgh_local_port; - uint32 msgh_reserved; - int32 msgh_id; -}; - -typedef struct MachNDR MachNDR; -struct MachNDR { - uint8 mig_vers; - uint8 if_vers; - uint8 reserved1; - uint8 mig_encoding; - uint8 int_rep; - uint8 char_rep; - uint8 float_rep; - uint8 reserved2; -}; - -typedef struct MachPort MachPort; -struct MachPort { - uint32 name; - uint32 pad1; - uint16 pad2; - uint8 disposition; - uint8 type; -}; - -typedef struct StackT StackT; -struct StackT { - void *ss_sp; - uint32 ss_size; - int32 ss_flags; -}; - -typedef union Sighandler Sighandler; -union Sighandler { - void *__sa_handler; - void *__sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - void *sa_tramp; - uint32 sa_mask; - int32 sa_flags; -}; - -typedef union Sigval Sigval; -union Sigval { - int32 sival_int; - void *sival_ptr; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - int32 si_pid; - uint32 si_uid; - int32 si_status; - void *si_addr; - Sigval si_value; - int32 si_band; - uint32 __pad[7]; -}; - -typedef struct FPControl FPControl; -struct FPControl { - byte pad0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad0[2]; -}; - -typedef struct RegMMST RegMMST; -struct RegMMST { - int8 mmst_reg[10]; - int8 mmst_rsrv[6]; -}; - -typedef struct RegXMM RegXMM; -struct RegXMM { - int8 xmm_reg[16]; -}; - -typedef struct Regs Regs; -struct Regs { - uint32 eax; - uint32 ebx; - uint32 ecx; - uint32 edx; - uint32 edi; - uint32 esi; - uint32 ebp; - uint32 esp; - uint32 ss; - uint32 eflags; - uint32 eip; - uint32 cs; - uint32 ds; - uint32 es; - uint32 fs; - uint32 gs; -}; - -typedef struct FloatState FloatState; -struct FloatState { - int32 fpu_reserved[2]; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - int8 fpu_rsrv4[224]; - int32 fpu_reserved1; -}; - -typedef struct ExceptionState ExceptionState; -struct ExceptionState { - uint32 trapno; - uint32 err; - uint32 faultvaddr; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - ExceptionState es; - Regs ss; - FloatState fs; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - int32 uc_onstack; - uint32 uc_sigmask; - StackT uc_stack; - Ucontext *uc_link; - uint32 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/lib/runtime/darwin/386/rt0.s b/src/lib/runtime/darwin/386/rt0.s deleted file mode 100755 index 5b52e912c..000000000 --- a/src/lib/runtime/darwin/386/rt0.s +++ /dev/null @@ -1,8 +0,0 @@ -// 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. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_386_darwin(SB),7,$0 - JMP _rt0_386(SB) diff --git a/src/lib/runtime/darwin/386/signal.c b/src/lib/runtime/darwin/386/signal.c deleted file mode 100644 index 3a63c4b38..000000000 --- a/src/lib/runtime/darwin/386/signal.c +++ /dev/null @@ -1,103 +0,0 @@ -// 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" -#include "defs.h" -#include "os.h" -#include "signals.h" - -void -dumpregs(Regs *r) -{ - printf("eax %x\n", r->eax); - printf("ebx %x\n", r->ebx); - printf("ecx %x\n", r->ecx); - printf("edx %x\n", r->edx); - printf("edi %x\n", r->edi); - printf("esi %x\n", r->esi); - printf("ebp %x\n", r->ebp); - printf("esp %x\n", r->esp); - printf("eip %x\n", r->eip); - printf("eflags %x\n", r->eflags); - printf("cs %x\n", r->cs); - printf("fs %x\n", r->fs); - printf("gs %x\n", r->gs); -} - -void -sighandler(int32 sig, Siginfo *info, void *context) -{ - Ucontext *uc; - Mcontext *mc; - Regs *r; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - if(sig < 0 || sig >= NSIG){ - printf("Signal %d\n", sig); - }else{ - printf("%s\n", sigtab[sig].name); - } - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - printf("Faulting address: %p\n", info->si_addr); - printf("pc: %x\n", r->eip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)r->eip, (void*)r->esp, m->curg); - tracebackothers(m->curg); - dumpregs(r); - } - - breakpoint(); - exit(2); -} - -void -sigignore(int32, Siginfo*, void*) -{ -} - -void -signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - int32 i; - static Sigaction sa; - - sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; - sa.sa_mask = 0; // 0xFFFFFFFFU; - sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler - for(i = 0; i<NSIG; i++) { - if(sigtab[i].flags) { - if(sigtab[i].flags & SigCatch) { - sa.__sigaction_u.__sa_sigaction = sighandler; - } else { - sa.__sigaction_u.__sa_sigaction = sigignore; - } - if(sigtab[i].flags & SigRestart) - sa.sa_flags |= SA_RESTART; - else - sa.sa_flags &= ~SA_RESTART; - sigaction(i, &sa, nil); - } - } -} - diff --git a/src/lib/runtime/darwin/386/sys.s b/src/lib/runtime/darwin/386/sys.s deleted file mode 100644 index bbcb622d5..000000000 --- a/src/lib/runtime/darwin/386/sys.s +++ /dev/null @@ -1,278 +0,0 @@ -// 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. - -// System calls and other sys.stuff for 386, Darwin -// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 -// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. - -TEXT notok(SB),7,$0 - MOVL $0xf1, 0xf1 - RET - -// Exit the entire program (like C exit) -TEXT exit(SB),7,$0 - MOVL $1, AX - INT $0x80 - CALL notok(SB) - RET - -// Exit this OS thread (like pthread_exit, which eventually -// calls __bsdthread_terminate). -TEXT exit1(SB),7,$0 - MOVL $361, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -TEXT sys·write(SB),7,$0 - MOVL $4, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -TEXT sys·mmap(SB),7,$0 - MOVL $197, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -TEXT sigaction(SB),7,$0 - MOVL $46, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -// Sigtramp's job is to call the actual signal handler. -// It is called with the following arguments on the stack: -// 0(FP) "return address" - ignored -// 4(FP) actual handler -// 8(FP) siginfo style - ignored -// 12(FP) signal number -// 16(FP) siginfo -// 20(FP) context -TEXT sigtramp(SB),7,$40 - MOVL 4(FS), BP // m - MOVL 28(BP), BP // m->gsignal - MOVL BP, 0(FS) // g = m->gsignal - - MOVL handler+4(FP), DI - MOVL signo+12(FP), AX - MOVL siginfo+16(FP), BX - MOVL context+20(FP), CX - - MOVL AX, 0(SP) - MOVL BX, 4(SP) - MOVL CX, 8(SP) - CALL DI - - MOVL context+20(FP), CX - MOVL style+8(FP), BX - - MOVL $0, 0(SP) // "caller PC" - ignored - MOVL CX, 4(SP) - MOVL BX, 8(SP) - MOVL $184, AX // sigreturn(ucontext, infostyle) - INT $0x80 - CALL notok(SB) - RET - -TEXT sigaltstack(SB),7,$0 - MOVL $53, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) -// System call args are: func arg stack pthread flags. -TEXT bsdthread_create(SB),7,$32 - MOVL $360, AX - // 0(SP) is where the caller PC would be; kernel skips it - MOVL func+12(FP), BX - MOVL BX, 4(SP) // func - MOVL m+4(FP), BX - MOVL BX, 8(SP) // arg - MOVL stk+0(FP), BX - MOVL BX, 12(SP) // stack - MOVL g+8(FP), BX - MOVL BX, 16(SP) // pthread - MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -// The thread that bsdthread_create creates starts executing here, -// because we registered this function using bsdthread_register -// at startup. -// AX = "pthread" (= g) -// BX = mach thread port -// CX = "func" (= fn) -// DX = "arg" (= m) -// DI = stack top -// SI = flags (= 0x1000000) -// SP = stack - C_32_STK_ALIGN -TEXT bsdthread_start(SB),7,$0 - // set up ldt 7+id to point at m->tls. - // m->tls is at m+40. newosproc left - // the m->id in tls[0]. - LEAL 40(DX), BP - MOVL 0(BP), DI - ADDL $7, DI // m0 is LDT#7. count up. - // setldt(tls#, &tls, sizeof tls) - PUSHAL // save registers - PUSHL $32 // sizeof tls - PUSHL BP // &tls - PUSHL DI // tls # - CALL setldt(SB) - POPL AX - POPL AX - POPL AX - POPAL - SHLL $3, DI // segment# is ldt*8 + 7. - ADDL $7, DI - MOVW DI, FS - - // Now segment is established. Initialize m, g. - MOVL AX, 0(FS) // g - MOVL DX, 4(FS) // m - MOVL BX, 20(DX) // m->procid = thread port (for debuggers) - CALL CX // fn() - CALL exit1(SB) - RET - -// void bsdthread_register(void) -// registers callbacks for threadstart (see bsdthread_create above -// and wqthread and pthsize (not used). returns 0 on success. -TEXT bsdthread_register(SB),7,$40 - MOVL $366, AX - // 0(SP) is where kernel expects caller PC; ignored - MOVL $bsdthread_start(SB), 4(SP) // threadstart - MOVL $0, 8(SP) // wqthread, not used by us - MOVL $0, 12(SP) // pthsize, not used by us - MOVL $0, 16(SP) // paranoia - MOVL $0, 20(SP) - MOVL $0, 24(SP) - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -// Invoke Mach system call. -// Assumes system call number in AX, -// caller PC on stack, caller's caller PC next, -// and then the system call arguments. -// -// Can be used for BSD too, but we don't, -// because if you use this interface the BSD -// system call numbers need an extra field -// in the high 16 bits that seems to be the -// argument count in bytes but is not always. -// INT $0x80 works fine for those. -TEXT sysenter(SB),7,$0 - POPL DX - MOVL SP, CX - BYTE $0x0F; BYTE $0x34; // SYSENTER - // returns to DX with SP set to CX - -TEXT mach_msg_trap(SB),7,$0 - MOVL $-31, AX - CALL sysenter(SB) - RET - -TEXT mach_reply_port(SB),7,$0 - MOVL $-26, AX - CALL sysenter(SB) - RET - -TEXT mach_task_self(SB),7,$0 - MOVL $-28, AX - CALL sysenter(SB) - RET - -// Mach provides trap versions of the semaphore ops, -// instead of requiring the use of RPC. - -// uint32 mach_semaphore_wait(uint32) -TEXT mach_semaphore_wait(SB),7,$0 - MOVL $-36, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) -TEXT mach_semaphore_timedwait(SB),7,$0 - MOVL $-38, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_signal(uint32) -TEXT mach_semaphore_signal(SB),7,$0 - MOVL $-33, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_signal_all(uint32) -TEXT mach_semaphore_signal_all(SB),7,$0 - MOVL $-34, AX - CALL sysenter(SB) - RET - -/* -descriptor entry format for system call -is the native machine format, ugly as it is: - - 2-byte limit - 3-byte base - 1-byte: 0x80=present, 0x60=dpl<<5, 0x1F=type - 1-byte: 0x80=limit is *4k, 0x40=32-bit operand size, - 0x0F=4 more bits of limit - 1 byte: 8 more bits of base - -int i386_get_ldt(int, union ldt_entry *, int); -int i386_set_ldt(int, const union ldt_entry *, int); - -*/ - -// setldt(int entry, int address, int limit) -TEXT setldt(SB),7,$32 - // set up data_desc - LEAL 16(SP), AX // struct data_desc - MOVL $0, 0(AX) - MOVL $0, 4(AX) - - MOVL address+4(FP), BX // aka base - MOVW BX, 2(AX) - SHRL $16, BX - MOVB BX, 4(AX) - SHRL $8, BX - MOVB BX, 7(AX) - - MOVL limit+8(FP), BX - MOVW BX, 0(AX) - SHRL $16, BX - ANDL $0x0F, BX - ORL $0x40, BX // 32-bit operand size - MOVB BX, 6(AX) - - MOVL $0xF2, 5(AX) // r/w data descriptor, dpl=3, present - - // call i386_set_ldt(entry, desc, 1) - MOVL entry+0(FP), BX - MOVL BX, 0(SP) - MOVL AX, 4(SP) - MOVL $1, 8(SP) - CALL i386_set_ldt(SB) - RET - -TEXT i386_set_ldt(SB),7,$0 - MOVL $5, AX - INT $0x82 // sic - JAE 2(PC) - CALL notok(SB) - RET - diff --git a/src/lib/runtime/darwin/amd64/defs.h b/src/lib/runtime/darwin/amd64/defs.h deleted file mode 100644 index 1076e4c10..000000000 --- a/src/lib/runtime/darwin/amd64/defs.h +++ /dev/null @@ -1,244 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, - MACH_MSG_TYPE_MOVE_SEND = 0x11, - MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, - MACH_MSG_TYPE_COPY_SEND = 0x13, - MACH_MSG_TYPE_MAKE_SEND = 0x14, - MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, - MACH_MSG_TYPE_COPY_RECEIVE = 0x16, - MACH_MSG_PORT_DESCRIPTOR = 0, - MACH_MSG_OOL_DESCRIPTOR = 0x1, - MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, - MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, - MACH_MSGH_BITS_COMPLEX = 0x80000000, - MACH_SEND_MSG = 0x1, - MACH_RCV_MSG = 0x2, - MACH_RCV_LARGE = 0x4, - MACH_SEND_TIMEOUT = 0x10, - MACH_SEND_INTERRUPT = 0x40, - MACH_SEND_CANCEL = 0x80, - MACH_SEND_ALWAYS = 0x10000, - MACH_SEND_TRAILER = 0x20000, - MACH_RCV_TIMEOUT = 0x100, - MACH_RCV_NOTIFY = 0x200, - MACH_RCV_INTERRUPT = 0x400, - MACH_RCV_OVERWRITE = 0x1000, - NDR_PROTOCOL_2_0 = 0, - NDR_INT_BIG_ENDIAN = 0, - NDR_INT_LITTLE_ENDIAN = 0x1, - NDR_FLOAT_IEEE = 0, - NDR_CHAR_ASCII = 0, - SA_SIGINFO = 0x40, - SA_RESTART = 0x2, - SA_ONSTACK = 0x1, - SA_USERTRAMP = 0x100, - SA_64REGSET = 0x200, -}; - -// Types -#pragma pack on - -typedef struct MachBody MachBody; -struct MachBody { - uint32 msgh_descriptor_count; -}; - -typedef struct MachHeader MachHeader; -struct MachHeader { - uint32 msgh_bits; - uint32 msgh_size; - uint32 msgh_remote_port; - uint32 msgh_local_port; - uint32 msgh_reserved; - int32 msgh_id; -}; - -typedef struct MachNDR MachNDR; -struct MachNDR { - uint8 mig_vers; - uint8 if_vers; - uint8 reserved1; - uint8 mig_encoding; - uint8 int_rep; - uint8 char_rep; - uint8 float_rep; - uint8 reserved2; -}; - -typedef struct MachPort MachPort; -struct MachPort { - uint32 name; - uint32 pad1; - uint16 pad2; - uint8 disposition; - uint8 type; -}; - -typedef struct StackT StackT; -struct StackT { - void *ss_sp; - uint64 ss_size; - int32 ss_flags; - byte pad0[4]; -}; - -typedef union Sighandler Sighandler; -union Sighandler { - void *__sa_handler; - void *__sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - void *sa_tramp; - uint32 sa_mask; - int32 sa_flags; -}; - -typedef union Sigval Sigval; -union Sigval { - int32 sival_int; - void *sival_ptr; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - int32 si_pid; - uint32 si_uid; - int32 si_status; - void *si_addr; - Sigval si_value; - int64 si_band; - uint64 __pad[7]; -}; - -typedef struct FPControl FPControl; -struct FPControl { - byte pad0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad0[2]; -}; - -typedef struct RegMMST RegMMST; -struct RegMMST { - int8 mmst_reg[10]; - int8 mmst_rsrv[6]; -}; - -typedef struct RegXMM RegXMM; -struct RegXMM { - int8 xmm_reg[16]; -}; - -typedef struct Regs Regs; -struct Regs { - uint64 rax; - uint64 rbx; - uint64 rcx; - uint64 rdx; - uint64 rdi; - uint64 rsi; - uint64 rbp; - uint64 rsp; - uint64 r8; - uint64 r9; - uint64 r10; - uint64 r11; - uint64 r12; - uint64 r13; - uint64 r14; - uint64 r15; - uint64 rip; - uint64 rflags; - uint64 cs; - uint64 fs; - uint64 gs; -}; - -typedef struct FloatState FloatState; -struct FloatState { - int32 fpu_reserved[2]; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - RegXMM fpu_xmm8; - RegXMM fpu_xmm9; - RegXMM fpu_xmm10; - RegXMM fpu_xmm11; - RegXMM fpu_xmm12; - RegXMM fpu_xmm13; - RegXMM fpu_xmm14; - RegXMM fpu_xmm15; - int8 fpu_rsrv4[96]; - int32 fpu_reserved1; -}; - -typedef struct ExceptionState ExceptionState; -struct ExceptionState { - uint32 trapno; - uint32 err; - uint64 faultvaddr; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - ExceptionState es; - Regs ss; - FloatState fs; - byte pad0[4]; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - int32 uc_onstack; - uint32 uc_sigmask; - StackT uc_stack; - Ucontext *uc_link; - uint64 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/lib/runtime/darwin/amd64/rt0.s b/src/lib/runtime/darwin/amd64/rt0.s deleted file mode 100644 index 0a0011781..000000000 --- a/src/lib/runtime/darwin/amd64/rt0.s +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_amd64_darwin(SB),7,$-8 - MOVQ $_rt0_amd64(SB), AX - JMP AX diff --git a/src/lib/runtime/darwin/amd64/signal.c b/src/lib/runtime/darwin/amd64/signal.c deleted file mode 100644 index 45e5e8d47..000000000 --- a/src/lib/runtime/darwin/amd64/signal.c +++ /dev/null @@ -1,111 +0,0 @@ -// 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" -#include "defs.h" -#include "os.h" -#include "signals.h" - -void -dumpregs(Regs *r) -{ - printf("rax %X\n", r->rax); - printf("rbx %X\n", r->rbx); - printf("rcx %X\n", r->rcx); - printf("rdx %X\n", r->rdx); - printf("rdi %X\n", r->rdi); - printf("rsi %X\n", r->rsi); - printf("rbp %X\n", r->rbp); - printf("rsp %X\n", r->rsp); - printf("r8 %X\n", r->r8 ); - printf("r9 %X\n", r->r9 ); - printf("r10 %X\n", r->r10); - printf("r11 %X\n", r->r11); - printf("r12 %X\n", r->r12); - printf("r13 %X\n", r->r13); - printf("r14 %X\n", r->r14); - printf("r15 %X\n", r->r15); - printf("rip %X\n", r->rip); - printf("rflags %X\n", r->rflags); - printf("cs %X\n", r->cs); - printf("fs %X\n", r->fs); - printf("gs %X\n", r->gs); -} - -void -sighandler(int32 sig, Siginfo *info, void *context) -{ - Ucontext *uc; - Mcontext *mc; - Regs *r; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - if(sig < 0 || sig >= NSIG){ - printf("Signal %d\n", sig); - }else{ - printf("%s\n", sigtab[sig].name); - } - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - printf("Faulting address: %p\n", info->si_addr); - printf("pc: %X\n", r->rip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)r->rip, (void*)r->rsp, (void*)r->r15); - tracebackothers((void*)r->r15); - dumpregs(r); - } - - breakpoint(); - exit(2); -} - -void -sigignore(int32, Siginfo*, void*) -{ -} - -void -signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - int32 i; - static Sigaction sa; - - sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; - sa.sa_mask = 0; // 0xFFFFFFFFU; - sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler - for(i = 0; i<NSIG; i++) { - if(sigtab[i].flags) { - if(sigtab[i].flags & SigCatch) { - sa.__sigaction_u.__sa_sigaction = sighandler; - } else { - sa.__sigaction_u.__sa_sigaction = sigignore; - } - if(sigtab[i].flags & SigRestart) - sa.sa_flags |= SA_RESTART; - else - sa.sa_flags &= ~SA_RESTART; - sigaction(i, &sa, nil); - } - } -} - diff --git a/src/lib/runtime/darwin/amd64/sys.s b/src/lib/runtime/darwin/amd64/sys.s deleted file mode 100644 index b46c823ae..000000000 --- a/src/lib/runtime/darwin/amd64/sys.s +++ /dev/null @@ -1,263 +0,0 @@ -// 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. - -// -// System calls and other sys.stuff for AMD64, Darwin -// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 -// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. -// - -// Exit the entire program (like C exit) -TEXT exit(SB),7,$-8 - MOVL 8(SP), DI // arg 1 exit status - MOVL $(0x2000000+1), AX // syscall entry - SYSCALL - CALL notok(SB) - RET - -// Exit this OS thread (like pthread_exit, which eventually -// calls __bsdthread_terminate). -TEXT exit1(SB),7,$-8 - MOVL 8(SP), DI // arg 1 exit status - MOVL $(0x2000000+361), AX // syscall entry - SYSCALL - CALL notok(SB) - RET - -TEXT sys·write(SB),7,$-8 - MOVL 8(SP), DI // arg 1 fid - MOVQ 16(SP), SI // arg 2 buf - MOVL 24(SP), DX // arg 3 count - MOVL $(0x2000000+4), AX // syscall entry - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -TEXT open(SB),7,$-8 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVQ $0, R10 - MOVL $(0x2000000+5), AX // syscall entry - SYSCALL - RET - -TEXT close(SB),7,$-8 - MOVL 8(SP), DI - MOVL $(0x2000000+6), AX // syscall entry - SYSCALL - RET - -TEXT fstat(SB),7,$-8 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL $(0x2000000+339), AX // syscall entry; really fstat64 - SYSCALL - RET - -TEXT read(SB),7,$-8 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL 24(SP), DX - MOVL $(0x2000000+3), AX // syscall entry - SYSCALL - RET - -TEXT write(SB),7,$-8 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL 24(SP), DX - MOVL $(0x2000000+4), AX // syscall entry - SYSCALL - RET - -TEXT sigaction(SB),7,$-8 - MOVL 8(SP), DI // arg 1 sig - MOVQ 16(SP), SI // arg 2 act - MOVQ 24(SP), DX // arg 3 oact - MOVQ 24(SP), CX // arg 3 oact - MOVQ 24(SP), R10 // arg 3 oact - MOVL $(0x2000000+46), AX // syscall entry - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -TEXT sigtramp(SB),7,$40 - MOVQ 32(R14), R15 // g = m->gsignal - MOVL DX,0(SP) - MOVQ CX,8(SP) - MOVQ R8,16(SP) - MOVQ R8, 24(SP) // save ucontext - MOVQ SI, 32(SP) // save infostyle - CALL DI - MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) - MOVQ 24(SP), DI // saved ucontext - MOVQ 32(SP), SI // saved infostyle - SYSCALL - INT $3 // not reached - -TEXT sys·mmap(SB),7,$-8 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), SI // arg 2 len - MOVL 20(SP), DX // arg 3 prot - MOVL 24(SP), R10 // arg 4 flags - MOVL 28(SP), R8 // arg 5 fid - MOVL 32(SP), R9 // arg 6 offset - MOVL $(0x2000000+197), AX // syscall entry - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -TEXT notok(SB),7,$-8 - MOVL $0xf1, BP - MOVQ BP, (BP) - RET - -TEXT sys·memclr(SB),7,$-8 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), CX // arg 2 count - ADDL $7, CX - SHRL $3, CX - MOVQ $0, AX - CLD - REP - STOSQ - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ -8(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ x+8(FP), BX - MOVQ BX, -8(AX) // set calling pc - RET - -TEXT sigaltstack(SB),7,$-8 - MOVQ new+8(SP), DI - MOVQ old+16(SP), SI - MOVQ $(0x2000000+53), AX - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) -TEXT bsdthread_create(SB),7,$-8 - // Set up arguments to bsdthread_create system call. - // The ones in quotes pass through to the thread callback - // uninterpreted, so we can put whatever we want there. - MOVQ fn+32(SP), DI // "func" - MOVQ m+16(SP), SI // "arg" - MOVQ stk+8(SP), DX // stack - MOVQ g+24(SP), R10 // "pthread" -// TODO(rsc): why do we get away with 0 flags here but not on 386? - MOVQ $0, R8 // flags - MOVQ $(0x2000000+360), AX // bsdthread_create - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// The thread that bsdthread_create creates starts executing here, -// because we registered this function using bsdthread_register -// at startup. -// DI = "pthread" (= g) -// SI = mach thread port -// DX = "func" (= fn) -// CX = "arg" (= m) -// R8 = stack -// R9 = flags (= 0) -// SP = stack - C_64_REDZONE_LEN (= stack - 128) -TEXT bsdthread_start(SB),7,$-8 - MOVQ CX, R14 // m - MOVQ DI, R15 // g - MOVQ SI, 24(R14) // thread port is m->procid - CALL DX // fn - CALL exit1(SB) - RET - -// void bsdthread_register(void) -// registers callbacks for threadstart (see bsdthread_create above -// and wqthread and pthsize (not used). returns 0 on success. -TEXT bsdthread_register(SB),7,$-8 - MOVQ $bsdthread_start(SB), DI // threadstart - MOVQ $0, SI // wqthread, not used by us - MOVQ $0, DX // pthsize, not used by us - MOVQ $(0x2000000+366), AX // bsdthread_register - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// Mach system calls use 0x1000000 instead of the BSD's 0x2000000. - -// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) -TEXT mach_msg_trap(SB),7,$0 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVL 24(SP), R10 - MOVL 28(SP), R8 - MOVL 32(SP), R9 - MOVL 36(SP), R11 - PUSHQ R11 // seventh arg, on stack - MOVL $(0x1000000+31), AX // mach_msg_trap - SYSCALL - POPQ R11 - RET - -TEXT mach_task_self(SB),7,$0 - MOVL $(0x1000000+28), AX // task_self_trap - SYSCALL - RET - -TEXT mach_thread_self(SB),7,$0 - MOVL $(0x1000000+27), AX // thread_self_trap - SYSCALL - RET - -TEXT mach_reply_port(SB),7,$0 - MOVL $(0x1000000+26), AX // mach_reply_port - SYSCALL - RET - -// Mach provides trap versions of the semaphore ops, -// instead of requiring the use of RPC. - -// uint32 mach_semaphore_wait(uint32) -TEXT mach_semaphore_wait(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+36), AX // semaphore_wait_trap - SYSCALL - RET - -// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) -TEXT mach_semaphore_timedwait(SB),7,$0 - MOVL 8(SP), DI - MOVL 12(SP), SI - MOVL 16(SP), DX - MOVL $(0x1000000+38), AX // semaphore_timedwait_trap - SYSCALL - RET - -// uint32 mach_semaphore_signal(uint32) -TEXT mach_semaphore_signal(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+33), AX // semaphore_signal_trap - SYSCALL - RET - -// uint32 mach_semaphore_signal_all(uint32) -TEXT mach_semaphore_signal_all(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+34), AX // semaphore_signal_all_trap - SYSCALL - RET - diff --git a/src/lib/runtime/darwin/defs.c b/src/lib/runtime/darwin/defs.c deleted file mode 100644 index 1ed662957..000000000 --- a/src/lib/runtime/darwin/defs.c +++ /dev/null @@ -1,104 +0,0 @@ -// 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. - -/* - * Input to godefs. - * - godefs -f -m64 defs.c >amd64/defs.h - godefs defs.c >386/defs.h - */ - -#define __DARWIN_UNIX03 0 - -#include <mach/mach.h> -#include <mach/message.h> -#include <sys/types.h> -#include <sys/time.h> -#include <signal.h> -#include <sys/mman.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANON, - $MAP_PRIVATE = MAP_PRIVATE, - - $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE, - $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND, - $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE, - $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND, - $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND, - $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE, - $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE, - - $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR, - $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR, - $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR, - $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR, - - $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX, - - $MACH_SEND_MSG = MACH_SEND_MSG, - $MACH_RCV_MSG = MACH_RCV_MSG, - $MACH_RCV_LARGE = MACH_RCV_LARGE, - - $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT, - $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT, - $MACH_SEND_CANCEL = MACH_SEND_CANCEL, - $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS, - $MACH_SEND_TRAILER = MACH_SEND_TRAILER, - $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT, - $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY, - $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT, - $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE, - - $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0, - $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN, - $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN, - $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE, - $NDR_CHAR_ASCII = NDR_CHAR_ASCII, - - $SA_SIGINFO = SA_SIGINFO, - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_USERTRAMP = SA_USERTRAMP, - $SA_64REGSET = SA_64REGSET, -}; - -typedef mach_msg_body_t $MachBody; -typedef mach_msg_header_t $MachHeader; -typedef NDR_record_t $MachNDR; -typedef mach_msg_port_descriptor_t $MachPort; - -typedef stack_t $StackT; -typedef union __sigaction_u $Sighandler; - -typedef struct __sigaction $Sigaction; // used in syscalls -// typedef struct sigaction $Sigaction; // used by the C library -typedef union sigval $Sigval; -typedef siginfo_t $Siginfo; - -typedef struct fp_control $FPControl; -typedef struct fp_status $FPStatus; -typedef struct mmst_reg $RegMMST; -typedef struct xmm_reg $RegXMM; - -#ifdef __LP64__ -// amd64 -typedef x86_thread_state64_t $Regs; -typedef x86_float_state64_t $FloatState; -typedef x86_exception_state64_t $ExceptionState; -typedef struct mcontext64 $Mcontext; -#else -// 386 -typedef x86_thread_state32_t $Regs; -typedef x86_float_state32_t $FloatState; -typedef x86_exception_state32_t $ExceptionState; -typedef struct mcontext32 $Mcontext; -#endif - -typedef ucontext_t $Ucontext; diff --git a/src/lib/runtime/darwin/os.h b/src/lib/runtime/darwin/os.h deleted file mode 100644 index 2a3ca87bd..000000000 --- a/src/lib/runtime/darwin/os.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -void bsdthread_create(void*, M*, G*, void(*)(void)); -void bsdthread_register(void); -int32 mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32); -uint32 mach_reply_port(void); -void mach_semacquire(uint32); -uint32 mach_semcreate(void); -void mach_semdestroy(uint32); -void mach_semrelease(uint32); -void mach_semreset(uint32); -uint32 mach_task_self(void); -uint32 mach_task_self(void); -uint32 mach_thread_self(void); -uint32 mach_thread_self(void); - -struct Sigaction; -void sigaction(int64, struct Sigaction*, struct Sigaction*); - -struct StackT; -void sigaltstack(struct StackT*, struct StackT*); -void sigtramp(void); diff --git a/src/lib/runtime/darwin/signals.h b/src/lib/runtime/darwin/signals.h deleted file mode 100644 index 4051dc4dc..000000000 --- a/src/lib/runtime/darwin/signals.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - - -#define C SigCatch -#define I SigIgnore -#define R SigRestart - -static SigTab sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ 0, "SIGHUP: terminal line hangup", - /* 2 */ 0, "SIGINT: interrupt", - /* 3 */ C, "SIGQUIT: quit", - /* 4 */ C, "SIGILL: illegal instruction", - /* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */ - /* 6 */ C, "SIGABRT: abort", - /* 7 */ C, "SIGEMT: emulate instruction executed", - /* 8 */ C, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ C, "SIGBUS: bus error", - /* 11 */ C, "SIGSEGV: segmentation violation", - /* 12 */ C, "SIGSYS: bad system call", - /* 13 */ I, "SIGPIPE: write to broken pipe", - /* 14 */ 0, "SIGALRM: alarm clock", - /* 15 */ 0, "SIGTERM: termination", - /* 16 */ 0, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ 0, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ I+R, "SIGCHLD: child status has changed", - /* 21 */ 0, "SIGTTIN: background read from tty", - /* 22 */ 0, "SIGTTOU: background write to tty", - /* 23 */ 0, "SIGIO: i/o now possible", - /* 24 */ 0, "SIGXCPU: cpu limit exceeded", - /* 25 */ 0, "SIGXFSZ: file size limit exceeded", - /* 26 */ 0, "SIGVTALRM: virtual alarm clock", - /* 27 */ 0, "SIGPROF: profiling alarm clock", - /* 28 */ I+R, "SIGWINCH: window size change", - /* 29 */ 0, "SIGINFO: status request from keyboard", - /* 30 */ 0, "SIGUSR1: user-defined signal 1", - /* 31 */ 0, "SIGUSR2: user-defined signal 2", -}; -#undef C -#undef I -#undef R - -#define NSIG 32 diff --git a/src/lib/runtime/darwin/thread.c b/src/lib/runtime/darwin/thread.c deleted file mode 100644 index 3a982471a..000000000 --- a/src/lib/runtime/darwin/thread.c +++ /dev/null @@ -1,441 +0,0 @@ -// 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" -#include "defs.h" -#include "os.h" - -static void -unimplemented(int8 *name) -{ - prints(name); - prints(" not implemented\n"); - *(int32*)1231 = 1231; -} - -// Thread-safe allocation of a semaphore. -// Psema points at a kernel semaphore key. -// It starts out zero, meaning no semaphore. -// Fill it in, being careful of others calling initsema -// simultaneously. -static void -initsema(uint32 *psema) -{ - uint32 sema; - - if(*psema != 0) // already have one - return; - - sema = mach_semcreate(); - if(!cas(psema, 0, sema)){ - // Someone else filled it in. Use theirs. - mach_semdestroy(sema); - return; - } -} - - -// Atomic add and return new value. -static uint32 -xadd(uint32 volatile *val, int32 delta) -{ - uint32 oval, nval; - - for(;;){ - oval = *val; - nval = oval + delta; - if(cas(val, oval, nval)) - return nval; - } -} - - -// Blocking locks. - -// Implement Locks, using semaphores. -// l->key is the number of threads who want the lock. -// In a race, one thread increments l->key from 0 to 1 -// and the others increment it from >0 to >1. The thread -// who does the 0->1 increment gets the lock, and the -// others wait on the semaphore. When the 0->1 thread -// releases the lock by decrementing l->key, l->key will -// be >0, so it will increment the semaphore to wake up -// one of the others. This is the same algorithm used -// in Plan 9's user-level locks. -// -// Note that semaphores are never destroyed (the kernel -// will clean up when the process exits). We assume for now -// that Locks are only used for long-lived structures like M and G. - -void -lock(Lock *l) -{ - if(m->locks < 0) - throw("lock count"); - m->locks++; - - // Allocate semaphore if needed. - if(l->sema == 0) - initsema(&l->sema); - - if(xadd(&l->key, 1) > 1) // someone else has it; wait - mach_semacquire(l->sema); -} - -void -unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - throw("lock count"); - - if(xadd(&l->key, -1) > 0) // someone else is waiting - mach_semrelease(l->sema); -} - - -// User-level semaphore implementation: -// try to do the operations in user space on u, -// but when it's time to block, fall back on the kernel semaphore k. -// This is the same algorithm used in Plan 9. -void -usemacquire(Usema *s) -{ - if((int32)xadd(&s->u, -1) < 0) - mach_semacquire(s->k); -} - -void -usemrelease(Usema *s) -{ - if((int32)xadd(&s->u, 1) <= 0) - mach_semrelease(s->k); -} - - -// Event notifications. -void -noteclear(Note *n) -{ - n->wakeup = 0; -} - -void -notesleep(Note *n) -{ - if(n->sema.k == 0) - initsema(&n->sema.k); - while(!n->wakeup) - usemacquire(&n->sema); -} - -void -notewakeup(Note *n) -{ - if(n->sema.k == 0) - initsema(&n->sema.k); - n->wakeup = 1; - usemrelease(&n->sema); -} - - -// BSD interface for threading. -void -osinit(void) -{ - // Register our thread-creation callback (see {amd64,386}/sys.s). - bsdthread_register(); -} - -void -newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - // printf("newosproc m=%p g=%p stk=%p fn=%p\n", m, g, stk, fn); - m->tls[0] = m->id; // so 386 asm can find it - bsdthread_create(stk, m, g, fn); -} - -// Called to initialize a new m (including the bootstrap m). -void -minit(void) -{ - // Initialize signal handling. - m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K - signalstack(m->gsignal->stackguard, 32*1024); -} - -// Mach IPC, to get at semaphores -// Definitions are in /usr/include/mach on a Mac. - -static void -macherror(int32 r, int8 *fn) -{ - printf("mach error %s: %d\n", fn, r); - throw("mach error"); -} - -enum -{ - DebugMach = 0 -}; - -static MachNDR zerondr; - -#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8)) - -static int32 -mach_msg(MachHeader *h, - int32 op, - uint32 send_size, - uint32 rcv_size, - uint32 rcv_name, - uint32 timeout, - uint32 notify) -{ - // TODO: Loop on interrupt. - return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify); -} - -// Mach RPC (MIG) - -enum -{ - MinMachMsg = 48, - Reply = 100, -}; - -#pragma pack on -typedef struct CodeMsg CodeMsg; -struct CodeMsg -{ - MachHeader h; - MachNDR NDR; - int32 code; -}; -#pragma pack off - -static int32 -machcall(MachHeader *h, int32 maxsize, int32 rxsize) -{ - uint32 *p; - int32 i, ret, id; - uint32 port; - CodeMsg *c; - - if((port = m->machport) == 0){ - port = mach_reply_port(); - m->machport = port; - } - - h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); - h->msgh_local_port = port; - h->msgh_reserved = 0; - id = h->msgh_id; - - if(DebugMach){ - p = (uint32*)h; - prints("send:\t"); - for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ - prints(" "); - sys·printpointer((void*)p[i]); - if(i%8 == 7) - prints("\n\t"); - } - if(i%8) - prints("\n"); - } - - ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG, - h->msgh_size, maxsize, port, 0, 0); - if(ret != 0){ - if(DebugMach){ - prints("mach_msg error "); - sys·printint(ret); - prints("\n"); - } - return ret; - } - - if(DebugMach){ - p = (uint32*)h; - prints("recv:\t"); - for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ - prints(" "); - sys·printpointer((void*)p[i]); - if(i%8 == 7) - prints("\n\t"); - } - if(i%8) - prints("\n"); - } - - if(h->msgh_id != id+Reply){ - if(DebugMach){ - prints("mach_msg reply id mismatch "); - sys·printint(h->msgh_id); - prints(" != "); - sys·printint(id+Reply); - prints("\n"); - } - return -303; // MIG_REPLY_MISMATCH - } - - // Look for a response giving the return value. - // Any call can send this back with an error, - // and some calls only have return values so they - // send it back on success too. I don't quite see how - // you know it's one of these and not the full response - // format, so just look if the message is right. - c = (CodeMsg*)h; - if(h->msgh_size == sizeof(CodeMsg) - && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){ - if(DebugMach){ - prints("mig result "); - sys·printint(c->code); - prints("\n"); - } - return c->code; - } - - if(h->msgh_size != rxsize){ - if(DebugMach){ - prints("mach_msg reply size mismatch "); - sys·printint(h->msgh_size); - prints(" != "); - sys·printint(rxsize); - prints("\n"); - } - return -307; // MIG_ARRAY_TOO_LARGE - } - - return 0; -} - - -// Semaphores! - -enum -{ - Tmach_semcreate = 3418, - Rmach_semcreate = Tmach_semcreate + Reply, - - Tmach_semdestroy = 3419, - Rmach_semdestroy = Tmach_semdestroy + Reply, - - // Mach calls that get interrupted by Unix signals - // return this error code. We retry them. - KERN_ABORTED = 14, -}; - -typedef struct Tmach_semcreateMsg Tmach_semcreateMsg; -typedef struct Rmach_semcreateMsg Rmach_semcreateMsg; -typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg; -// Rmach_semdestroyMsg = CodeMsg - -#pragma pack on -struct Tmach_semcreateMsg -{ - MachHeader h; - MachNDR ndr; - int32 policy; - int32 value; -}; - -struct Rmach_semcreateMsg -{ - MachHeader h; - MachBody body; - MachPort semaphore; -}; - -struct Tmach_semdestroyMsg -{ - MachHeader h; - MachBody body; - MachPort semaphore; -}; -#pragma pack off - -uint32 -mach_semcreate(void) -{ - union { - Tmach_semcreateMsg tx; - Rmach_semcreateMsg rx; - uint8 pad[MinMachMsg]; - } m; - int32 r; - - m.tx.h.msgh_bits = 0; - m.tx.h.msgh_size = sizeof(m.tx); - m.tx.h.msgh_remote_port = mach_task_self(); - m.tx.h.msgh_id = Tmach_semcreate; - m.tx.ndr = zerondr; - - m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO - m.tx.value = 0; - - while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){ - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_create"); - } - if(m.rx.body.msgh_descriptor_count != 1) - unimplemented("mach_semcreate desc count"); - return m.rx.semaphore.name; -} - -void -mach_semdestroy(uint32 sem) -{ - union { - Tmach_semdestroyMsg tx; - uint8 pad[MinMachMsg]; - } m; - int32 r; - - m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX; - m.tx.h.msgh_size = sizeof(m.tx); - m.tx.h.msgh_remote_port = mach_task_self(); - m.tx.h.msgh_id = Tmach_semdestroy; - m.tx.body.msgh_descriptor_count = 1; - m.tx.semaphore.name = sem; - m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND; - m.tx.semaphore.type = 0; - - while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){ - macherror(r, "semaphore_destroy"); - } -} - -// The other calls have simple system call traps in sys.s -int32 mach_semaphore_wait(uint32 sema); -int32 mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); -int32 mach_semaphore_signal(uint32 sema); -int32 mach_semaphore_signal_all(uint32 sema); - -void -mach_semacquire(uint32 sem) -{ - int32 r; - - while((r = mach_semaphore_wait(sem)) != 0) { - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_wait"); - } -} - -void -mach_semrelease(uint32 sem) -{ - int32 r; - - while((r = mach_semaphore_signal(sem)) != 0) { - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_signal"); - } -} - diff --git a/src/lib/runtime/extern.go b/src/lib/runtime/extern.go deleted file mode 100644 index 6fb5756d6..000000000 --- a/src/lib/runtime/extern.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -/* - The runtime package contains operations that interact with Go's runtime system, - such as functions to control goroutines. - */ -package runtime - -// These functions are implemented in the base runtime library, ../../runtime/. - -// Gosched yields the processor, allowing other goroutines to run. It does not -// suspend the current goroutine, so execution resumes automatically. -func Gosched() - -// Goexit terminates the goroutine that calls it. No other goroutine is affected. -func Goexit() - -// Breakpoint() executes a breakpoint trap. -func Breakpoint() - -// Caller reports file and line number information about function invocations on -// the calling goroutine's stack. The argument is the number of stack frames to -// ascend, with 1 identifying the the caller of Caller. The return values report the -// program counter, file name, and line number within the file of the corresponding -// call. The boolean ok is false if it was not possible to recover the information. -func Caller(n int) (pc uintptr, file string, line int, ok bool) diff --git a/src/lib/runtime/float.c b/src/lib/runtime/float.c deleted file mode 100644 index 5122f359a..000000000 --- a/src/lib/runtime/float.c +++ /dev/null @@ -1,173 +0,0 @@ -// 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" - -static uint64 uvnan = 0x7FF0000000000001ULL; -static uint64 uvinf = 0x7FF0000000000000ULL; -static uint64 uvneginf = 0xFFF0000000000000ULL; - -uint32 -float32tobits(float32 f) -{ - // The obvious cast-and-pointer code is technically - // not valid, and gcc miscompiles it. Use a union instead. - union { - float32 f; - uint32 i; - } u; - u.f = f; - return u.i; -} - -uint64 -float64tobits(float64 f) -{ - // The obvious cast-and-pointer code is technically - // not valid, and gcc miscompiles it. Use a union instead. - union { - float64 f; - uint64 i; - } u; - u.f = f; - return u.i; -} - -float64 -float64frombits(uint64 i) -{ - // The obvious cast-and-pointer code is technically - // not valid, and gcc miscompiles it. Use a union instead. - union { - float64 f; - uint64 i; - } u; - u.i = i; - return u.f; -} - -float32 -float32frombits(uint32 i) -{ - // The obvious cast-and-pointer code is technically - // not valid, and gcc miscompiles it. Use a union instead. - union { - float32 f; - uint32 i; - } u; - u.i = i; - return u.f; -} - -bool -isInf(float64 f, int32 sign) -{ - uint64 x; - - x = float64tobits(f); - if(sign == 0) - return x == uvinf || x == uvneginf; - if(sign > 0) - return x == uvinf; - return x == uvneginf; -} - -float64 -NaN(void) -{ - return float64frombits(uvnan); -} - -bool -isNaN(float64 f) -{ - uint64 x; - - x = float64tobits(f); - return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0); -} - -float64 -Inf(int32 sign) -{ - if(sign >= 0) - return float64frombits(uvinf); - else - return float64frombits(uvneginf); -} - -enum -{ - MASK = 0x7ffL, - SHIFT = 64-11-1, - BIAS = 1022L, -}; - -float64 -frexp(float64 d, int32 *ep) -{ - uint64 x; - - if(d == 0) { - *ep = 0; - return 0; - } - x = float64tobits(d); - *ep = (int32)((x >> SHIFT) & MASK) - BIAS; - x &= ~((uint64)MASK << SHIFT); - x |= (uint64)BIAS << SHIFT; - return float64frombits(x); -} - -float64 -ldexp(float64 d, int32 e) -{ - uint64 x; - - if(d == 0) - return 0; - x = float64tobits(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 float64frombits(x); -} - -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 = float64tobits(d); - e = (int32)((x >> SHIFT) & MASK) - BIAS; - - /* - * Keep the top 11+e bits; clear the rest. - */ - if(e <= 64-11) - x &= ~(((uint64)1 << (64LL-11LL-e))-1); - dd = float64frombits(x); - *ip = dd; - return d - dd; -} - diff --git a/src/lib/runtime/float_go.cgo b/src/lib/runtime/float_go.cgo deleted file mode 100644 index 518d55950..000000000 --- a/src/lib/runtime/float_go.cgo +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -package math - -#include "runtime.h" - -func Frexp(f float64) (frac float64, exp int32) { - frac = frexp(f, &exp); -} - -func Ldexp(frac float64, exp int32) (f float64) { - f = ldexp(frac, exp); -} - -func Modf(f float64) (integer float64, frac float64) { - frac = modf(f, &integer); -} - -func IsInf(f float64, sign int32) (is bool) { - is = isInf(f, sign); -} - -func IsNaN(f float64) (is bool) { - is = isNaN(f); -} - -func Inf(sign int32) (f float64) { - f = Inf(sign); -} - -func NaN() (f float64) { - f = NaN(); -} - -func Float32bits(f float32) (b uint32) { - b = float32tobits(f); -} - -func Float64bits(f float64) (b uint64) { - b = float64tobits(f); -} - -func Float32frombits(b uint32) (f float32) { - f = float32frombits(b); -} - -func Float64frombits(b uint64) (f float64) { - f = float64frombits(b); -} - diff --git a/src/lib/runtime/hashmap.c b/src/lib/runtime/hashmap.c deleted file mode 100644 index b3022ca14..000000000 --- a/src/lib/runtime/hashmap.c +++ /dev/null @@ -1,954 +0,0 @@ -// 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" -#include "hashmap.h" - -/* Return a pointer to the struct/union of type "type" - whose "field" field is addressed by pointer "p". */ - - -struct hash { /* a hash table; initialize with hash_init() */ - uint32 count; /* elements in table - must be first */ - - uint8 datasize; /* amount of data to store in entry */ - uint8 max_power; /* max power of 2 to create sub-tables */ - uint8 max_probes; /* max entries to probe before rehashing */ - int32 changes; /* inc'ed whenever a subtable is created/grown */ - hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */ - uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */ - void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */ - struct hash_subtable *st; /* first-level table */ - - uint32 keysize; - uint32 valsize; - uint32 datavo; - uint32 ko; - uint32 vo; - uint32 po; - Alg* keyalg; - Alg* valalg; -}; - -struct hash_entry { - hash_hash_t hash; /* hash value of data */ - byte data[1]; /* user data has "datasize" bytes */ -}; - -struct hash_subtable { - uint8 power; /* bits used to index this table */ - uint8 used; /* bits in hash used before reaching this table */ - uint8 datasize; /* bytes of client data in an entry */ - uint8 max_probes; /* max number of probes when searching */ - int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */ - struct hash_entry *end; /* points just past end of entry[] */ - struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */ -}; - -#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y))) - -#define HASH_REHASH 0x2 /* an internal flag */ -/* the number of bits used is stored in the flags word too */ -#define HASH_USED(x) ((x) >> 2) -#define HASH_MAKE_USED(x) ((x) << 2) - -#define HASH_LOW 6 -#define HASH_ONE (((hash_hash_t)1) << HASH_LOW) -#define HASH_MASK (HASH_ONE - 1) -#define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW) - -#define HASH_BITS (sizeof (hash_hash_t) * 8) - -#define HASH_SUBHASH HASH_MASK -#define HASH_NIL 0 -#define HASH_NIL_MEMSET 0 - -#define HASH_OFFSET(base, byte_offset) \ - ((struct hash_entry *) (((byte *) (base)) + (byte_offset))) - - -/* return a hash layer with 2**power empty entries */ -static struct hash_subtable * -hash_subtable_new (struct hash *h, int32 power, int32 used) -{ - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - int32 bytes = elemsize << power; - struct hash_subtable *st; - int32 limit_bytes = h->max_probes * elemsize; - int32 max_probes = h->max_probes; - - if (bytes < limit_bytes) { - limit_bytes = bytes; - max_probes = 1 << power; - } - bytes += limit_bytes - elemsize; - st = malloc (offsetof (struct hash_subtable, entry[0]) + bytes); - st->power = power; - st->used = used; - st->datasize = h->datasize; - st->max_probes = max_probes; - st->limit_bytes = limit_bytes; - st->end = HASH_OFFSET (st->entry, bytes); - memset (st->entry, HASH_NIL_MEMSET, bytes); - return (st); -} - -static void -init_sizes (int64 hint, int32 *init_power, int32 *max_power) -{ - int32 log = 0; - int32 i; - - for (i = 32; i != 0; i >>= 1) { - if ((hint >> (log + i)) != 0) { - log += i; - } - } - log += 1 + (((hint << 3) >> log) >= 11); /* round up for utilization */ - if (log <= 14) { - *init_power = log; - } else { - *init_power = 12; - } - *max_power = 12; -} - -static void -hash_init (struct hash *h, - int32 datasize, - hash_hash_t (*data_hash) (uint32, void *), - uint32 (*data_eq) (uint32, void *, void *), - void (*data_del) (uint32, void *, void *), - int64 hint) -{ - int32 init_power; - int32 max_power; - - if(datasize < sizeof (void *)) - datasize = sizeof (void *); - datasize = rnd(datasize, sizeof (void *)); - init_sizes (hint, &init_power, &max_power); - h->datasize = datasize; - h->max_power = max_power; - h->max_probes = 15; - assert (h->datasize == datasize); - assert (h->max_power == max_power); - assert (sizeof (void *) <= h->datasize || h->max_power == 255); - h->count = 0; - h->changes = 0; - h->data_hash = data_hash; - h->data_eq = data_eq; - h->data_del = data_del; - h->st = hash_subtable_new (h, init_power, 0); -} - -static void -hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) -{ - int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); - struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize); - struct hash_entry *end_e = st->end; - int32 shift = HASH_BITS - (st->power + st->used); - int32 index_mask = (((hash_hash_t)1) << st->power) - 1; - int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize; - int32 src_i = dst_i + n; - hash_hash_t hash; - int32 skip; - int32 bytes; - - while (dst_e != src_e) { - if (src_e != end_e) { - struct hash_entry *cp_e = src_e; - int32 save_dst_i = dst_i; - while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL && - ((hash >> shift) & index_mask) <= dst_i) { - cp_e = HASH_OFFSET (cp_e, elemsize); - dst_i++; - } - bytes = ((byte *) cp_e) - (byte *) src_e; - memmove (dst_e, src_e, bytes); - dst_e = HASH_OFFSET (dst_e, bytes); - src_e = cp_e; - src_i += dst_i - save_dst_i; - if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) { - skip = ((hash >> shift) & index_mask) - dst_i; - } else { - skip = src_i - dst_i; - } - } else { - skip = src_i - dst_i; - } - bytes = skip * elemsize; - memset (dst_e, HASH_NIL_MEMSET, bytes); - dst_e = HASH_OFFSET (dst_e, bytes); - dst_i += skip; - } -} - -static int32 -hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, - struct hash *h, void *data, void **pres); - -static void -hash_conv (struct hash *h, - struct hash_subtable *st, int32 flags, - hash_hash_t hash, - struct hash_entry *e) -{ - int32 new_flags = (flags + HASH_MAKE_USED (st->power)) | HASH_REHASH; - int32 shift = HASH_BITS - HASH_USED (new_flags); - hash_hash_t prefix_mask = (-(hash_hash_t)1) << shift; - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - void *dummy_result; - struct hash_entry *de; - int32 index_mask = (1 << st->power) - 1; - hash_hash_t e_hash; - struct hash_entry *pe = HASH_OFFSET (e, -elemsize); - - while (e != st->entry && (e_hash = pe->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) { - e = pe; - pe = HASH_OFFSET (pe, -elemsize); - } - - de = e; - while (e != st->end && - (e_hash = e->hash) != HASH_NIL && - (e_hash & HASH_MASK) != HASH_SUBHASH) { - struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize); - struct hash_entry *ne = HASH_OFFSET (e, elemsize); - hash_hash_t current = e_hash & prefix_mask; - if (de < target_e) { - memset (de, HASH_NIL_MEMSET, ((byte *) target_e) - (byte *) de); - de = target_e; - } - if ((hash & prefix_mask) == current || - (ne != st->end && (e_hash = ne->hash) != HASH_NIL && - (e_hash & prefix_mask) == current)) { - struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags)); - int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result); - assert (rc == 0); - memcpy(dummy_result, e->data, h->datasize); - e = ne; - while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) { - assert ((e_hash & HASH_MASK) != HASH_SUBHASH); - rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result); - assert (rc == 0); - memcpy(dummy_result, e->data, h->datasize); - e = HASH_OFFSET (e, elemsize); - } - memset (de->data, HASH_NIL_MEMSET, h->datasize); - *(struct hash_subtable **)de->data = new_st; - de->hash = current | HASH_SUBHASH; - } else { - if (e != de) { - memcpy (de, e, elemsize); - } - e = HASH_OFFSET (e, elemsize); - } - de = HASH_OFFSET (de, elemsize); - } - if (e != de) { - hash_remove_n (st, de, (((byte *) e) - (byte *) de) / elemsize); - } -} - -static void -hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags) -{ - struct hash_subtable *old_st = *pst; - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags)); - struct hash_entry *end_e = old_st->end; - struct hash_entry *e; - void *dummy_result; - int32 used = 0; - - flags |= HASH_REHASH; - for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) { - hash_hash_t hash = e->hash; - if (hash != HASH_NIL) { - int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result); - assert (rc == 0); - memcpy(dummy_result, e->data, h->datasize); - used++; - } - } - free (old_st); -} - -int32 -hash_lookup (struct hash *h, void *data, void **pres) -{ - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; - struct hash_subtable *st = h->st; - int32 used = 0; - hash_hash_t e_hash; - struct hash_entry *e; - struct hash_entry *end_e; - - hash += HASH_ADJUST (hash); - for (;;) { - int32 shift = HASH_BITS - (st->power + used); - int32 index_mask = (1 << st->power) - 1; - int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */ - - e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */ - e_hash = e->hash; - if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */ - break; - } - used += st->power; - st = *(struct hash_subtable **)e->data; - } - end_e = HASH_OFFSET (e, st->limit_bytes); - while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { - e = HASH_OFFSET (e, elemsize); - } - while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, e->data)) { /* a match */ - *pres = e->data; - return (1); - } - e = HASH_OFFSET (e, elemsize); - } - USED(e_hash); - *pres = 0; - return (0); -} - -int32 -hash_remove (struct hash *h, void *data, void *arg) -{ - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; - struct hash_subtable *st = h->st; - int32 used = 0; - hash_hash_t e_hash; - struct hash_entry *e; - struct hash_entry *end_e; - - hash += HASH_ADJUST (hash); - for (;;) { - int32 shift = HASH_BITS - (st->power + used); - int32 index_mask = (1 << st->power) - 1; - int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */ - - e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */ - e_hash = e->hash; - if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */ - break; - } - used += st->power; - st = *(struct hash_subtable **)e->data; - } - end_e = HASH_OFFSET (e, st->limit_bytes); - while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { - e = HASH_OFFSET (e, elemsize); - } - while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, e->data)) { /* a match */ - (*h->data_del) (h->keysize, arg, e->data); - hash_remove_n (st, e, 1); - h->count--; - return (1); - } - e = HASH_OFFSET (e, elemsize); - } - USED(e_hash); - return (0); -} - -static int32 -hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, - struct hash *h, void *data, void **pres) -{ - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - - if ((flags & HASH_REHASH) == 0) { - hash += HASH_ADJUST (hash); - hash &= ~HASH_MASK; - } - for (;;) { - struct hash_subtable *st = *pst; - int32 shift = HASH_BITS - (st->power + HASH_USED (flags)); - int32 index_mask = (1 << st->power) - 1; - int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */ - struct hash_entry *start_e = - HASH_OFFSET (st->entry, i * elemsize); /* start_e is the pointer to element i */ - struct hash_entry *e = start_e; /* e is going to range over [start_e, end_e) */ - struct hash_entry *end_e; - hash_hash_t e_hash = e->hash; - - if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable */ - pst = (struct hash_subtable **) e->data; - flags += HASH_MAKE_USED (st->power); - continue; - } - end_e = HASH_OFFSET (start_e, st->limit_bytes); - while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) { - e = HASH_OFFSET (e, elemsize); - i++; - } - if (e != end_e && e_hash != HASH_NIL) { - /* ins_e ranges over the elements that may match */ - struct hash_entry *ins_e = e; - int32 ins_i = i; - hash_hash_t ins_e_hash; - while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */ - *pres = ins_e->data; - return (1); - } - assert (e_hash != hash || (flags & HASH_REHASH) == 0); - hash += (e_hash == hash); /* adjust hash if it collides */ - ins_e = HASH_OFFSET (ins_e, elemsize); - ins_i++; - if (e_hash <= hash) { /* set e to insertion point */ - e = ins_e; - i = ins_i; - } - } - /* set ins_e to the insertion point for the new element */ - ins_e = e; - ins_i = i; - ins_e_hash = 0; - /* move ins_e to point at the end of the contiguous block, but - stop if any element can't be moved by one up */ - while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL && - ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes && - (ins_e_hash & HASH_MASK) != HASH_SUBHASH) { - ins_e = HASH_OFFSET (ins_e, elemsize); - ins_i++; - } - if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) { - e = end_e; /* can't insert; must grow or convert to subtable */ - } else { /* make space for element */ - memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e); - } - } - if (e != end_e) { - e->hash = hash; - *pres = e->data; - return (0); - } - h->changes++; - if (st->power < h->max_power) { - hash_grow (h, pst, flags); - } else { - hash_conv (h, st, flags, hash, start_e); - } - } -} - -int32 -hash_insert (struct hash *h, void *data, void **pres) -{ - int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres); - - h->count += (rc == 0); /* increment count if element didn't previously exist */ - return (rc); -} - -uint32 -hash_count (struct hash *h) -{ - return (h->count); -} - -static void -iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) -{ - int32 elemsize = it->elemsize; - hash_hash_t last_hash = it->last_hash; - struct hash_entry *e; - hash_hash_t e_hash; - struct hash_iter_sub *sub = &it->subtable_state[it->i]; - struct hash_entry *end; - - for (;;) { - int32 shift = HASH_BITS - (st->power + used); - int32 index_mask = (1 << st->power) - 1; - int32 i = (last_hash >> shift) & index_mask; - - end = st->end; - e = HASH_OFFSET (st->entry, i * elemsize); - sub->start = st->entry; - sub->end = end; - - if ((e->hash & HASH_MASK) != HASH_SUBHASH) { - break; - } - sub->e = HASH_OFFSET (e, elemsize); - sub = &it->subtable_state[++(it->i)]; - used += st->power; - st = *(struct hash_subtable **)e->data; - } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { - e = HASH_OFFSET (e, elemsize); - } - sub->e = e; -} - -void * -hash_next (struct hash_iter *it) -{ - int32 elemsize = it->elemsize; - struct hash_iter_sub *sub = &it->subtable_state[it->i]; - struct hash_entry *e = sub->e; - struct hash_entry *end = sub->end; - hash_hash_t e_hash = 0; - - if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */ - it->changes = it->h->changes; - it->i = 0; - iter_restart (it, it->h->st, 0); - sub = &it->subtable_state[it->i]; - e = sub->e; - end = sub->end; - } - if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) { - struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes)); - struct hash_entry *pe = HASH_OFFSET (e, -elemsize); - hash_hash_t last_hash = it->last_hash; - if (start < sub->start) { - start = sub->start; - } - while (e != start && ((e_hash = pe->hash) == HASH_NIL || last_hash < e_hash)) { - e = pe; - pe = HASH_OFFSET (pe, -elemsize); - } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { - e = HASH_OFFSET (e, elemsize); - } - } - - for (;;) { - while (e != end && (e_hash = e->hash) == HASH_NIL) { - e = HASH_OFFSET (e, elemsize); - } - if (e == end) { - if (it->i == 0) { - it->last_hash = HASH_OFFSET (e, -elemsize)->hash; - sub->e = e; - return (0); - } else { - it->i--; - sub = &it->subtable_state[it->i]; - e = sub->e; - end = sub->end; - } - } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) { - it->last_hash = e->hash; - sub->e = HASH_OFFSET (e, elemsize); - return (e->data); - } else { - struct hash_subtable *st = - *(struct hash_subtable **)e->data; - sub->e = HASH_OFFSET (e, elemsize); - it->i++; - assert (it->i < sizeof (it->subtable_state) / - sizeof (it->subtable_state[0])); - sub = &it->subtable_state[it->i]; - sub->e = e = st->entry; - sub->start = st->entry; - sub->end = end = st->end; - } - } -} - -void -hash_iter_init (struct hash *h, struct hash_iter *it) -{ - it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - it->changes = h->changes; - it->i = 0; - it->h = h; - it->last_hash = 0; - it->subtable_state[0].e = h->st->entry; - it->subtable_state[0].start = h->st->entry; - it->subtable_state[0].end = h->st->end; -} - -static void -clean_st (struct hash_subtable *st, int32 *slots, int32 *used) -{ - int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); - struct hash_entry *e = st->entry; - struct hash_entry *end = st->end; - int32 lslots = (((byte *) end) - (byte *) e) / elemsize; - int32 lused = 0; - - while (e != end) { - hash_hash_t hash = e->hash; - if ((hash & HASH_MASK) == HASH_SUBHASH) { - clean_st (*(struct hash_subtable **)e->data, slots, used); - } else { - lused += (hash != HASH_NIL); - } - e = HASH_OFFSET (e, elemsize); - } - free (st); - *slots += lslots; - *used += lused; -} - -void -hash_destroy (struct hash *h) -{ - int32 slots = 0; - int32 used = 0; - - clean_st (h->st, &slots, &used); - free (h); -} - -static void -hash_visit_internal (struct hash_subtable *st, - int32 used, int32 level, - void (*data_visit) (void *arg, int32 level, void *data), - void *arg) -{ - int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); - struct hash_entry *e = st->entry; - int32 shift = HASH_BITS - (used + st->power); - int32 i = 0; - - while (e != st->end) { - int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1); - if ((e->hash & HASH_MASK) == HASH_SUBHASH) { - (*data_visit) (arg, level, e->data); - hash_visit_internal (*(struct hash_subtable **)e->data, - used + st->power, level + 1, data_visit, arg); - } else { - (*data_visit) (arg, level, e->data); - } - if (e->hash != HASH_NIL) { - assert (i < index + st->max_probes); - assert (index <= i); - } - e = HASH_OFFSET (e, elemsize); - i++; - } -} - -void -hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg) -{ - hash_visit_internal (h->st, 0, 0, data_visit, arg); -} - -// -/// interfaces to go runtime -// - -static void -donothing(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); -} - -typedef struct hash Hmap; -static int32 debug = 0; - -// newmap(keysize uint32, valsize uint32, -// keyalg uint32, valalg uint32, -// hint uint32) (hmap *map[any]any); -void -sys·newmap(uint32 keysize, uint32 valsize, - uint32 keyalg, uint32 valalg, uint32 hint, - Hmap* ret) -{ - Hmap *h; - - if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) { - printf("map(keyalg=%d)\n", keyalg); - throw("sys·newmap: unsupported map key type"); - } - - if(valalg >= nelem(algarray)) { - printf("map(valalg=%d)\n", valalg); - throw("sys·newmap: unsupported map value type"); - } - - h = mal(sizeof(*h)); - - // align value inside data so that mark-sweep gc can find it. - // might remove in the future and just assume datavo == keysize. - h->datavo = keysize; - if(valsize >= sizeof(void*)) - h->datavo = rnd(keysize, sizeof(void*)); - - hash_init(h, h->datavo+valsize, - algarray[keyalg].hash, - algarray[keyalg].equal, - donothing, - hint); - - h->keysize = keysize; - h->valsize = valsize; - h->keyalg = &algarray[keyalg]; - h->valalg = &algarray[valalg]; - - // these calculations are compiler dependent. - // figure out offsets of map call arguments. - h->ko = rnd(sizeof(h), keysize); - h->vo = rnd(h->ko+keysize, valsize); - h->po = rnd(h->vo+valsize, 1); - - ret = h; - FLUSH(&ret); - - if(debug) { - prints("newmap: map="); - sys·printpointer(h); - prints("; keysize="); - sys·printint(keysize); - prints("; valsize="); - sys·printint(valsize); - prints("; keyalg="); - sys·printint(keyalg); - prints("; valalg="); - sys·printint(valalg); - prints("; ko="); - sys·printint(h->ko); - prints("; vo="); - sys·printint(h->vo); - prints("; po="); - sys·printint(h->po); - prints("\n"); - } -} - -// mapaccess1(hmap *map[any]any, key any) (val any); -void -sys·mapaccess1(Hmap *h, ...) -{ - byte *ak, *av; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - - res = nil; - hit = hash_lookup(h, ak, (void**)&res); - if(!hit) - throw("sys·mapaccess1: key not in map"); - h->valalg->copy(h->valsize, av, res+h->datavo); - - if(debug) { - prints("sys·mapaccess1: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapaccess2(hmap *map[any]any, key any) (val any, pres bool); -void -sys·mapaccess2(Hmap *h, ...) -{ - byte *ak, *av, *ap; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - ap = (byte*)&h + h->po; - - res = nil; - hit = hash_lookup(h, ak, (void**)&res); - if(!hit) { - *ap = false; - h->valalg->copy(h->valsize, av, nil); - } else { - *ap = true; - h->valalg->copy(h->valsize, av, res+h->datavo); - } - - if(debug) { - prints("sys·mapaccess2: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("; pres="); - sys·printbool(*ap); - prints("\n"); - } -} - -static void -mapassign(Hmap *h, byte *ak, byte *av) -{ - byte *res; - int32 hit; - - res = nil; - hit = hash_insert(h, ak, (void**)&res); - h->keyalg->copy(h->keysize, res, ak); - h->valalg->copy(h->valsize, res+h->datavo, av); - - if(debug) { - prints("mapassign: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapassign1(hmap *map[any]any, key any, val any); -void -sys·mapassign1(Hmap *h, ...) -{ - byte *ak, *av; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - - mapassign(h, ak, av); -} - -// mapassign2(hmap *map[any]any, key any, val any, pres bool); -void -sys·mapassign2(Hmap *h, ...) -{ - byte *ak, *av, *ap; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - ap = (byte*)&h + h->po; - - if(*ap == true) { - // assign - mapassign(h, ak, av); - return; - } - - // delete - hit = hash_remove(h, ak, (void**)&res); - - if(debug) { - prints("mapassign2: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapiterinit(hmap *map[any]any, hiter *any); -void -sys·mapiterinit(Hmap *h, struct hash_iter *it) -{ - if(h == nil) { - it->data = nil; - return; - } - hash_iter_init(h, it); - it->data = hash_next(it); - if(debug) { - prints("sys·mapiterinit: map="); - sys·printpointer(h); - prints("; iter="); - sys·printpointer(it); - prints("; data="); - sys·printpointer(it->data); - prints("\n"); - } -} - -// mapiternext(hiter *any); -void -sys·mapiternext(struct hash_iter *it) -{ - it->data = hash_next(it); - if(debug) { - prints("sys·mapiternext: iter="); - sys·printpointer(it); - prints("; data="); - sys·printpointer(it->data); - prints("\n"); - } -} - -// mapiter1(hiter *any) (key any); -void -sys·mapiter1(struct hash_iter *it, ...) -{ - Hmap *h; - byte *ak, *res; - - h = it->h; - ak = (byte*)&it + h->ko; - - res = it->data; - if(res == nil) - throw("sys·mapiter2: key:val nil pointer"); - - h->keyalg->copy(h->keysize, ak, res); - - if(debug) { - prints("mapiter2: iter="); - sys·printpointer(it); - prints("; map="); - sys·printpointer(h); - prints("\n"); - } -} - -// mapiter2(hiter *any) (key any, val any); -void -sys·mapiter2(struct hash_iter *it, ...) -{ - Hmap *h; - byte *ak, *av, *res; - - h = it->h; - ak = (byte*)&it + h->ko; - av = (byte*)&it + h->vo; - - res = it->data; - if(res == nil) - throw("sys·mapiter2: key:val nil pointer"); - - h->keyalg->copy(h->keysize, ak, res); - h->valalg->copy(h->valsize, av, res+h->datavo); - - if(debug) { - prints("mapiter2: iter="); - sys·printpointer(it); - prints("; map="); - sys·printpointer(h); - prints("\n"); - } -} diff --git a/src/lib/runtime/hashmap.h b/src/lib/runtime/hashmap.h deleted file mode 100644 index ff93e9ee3..000000000 --- a/src/lib/runtime/hashmap.h +++ /dev/null @@ -1,161 +0,0 @@ -// 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. - - -/* A hash table. - Example, hashing nul-terminated char*s: - hash_hash_t str_hash (void *v) { - char *s; - hash_hash_t hash = 0; - for (s = *(char **)v; *s != 0; s++) { - hash = (hash ^ *s) * 2654435769U; - } - return (hash); - } - int str_eq (void *a, void *b) { - return (strcmp (*(char **)a, *(char **)b) == 0); - } - void str_del (void *arg, void *data) { - *(char **)arg = *(char **)data; - } - - struct hash *h = hash_new (sizeof (char *), &str_hash, &str_eq, &str_del, 3, 12, 15); - ... 3=> 2**3 entries initial size - ... 12=> 2**12 entries before sprouting sub-tables - ... 15=> number of adjacent probes to attempt before growing - - Example lookup: - char *key = "foobar"; - char **result_ptr; - if (hash_lookup (h, &key, (void **) &result_ptr)) { - printf ("found in table: %s\n", *result_ptr); - } else { - printf ("not found in table\n"); - } - - Example insertion: - char *key = strdup ("foobar"); - char **result_ptr; - if (hash_lookup (h, &key, (void **) &result_ptr)) { - printf ("found in table: %s\n", *result_ptr); - printf ("to overwrite, do *result_ptr = key\n"); - } else { - printf ("not found in table; inserted as %s\n", *result_ptr); - assert (*result_ptr == key); - } - - Example deletion: - char *key = "foobar"; - char *result; - if (hash_remove (h, &key, &result)) { - printf ("key found and deleted from table\n"); - printf ("called str_del (&result, data) to copy data to result: %s\n", result); - } else { - printf ("not found in table\n"); - } - - Example iteration over the elements of *h: - char **data; - struct hash_iter it; - hash_iter_init (h, &it); - for (data = hash_next (&it); data != 0; data = hash_next (&it)) { - printf ("%s\n", *data); - } - */ - -#define malloc mal -#define free(a) USED(a) -#define offsetof(s,m) (uint32)(&(((s*)0)->m)) -#define memset(a,b,c) sys·memclr((byte*)(a), (uint32)(c)) -#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c)) -#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c)) -#define assert(a) if(!(a)) throw("assert") - -struct hash; /* opaque */ -struct hash_subtable; /* opaque */ -struct hash_entry; /* opaque */ - -typedef uintptr uintptr_t; -typedef uintptr_t hash_hash_t; - -struct hash_iter { - uint8* data; /* returned from next */ - int32 elemsize; /* size of elements in table */ - int32 changes; /* number of changes observed last time */ - int32 i; /* stack pointer in subtable_state */ - hash_hash_t last_hash; /* last hash value returned */ - struct hash *h; /* the hash table */ - struct hash_iter_sub { - struct hash_entry *e; /* pointer into subtable */ - struct hash_entry *start; /* start of subtable */ - struct hash_entry *end; /* end of subtable */ - } subtable_state[4]; /* Should be large enough unless the hashing is - so bad that many distinct data values hash - to the same hash value. */ -}; - -/* Return a hashtable h 2**init_power empty entries, each with - "datasize" data bytes. - (*data_hash)(a) should return the hash value of data element *a. - (*data_eq)(a,b) should return whether the data at "a" and the data at "b" - are equal. - (*data_del)(arg, a) will be invoked when data element *a is about to be removed - from the table. "arg" is the argument passed to "hash_remove()". - - Growing is accomplished by resizing if the current tables size is less than - a threshold, and by adding subtables otherwise. hint should be set - the expected maximum size of the table. - "datasize" should be in [sizeof (void*), ..., 255]. If you need a - bigger "datasize", store a pointer to another piece of memory. */ - -//struct hash *hash_new (int32 datasize, -// hash_hash_t (*data_hash) (void *), -// int32 (*data_eq) (void *, void *), -// void (*data_del) (void *, void *), -// int64 hint); - -/* Lookup *data in *h. If the data is found, return 1 and place a pointer to - the found element in *pres. Otherwise return 0 and place 0 in *pres. */ -int32 hash_lookup (struct hash *h, void *data, void **pres); - -/* Lookup *data in *h. If the data is found, execute (*data_del) (arg, p) - where p points to the data in the table, then remove it from *h and return - 1. Otherwise return 0. */ -int32 hash_remove (struct hash *h, void *data, void *arg); - -/* Lookup *data in *h. If the data is found, return 1, and place a pointer - to the found element in *pres. Otherwise, return 0, allocate a region - for the data to be inserted, and place a pointer to the inserted element - in *pres; it is the caller's responsibility to copy the data to be - inserted to the pointer returned in *pres in this case. - - If using garbage collection, it is the caller's responsibility to - add references for **pres if HASH_ADDED is returned. */ -int32 hash_insert (struct hash *h, void *data, void **pres); - -/* Return the number of elements in the table. */ -uint32 hash_count (struct hash *h); - -/* The following call is useful only if not using garbage collection on the - table. - Remove all sub-tables associated with *h. - This undoes the effects of hash_init(). - If other memory pointed to by user data must be freed, the caller is - responsible for doiing do by iterating over *h first; see - hash_iter_init()/hash_next(). */ -void hash_destroy (struct hash *h); - -/*----- iteration -----*/ - -/* Initialize *it from *h. */ -void hash_iter_init (struct hash *h, struct hash_iter *it); - -/* Return the next used entry in the table which which *it was initialized. */ -void *hash_next (struct hash_iter *it); - -/*---- test interface ----*/ -/* Call (*data_visit) (arg, level, data) for every data entry in the table, - whether used or not. "level" is the subtable level, 0 means first level. */ -/* TESTING ONLY: DO NOT USE THIS ROUTINE IN NORMAL CODE */ -void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg); diff --git a/src/lib/runtime/iface.c b/src/lib/runtime/iface.c deleted file mode 100644 index 6c933b1b2..000000000 --- a/src/lib/runtime/iface.c +++ /dev/null @@ -1,906 +0,0 @@ -// 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 iface_debug = 0; - -typedef struct Sigt Sigt; -typedef struct Sigi Sigi; -typedef struct Itype Itype; - -/* - * the layout of Iface, Sigt and Sigi are known to the compiler - */ -struct Sigt -{ - byte* name; // name of basic type - Sigt* link; // for linking into hash tables - uint32 thash; // hash of type - uint32 mhash; // hash of methods - uint16 width; // width of base type in bytes - uint16 alg; // algorithm - // note: on amd64 there is a 32-bit pad here. - struct { - byte* fname; - uint32 fhash; // hash of type - uint32 offset; // offset of substruct - void (*fun)(void); - } meth[1]; // one or more - last name is nil -}; - -struct Sigi -{ - byte* name; - uint32 hash; - uint32 size; // number of methods - struct { - byte* fname; - uint32 fhash; - uint32 perm; // location of fun in Sigt - } meth[1]; // [size+1] - last name is nil -}; - -struct Itype -{ - Sigi* sigi; - Sigt* sigt; - Itype* link; - int32 bad; - int32 unused; - void (*fun[])(void); -}; - -static Iface niliface; -static Eface nileface; - -static Itype* hash[1009]; -static Lock ifacelock; - -Sigi sigi·empty[2] = { (byte*)"interface { }" }; - -static void -printsigi(Sigi *si) -{ - int32 i; - byte *name; - - sys·printpointer(si); - prints("{"); - prints((int8*)si->name); - prints(":"); - for(i=0;; i++) { - name = si->meth[i].fname; - if(name == nil) - break; - prints("["); - sys·printint(i); - prints("]\""); - prints((int8*)name); - prints("\""); - sys·printint(si->meth[i].fhash%999); - prints("/"); - sys·printint(si->meth[i].perm); - } - prints("}"); -} - -static void -printsigt(Sigt *st) -{ - int32 i; - byte *name; - - sys·printpointer(st); - prints("{"); - prints((int8*)st->name); - prints(":"); - sys·printint(st->thash%999); // type hash - prints(","); - sys·printint(st->mhash%999); // method hash - prints(","); - sys·printint(st->width); // width - prints(","); - sys·printint(st->alg); // algorithm - for(i=0;; i++) { - name = st->meth[i].fname; - if(name == nil) - break; - prints("["); - sys·printint(i); - prints("]\""); - prints((int8*)name); - prints("\""); - sys·printint(st->meth[i].fhash%999); - prints("/"); - sys·printint(st->meth[i].offset); - prints("/"); - sys·printpointer(st->meth[i].fun); - } - prints("}"); -} - -static void -printiface(Iface i) -{ - prints("("); - sys·printpointer(i.type); - prints(","); - sys·printpointer(i.data); - prints(")"); -} - -static void -printeface(Eface e) -{ - prints("("); - sys·printpointer(e.type); - prints(","); - sys·printpointer(e.data); - prints(")"); -} - -static Itype* -itype(Sigi *si, Sigt *st, int32 canfail) -{ - int32 locked; - int32 nt, ni; - uint32 ihash, h; - byte *sname, *iname; - Itype *m; - - if(si->size == 0) - throw("internal error - misuse of itype"); - - // easy case - if(st->meth[0].fname == nil) { - if(canfail) - return nil; - iname = si->meth[0].fname; - goto throw1; - } - - // compiler has provided some good hash codes for us. - h = 0; - if(si) - h += si->hash; - if(st) { - h += st->thash; - h += st->mhash; - } - - h %= nelem(hash); - - // look twice - once without lock, once with. - // common case will be no lock contention. - for(locked=0; locked<2; locked++) { - if(locked) - lock(&ifacelock); - for(m=hash[h]; m!=nil; m=m->link) { - if(m->sigi == si && m->sigt == st) { - if(m->bad) { - m = nil; - if(!canfail) { - // this can only happen if the conversion - // was already done once using the , ok form - // and we have a cached negative result. - // the cached result doesn't record which - // interface function was missing, so jump - // down to the interface check, which will - // give a better error. - goto throw; - } - } - if(locked) - unlock(&ifacelock); - return m; - } - } - } - - ni = si->size; - m = malloc(sizeof(*m) + ni*sizeof(m->fun[0])); - m->sigi = si; - m->sigt = st; - -throw: - nt = 0; - for(ni=0;; ni++) { - iname = si->meth[ni].fname; - if(iname == nil) - break; - - // pick up next name from - // interface signature - ihash = si->meth[ni].fhash; - - for(;; nt++) { - // pick up and compare next name - // from structure signature - sname = st->meth[nt].fname; - if(sname == nil) { - if(!canfail) { - throw1: - printf("cannot convert type %s to interface %s: missing method %s\n", - st->name, si->name, iname); - if(iface_debug) { - prints("interface"); - printsigi(si); - prints("\ntype"); - printsigt(st); - prints("\n"); - } - throw("interface conversion"); - return nil; // not reached - } - m->bad = 1; - m->link = hash[h]; - hash[h] = m; - if(locked) - unlock(&ifacelock); - return nil; - } - if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0) - break; - } - m->fun[si->meth[ni].perm] = st->meth[nt].fun; - } - m->link = hash[h]; - hash[h] = m; - if(locked) - unlock(&ifacelock); - - return m; -} - -static void -copyin(Sigt *st, void *src, void **dst) -{ - int32 wid, alg; - void *p; - - wid = st->width; - alg = st->alg; - - if(wid <= sizeof(*dst)) - algarray[alg].copy(wid, dst, src); - else { - p = mal(wid); - algarray[alg].copy(wid, p, src); - *dst = p; - } -} - -static void -copyout(Sigt *st, void **src, void *dst) -{ - int32 wid, alg; - - wid = st->width; - alg = st->alg; - - if(wid <= sizeof(*src)) - algarray[alg].copy(wid, dst, src); - else - algarray[alg].copy(wid, dst, *src); -} - -// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); -#pragma textflag 7 -void -sys·ifaceT2I(Sigi *si, Sigt *st, ...) -{ - byte *elem; - Iface *ret; - int32 wid; - - elem = (byte*)(&st+1); - wid = st->width; - ret = (Iface*)(elem + rnd(wid, sizeof(uintptr))); - - ret->type = itype(si, st, 0); - copyin(st, elem, &ret->data); -} - -// ifaceT2E(sigt *byte, elem any) (ret any); -#pragma textflag 7 -void -sys·ifaceT2E(Sigt *st, ...) -{ - byte *elem; - Eface *ret; - int32 wid; - - elem = (byte*)(&st+1); - wid = st->width; - ret = (Eface*)(elem + rnd(wid, sizeof(uintptr))); - - ret->type = st; - copyin(st, elem, &ret->data); -} - -// ifaceI2T(sigt *byte, iface any) (ret any); -#pragma textflag 7 -void -sys·ifaceI2T(Sigt *st, Iface i, ...) -{ - Itype *im; - byte *ret; - - ret = (byte*)(&i+1); - - im = i.type; - if(im == nil) { - printf("interface is nil, not %s\n", st->name); - throw("interface conversion"); - } - if(im->sigt != st) { - printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name); - throw("interface conversion"); - } - copyout(st, &i.data, ret); -} - -// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); -#pragma textflag 7 -void -sys·ifaceI2T2(Sigt *st, Iface i, ...) -{ - byte *ret; - bool *ok; - Itype *im; - int32 wid; - - ret = (byte*)(&i+1); - wid = st->width; - ok = (bool*)(ret+rnd(wid, 1)); - - im = i.type; - if(im == nil || im->sigt != st) { - *ok = false; - sys·memclr(ret, wid); - return; - } - - *ok = true; - copyout(st, &i.data, ret); -} - -// ifaceE2T(sigt *byte, iface any) (ret any); -#pragma textflag 7 -void -sys·ifaceE2T(Sigt *st, Eface e, ...) -{ - Sigt *t; - byte *ret; - - ret = (byte*)(&e+1); - - t = e.type; - if(t == nil) { - printf("interface is nil, not %s\n", st->name); - throw("interface conversion"); - } - if(t != st) { - printf("interface is %s, not %s\n", t->name, st->name); - throw("interface conversion"); - } - copyout(st, &e.data, ret); -} - -// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); -#pragma textflag 7 -void -sys·ifaceE2T2(Sigt *st, Eface e, ...) -{ - byte *ret; - bool *ok; - Sigt *t; - int32 wid; - - ret = (byte*)(&e+1); - wid = st->width; - ok = (bool*)(ret+rnd(wid, 1)); - - t = e.type; - if(t != st) { - *ok = false; - sys·memclr(ret, wid); - return; - } - - *ok = true; - copyout(st, &e.data, ret); -} - -// ifaceI2E(sigi *byte, iface any) (ret any); -// TODO(rsc): Move to back end, throw away function. -void -sys·ifaceI2E(Iface i, Eface ret) -{ - Itype *im; - - ret.data = i.data; - im = i.type; - if(im == nil) - ret.type = nil; - else - ret.type = im->sigt; - FLUSH(&ret); -} - -// ifaceI2I(sigi *byte, iface any) (ret any); -// called only for implicit (no type assertion) conversions -void -sys·ifaceI2I(Sigi *si, Iface i, Iface ret) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // If incoming interface is uninitialized (zeroed) - // make the outgoing interface zeroed as well. - ret = niliface; - } else { - ret = i; - if(im->sigi != si) - ret.type = itype(si, im->sigt, 0); - } - - FLUSH(&ret); -} - -// ifaceI2Ix(sigi *byte, iface any) (ret any); -// called only for explicit conversions (with type assertion). -void -sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // explicit conversions require non-nil interface value. - printf("interface is nil, not %s\n", si->name); - throw("interface conversion"); - } else { - ret = i; - if(im->sigi != si) - ret.type = itype(si, im->sigt, 0); - } - - FLUSH(&ret); -} - -// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); -void -sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // If incoming interface is nil, the conversion fails. - ret = niliface; - ok = false; - } else { - ret = i; - ok = true; - if(im->sigi != si) { - ret.type = itype(si, im->sigt, 1); - if(ret.type == nil) { - ret = niliface; - ok = false; - } - } - } - - FLUSH(&ret); - FLUSH(&ok); -} - -// ifaceE2I(sigi *byte, iface any) (ret any); -// Called only for explicit conversions (with type assertion). -void -sys·ifaceE2I(Sigi *si, Eface e, Iface ret) -{ - Sigt *t; - - t = e.type; - if(t == nil) { - // explicit conversions require non-nil interface value. - printf("interface is nil, not %s\n", si->name); - throw("interface conversion"); - } else { - ret.data = e.data; - ret.type = itype(si, t, 0); - } - FLUSH(&ret); -} - -// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); -void -sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) -{ - Sigt *t; - - t = e.type; - ok = true; - if(t == nil) { - // If incoming interface is nil, the conversion fails. - ret = niliface; - ok = false; - } else { - ret.data = e.data; - ret.type = itype(si, t, 1); - if(ret.type == nil) { - ret = niliface; - ok = false; - } - } - FLUSH(&ret); - FLUSH(&ok); -} - -static uintptr -ifacehash1(void *data, Sigt *sigt) -{ - int32 alg, wid; - - if(sigt == nil) - return 0; - - alg = sigt->alg; - wid = sigt->width; - if(algarray[alg].hash == nohash) { - // calling nohash will throw too, - // but we can print a better error. - printf("hash of unhashable type %s\n", sigt->name); - if(alg == AFAKE) - throw("fake interface hash"); - throw("interface hash"); - } - if(wid <= sizeof(data)) - return algarray[alg].hash(wid, &data); - return algarray[alg].hash(wid, data); -} - -uintptr -ifacehash(Iface a) -{ - if(a.type == nil) - return 0; - return ifacehash1(a.data, a.type->sigt); -} - -uintptr -efacehash(Eface a) -{ - return ifacehash1(a.data, a.type); -} - -static bool -ifaceeq1(void *data1, void *data2, Sigt *sigt) -{ - int32 alg, wid; - - alg = sigt->alg; - wid = sigt->width; - - if(algarray[alg].equal == noequal) { - // calling noequal will throw too, - // but we can print a better error. - printf("comparing uncomparable type %s\n", sigt->name); - if(alg == AFAKE) - throw("fake interface compare"); - throw("interface compare"); - } - - if(wid <= sizeof(data1)) - return algarray[alg].equal(wid, &data1, &data2); - return algarray[alg].equal(wid, data1, data2); -} - -bool -ifaceeq(Iface i1, Iface i2) -{ - if(i1.type != i2.type) - return false; - if(i1.type == nil) - return true; - return ifaceeq1(i1.data, i2.data, i1.type->sigt); -} - -bool -efaceeq(Eface e1, Eface e2) -{ - if(e1.type != e2.type) - return false; - if(e1.type == nil) - return true; - return ifaceeq1(e1.data, e2.data, e1.type); -} - -// ifaceeq(i1 any, i2 any) (ret bool); -void -sys·ifaceeq(Iface i1, Iface i2, bool ret) -{ - ret = ifaceeq(i1, i2); - FLUSH(&ret); -} - -// efaceeq(i1 any, i2 any) (ret bool) -void -sys·efaceeq(Eface e1, Eface e2, bool ret) -{ - ret = efaceeq(e1, e2); - FLUSH(&ret); -} - -// ifacethash(i1 any) (ret uint32); -void -sys·ifacethash(Iface i1, uint32 ret) -{ - Itype *im; - Sigt *st; - - ret = 0; - im = i1.type; - if(im != nil) { - st = im->sigt; - if(st != nil) - ret = st->thash; - } - FLUSH(&ret); -} - -// efacethash(e1 any) (ret uint32) -void -sys·efacethash(Eface e1, uint32 ret) -{ - Sigt *st; - - ret = 0; - st = e1.type; - if(st != nil) - ret = st->thash; - FLUSH(&ret); -} - -void -sys·printiface(Iface i) -{ - printiface(i); -} - -void -sys·printeface(Eface e) -{ - printeface(e); -} - -void -unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir) -{ - int32 wid; - - if(i.type == nil) { - retit = 0; - rettype = emptystring; - retindir = false; - } else { - retit = (uint64)i.data; - rettype = gostring(i.type->name); - wid = i.type->width; - retindir = wid > sizeof(i.data); - } - FLUSH(&retit); - FLUSH(&rettype); - FLUSH(&retindir); -} - -extern Sigt *gotypesigs[]; -extern int32 ngotypesigs; - - -// The reflection library can ask to unreflect on a type -// that has never been used, so we don't have a signature for it. -// For concreteness, suppose a program does -// -// type T struct{ x []int } -// var t T; -// v := reflect.NewValue(v); -// vv := v.Field(0); -// if s, ok := vv.Interface().(string) { -// print("first field is string"); -// } -// -// vv.Interface() returns the result of sys.Unreflect with -// a typestring of "[]int". If []int is not used with interfaces -// in the rest of the program, there will be no signature in gotypesigs -// for "[]int", so we have to invent one. The requirements -// on the fake signature are: -// -// (1) any interface conversion using the signature will fail -// (2) calling unsafe.Reflect() returns the args to unreflect -// (3) the right algorithm type is used, for == and map insertion -// -// (1) is ensured by the fact that we allocate a new Sigt, -// so it will necessarily be != any Sigt in gotypesigs. -// (2) is ensured by storing the type string in the signature -// and setting the width to force the correct value of the bool indir. -// (3) is ensured by sniffing the type string. -// -// Note that (1) is correct behavior: if the program had tested -// for .([]int) instead of .(string) above, then there would be a -// signature with type string "[]int" in gotypesigs, and unreflect -// wouldn't call fakesigt. - -static Sigt* fake[1009]; -static int32 nfake; - -enum -{ - SizeofInt = 4, - SizeofFloat = 4, -}; - -// Table of prefixes of names of comparable types. -static struct { - int8 *s; - int8 n; - int8 alg; - int8 w; -} cmp[] = -{ - // basic types - "int", 3+1, AMEM, SizeofInt, // +1 is NUL - "uint", 4+1, AMEM, SizeofInt, - "int8", 4+1, AMEM, 1, - "uint8", 5+1, AMEM, 1, - "int16", 5+1, AMEM, 2, - "uint16", 6+1, AMEM, 2, - "int32", 5+1, AMEM, 4, - "uint32", 6+1, AMEM, 4, - "int64", 5+1, AMEM, 8, - "uint64", 6+1, AMEM, 8, - "uintptr", 7+1, AMEM, sizeof(uintptr), - "float", 5+1, AMEM, SizeofFloat, - "float32", 7+1, AMEM, 4, - "float64", 7+1, AMEM, 8, - "bool", 4+1, AMEM, sizeof(bool), - - // string compare is special - "string", 6+1, ASTRING, sizeof(String), - - // generic types, identified by prefix - "*", 1, AMEM, sizeof(uintptr), - "chan ", 5, AMEM, sizeof(uintptr), - "func(", 5, AMEM, sizeof(uintptr), - "map[", 4, AMEM, sizeof(uintptr), -}; - -static Sigt* -fakesigt(String type, bool indir) -{ - Sigt *sigt; - uint32 h; - int32 i, locked; - - h = 0; - for(i=0; i<type.len; i++) - h = h*37 + type.str[i]; - h += indir; - h %= nelem(fake); - - for(locked=0; locked<2; locked++) { - if(locked) - lock(&ifacelock); - for(sigt = fake[h]; sigt != nil; sigt = sigt->link) { - // don't need to compare indir. - // same type string but different indir will have - // different hashes. - if(mcmp(sigt->name, type.str, type.len) == 0) - if(sigt->name[type.len] == '\0') { - if(locked) - unlock(&ifacelock); - return sigt; - } - } - } - - sigt = malloc(sizeof(*sigt)); - sigt->name = malloc(type.len + 1); - mcpy(sigt->name, type.str, type.len); - - sigt->alg = AFAKE; - sigt->width = 1; // small width - if(indir) - sigt->width = 2*sizeof(niliface.data); // big width - - // AFAKE is like ANOEQ; check whether the type - // should have a more capable algorithm. - for(i=0; i<nelem(cmp); i++) { - if(mcmp((byte*)sigt->name, (byte*)cmp[i].s, cmp[i].n) == 0) { - sigt->alg = cmp[i].alg; - sigt->width = cmp[i].w; - break; - } - } - - sigt->link = fake[h]; - fake[h] = sigt; - - unlock(&ifacelock); - return sigt; -} - -static int32 -cmpstringchars(String a, uint8 *b) -{ - int32 i; - byte c1, c2; - - for(i=0;; i++) { - c1 = 0; - if(i < a.len) - c1 = a.str[i]; - c2 = b[i]; - if(c1 < c2) - return -1; - if(c1 > c2) - return +1; - if(c1 == 0) - return 0; - } -} - -static Sigt* -findtype(String type, bool indir) -{ - int32 i, lo, hi, m; - - lo = 0; - hi = ngotypesigs; - while(lo < hi) { - m = lo + (hi - lo)/2; - i = cmpstringchars(type, gotypesigs[m]->name); - if(i == 0) - return gotypesigs[m]; - if(i < 0) - hi = m; - else - lo = m+1; - } - return fakesigt(type, indir); -} - - -void -unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret) -{ - Sigt *sigt; - - ret = nileface; - - if(cmpstring(type, emptystring) == 0) - goto out; - - if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) { - printf("unsafe.Unreflect: cannot put %S in interface\n", type); - throw("unsafe.Unreflect"); - } - - // if we think the type should be indirect - // and caller does not, play it safe, return nil. - sigt = findtype(type, indir); - if(indir != (sigt->width > sizeof(ret.data))) - goto out; - - ret.type = sigt; - ret.data = (void*)it; - -out: - FLUSH(&ret); -} - diff --git a/src/lib/runtime/linux/386/defs.h b/src/lib/runtime/linux/386/defs.h deleted file mode 100755 index 112fc7b09..000000000 --- a/src/lib/runtime/linux/386/defs.h +++ /dev/null @@ -1,136 +0,0 @@ -// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include defs2.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// Types -#pragma pack on - -typedef struct Fpreg Fpreg; -struct Fpreg { - uint16 significand[4]; - uint16 exponent; -}; - -typedef struct Fpxreg Fpxreg; -struct Fpxreg { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg Xmmreg; -struct Xmmreg { - uint32 element[4]; -}; - -typedef struct Fpstate Fpstate; -struct Fpstate { - uint32 cw; - uint32 sw; - uint32 tag; - uint32 ipoff; - uint32 cssel; - uint32 dataoff; - uint32 datasel; - Fpreg _st[8]; - uint16 status; - uint16 magic; - uint32 _fxsr_env[6]; - uint32 mxcsr; - uint32 reserved; - Fpxreg _fxsr_st[8]; - Xmmreg _xmm[8]; - uint32 padding1[44]; - byte _anon_[48]; -}; - -typedef struct Timespec Timespec; -struct Timespec { - int32 tv_sec; - int32 tv_nsec; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int32 tv_sec; - int32 tv_usec; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - byte _u[4]; - uint32 sa_mask; - uint32 sa_flags; - void *sa_restorer; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte _sifields[116]; -}; - -typedef struct Sigaltstack Sigaltstack; -struct Sigaltstack { - void *ss_sp; - int32 ss_flags; - uint32 ss_size; -}; - -typedef struct Sigcontext Sigcontext; -struct Sigcontext { - uint16 gs; - uint16 __gsh; - uint16 fs; - uint16 __fsh; - uint16 es; - uint16 __esh; - uint16 ds; - uint16 __dsh; - uint32 edi; - uint32 esi; - uint32 ebp; - uint32 esp; - uint32 ebx; - uint32 edx; - uint32 ecx; - uint32 eax; - uint32 trapno; - uint32 err; - uint32 eip; - uint16 cs; - uint16 __csh; - uint32 eflags; - uint32 esp_at_signal; - uint16 ss; - uint16 __ssh; - Fpstate *fpstate; - uint32 oldmask; - uint32 cr2; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - uint32 uc_flags; - Ucontext *uc_link; - Sigaltstack uc_stack; - Sigcontext uc_mcontext; - uint32 uc_sigmask; -}; -#pragma pack off diff --git a/src/lib/runtime/linux/386/rt0.s b/src/lib/runtime/linux/386/rt0.s deleted file mode 100755 index 7717c37e8..000000000 --- a/src/lib/runtime/linux/386/rt0.s +++ /dev/null @@ -1,8 +0,0 @@ -// 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. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_386_linux(SB),7,$0 - JMP _rt0_386(SB) diff --git a/src/lib/runtime/linux/386/signal.c b/src/lib/runtime/linux/386/signal.c deleted file mode 100644 index 7dfca6bb4..000000000 --- a/src/lib/runtime/linux/386/signal.c +++ /dev/null @@ -1,102 +0,0 @@ -// 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" -#include "defs.h" -#include "signals.h" -#include "os.h" - -void -dumpregs(Sigcontext *r) -{ - printf("eax %X\n", r->eax); - printf("ebx %X\n", r->ebx); - printf("ecx %X\n", r->ecx); - printf("edx %X\n", r->edx); - printf("edi %X\n", r->edi); - printf("esi %X\n", r->esi); - printf("ebp %X\n", r->ebp); - printf("esp %X\n", r->esp); - printf("eip %X\n", r->eip); - printf("eflags %X\n", r->eflags); - printf("cs %X\n", r->cs); - printf("fs %X\n", r->fs); - printf("gs %X\n", r->gs); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void sigtramp(void); -extern void sigignore(void); // just returns -extern void sigreturn(void); // calls sigreturn - -void -sighandler(int32 sig, Siginfo* info, void* context) -{ - Ucontext *uc; - Sigcontext *sc; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - uc = context; - sc = &uc->uc_mcontext; - - if(sig < 0 || sig >= NSIG) - printf("Signal %d\n", sig); - else - printf("%s\n", sigtab[sig].name); - - printf("Faulting address: %p\n", *(void**)info->_sifields); - printf("pc=%X\n", sc->eip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)sc->eip, (void*)sc->esp, m->curg); - tracebackothers(m->curg); - dumpregs(sc); - } - - breakpoint(); - exit(2); -} - -void -signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - static Sigaction sa; - - int32 i; - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; - sa.sa_restorer = (void*)sigreturn; - for(i = 0; i<NSIG; i++) { - if(sigtab[i].flags) { - if(sigtab[i].flags & SigCatch) - *(void**)sa._u = (void*)sigtramp; // handler - else - *(void**)sa._u = (void*)sigignore; // handler - if(sigtab[i].flags & SigRestart) - sa.sa_flags |= SA_RESTART; - else - sa.sa_flags &= ~SA_RESTART; - rt_sigaction(i, &sa, nil, 8); - } - } -} - diff --git a/src/lib/runtime/linux/386/sys.s b/src/lib/runtime/linux/386/sys.s deleted file mode 100755 index 419973a5c..000000000 --- a/src/lib/runtime/linux/386/sys.s +++ /dev/null @@ -1,222 +0,0 @@ -// 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. - -// -// System calls and other sys.stuff for 386, Linux -// - -TEXT syscall(SB),7,$0 - MOVL 4(SP), AX // syscall number - MOVL 8(SP), BX // arg1 - MOVL 12(SP), CX // arg2 - MOVL 16(SP), DX // arg3 - MOVL 20(SP), SI // arg4 - MOVL 24(SP), DI // arg5 - MOVL 28(SP), BP // arg6 - INT $0x80 - CMPL AX, $0xfffff001 - JLS 2(PC) - INT $3 // not reached - RET - -TEXT exit(SB),7,$0 - MOVL $252, AX // syscall number - MOVL 4(SP), BX - INT $0x80 - INT $3 // not reached - RET - -TEXT exit1(SB),7,$0 - MOVL $1, AX // exit - exit the current os thread - MOVL 4(SP), BX - INT $0x80 - INT $3 // not reached - RET - -TEXT write(SB),7,$0 - MOVL $4, AX // syscall - write - MOVL 4(SP), BX - MOVL 8(SP), CX - MOVL 12(SP), DX - INT $0x80 - RET - -TEXT getpid(SB),7,$0 - MOVL $20, AX - INT $0x80 - RET - -TEXT kill(SB),7,$0 - MOVL $37, AX - MOVL 4(SP), BX - MOVL 8(SP), CX - INT $0x80 - RET - -TEXT sys·write(SB),7,$0 - MOVL $4, AX // syscall - write - MOVL 4(SP), BX - MOVL 8(SP), CX - MOVL 12(SP), DX - INT $0x80 - RET - -TEXT rt_sigaction(SB),7,$0 - MOVL $174, AX // syscall - rt_sigaction - MOVL 4(SP), BX - MOVL 8(SP), CX - MOVL 12(SP), DX - MOVL 16(SP), SI - INT $0x80 - RET - -TEXT sigtramp(SB),7,$0 - MOVL 4(FS), BP // m - MOVL 20(BP), AX // m->gsignal - MOVL AX, 0(FS) // g = m->gsignal - JMP sighandler(SB) - -TEXT sigignore(SB),7,$0 - RET - -TEXT sigreturn(SB),7,$0 - MOVL 4(FS), BP // m - MOVL 32(BP), BP // m->curg - MOVL BP, 0(FS) // g = m->curg - MOVL $173, AX // rt_sigreturn - INT $0x80 - INT $3 // not reached - RET - -TEXT sys·mmap(SB),7,$0 - MOVL $192, AX // mmap2 - MOVL 4(SP), BX - MOVL 8(SP), CX - MOVL 12(SP), DX - MOVL 16(SP), SI - MOVL 20(SP), DI - MOVL 24(SP), BP - SHRL $12, BP - INT $0x80 - CMPL AX, $0xfffff001 - JLS 2(PC) - INT $3 - RET - -// int64 futex(int32 *uaddr, int32 op, int32 val, -// struct timespec *timeout, int32 *uaddr2, int32 val2); -TEXT futex(SB),7,$0 - MOVL $240, AX // futex - MOVL 4(SP), BX - MOVL 8(SP), CX - MOVL 12(SP), DX - MOVL 16(SP), SI - MOVL 20(SP), DI - MOVL 24(SP), BP - INT $0x80 - RET - -// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); -TEXT clone(SB),7,$0 - MOVL $120, AX // clone - MOVL flags+4(SP), BX - MOVL stack+8(SP), CX - - // Copy m, g, fn off parent stack for use by child. - SUBL $12, CX - MOVL m+12(SP), DX - MOVL DX, 0(CX) - MOVL g+16(SP), DX - MOVL DX, 4(CX) - MOVL fn+20(SP), DX - MOVL DX, 8(CX) - - MOVL $120, AX - INT $0x80 - - // In parent, return. - CMPL AX, $0 - JEQ 2(PC) - RET - - // In child, set up new stack, etc. - MOVL 0(CX), BX // m - MOVL 12(AX), AX // fs (= m->cret) - MOVW AX, FS - MOVL 8(CX), DX // fn - ADDL $12, CX - MOVL CX, SP - - // fn is now on top of stack. - - // initialize m->procid to Linux tid - MOVL $224, AX - INT $0x80 - MOVL AX, 20(BX) - - // call fn - CALL DX - - // It shouldn't return; if it does, exit. - MOVL $111, DI - MOVL $1, AX - INT $0x80 - JMP -3(PC) // keep exiting - -TEXT sigaltstack(SB),7,$-8 - MOVL $186, AX // sigaltstack - MOVL new+4(SP), BX - MOVL old+8(SP), CX - INT $0x80 - CMPL AX, $0xfffff001 - JLS 2(PC) - INT $3 - RET - -// // fake the per-goroutine and per-mach registers -// LEAL m0(SB), - -// TODO(rsc): move to linux.s -// <asm-i386/ldt.h> -// struct user_desc { -// unsigned int entry_number; -// unsigned long base_addr; -// unsigned int limit; -// unsigned int seg_32bit:1; -// unsigned int contents:2; -// unsigned int read_exec_only:1; -// unsigned int limit_in_pages:1; -// unsigned int seg_not_present:1; -// unsigned int useable:1; -// }; -#define SEG_32BIT 0x01 -// contents are the 2 bits 0x02 and 0x04. -#define CONTENTS_DATA 0x00 -#define CONTENTS_STACK 0x02 -#define CONTENTS_CODE 0x04 -#define READ_EXEC_ONLY 0x08 -#define LIMIT_IN_PAGES 0x10 -#define SEG_NOT_PRESENT 0x20 -#define USEABLE 0x40 - -// setldt(int entry, int address, int limit) -TEXT setldt(SB),7,$32 - // set up user_desc - LEAL 16(SP), AX // struct user_desc - MOVL entry+0(FP), BX // entry - MOVL BX, 0(AX) - MOVL address+4(FP), BX // base address - MOVL BX, 4(AX) - MOVL limit+8(FP), BX // limit - MOVL BX, 8(AX) - MOVL $(SEG_32BIT|USEABLE|CONTENTS_DATA), 12(AX) // flag bits - - // call modify_ldt - MOVL $123, 0(SP) // syscall - modify_ldt - MOVL $1, 4(SP) // func = 1 (write) - MOVL AX, 8(SP) // user_desc - MOVL $16, 12(SP) // sizeof(user_desc) - CALL syscall(SB) - RET - diff --git a/src/lib/runtime/linux/amd64/defs.h b/src/lib/runtime/linux/amd64/defs.h deleted file mode 100644 index 43b047523..000000000 --- a/src/lib/runtime/linux/amd64/defs.h +++ /dev/null @@ -1,175 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// Types -#pragma pack on - -typedef struct Timespec Timespec; -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte pad0[4]; - byte _sifields[112]; -}; -#pragma pack off -// godefs -f -m64 defs1.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants - -// Types -#pragma pack on - -typedef struct Usigset Usigset; -struct Usigset { - uint64 __val[16]; -}; - -typedef struct Fpxreg Fpxreg; -struct Fpxreg { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg Xmmreg; -struct Xmmreg { - uint32 element[4]; -}; - -typedef struct Fpstate Fpstate; -struct Fpstate { - uint16 cwd; - uint16 swd; - uint16 ftw; - uint16 fop; - uint64 rip; - uint64 rdp; - uint32 mxcsr; - uint32 mxcr_mask; - Fpxreg _st[8]; - Xmmreg _xmm[16]; - uint32 padding[24]; -}; - -typedef struct Fpxreg1 Fpxreg1; -struct Fpxreg1 { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg1 Xmmreg1; -struct Xmmreg1 { - uint32 element[4]; -}; - -typedef struct Fpstate1 Fpstate1; -struct Fpstate1 { - uint16 cwd; - uint16 swd; - uint16 ftw; - uint16 fop; - uint64 rip; - uint64 rdp; - uint32 mxcsr; - uint32 mxcr_mask; - Fpxreg1 _st[8]; - Xmmreg1 _xmm[16]; - uint32 padding[24]; -}; - -typedef struct Sigaltstack Sigaltstack; -struct Sigaltstack { - void *ss_sp; - int32 ss_flags; - byte pad0[4]; - uint64 ss_size; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - int64 gregs[23]; - Fpstate *fpregs; - uint64 __reserved1[8]; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - Sigaltstack uc_stack; - Mcontext uc_mcontext; - Usigset uc_sigmask; - Fpstate __fpregs_mem; -}; - -typedef struct Sigcontext Sigcontext; -struct Sigcontext { - uint64 r8; - uint64 r9; - uint64 r10; - uint64 r11; - uint64 r12; - uint64 r13; - uint64 r14; - uint64 r15; - uint64 rdi; - uint64 rsi; - uint64 rbp; - uint64 rbx; - uint64 rdx; - uint64 rax; - uint64 rcx; - uint64 rsp; - uint64 rip; - uint64 eflags; - uint16 cs; - uint16 gs; - uint16 fs; - uint16 __pad0; - uint64 err; - uint64 trapno; - uint64 oldmask; - uint64 cr2; - Fpstate1 *fpstate; - uint64 __reserved1[8]; -}; -#pragma pack off diff --git a/src/lib/runtime/linux/amd64/rt0.s b/src/lib/runtime/linux/amd64/rt0.s deleted file mode 100644 index 55be5bcee..000000000 --- a/src/lib/runtime/linux/amd64/rt0.s +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_amd64_linux(SB),7,$-8 - MOVQ $_rt0_amd64(SB), AX - JMP AX diff --git a/src/lib/runtime/linux/amd64/signal.c b/src/lib/runtime/linux/amd64/signal.c deleted file mode 100644 index 55215176d..000000000 --- a/src/lib/runtime/linux/amd64/signal.c +++ /dev/null @@ -1,112 +0,0 @@ -// 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" -#include "defs.h" -#include "signals.h" -#include "os.h" - -void -dumpregs(Sigcontext *r) -{ - printf("rax %X\n", r->rax); - printf("rbx %X\n", r->rbx); - printf("rcx %X\n", r->rcx); - printf("rdx %X\n", r->rdx); - printf("rdi %X\n", r->rdi); - printf("rsi %X\n", r->rsi); - printf("rbp %X\n", r->rbp); - printf("rsp %X\n", r->rsp); - printf("r8 %X\n", r->r8 ); - printf("r9 %X\n", r->r9 ); - printf("r10 %X\n", r->r10); - printf("r11 %X\n", r->r11); - printf("r12 %X\n", r->r12); - printf("r13 %X\n", r->r13); - printf("r14 %X\n", r->r14); - printf("r15 %X\n", r->r15); - printf("rip %X\n", r->rip); - printf("rflags %X\n", r->eflags); - printf("cs %X\n", (uint64)r->cs); - printf("fs %X\n", (uint64)r->fs); - printf("gs %X\n", (uint64)r->gs); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void sigtramp(void); -extern void sigignore(void); // just returns -extern void sigreturn(void); // calls sigreturn - -void -sighandler(int32 sig, Siginfo* info, void* context) -{ - Ucontext *uc; - Mcontext *mc; - Sigcontext *sc; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - uc = context; - mc = &uc->uc_mcontext; - sc = (Sigcontext*)mc; // same layout, more conveient names - - if(sig < 0 || sig >= NSIG) - printf("Signal %d\n", sig); - else - printf("%s\n", sigtab[sig].name); - - printf("Faulting address: %p\n", *(void**)info->_sifields); - printf("PC=%X\n", sc->rip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)sc->rip, (void*)sc->rsp, (void*)sc->r15); - tracebackothers((void*)sc->r15); - dumpregs(sc); - } - - breakpoint(); - exit(2); -} - -void -signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - static Sigaction sa; - - int32 i; - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; - sa.sa_restorer = (void*)sigreturn; - for(i = 0; i<NSIG; i++) { - if(sigtab[i].flags) { - if(sigtab[i].flags & SigCatch) - sa.sa_handler = (void*)sigtramp; - else - sa.sa_handler = (void*)sigignore; - if(sigtab[i].flags & SigRestart) - sa.sa_flags |= SA_RESTART; - else - sa.sa_flags &= ~SA_RESTART; - rt_sigaction(i, &sa, nil, 8); - } - } -} - diff --git a/src/lib/runtime/linux/amd64/sys.s b/src/lib/runtime/linux/amd64/sys.s deleted file mode 100644 index f90c704fa..000000000 --- a/src/lib/runtime/linux/amd64/sys.s +++ /dev/null @@ -1,193 +0,0 @@ -// 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. - -// -// System calls and other sys.stuff for AMD64, Linux -// - -TEXT exit(SB),7,$0-8 - MOVL 8(SP), DI - MOVL $231, AX // exitgroup - force all os threads to exi - SYSCALL - RET - -TEXT exit1(SB),7,$0-8 - MOVL 8(SP), DI - MOVL $60, AX // exit - exit the current os thread - SYSCALL - RET - -TEXT open(SB),7,$0-16 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVL $2, AX // syscall entry - SYSCALL - RET - -TEXT close(SB),7,$0-8 - MOVL 8(SP), DI - MOVL $3, AX // syscall entry - SYSCALL - RET - -TEXT fstat(SB),7,$0-16 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL $5, AX // syscall entry - SYSCALL - RET - -TEXT read(SB),7,$0-24 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL 24(SP), DX - MOVL $0, AX // syscall entry - SYSCALL - RET - -TEXT write(SB),7,$0-24 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL 24(SP), DX - MOVL $1, AX // syscall entry - SYSCALL - RET - -TEXT sys·write(SB),7,$0-24 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVL 24(SP), DX - MOVL $1, AX // syscall entry - SYSCALL - RET - -TEXT rt_sigaction(SB),7,$0-32 - MOVL 8(SP), DI - MOVQ 16(SP), SI - MOVQ 24(SP), DX - MOVQ 32(SP), R10 - MOVL $13, AX // syscall entry - SYSCALL - RET - -TEXT sigtramp(SB),7,$24-16 - MOVQ 32(R14), R15 // g = m->gsignal - MOVQ DI,0(SP) - MOVQ SI,8(SP) - MOVQ DX,16(SP) - CALL sighandler(SB) - RET - -TEXT sigignore(SB),7,$0 - RET - -TEXT sigreturn(SB),7,$0 - MOVL $15, AX // rt_sigreturn - SYSCALL - INT $3 // not reached - -TEXT sys·mmap(SB),7,$0-32 - MOVQ 8(SP), DI - MOVQ $0, SI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVL 24(SP), R10 - MOVL 28(SP), R8 - MOVL 32(SP), R9 - - MOVL $9, AX // syscall entry - SYSCALL - CMPQ AX, $0xfffffffffffff001 - JLS 2(PC) - CALL notok(SB) - RET - -TEXT notok(SB),7,$0 - MOVQ $0xf1, BP - MOVQ BP, (BP) - RET - -TEXT sys·memclr(SB),7,$0-16 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), CX // arg 2 count (cannot be zero) - ADDL $7, CX - SHRL $3, CX - MOVQ $0, AX - CLD - REP - STOSQ - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ -8(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ x+8(FP), BX - MOVQ BX, -8(AX) // set calling pc - RET - -// int64 futex(int32 *uaddr, int32 op, int32 val, -// struct timespec *timeout, int32 *uaddr2, int32 val2); -TEXT futex(SB),7,$0 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVQ 24(SP), R10 - MOVQ 32(SP), R8 - MOVL 40(SP), R9 - MOVL $202, AX - SYSCALL - RET - -// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); -TEXT clone(SB),7,$0 - MOVL flags+8(SP), DI - MOVQ stack+16(SP), SI - - // Copy m, g, fn off parent stack for use by child. - // Careful: Linux system call clobbers CX and R11. - MOVQ m+24(SP), R8 - MOVQ g+32(SP), R9 - MOVQ fn+40(SP), R12 - - MOVL $56, AX - SYSCALL - - // In parent, return. - CMPQ AX, $0 - JEQ 2(PC) - RET - - // In child, set up new stack - MOVQ SI, SP - MOVQ R8, R14 // m - MOVQ R9, R15 // g - - // Initialize m->procid to Linux tid - MOVL $186, AX // gettid - SYSCALL - MOVQ AX, 24(R14) - - // Call fn - CALL R12 - - // It shouldn't return. If it does, exi - MOVL $111, DI - MOVL $60, AX - SYSCALL - JMP -3(PC) // keep exiting - -TEXT sigaltstack(SB),7,$-8 - MOVQ new+8(SP), DI - MOVQ old+16(SP), SI - MOVQ $131, AX - SYSCALL - CMPQ AX, $0xfffffffffffff001 - JLS 2(PC) - CALL notok(SB) - RET diff --git a/src/lib/runtime/linux/arm/defs.h b/src/lib/runtime/linux/arm/defs.h deleted file mode 100644 index caad66989..000000000 --- a/src/lib/runtime/linux/arm/defs.h +++ /dev/null @@ -1,27 +0,0 @@ -// godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f -I/usr/local/google/src/linux-2.6.28/include defs_arm.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// Types -#pragma pack on - -typedef struct Timespec Timespec; -struct Timespec { - int32 tv_sec; - int32 tv_nsec; -}; -#pragma pack off diff --git a/src/lib/runtime/linux/arm/rt0.s b/src/lib/runtime/linux/arm/rt0.s deleted file mode 100644 index 024547ddd..000000000 --- a/src/lib/runtime/linux/arm/rt0.s +++ /dev/null @@ -1,6 +0,0 @@ -// 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. - -TEXT _rt0_arm_linux(SB),7,$0 - B _rt0_arm(SB) diff --git a/src/lib/runtime/linux/arm/signal.c b/src/lib/runtime/linux/arm/signal.c deleted file mode 100644 index 024018d5a..000000000 --- a/src/lib/runtime/linux/arm/signal.c +++ /dev/null @@ -1,4 +0,0 @@ -// 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. - diff --git a/src/lib/runtime/linux/arm/sys.s b/src/lib/runtime/linux/arm/sys.s deleted file mode 100644 index f5db32305..000000000 --- a/src/lib/runtime/linux/arm/sys.s +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -// -// System calls and other sys.stuff for arm, Linux -// - -TEXT write(SB),7,$0 - MOVW 4(SP), R0 - MOVW 8(SP), R1 - MOVW 12(SP), R2 - SWI $0x00900004 // syscall write - RET - diff --git a/src/lib/runtime/linux/defs.c b/src/lib/runtime/linux/defs.c deleted file mode 100644 index 35fa02953..000000000 --- a/src/lib/runtime/linux/defs.c +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m64 defs1.c >>amd64/defs.h - */ - -// Linux glibc and Linux kernel define different and conflicting -// definitions for struct sigaction, struct timespec, etc. -// We want the kernel ones, which are in the asm/* headers. -// But then we'd get conflicts when we include the system -// headers for things like ucontext_t, so that happens in -// a separate file, defs1.c. - -#include <asm/signal.h> -#include <asm/siginfo.h> -#include <asm/mman.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, -}; - -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct sigaction $Sigaction; -typedef siginfo_t $Siginfo; diff --git a/src/lib/runtime/linux/defs1.c b/src/lib/runtime/linux/defs1.c deleted file mode 100644 index 0fe3506ad..000000000 --- a/src/lib/runtime/linux/defs1.c +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m64 defs1.c >>amd64/defs.h - */ - -#include <ucontext.h> - -typedef __sigset_t $Usigset; -typedef struct _libc_fpxreg $Fpxreg; -typedef struct _libc_xmmreg $Xmmreg; -typedef struct _libc_fpstate $Fpstate; -typedef struct _libc_fpreg $Fpreg; -typedef struct _fpxreg $Fpxreg1; -typedef struct _xmmreg $Xmmreg1; -typedef struct _fpstate $Fpstate1; -typedef struct _fpreg $Fpreg1; -typedef struct sigaltstack $Sigaltstack; -typedef mcontext_t $Mcontext; -typedef ucontext_t $Ucontext; -typedef struct sigcontext $Sigcontext; diff --git a/src/lib/runtime/linux/defs2.c b/src/lib/runtime/linux/defs2.c deleted file mode 100644 index aa0331a37..000000000 --- a/src/lib/runtime/linux/defs2.c +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include defs2.c >386/defs.h - - * The asm header tricks we have to use for Linux on amd64 - * (see defs.c and defs1.c) don't work here, so this is yet another - * file. Sigh. - */ - -#include <asm/signal.h> -#include <asm/mman.h> -#include <asm/sigframe.h> -#include <asm/ucontext.h> - -/* -#include <sys/signal.h> -#include <sys/mman.h> -#include <ucontext.h> -*/ - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, -}; - -typedef struct _fpreg $Fpreg; -typedef struct _fpxreg $Fpxreg; -typedef struct _xmmreg $Xmmreg; -typedef struct _fpstate $Fpstate; -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct sigaction $Sigaction; -typedef siginfo_t $Siginfo; -typedef struct sigaltstack $Sigaltstack; -typedef struct sigcontext $Sigcontext; -typedef struct ucontext $Ucontext; - diff --git a/src/lib/runtime/linux/defs_arm.c b/src/lib/runtime/linux/defs_arm.c deleted file mode 100644 index eaec05154..000000000 --- a/src/lib/runtime/linux/defs_arm.c +++ /dev/null @@ -1,54 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f - -I/usr/local/google/src/linux-2.6.28/include defs_arm.c >arm/defs.h - - * Another input file for ARM defs.h - */ - -#include <asm/signal.h> -#include <asm/mman.h> -#include <asm/sigcontext.h> -#include <asm/ucontext.h> - -/* -#include <sys/signal.h> -#include <sys/mman.h> -#include <ucontext.h> -*/ - -#include <time.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO -}; - - - - -//typedef struct _fpreg $Fpreg; -//typedef struct _fpxreg $Fpxreg; -//typedef struct _xmmreg $Xmmreg; -//typedef struct _fpstate $Fpstate; -typedef struct timespec $Timespec; -//typedef struct timeval $Timeval; -// typedef struct sigaction $Sigaction; -// typedef siginfo_t $Siginfo; -// typedef struct sigaltstack $Sigaltstack; -// typedef struct sigcontext $Sigcontext; -// typedef struct ucontext $Ucontext; diff --git a/src/lib/runtime/linux/os.h b/src/lib/runtime/linux/os.h deleted file mode 100644 index c61619367..000000000 --- a/src/lib/runtime/linux/os.h +++ /dev/null @@ -1,10 +0,0 @@ -// 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. - -// Linux-specific system calls -int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32); -int64 clone(int32, void*, M*, G*, void(*)(void)); - -struct Sigaction; -void rt_sigaction(int64, struct Sigaction*, void*, uint64); diff --git a/src/lib/runtime/linux/signals.h b/src/lib/runtime/linux/signals.h deleted file mode 100644 index 1fb49c513..000000000 --- a/src/lib/runtime/linux/signals.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - - -#define C SigCatch -#define I SigIgnore -#define R SigRestart - -static SigTab sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ 0, "SIGHUP: terminal line hangup", - /* 2 */ 0, "SIGINT: interrupt", - /* 3 */ C, "SIGQUIT: quit", - /* 4 */ C, "SIGILL: illegal instruction", - /* 5 */ C, "SIGTRAP: trace trap", - /* 6 */ C, "SIGABRT: abort", - /* 7 */ C, "SIGBUS: bus error", - /* 8 */ C, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ 0, "SIGUSR1: user-defined signal 1", - /* 11 */ C, "SIGSEGV: segmentation violation", - /* 12 */ 0, "SIGUSR2: user-defined signal 2", - /* 13 */ I, "SIGPIPE: write to broken pipe", - /* 14 */ 0, "SIGALRM: alarm clock", - /* 15 */ 0, "SIGTERM: termination", - /* 16 */ 0, "SIGSTKFLT: stack fault", - /* 17 */ I+R, "SIGCHLD: child status has changed", - /* 18 */ 0, "SIGCONT: continue", - /* 19 */ 0, "SIGSTOP: stop, unblockable", - /* 20 */ 0, "SIGTSTP: keyboard stop", - /* 21 */ 0, "SIGTTIN: background read from tty", - /* 22 */ 0, "SIGTTOU: background write to tty", - /* 23 */ 0, "SIGURG: urgent condition on socket", - /* 24 */ 0, "SIGXCPU: cpu limit exceeded", - /* 25 */ 0, "SIGXFSZ: file size limit exceeded", - /* 26 */ 0, "SIGVTALRM: virtual alarm clock", - /* 27 */ 0, "SIGPROF: profiling alarm clock", - /* 28 */ I+R, "SIGWINCH: window size change", - /* 29 */ 0, "SIGIO: i/o now possible", - /* 30 */ 0, "SIGPWR: power failure restart", - /* 31 */ C, "SIGSYS: bad system call", -}; -#undef C -#undef I -#undef R - -#define NSIG 32 diff --git a/src/lib/runtime/linux/thread.c b/src/lib/runtime/linux/thread.c deleted file mode 100644 index cc9ba161b..000000000 --- a/src/lib/runtime/linux/thread.c +++ /dev/null @@ -1,282 +0,0 @@ -// 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" -#include "defs.h" -#include "signals.h" -#include "os.h" - -// Linux futex. -// -// futexsleep(uint32 *addr, uint32 val) -// futexwakeup(uint32 *addr) -// -// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. -// Futexwakeup wakes up one thread sleeping on addr. -// Futexsleep is allowed to wake up spuriously. - -enum -{ - FUTEX_WAIT = 0, - FUTEX_WAKE = 1, - - EINTR = 4, - EAGAIN = 11, -}; - -// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT). -// I wonder if the timespec that gets to the kernel -// actually has two 32-bit numbers in it, so that -// a 64-bit 1<<40 ends up being 0 seconds, -// 1<<8 nanoseconds. -static Timespec longtime = -{ - 1<<30, // 34 years - 0 -}; - -// Atomically, -// if(*addr == val) sleep -// Might be woken up spuriously; that's allowed. -static void -futexsleep(uint32 *addr, uint32 val) -{ - int64 ret; - - ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0); - if(ret >= 0 || ret == -EAGAIN || ret == -EINTR) - return; - - prints("futexsleep addr="); - sys·printpointer(addr); - prints(" val="); - sys·printint(val); - prints(" returned "); - sys·printint(ret); - prints("\n"); - *(int32*)0x1005 = 0x1005; -} - -// If any procs are sleeping on addr, wake up at least one. -static void -futexwakeup(uint32 *addr) -{ - int64 ret; - - ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0); - - if(ret >= 0) - return; - - // I don't know that futex wakeup can return - // EAGAIN or EINTR, but if it does, it would be - // safe to loop and call futex again. - - prints("futexwakeup addr="); - sys·printpointer(addr); - prints(" returned "); - sys·printint(ret); - prints("\n"); - *(int32*)0x1006 = 0x1006; -} - - -// Lock and unlock. -// -// The lock state is a single 32-bit word that holds -// a 31-bit count of threads waiting for the lock -// and a single bit (the low bit) saying whether the lock is held. -// The uncontended case runs entirely in user space. -// When contention is detected, we defer to the kernel (futex). -// -// A reminder: compare-and-swap cas(addr, old, new) does -// if(*addr == old) { *addr = new; return 1; } -// else return 0; -// but atomically. - -static void -futexlock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0){ - if(cas(&l->key, v, v|1)){ - // Lock wasn't held; we grabbed it. - return; - } - goto again; - } - - // Lock was held; try to add ourselves to the waiter count. - if(!cas(&l->key, v, v+2)) - goto again; - - // We're accounted for, now sleep in the kernel. - // - // We avoid the obvious lock/unlock race because - // the kernel won't put us to sleep if l->key has - // changed underfoot and is no longer v+2. - // - // We only really care that (v&1) == 1 (the lock is held), - // and in fact there is a futex variant that could - // accomodate that check, but let's not get carried away.) - futexsleep(&l->key, v+2); - - // We're awake: remove ourselves from the count. - for(;;){ - v = l->key; - if(v < 2) - throw("bad lock key"); - if(cas(&l->key, v, v-2)) - break; - } - - // Try for the lock again. - goto again; -} - -static void -futexunlock(Lock *l) -{ - uint32 v; - - // Atomically get value and clear lock bit. -again: - v = l->key; - if((v&1) == 0) - throw("unlock of unlocked lock"); - if(!cas(&l->key, v, v&~1)) - goto again; - - // If there were waiters, wake one. - if(v & ~1) - futexwakeup(&l->key); -} - -void -lock(Lock *l) -{ - if(m->locks < 0) - throw("lock count"); - m->locks++; - futexlock(l); -} - -void -unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - throw("lock count"); - futexunlock(l); -} - - -// One-time notifications. -// -// Since the lock/unlock implementation already -// takes care of sleeping in the kernel, we just reuse it. -// (But it's a weird use, so it gets its own interface.) -// -// We use a lock to represent the event: -// unlocked == event has happened. -// Thus the lock starts out locked, and to wait for the -// event you try to lock the lock. To signal the event, -// you unlock the lock. - -void -noteclear(Note *n) -{ - n->lock.key = 0; // memset(n, 0, sizeof *n) - futexlock(&n->lock); -} - -void -notewakeup(Note *n) -{ - futexunlock(&n->lock); -} - -void -notesleep(Note *n) -{ - futexlock(&n->lock); - futexunlock(&n->lock); // Let other sleepers find out too. -} - - -// Clone, the Linux rfork. -enum -{ - CLONE_VM = 0x100, - CLONE_FS = 0x200, - CLONE_FILES = 0x400, - CLONE_SIGHAND = 0x800, - CLONE_PTRACE = 0x2000, - CLONE_VFORK = 0x4000, - CLONE_PARENT = 0x8000, - CLONE_THREAD = 0x10000, - CLONE_NEWNS = 0x20000, - CLONE_SYSVSEM = 0x40000, - CLONE_SETTLS = 0x80000, - CLONE_PARENT_SETTID = 0x100000, - CLONE_CHILD_CLEARTID = 0x200000, - CLONE_UNTRACED = 0x800000, - CLONE_CHILD_SETTID = 0x1000000, - CLONE_STOPPED = 0x2000000, - CLONE_NEWUTS = 0x4000000, - CLONE_NEWIPC = 0x8000000, -}; - -void -newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - int64 ret; - int32 flags; - - /* - * note: strace gets confused if we use CLONE_PTRACE here. - */ - flags = CLONE_PARENT /* getppid doesn't change in child */ - | CLONE_VM /* share memory */ - | CLONE_FS /* share cwd, etc */ - | CLONE_FILES /* share fd table */ - | CLONE_SIGHAND /* share sig handler table */ - | CLONE_THREAD /* revisit - okay for now */ - ; - - if(0){ - prints("newosproc stk="); - sys·printpointer(stk); - prints(" m="); - sys·printpointer(m); - prints(" g="); - sys·printpointer(g); - prints(" fn="); - sys·printpointer(fn); - prints(" clone="); - sys·printpointer(clone); - prints("\n"); - } - - ret = clone(flags, stk, m, g, fn); - if(ret < 0) - *(int32*)123 = 123; -} - -void -osinit(void) -{ -} - -// Called to initialize a new m (including the bootstrap m). -void -minit(void) -{ - // Initialize signal handling. - m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K - signalstack(m->gsignal->stackguard, 32*1024); -} diff --git a/src/lib/runtime/malloc.c b/src/lib/runtime/malloc.c deleted file mode 100644 index 81cdfb300..000000000 --- a/src/lib/runtime/malloc.c +++ /dev/null @@ -1,308 +0,0 @@ -// 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. - -// See malloc.h for overview. -// -// TODO(rsc): double-check stats. -// TODO(rsc): solve "stack overflow during malloc" problem. - -#include "runtime.h" -#include "malloc.h" -#include "defs.h" - -MHeap mheap; -MStats mstats; - -// Allocate an object of at least size bytes. -// Small objects are allocated from the per-thread cache's free lists. -// Large objects (> 32 kB) are allocated straight from the heap. -void* -malloc(uintptr size) -{ - int32 sizeclass; - MCache *c; - uintptr npages; - MSpan *s; - void *v; - uint32 *ref; - - if(m->mallocing) - throw("malloc/free - deadlock"); - m->mallocing = 1; - - if(size == 0) - size = 1; - - if(size <= MaxSmallSize) { - // Allocate from mcache free lists. - sizeclass = SizeToClass(size); - size = class_to_size[sizeclass]; - c = m->mcache; - v = MCache_Alloc(c, sizeclass, size); - if(v == nil) - throw("out of memory"); - mstats.alloc += size; - } else { - // TODO(rsc): Report tracebacks for very large allocations. - - // Allocate directly from heap. - npages = size >> PageShift; - if((size & PageMask) != 0) - npages++; - s = MHeap_Alloc(&mheap, npages, 0); - if(s == nil) - throw("out of memory"); - mstats.alloc += npages<<PageShift; - v = (void*)(s->start << PageShift); - } - - // setup for mark sweep - if(!mlookup(v, nil, nil, &ref)) { - printf("malloc %D; mlookup failed\n", (uint64)size); - throw("malloc mlookup"); - } - *ref = RefNone; - - m->mallocing = 0; - return v; -} - -void* -mallocgc(uintptr size) -{ - void *v; - - v = malloc(size); - if(mstats.inuse_pages > mstats.next_gc) - gc(0); - return v; -} - -// Free the object whose base pointer is v. -void -free(void *v) -{ - int32 sizeclass, size; - uintptr page, tmp; - MSpan *s; - MCache *c; - uint32 *ref; - - if(v == nil) - return; - - if(m->mallocing) - throw("malloc/free - deadlock"); - m->mallocing = 1; - - if(!mlookup(v, nil, nil, &ref)) - throw("free mlookup"); - *ref = RefFree; - - // Find size class for v. - page = (uintptr)v >> PageShift; - sizeclass = MHeapMapCache_GET(&mheap.mapcache, page, tmp); - if(sizeclass == 0) { - // Missed in cache. - s = MHeap_Lookup(&mheap, page); - if(s == nil) - throw("free - invalid pointer"); - sizeclass = s->sizeclass; - if(sizeclass == 0) { - // Large object. - mstats.alloc -= s->npages<<PageShift; - sys_memclr(v, s->npages<<PageShift); - MHeap_Free(&mheap, s); - goto out; - } - MHeapMapCache_SET(&mheap.mapcache, page, sizeclass); - } - - // Small object. - c = m->mcache; - size = class_to_size[sizeclass]; - sys_memclr(v, size); - mstats.alloc -= size; - MCache_Free(c, v, sizeclass, size); - -out: - m->mallocing = 0; -} - -int32 -mlookup(void *v, byte **base, uintptr *size, uint32 **ref) -{ - uintptr n, nobj, i; - byte *p; - MSpan *s; - - s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift); - if(s == nil) { - if(base) - *base = nil; - if(size) - *size = 0; - if(ref) - *ref = 0; - return 0; - } - - p = (byte*)((uintptr)s->start<<PageShift); - if(s->sizeclass == 0) { - // Large object. - if(base) - *base = p; - if(size) - *size = s->npages<<PageShift; - if(ref) - *ref = &s->gcref0; - return 1; - } - - if((byte*)v >= (byte*)s->gcref) { - // pointers into the gc ref counts - // do not count as pointers. - return 0; - } - - n = class_to_size[s->sizeclass]; - i = ((byte*)v - p)/n; - if(base) - *base = p + i*n; - if(size) - *size = n; - nobj = (s->npages << PageShift) / (n + RefcountOverhead); - if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) { - printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n", - s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages); - printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n", - s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift, - (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift)); - throw("bad gcref"); - } - if(ref) - *ref = &s->gcref[i]; - - return 1; -} - -MCache* -allocmcache(void) -{ - return FixAlloc_Alloc(&mheap.cachealloc); -} - -void -mallocinit(void) -{ - InitSizes(); - MHeap_Init(&mheap, SysAlloc); - m->mcache = allocmcache(); - - // See if it works. - free(malloc(1)); -} - -void* -SysAlloc(uintptr n) -{ - mstats.sys += n; - return sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); -} - -void -SysUnused(void *v, uintptr n) -{ - USED(v); - USED(n); - // TODO(rsc): call madvise MADV_DONTNEED -} - -void -SysFree(void *v, uintptr n) -{ - USED(v); - USED(n); - // TODO(rsc): call munmap -} - -// Runtime stubs. - -extern void *oldmal(uint32); - -void* -mal(uint32 n) -{ -//return oldmal(n); - void *v; - - v = mallocgc(n); - - if(0) { - byte *p; - uint32 i; - p = v; - for(i=0; i<n; i++) { - if(p[i] != 0) { - printf("mal %d => %p: byte %d is non-zero\n", n, v, i); - throw("mal"); - } - } - } - -//printf("mal %d %p\n", n, v); // |checkmal to check for overlapping returns. - return v; -} - -// Stack allocator uses malloc/free most of the time, -// but if we're in the middle of malloc and need stack, -// we have to do something else to avoid deadlock. -// In that case, we fall back on a fixed-size free-list -// allocator, assuming that inside malloc all the stack -// frames are small, so that all the stack allocations -// will be a single size, the minimum (right now, 5k). -struct { - Lock; - FixAlloc; -} stacks; - -void* -stackalloc(uint32 n) -{ - void *v; - uint32 *ref; - -//return oldmal(n); - if(m->mallocing) { - lock(&stacks); - if(stacks.size == 0) - FixAlloc_Init(&stacks, n, SysAlloc, nil, nil); - if(stacks.size != n) { - printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n); - throw("stackalloc"); - } - v = FixAlloc_Alloc(&stacks); - unlock(&stacks); - return v; - } - v = malloc(n); - if(!mlookup(v, nil, nil, &ref)) - throw("stackalloc mlookup"); - *ref = RefStack; - return v; -} - -void -stackfree(void *v) -{ -//return; - - if(m->mallocing) { - lock(&stacks); - FixAlloc_Free(&stacks, v); - unlock(&stacks); - return; - } - free(v); -} diff --git a/src/lib/runtime/malloc.h b/src/lib/runtime/malloc.h deleted file mode 100644 index 9b3d6b811..000000000 --- a/src/lib/runtime/malloc.h +++ /dev/null @@ -1,308 +0,0 @@ -// 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. - -// Memory allocator, based on tcmalloc. -// http://goog-perftools.sourceforge.net/doc/tcmalloc.html - -// The main allocator works in runs of pages. -// Small allocation sizes (up to and including 32 kB) are -// rounded to one of about 100 size classes, each of which -// has its own free list of objects of exactly that size. -// Any free page of memory can be split into a set of objects -// of one size class, which are then managed using free list -// allocators. -// -// The allocator's data structures are: -// -// FixAlloc: a free-list allocator for fixed-size objects, -// used to manage storage used by the allocator. -// MHeap: the malloc heap, managed at page (4096-byte) granularity. -// MSpan: a run of pages managed by the MHeap. -// MHeapMap: a mapping from page IDs to MSpans. -// MHeapMapCache: a small cache of MHeapMap mapping page IDs -// to size classes for pages used for small objects. -// MCentral: a shared free list for a given size class. -// MCache: a per-thread (in Go, per-M) cache for small objects. -// MStats: allocation statistics. -// -// Allocating a small object proceeds up a hierarchy of caches: -// -// 1. Round the size up to one of the small size classes -// and look in the corresponding MCache free list. -// If the list is not empty, allocate an object from it. -// This can all be done without acquiring a lock. -// -// 2. If the MCache free list is empty, replenish it by -// taking a bunch of objects from the MCentral free list. -// Moving a bunch amortizes the cost of acquiring the MCentral lock. -// -// 3. If the MCentral free list is empty, replenish it by -// allocating a run of pages from the MHeap and then -// chopping that memory into a objects of the given size. -// Allocating many objects amortizes the cost of locking -// the heap. -// -// 4. If the MHeap is empty or has no page runs large enough, -// allocate a new group of pages (at least 1MB) from the -// operating system. Allocating a large run of pages -// amortizes the cost of talking to the operating system. -// -// Freeing a small object proceeds up the same hierarchy: -// -// 1. Look up the size class for the object and add it to -// the MCache free list. -// -// 2. If the MCache free list is too long or the MCache has -// too much memory, return some to the MCentral free lists. -// -// 3. If all the objects in a given span have returned to -// the MCentral list, return that span to the page heap. -// -// 4. If the heap has too much memory, return some to the -// operating system. -// -// TODO(rsc): Step 4 is not implemented. -// -// Allocating and freeing a large object uses the page heap -// directly, bypassing the MCache and MCentral free lists. -// -// This C code was written with an eye toward translating to Go -// in the future. Methods have the form Type_Method(Type *t, ...). - - -typedef struct FixAlloc FixAlloc; -typedef struct MCentral MCentral; -typedef struct MHeap MHeap; -typedef struct MHeapMap MHeapMap; -typedef struct MHeapMapCache MHeapMapCache; -typedef struct MSpan MSpan; -typedef struct MStats MStats; -typedef struct MLink MLink; - -enum -{ - PageShift = 12, - PageSize = 1<<PageShift, - PageMask = PageSize - 1, -}; -typedef uintptr PageID; // address >> PageShift - -enum -{ - // Tunable constants. - NumSizeClasses = 67, // Number of size classes (must match msize.c) - MaxSmallSize = 32<<10, - - FixAllocChunk = 128<<10, // Chunk size for FixAlloc - MaxMCacheListLen = 256, // Maximum objects on MCacheList - MaxMCacheSize = 2<<20, // Maximum bytes in one MCache - MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap. - HeapAllocChunk = 1<<20, // Chunk size for heap growth -}; - -#ifdef _64BIT -#include "mheapmap64.h" -#else -#include "mheapmap32.h" -#endif - -// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) -struct MLink -{ - MLink *next; -}; - -// SysAlloc obtains a large chunk of memory from the operating system, -// typically on the order of a hundred kilobytes or a megabyte. -// -// SysUnused notifies the operating system that the contents -// of the memory region are no longer needed and can be reused -// for other purposes. The program reserves the right to start -// accessing those pages in the future. -// -// SysFree returns it unconditionally; this is only used if -// an out-of-memory error has been detected midway through -// an allocation. It is okay if SysFree is a no-op. - -void* SysAlloc(uintptr nbytes); -void SysFree(void *v, uintptr nbytes); -void SysUnused(void *v, uintptr nbytes); - - -// FixAlloc is a simple free-list allocator for fixed size objects. -// Malloc uses a FixAlloc wrapped around SysAlloc to manages its -// MCache and MSpan objects. -// -// Memory returned by FixAlloc_Alloc is not zeroed. -// The caller is responsible for locking around FixAlloc calls. -// Callers can keep state in the object but the first word is -// smashed by freeing and reallocating. -struct FixAlloc -{ - uintptr size; - void *(*alloc)(uintptr); - void (*first)(void *arg, byte *p); // called first time p is returned - void *arg; - MLink *list; - byte *chunk; - uint32 nchunk; -}; - -void FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg); -void* FixAlloc_Alloc(FixAlloc *f); -void FixAlloc_Free(FixAlloc *f, void *p); - - -// Statistics. -// Shared with Go: if you edit this structure, also edit ../lib/malloc.go. -struct MStats -{ - uint64 alloc; - uint64 sys; - uint64 stacks; - uint64 inuse_pages; // protected by mheap.Lock - uint64 next_gc; // protected by mheap.Lock - bool enablegc; -}; -extern MStats mstats; - - -// Size classes. Computed and initialized by InitSizes. -// -// SizeToClass(0 <= n <= MaxSmallSize) returns the size class, -// 1 <= sizeclass < NumSizeClasses, for n. -// Size class 0 is reserved to mean "not small". -// -// class_to_size[i] = largest size in class i -// class_to_allocnpages[i] = number of pages to allocate when -// making new objects in class i -// class_to_transfercount[i] = number of objects to move when -// taking a bunch of objects out of the central lists -// and putting them in the thread free list. - -int32 SizeToClass(int32); -extern int32 class_to_size[NumSizeClasses]; -extern int32 class_to_allocnpages[NumSizeClasses]; -extern int32 class_to_transfercount[NumSizeClasses]; -extern void InitSizes(void); - - -// Per-thread (in Go, per-M) cache for small objects. -// No locking needed because it is per-thread (per-M). -typedef struct MCacheList MCacheList; -struct MCacheList -{ - MLink *list; - uint32 nlist; - uint32 nlistmin; -}; - -struct MCache -{ - MCacheList list[NumSizeClasses]; - uint64 size; -}; - -void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size); -void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size); - - -// An MSpan is a run of pages. -enum -{ - MSpanInUse = 0, - MSpanFree, - MSpanListHead, - MSpanDead, -}; -struct MSpan -{ - MSpan *next; // in a span linked list - MSpan *prev; // in a span linked list - MSpan *allnext; // in the list of all spans - PageID start; // starting page number - uintptr npages; // number of pages in span - MLink *freelist; // list of free objects - uint32 ref; // number of allocated objects in this span - uint32 sizeclass; // size class - uint32 state; // MSpanInUse etc - union { - uint32 *gcref; // sizeclass > 0 - uint32 gcref0; // sizeclass == 0 - }; -}; - -void MSpan_Init(MSpan *span, PageID start, uintptr npages); - -// Every MSpan is in one doubly-linked list, -// either one of the MHeap's free lists or one of the -// MCentral's span lists. We use empty MSpan structures as list heads. -void MSpanList_Init(MSpan *list); -bool MSpanList_IsEmpty(MSpan *list); -void MSpanList_Insert(MSpan *list, MSpan *span); -void MSpanList_Remove(MSpan *span); // from whatever list it is in - - -// Central list of free objects of a given size. -struct MCentral -{ - Lock; - int32 sizeclass; - MSpan nonempty; - MSpan empty; - int32 nfree; -}; - -void MCentral_Init(MCentral *c, int32 sizeclass); -int32 MCentral_AllocList(MCentral *c, int32 n, MLink **first); -void MCentral_FreeList(MCentral *c, int32 n, MLink *first); - -// Main malloc heap. -// The heap itself is the "free[]" and "large" arrays, -// but all the other global data is here too. -struct MHeap -{ - Lock; - MSpan free[MaxMHeapList]; // free lists of given length - MSpan large; // free lists length >= MaxMHeapList - MSpan *allspans; - - // span lookup - MHeapMap map; - MHeapMapCache mapcache; - - // central free lists for small size classes. - // the union makes sure that the MCentrals are - // spaced 64 bytes apart, so that each MCentral.Lock - // gets its own cache line. - union { - MCentral; - byte pad[64]; - } central[NumSizeClasses]; - - FixAlloc spanalloc; // allocator for Span* - FixAlloc cachealloc; // allocator for MCache* -}; -extern MHeap mheap; - -void MHeap_Init(MHeap *h, void *(*allocator)(uintptr)); -MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass); -void MHeap_Free(MHeap *h, MSpan *s); -MSpan* MHeap_Lookup(MHeap *h, PageID p); -MSpan* MHeap_LookupMaybe(MHeap *h, PageID p); - -int32 mlookup(void *v, byte **base, uintptr *size, uint32 **ref); -void gc(int32 force); - -enum -{ - RefcountOverhead = 4, // one uint32 per object - - RefFree = 0, // must be zero - RefManual, // manual allocation - don't free - RefStack, // stack segment - don't free and don't scan for pointers - RefNone, // no references - RefSome, // some references -}; - diff --git a/src/lib/runtime/malloc_go.cgo b/src/lib/runtime/malloc_go.cgo deleted file mode 100644 index 6dcdaece2..000000000 --- a/src/lib/runtime/malloc_go.cgo +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -package malloc -#include "runtime.h" -#include "malloc.h" - -func Alloc(n uintptr) (p *byte) { - p = malloc(n); -} - -func Free(p *byte) { - free(p); -} - -func Lookup(p *byte) (base *byte, size uintptr) { - mlookup(p, &base, &size, nil); -} - -func GetStats() (s *MStats) { - s = &mstats; -} - -func GC() { - gc(1); -} - diff --git a/src/lib/runtime/mcache.c b/src/lib/runtime/mcache.c deleted file mode 100644 index ae2594023..000000000 --- a/src/lib/runtime/mcache.c +++ /dev/null @@ -1,105 +0,0 @@ -// 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. - -// Per-thread (in Go, per-M) malloc cache for small objects. -// -// See malloc.h for an overview. - -#include "runtime.h" -#include "malloc.h" - -void* -MCache_Alloc(MCache *c, int32 sizeclass, uintptr size) -{ - MCacheList *l; - MLink *first, *v; - int32 n; - - // Allocate from list. - l = &c->list[sizeclass]; - if(l->list == nil) { - // Replenish using central lists. - n = MCentral_AllocList(&mheap.central[sizeclass], - class_to_transfercount[sizeclass], &first); - l->list = first; - l->nlist = n; - c->size += n*size; - } - v = l->list; - l->list = v->next; - l->nlist--; - if(l->nlist < l->nlistmin) - l->nlistmin = l->nlist; - c->size -= size; - - // v is zeroed except for the link pointer - // that we used above; zero that. - v->next = nil; - return v; -} - -// Take n elements off l and return them to the central free list. -static void -ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass) -{ - MLink *first, **lp; - int32 i; - - // Cut off first n elements. - first = l->list; - lp = &l->list; - for(i=0; i<n; i++) - lp = &(*lp)->next; - l->list = *lp; - *lp = nil; - l->nlist -= n; - if(l->nlist < l->nlistmin) - l->nlistmin = l->nlist; - c->size -= n*class_to_size[sizeclass]; - - // Return them to central free list. - MCentral_FreeList(&mheap.central[sizeclass], n, first); -} - -void -MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size) -{ - int32 i, n; - MCacheList *l; - MLink *p; - - // Put back on list. - l = &c->list[sizeclass]; - p = v; - p->next = l->list; - l->list = p; - l->nlist++; - c->size += size; - - if(l->nlist >= MaxMCacheListLen) { - // Release a chunk back. - ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass); - } - - if(c->size >= MaxMCacheSize) { - // Scavenge. - for(i=0; i<NumSizeClasses; i++) { - l = &c->list[i]; - n = l->nlistmin; - - // n is the minimum number of elements we've seen on - // the list since the last scavenge. If n > 0, it means that - // we could have gotten by with n fewer elements - // without needing to consult the central free list. - // Move toward that situation by releasing n/2 of them. - if(n > 0) { - if(n > 1) - n /= 2; - ReleaseN(c, l, n, i); - } - l->nlistmin = l->nlist; - } - } -} - diff --git a/src/lib/runtime/mcentral.c b/src/lib/runtime/mcentral.c deleted file mode 100644 index 5c9f720c0..000000000 --- a/src/lib/runtime/mcentral.c +++ /dev/null @@ -1,192 +0,0 @@ -// 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. - -// Central free lists. -// -// See malloc.h for an overview. -// -// The MCentral doesn't actually contain the list of free objects; the MSpan does. -// Each MCentral is two lists of MSpans: those with free objects (c->nonempty) -// and those that are completely allocated (c->empty). -// -// TODO(rsc): tcmalloc uses a "transfer cache" to split the list -// into sections of class_to_transfercount[sizeclass] objects -// so that it is faster to move those lists between MCaches and MCentrals. - -#include "runtime.h" -#include "malloc.h" - -static bool MCentral_Grow(MCentral *c); -static void* MCentral_Alloc(MCentral *c); -static void MCentral_Free(MCentral *c, void *v); - -// Initialize a single central free list. -void -MCentral_Init(MCentral *c, int32 sizeclass) -{ - c->sizeclass = sizeclass; - MSpanList_Init(&c->nonempty); - MSpanList_Init(&c->empty); -} - -// Allocate up to n objects from the central free list. -// Return the number of objects allocated. -// The objects are linked together by their first words. -// On return, *pstart points at the first object and *pend at the last. -int32 -MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) -{ - MLink *first, *last, *v; - int32 i; - - - lock(c); - // Replenish central list if empty. - if(MSpanList_IsEmpty(&c->nonempty)) { - if(!MCentral_Grow(c)) { - unlock(c); - *pfirst = nil; - return 0; - } - } - - // Copy from list, up to n. - // First one is guaranteed to work, because we just grew the list. - first = MCentral_Alloc(c); - last = first; - for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) { - last->next = v; - last = v; - } - last->next = nil; - c->nfree -= i; - - unlock(c); - *pfirst = first; - return i; -} - -// Helper: allocate one object from the central free list. -static void* -MCentral_Alloc(MCentral *c) -{ - MSpan *s; - MLink *v; - - if(MSpanList_IsEmpty(&c->nonempty)) - return nil; - s = c->nonempty.next; - s->ref++; - v = s->freelist; - s->freelist = v->next; - if(s->freelist == nil) { - MSpanList_Remove(s); - MSpanList_Insert(&c->empty, s); - } - return v; -} - -// Free n objects back into the central free list. -// Return the number of objects allocated. -// The objects are linked together by their first words. -// On return, *pstart points at the first object and *pend at the last. -void -MCentral_FreeList(MCentral *c, int32 n, MLink *start) -{ - MLink *v, *next; - - // Assume next == nil marks end of list. - // n and end would be useful if we implemented - // the transfer cache optimization in the TODO above. - USED(n); - - lock(c); - for(v=start; v; v=next) { - next = v->next; - MCentral_Free(c, v); - } - unlock(c); -} - -// Helper: free one object back into the central free list. -static void -MCentral_Free(MCentral *c, void *v) -{ - MSpan *s; - PageID page; - MLink *p, *next; - - // Find span for v. - page = (uintptr)v >> PageShift; - s = MHeap_Lookup(&mheap, page); - if(s == nil || s->ref == 0) - throw("invalid free"); - - // Move to nonempty if necessary. - if(s->freelist == nil) { - MSpanList_Remove(s); - MSpanList_Insert(&c->nonempty, s); - } - - // Add v back to s's free list. - p = v; - p->next = s->freelist; - s->freelist = p; - c->nfree++; - - // If s is completely freed, return it to the heap. - if(--s->ref == 0) { - MSpanList_Remove(s); - // Freed blocks are zeroed except for the link pointer. - // Zero the link pointers so that the page is all zero. - for(p=s->freelist; p; p=next) { - next = p->next; - p->next = nil; - } - s->freelist = nil; - c->nfree -= (s->npages << PageShift) / class_to_size[c->sizeclass]; - unlock(c); - MHeap_Free(&mheap, s); - lock(c); - } -} - -// Fetch a new span from the heap and -// carve into objects for the free list. -static bool -MCentral_Grow(MCentral *c) -{ - int32 i, n, npages, size; - MLink **tailp, *v; - byte *p; - MSpan *s; - - unlock(c); - npages = class_to_allocnpages[c->sizeclass]; - s = MHeap_Alloc(&mheap, npages, c->sizeclass); - if(s == nil) { - // TODO(rsc): Log out of memory - lock(c); - return false; - } - - // Carve span into sequence of blocks. - tailp = &s->freelist; - p = (byte*)(s->start << PageShift); - size = class_to_size[c->sizeclass]; - n = (npages << PageShift) / (size + RefcountOverhead); - s->gcref = (uint32*)(p + size*n); - for(i=0; i<n; i++) { - v = (MLink*)p; - *tailp = v; - tailp = &v->next; - p += size; - } - *tailp = nil; - - lock(c); - c->nfree += n; - MSpanList_Insert(&c->nonempty, s); - return true; -} diff --git a/src/lib/runtime/mem.c b/src/lib/runtime/mem.c deleted file mode 100644 index 7ed299eb0..000000000 --- a/src/lib/runtime/mem.c +++ /dev/null @@ -1,75 +0,0 @@ -// 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" -#include "defs.h" - -// Stubs for memory management. -// In a separate file so they can be overridden during testing of gc. - -enum -{ - NHUNK = 20<<20, -}; - -// Convenient wrapper around mmap. -static void* -brk(uint32 n) -{ - byte *v; - - v = sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); - m->mem.nmmap += n; - return v; -} - -// Allocate n bytes of memory. Note that this gets used -// to allocate new stack segments, so at each call to a function -// you have to ask yourself "would it be okay to call mal recursively -// right here?" The answer is yes unless we're in the middle of -// editing the malloc state in m->mem. -void* -oldmal(uint32 n) -{ - byte* v; - - // round to keep everything 64-bit aligned - n = rnd(n, 8); - - // be careful. calling any function might invoke - // mal to allocate more stack. - if(n > NHUNK) { - v = brk(n); - } else { - // allocate a new hunk if this one is too small - if(n > m->mem.nhunk) { - // here we're in the middle of editing m->mem - // (we're about to overwrite m->mem.hunk), - // so we can't call brk - it might call mal to grow the - // stack, and the recursive call would allocate a new - // hunk, and then once brk returned we'd immediately - // overwrite that hunk with our own. - // (the net result would be a memory leak, not a crash.) - // so we have to call sys_mmap directly - it is written - // in assembly and tagged not to grow the stack. - m->mem.hunk = - sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_ANON|MAP_PRIVATE, 0, 0); - m->mem.nhunk = NHUNK; - m->mem.nmmap += NHUNK; - } - v = m->mem.hunk; - m->mem.hunk += n; - m->mem.nhunk -= n; - } - m->mem.nmal += n; - return v; -} - -void -sys_mal(uint32 n, uint8 *ret) -{ - ret = mal(n); - FLUSH(&ret); -} diff --git a/src/lib/runtime/mfixalloc.c b/src/lib/runtime/mfixalloc.c deleted file mode 100644 index dd4f3f251..000000000 --- a/src/lib/runtime/mfixalloc.c +++ /dev/null @@ -1,56 +0,0 @@ -// 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. - -// Fixed-size object allocator. Returned memory is not zeroed. -// -// See malloc.h for overview. - -#include "runtime.h" -#include "malloc.h" - -// Initialize f to allocate objects of the given size, -// using the allocator to obtain chunks of memory. -void -FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg) -{ - f->size = size; - f->alloc = alloc; - f->first = first; - f->arg = arg; - f->list = nil; - f->chunk = nil; - f->nchunk = 0; -} - -void* -FixAlloc_Alloc(FixAlloc *f) -{ - void *v; - - if(f->list) { - v = f->list; - f->list = *(void**)f->list; - return v; - } - if(f->nchunk < f->size) { - f->chunk = f->alloc(FixAllocChunk); - if(f->chunk == nil) - throw("out of memory (FixAlloc)"); - f->nchunk = FixAllocChunk; - } - v = f->chunk; - if(f->first) - f->first(f->arg, v); - f->chunk += f->size; - f->nchunk -= f->size; - return v; -} - -void -FixAlloc_Free(FixAlloc *f, void *p) -{ - *(void**)p = f->list; - f->list = p; -} - diff --git a/src/lib/runtime/mgc0.c b/src/lib/runtime/mgc0.c deleted file mode 100644 index d58d6ce44..000000000 --- a/src/lib/runtime/mgc0.c +++ /dev/null @@ -1,231 +0,0 @@ -// 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. - -// Garbage collector -- step 0. -// -// Stop the world, mark and sweep garbage collector. -// NOT INTENDED FOR PRODUCTION USE. -// -// A mark and sweep collector provides a way to exercise -// and test the memory allocator and the stack walking machinery -// without also needing to get reference counting -// exactly right. - -#include "runtime.h" -#include "malloc.h" - -enum { - Debug = 0 -}; - -extern byte etext[]; -extern byte end[]; - -enum { - PtrSize = sizeof(void*) -}; - -static void -scanblock(int32 depth, byte *b, int64 n) -{ - int32 off; - void *obj; - uintptr size; - uint32 *ref; - void **vp; - int64 i; - - if(Debug) - printf("%d scanblock %p %D\n", depth, b, n); - off = (uint32)(uintptr)b & (PtrSize-1); - if(off) { - b += PtrSize - off; - n -= PtrSize - off; - } - - vp = (void**)b; - n /= PtrSize; - for(i=0; i<n; i++) { - if(mlookup(vp[i], &obj, &size, &ref)) { - if(*ref == RefFree || *ref == RefStack) - continue; - if(*ref == RefNone) { - if(Debug) - printf("%d found at %p: ", depth, &vp[i]); - *ref = RefSome; - scanblock(depth+1, obj, size); - } - } - } -} - -static void -scanstack(G *g) -{ - Stktop *stk; - byte *sp; - - sp = g->sched.SP; - stk = (Stktop*)g->stackbase; - while(stk) { - scanblock(0, sp, (byte*)stk - sp); - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - } -} - -static void -mark(void) -{ - G *gp; - - // mark data+bss - scanblock(0, etext, end - etext); - - // mark stacks - for(gp=allg; gp!=nil; gp=gp->alllink) { - switch(gp->status){ - default: - printf("unexpected G.status %d\n", gp->status); - throw("mark - bad status"); - case Gdead: - break; - case Grunning: - if(gp != g) - throw("mark - world not stopped"); - scanstack(gp); - break; - case Grunnable: - case Gsyscall: - case Gwaiting: - scanstack(gp); - break; - } - } -} - -static void -sweepspan(MSpan *s) -{ - int32 i, n, npages, size; - byte *p; - - if(s->state != MSpanInUse) - return; - - p = (byte*)(s->start << PageShift); - if(s->sizeclass == 0) { - // Large block. - switch(s->gcref0) { - default: - throw("bad 'ref count'"); - case RefFree: - case RefManual: - case RefStack: - break; - case RefNone: - if(Debug) - printf("free %D at %p\n", (uint64)s->npages<<PageShift, p); - free(p); - break; - case RefSome: - s->gcref0 = RefNone; // set up for next mark phase - break; - } - return; - } - - // Chunk full of small blocks. - // Must match computation in MCentral_Grow. - size = class_to_size[s->sizeclass]; - npages = class_to_allocnpages[s->sizeclass]; - n = (npages << PageShift) / (size + RefcountOverhead); - for(i=0; i<n; i++) { - switch(s->gcref[i]) { - default: - throw("bad 'ref count'"); - case RefFree: - case RefManual: - case RefStack: - break; - case RefNone: - if(Debug) - printf("free %d at %p\n", size, p+i*size); - free(p + i*size); - break; - case RefSome: - s->gcref[i] = RefNone; // set up for next mark phase - break; - } - } -} - -static void -sweep(void) -{ - MSpan *s; - - // Sweep all the spans. - for(s = mheap.allspans; s != nil; s = s->allnext) - sweepspan(s); -} - -// Semaphore, not Lock, so that the goroutine -// reschedules when there is contention rather -// than spinning. -static uint32 gcsema = 1; - -// Initialized from $GOGC. GOGC=off means no gc. -// -// Next gc is after we've allocated an extra amount of -// memory proportional to the amount already in use. -// If gcpercent=100 and we're using 4M, we'll gc again -// when we get to 8M. This keeps the gc cost in linear -// proportion to the allocation cost. Adjusting gcpercent -// just changes the linear constant (and also the amount of -// extra memory used). -static int32 gcpercent = -2; - -void -gc(int32 force) -{ - byte *p; - - // The gc is turned off (via enablegc) until - // the bootstrap has completed. - // Also, malloc gets called in the guts - // of a number of libraries that might be - // holding locks. To avoid priority inversion - // problems, don't bother trying to run gc - // while holding a lock. The next mallocgc - // without a lock will do the gc instead. - if(!mstats.enablegc || m->locks > 0 || panicking) - return; - - if(gcpercent == -2) { // first time through - p = getenv("GOGC"); - if(p == nil || p[0] == '\0') - gcpercent = 100; - else if(strcmp(p, (byte*)"off") == 0) - gcpercent = -1; - else - gcpercent = atoi(p); - } - if(gcpercent < 0) - return; - - semacquire(&gcsema); - gosave(&g->sched); // update g's stack pointer for scanstack - stoptheworld(); - if(mheap.Lock.key != 0) - throw("mheap locked during gc"); - if(force || mstats.inuse_pages >= mstats.next_gc) { - mark(); - sweep(); - mstats.next_gc = mstats.inuse_pages+mstats.inuse_pages*gcpercent/100; - } - starttheworld(); - gosave(&g->sched); // update g's stack pointer for debugging - semrelease(&gcsema); -} diff --git a/src/lib/runtime/mheap.c b/src/lib/runtime/mheap.c deleted file mode 100644 index d0cf2237b..000000000 --- a/src/lib/runtime/mheap.c +++ /dev/null @@ -1,333 +0,0 @@ -// 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. - -// Page heap. -// -// See malloc.h for overview. -// -// When a MSpan is in the heap free list, state == MSpanFree -// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span. -// -// When a MSpan is allocated, state == MSpanInUse -// and heapmap(i) == span for all s->start <= i < s->start+s->npages. - -#include "runtime.h" -#include "malloc.h" - -static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32); -static bool MHeap_Grow(MHeap*, uintptr); -static void MHeap_FreeLocked(MHeap*, MSpan*); -static MSpan *MHeap_AllocLarge(MHeap*, uintptr); -static MSpan *BestFit(MSpan*, uintptr, MSpan*); - -static void -RecordSpan(void *vh, byte *p) -{ - MHeap *h; - MSpan *s; - - h = vh; - s = (MSpan*)p; - s->allnext = h->allspans; - h->allspans = s; -} - -// Initialize the heap; fetch memory using alloc. -void -MHeap_Init(MHeap *h, void *(*alloc)(uintptr)) -{ - uint32 i; - - FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h); - FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil); - MHeapMap_Init(&h->map, alloc); - // h->mapcache needs no init - for(i=0; i<nelem(h->free); i++) - MSpanList_Init(&h->free[i]); - MSpanList_Init(&h->large); - for(i=0; i<nelem(h->central); i++) - MCentral_Init(&h->central[i], i); -} - -// Allocate a new span of npage pages from the heap -// and record its size class in the HeapMap and HeapMapCache. -MSpan* -MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass) -{ - MSpan *s; - - lock(h); - s = MHeap_AllocLocked(h, npage, sizeclass); - if(s != nil) - mstats.inuse_pages += npage; - unlock(h); - return s; -} - -static MSpan* -MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass) -{ - uintptr n; - MSpan *s, *t; - - // Try in fixed-size lists up to max. - for(n=npage; n < nelem(h->free); n++) { - if(!MSpanList_IsEmpty(&h->free[n])) { - s = h->free[n].next; - goto HaveSpan; - } - } - - // Best fit in list of large spans. - if((s = MHeap_AllocLarge(h, npage)) == nil) { - if(!MHeap_Grow(h, npage)) - return nil; - if((s = MHeap_AllocLarge(h, npage)) == nil) - return nil; - } - -HaveSpan: - // Mark span in use. - if(s->state != MSpanFree) - throw("MHeap_AllocLocked - MSpan not free"); - if(s->npages < npage) - throw("MHeap_AllocLocked - bad npages"); - MSpanList_Remove(s); - s->state = MSpanInUse; - - if(s->npages > npage) { - // Trim extra and put it back in the heap. - t = FixAlloc_Alloc(&h->spanalloc); - MSpan_Init(t, s->start + npage, s->npages - npage); - s->npages = npage; - MHeapMap_Set(&h->map, t->start - 1, s); - MHeapMap_Set(&h->map, t->start, t); - MHeapMap_Set(&h->map, t->start + t->npages - 1, t); - t->state = MSpanInUse; - MHeap_FreeLocked(h, t); - } - - // If span is being used for small objects, cache size class. - // No matter what, cache span info, because gc needs to be - // able to map interior pointer to containing span. - s->sizeclass = sizeclass; - for(n=0; n<npage; n++) - MHeapMap_Set(&h->map, s->start+n, s); - if(sizeclass == 0) { - uintptr tmp; - - // If there are entries for this span, invalidate them, - // but don't blow out cache entries about other spans. - for(n=0; n<npage; n++) - if(MHeapMapCache_GET(&h->mapcache, s->start+n, tmp) != 0) - MHeapMapCache_SET(&h->mapcache, s->start+n, 0); - } else { - // Save cache entries for this span. - // If there's a size class, there aren't that many pages. - for(n=0; n<npage; n++) - MHeapMapCache_SET(&h->mapcache, s->start+n, sizeclass); - } - - return s; -} - -// Allocate a span of exactly npage pages from the list of large spans. -static MSpan* -MHeap_AllocLarge(MHeap *h, uintptr npage) -{ - return BestFit(&h->large, npage, nil); -} - -// Search list for smallest span with >= npage pages. -// If there are multiple smallest spans, take the one -// with the earliest starting address. -static MSpan* -BestFit(MSpan *list, uintptr npage, MSpan *best) -{ - MSpan *s; - - for(s=list->next; s != list; s=s->next) { - if(s->npages < npage) - continue; - if(best == nil - || s->npages < best->npages - || (s->npages == best->npages && s->start < best->start)) - best = s; - } - return best; -} - -// Try to add at least npage pages of memory to the heap, -// returning whether it worked. -static bool -MHeap_Grow(MHeap *h, uintptr npage) -{ - uintptr ask; - void *v; - MSpan *s; - - // Ask for a big chunk, to reduce the number of mappings - // the operating system needs to track; also amortizes - // the overhead of an operating system mapping. - ask = npage<<PageShift; - if(ask < HeapAllocChunk) - ask = HeapAllocChunk; - - v = SysAlloc(ask); - if(v == nil) { - if(ask > (npage<<PageShift)) { - ask = npage<<PageShift; - v = SysAlloc(ask); - } - if(v == nil) - return false; - } - - // NOTE(rsc): In tcmalloc, if we've accumulated enough - // system allocations, the heap map gets entirely allocated - // in 32-bit mode. (In 64-bit mode that's not practical.) - - if(!MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) { - SysFree(v, ask); - return false; - } - - // Create a fake "in use" span and free it, so that the - // right coalescing happens. - s = FixAlloc_Alloc(&h->spanalloc); - MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift); - MHeapMap_Set(&h->map, s->start, s); - MHeapMap_Set(&h->map, s->start + s->npages - 1, s); - s->state = MSpanInUse; - MHeap_FreeLocked(h, s); - return true; -} - -// Look up the span at the given page number. -// Page number is guaranteed to be in map -// and is guaranteed to be start or end of span. -MSpan* -MHeap_Lookup(MHeap *h, PageID p) -{ - return MHeapMap_Get(&h->map, p); -} - -// Look up the span at the given page number. -// Page number is *not* guaranteed to be in map -// and may be anywhere in the span. -// Map entries for the middle of a span are only -// valid for allocated spans. Free spans may have -// other garbage in their middles, so we have to -// check for that. -MSpan* -MHeap_LookupMaybe(MHeap *h, PageID p) -{ - MSpan *s; - - s = MHeapMap_GetMaybe(&h->map, p); - if(s == nil || p < s->start || p - s->start >= s->npages) - return nil; - if(s->state != MSpanInUse) - return nil; - return s; -} - -// Free the span back into the heap. -void -MHeap_Free(MHeap *h, MSpan *s) -{ - lock(h); - mstats.inuse_pages -= s->npages; - MHeap_FreeLocked(h, s); - unlock(h); -} - -static void -MHeap_FreeLocked(MHeap *h, MSpan *s) -{ - MSpan *t; - - if(s->state != MSpanInUse || s->ref != 0) { - printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref); - throw("MHeap_FreeLocked - invalid free"); - } - s->state = MSpanFree; - MSpanList_Remove(s); - - // Coalesce with earlier, later spans. - if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) { - s->start = t->start; - s->npages += t->npages; - MHeapMap_Set(&h->map, s->start, s); - MSpanList_Remove(t); - t->state = MSpanDead; - FixAlloc_Free(&h->spanalloc, t); - } - if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) { - s->npages += t->npages; - MHeapMap_Set(&h->map, s->start + s->npages - 1, s); - MSpanList_Remove(t); - t->state = MSpanDead; - FixAlloc_Free(&h->spanalloc, t); - } - - // Insert s into appropriate list. - if(s->npages < nelem(h->free)) - MSpanList_Insert(&h->free[s->npages], s); - else - MSpanList_Insert(&h->large, s); - - // TODO(rsc): IncrementalScavenge() to return memory to OS. -} - -// Initialize a new span with the given start and npages. -void -MSpan_Init(MSpan *span, PageID start, uintptr npages) -{ - span->next = nil; - span->prev = nil; - span->start = start; - span->npages = npages; - span->freelist = nil; - span->ref = 0; - span->sizeclass = 0; - span->state = 0; -} - -// Initialize an empty doubly-linked list. -void -MSpanList_Init(MSpan *list) -{ - list->state = MSpanListHead; - list->next = list; - list->prev = list; -} - -void -MSpanList_Remove(MSpan *span) -{ - if(span->prev == nil && span->next == nil) - return; - span->prev->next = span->next; - span->next->prev = span->prev; - span->prev = nil; - span->next = nil; -} - -bool -MSpanList_IsEmpty(MSpan *list) -{ - return list->next == list; -} - -void -MSpanList_Insert(MSpan *list, MSpan *span) -{ - if(span->next != nil || span->prev != nil) - throw("MSpanList_Insert"); - span->next = list->next; - span->prev = list; - span->next->prev = span; - span->prev->next = span; -} diff --git a/src/lib/runtime/mheapmap32.c b/src/lib/runtime/mheapmap32.c deleted file mode 100644 index 420ca2d83..000000000 --- a/src/lib/runtime/mheapmap32.c +++ /dev/null @@ -1,96 +0,0 @@ -// 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. - -// Heap map, 32-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) -{ - m->allocator = allocator; -} - -MSpan* -MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - return m->p[i1]->s[i2]; -} - -MSpan* -MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2; - MHeapMapNode2 *p2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - return p2->s[i2]; -} - -void -MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Set"); - - m->p[i1]->s[i2] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1; - MHeapMapNode2 *p2; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask; - - // first-level pointer - if(m->p[i1] == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - sys_memclr((byte*)p2, sizeof *p2); - m->p[i1] = p2; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits; - } - return true; -} - diff --git a/src/lib/runtime/mheapmap32.h b/src/lib/runtime/mheapmap32.h deleted file mode 100644 index 0a16ccd10..000000000 --- a/src/lib/runtime/mheapmap32.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans. - -typedef struct MHeapMapNode2 MHeapMapNode2; - -enum -{ - // 32 bit address - 12 bit page size = 20 bits to map - MHeapMap_Level1Bits = 10, - MHeapMap_Level2Bits = 10, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits, - - MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1, - MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1, -}; - -struct MHeapMap -{ - void *(*allocator)(uintptr); - MHeapMapNode2 *p[1<<MHeapMap_Level1Bits]; -}; - -struct MHeapMapNode2 -{ - MSpan *s[1<<MHeapMap_Level2Bits]; -}; - -void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)); -bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages); -MSpan* MHeapMap_Get(MHeapMap *m, PageID k); -MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k); -void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v); - - -// Much of the time, free(v) needs to know only the size class for v, -// not which span it came from. The MHeapMap finds the size class -// by looking up the span. -// -// An MHeapMapCache is a simple direct-mapped cache translating -// page numbers to size classes. It avoids the expensive MHeapMap -// lookup for hot pages. -// -// The cache entries are 32 bits, with the page number in the low part -// and the value at the top. -// -// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers), -// we can use a 16-bit cache entry by not storing the redundant 12 bits -// of the key that are used as the entry index. For now, keep it simple. -enum -{ - MHeapMapCache_HashBits = 12 -}; - -struct MHeapMapCache -{ - uint32 array[1<<MHeapMapCache_HashBits]; -}; - -// All macros for speed (sorry). -#define HMASK ((1<<MHeapMapCache_HashBits)-1) -#define KBITS MHeapMap_TotalBits -#define KMASK ((1LL<<KBITS)-1) - -#define MHeapMapCache_SET(cache, key, value) \ - ((cache)->array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) - -#define MHeapMapCache_GET(cache, key, tmp) \ - (tmp = (cache)->array[(key) & HMASK], \ - (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/lib/runtime/mheapmap64.c b/src/lib/runtime/mheapmap64.c deleted file mode 100644 index 1886ba529..000000000 --- a/src/lib/runtime/mheapmap64.c +++ /dev/null @@ -1,117 +0,0 @@ -// 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. - -// Heap map, 64-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) -{ - m->allocator = allocator; -} - -MSpan* -MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - return m->p[i1]->p[i2]->s[i3]; -} - -MSpan* -MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - p3 = p2->p[i2]; - if(p3 == nil) - return nil; - return p3->s[i3]; -} - -void -MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Set"); - - m->p[i1]->p[i2]->s[i3] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1, i2; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask; - i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask; - - // first-level pointer - if((p2 = m->p[i1]) == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - sys_memclr((byte*)p2, sizeof *p2); - m->p[i1] = p2; - } - - // second-level pointer - if(p2->p[i2] == nil) { - p3 = m->allocator(sizeof *p3); - if(p3 == nil) - return false; - sys_memclr((byte*)p3, sizeof *p3); - p2->p[i2] = p3; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits; - } - return true; -} - diff --git a/src/lib/runtime/mheapmap64.h b/src/lib/runtime/mheapmap64.h deleted file mode 100644 index 127b773f7..000000000 --- a/src/lib/runtime/mheapmap64.h +++ /dev/null @@ -1,96 +0,0 @@ -// 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. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans. -// -// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers), -// we can swap in a 2-level radix tree. -// -// NOTE(rsc): We use a 3-level tree because tcmalloc does, but -// having only three levels requires approximately 1 MB per node -// in the tree, making the minimum map footprint 3 MB. -// Using a 4-level tree would cut the minimum footprint to 256 kB. -// On the other hand, it's just virtual address space: most of -// the memory is never going to be touched, thus never paged in. - -typedef struct MHeapMapNode2 MHeapMapNode2; -typedef struct MHeapMapNode3 MHeapMapNode3; - -enum -{ - // 64 bit address - 12 bit page size = 52 bits to map - MHeapMap_Level1Bits = 18, - MHeapMap_Level2Bits = 18, - MHeapMap_Level3Bits = 16, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits + - MHeapMap_Level3Bits, - - MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1, - MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1, - MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1, -}; - -struct MHeapMap -{ - void *(*allocator)(uintptr); - MHeapMapNode2 *p[1<<MHeapMap_Level1Bits]; -}; - -struct MHeapMapNode2 -{ - MHeapMapNode3 *p[1<<MHeapMap_Level2Bits]; -}; - -struct MHeapMapNode3 -{ - MSpan *s[1<<MHeapMap_Level3Bits]; -}; - -void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)); -bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages); -MSpan* MHeapMap_Get(MHeapMap *m, PageID k); -MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k); -void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v); - - -// Much of the time, free(v) needs to know only the size class for v, -// not which span it came from. The MHeapMap finds the size class -// by looking up the span. -// -// An MHeapMapCache is a simple direct-mapped cache translating -// page numbers to size classes. It avoids the expensive MHeapMap -// lookup for hot pages. -// -// The cache entries are 64 bits, with the page number in the low part -// and the value at the top. -// -// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers), -// we can use a 16-bit cache entry by not storing the redundant 12 bits -// of the key that are used as the entry index. Here in 64-bit land, -// that trick won't work unless the hash table has 2^28 entries. -enum -{ - MHeapMapCache_HashBits = 12 -}; - -struct MHeapMapCache -{ - uintptr array[1<<MHeapMapCache_HashBits]; -}; - -// All macros for speed (sorry). -#define HMASK ((1<<MHeapMapCache_HashBits)-1) -#define KBITS MHeapMap_TotalBits -#define KMASK ((1LL<<KBITS)-1) - -#define MHeapMapCache_SET(cache, key, value) \ - ((cache)->array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) - -#define MHeapMapCache_GET(cache, key, tmp) \ - (tmp = (cache)->array[(key) & HMASK], \ - (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/lib/runtime/msize.c b/src/lib/runtime/msize.c deleted file mode 100644 index 25e22637d..000000000 --- a/src/lib/runtime/msize.c +++ /dev/null @@ -1,165 +0,0 @@ -// 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. - -// Malloc small size classes. -// -// See malloc.h for overview. -// -// The size classes are chosen so that rounding an allocation -// request up to the next size class wastes at most 12.5% (1.125x). -// -// Each size class has its own page count that gets allocated -// and chopped up when new objects of the size class are needed. -// That page count is chosen so that chopping up the run of -// pages into objects of the given size wastes at most 12.5% (1.125x) -// of the memory. It is not necessary that the cutoff here be -// the same as above. -// -// The two sources of waste multiply, so the worst possible case -// for the above constraints would be that allocations of some -// size might have a 26.6% (1.266x) overhead. -// In practice, only one of the wastes comes into play for a -// given size (sizes < 512 waste mainly on the round-up, -// sizes > 512 waste mainly on the page chopping). -// -// TODO(rsc): Compute max waste for any given size. - -#include "runtime.h" -#include "malloc.h" - -int32 class_to_size[NumSizeClasses]; -int32 class_to_allocnpages[NumSizeClasses]; -int32 class_to_transfercount[NumSizeClasses]; - -// The SizeToClass lookup is implemented using two arrays, -// one mapping sizes <= 1024 to their class and one mapping -// sizes >= 1024 and <= MaxSmallSize to their class. -// All objects are 8-aligned, so the first array is indexed by -// the size divided by 8 (rounded up). Objects >= 1024 bytes -// are 128-aligned, so the second array is indexed by the -// size divided by 128 (rounded up). The arrays are filled in -// by InitSizes. - -static int32 size_to_class8[1024/8 + 1]; -static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1]; - -int32 -SizeToClass(int32 size) -{ - if(size > MaxSmallSize) - throw("SizeToClass - invalid size"); - if(size > 1024-8) - return size_to_class128[(size-1024+127) >> 7]; - return size_to_class8[(size+7)>>3]; -} - -void -InitSizes(void) -{ - int32 align, sizeclass, size, osize, nextsize, n; - uint32 i; - uintptr allocsize, npages; - - // Initialize the class_to_size table (and choose class sizes in the process). - class_to_size[0] = 0; - sizeclass = 1; // 0 means no class - align = 8; - for(size = align; size <= MaxSmallSize; size += align) { - if((size&(size-1)) == 0) { // bump alignment once in a while - if(size >= 2048) - align = 256; - else if(size >= 128) - align = size / 8; - else if(size >= 16) - align = 16; // required for x86 SSE instructions, if we want to use them - } - if((align&(align-1)) != 0) - throw("InitSizes - bug"); - - // Make the allocnpages big enough that - // the leftover is less than 1/8 of the total, - // so wasted space is at most 12.5%. - allocsize = PageSize; - osize = size + RefcountOverhead; - while(allocsize%osize > (allocsize/8)) - allocsize += PageSize; - npages = allocsize >> PageShift; - - // If the previous sizeclass chose the same - // allocation size and fit the same number of - // objects into the page, we might as well - // use just this size instead of having two - // different sizes. - if(sizeclass > 1 - && npages == class_to_allocnpages[sizeclass-1] - && allocsize/osize == allocsize/(class_to_size[sizeclass-1]+RefcountOverhead)) { - class_to_size[sizeclass-1] = size; - continue; - } - - class_to_allocnpages[sizeclass] = npages; - class_to_size[sizeclass] = size; - sizeclass++; - } - if(sizeclass != NumSizeClasses) { - printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses); - throw("InitSizes - bad NumSizeClasses"); - } - - // Initialize the size_to_class tables. - nextsize = 0; - for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { - for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8) - size_to_class8[nextsize/8] = sizeclass; - if(nextsize >= 1024) - for(; nextsize <= class_to_size[sizeclass]; nextsize += 128) - size_to_class128[(nextsize-1024)/128] = sizeclass; - } - - // Double-check SizeToClass. - if(0) { - for(n=0; n < MaxSmallSize; n++) { - sizeclass = SizeToClass(n); - if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) { - printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); - printf("incorrect SizeToClass"); - goto dump; - } - if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) { - printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); - printf("SizeToClass too big"); - goto dump; - } - } - } - - // Initialize the class_to_transfercount table. - for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { - n = 64*1024 / class_to_size[sizeclass]; - if(n < 2) - n = 2; - if(n > 32) - n = 32; - class_to_transfercount[sizeclass] = n; - } - return; - -dump: - if(1){ - printf("NumSizeClasses=%d\n", NumSizeClasses); - printf("class_to_size:"); - for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++) - printf(" %d", class_to_size[sizeclass]); - printf("\n\n"); - printf("size_to_class8:"); - for(i=0; i<nelem(size_to_class8); i++) - printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]); - printf("\n"); - printf("size_to_class128:"); - for(i=0; i<nelem(size_to_class128); i++) - printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]); - printf("\n"); - } - throw("InitSizes failed"); -} diff --git a/src/lib/runtime/print.c b/src/lib/runtime/print.c deleted file mode 100644 index 5295e338d..000000000 --- a/src/lib/runtime/print.c +++ /dev/null @@ -1,268 +0,0 @@ -// 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" - - -void -dump(byte *p, int32 n) -{ - 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"); -} - -void -prints(int8 *s) -{ - sys·write(1, s, findnull((byte*)s)); -} - -// Very simple printf. Only for debugging prints. -// Do not add to this without checking with Rob. -void -printf(int8 *s, ...) -{ - int8 *p, *lp; - byte *arg, *narg; - - lp = p = s; - arg = (byte*)(&s+1); - for(; *p; p++) { - if(*p != '%') - continue; - if(p > lp) - sys·write(1, lp, p-lp); - p++; - narg = nil; - switch(*p) { - case 'd': // 32-bit - case 'x': - narg = arg + 4; - break; - case 'D': // 64-bit - case 'X': - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + 8; - break; - case 'p': // pointer-sized - case 's': - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + sizeof(uintptr); - break; - case 'S': // pointer-aligned but bigger - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + sizeof(String); - break; - } - switch(*p) { - case 'd': - sys·printint(*(int32*)arg); - break; - case 'D': - sys·printint(*(int64*)arg); - break; - case 'x': - sys·printhex(*(int32*)arg); - break; - case 'X': - sys·printhex(*(int64*)arg); - break; - case 'p': - sys·printpointer(*(void**)arg); - break; - case 's': - prints(*(int8**)arg); - break; - case 'S': - sys·printstring(*(String*)arg); - break; - } - arg = narg; - lp = p+1; - } - if(p > lp) - sys·write(1, lp, p-lp); -} - - -void -sys·printpc(void *p) -{ - prints("PC="); - sys·printhex((uint64)sys·getcallerpc(p)); -} - -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) -{ - byte buf[20]; - int32 e, s, i, n; - float64 h; - - if(isNaN(v)) { - sys·write(1, "NaN", 3); - return; - } - if(isInf(v, 0)) { - sys·write(1, "+Inf", 4); - return; - } - if(isInf(v, -1)) { - sys·write(1, "+Inf", 4); - return; - } - - - n = 7; // digits printed - e = 0; // exp - s = 0; // sign - if(v != 0) { - // sign - if(v < 0) { - v = -v; - s = 1; - } - - // normalize - while(v >= 10) { - e++; - v /= 10; - } - while(v < 1) { - e--; - v *= 10; - } - - // round - h = 5; - for(i=0; i<n; i++) - h /= 10; - v += h; - if(v >= 10) { - e++; - v /= 10; - } - } - - // format +d.dddd+edd - buf[0] = '+'; - if(s) - buf[0] = '-'; - for(i=0; i<n; i++) { - s = v; - buf[i+2] = s+'0'; - v -= s; - v *= 10.; - } - buf[1] = buf[2]; - buf[2] = '.'; - - buf[n+2] = 'e'; - buf[n+3] = '+'; - if(e < 0) { - e = -e; - buf[n+3] = '-'; - } - - buf[n+4] = (e/100) + '0'; - buf[n+5] = (e/10)%10 + '0'; - buf[n+6] = (e%10) + '0'; - sys·write(1, buf, n+7); -} - -void -sys·printuint(uint64 v) -{ - byte buf[100]; - int32 i; - - for(i=nelem(buf)-1; i>0; i--) { - buf[i] = v%10 + '0'; - if(v < 10) - break; - v = v/10; - } - sys·write(1, buf+i, nelem(buf)-i); -} - -void -sys·printint(int64 v) -{ - if(v < 0) { - sys·write(1, "-", 1); - v = -v; - } - sys·printuint(v); -} - -void -sys·printhex(uint64 v) -{ - static int8 *dig = "0123456789abcdef"; - byte buf[100]; - int32 i; - - i=nelem(buf); - for(; v>0; v/=16) - buf[--i] = dig[v%16]; - if(i == nelem(buf)) - buf[--i] = '0'; - buf[--i] = 'x'; - buf[--i] = '0'; - sys·write(1, buf+i, nelem(buf)-i); -} - -void -sys·printpointer(void *p) -{ - sys·printhex((uint64)p); -} - -void -sys·printstring(String v) -{ - extern int32 maxstring; - - if(v.len > maxstring) { - sys·write(1, "[invalid string]", 16); - return; - } - if(v.len > 0) - sys·write(1, v.str, v.len); -} - -void -sys·printsp(void) -{ - sys·write(1, " ", 1); -} - -void -sys·printnl(void) -{ - sys·write(1, "\n", 1); -} diff --git a/src/lib/runtime/proc.c b/src/lib/runtime/proc.c deleted file mode 100644 index 1d065e6d2..000000000 --- a/src/lib/runtime/proc.c +++ /dev/null @@ -1,858 +0,0 @@ -// 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" -#include "malloc.h" - -typedef struct Sched Sched; - -M m0; -G g0; // idle goroutine for m0 - -static int32 debug = 0; -static Lock debuglock; - -// Go scheduler -// -// The go scheduler's job is to match ready-to-run goroutines (`g's) -// with waiting-for-work schedulers (`m's). If there are ready gs -// and no waiting ms, ready() will start a new m running in a new -// OS thread, so that all ready gs can run simultaneously, up to a limit. -// For now, ms never go away. -// -// The default maximum number of ms is one: go runs single-threaded. -// This is because some locking details have to be worked ou -// (select in particular is not locked properly) and because the low-level -// code hasn't been written yet for OS X. Setting the environmen -// variable $gomaxprocs changes sched.mmax for now. -// -// Even a program that can run without deadlock in a single process -// might use more ms if given the chance. For example, the prime -// sieve will use as many ms as there are primes (up to sched.mmax), -// allowing different stages of the pipeline to execute in parallel. -// We could revisit this choice, only kicking off new ms for blocking -// system calls, but that would limit the amount of parallel computation -// that go would try to do. -// -// In general, one could imagine all sorts of refinements to the -// scheduler, but the goal now is just to get something working on -// Linux and OS X. - -struct Sched { - Lock; - - G *gfree; // available gs (status == Gdead) - - G *ghead; // gs waiting to run - G *gtail; - int32 gwait; // number of gs waiting to run - int32 gcount; // number of gs that are alive - - M *mhead; // ms waiting for work - int32 mwait; // number of ms waiting for work - int32 mcount; // number of ms that have been created - int32 mcpu; // number of ms executing on cpu - int32 mcpumax; // max number of ms allowed on cpu - int32 gomaxprocs; - int32 msyscall; // number of ms in system calls - - int32 predawn; // running initialization, don't run new gs. - - Note stopped; // one g can wait here for ms to stop - int32 waitstop; // after setting this flag -}; - -Sched sched; - -// Scheduling helpers. Sched must be locked. -static void gput(G*); // put/get on ghead/gtail -static G* gget(void); -static void mput(M*); // put/get on mhead -static M* mget(void); -static void gfput(G*); // put/get on gfree -static G* gfget(void); -static void matchmg(void); // match ms to gs -static void readylocked(G*); // ready, but sched is locked - -// Scheduler loop. -static void scheduler(void); - -// The bootstrap sequence is: -// -// call osinit -// call schedinit -// make & queue new G -// call mstart -// -// The new G does: -// -// call main·init_function -// call initdone -// call main·main -void -schedinit(void) -{ - int32 n; - byte *p; - - mallocinit(); - goargs(); - - // Allocate internal symbol table representation now, - // so that we don't need to call malloc when we crash. - findfunc(0); - - sched.gomaxprocs = 1; - p = getenv("GOMAXPROCS"); - if(p != nil && (n = atoi(p)) != 0) - sched.gomaxprocs = n; - sched.mcpumax = sched.gomaxprocs; - sched.mcount = 1; - sched.predawn = 1; -} - -// Called after main·init_function; main·main will be called on return. -void -initdone(void) -{ - // Let's go. - sched.predawn = 0; - mstats.enablegc = 1; - - // If main·init_function started other goroutines, - // kick off new ms to handle them, like ready - // would have, had it not been pre-dawn. - lock(&sched); - matchmg(); - unlock(&sched); -} - -void -goexit(void) -{ - if(debug > 1){ - lock(&debuglock); - printf("goexit goid=%d\n", g->goid); - unlock(&debuglock); - } - g->status = Gmoribund; - gosched(); -} - -void -tracebackothers(G *me) -{ - G *g; - - for(g = allg; g != nil; g = g->alllink) { - if(g == me || g->status == Gdead) - continue; - printf("\ngoroutine %d:\n", g->goid); - traceback(g->sched.PC, g->sched.SP+sizeof(uintptr), g); // gogo adjusts SP by one word - } -} - -// Put on `g' queue. Sched must be locked. -static void -gput(G *g) -{ - g->schedlink = nil; - if(sched.ghead == nil) - sched.ghead = g; - else - sched.gtail->schedlink = g; - sched.gtail = g; - sched.gwait++; -} - -// Get from `g' queue. Sched must be locked. -static G* -gget(void) -{ - G *g; - - g = sched.ghead; - if(g){ - sched.ghead = g->schedlink; - if(sched.ghead == nil) - sched.gtail = nil; - sched.gwait--; - } - return g; -} - -// Put on `m' list. Sched must be locked. -static void -mput(M *m) -{ - m->schedlink = sched.mhead; - sched.mhead = m; - sched.mwait++; -} - -// Get from `m' list. Sched must be locked. -static M* -mget(void) -{ - M *m; - - m = sched.mhead; - if(m){ - sched.mhead = m->schedlink; - sched.mwait--; - } - return m; -} - -// Put on gfree list. Sched must be locked. -static void -gfput(G *g) -{ - g->schedlink = sched.gfree; - sched.gfree = g; -} - -// Get from gfree list. Sched must be locked. -static G* -gfget(void) -{ - G *g; - - g = sched.gfree; - if(g) - sched.gfree = g->schedlink; - return g; -} - -// Mark g ready to run. -void -ready(G *g) -{ - lock(&sched); - readylocked(g); - unlock(&sched); -} - -// Mark g ready to run. Sched is already locked. -// G might be running already and about to stop. -// The sched lock protects g->status from changing underfoot. -static void -readylocked(G *g) -{ - if(g->m){ - // Running on another machine. - // Ready it when it stops. - g->readyonstop = 1; - return; - } - - // Mark runnable. - if(g->status == Grunnable || g->status == Grunning) - throw("bad g->status in ready"); - g->status = Grunnable; - - gput(g); - if(!sched.predawn) - matchmg(); -} - -// Get the next goroutine that m should run. -// Sched must be locked on entry, is unlocked on exit. -// Makes sure that at most $GOMAXPROCS gs are -// running on cpus (not in system calls) at any given time. -static G* -nextgandunlock(void) -{ - G *gp; - - // On startup, each m is assigned a nextg and - // has already been accounted for in mcpu. - if(m->nextg != nil) { - gp = m->nextg; - m->nextg = nil; - unlock(&sched); - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg found g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; - } - - // Otherwise, look for work. - if(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) { - sched.mcpu++; - unlock(&sched); - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg got g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; - } - - // Otherwise, sleep. - mput(m); - if(sched.mcpu == 0 && sched.msyscall == 0) - throw("all goroutines are asleep - deadlock!"); - m->nextg = nil; - noteclear(&m->havenextg); - if(sched.waitstop && sched.mcpu <= sched.mcpumax) { - sched.waitstop = 0; - notewakeup(&sched.stopped); - } - unlock(&sched); - - notesleep(&m->havenextg); - if((gp = m->nextg) == nil) - throw("bad m->nextg in nextgoroutine"); - m->nextg = nil; - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg woke g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; -} - -// TODO(rsc): Remove. This is only temporary, -// for the mark and sweep collector. -void -stoptheworld(void) -{ - lock(&sched); - sched.mcpumax = 1; - while(sched.mcpu > 1) { - noteclear(&sched.stopped); - sched.waitstop = 1; - unlock(&sched); - notesleep(&sched.stopped); - lock(&sched); - } - unlock(&sched); -} - -// TODO(rsc): Remove. This is only temporary, -// for the mark and sweep collector. -void -starttheworld(void) -{ - lock(&sched); - sched.mcpumax = sched.gomaxprocs; - matchmg(); - unlock(&sched); -} - -// Called to start an M. -void -mstart(void) -{ - if(m->mcache == nil) - m->mcache = allocmcache(); - minit(); - scheduler(); -} - -// Kick of new ms as needed (up to mcpumax). -// There are already `other' other cpus that will -// start looking for goroutines shortly. -// Sched is locked. -static void -matchmg(void) -{ - M *m; - G *g; - - if(debug > 1 && sched.ghead != nil) { - lock(&debuglock); - printf("matchmg mcpu=%d mcpumax=%d gwait=%d\n", sched.mcpu, sched.mcpumax, sched.gwait); - unlock(&debuglock); - } - - while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){ - sched.mcpu++; - if((m = mget()) != nil){ - if(debug > 1) { - lock(&debuglock); - printf("wakeup m%d g%d\n", m->id, g->goid); - unlock(&debuglock); - } - m->nextg = g; - notewakeup(&m->havenextg); - }else{ - m = malloc(sizeof(M)); - m->g0 = malg(8192); - m->nextg = g; - m->id = sched.mcount++; - if(debug) { - lock(&debuglock); - printf("alloc m%d g%d\n", m->id, g->goid); - unlock(&debuglock); - } - newosproc(m, m->g0, m->g0->stackbase, mstart); - } - } -} - -// Scheduler loop: find g to run, run it, repeat. -static void -scheduler(void) -{ - G* gp; - - lock(&sched); - if(gosave(&m->sched)){ - // Jumped here via gosave/gogo, so didn't - // execute lock(&sched) above. - lock(&sched); - - if(sched.predawn) - throw("init sleeping"); - - // Just finished running m->curg. - gp = m->curg; - gp->m = nil; - sched.mcpu--; - if(debug > 1) { - lock(&debuglock); - printf("m%d sched g%d status %d\n", m->id, gp->goid, gp->status); - unlock(&debuglock); - } - switch(gp->status){ - case Grunnable: - case Gdead: - // Shouldn't have been running! - throw("bad gp->status in sched"); - case Grunning: - gp->status = Grunnable; - gput(gp); - break; - case Gmoribund: - gp->status = Gdead; - if(--sched.gcount == 0) - exit(0); - break; - } - if(gp->readyonstop){ - gp->readyonstop = 0; - readylocked(gp); - } - } - - // Find (or wait for) g to run. Unlocks sched. - gp = nextgandunlock(); - gp->readyonstop = 0; - gp->status = Grunning; - if(debug > 1) { - lock(&debuglock); - printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.PC); - traceback(gp->sched.PC, gp->sched.SP+8, gp); - unlock(&debuglock); - } - m->curg = gp; - gp->m = m; - g = gp; - gogo(&gp->sched); -} - -// Enter scheduler. If g->status is Grunning, -// re-queues g and runs everyone else who is waiting -// before running g again. If g->status is Gmoribund, -// kills off g. -void -gosched(void) -{ - if(g == m->g0) - throw("gosched of g0"); - if(gosave(&g->sched) == 0){ - g = m->g0; - gogo(&m->sched); - } -} - -// The goroutine g is about to enter a system call. -// Record that it's not using the cpu anymore. -// This is called only from the go syscall library, not -// from the low-level system calls used by the runtime. -// The "arguments" are syscall.Syscall's stack frame -void -sys·entersyscall(uint64 callerpc, int64 trap) -{ - USED(callerpc); - - if(debug > 1) { - lock(&debuglock); - printf("m%d g%d enter syscall %D\n", m->id, g->goid, trap); - unlock(&debuglock); - } - lock(&sched); - g->status = Gsyscall; - sched.mcpu--; - sched.msyscall++; - if(sched.gwait != 0) - matchmg(); - if(sched.waitstop && sched.mcpu <= sched.mcpumax) { - sched.waitstop = 0; - notewakeup(&sched.stopped); - } - unlock(&sched); - // leave SP around for gc and traceback - gosave(&g->sched); -} - -// The goroutine g exited its system call. -// Arrange for it to run on a cpu again. -// This is called only from the go syscall library, not -// from the low-level system calls used by the runtime. -void -sys·exitsyscall(void) -{ - if(debug > 1) { - lock(&debuglock); - printf("m%d g%d exit syscall mcpu=%d mcpumax=%d\n", m->id, g->goid, sched.mcpu, sched.mcpumax); - unlock(&debuglock); - } - - lock(&sched); - g->status = Grunning; - sched.msyscall--; - sched.mcpu++; - // Fast path - if there's room for this m, we're done. - if(sched.mcpu <= sched.mcpumax) { - unlock(&sched); - return; - } - unlock(&sched); - - // Slow path - all the cpus are taken. - // The scheduler will ready g and put this m to sleep. - // When the scheduler takes g awa from m, - // it will undo the sched.mcpu++ above. - gosched(); -} - -/* - * stack layout parameters. - * known to linkers. - * - * g->stackguard is set to point StackGuard bytes - * above the bottom of the stack. each function - * compares its stack pointer against g->stackguard - * to check for overflow. to cut one instruction from - * the check sequence for functions with tiny frames, - * the stack is allowed to protrude StackSmall bytes - * below the stack guard. functions with large frames - * don't bother with the check and always call morestack. - * the sequences are: - * - * guard = g->stackguard - * frame = function's stack frame size - * argsize = size of function arguments (call + return) - * - * stack frame size <= StackSmall: - * CMPQ guard, SP - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size > StackSmall but < StackBig - * LEAQ (frame-StackSmall)(SP), R0 - * CMPQ guard, R0 - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size >= StackBig: - * MOVQ m->morearg, $((argsize << 32) | frame) - * CALL sys.morestack(SB) - * - * the bottom StackGuard - StackSmall bytes are important: - * there has to be enough room to execute functions that - * refuse to check for stack overflow, either because they - * need to be adjacent to the actual caller's frame (sys.deferproc) - * or because they handle the imminent stack overflow (sys.morestack). - * - * for example, sys.deferproc might call malloc, - * which does one of the above checks (without allocating a full frame), - * which might trigger a call to sys.morestack. - * this sequence needs to fit in the bottom section of the stack. - * on amd64, sys.morestack's frame is 40 bytes, and - * sys.deferproc's frame is 56 bytes. that fits well within - * the StackGuard - StackSmall = 128 bytes at the bottom. - * there may be other sequences lurking or yet to be written - * that require more stack. sys.morestack checks to make sure - * the stack has not completely overflowed and should - * catch such sequences. - */ -enum -{ - // byte offset of stack guard (g->stackguard) above bottom of stack. - StackGuard = 256, - - // checked frames are allowed to protrude below the guard by - // this many bytes. this saves an instruction in the checking - // sequence when the stack frame is tiny. - StackSmall = 128, - - // extra space in the frame (beyond the function for which - // the frame is allocated) is assumed not to be much bigger - // than this amount. it may not be used efficiently if it is. - StackBig = 4096, -}; - -void -oldstack(void) -{ - Stktop *top; - uint32 args; - byte *sp; - uintptr oldsp, oldpc, oldbase, oldguard; - -// printf("oldstack m->cret=%p\n", m->cret); - - top = (Stktop*)m->curg->stackbase; - - args = (top->magic>>32) & 0xffffLL; - - sp = (byte*)top; - if(args > 0) { - args = (args+7) & ~7; - sp -= args; - mcpy(top->oldsp+2*sizeof(uintptr), sp, args); - } - - oldsp = (uintptr)top->oldsp + sizeof(uintptr); - oldpc = *(uintptr*)oldsp; - oldbase = (uintptr)top->oldbase; - oldguard = (uintptr)top->oldguard; - - stackfree((byte*)m->curg->stackguard - StackGuard); - - m->curg->stackbase = (byte*)oldbase; - m->curg->stackguard = (byte*)oldguard; - m->morestack.SP = (byte*)oldsp; - m->morestack.PC = (byte*)oldpc; - - // These two lines must happen in sequence; - // once g has been changed, must switch to g's stack - // before calling any non-assembly functions. - // TODO(rsc): Perhaps make the new g a parameter - // to gogoret and setspgoto, so that g is never - // explicitly assigned to without also setting - // the stack pointer. - g = m->curg; - gogoret(&m->morestack, m->cret); -} - -#pragma textflag 7 -void -lessstack(void) -{ - g = m->g0; - setspgoto(m->sched.SP, oldstack, nil); -} - -void -newstack(void) -{ - int32 frame, args; - Stktop *top; - byte *stk, *sp; - void (*fn)(void); - - frame = m->morearg & 0xffffffffLL; - args = (m->morearg>>32) & 0xffffLL; - -// printf("newstack frame=%d args=%d moresp=%p morepc=%p\n", frame, args, m->moresp, *(uintptr*)m->moresp); - - if(frame < StackBig) - frame = StackBig; - frame += 1024; // for more functions, Stktop. - stk = stackalloc(frame); - - top = (Stktop*)(stk+frame-sizeof(*top)); - - top->oldbase = m->curg->stackbase; - top->oldguard = m->curg->stackguard; - top->oldsp = m->moresp; - top->magic = m->morearg; - - m->curg->stackbase = (byte*)top; - m->curg->stackguard = stk + StackGuard; - - sp = (byte*)top; - - if(args > 0) { - // Copy args. There have been two function calls - // since they got pushed, so skip over those return - // addresses. - args = (args+7) & ~7; - sp -= args; - mcpy(sp, m->moresp+2*sizeof(uintptr), args); - } - - g = m->curg; - - // sys.morestack's return address - fn = (void(*)(void))(*(uintptr*)m->moresp); - -// printf("fn=%p\n", fn); - - setspgoto(sp, fn, retfromnewstack); - - *(int32*)345 = 123; // never return -} - -#pragma textflag 7 -void -sys·morestack(uintptr u) -{ - while(g == m->g0) { - // very bad news - *(int32*)0x1001 = 123; - } - - // Morestack's frame is about 0x30 bytes on amd64. - // If that the frame ends below the stack bottom, we've already - // overflowed. Stop right now. - while((byte*)&u - 0x30 < m->curg->stackguard - StackGuard) { - // very bad news - *(int32*)0x1002 = 123; - } - - g = m->g0; - m->moresp = (byte*)(&u-1); - setspgoto(m->sched.SP, newstack, nil); - - *(int32*)0x1003 = 123; // never return -} - -G* -malg(int32 stacksize) -{ - G *g; - byte *stk; - - g = malloc(sizeof(G)); - stk = stackalloc(stacksize + StackGuard); - g->stack0 = stk; - g->stackguard = stk + StackGuard; - g->stackbase = stk + StackGuard + stacksize; - return g; -} - -/* - * Newproc and deferproc need to be textflag 7 - * (no possible stack split when nearing overflow) - * because they assume that the arguments to fn - * are available sequentially beginning at &arg0. - * If a stack split happened, only the one word - * arg0 would be copied. It's okay if any functions - * they call split the stack below the newproc frame. - */ -#pragma textflag 7 -void -sys·newproc(int32 siz, byte* fn, byte* arg0) -{ - byte *stk, *sp; - G *newg; - -//printf("newproc siz=%d fn=%p", siz, fn); - - siz = (siz+7) & ~7; - if(siz > 1024) - throw("sys·newproc: too many args"); - - lock(&sched); - - if((newg = gfget()) != nil){ - newg->status = Gwaiting; - } else { - newg = malg(4096); - newg->status = Gwaiting; - newg->alllink = allg; - allg = newg; - } - stk = newg->stack0; - - newg->stackguard = stk+StackGuard; - - sp = stk + 4096 - 4*8; - newg->stackbase = sp; - - sp -= siz; - mcpy(sp, (byte*)&arg0, siz); - - sp -= sizeof(uintptr); - *(byte**)sp = (byte*)goexit; - - sp -= sizeof(uintptr); // retpc used by gogo - newg->sched.SP = sp; - newg->sched.PC = fn; - - sched.gcount++; - goidgen++; - newg->goid = goidgen; - - readylocked(newg); - unlock(&sched); - -//printf(" goid=%d\n", newg->goid); -} - -#pragma textflag 7 -void -sys·deferproc(int32 siz, byte* fn, byte* arg0) -{ - Defer *d; - - d = malloc(sizeof(*d) + siz - sizeof(d->args)); - d->fn = fn; - d->sp = (byte*)&arg0; - d->siz = siz; - mcpy(d->args, d->sp, d->siz); - - d->link = g->defer; - g->defer = d; -} - -#pragma textflag 7 -void -sys·deferreturn(uintptr arg0) -{ - Defer *d; - byte *sp, *fn; - uintptr *caller; - - d = g->defer; - if(d == nil) - return; - sp = (byte*)&arg0; - if(d->sp != sp) - return; - mcpy(d->sp, d->args, d->siz); - g->defer = d->link; - fn = d->fn; - free(d); - jmpdefer(fn, sp); - } - -void -runtime·Breakpoint(void) -{ - breakpoint(); -} - -void -runtime·Goexit(void) -{ - goexit(); -} - -void -runtime·Gosched(void) -{ - gosched(); -} - diff --git a/src/lib/runtime/rune.c b/src/lib/runtime/rune.c deleted file mode 100644 index ca4f9ac6a..000000000 --- a/src/lib/runtime/rune.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Portions Copyright 2009 The Go Authors. All rights reserved. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -/* - * This code is copied, with slight editing due to type differences, - * from a subset of ../lib9/utf/rune.c - */ - -#include "runtime.h" - -enum -{ - Bit1 = 7, - Bitx = 6, - Bit2 = 5, - Bit3 = 4, - Bit4 = 3, - Bit5 = 2, - - T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ - Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ - T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ - T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ - T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ - T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ - - Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ - Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ - Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ - Rune4 = (1<<(Bit4+3*Bitx))-1, - /* 0001 1111 1111 1111 1111 1111 */ - - Maskx = (1<<Bitx)-1, /* 0011 1111 */ - Testx = Maskx ^ 0xFF, /* 1100 0000 */ - - Runeerror = 0xFFFD, - Runeself = 0x80, - - Bad = Runeerror, - - Runemax = 0x10FFFF, /* maximum rune value */ -}; - -/* - * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24 - * This is a slower but "safe" version of the old chartorune - * that works on strings that are not necessarily null-terminated. - * - * If you know for sure that your string is null-terminated, - * chartorune will be a bit faster. - * - * It is guaranteed not to attempt to access "length" - * past the incoming pointer. This is to avoid - * possible access violations. If the string appears to be - * well-formed but incomplete (i.e., to get the whole Rune - * we'd need to read past str+length) then we'll set the Rune - * to Bad and return 0. - * - * Note that if we have decoding problems for other - * reasons, we return 1 instead of 0. - */ -int32 -charntorune(int32 *rune, uint8 *str, int32 length) -{ - int32 c, c1, c2, c3, l; - - /* When we're not allowed to read anything */ - if(length <= 0) { - goto badlen; - } - - /* - * one character sequence (7-bit value) - * 00000-0007F => T1 - */ - c = *(uint8*)str; - if(c < Tx) { - *rune = c; - return 1; - } - - // If we can't read more than one character we must stop - if(length <= 1) { - goto badlen; - } - - /* - * two character sequence (11-bit value) - * 0080-07FF => T2 Tx - */ - c1 = *(uint8*)(str+1) ^ Tx; - if(c1 & Testx) - goto bad; - if(c < T3) { - if(c < T2) - goto bad; - l = ((c << Bitx) | c1) & Rune2; - if(l <= Rune1) - goto bad; - *rune = l; - return 2; - } - - // If we can't read more than two characters we must stop - if(length <= 2) { - goto badlen; - } - - /* - * three character sequence (16-bit value) - * 0800-FFFF => T3 Tx Tx - */ - c2 = *(uint8*)(str+2) ^ Tx; - if(c2 & Testx) - goto bad; - if(c < T4) { - l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; - if(l <= Rune2) - goto bad; - *rune = l; - return 3; - } - - if (length <= 3) - goto badlen; - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => T4 Tx Tx Tx - */ - c3 = *(uint8*)(str+3) ^ Tx; - if (c3 & Testx) - goto bad; - if (c < T5) { - l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; - if (l <= Rune3 || l > Runemax) - goto bad; - *rune = l; - return 4; - } - - // Support for 5-byte or longer UTF-8 would go here, but - // since we don't have that, we'll just fall through to bad. - - /* - * bad decoding - */ -bad: - *rune = Bad; - return 1; -badlen: - *rune = Bad; - return 0; - -} - -int32 -runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */ -{ - /* Runes are signed, so convert to unsigned for range check. */ - uint32 c; - - /* - * one character sequence - * 00000-0007F => 00-7F - */ - c = rune; - if(c <= Rune1) { - str[0] = c; - return 1; - } - - /* - * two character sequence - * 0080-07FF => T2 Tx - */ - if(c <= Rune2) { - str[0] = T2 | (c >> 1*Bitx); - str[1] = Tx | (c & Maskx); - return 2; - } - - /* - * If the Rune is out of range, convert it to the error rune. - * Do this test here because the error rune encodes to three bytes. - * Doing it earlier would duplicate work, since an out of range - * Rune wouldn't have fit in one or two bytes. - */ - if (c > Runemax) - c = Runeerror; - - /* - * three character sequence - * 0800-FFFF => T3 Tx Tx - */ - if (c <= Rune3) { - str[0] = T3 | (c >> 2*Bitx); - str[1] = Tx | ((c >> 1*Bitx) & Maskx); - str[2] = Tx | (c & Maskx); - return 3; - } - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => T4 Tx Tx Tx - */ - str[0] = T4 | (c >> 3*Bitx); - str[1] = Tx | ((c >> 2*Bitx) & Maskx); - str[2] = Tx | ((c >> 1*Bitx) & Maskx); - str[3] = Tx | (c & Maskx); - return 4; -} diff --git a/src/lib/runtime/runtime.c b/src/lib/runtime/runtime.c deleted file mode 100644 index c5ba3e6a5..000000000 --- a/src/lib/runtime/runtime.c +++ /dev/null @@ -1,462 +0,0 @@ -// 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 panicking = 0; -int32 maxround = sizeof(uintptr); - -int32 -gotraceback(void) -{ - byte *p; - - p = getenv("GOTRACEBACK"); - if(p == nil || p[0] == '\0') - return 1; // default is on - return atoi(p); -} - -void -sys·panicl(int32 lno) -{ - uint8 *sp; - - if(panicking) { - printf("double panic\n"); - exit(3); - } - panicking++; - - printf("\npanic PC=%X\n", (uint64)(uintptr)&lno); - sp = (uint8*)&lno; - if(gotraceback()){ - traceback(sys·getcallerpc(&lno), sp, g); - tracebackothers(g); - } - breakpoint(); // so we can grab it in a debugger - exit(2); -} - -void -sys·throwindex(void) -{ - throw("index out of range"); -} - -void -sys·throwreturn(void) -{ - throw("no return at end of a typed function"); -} - -void -sys·throwinit(void) -{ - throw("recursive call during initialization"); -} - -void -throw(int8 *s) -{ - printf("throw: %s\n", s); - sys·panicl(-1); - *(int32*)0 = 0; // not reached - exit(1); // even more not reached -} - -void -mcpy(byte *t, byte *f, uint32 n) -{ - while(n > 0) { - *t = *f; - t++; - f++; - n--; - } -} - -int32 -mcmp(byte *s1, byte *s2, uint32 n) -{ - uint32 i; - byte c1, c2; - - for(i=0; i<n; i++) { - c1 = s1[i]; - c2 = s2[i]; - if(c1 < c2) - return -1; - if(c1 > c2) - return +1; - } - return 0; -} - - -void -mmov(byte *t, byte *f, uint32 n) -{ - if(t < f) { - while(n > 0) { - *t = *f; - t++; - f++; - n--; - } - } else { - t += n; - f += n; - while(n > 0) { - t--; - f--; - *t = *f; - n--; - } - } -} - -byte* -mchr(byte *p, byte c, byte *ep) -{ - for(; p < ep; p++) - if(*p == c) - return p; - return nil; -} - -uint32 -rnd(uint32 n, uint32 m) -{ - uint32 r; - - if(m > maxround) - m = maxround; - r = n % m; - if(r) - n += m-r; - return n; -} - -static int32 argc; -static uint8** argv; - -Array os·Args; -Array os·Envs; - -void -args(int32 c, uint8 **v) -{ - argc = c; - argv = v; -} - -void -goargs(void) -{ - String *gargv; - String *genvv; - int32 i, envc; - - for(envc=0; argv[argc+1+envc] != 0; envc++) - ; - - gargv = malloc(argc*sizeof gargv[0]); - genvv = malloc(envc*sizeof genvv[0]); - - for(i=0; i<argc; i++) - gargv[i] = gostring(argv[i]); - os·Args.array = (byte*)gargv; - os·Args.nel = argc; - os·Args.cap = argc; - - for(i=0; i<envc; i++) - genvv[i] = gostring(argv[argc+1+i]); - os·Envs.array = (byte*)genvv; - os·Envs.nel = envc; - os·Envs.cap = envc; -} - -byte* -getenv(int8 *s) -{ - int32 i, j, len; - byte *v, *bs; - String* envv; - int32 envc; - - bs = (byte*)s; - len = findnull(bs); - envv = (String*)os·Envs.array; - envc = os·Envs.nel; - for(i=0; i<envc; i++){ - if(envv[i].len <= len) - continue; - v = envv[i].str; - for(j=0; j<len; j++) - if(bs[j] != v[j]) - goto nomatch; - if(v[len] != '=') - goto nomatch; - return v+len+1; - nomatch:; - } - return nil; -} - - -int32 -atoi(byte *p) -{ - int32 n; - - n = 0; - while('0' <= *p && *p <= '9') - n = n*10 + *p++ - '0'; - return n; -} - -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) != sizeof(uintptr)) throw("bad k"); - if(sizeof(l) != sizeof(uintptr)) throw("bad l"); -// prints(1"check ok\n"); - - uint32 z; - z = 1; - if(!cas(&z, 1, 2)) - throw("cas1"); - if(z != 2) - throw("cas2"); - - z = 4; - if(cas(&z, 5, 6)) - throw("cas3"); - if(z != 4) - throw("cas4"); - - initsig(); -} - -/* - * map and chan helpers for - * dealing with unknown types - */ -static uintptr -memhash(uint32 s, void *a) -{ - byte *b; - uintptr hash; - - b = a; - if(sizeof(hash) == 4) - hash = 2860486313U; - else - hash = 33054211828000289ULL; - while(s > 0) { - if(sizeof(hash) == 4) - hash = (hash ^ *b) * 3267000013UL; - else - hash = (hash ^ *b) * 23344194077549503ULL; - b++; - s--; - } - return hash; -} - -static uint32 -memequal(uint32 s, void *a, void *b) -{ - byte *ba, *bb; - uint32 i; - - ba = a; - bb = b; - for(i=0; i<s; i++) - if(ba[i] != bb[i]) - return 0; - return 1; -} - -static void -memprint(uint32 s, void *a) -{ - uint64 v; - - v = 0xbadb00b; - switch(s) { - case 1: - v = *(uint8*)a; - break; - case 2: - v = *(uint16*)a; - break; - case 4: - v = *(uint32*)a; - break; - case 8: - v = *(uint64*)a; - break; - } - sys·printint(v); -} - -static void -memcopy(uint32 s, void *a, void *b) -{ - byte *ba, *bb; - uint32 i; - - ba = a; - bb = b; - if(bb == nil) { - for(i=0; i<s; i++) - ba[i] = 0; - return; - } - for(i=0; i<s; i++) - ba[i] = bb[i]; -} - -static uintptr -strhash(uint32 s, String *a) -{ - USED(s); - return memhash((*a).len, (*a).str); -} - -static uint32 -strequal(uint32 s, String *a, String *b) -{ - USED(s); - return cmpstring(*a, *b) == 0; -} - -static void -strprint(uint32 s, String *a) -{ - USED(s); - sys·printstring(*a); -} - -static uintptr -interhash(uint32 s, Iface *a) -{ - USED(s); - return ifacehash(*a); -} - -static void -interprint(uint32 s, Iface *a) -{ - USED(s); - sys·printiface(*a); -} - -static uint32 -interequal(uint32 s, Iface *a, Iface *b) -{ - USED(s); - return ifaceeq(*a, *b); -} - -static uintptr -nilinterhash(uint32 s, Eface *a) -{ - USED(s); - return efacehash(*a); -} - -static void -nilinterprint(uint32 s, Eface *a) -{ - USED(s); - sys·printeface(*a); -} - -static uint32 -nilinterequal(uint32 s, Eface *a, Eface *b) -{ - USED(s); - return efaceeq(*a, *b); -} - -uintptr -nohash(uint32 s, void *a) -{ - USED(s); - USED(a); - throw("hash of unhashable type"); - return 0; -} - -uint32 -noequal(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); - throw("comparing uncomparable types"); - return 0; -} - -static void -noprint(uint32 s, void *a) -{ - USED(s); - USED(a); - throw("print of unprintable type"); -} - -static void -nocopy(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); - throw("copy of uncopyable type"); -} - -Alg -algarray[] = -{ -[AMEM] { memhash, memequal, memprint, memcopy }, -[ANOEQ] { nohash, noequal, memprint, memcopy }, -[ASTRING] { strhash, strequal, strprint, memcopy }, -[AINTER] { interhash, interequal, interprint, memcopy }, -[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy }, -[AFAKE] { nohash, noequal, noprint, nocopy }, -}; - -#pragma textflag 7 -void -FLUSH(void *v) -{ - USED(v); -} - diff --git a/src/lib/runtime/runtime.h b/src/lib/runtime/runtime.h deleted file mode 100644 index 749364f95..000000000 --- a/src/lib/runtime/runtime.h +++ /dev/null @@ -1,464 +0,0 @@ -// 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; - -#ifdef _64BIT -typedef uint64 uintptr; -#else -typedef uint32 uintptr; -#endif - -/* - * get rid of C types - * the / / / forces a syntax error immediately, - * which will show "last name: XXunsigned". - */ -#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 Alg Alg; -typedef struct Array Array; -typedef struct Func Func; -typedef struct G G; -typedef struct Gobuf Gobuf; -typedef struct Lock Lock; -typedef struct M M; -typedef struct Mem Mem; -typedef union Note Note; -typedef struct Stktop Stktop; -typedef struct String String; -typedef struct Usema Usema; -typedef struct SigTab SigTab; -typedef struct MCache MCache; -typedef struct Iface Iface; -typedef struct Itype Itype; -typedef struct Eface Eface; -typedef struct Sigt Sigt; -typedef struct Defer Defer; - -/* - * per cpu declaration - */ -extern register G* g; // R15 -extern register M* m; // R14 - -/* - * defined constants - */ -enum -{ - // G status - Gidle, - Grunnable, - Grunning, - Gsyscall, - Gwaiting, - Gmoribund, - Gdead, -}; -enum -{ - true = 1, - false = 0, -}; - -/* - * structures - */ -struct Lock -{ - uint32 key; - uint32 sema; // for OS X -}; -struct Usema -{ - uint32 u; - uint32 k; -}; -union Note -{ - struct { // Linux - Lock lock; - }; - struct { // OS X - int32 wakeup; - Usema sema; - }; -}; -struct String -{ - byte* str; - int32 len; -}; -struct Iface -{ - Itype* type; - void* data; -}; -struct Eface -{ - Sigt* type; - void* data; -}; - -struct Array -{ // must not move anything - byte* array; // actual data - uint32 nel; // number of elements - uint32 cap; // allocated number of elements -}; -struct Gobuf -{ - byte* SP; - byte* PC; -}; -struct G -{ - byte* stackguard; // must not move - byte* stackbase; // must not move - Defer* defer; // must not move - byte* stack0; // first stack segment - Gobuf sched; - G* alllink; // on allg - void* param; // passed parameter on wakeup - int16 status; - int32 goid; - int32 selgen; // valid sudog pointer - G* schedlink; - bool readyonstop; - M* m; // for debuggers -}; -struct Mem -{ - uint8* hunk; - uint32 nhunk; - uint64 nmmap; - uint64 nmal; -}; -struct M -{ - G* g0; // g0 w interrupt stack - must not move - uint64 morearg; // arg to morestack - must not move - uint64 cret; // return value from C - must not move - uint64 procid; // for debuggers - must not move - G* gsignal; // signal-handling G - must not move - G* curg; // current running goroutine - must not move - G* lastg; // last running goroutine - to emulate fifo - must not move - uint32 tls[8]; // thread-local storage (for 386 extern register) - must not move - Gobuf sched; - Gobuf morestack; - byte* moresp; - int32 siz1; - int32 siz2; - int32 id; - int32 mallocing; - int32 locks; - Note havenextg; - G* nextg; - M* schedlink; - Mem mem; - uint32 machport; // Return address for Mach IPC (OS X) - MCache *mcache; -}; -struct Stktop -{ - uint8* oldbase; - uint8* oldsp; - uint64 magic; - uint8* oldguard; -}; -struct Alg -{ - uintptr (*hash)(uint32, void*); - uint32 (*equal)(uint32, void*, void*); - void (*print)(uint32, void*); - void (*copy)(uint32, void*, void*); -}; -struct SigTab -{ - int32 flags; - int8 *name; -}; -enum -{ - SigCatch = 1<<0, - SigIgnore = 1<<1, - SigRestart = 1<<2, -}; - -// (will be) shared with go; edit ../cmd/6g/sys.go too. -// should move out of sys.go eventually. -// also eventually, the loaded symbol table should -// be closer to this form. -struct Func -{ - String name; - String type; // go type string - String src; // src file name - uint64 entry; // entry pc - int64 frame; // stack frame size - Array pcln; // pc/ln tab for this func - int64 pc0; // starting pc, ln for table - int32 ln0; - int32 args; // number of 32-bit in/out args - int32 locals; // number of 32-bit locals -}; - -/* - * defined macros - * you need super-goru privilege - * to add this list. - */ -#define nelem(x) (sizeof(x)/sizeof((x)[0])) -#define nil ((void*)0) - -/* - * known to compiler - */ -enum -{ - AMEM, - ANOEQ, - ASTRING, - AINTER, - ANILINTER, - AFAKE, - Amax -}; - -/* - * deferred subroutine calls - */ -struct Defer -{ - int32 siz; - byte* sp; - byte* fn; - Defer* link; - byte args[8]; // padded to actual size -}; - -/* - * external data - */ -extern Alg algarray[Amax]; -extern String emptystring; -G* allg; -int32 goidgen; -extern int32 gomaxprocs; -extern int32 panicking; -extern int32 maxround; - -/* - * common functions and data - */ -int32 strcmp(byte*, byte*); -int32 findnull(byte*); -void dump(byte*, int32); -int32 runetochar(byte*, int32); -int32 charntorune(int32*, uint8*, int32); - -/* - * very low level c-called - */ -int32 gogo(Gobuf*); -int32 gosave(Gobuf*); -int32 gogoret(Gobuf*, uint64); -void retfromnewstack(void); -void goargs(void); -void setspgoto(byte*, void(*)(void), void(*)(void)); -void FLUSH(void*); -void* getu(void); -void throw(int8*); -uint32 rnd(uint32, uint32); -void prints(int8*); -void printf(int8*, ...); -byte* mchr(byte*, byte, byte*); -void mcpy(byte*, byte*, uint32); -int32 mcmp(byte*, byte*, uint32); -void mmov(byte*, byte*, uint32); -void* mal(uint32); -uint32 cmpstring(String, String); -String gostring(byte*); -void initsig(void); -int32 gotraceback(void); -void traceback(uint8 *pc, uint8 *sp, G* gp); -void tracebackothers(G*); -int32 open(byte*, int32, ...); -int32 read(int32, void*, int32); -int32 write(int32, void*, int32); -void close(int32); -int32 fstat(int32, void*); -bool cas(uint32*, uint32, uint32); -void jmpdefer(byte*, void*); -void exit1(int32); -void ready(G*); -byte* getenv(int8*); -int32 atoi(byte*); -void newosproc(M *m, G *g, void *stk, void (*fn)(void)); -void sigaltstack(void*, void*); -void signalstack(byte*, int32); -G* malg(int32); -void minit(void); -Func* findfunc(uintptr); -int32 funcline(Func*, uint64); -void* stackalloc(uint32); -void stackfree(void*); -MCache* allocmcache(void); -void mallocinit(void); -bool ifaceeq(Iface, Iface); -bool efaceeq(Eface, Eface); -uintptr ifacehash(Iface); -uintptr efacehash(Eface); -uintptr nohash(uint32, void*); -uint32 noequal(uint32, void*, void*); -void* malloc(uintptr size); -void* mallocgc(uintptr size); -void free(void *v); -void exit(int32); -void breakpoint(void); -void gosched(void); -void goexit(void); - -#pragma varargck argpos printf 1 - -#pragma varargck type "d" int32 -#pragma varargck type "d" uint32 -#pragma varargck type "D" int64 -#pragma varargck type "D" uint64 -#pragma varargck type "x" int32 -#pragma varargck type "x" uint32 -#pragma varargck type "X" int64 -#pragma varargck type "X" uint64 -#pragma varargck type "p" void* -#pragma varargck type "p" uintptr -#pragma varargck type "s" int8* -#pragma varargck type "s" uint8* -#pragma varargck type "S" String - -// TODO(rsc): Remove. These are only temporary, -// for the mark and sweep collector. -void stoptheworld(void); -void starttheworld(void); - -/* - * mutual exclusion locks. in the uncontended case, - * as fast as spin locks (just a few user-level instructions), - * but on the contention path they sleep in the kernel. - * a zeroed Lock is unlocked (no need to initialize each lock). - */ -void lock(Lock*); -void unlock(Lock*); - -/* - * sleep and wakeup on one-time events. - * before any calls to notesleep or notewakeup, - * must call noteclear to initialize the Note. - * then, any number of threads can call notesleep - * and exactly one thread can call notewakeup (once). - * once notewakeup has been called, all the notesleeps - * will return. future notesleeps will return immediately. - */ -void noteclear(Note*); -void notesleep(Note*); -void notewakeup(Note*); - -/* - * Redefine methods for the benefit of gcc, which does not support - * UTF-8 characters in identifiers. - */ -#ifndef __GNUC__ -#define sys_memclr sys·memclr -#define sys_write sys·write -#define sys_catstring sys·catstring -#define sys_cmpstring sys·cmpstring -#define sys_getcallerpc sys·getcallerpc -#define sys_indexstring sys·indexstring -#define sys_intstring sys·intstring -#define sys_mal sys·mal -#define sys_mmap sys·mmap -#define sys_printarray sys·printarray -#define sys_printbool sys·printbool -#define sys_printfloat sys·printfloat -#define sys_printhex sys·printhex -#define sys_printint sys·printint -#define sys_printiface sys·printiface -#define sys_printeface sys·printeface -#define sys_printpc sys·printpc -#define sys_printpointer sys·printpointer -#define sys_printstring sys·printstring -#define sys_printuint sys·printuint -#define sys_setcallerpc sys·setcallerpc -#define sys_slicestring sys·slicestring -#endif - -/* - * low level go-called - */ -void sys_write(int32, void*, int32); -uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32); -void sys_memclr(byte*, uint32); -void sys_setcallerpc(void*, void*); -void* sys_getcallerpc(void*); - -/* - * runtime go-called - */ -void sys_printbool(bool); -void sys_printfloat(float64); -void sys_printint(int64); -void sys_printiface(Iface); -void sys_printeface(Eface); -void sys_printstring(String); -void sys_printpc(void*); -void sys_printpointer(void*); -void sys_printuint(uint64); -void sys_printhex(uint64); -void sys_printarray(Array); -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); - -/* - * wrapped for go users - */ -float64 Inf(int32 sign); -float64 NaN(void); -float32 float32frombits(uint32 i); -uint32 float32tobits(float32 f); -float64 float64frombits(uint64 i); -uint64 float64tobits(float64 f); -float64 frexp(float64 d, int32 *ep); -bool isInf(float64 f, int32 sign); -bool isNaN(float64 f); -float64 ldexp(float64 d, int32 e); -float64 modf(float64 d, float64 *ip); -void semacquire(uint32*); -void semrelease(uint32*); diff --git a/src/lib/runtime/sema.c b/src/lib/runtime/sema.c deleted file mode 100644 index 5e5b07aa6..000000000 --- a/src/lib/runtime/sema.c +++ /dev/null @@ -1,176 +0,0 @@ -// 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. - -// Semaphore implementation exposed to Go. -// Intended use is provide a sleep and wakeup -// primitive that can be used in the contended case -// of other synchronization primitives. -// Thus it targets the same goal as Linux's futex, -// but it has much simpler semantics. -// -// That is, don't think of these as semaphores. -// Think of them as a way to implement sleep and wakeup -// such that every sleep is paired with a single wakeup, -// even if, due to races, the wakeup happens before the sleep. -// -// See Mullender and Cox, ``Semaphores in Plan 9,'' -// http://swtch.com/semaphore.pdf - -#include "runtime.h" - -typedef struct Sema Sema; -struct Sema -{ - uint32 *addr; - G *g; - Sema *prev; - Sema *next; -}; - -// TODO: For now, a linked list; maybe a hash table of linked lists later. -static Sema *semfirst, *semlast; -static Lock semlock; - -static void -semqueue(uint32 *addr, Sema *s) -{ - s->addr = addr; - s->g = nil; - - lock(&semlock); - s->prev = semlast; - s->next = nil; - if(semlast) - semlast->next = s; - else - semfirst = s; - semlast = s; - unlock(&semlock); -} - -static void -semdequeue(Sema *s) -{ - lock(&semlock); - if(s->next) - s->next->prev = s->prev; - else - semlast = s->prev; - if(s->prev) - s->prev->next = s->next; - else - semfirst = s->next; - s->prev = nil; - s->next = nil; - unlock(&semlock); -} - -static void -semwakeup(uint32 *addr) -{ - Sema *s; - - lock(&semlock); - for(s=semfirst; s; s=s->next) { - if(s->addr == addr && s->g) { - ready(s->g); - s->g = nil; - break; - } - } - unlock(&semlock); -} - -// Step 1 of sleep: make ourselves available for wakeup. -// TODO(rsc): Maybe we can write a version without -// locks by using cas on s->g. Maybe not: I need to -// think more about whether it would be correct. -static void -semsleep1(Sema *s) -{ - lock(&semlock); - s->g = g; - unlock(&semlock); -} - -// Decided not to go through with it: undo step 1. -static void -semsleepundo1(Sema *s) -{ - lock(&semlock); - if(s->g != nil) { - s->g = nil; // back ourselves out - } else { - // If s->g == nil already, semwakeup - // already readied us. Since we never stopped - // running, readying us just set g->readyonstop. - // Clear it. - if(g->readyonstop == 0) - *(int32*)0x555 = 555; - g->readyonstop = 0; - } - unlock(&semlock); -} - -// Step 2: wait for the wakeup. -static void -semsleep2(Sema *s) -{ - USED(s); - g->status = Gwaiting; - gosched(); -} - -static int32 -cansemacquire(uint32 *addr) -{ - uint32 v; - - while((v = *addr) > 0) - if(cas(addr, v, v-1)) - return 1; - return 0; -} - -// For now has no return value. -// Might return an ok (not interrupted) bool in the future? -void -semacquire(uint32 *addr) -{ - Sema s; - - // Easy case. - if(cansemacquire(addr)) - return; - - // Harder case: - // queue - // try semacquire one more time, sleep if failed - // dequeue - // wake up one more guy to avoid races (TODO(rsc): maybe unnecessary?) - semqueue(addr, &s); - for(;;) { - semsleep1(&s); - if(cansemacquire(addr)) { - semsleepundo1(&s); - break; - } - semsleep2(&s); - } - semdequeue(&s); - semwakeup(addr); -} - -void -semrelease(uint32 *addr) -{ - uint32 v; - - for(;;) { - v = *addr; - if(cas(addr, v, v+1)) - break; - } - semwakeup(addr); -} diff --git a/src/lib/runtime/sema_go.cgo b/src/lib/runtime/sema_go.cgo deleted file mode 100644 index eb4082a0d..000000000 --- a/src/lib/runtime/sema_go.cgo +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -package sync -#include "runtime.h" - -func semacquire(addr *uint32) { - semacquire(addr); -} - -func semrelease(addr *uint32) { - semrelease(addr); -} - diff --git a/src/lib/runtime/string.c b/src/lib/runtime/string.c deleted file mode 100644 index 5bfe8196f..000000000 --- a/src/lib/runtime/string.c +++ /dev/null @@ -1,263 +0,0 @@ -// 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" - -String emptystring; - -int32 -findnull(byte *s) -{ - int32 l; - - if(s == nil) - return 0; - for(l=0; s[l]!=0; l++) - ; - return l; -} - -int32 maxstring; - -String -gostringsize(int32 l) -{ - String s; - - if(l == 0) - return emptystring; - s.str = mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv) - s.len = l; - if(l > maxstring) - maxstring = l; - return s; -} - -String -gostring(byte *str) -{ - int32 l; - String s; - - l = findnull(str); - s = gostringsize(l); - mcpy(s.str, str, l); - return s; -} - -void -sys·catstring(String s1, String s2, String s3) -{ - if(s1.len == 0) { - s3 = s2; - goto out; - } - if(s2.len == 0) { - s3 = s1; - goto out; - } - - s3 = gostringsize(s1.len + s2.len); - mcpy(s3.str, s1.str, s1.len); - mcpy(s3.str+s1.len, s2.str, s2.len); - -out: - FLUSH(&s3); -} - -static void -prbounds(int8* s, int32 a, int32 b, int32 c) -{ - prints(s); - prints(" "); - sys·printint(a); - prints("<"); - sys·printint(b); - prints(">"); - sys·printint(c); - prints("\n"); - throw("string bounds"); -} - -uint32 -cmpstring(String s1, String s2) -{ - 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) - 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·cmpstring(String s1, String s2, int32 v) -{ - v = cmpstring(s1, s2); - FLUSH(&v); -} - -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; - } -} - -void -sys·slicestring(String si, int32 lindex, int32 hindex, String so) -{ - int32 l; - - 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.str = si.str + lindex; - so.len = l; - -// alternate to create a new string -// so = gostringsize(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) { - sys·printpc(&s); - prints(" "); - prbounds("index", 0, i, s.len); - } - - b = s.str[i]; - FLUSH(&b); -} - -void -sys·intstring(int64 v, String s) -{ - s = gostringsize(8); - s.len = runetochar(s.str, v); - FLUSH(&s); -} - -void -sys·arraystring(Array b, String s) -{ - s = gostringsize(b.nel); - mcpy(s.str, b.array, s.len); - FLUSH(&s); -} - -void -sys·arraystringi(Array b, String s) -{ - int32 siz1, siz2, i; - int32 *a; - byte dum[8]; - - a = (int32*)b.array; - siz1 = 0; - for(i=0; i<b.nel; i++) { - siz1 += runetochar(dum, a[i]); - } - - s = gostringsize(siz1+4); - siz2 = 0; - for(i=0; i<b.nel; i++) { - // check for race - if(siz2 >= siz1) - break; - siz2 += runetochar(s.str+siz2, a[i]); - } - s.len = siz2; - - FLUSH(&s); -} - -enum -{ - Runeself = 0x80, -}; - -// func stringiter(string, int) (retk int); -void -sys·stringiter(String s, int32 k, int32 retk) -{ - int32 l; - - if(k >= s.len) { - // retk=0 is end of iteration - retk = 0; - goto out; - } - - l = s.str[k]; - if(l < Runeself) { - retk = k+1; - goto out; - } - - // multi-char rune - retk = k + charntorune(&l, s.str+k, s.len-k); - -out: - FLUSH(&retk); -} - -// func stringiter2(string, int) (retk int, retv any); -void -sys·stringiter2(String s, int32 k, int32 retk, int32 retv) -{ - if(k >= s.len) { - // retk=0 is end of iteration - retk = 0; - retv = 0; - goto out; - } - - retv = s.str[k]; - if(retv < Runeself) { - retk = k+1; - goto out; - } - - // multi-char rune - retk = k + charntorune(&retv, s.str+k, s.len-k); - -out: - FLUSH(&retk); - FLUSH(&retv); -} diff --git a/src/lib/runtime/symtab.c b/src/lib/runtime/symtab.c deleted file mode 100644 index b4802715e..000000000 --- a/src/lib/runtime/symtab.c +++ /dev/null @@ -1,377 +0,0 @@ -// 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. - -// Runtime symbol table access. Work in progress. -// The Plan 9 symbol table is not in a particularly convenient form. -// The routines here massage it into a more usable form; eventually -// we'll change 6l to do this for us, but it is easier to experiment -// here than to change 6l and all the other tools. -// -// The symbol table also needs to be better integrated with the type -// strings table in the future. This is just a quick way to get started -// and figure out exactly what we want. - -#include "runtime.h" - -// TODO(rsc): Move this *under* the text segment. -// Then define names for these addresses instead of hard-coding magic ones. -#ifdef _64BIT -#define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l -#define SYMDATA ((byte*)(0x99LL<<32) + 8) -#else -#define SYMCOUNTS ((int32*)(0x99LL<<24)) // known to 8l -#define SYMDATA ((byte*)(0x99LL<<24) + 8) -#endif - - -// Return a pointer to a byte array containing the symbol table segment. -void -sys·symdat(Array *symtab, Array *pclntab) -{ - Array *a; - int32 *v; - - v = SYMCOUNTS; - - a = mal(sizeof *a); - a->nel = v[0]; - a->cap = a->nel; - a->array = SYMDATA; - symtab = a; - FLUSH(&symtab); - - a = mal(sizeof *a); - a->nel = v[1]; - a->cap = a->nel; - a->array = SYMDATA + v[0]; - pclntab = a; - FLUSH(&pclntab); -} - -typedef struct Sym Sym; -struct Sym -{ - uintptr value; - byte symtype; - byte *name; - byte *gotype; -}; - -// Walk over symtab, calling fn(&s) for each symbol. -static void -walksymtab(void (*fn)(Sym*)) -{ - int32 *v; - byte *p, *ep, *q; - Sym s; - - v = SYMCOUNTS; - p = SYMDATA; - ep = p + v[0]; - while(p < ep) { - if(p + 7 > ep) - break; - s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]); - if(!(p[4]&0x80)) - break; - s.symtype = p[4] & ~0x80; - p += 5; - s.name = p; - if(s.symtype == 'z' || s.symtype == 'Z') { - // path reference string - skip first byte, - // then 2-byte pairs ending at two zeros. - q = p+1; - for(;;) { - if(q+2 > ep) - return; - if(q[0] == '\0' && q[1] == '\0') - break; - q += 2; - } - p = q+2; - }else{ - q = mchr(p, '\0', ep); - if(q == nil) - break; - p = q+1; - } - q = mchr(p, '\0', ep); - if(q == nil) - break; - s.gotype = p; - p = q+1; - fn(&s); - } -} - -// Symtab walker; accumulates info about functions. - -static Func *func; -static int32 nfunc; - -static byte **fname; -static int32 nfname; - -static void -dofunc(Sym *sym) -{ - Func *f; - - switch(sym->symtype) { - case 't': - case 'T': - if(strcmp(sym->name, (byte*)"etext") == 0) - break; - if(func == nil) { - nfunc++; - break; - } - f = &func[nfunc++]; - f->name = gostring(sym->name); - f->entry = sym->value; - break; - case 'm': - if(nfunc > 0 && func != nil) - func[nfunc-1].frame = sym->value; - break; - case 'p': - if(nfunc > 0 && func != nil) { - f = &func[nfunc-1]; - // args counts 32-bit words. - // sym->value is the arg's offset. - // don't know width of this arg, so assume it is 64 bits. - if(f->args < sym->value/4 + 2) - f->args = sym->value/4 + 2; - } - break; - case 'f': - if(fname == nil) { - if(sym->value >= nfname) - nfname = sym->value+1; - break; - } - fname[sym->value] = sym->name; - break; - } -} - -// put together the path name for a z entry. -// the f entries have been accumulated into fname already. -static void -makepath(byte *buf, int32 nbuf, byte *path) -{ - int32 n, len; - byte *p, *ep, *q; - - if(nbuf <= 0) - return; - - p = buf; - ep = buf + nbuf; - *p = '\0'; - for(;;) { - if(path[0] == 0 && path[1] == 0) - break; - n = (path[0]<<8) | path[1]; - path += 2; - if(n >= nfname) - break; - q = fname[n]; - len = findnull(q); - if(p+1+len >= ep) - break; - if(p > buf && p[-1] != '/') - *p++ = '/'; - mcpy(p, q, len+1); - p += len; - } -} - -// walk symtab accumulating path names for use by pc/ln table. -// don't need the full generality of the z entry history stack because -// there are no includes in go (and only sensible includes in our c). -static void -dosrcline(Sym *sym) -{ - static byte srcbuf[1000]; - static String srcstring; - static int32 lno, incstart; - static int32 nf, nhist; - Func *f; - - switch(sym->symtype) { - case 't': - case 'T': - if(strcmp(sym->name, (byte*)"etext") == 0) - break; - f = &func[nf++]; - f->src = srcstring; - f->ln0 += lno; - break; - case 'z': - if(sym->value == 1) { - // entry for main source file for a new object. - makepath(srcbuf, sizeof srcbuf, sym->name+1); - srcstring = gostring(srcbuf); - lno = 0; - nhist = 0; - } else { - // push or pop of included file. - makepath(srcbuf, sizeof srcbuf, sym->name+1); - if(srcbuf[0] != '\0') { - if(nhist++ == 0) - incstart = sym->value; - }else{ - if(--nhist == 0) - lno -= sym->value - incstart; - } - } - } -} - -enum { PcQuant = 1 }; - -// Interpret pc/ln table, saving the subpiece for each func. -static void -splitpcln(void) -{ - int32 line; - uintptr pc; - byte *p, *ep; - Func *f, *ef; - int32 *v; - - // pc/ln table bounds - v = SYMCOUNTS; - p = SYMDATA; - p += v[0]; - ep = p+v[1]; - - f = func; - ef = func + nfunc; - pc = func[0].entry; // text base - f->pcln.array = p; - f->pc0 = pc - PcQuant; - line = 0; - for(; p < ep; p++) { - if(f < ef && pc >= (f+1)->entry) { - f->pcln.nel = p - f->pcln.array; - f->pcln.cap = f->pcln.nel; - f++; - f->pcln.array = p; - f->pc0 = pc; - f->ln0 = line; - } - if(*p == 0) { - // 4 byte add to line - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 4; - } else if(*p <= 64) { - line += *p; - } else if(*p <= 128) { - line -= *p - 64; - } else { - pc += PcQuant*(*p - 129); - } - pc += PcQuant; - } - if(f < ef) { - f->pcln.nel = p - f->pcln.array; - f->pcln.cap = f->pcln.nel; - } -} - - -// Return actual file line number for targetpc in func f. -// (Source file is f->src.) -int32 -funcline(Func *f, uint64 targetpc) -{ - byte *p, *ep; - uintptr pc; - int32 line; - - p = f->pcln.array; - ep = p + f->pcln.nel; - pc = f->pc0; - line = f->ln0; - for(; p < ep; p++) { - if(pc >= targetpc) - return line; - if(*p == 0) { - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 4; - } else if(*p <= 64) { - line += *p; - } else if(*p <= 128) { - line -= *p - 64; - } else { - pc += PcQuant*(*p - 129); - } - pc += PcQuant; - } - return line; -} - -static void -buildfuncs(void) -{ - extern byte etext[]; - - if(func != nil) - return; - // count funcs, fnames - nfunc = 0; - nfname = 0; - walksymtab(dofunc); - - // initialize tables - func = mal((nfunc+1)*sizeof func[0]); - func[nfunc].entry = (uint64)etext; - fname = mal(nfname*sizeof fname[0]); - nfunc = 0; - walksymtab(dofunc); - - // split pc/ln table by func - splitpcln(); - - // record src file and line info for each func - walksymtab(dosrcline); -} - -Func* -findfunc(uintptr addr) -{ - Func *f; - int32 nf, n; - - if(func == nil) - buildfuncs(); - if(nfunc == 0) - return nil; - if(addr < func[0].entry || addr >= func[nfunc].entry) - return nil; - - // binary search to find func with entry <= addr. - f = func; - nf = nfunc; - while(nf > 0) { - n = nf/2; - if(f[n].entry <= addr && addr < f[n+1].entry) - return &f[n]; - else if(addr < f[n].entry) - nf = n; - else { - f += n+1; - nf -= n+1; - } - } - - // can't get here -- we already checked above - // that the address was in the table bounds. - // this can only happen if the table isn't sorted - // by address or if the binary search above is buggy. - prints("findfunc unreachable\n"); - return nil; -} |