summaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
committerOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
commit3e45412327a2654a77944249962b3652e6142299 (patch)
treebc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/pkg/runtime
parentc533680039762cacbc37db8dc7eed074c3e497be (diff)
downloadgolang-3e45412327a2654a77944249962b3652e6142299.tar.gz
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/386/asm.s90
-rw-r--r--src/pkg/runtime/386/closure.c17
-rw-r--r--src/pkg/runtime/386/memmove.s3
-rw-r--r--src/pkg/runtime/386/vlop.s4
-rw-r--r--src/pkg/runtime/386/vlrt.c12
-rw-r--r--src/pkg/runtime/Makefile42
-rw-r--r--src/pkg/runtime/amd64/asm.s290
-rw-r--r--src/pkg/runtime/amd64/closure.c12
-rw-r--r--src/pkg/runtime/amd64/memmove.s2
-rw-r--r--src/pkg/runtime/amd64/traceback.c44
-rw-r--r--src/pkg/runtime/arm/asm.s112
-rw-r--r--src/pkg/runtime/arm/cas5.s8
-rw-r--r--src/pkg/runtime/arm/cas6.s2
-rw-r--r--src/pkg/runtime/arm/closure.c14
-rw-r--r--src/pkg/runtime/arm/memmove.s2
-rw-r--r--src/pkg/runtime/arm/memset.s2
-rw-r--r--src/pkg/runtime/arm/softfloat.c784
-rw-r--r--src/pkg/runtime/arm/traceback.c32
-rw-r--r--src/pkg/runtime/arm/vlop.s22
-rw-r--r--src/pkg/runtime/arm/vlrt.c854
-rwxr-xr-xsrc/pkg/runtime/cgo/386.S67
-rw-r--r--src/pkg/runtime/cgo/Makefile61
-rw-r--r--src/pkg/runtime/cgo/amd64.S73
-rw-r--r--src/pkg/runtime/cgo/arm.S1
-rw-r--r--src/pkg/runtime/cgo/callbacks.c73
-rw-r--r--src/pkg/runtime/cgo/cgo.go17
-rw-r--r--src/pkg/runtime/cgo/darwin_386.c144
-rw-r--r--src/pkg/runtime/cgo/darwin_amd64.c125
-rw-r--r--src/pkg/runtime/cgo/freebsd.c13
-rw-r--r--src/pkg/runtime/cgo/freebsd_386.c59
-rw-r--r--src/pkg/runtime/cgo/freebsd_amd64.c58
-rw-r--r--src/pkg/runtime/cgo/iscgo.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h60
-rw-r--r--src/pkg/runtime/cgo/linux_386.c68
-rw-r--r--src/pkg/runtime/cgo/linux_amd64.c58
-rw-r--r--src/pkg/runtime/cgo/linux_arm.c19
-rw-r--r--src/pkg/runtime/cgo/nacl_386.c19
-rw-r--r--src/pkg/runtime/cgo/util.c51
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_386.c57
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_amd64.c47
-rw-r--r--src/pkg/runtime/cgocall.c54
-rw-r--r--src/pkg/runtime/cgocall.h8
-rw-r--r--src/pkg/runtime/chan.c294
-rw-r--r--src/pkg/runtime/chan_defs.go56
-rw-r--r--src/pkg/runtime/complex.c26
-rw-r--r--src/pkg/runtime/darwin/386/defs.h1
-rw-r--r--src/pkg/runtime/darwin/386/rt0.s2
-rw-r--r--src/pkg/runtime/darwin/386/signal.c105
-rw-r--r--src/pkg/runtime/darwin/386/sys.s85
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h1
-rw-r--r--src/pkg/runtime/darwin/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c120
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s122
-rw-r--r--src/pkg/runtime/darwin/defs.c1
-rw-r--r--src/pkg/runtime/darwin/mem.c25
-rw-r--r--src/pkg/runtime/darwin/os.h34
-rw-r--r--src/pkg/runtime/darwin/runtime_defs.go23
-rw-r--r--src/pkg/runtime/darwin/signals.h2
-rw-r--r--src/pkg/runtime/darwin/thread.c187
-rw-r--r--src/pkg/runtime/debug.go23
-rw-r--r--src/pkg/runtime/error.go4
-rw-r--r--src/pkg/runtime/export_test.go17
-rw-r--r--src/pkg/runtime/extern.go59
-rw-r--r--src/pkg/runtime/float.c52
-rw-r--r--src/pkg/runtime/freebsd/386/defs.h1
-rw-r--r--src/pkg/runtime/freebsd/386/rt0.s2
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c104
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s70
-rw-r--r--src/pkg/runtime/freebsd/amd64/defs.h1
-rw-r--r--src/pkg/runtime/freebsd/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c120
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s81
-rw-r--r--src/pkg/runtime/freebsd/defs.c1
-rw-r--r--src/pkg/runtime/freebsd/mem.c25
-rw-r--r--src/pkg/runtime/freebsd/os.h8
-rw-r--r--src/pkg/runtime/freebsd/runtime_defs.go14
-rw-r--r--src/pkg/runtime/freebsd/signals.h2
-rw-r--r--src/pkg/runtime/freebsd/thread.c88
-rw-r--r--src/pkg/runtime/goc2c.c6
-rw-r--r--src/pkg/runtime/hashmap.c241
-rw-r--r--src/pkg/runtime/hashmap.h27
-rw-r--r--src/pkg/runtime/hashmap_defs.go51
-rw-r--r--src/pkg/runtime/iface.c192
-rw-r--r--src/pkg/runtime/iface_defs.go18
-rw-r--r--src/pkg/runtime/linux/386/defs.h1
-rw-r--r--src/pkg/runtime/linux/386/rt0.s10
-rw-r--r--src/pkg/runtime/linux/386/signal.c108
-rw-r--r--src/pkg/runtime/linux/386/sys.s55
-rw-r--r--src/pkg/runtime/linux/amd64/defs.h1
-rw-r--r--src/pkg/runtime/linux/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c124
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s96
-rw-r--r--src/pkg/runtime/linux/arm/defs.h27
-rw-r--r--src/pkg/runtime/linux/arm/rt0.s2
-rw-r--r--src/pkg/runtime/linux/arm/signal.c118
-rw-r--r--src/pkg/runtime/linux/arm/sys.s47
-rw-r--r--src/pkg/runtime/linux/defs.c1
-rw-r--r--src/pkg/runtime/linux/defs2.c1
-rw-r--r--src/pkg/runtime/linux/defs_arm.c29
-rw-r--r--src/pkg/runtime/linux/mem.c27
-rw-r--r--src/pkg/runtime/linux/os.h10
-rw-r--r--src/pkg/runtime/linux/runtime_defs.go14
-rw-r--r--src/pkg/runtime/linux/signals.h2
-rw-r--r--src/pkg/runtime/linux/thread.c90
-rw-r--r--src/pkg/runtime/malloc.goc165
-rw-r--r--src/pkg/runtime/malloc.h88
-rw-r--r--src/pkg/runtime/malloc_defs.go130
-rw-r--r--src/pkg/runtime/mcache.c25
-rw-r--r--src/pkg/runtime/mcentral.c66
-rw-r--r--src/pkg/runtime/mfinal.c48
-rw-r--r--src/pkg/runtime/mfixalloc.c8
-rw-r--r--src/pkg/runtime/mgc0.c227
-rw-r--r--src/pkg/runtime/mheap.c122
-rw-r--r--src/pkg/runtime/mheapmap32.c16
-rw-r--r--src/pkg/runtime/mheapmap32.h10
-rw-r--r--src/pkg/runtime/mheapmap32_defs.go23
-rw-r--r--src/pkg/runtime/mheapmap64.c16
-rw-r--r--src/pkg/runtime/mheapmap64.h10
-rw-r--r--src/pkg/runtime/mheapmap64_defs.go31
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh46
-rw-r--r--src/pkg/runtime/mkversion.c6
-rw-r--r--src/pkg/runtime/mprof.goc30
-rw-r--r--src/pkg/runtime/msize.c82
-rw-r--r--src/pkg/runtime/nacl/386/closure.c247
-rw-r--r--src/pkg/runtime/nacl/386/defs.h17
-rw-r--r--src/pkg/runtime/nacl/386/rt0.s8
-rw-r--r--src/pkg/runtime/nacl/386/signal.c14
-rw-r--r--src/pkg/runtime/nacl/386/sys.s138
-rw-r--r--src/pkg/runtime/nacl/defs.c27
-rw-r--r--src/pkg/runtime/nacl/mem.c28
-rw-r--r--src/pkg/runtime/nacl/os.h9
-rw-r--r--src/pkg/runtime/nacl/signals.h0
-rw-r--r--src/pkg/runtime/nacl/thread.c164
-rw-r--r--src/pkg/runtime/plan9/386/defs.h1
-rw-r--r--src/pkg/runtime/plan9/386/rt0.s32
-rw-r--r--src/pkg/runtime/plan9/386/signal.c16
-rw-r--r--src/pkg/runtime/plan9/386/sys.s76
-rw-r--r--src/pkg/runtime/plan9/mem.c49
-rw-r--r--src/pkg/runtime/plan9/os.h27
-rw-r--r--src/pkg/runtime/plan9/runtime_defs.go23
-rw-r--r--src/pkg/runtime/plan9/signals.h1
-rw-r--r--src/pkg/runtime/plan9/thread.c140
-rw-r--r--src/pkg/runtime/pprof/Makefile2
-rw-r--r--src/pkg/runtime/print.c140
-rw-r--r--src/pkg/runtime/proc.c545
-rw-r--r--src/pkg/runtime/reflect.goc28
-rw-r--r--src/pkg/runtime/rune.c7
-rw-r--r--src/pkg/runtime/runtime-gdb.py398
-rw-r--r--src/pkg/runtime/runtime.c286
-rw-r--r--src/pkg/runtime/runtime.h378
-rw-r--r--src/pkg/runtime/runtime1.goc2
-rw-r--r--src/pkg/runtime/runtime_defs.go200
-rw-r--r--src/pkg/runtime/sema.goc36
-rw-r--r--src/pkg/runtime/sigqueue.goc24
-rw-r--r--src/pkg/runtime/slice.c308
-rw-r--r--src/pkg/runtime/softfloat64.go498
-rw-r--r--src/pkg/runtime/softfloat64_test.go198
-rw-r--r--src/pkg/runtime/string.goc136
-rw-r--r--src/pkg/runtime/symtab.c72
-rw-r--r--src/pkg/runtime/tiny/386/rt0.s8
-rw-r--r--src/pkg/runtime/tiny/386/signal.c8
-rw-r--r--src/pkg/runtime/tiny/386/sys.s18
-rwxr-xr-xsrc/pkg/runtime/tiny/README32
-rw-r--r--src/pkg/runtime/tiny/mem.c31
-rw-r--r--src/pkg/runtime/tiny/runtime_defs.go14
-rw-r--r--src/pkg/runtime/tiny/thread.c44
-rw-r--r--src/pkg/runtime/type.go6
-rw-r--r--src/pkg/runtime/windows/386/rt0.s2
-rw-r--r--src/pkg/runtime/windows/386/signal.c9
-rw-r--r--src/pkg/runtime/windows/386/sys.s157
-rw-r--r--src/pkg/runtime/windows/mem.c47
-rw-r--r--src/pkg/runtime/windows/os.h34
-rw-r--r--src/pkg/runtime/windows/runtime_defs.go22
-rw-r--r--src/pkg/runtime/windows/syscall.goc54
-rw-r--r--src/pkg/runtime/windows/thread.c268
175 files changed, 7980 insertions, 4752 deletions
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 614c026ea..84f5367e5 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -23,21 +23,23 @@ TEXT _rt0_386(SB),7,$0
JMP ok
// set up %gs
- CALL ldt0setup(SB)
+ CALL runtime·ldt0setup(SB)
// store through it, to make sure it works
+ CMPL runtime·isplan9(SB), $1
+ JEQ ok
get_tls(BX)
MOVL $0x123, g(BX)
- MOVL tls0(SB), AX
+ MOVL runtime·tls0(SB), AX
CMPL AX, $0x123
JEQ ok
MOVL AX, 0 // abort
ok:
// set up m and g "registers"
get_tls(BX)
- LEAL g0(SB), CX
+ LEAL runtime·g0(SB), CX
MOVL CX, g(BX)
- LEAL m0(SB), AX
+ LEAL runtime·m0(SB), AX
MOVL AX, m(BX)
// save m->g0 = g0
@@ -47,46 +49,46 @@ ok:
LEAL (-8192+104)(SP), AX // TODO: 104?
MOVL AX, g_stackguard(CX)
MOVL SP, g_stackbase(CX)
- CALL emptyfunc(SB) // fault if stack check is wrong
+ CALL runtime·emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
CLD
- CALL check(SB)
+ CALL runtime·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)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHL $mainstart(SB) // entry
+ PUSHL $runtime·mainstart(SB) // entry
PUSHL $0 // arg size
- CALL ·newproc(SB)
+ CALL runtime·newproc(SB)
POPL AX
POPL AX
// start this M
- CALL mstart(SB)
+ CALL runtime·mstart(SB)
INT $3
RET
-TEXT mainstart(SB),7,$0
+TEXT runtime·mainstart(SB),7,$0
CALL main·init(SB)
- CALL initdone(SB)
+ CALL runtime·initdone(SB)
CALL main·main(SB)
PUSHL $0
- CALL exit(SB)
+ CALL runtime·exit(SB)
POPL AX
INT $3
RET
-TEXT breakpoint(SB),7,$0
+TEXT runtime·breakpoint(SB),7,$0
INT $3
RET
@@ -96,7 +98,7 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $0
+TEXT runtime·gosave(SB), 7, $0
MOVL 4(SP), AX // gobuf
LEAL 4(SP), BX // caller's SP
MOVL BX, gobuf_sp(AX)
@@ -110,7 +112,7 @@ TEXT gosave(SB), 7, $0
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $0
+TEXT runtime·gogo(SB), 7, $0
MOVL 8(SP), AX // return 2nd arg
MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX
@@ -124,7 +126,7 @@ TEXT gogo(SB), 7, $0
// void gogocall(Gobuf*, void (*fn)(void))
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
-TEXT gogocall(SB), 7, $0
+TEXT runtime·gogocall(SB), 7, $0
MOVL 8(SP), AX // fn
MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX
@@ -142,7 +144,7 @@ TEXT gogocall(SB), 7, $0
*/
// Called during function prolog when more stack is needed.
-TEXT ·morestack(SB),7,$0
+TEXT runtime·morestack(SB),7,$0
// Cannot grow scheduler stack (m->g0).
get_tls(CX)
MOVL m(CX), BX
@@ -175,8 +177,10 @@ TEXT ·morestack(SB),7,$0
// Call newstack on m's scheduling stack.
MOVL m_g0(BX), BP
MOVL BP, g(CX)
- MOVL (m_sched+gobuf_sp)(BX), SP
- CALL newstack(SB)
+ MOVL (m_sched+gobuf_sp)(BX), AX
+ MOVL -4(AX), BX // fault if CALL would, before smashing SP
+ MOVL AX, SP
+ CALL runtime·newstack(SB)
MOVL $0, 0x1003 // crash if newstack returns
RET
@@ -218,13 +222,13 @@ TEXT reflect·call(SB), 7, $0
get_tls(CX)
MOVL BP, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP
- CALL newstack(SB)
+ CALL runtime·newstack(SB)
MOVL $0, 0x1103 // crash if newstack returns
RET
// Return point when leaving stack.
-TEXT ·lessstack(SB), 7, $0
+TEXT runtime·lessstack(SB), 7, $0
// Save return value in m->cret
get_tls(CX)
MOVL m(CX), BX
@@ -234,7 +238,7 @@ TEXT ·lessstack(SB), 7, $0
MOVL m_g0(BX), DX
MOVL DX, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP
- CALL oldstack(SB)
+ CALL runtime·oldstack(SB)
MOVL $0, 0x1004 // crash if oldstack returns
RET
@@ -246,7 +250,7 @@ TEXT ·lessstack(SB), 7, $0
// return 1;
// }else
// return 0;
-TEXT cas(SB), 7, $0
+TEXT runtime·cas(SB), 7, $0
MOVL 4(SP), BX
MOVL 8(SP), AX
MOVL 12(SP), CX
@@ -265,7 +269,7 @@ TEXT cas(SB), 7, $0
// return 1;
// }else
// return 0;
-TEXT casp(SB), 7, $0
+TEXT runtime·casp(SB), 7, $0
MOVL 4(SP), BX
MOVL 8(SP), AX
MOVL 12(SP), CX
@@ -282,14 +286,14 @@ TEXT casp(SB), 7, $0
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·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 ·memclr(SB),7,$0
+TEXT runtime·memclr(SB),7,$0
MOVL 4(SP), DI // arg 1 addr
MOVL 8(SP), CX // arg 2 count
ADDL $3, CX
@@ -300,42 +304,42 @@ TEXT ·memclr(SB),7,$0
STOSL
RET
-TEXT ·getcallerpc+0(SB),7,$0
+TEXT runtime·getcallerpc(SB),7,$0
MOVL x+0(FP),AX // addr of first arg
MOVL -4(AX),AX // get calling pc
RET
-TEXT ·setcallerpc+0(SB),7,$0
+TEXT runtime·setcallerpc(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 getcallersp(SB), 7, $0
+TEXT runtime·getcallersp(SB), 7, $0
MOVL sp+0(FP), AX
RET
-TEXT ldt0setup(SB),7,$16
+TEXT runtime·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.
// the entry number is just a hint. setldt will set up GS with what it used.
MOVL $7, 0(SP)
- LEAL tls0(SB), AX
+ LEAL runtime·tls0(SB), AX
MOVL AX, 4(SP)
MOVL $32, 8(SP) // sizeof(tls array)
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
RET
-TEXT emptyfunc(SB),0,$0
+TEXT runtime·emptyfunc(SB),0,$0
RET
-TEXT abort(SB),7,$0
+TEXT runtime·abort(SB),7,$0
INT $0x3
// runcgo(void(*fn)(void*), void *arg)
// Call fn(arg) on the scheduler stack,
// aligned appropriately for the gcc ABI.
-TEXT runcgo(SB),7,$16
+TEXT runtime·runcgo(SB),7,$16
MOVL fn+0(FP), AX
MOVL arg+4(FP), BX
MOVL SP, CX
@@ -370,7 +374,7 @@ TEXT runcgo(SB),7,$16
// runcgocallback(G *g1, void* sp, void (*fn)(void))
// Switch to g1 and sp, call fn, switch back. fn's arguments are on
// the new stack.
-TEXT runcgocallback(SB),7,$32
+TEXT runtime·runcgocallback(SB),7,$32
MOVL g1+0(FP), DX
MOVL sp+4(FP), AX
MOVL fn+8(FP), BX
@@ -399,7 +403,7 @@ TEXT runcgocallback(SB),7,$32
RET
// check that SP is in range [g->stackbase, g->stackguard)
-TEXT stackcheck(SB), 7, $0
+TEXT runtime·stackcheck(SB), 7, $0
get_tls(CX)
MOVL g(CX), AX
CMPL g_stackbase(AX), SP
@@ -410,8 +414,4 @@ TEXT stackcheck(SB), 7, $0
INT $3
RET
-GLOBL m0(SB), $1024
-GLOBL g0(SB), $1024
-GLOBL tls0(SB), $32
-GLOBL initcgo(SB), $4
-
+GLOBL runtime·tls0(SB), $32
diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/386/closure.c
index 9f639c472..b0d4cc41a 100644
--- a/src/pkg/runtime/386/closure.c
+++ b/src/pkg/runtime/386/closure.c
@@ -9,23 +9,20 @@
// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, *q, **ret;
int32 i, n;
int32 pcrel;
- if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
- throw("no closures in native client yet");
-
if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(rsc): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// compute size of new fn.
@@ -43,12 +40,12 @@ void
if(n%4)
n += 4 - n%4;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// SUBL $siz, SP
*p++ = 0x81;
@@ -104,7 +101,5 @@ void
*p++ = 0xc3;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
}
-
-
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/386/memmove.s
index 8adb687c5..38a0652b5 100644
--- a/src/pkg/runtime/386/memmove.s
+++ b/src/pkg/runtime/386/memmove.s
@@ -23,8 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
- TEXT memmove(SB), 7, $0
-
+TEXT runtime·memmove(SB), 7, $0
MOVL to+0(FP), DI
MOVL fr+4(FP), SI
MOVL n+8(FP), BX
diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/386/vlop.s
index 803276ce2..28f6da82d 100644
--- a/src/pkg/runtime/386/vlop.s
+++ b/src/pkg/runtime/386/vlop.s
@@ -27,7 +27,7 @@
* C runtime for 64-bit divide.
*/
-TEXT _mul64by32(SB), 7, $0
+TEXT _mul64by32(SB), 7, $0
MOVL r+0(FP), CX
MOVL a+4(FP), AX
MULL b+12(FP)
@@ -39,7 +39,7 @@ TEXT _mul64by32(SB), 7, $0
MOVL BX, 4(CX)
RET
-TEXT _div64by32(SB), 7, $0
+TEXT _div64by32(SB), 7, $0
MOVL r+12(FP), CX
MOVL a+0(FP), AX
MOVL a+4(FP), DX
diff --git a/src/pkg/runtime/386/vlrt.c b/src/pkg/runtime/386/vlrt.c
index 10417f596..1631dbe10 100644
--- a/src/pkg/runtime/386/vlrt.c
+++ b/src/pkg/runtime/386/vlrt.c
@@ -59,7 +59,7 @@ struct Vlong
};
};
-void abort(void);
+void runtime·abort(void);
void
_d2v(Vlong *y, double d)
@@ -270,7 +270,7 @@ _divvu(Vlong *q, Vlong n, Vlong d)
}
void
-·uint64div(Vlong n, Vlong d, Vlong q)
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
{
_divvu(&q, n, d);
}
@@ -288,7 +288,7 @@ _modvu(Vlong *r, Vlong n, Vlong d)
}
void
-·uint64mod(Vlong n, Vlong d, Vlong q)
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
{
_modvu(&q, n, d);
}
@@ -334,7 +334,7 @@ _divv(Vlong *q, Vlong n, Vlong d)
}
void
-·int64div(Vlong n, Vlong d, Vlong q)
+runtime·int64div(Vlong n, Vlong d, Vlong q)
{
_divv(&q, n, d);
}
@@ -368,7 +368,7 @@ _modv(Vlong *r, Vlong n, Vlong d)
}
void
-·int64mod(Vlong n, Vlong d, Vlong q)
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
{
_modv(&q, n, d);
}
@@ -522,7 +522,7 @@ _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
u.hi = 0;
switch(type) {
default:
- abort();
+ runtime·abort();
break;
case 1: /* schar */
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 6571d802d..e62dbe393 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=runtime
@@ -12,21 +12,27 @@ SIZE_amd64=64
SIZE_arm=32
SIZE=$(SIZE_$(GOARCH))
-# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry).
-CFLAGS_64=-D_64BIT
# TODO(kaib): fix register allocation to honor extern register so we
# can enable optimizations again.
CFLAGS_arm=-N
CFLAGS_windows=-D__WINDOWS__
-CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
+CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
GOFILES=\
debug.go\
error.go\
extern.go\
sig.go\
+ softfloat64.go\
type.go\
version.go\
+ chan_defs.go\
+ hashmap_defs.go\
+ iface_defs.go\
+ malloc_defs.go\
+ mheapmap$(SIZE)_defs.go\
+ runtime_defs.go\
+ $(GOOS)/runtime_defs.go\
GOFILES_tiny=\
tiny/io.go\
@@ -116,52 +122,46 @@ $(pkgdir)/%.h: %.h
clean: clean-local
clean-local:
- rm -f goc2c mkversion version.go */asm.h runtime.acid.*
+ rm -f goc2c mkversion version.go */asm.h runtime.acid.* $$(ls *.goc | sed 's/goc$$/c/')
$(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH)
./mkasmh.sh >$@.x
mv -f $@.x $@
goc2c: goc2c.c
- $(QUOTED_GOBIN)/quietgcc -o $@ $<
+ quietgcc -o $@ $<
mkversion: mkversion.c
- $(QUOTED_GOBIN)/quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
+ quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
version.go: mkversion
./mkversion >version.go
%.c: %.goc goc2c
- ./goc2c $< > $@.tmp
+ ./goc2c `pwd`/$< > $@.tmp
mv -f $@.tmp $@
%.$O: $(GOARCH)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOOS)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOOS)/$(GOARCH)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOARCH)/%.s $(GOARCH)/asm.h
- $(QUOTED_GOBIN)/$(AS) $<
+ $(AS) $<
%.$O: $(GOOS)/$(GOARCH)/%.s $(GOARCH)/asm.h
- $(QUOTED_GOBIN)/$(AS) $<
+ $(AS) $<
# for discovering offsets inside structs when debugging
runtime.acid.$(GOARCH): runtime.h proc.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@
+ $(CC) $(CFLAGS) -a proc.c >$@
# 386 traceback is really amd64 traceback
ifeq ($(GOARCH),386)
traceback.$O: amd64/traceback.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
-endif
-
-# NaCl closure is special.
-ifeq ($(GOOS),nacl)
-closure.$O: nacl/$(GOARCH)/closure.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
endif
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s
index 52b0a89bc..235f27206 100644
--- a/src/pkg/runtime/amd64/asm.s
+++ b/src/pkg/runtime/amd64/asm.s
@@ -4,7 +4,7 @@
#include "amd64/asm.h"
-TEXT _rt0_amd64(SB),7,$-8
+TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack
MOVQ 0(DI), AX // argc
LEAQ 8(DI), BX // argv
@@ -16,54 +16,72 @@ TEXT _rt0_amd64(SB),7,$-8
// if there is an initcgo, call it.
MOVQ initcgo(SB), AX
TESTQ AX, AX
- JZ 2(PC)
+ JZ needtls
CALL AX
-
- // set the per-goroutine and per-mach registers
- LEAQ m0(SB), m
- LEAQ g0(SB), g
- MOVQ g, m_g0(m) // m has pointer to its g0
+ JMP ok
+
+needtls:
+ LEAQ runtime·tls0(SB), DI
+ CALL runtime·settls(SB)
+
+ // store through it, to make sure it works
+ get_tls(BX)
+ MOVQ $0x123, g(BX)
+ MOVQ runtime·tls0(SB), AX
+ CMPQ AX, $0x123
+ JEQ 2(PC)
+ MOVL AX, 0 // abort
+ok:
+ // set the per-goroutine and per-mach "registers"
+ get_tls(BX)
+ LEAQ runtime·g0(SB), CX
+ MOVQ CX, g(BX)
+ LEAQ runtime·m0(SB), AX
+ MOVQ AX, m(BX)
+
+ // save m->g0 = g0
+ MOVQ CX, m_g0(AX)
// create istack out of the given (operating system) stack
LEAQ (-8192+104)(SP), AX
- MOVQ AX, g_stackguard(g)
- MOVQ SP, g_stackbase(g)
+ MOVQ AX, g_stackguard(CX)
+ MOVQ SP, g_stackbase(CX)
CLD // convention is D is always left cleared
- CALL check(SB)
+ CALL runtime·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)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHQ $mainstart(SB) // entry
+ PUSHQ $runtime·mainstart(SB) // entry
PUSHQ $0 // arg size
- CALL ·newproc(SB)
+ CALL runtime·newproc(SB)
POPQ AX
POPQ AX
// start this M
- CALL mstart(SB)
+ CALL runtime·mstart(SB)
- CALL notok(SB) // never returns
+ CALL runtime·notok(SB) // never returns
RET
-TEXT mainstart(SB),7,$0
+TEXT runtime·mainstart(SB),7,$0
CALL main·init(SB)
- CALL initdone(SB)
+ CALL runtime·initdone(SB)
CALL main·main(SB)
PUSHQ $0
- CALL exit(SB)
+ CALL runtime·exit(SB)
POPQ AX
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT breakpoint(SB),7,$0
+TEXT runtime·breakpoint(SB),7,$0
BYTE $0xcc
RET
@@ -73,23 +91,27 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $0
+TEXT runtime·gosave(SB), 7, $0
MOVQ 8(SP), AX // gobuf
LEAQ 8(SP), BX // caller's SP
MOVQ BX, gobuf_sp(AX)
MOVQ 0(SP), BX // caller's PC
MOVQ BX, gobuf_pc(AX)
- MOVQ g, gobuf_g(AX)
+ get_tls(CX)
+ MOVQ g(CX), BX
+ MOVQ BX, gobuf_g(AX)
MOVL $0, AX // return 0
RET
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $0
+TEXT runtime·gogo(SB), 7, $0
MOVQ 16(SP), AX // return 2nd arg
MOVQ 8(SP), BX // gobuf
- MOVQ gobuf_g(BX), g
- MOVQ 0(g), CX // make sure g != nil
+ MOVQ gobuf_g(BX), DX
+ MOVQ 0(DX), CX // make sure g != nil
+ get_tls(CX)
+ MOVQ DX, g(CX)
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
JMP BX
@@ -97,11 +119,13 @@ TEXT gogo(SB), 7, $0
// void gogocall(Gobuf*, void (*fn)(void))
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
-TEXT gogocall(SB), 7, $0
+TEXT runtime·gogocall(SB), 7, $0
MOVQ 16(SP), AX // fn
MOVQ 8(SP), BX // gobuf
- MOVQ gobuf_g(BX), g
- MOVQ 0(g), CX // make sure g != nil
+ MOVQ gobuf_g(BX), DX
+ get_tls(CX)
+ MOVQ DX, g(CX)
+ MOVQ 0(DX), CX // make sure g != nil
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
PUSHQ BX
@@ -113,24 +137,34 @@ TEXT gogocall(SB), 7, $0
*/
// Called during function prolog when more stack is needed.
-TEXT ·morestack(SB),7,$0
+// Caller has already done get_tls(CX); MOVQ m(CX), BX.
+TEXT runtime·morestack(SB),7,$0
+ // Cannot grow scheduler stack (m->g0).
+ MOVQ m_g0(BX), SI
+ CMPQ g(CX), SI
+ JNE 2(PC)
+ INT $3
+
// Called from f.
// Set m->morebuf to f's caller.
MOVQ 8(SP), AX // f's caller's PC
- MOVQ AX, (m_morebuf+gobuf_pc)(m)
+ MOVQ AX, (m_morebuf+gobuf_pc)(BX)
LEAQ 16(SP), AX // f's caller's SP
- MOVQ AX, (m_morebuf+gobuf_sp)(m)
- MOVQ AX, (m_morefp)(m)
- MOVQ g, (m_morebuf+gobuf_g)(m)
+ MOVQ AX, (m_morebuf+gobuf_sp)(BX)
+ MOVQ AX, (m_morefp)(BX)
+ get_tls(CX)
+ MOVQ g(CX), SI
+ MOVQ SI, (m_morebuf+gobuf_g)(BX)
// Set m->morepc to f's PC.
MOVQ 0(SP), AX
- MOVQ AX, m_morepc(m)
+ MOVQ AX, m_morepc(BX)
// Call newstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL newstack(SB)
+ MOVQ m_g0(BX), BP
+ MOVQ BP, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
MOVQ $0, 0x1003 // crash if newstack returns
RET
@@ -140,13 +174,17 @@ TEXT ·morestack(SB),7,$0
//
// func call(fn *byte, arg *byte, argsize uint32).
TEXT reflect·call(SB), 7, $0
+ get_tls(CX)
+ MOVQ m(CX), BX
+
// Save our caller's state as the PC and SP to
// restore when returning from f.
MOVQ 0(SP), AX // our caller's PC
- MOVQ AX, (m_morebuf+gobuf_pc)(m)
+ MOVQ AX, (m_morebuf+gobuf_pc)(BX)
LEAQ 8(SP), AX // our caller's SP
- MOVQ AX, (m_morebuf+gobuf_sp)(m)
- MOVQ g, (m_morebuf+gobuf_g)(m)
+ MOVQ AX, (m_morebuf+gobuf_sp)(BX)
+ MOVQ g(CX), AX
+ MOVQ AX, (m_morebuf+gobuf_g)(BX)
// Set up morestack arguments to call f on a new stack.
// We set f's frame size to 1, as a hint to newstack
@@ -155,94 +193,109 @@ TEXT reflect·call(SB), 7, $0
// the default stack, f's usual stack growth prolog will
// allocate a new segment (and recopy the arguments).
MOVQ 8(SP), AX // fn
- MOVQ 16(SP), BX // arg frame
+ MOVQ 16(SP), DX // arg frame
MOVL 24(SP), CX // arg size
- MOVQ AX, m_morepc(m) // f's PC
- MOVQ BX, m_morefp(m) // argument frame pointer
- MOVL CX, m_moreargs(m) // f's argument size
- MOVL $1, m_moreframe(m) // f's frame size
+ MOVQ AX, m_morepc(BX) // f's PC
+ MOVQ DX, m_morefp(BX) // argument frame pointer
+ MOVL CX, m_moreargs(BX) // f's argument size
+ MOVL $1, m_moreframe(BX) // f's frame size
// Call newstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL newstack(SB)
+ MOVQ m_g0(BX), BP
+ get_tls(CX)
+ MOVQ BP, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
MOVQ $0, 0x1103 // crash if newstack returns
RET
// Return point when leaving stack.
-TEXT ·lessstack(SB), 7, $0
+TEXT runtime·lessstack(SB), 7, $0
// Save return value in m->cret
- MOVQ AX, m_cret(m)
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_cret(BX)
// Call oldstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL oldstack(SB)
+ MOVQ m_g0(BX), DX
+ MOVQ DX, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·oldstack(SB)
MOVQ $0, 0x1004 // crash if oldstack returns
RET
// morestack trampolines
-TEXT ·morestack00+0(SB),7,$0
+TEXT runtime·morestack00(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
MOVQ $0, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack01+0(SB),7,$0
+TEXT runtime·morestack01(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
SHLQ $32, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack10+0(SB),7,$0
+TEXT runtime·morestack10(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
MOVLQZX AX, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack11+0(SB),7,$0
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+TEXT runtime·morestack11(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
// subcases of morestack01
// with const of 8,16,...48
-TEXT ·morestack8(SB),7,$0
+TEXT runtime·morestack8(SB),7,$0
PUSHQ $1
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack16(SB),7,$0
+TEXT runtime·morestack16(SB),7,$0
PUSHQ $2
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack24(SB),7,$0
+TEXT runtime·morestack24(SB),7,$0
PUSHQ $3
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack32(SB),7,$0
+TEXT runtime·morestack32(SB),7,$0
PUSHQ $4
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack40(SB),7,$0
+TEXT runtime·morestack40(SB),7,$0
PUSHQ $5
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack48(SB),7,$0
+TEXT runtime·morestack48(SB),7,$0
PUSHQ $6
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestackx(SB),7,$0
+TEXT morestack<>(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
POPQ AX
SHLQ $35, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
// bool cas(int32 *val, int32 old, int32 new)
@@ -252,7 +305,7 @@ TEXT ·morestackx(SB),7,$0
// return 1;
// } else
// return 0;
-TEXT cas(SB), 7, $0
+TEXT runtime·cas(SB), 7, $0
MOVQ 8(SP), BX
MOVL 16(SP), AX
MOVL 20(SP), CX
@@ -269,7 +322,7 @@ TEXT cas(SB), 7, $0
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·jmpdefer(SB), 7, $0
MOVQ 8(SP), AX // fn
MOVQ 16(SP), BX // caller sp
LEAQ -8(BX), SP // caller sp after CALL
@@ -279,80 +332,80 @@ TEXT jmpdefer(SB), 7, $0
// runcgo(void(*fn)(void*), void *arg)
// Call fn(arg) on the scheduler stack,
// aligned appropriately for the gcc ABI.
-// Save g and m across the call,
-// since the foreign code might reuse them.
-TEXT runcgo(SB),7,$32
+TEXT runtime·runcgo(SB),7,$32
MOVQ fn+0(FP), R12
MOVQ arg+8(FP), R13
MOVQ SP, CX
// Figure out if we need to switch to m->g0 stack.
- MOVQ m_g0(m), SI
- CMPQ SI, g
+ get_tls(DI)
+ MOVQ m(DI), DX
+ MOVQ m_g0(DX), SI
+ CMPQ g(DI), SI
JEQ 2(PC)
- MOVQ (m_sched+gobuf_sp)(m), SP
+ MOVQ (m_sched+gobuf_sp)(DX), SP
// Now on a scheduling stack (a pthread-created stack).
SUBQ $32, SP
ANDQ $~15, SP // alignment for gcc ABI
- MOVQ g, 24(SP) // save old g, m, SP
- MOVQ m, 16(SP)
+ MOVQ g(DI), BP
+ MOVQ BP, 16(SP)
+ MOVQ SI, g(DI)
MOVQ CX, 8(SP)
-
- // Save g and m values for a potential callback. The callback
- // will start running with on the g0 stack and as such should
- // have g set to m->g0.
- MOVQ m, DI // DI = first argument in AMD64 ABI
- // SI, second argument, set above
- MOVQ libcgo_set_scheduler(SB), BX
- CALL BX
-
MOVQ R13, DI // DI = first argument in AMD64 ABI
CALL R12
- // Restore registers, stack pointer.
- MOVQ 16(SP), m
- MOVQ 24(SP), g
+ // Restore registers, g, stack pointer.
+ get_tls(DI)
+ MOVQ 16(SP), SI
+ MOVQ SI, g(DI)
MOVQ 8(SP), SP
RET
// runcgocallback(G *g1, void* sp, void (*fn)(void))
// Switch to g1 and sp, call fn, switch back. fn's arguments are on
// the new stack.
-TEXT runcgocallback(SB),7,$48
+TEXT runtime·runcgocallback(SB),7,$48
MOVQ g1+0(FP), DX
MOVQ sp+8(FP), AX
MOVQ fp+16(FP), BX
- MOVQ DX, g
-
// We are running on m's scheduler stack. Save current SP
// into m->sched.sp so that a recursive call to runcgo doesn't
// clobber our stack, and also so that we can restore
// the SP when the call finishes. Reusing m->sched.sp
// for this purpose depends on the fact that there is only
// one possible gosave of m->sched.
- MOVQ SP, (m_sched+gobuf_sp)(m)
+ get_tls(CX)
+ MOVQ DX, g(CX)
+ MOVQ m(CX), CX
+ MOVQ SP, (m_sched+gobuf_sp)(CX)
// Set new SP, call fn
MOVQ AX, SP
CALL BX
- // Restore old SP, return
- MOVQ (m_sched+gobuf_sp)(m), SP
+ // Restore old g and SP, return
+ get_tls(CX)
+ MOVQ m(CX), DX
+ MOVQ m_g0(DX), BX
+ MOVQ BX, g(CX)
+ MOVQ (m_sched+gobuf_sp)(DX), SP
RET
// check that SP is in range [g->stackbase, g->stackguard)
-TEXT stackcheck(SB), 7, $0
- CMPQ g_stackbase(g), SP
+TEXT runtime·stackcheck(SB), 7, $0
+ get_tls(CX)
+ MOVQ g(CX), AX
+ CMPQ g_stackbase(AX), SP
JHI 2(PC)
INT $3
- CMPQ SP, g_stackguard(g)
+ CMPQ SP, g_stackguard(AX)
JHI 2(PC)
INT $3
RET
-TEXT ·memclr(SB),7,$0
+TEXT runtime·memclr(SB),7,$0
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), CX // arg 2 count
ADDL $7, CX
@@ -363,20 +416,19 @@ TEXT ·memclr(SB),7,$0
STOSQ
RET
-TEXT ·getcallerpc+0(SB),7,$0
+TEXT runtime·getcallerpc(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
-TEXT ·setcallerpc+0(SB),7,$0
+TEXT runtime·setcallerpc(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 getcallersp(SB),7,$0
+TEXT runtime·getcallersp(SB),7,$0
MOVQ sp+0(FP), AX
RET
-GLOBL initcgo(SB), $8
-GLOBL libcgo_set_scheduler(SB), $8
+GLOBL runtime·tls0(SB), $64
diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/amd64/closure.c
index de2d1695f..5033468d2 100644
--- a/src/pkg/runtime/amd64/closure.c
+++ b/src/pkg/runtime/amd64/closure.c
@@ -9,20 +9,20 @@
// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·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");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(rsc): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// compute size of new fn.
@@ -40,12 +40,12 @@ void
if(n%8)
n += 8 - n%8;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// SUBQ $siz, SP
*p++ = 0x48;
@@ -117,7 +117,7 @@ void
*p++ = 0xc3;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
}
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/amd64/memmove.s
index d755580dc..9966b0ba7 100644
--- a/src/pkg/runtime/amd64/memmove.s
+++ b/src/pkg/runtime/amd64/memmove.s
@@ -23,7 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
- TEXT memmove(SB), 7, $0
+TEXT runtime·memmove(SB), 7, $0
MOVQ to+0(FP), DI
MOVQ fr+8(FP), SI
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c
index 20e9200e5..3ea80a661 100644
--- a/src/pkg/runtime/amd64/traceback.c
+++ b/src/pkg/runtime/amd64/traceback.c
@@ -6,6 +6,8 @@
#include "malloc.h"
static uintptr isclosureentry(uintptr);
+void runtime·deferproc(void);
+void runtime·newproc(void);
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
@@ -19,7 +21,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
{
byte *p;
int32 i, n, iter, nascent;
- uintptr pc, tracepc;
+ uintptr pc, tracepc, *fp;
Stktop *stk;
Func *f;
@@ -33,7 +35,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
}
nascent = 0;
- if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)goexit) {
+ if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
// Hasn't started yet. g->sched is set up for goexit
// but goroutine will start at g->entry.
nascent = 1;
@@ -43,7 +45,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
n = 0;
stk = (Stktop*)g->stackbase;
for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever
- if(pc == (uintptr)·lessstack) {
+ if(pc == (uintptr)runtime·lessstack) {
// Hit top of stack segment. Unwind to next segment.
pc = (uintptr)stk->gobuf.pc;
sp = stk->gobuf.sp;
@@ -51,13 +53,14 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
continue;
}
- if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
// Dangerous, but worthwhile: see if this is a closure:
// ADDQ $wwxxyyzz, SP; RET
// [48] 81 c4 zz yy xx ww c3
// The 0x48 byte is only on amd64.
p = (byte*)pc;
- if(mheap.min < p && p+8 < mheap.max && // pointer in allocated memory
+ // We check p < p+8 to avoid wrapping and faulting if we lose track.
+ if(runtime·mheap.min < p && p < p+8 && p+8 < runtime·mheap.max && // pointer in allocated memory
(sizeof(uintptr) != 8 || *p++ == 0x48) && // skip 0x48 byte on amd64
p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
sp += *(uint32*)(p+2);
@@ -82,24 +85,29 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
// Print during crash.
// main+0xf /home/rsc/go/src/runtime/x.go:23
// main(0x1, 0x2, 0x3)
- printf("%S", f->name);
+ runtime·printf("%S", f->name);
if(pc > f->entry)
- printf("+%p", (uintptr)(pc - f->entry));
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry)
tracepc--;
- printf(" %S:%d\n", f->src, funcline(f, tracepc));
- printf("\t%S(", f->name);
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S(", f->name);
+ fp = (uintptr*)sp;
+ if(f->frame < sizeof(uintptr))
+ fp++;
+ else
+ fp += f->frame/sizeof(uintptr);
for(i = 0; i < f->args; i++) {
if(i != 0)
- prints(", ");
- ·printhex(((uintptr*)sp)[i]);
+ runtime·prints(", ");
+ runtime·printhex(fp[i]);
if(i >= 4) {
- prints(", ...");
+ runtime·prints(", ...");
break;
}
}
- prints(")\n");
+ runtime·prints(")\n");
n++;
}
@@ -115,24 +123,26 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
else
sp += f->frame;
pc = *((uintptr*)sp - 1);
+ if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
+ sp += 2*sizeof(uintptr);
}
return n;
}
void
-traceback(byte *pc0, byte *sp, byte*, G *g)
+runtime·traceback(byte *pc0, byte *sp, byte*, G *g)
{
gentraceback(pc0, sp, g, 0, nil, 100);
}
int32
-callers(int32 skip, uintptr *pcbuf, int32 m)
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
{
byte *pc, *sp;
// our caller's pc, sp.
sp = (byte*)&skip;
- pc = ·getcallerpc(&skip);
+ pc = runtime·getcallerpc(&skip);
return gentraceback(pc, sp, g, skip, pcbuf, m);
}
@@ -144,7 +154,7 @@ isclosureentry(uintptr pc)
int32 i, siz;
p = (byte*)pc;
- if(p < mheap.min || p+32 > mheap.max)
+ if(p < runtime·mheap.min || p+32 > runtime·mheap.max)
return 0;
// SUBQ $siz, SP
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s
index 1144ff2a1..44c47bad1 100644
--- a/src/pkg/runtime/arm/asm.s
+++ b/src/pkg/runtime/arm/asm.s
@@ -6,7 +6,7 @@
// using frame size $-4 means do not save LR on stack.
TEXT _rt0_arm(SB),7,$-4
- MOVW $setR12(SB), R12
+ MOVW $0xcafebabe, R12
// copy arguments forward on an even stack
// use R13 instead of SP to avoid linker rewriting the offsets
@@ -19,8 +19,8 @@ TEXT _rt0_arm(SB),7,$-4
// set up m and g registers
// g is R10, m is R9
- MOVW $g0(SB), g
- MOVW $m0(SB), m
+ MOVW $runtime·g0(SB), g
+ MOVW $runtime·m0(SB), m
// save m->g0 = g0
MOVW g, m_g0(m)
@@ -29,45 +29,47 @@ TEXT _rt0_arm(SB),7,$-4
MOVW $(-8192+104)(R13), R0
MOVW R0, g_stackguard(g) // (w 104b guard)
MOVW R13, g_stackbase(g)
- BL emptyfunc(SB) // fault if stack check is wrong
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
- BL check(SB)
+ BL runtime·check(SB)
// saved argc, argv
MOVW 120(R13), R0
MOVW R0, 4(R13)
MOVW 124(R13), R1
MOVW R1, 8(R13)
- BL args(SB)
- BL osinit(SB)
- BL schedinit(SB)
+ BL runtime·args(SB)
+ BL runtime·osinit(SB)
+ BL runtime·schedinit(SB)
// create a new goroutine to start program
- MOVW $mainstart(SB), R0
+ MOVW $runtime·mainstart(SB), R0
MOVW.W R0, -4(R13)
MOVW $8, R0
MOVW.W R0, -4(R13)
MOVW $0, R0
MOVW.W R0, -4(R13) // push $0 as guard
- BL ·newproc(SB)
+ BL runtime·newproc(SB)
MOVW $12(R13), R13 // pop args and LR
// start this M
- BL mstart(SB)
+ BL runtime·mstart(SB)
MOVW $1234, R0
MOVW $1000, R1
MOVW R0, (R1) // fail hard
- B _dep_dummy(SB) // Never reached
+ B runtime·_dep_dummy(SB) // Never reached
-TEXT mainstart(SB),7,$4
+TEXT runtime·mainstart(SB),7,$4
BL main·init(SB)
- BL initdone(SB)
+ BL runtime·initdone(SB)
+ EOR R0, R0
+ MOVW R0, 0(R13)
BL main·main(SB)
MOVW $0, R0
MOVW R0, 4(SP)
- BL exit(SB)
+ BL runtime·exit(SB)
MOVW $1234, R0
MOVW $1001, R1
MOVW R0, (R1) // fail hard
@@ -75,7 +77,7 @@ TEXT mainstart(SB),7,$4
// TODO(kaib): remove these once i actually understand how the linker removes symbols
// pull in dummy dependencies
-TEXT _dep_dummy(SB),7,$0
+TEXT runtime·_dep_dummy(SB),7,$0
BL _div(SB)
BL _divu(SB)
BL _mod(SB)
@@ -83,8 +85,8 @@ TEXT _dep_dummy(SB),7,$0
BL _modu(SB)
BL _sfloat(SB)
-TEXT breakpoint(SB),7,$0
- BL abort(SB)
+TEXT runtime·breakpoint(SB),7,$0
+ // no breakpoint yet; let program exit
RET
/*
@@ -93,8 +95,8 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $-4
- MOVW 0(FP), R0
+TEXT runtime·gosave(SB), 7, $-4
+ MOVW 0(FP), R0 // gobuf
MOVW SP, gobuf_sp(R0)
MOVW LR, gobuf_pc(R0)
MOVW g, gobuf_g(R0)
@@ -103,8 +105,8 @@ TEXT gosave(SB), 7, $-4
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $-4
- MOVW 0(FP), R1 // gobuf
+TEXT runtime·gogo(SB), 7, $-4
+ MOVW 0(FP), R1 // gobuf
MOVW 4(FP), R0 // return 2nd arg
MOVW gobuf_g(R1), g
MOVW 0(g), R2 // make sure g != nil
@@ -115,11 +117,12 @@ TEXT gogo(SB), 7, $-4
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
// using frame size $-4 means do not save LR on stack.
-TEXT gogocall(SB), 7, $-4
- MOVW 0(FP), R0
+TEXT runtime·gogocall(SB), 7, $-4
+ MOVW 0(FP), R0 // gobuf
MOVW 4(FP), R1 // fn
+ MOVW 8(FP), R2 // fp offset
MOVW gobuf_g(R0), g
- MOVW 0(g), R2 // make sure g != nil
+ MOVW 0(g), R3 // make sure g != nil
MOVW gobuf_sp(R0), SP // restore SP
MOVW gobuf_pc(R0), LR
MOVW R1, PC
@@ -135,12 +138,11 @@ TEXT gogocall(SB), 7, $-4
// NB. we do not save R0 because we've forced 5c to pass all arguments
// on the stack.
// using frame size $-4 means do not save LR on stack.
-TEXT ·morestack(SB),7,$-4
+TEXT runtime·morestack(SB),7,$-4
// Cannot grow scheduler stack (m->g0).
MOVW m_g0(m), R4
CMP g, R4
- BNE 2(PC)
- BL abort(SB)
+ BL.EQ runtime·abort(SB)
// Save in m.
MOVW R1, m_moreframe(m)
@@ -148,9 +150,9 @@ TEXT ·morestack(SB),7,$-4
// Called from f.
// Set m->morebuf to f's caller.
- MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC
- MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP
- MOVW SP, m_morefp(m) // f's caller's SP
+ MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC
+ MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP
+ MOVW SP, m_morefp(m) // f's caller's SP
MOVW g, (m_morebuf+gobuf_g)(m)
// Set m->morepc to f's PC.
@@ -159,7 +161,7 @@ TEXT ·morestack(SB),7,$-4
// Call newstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B newstack(SB)
+ B runtime·newstack(SB)
// Called from reflection library. Mimics morestack,
// reuses stack growth code to create a frame
@@ -179,45 +181,48 @@ TEXT reflect·call(SB), 7, $-4
// If it turns out that f needs a larger frame than
// the default stack, f's usual stack growth prolog will
// allocate a new segment (and recopy the arguments).
- MOVW 4(SP), R0 // fn
- MOVW 8(SP), R1 // arg frame
- MOVW 12(SP), R2 // arg size
+ MOVW 4(SP), R0 // fn
+ MOVW 8(SP), R1 // arg frame
+ MOVW 12(SP), R2 // arg size
- MOVW R0, m_morepc(m) // f's PC
- MOVW R1, m_morefp(m) // argument frame pointer
- MOVW R2, m_moreargs(m) // f's argument size
+ SUB $4,R1 // add the saved LR to the frame
+ ADD $4,R2
+
+ MOVW R0, m_morepc(m) // f's PC
+ MOVW R1, m_morefp(m) // argument frame pointer
+ MOVW R2, m_moreargs(m) // f's argument size
MOVW $1, R3
- MOVW R3, m_moreframe(m) // f's frame size
+ MOVW R3, m_moreframe(m) // f's frame size
// Call newstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B newstack(SB)
+ B runtime·newstack(SB)
// Return point when leaving stack.
// using frame size $-4 means do not save LR on stack.
-TEXT ·lessstack(SB), 7, $-4
+TEXT runtime·lessstack(SB), 7, $-4
// Save return value in m->cret
MOVW R0, m_cret(m)
// Call oldstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B oldstack(SB)
+ B runtime·oldstack(SB)
// void jmpdefer(fn, sp);
// called from deferreturn.
// 1. grab stored LR for caller
// 2. sub 4 bytes to get back to BL deferreturn
// 3. B to fn
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·jmpdefer(SB), 7, $0
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
MOVW 4(SP), R0 // fn
MOVW 8(SP), SP
B (R0)
-TEXT ·memclr(SB),7,$20
+TEXT runtime·memclr(SB),7,$20
MOVW 0(FP), R0
MOVW $0, R1 // c = 0
MOVW R1, -16(SP)
@@ -225,21 +230,21 @@ TEXT ·memclr(SB),7,$20
MOVW R1, -12(SP)
MOVW m, -8(SP) // Save m and g
MOVW g, -4(SP)
- BL memset(SB)
+ BL runtime·memset(SB)
MOVW -8(SP), m // Restore m and g, memset clobbers them
MOVW -4(SP), g
RET
-TEXT ·getcallerpc+0(SB),7,$-4
+TEXT runtime·getcallerpc(SB),7,$-4
MOVW 0(SP), R0
RET
-TEXT ·setcallerpc+0(SB),7,$-4
+TEXT runtime·setcallerpc(SB),7,$-4
MOVW x+4(FP), R0
MOVW R0, 0(SP)
RET
-TEXT getcallersp(SB),7,$-4
+TEXT runtime·getcallersp(SB),7,$-4
MOVW 0(FP), R0
MOVW $-4(R0), R0
RET
@@ -248,8 +253,8 @@ TEXT getcallersp(SB),7,$-4
// Just call fn(arg), but first align the stack
// appropriately for the gcc ABI.
// TODO(kaib): figure out the arm-gcc ABI
-TEXT runcgo(SB),7,$16
- BL abort(SB)
+TEXT runtime·runcgo(SB),7,$16
+ BL runtime·abort(SB)
// MOVL fn+0(FP), AX
// MOVL arg+4(FP), BX
// MOVL SP, CX
@@ -260,10 +265,13 @@ TEXT runcgo(SB),7,$16
// MOVL 4(SP), SP
// RET
-TEXT emptyfunc(SB),0,$0
+TEXT runtime·emptyfunc(SB),0,$0
RET
-TEXT abort(SB),7,$-4
+TEXT runtime·abort(SB),7,$-4
MOVW $0, R0
MOVW (R0), R1
+TEXT runtime·runcgocallback(SB),7,$0
+ MOVW $0, R0
+ MOVW (R0), R1
diff --git a/src/pkg/runtime/arm/cas5.s b/src/pkg/runtime/arm/cas5.s
index 8a4c8be12..20bd3c3e2 100644
--- a/src/pkg/runtime/arm/cas5.s
+++ b/src/pkg/runtime/arm/cas5.s
@@ -14,12 +14,12 @@
// }else
// return 0;
-TEXT cas(SB),7,$0
+TEXT runtime·cas(SB),7,$0
MOVW 0(FP), R0 // *val
MOVW 4(FP), R1 // old
MOVW 8(FP), R2 // new
MOVW $1, R3
- MOVW $cas_mutex(SB), R4
+ MOVW $runtime·cas_mutex(SB), R4
l:
SWPW (R4), R3 // acquire mutex
CMP $0, R3
@@ -39,5 +39,5 @@ fail0:
MOVW $0, R0
RET
-DATA cas_mutex(SB)/4, $0
-GLOBL cas_mutex(SB), $4
+DATA runtime·cas_mutex(SB)/4, $0
+GLOBL runtime·cas_mutex(SB), $4
diff --git a/src/pkg/runtime/arm/cas6.s b/src/pkg/runtime/arm/cas6.s
index 63df1396d..43788b28a 100644
--- a/src/pkg/runtime/arm/cas6.s
+++ b/src/pkg/runtime/arm/cas6.s
@@ -10,7 +10,7 @@
// }else
// return 0;
-TEXT cas(SB),7,$0
+TEXT runtime·cas(SB),7,$0
MOVW 0(FP), R1 // *val
MOVW 4(FP), R2 // old
MOVW 8(FP), R3 // new
diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c
index 11a7719c9..3aca3a42d 100644
--- a/src/pkg/runtime/arm/closure.c
+++ b/src/pkg/runtime/arm/closure.c
@@ -47,20 +47,20 @@ extern void cacheflush(byte* start, byte* end);
#pragma textflag 7
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, *q, **ret;
uint32 *pc;
int32 n;
if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(kaib): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// size of new fn.
@@ -73,7 +73,7 @@ void
// store args aligned after code, so gc can find them.
n += siz;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
@@ -83,7 +83,7 @@ void
*pc++ = 0xe52de000 | (siz + 4);
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// MOVW $vars(PC), R0
*pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8);
@@ -122,8 +122,8 @@ void
p = (byte*)pc;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
- cacheflush(*ret, q+siz);
+ runtime·cacheflush(*ret, q+siz);
}
diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/arm/memmove.s
index 9f7dc1dd2..5c0e57404 100644
--- a/src/pkg/runtime/arm/memmove.s
+++ b/src/pkg/runtime/arm/memmove.s
@@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */
TMP1 = 4
// TODO(kaib): This can be done with the existing registers of LR is re-used. Same for memset.
-TEXT memmove(SB), 7, $8
+TEXT runtime·memmove(SB), 7, $8
// save g and m
MOVW R9, 4(R13)
MOVW R10, 8(R13)
diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/arm/memset.s
index cce94534c..974b8da7a 100644
--- a/src/pkg/runtime/arm/memset.s
+++ b/src/pkg/runtime/arm/memset.s
@@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */
// TODO(kaib): memset clobbers R9 and R10 (m and g). This makes the
// registers unpredictable if (when) memset SIGSEGV's. Fix it by
// moving the R4-R11 register bank.
-TEXT memset(SB), $0
+TEXT runtime·memset(SB), $0
MOVW R0, R(TO)
MOVW data+4(FP), R(4)
MOVW n+8(FP), R(N)
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c
index 46ab07c82..f60fab14f 100644
--- a/src/pkg/runtime/arm/softfloat.c
+++ b/src/pkg/runtime/arm/softfloat.c
@@ -2,428 +2,498 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Software floating point interpretaton of ARM 7500 FP instructions.
+// The interpretation is not bit compatible with the 7500.
+// It uses true little-endian doubles, while the 7500 used mixed-endian.
+
#include "runtime.h"
-void abort(void);
+#define CPSR 14
+#define FLAGS_N (1 << 31)
+#define FLAGS_Z (1 << 30)
+#define FLAGS_C (1 << 29)
+#define FLAGS_V (1 << 28)
+
+void runtime·abort(void);
+
+static uint32 trace = 0;
static void
fabort(void)
{
if (1) {
- printf("Unsupported floating point instruction\n");
- abort();
+ runtime·printf("Unsupported floating point instruction\n");
+ runtime·abort();
}
}
-static uint32 doabort = 0;
-static uint32 trace = 0;
-
-#define DOUBLE_EXPBIAS 1023
-#define SINGLE_EXPBIAS 127
-
-static const int8* opnames[] = {
- // binary
- "adf",
- "muf",
- "suf",
- "rsf",
- "dvf",
- "rdf",
- "pow",
- "rpw",
- "rmf",
- "fml",
- "fdv",
- "frd",
- "pol",
- "UNDEFINED",
- "UNDEFINED",
- "UNDEFINED",
-
- // unary
- "mvf",
- "mnf",
- "abs",
- "rnd",
- "sqt",
- "log",
- "lgn",
- "exp",
- "sin",
- "cos",
- "tan",
- "asn",
- "acs",
- "atn",
- "urd",
- "nrm"
-};
-
-static const int8* fpconst[] = {
- "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0",
-};
-
-static const uint64 fpdconst[] = {
- 0x0000000000000000ll,
- 0x3ff0000000000000ll,
- 0x4000000000000000ll,
- 0x4008000000000000ll,
- 0x4010000000000000ll,
- 0x4014000000000000ll,
- 0x3fe0000000000000ll,
- 0x4024000000000000ll
-};
-
-static const int8* fpprec[] = {
- "s", "d", "e", "?"
-};
-
-static uint32
-precision(uint32 i)
-{
- switch (i&0x00080080) {
- case 0:
- return 0;
- case 0x80:
- return 1;
- default:
- fabort();
- }
- return 0;
-}
-
-static uint64
-frhs(uint32 rhs)
-{
- if (rhs & 0x8) {
- return fpdconst[rhs&0x7];
- } else {
- return m->freg[rhs&0x7];
- }
-}
-
-static int32
-fexp(uint64 f)
+static void
+putf(uint32 reg, uint32 val)
{
- return (int32)((uint32)(f >> 52) & 0x7ff) - DOUBLE_EXPBIAS;
+ m->freglo[reg] = val;
}
-static uint32
-fsign(uint64 f)
+static void
+putd(uint32 reg, uint64 val)
{
- return (uint32)(f >> 63) & 0x1;
+ m->freglo[reg] = (uint32)val;
+ m->freghi[reg] = (uint32)(val>>32);
}
static uint64
-fmantissa(uint64 f)
+getd(uint32 reg)
{
- return f &0x000fffffffffffffll;
+ return (uint64)m->freglo[reg] | ((uint64)m->freghi[reg]<<32);
}
static void
-fprint()
+fprint(void)
{
uint32 i;
- for (i = 0; i < 8; i++) {
- printf("\tf%d:\t%X\n", i, m->freg[i]);
+ for (i = 0; i < 16; i++) {
+ runtime·printf("\tf%d:\t%X %X\n", i, m->freghi[i], m->freglo[i]);
}
}
static uint32
-d2s(uint64 d)
+d2f(uint64 d)
{
- return (d>>32 & 0x80000000) | //sign
- ((uint32)(fexp(d) + SINGLE_EXPBIAS) & 0xff) << 23 | // exponent
- (d >> 29 & 0x7fffff); // mantissa
+ uint32 x;
+
+ runtime·f64to32c(d, &x);
+ return x;
}
static uint64
-s2d(uint32 s)
+f2d(uint32 f)
{
- return (uint64)(s & 0x80000000) << 63 | // sign
- (uint64)((s >> 23 &0xff) + (DOUBLE_EXPBIAS - SINGLE_EXPBIAS)) << 52 | // exponent
- (uint64)(s & 0x7fffff) << 29; // mantissa
+ uint64 x;
+
+ runtime·f32to64c(f, &x);
+ return x;
}
-// cdp, data processing instructions
-static void
-dataprocess(uint32* pc)
+static uint32
+fstatus(bool nan, int32 cmp)
{
- uint32 i, opcode, unary, dest, lhs, rhs, prec;
- uint32 high;
- uint64 fraw0, fraw1, exp, sign;
- uint64 fd, f0, f1;
-
- i = *pc;
-
- // data processing
- opcode = i>>20 & 15;
- unary = i>>15 & 1;
-
- dest = i>>12 & 7;
- lhs = i>>16 & 7;
- rhs = i & 15;
-
- prec = precision(i);
- if (unary) {
- switch (opcode) {
- case 0: // mvf
- m->freg[dest] = frhs(rhs);
- goto ret;
- default:
- goto undef;
- }
- } else {
- switch (opcode) {
- case 1: // muf
- fraw0 = m->freg[lhs];
- fraw1 = frhs(rhs);
- f0 = fraw0>>21 & 0xffffffff | 0x80000000;
- f1 = fraw1>>21 & 0xffffffff | 0x80000000;
- fd = f0*f1;
- high = fd >> 63;
- if (high)
- fd = fd >> 11 & 0x000fffffffffffffll;
- else
- fd = fd >> 10 & 0x000fffffffffffffll;
- exp = (uint64)(fexp(fraw0) + fexp(fraw1) + !!high + DOUBLE_EXPBIAS) & 0x7ff;
- sign = fraw0 >> 63 ^ fraw1 >> 63;
- fd = sign << 63 | exp <<52 | fd;
- m->freg[dest] = fd;
- goto ret;
- default:
- goto undef;
- }
- }
-
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- printf(" %p %x\t%s%s\tf%d, ", pc, *pc, opnames[opcode | unary<<4],
- fpprec[prec], dest);
- if (!unary)
- printf("f%d, ", lhs);
- if (rhs & 0x8)
- printf("#%s\n", fpconst[rhs&0x7]);
- else
- printf("f%d\n", rhs&0x7);
- }
- if (doabort)
- fabort();
+ if(nan)
+ return FLAGS_C | FLAGS_V;
+ if(cmp == 0)
+ return FLAGS_Z | FLAGS_C;
+ if(cmp < 0)
+ return FLAGS_N;
+ return FLAGS_C;
}
-#define CPSR 14
-#define FLAGS_N (1 << 31)
-#define FLAGS_Z (1 << 30)
-#define FLAGS_C (1 << 29)
-
-// cmf, compare floating point
-static void
-compare(uint32 *pc, uint32 *regs) {
- uint32 i, flags, lhs, rhs, sign0, sign1;
- uint32 f0, f1, mant0, mant1;
- int32 exp0, exp1;
+// returns number of words that the fp instruction
+// is occupying, 0 if next instruction isn't float.
+static uint32
+stepflt(uint32 *pc, uint32 *regs)
+{
+ uint32 i, regd, regm, regn;
+ uint32 *addr;
+ uint64 uval;
+ int64 sval;
+ bool nan, ok;
+ int32 cmp;
i = *pc;
- flags = 0;
- lhs = i>>16 & 0x7;
- rhs = i & 0xf;
-
- f0 = m->freg[lhs];
- f1 = frhs(rhs);
- if (f0 == f1) {
- flags = FLAGS_Z | FLAGS_C;
- goto ret;
- }
- sign0 = fsign(f0);
- sign1 = fsign(f1);
- if (sign0 == 1 && sign1 == 0) {
- flags = FLAGS_N;
- goto ret;
+ if(trace)
+ runtime·printf("stepflt %p %x\n", pc, i);
+
+ // special cases
+ if((i&0xfffff000) == 0xe59fb000) {
+ // load r11 from pc-relative address.
+ // might be part of a floating point move
+ // (or might not, but no harm in simulating
+ // one instruction too many).
+ addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
+ regs[11] = addr[0];
+
+ if(trace)
+ runtime·printf("*** cpu R[%d] = *(%p) %x\n",
+ 11, addr, regs[11]);
+ return 1;
}
- if (sign0 == 0 && sign1 == 1) {
- flags = FLAGS_C;
- goto ret;
+ if(i == 0xe08bb00d) {
+ // add sp to 11.
+ // might be part of a large stack offset address
+ // (or might not, but again no harm done).
+ regs[11] += regs[13];
+
+ if(trace)
+ runtime·printf("*** cpu R[%d] += R[%d] %x\n",
+ 11, 13, regs[11]);
+ return 1;
}
+ if(i == 0xeef1fa10) {
+ regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
- if (sign0 == 0) {
- exp0 = fexp(f0);
- exp1 = fexp(f1);
- mant0 = fmantissa(f0);
- mant1 = fmantissa(f1);
- } else {
- exp0 = fexp(f1);
- exp1 = fexp(f0);
- mant0 = fmantissa(f1);
- mant1 = fmantissa(f0);
+ if(trace)
+ runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
+ return 1;
}
+ goto stage1;
- if (exp0 > exp1) {
- flags = FLAGS_C;
- } else if (exp0 < exp1) {
- flags = FLAGS_N;
- } else {
- if (mant0 > mant1)
- flags = FLAGS_C;
- else
- flags = FLAGS_N;
- }
+stage1: // load/store regn is cpureg, regm is 8bit offset
+ regd = i>>12 & 0xf;
+ regn = i>>16 & 0xf;
+ regm = (i & 0xff) << 2; // PLUS or MINUS ??
-ret:
- if (trace) {
- printf(" %p %x\tcmf\tf%d, ", pc, *pc, lhs);
- if (rhs & 0x8)
- printf("#%s\n", fpconst[rhs&0x7]);
- else
- printf("f%d\n", rhs&0x7);
+ switch(i & 0xfff00f00) {
+ default:
+ goto stage2;
+
+ case 0xed900a00: // single load
+ addr = (uint32*)(regs[regn] + regm);
+ m->freglo[regd] = addr[0];
+
+ if(trace)
+ runtime·printf("*** load F[%d] = %x\n",
+ regd, m->freglo[regd]);
+ break;
+
+ case 0xed900b00: // double load
+ addr = (uint32*)(regs[regn] + regm);
+ m->freglo[regd] = addr[0];
+ m->freghi[regd] = addr[1];
+
+ if(trace)
+ runtime·printf("*** load D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xed800a00: // single store
+ addr = (uint32*)(regs[regn] + regm);
+ addr[0] = m->freglo[regd];
+
+ if(trace)
+ runtime·printf("*** *(%p) = %x\n",
+ addr, addr[0]);
+ break;
+
+ case 0xed800b00: // double store
+ addr = (uint32*)(regs[regn] + regm);
+ addr[0] = m->freglo[regd];
+ addr[1] = m->freghi[regd];
+
+ if(trace)
+ runtime·printf("*** *(%p) = %x-%x\n",
+ addr, addr[1], addr[0]);
+ break;
}
- regs[CPSR] = regs[CPSR] & 0x0fffffff | flags;
-}
+ return 1;
-// ldf/stf, load/store floating
-static void
-loadstore(uint32 *pc, uint32 *regs)
-{
- uint32 i, isload, coproc, ud, wb, tlen, p, reg, freg, offset;
- uint32 addr;
-
- i = *pc;
- coproc = i>>8&0xf;
- isload = i>>20&1;
- p = i>>24&1;
- ud = i>>23&1;
- tlen = i>>(22 - 1)&1 | i>>15&1;
- wb = i>>21&1;
- reg = i>>16 &0xf;
- freg = i>>12 &0x7;
- offset = (i&0xff) << 2;
-
- if (coproc != 1 || p != 1 || wb != 0 || tlen > 1)
- goto undef;
- if (reg > 13)
- goto undef;
-
- if (ud)
- addr = regs[reg] + offset;
- else
- addr = regs[reg] - offset;
-
- if (isload)
- if (tlen)
- m->freg[freg] = *((uint64*)addr);
- else
- m->freg[freg] = s2d(*((uint32*)addr));
- else
- if (tlen)
- *((uint64*)addr) = m->freg[freg];
- else
- *((uint32*)addr) = d2s(m->freg[freg]);
- goto ret;
-
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- if (isload)
- printf(" %p %x\tldf", pc, *pc);
- else
- printf(" %p %x\tstf", pc, *pc);
- printf("%s\t\tf%d, %s%d(r%d)", fpprec[tlen], freg, ud ? "" : "-", offset, reg);
- printf("\t\t// %p", regs[reg] + (ud ? offset : -offset));
- if (coproc != 1 || p != 1 || wb != 0)
- printf(" coproc: %d pre: %d wb %d", coproc, p, wb);
- printf("\n");
- fprint();
+stage2: // regd, regm, regn are 4bit variables
+ regm = i>>0 & 0xf;
+ switch(i & 0xfff00ff0) {
+ default:
+ goto stage3;
+
+ case 0xf3000110: // veor
+ m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
+ m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
+
+ if(trace)
+ runtime·printf("*** veor D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb00b00: // D[regd] = const(regn,regm)
+ regn = (regn<<4) | regm;
+ regm = 0x40000000UL;
+ if(regn & 0x80)
+ regm |= 0x80000000UL;
+ if(regn & 0x40)
+ regm ^= 0x7fc00000UL;
+ regm |= (regn & 0x3f) << 16;
+ m->freglo[regd] = 0;
+ m->freghi[regd] = regm;
+
+ if(trace)
+ runtime·printf("*** immed D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb00a00: // F[regd] = const(regn,regm)
+ regn = (regn<<4) | regm;
+ regm = 0x40000000UL;
+ if(regn & 0x80)
+ regm |= 0x80000000UL;
+ if(regn & 0x40)
+ regm ^= 0x7e000000UL;
+ regm |= (regn & 0x3f) << 19;
+ m->freglo[regd] = regm;
+
+ if(trace)
+ runtime·printf("*** immed D[%d] = %x\n",
+ regd, m->freglo[regd]);
+ break;
+
+ case 0xee300b00: // D[regd] = D[regn]+D[regm]
+ runtime·fadd64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee300a00: // F[regd] = F[regn]+F[regm]
+ runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee300b40: // D[regd] = D[regn]-D[regm]
+ runtime·fsub64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee300a40: // F[regd] = F[regn]-F[regm]
+ runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee200b00: // D[regd] = D[regn]*D[regm]
+ runtime·fmul64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee200a00: // F[regd] = F[regn]*F[regm]
+ runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee800b00: // D[regd] = D[regn]/D[regm]
+ runtime·fdiv64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee800a00: // F[regd] = F[regn]/F[regm]
+ runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored)
+ m->freglo[regn] = regs[regd];
+
+ if(trace)
+ runtime·printf("*** cpy S[%d] = R[%d] %x\n",
+ regn, regd, m->freglo[regn]);
+ break;
+
+ case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored)
+ regs[regd] = m->freglo[regn];
+
+ if(trace)
+ runtime·printf("*** cpy R[%d] = S[%d] %x\n",
+ regd, regn, regs[regd]);
+ break;
}
- if (doabort)
- fabort();
-}
-
-static void
-loadconst(uint32 *pc, uint32 *regs)
-{
- uint32 offset;
- uint32 *addr;
-
- if (*pc & 0xfffff000 != 0xe59fb838 ||
- *(pc+1) != 0xe08bb00c ||
- *(pc+2) & 0xffff8fff != 0xed9b0100)
- goto undef;
-
- offset = *pc & 0xfff;
- addr = (uint32*)((uint8*)pc + offset + 8);
-//printf("DEBUG: addr %p *addr %x final %p\n", addr, *addr, *addr + regs[12]);
- regs[11] = *addr + regs[12];
- loadstore(pc + 2, regs);
- goto ret;
+ return 1;
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- printf(" %p coproc const %x %x %x\n", pc, *pc, *(pc+1), *(pc+2));
- }
- if (doabort)
- fabort();
-}
+stage3: // regd, regm are 4bit variables
+ switch(i & 0xffff0ff0) {
+ default:
+ goto done;
+
+ case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
+ m->freglo[regd] = m->freglo[regm];
+
+ if(trace)
+ runtime·printf("*** F[%d] = F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
+ m->freglo[regd] = m->freglo[regm];
+ m->freghi[regd] = m->freghi[regm];
+
+ if(trace)
+ runtime·printf("*** D[%d] = D[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
+ runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
+ m->fflag = fstatus(nan, cmp);
+
+ if(trace)
+ runtime·printf("*** cmp D[%d]::D[%d] %x\n",
+ regd, regm, m->fflag);
+ break;
+
+ case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF)
+ runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
+ m->fflag = fstatus(nan, cmp);
+
+ if(trace)
+ runtime·printf("*** cmp F[%d]::F[%d] %x\n",
+ regd, regm, m->fflag);
+ break;
+
+ case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
+ putd(regd, f2d(m->freglo[regm]));
+
+ if(trace)
+ runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF)
+ m->freglo[regd] = d2f(getd(regm));
+
+ if(trace)
+ runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW)
+ runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+ if(!ok || (int32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix S[%d]=F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U)
+ runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+ if(!ok || (uint32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW)
+ runtime·f64tointc(getd(regm), &sval, &ok);
+ if(!ok || (int32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix S[%d]=D[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U)
+ runtime·f64tointc(getd(regm), &sval, &ok);
+ if(!ok || (uint32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
+ cmp = m->freglo[regm];
+ if(cmp < 0) {
+ runtime·fintto64c(-cmp, &uval);
+ putf(regd, d2f(uval));
+ m->freglo[regd] ^= 0x80000000;
+ } else {
+ runtime·fintto64c(cmp, &uval);
+ putf(regd, d2f(uval));
+ }
+ if(trace)
+ runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U)
+ runtime·fintto64c(m->freglo[regm], &uval);
+ putf(regd, d2f(uval));
+
+ if(trace)
+ runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
+ cmp = m->freglo[regm];
+ if(cmp < 0) {
+ runtime·fintto64c(-cmp, &uval);
+ putd(regd, uval);
+ m->freghi[regd] ^= 0x80000000;
+ } else {
+ runtime·fintto64c(cmp, &uval);
+ putd(regd, uval);
+ }
-// returns number of words that the fp instruction is occupying, 0 if next instruction isn't float.
-// TODO(kaib): insert sanity checks for coproc 1
-static uint32
-stepflt(uint32 *pc, uint32 *regs)
-{
- uint32 i, c;
+ if(trace)
+ runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
- i = *pc;
- c = i >> 25 & 7;
+ case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
+ runtime·fintto64c(m->freglo[regm], &uval);
+ putd(regd, uval);
- switch(c) {
- case 6: // 110
- loadstore(pc, regs);
- return 1;
- case 7: // 111
- if (i>>24 & 1) return 0; // ignore swi
-
- if (i>>4 & 1) { //data transfer
- if ((i&0x00f0ff00) != 0x0090f100) {
- printf(" %p %x\n", pc, i);
- fabort();
- }
- compare(pc, regs);
- } else {
- dataprocess(pc);
- }
- return 1;
+ if(trace)
+ runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
}
+ return 1;
- // lookahead for virtual instructions that span multiple arm instructions
- c = ((*pc & 0x0f000000) >> 16) |
- ((*(pc + 1) & 0x0f000000) >> 20) |
- ((*(pc + 2) & 0x0f000000) >> 24);
- if(c == 0x50d) { // 0101 0000 1101
- loadconst(pc, regs);
- return 3;
+done:
+ if((i&0xff000000) == 0xee000000 ||
+ (i&0xff000000) == 0xed000000) {
+ runtime·printf("stepflt %p %x\n", pc, i);
+ fabort();
}
-
return 0;
}
#pragma textflag 7
uint32*
-_sfloat2(uint32 *lr, uint32 r0)
+runtime·_sfloat2(uint32 *lr, uint32 r0)
{
uint32 skip;
- uint32 cpsr;
- while(skip = stepflt(lr, &r0)) {
+ skip = stepflt(lr, &r0);
+ if(skip == 0)
+ fabort(); // not ok to fail first instruction
+
+ lr += skip;
+ while(skip = stepflt(lr, &r0))
lr += skip;
- }
return lr;
}
-
diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c
index 0131f21d6..8289fdb28 100644
--- a/src/pkg/runtime/arm/traceback.c
+++ b/src/pkg/runtime/arm/traceback.c
@@ -16,9 +16,9 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
lr = (uintptr)lr0;
// If the PC is goexit, it hasn't started yet.
- if(pc == (uintptr)goexit) {
+ if(pc == (uintptr)runtime·goexit) {
pc = (uintptr)g->entry;
- lr = (uintptr)goexit;
+ lr = (uintptr)runtime·goexit;
}
// If the PC is zero, it's likely a nil function call.
@@ -31,7 +31,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
n = 0;
stk = (Stktop*)g->stackbase;
for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever
- if(pc == (uintptr)·lessstack) {
+ if(pc == (uintptr)runtime·lessstack) {
// Hit top of stack segment. Unwind to next segment.
pc = (uintptr)stk->gobuf.pc;
sp = stk->gobuf.sp;
@@ -39,7 +39,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
stk = (Stktop*)stk->stackbase;
continue;
}
- if(pc <= 0x1000 || (f = findfunc(pc-4)) == nil) {
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc-4)) == nil) {
// TODO: Check for closure.
break;
}
@@ -53,24 +53,24 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
// Print during crash.
// main+0xf /home/rsc/go/src/runtime/x.go:23
// main(0x1, 0x2, 0x3)
- printf("%S", f->name);
+ runtime·printf("%S", f->name);
if(pc > f->entry)
- printf("+%p", (uintptr)(pc - f->entry));
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry)
tracepc -= sizeof(uintptr);
- printf(" %S:%d\n", f->src, funcline(f, tracepc));
- printf("\t%S(", f->name);
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S(", f->name);
for(i = 0; i < f->args; i++) {
if(i != 0)
- prints(", ");
- ·printhex(((uintptr*)sp)[1+i]);
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)sp)[1+i]);
if(i >= 4) {
- prints(", ...");
+ runtime·prints(", ...");
break;
}
}
- prints(")\n");
+ runtime·prints(")\n");
n++;
}
@@ -85,19 +85,19 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
}
void
-traceback(byte *pc0, byte *sp, byte *lr, G *g)
+runtime·traceback(byte *pc0, byte *sp, byte *lr, G *g)
{
gentraceback(pc0, sp, lr, g, 0, nil, 100);
}
// func caller(n int) (pc uintptr, file string, line int, ok bool)
int32
-callers(int32 skip, uintptr *pcbuf, int32 m)
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
{
byte *pc, *sp;
- sp = getcallersp(&skip);
- pc = ·getcallerpc(&skip);
+ sp = runtime·getcallersp(&skip);
+ pc = runtime·getcallerpc(&skip);
return gentraceback(pc, sp, 0, g, skip, pcbuf, m);
}
diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/arm/vlop.s
index c9e7090fc..2c5d7ebe1 100644
--- a/src/pkg/runtime/arm/vlop.s
+++ b/src/pkg/runtime/arm/vlop.s
@@ -30,7 +30,7 @@ arg=0
/* replaced use of R10 by R11 because the former can be the data segment base register */
-TEXT _mulv(SB), $0
+TEXT _mulv(SB), $0
MOVW 0(FP), R0
MOVW 4(FP), R2 /* l0 */
MOVW 8(FP), R11 /* h0 */
@@ -52,7 +52,7 @@ D = 2
CC = 3
TMP = 11
-TEXT save<>(SB), 7, $0
+TEXT save<>(SB), 7, $0
MOVW R(Q), 0(FP)
MOVW R(N), 4(FP)
MOVW R(D), 8(FP)
@@ -62,11 +62,11 @@ TEXT save<>(SB), 7, $0
MOVW 20(FP), R(D) /* denominator */
CMP $0, R(D)
BNE s1
- SWI 0
+ BL runtime·panicdivide(SB)
/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
s1: RET
-TEXT rest<>(SB), 7, $0
+TEXT rest<>(SB), 7, $0
MOVW 0(FP), R(Q)
MOVW 4(FP), R(N)
MOVW 8(FP), R(D)
@@ -79,7 +79,7 @@ TEXT rest<>(SB), 7, $0
ADD $20, R13
B (R14)
-TEXT div<>(SB), 7, $0
+TEXT div<>(SB), 7, $0
MOVW $32, R(CC)
/*
* skip zeros 8-at-a-time
@@ -114,7 +114,7 @@ loop:
BNE loop
RET
-TEXT _div(SB), 7, $16
+TEXT _div(SB), 7, $16
BL save<>(SB)
CMP $0, R(Q)
BGE d1
@@ -135,7 +135,7 @@ d2:
RSB $0, R(Q), R(TMP)
B out
-TEXT _mod(SB), 7, $16
+TEXT _mod(SB), 7, $16
BL save<>(SB)
CMP $0, R(D)
RSB.LT $0, R(D), R(D)
@@ -150,13 +150,13 @@ m1:
MOVW R(N), R(TMP)
B out
-TEXT _divu(SB), 7, $16
+TEXT _divu(SB), 7, $16
BL save<>(SB)
BL div<>(SB)
MOVW R(Q), R(TMP)
B out
-TEXT _modu(SB), 7, $16
+TEXT _modu(SB), 7, $16
BL save<>(SB)
BL div<>(SB)
MOVW R(N), R(TMP)
@@ -169,7 +169,7 @@ out:
// trampoline for _sfloat2. passes LR as arg0 and
// saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can
// be changed by _sfloat2.
-TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
+TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
MOVW R14, 4(R13)
MOVW R0, 8(R13)
MOVW $12(R13), R0
@@ -178,7 +178,7 @@ TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
MOVW R1, 60(R13)
WORD $0xe10f1000 // mrs r1, cpsr
MOVW R1, 64(R13)
- BL _sfloat2(SB)
+ BL runtime·_sfloat2(SB)
MOVW R0, 0(R13)
MOVW 64(R13), R1
WORD $0xe128f001 // msr cpsr_f, r1
diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/arm/vlrt.c
index 76b777a35..50f33710b 100644
--- a/src/pkg/runtime/arm/vlrt.c
+++ b/src/pkg/runtime/arm/vlrt.c
@@ -23,6 +23,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// declared here to avoid include of runtime.h
+void runtime·panicstring(char*);
+
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
@@ -31,6 +34,12 @@ typedef signed char schar;
#define SIGN(n) (1UL<<(n-1))
+void
+runtime·panicdivide(void)
+{
+ runtime·panicstring("integer divide by zero");
+}
+
typedef struct Vlong Vlong;
struct Vlong
{
@@ -47,210 +56,231 @@ struct Vlong
ushort loms;
ushort hils;
ushort hims;
- };
- };
+ };
+ };
};
-void abort(void);
+void runtime·abort(void);
void
_addv(Vlong *r, Vlong a, Vlong b)
{
- ulong lo, hi;
+ ulong lo, hi;
- lo = a.lo + b.lo;
- hi = a.hi + b.hi;
- if(lo < a.lo)
- hi++;
- r->lo = lo;
- r->hi = hi;
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
}
void
_subv(Vlong *r, Vlong a, Vlong b)
{
- ulong lo, hi;
+ ulong lo, hi;
- lo = a.lo - b.lo;
- hi = a.hi - b.hi;
- if(lo > a.lo)
- hi--;
- r->lo = lo;
- r->hi = hi;
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
}
-
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;
+ 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 <= 11) {
+ 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);
+ _d2v(y, f);
+}
+
+void
+runtime·float64toint64(double d, Vlong y)
+{
+ _d2v(&y, d);
}
void
-·float64toint64(double d, Vlong y)
+runtime·float64touint64(double d, Vlong y)
{
_d2v(&y, d);
}
double
+_ul2d(ulong u)
+{
+ // compensate for bug in c
+ if(u & SIGN(32)) {
+ u ^= SIGN(32);
+ return 2147483648. + u;
+ }
+ return u;
+}
+
+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;
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
+ }
+ return x.hi*4294967296. + _ul2d(x.lo);
}
float
_v2f(Vlong x)
{
- return _v2d(x);
+ return _v2d(x);
}
void
-·int64tofloat64(Vlong y, double d)
+runtime·int64tofloat64(Vlong y, double d)
{
d = _v2d(y);
}
+void
+runtime·uint64tofloat64(Vlong y, double d)
+{
+ d = _ul2d(y.hi)*4294967296. + _ul2d(y.lo);
+}
static void
dodiv(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;
- }
+ 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) {
+ runtime·panicdivide();
+ }
+
+ /*
+ * 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;
+ }
}
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);
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
}
void
-·uint64div(Vlong n, Vlong d, Vlong q)
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
{
_divvu(&q, n, d);
}
@@ -259,16 +289,16 @@ 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);
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
}
void
-·uint64mod(Vlong n, Vlong d, Vlong q)
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
{
_modvu(&q, n, d);
}
@@ -277,20 +307,20 @@ static void
vneg(Vlong *v)
{
- if(v->lo == 0) {
- v->hi = -v->hi;
- return;
- }
- v->lo = -v->lo;
- v->hi = ~v->hi;
+ 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;
+ long nneg, dneg;
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ 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 wrong sign
q->lo = 0x80000000;
@@ -300,20 +330,20 @@ _divv(Vlong *q, Vlong n, Vlong d)
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);
+ }
+ 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
-·int64div(Vlong n, Vlong d, Vlong q)
+runtime·int64div(Vlong n, Vlong d, Vlong q)
{
_divv(&q, n, d);
}
@@ -321,26 +351,26 @@ void
void
_modv(Vlong *r, Vlong n, Vlong d)
{
- long nneg, dneg;
+ long nneg, dneg;
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- 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);
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ 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
-·int64mod(Vlong n, Vlong d, Vlong q)
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
{
_modv(&q, n, d);
}
@@ -348,439 +378,439 @@ void
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);
+ 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);
+ 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);
+ 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;
+ 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;
+ 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;
+ 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++;
+ 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--;
+ 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;
+ 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;
+ 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 = *ret;
- 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;
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ runtime·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;
+ long t;
- t = (ulong)p;
- ret->lo = t;
- ret->hi = 0;
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sl2v(Vlong *ret, long sl)
{
- long t;
+ long t;
- t = sl;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_ul2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul;
- ret->lo = t;
- ret->hi = 0;
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_si2v(Vlong *ret, int si)
{
- long t;
+ long t;
- t = si;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_ui2v(Vlong *ret, uint ui)
{
- long t;
+ long t;
- t = ui;
- ret->lo = t;
- ret->hi = 0;
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sh2v(Vlong *ret, long sh)
{
- long t;
+ long t;
- t = (sh << 16) >> 16;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_uh2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul & 0xffff;
- ret->lo = t;
- ret->hi = 0;
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sc2v(Vlong *ret, long uc)
{
- long t;
+ long t;
- t = (uc << 24) >> 24;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_uc2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul & 0xff;
- ret->lo = t;
- ret->hi = 0;
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
}
long
_v2sc(Vlong rv)
{
- long t;
+ long t;
- t = rv.lo & 0xff;
- return (t << 24) >> 24;
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
}
long
_v2uc(Vlong rv)
{
- return rv.lo & 0xff;
+ return rv.lo & 0xff;
}
long
_v2sh(Vlong rv)
{
- long t;
+ long t;
- t = rv.lo & 0xffff;
- return (t << 16) >> 16;
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
}
long
_v2uh(Vlong rv)
{
- return rv.lo & 0xffff;
+ return rv.lo & 0xffff;
}
long
_v2sl(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2ul(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2si(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2ui(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
int
_testv(Vlong rv)
{
- return rv.lo || rv.hi;
+ return rv.lo || rv.hi;
}
int
_eqv(Vlong lv, Vlong rv)
{
- return lv.lo == rv.lo && lv.hi == rv.hi;
+ return lv.lo == rv.lo && lv.hi == rv.hi;
}
int
_nev(Vlong lv, Vlong rv)
{
- return lv.lo != rv.lo || lv.hi != rv.hi;
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
}
diff --git a/src/pkg/runtime/cgo/386.S b/src/pkg/runtime/cgo/386.S
new file mode 100755
index 000000000..9abab7ebd
--- /dev/null
+++ b/src/pkg/runtime/cgo/386.S
@@ -0,0 +1,67 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_386(void (*fn)(void))
+ *
+ * Calling into the 8c tool chain, where all registers are caller save.
+ * Called from standard x86 ABI, where %ebp, %ebx, %esi,
+ * and %edi are callee-save, so they must be saved explicitly.
+ */
+.globl EXT(crosscall_386)
+EXT(crosscall_386):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ movl 8(%ebp), %eax /* fn */
+ call *%eax
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ *
+ * Save registers and call fn with two arguments.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ pushl 16(%ebp)
+ pushl 12(%ebp)
+ mov 8(%ebp), %eax
+ call *%eax
+ addl $8,%esp
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+ jmp 1b
+
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
new file mode 100644
index 000000000..55b6967d9
--- /dev/null
+++ b/src/pkg/runtime/cgo/Makefile
@@ -0,0 +1,61 @@
+# Copyright 2010 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 ../../../Make.inc
+
+ENABLED:=1
+
+ifeq ($(GOARCH),arm)
+ENABLED:=0
+endif
+
+TARG=runtime/cgo
+
+GOFILES=\
+ cgo.go\
+
+ifeq ($(ENABLED),1)
+
+# Unwarranted chumminess with Make.pkg's cgo rules.
+# Do not try this at home.
+CGO_OFILES=\
+ $(GOARCH).o\
+ $(GOOS)_$(GOARCH).o\
+ util.o\
+
+OFILES=\
+ iscgo.$O\
+ callbacks.$O\
+ _cgo_import.$O\
+ $(CGO_OFILES)\
+
+CGO_LDFLAGS=-lpthread
+
+ifeq ($(GOOS),freebsd)
+OFILES+=\
+ freebsd.$O\
+
+endif
+
+endif
+
+include ../../../Make.pkg
+
+ifeq ($(ENABLED),1)
+_cgo_defun.c:
+ echo >$@
+
+_cgo_main.c:
+ echo 'int main() { return 0; }' >$@
+ echo 'void *crosscall2;' >>$@
+endif
+
+$(GOARCH).o: $(GOARCH).S
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+$(GOOS)_$(GOARCH).o: $(GOOS)_$(GOARCH).c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+%.o: %.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
diff --git a/src/pkg/runtime/cgo/amd64.S b/src/pkg/runtime/cgo/amd64.S
new file mode 100644
index 000000000..083c2bc94
--- /dev/null
+++ b/src/pkg/runtime/cgo/amd64.S
@@ -0,0 +1,73 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_amd64(void (*fn)(void))
+ *
+ * Calling into the 6c tool chain, where all registers are caller save.
+ * Called from standard x86-64 ABI, where %rbx, %rbp, %r12-%r15
+ * are callee-save so they must be saved explicitly.
+ * The standard x86-64 ABI passes the three arguments m, g, fn
+ * in %rdi, %rsi, %rdx.
+ *
+ * Also need to set %r15 to g and %r14 to m (see ../pkg/runtime/mkasmh.sh)
+ * during the call.
+ */
+.globl EXT(crosscall_amd64)
+EXT(crosscall_amd64):
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+ call *%rdi /* fn */
+
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void *arg, int32 argsize)
+ *
+ * Save registers and call fn with two arguments. fn is a Go function
+ * which takes parameters on the stack rather than in registers.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ subq $0x58, %rsp /* keeps stack pointer 32-byte aligned */
+ movq %rbx, 0x10(%rsp)
+ movq %rbp, 0x18(%rsp)
+ movq %r12, 0x20(%rsp)
+ movq %r13, 0x28(%rsp)
+ movq %r14, 0x30(%rsp)
+ movq %r15, 0x38(%rsp)
+
+ movq %rsi, 0(%rsp) /* arg */
+ movq %rdx, 8(%rsp) /* argsize (includes padding) */
+
+ call *%rdi /* fn */
+
+ movq 0x10(%rsp), %rbx
+ movq 0x18(%rsp), %rbp
+ movq 0x20(%rsp), %r12
+ movq 0x28(%rsp), %r13
+ movq 0x30(%rsp), %r14
+ movq 0x38(%rsp), %r15
+ addq $0x58, %rsp
+ ret
diff --git a/src/pkg/runtime/cgo/arm.S b/src/pkg/runtime/cgo/arm.S
new file mode 100644
index 000000000..32d862984
--- /dev/null
+++ b/src/pkg/runtime/cgo/arm.S
@@ -0,0 +1 @@
+/* unimplemented */
diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c
new file mode 100644
index 000000000..f36fb3fd7
--- /dev/null
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -0,0 +1,73 @@
+// Copyright 2011 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 "../cgocall.h"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// The declaration of crosscall2 is:
+// void crosscall2(void (*fn)(void *, int), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries.
+#pragma dynexport crosscall2 crosscall2
+
+// Allocate memory. This allocates the requested number of bytes in
+// memory controlled by the Go runtime. The allocated memory will be
+// zeroed. You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime. If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+
+// Call like this in code compiled with gcc:
+// struct { size_t len; void *ret; } a;
+// a.len = /* number of bytes to allocate */;
+// crosscall2(_cgo_allocate, &a, sizeof a);
+// /* Here a.ret is a pointer to the allocated memory. */
+
+static void
+_cgo_allocate_internal(uintptr len, byte *ret)
+{
+ ret = runtime·mal(len);
+ FLUSH(&ret);
+}
+
+#pragma dynexport _cgo_allocate _cgo_allocate
+void
+_cgo_allocate(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_allocate_internal, a, n);
+}
+
+// Panic. The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+// struct { const char *p; } a;
+// a.p = /* string to pass to panic */;
+// crosscall2(_cgo_panic, &a, sizeof a);
+// /* The function call will not return. */
+
+extern void ·cgoStringToEface(String, Eface*);
+
+static void
+_cgo_panic_internal(byte *p)
+{
+ String s;
+ Eface err;
+
+ s = runtime·gostring(p);
+ ·cgoStringToEface(s, &err);
+ runtime·panic(err);
+}
+
+#pragma dynexport _cgo_panic _cgo_panic
+void
+_cgo_panic(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n);
+}
diff --git a/src/pkg/runtime/cgo/cgo.go b/src/pkg/runtime/cgo/cgo.go
new file mode 100644
index 000000000..5dcced1e4
--- /dev/null
+++ b/src/pkg/runtime/cgo/cgo.go
@@ -0,0 +1,17 @@
+// Copyright 2010 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 cgo contains runtime support for code generated
+by the cgo tool. See the documentation for the cgo command
+for details on using cgo.
+*/
+package cgo
+
+// Supports _cgo_panic by converting a string constant to an empty
+// interface.
+
+func cgoStringToEface(s string, ret *interface{}) {
+ *ret = s
+}
diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
new file mode 100644
index 000000000..4fc7eb4e0
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -0,0 +1,144 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+static void
+inittls(void)
+{
+ uint32 x, y;
+ pthread_key_t tofree[16], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Allocate thread-local storage slots for m, g.
+ * The key numbers start at 0x100, and we expect to be
+ * one of the early calls to pthread_key_create, so we
+ * should be able to get pretty low numbers.
+ *
+ * In Darwin/386 pthreads, %gs points at the thread
+ * structure, and each key is an index into the thread-local
+ * storage array that begins at offset 0x48 within in that structure.
+ * It may happen that we are not quite the first function to try
+ * to allocate thread-local storage keys, so instead of depending
+ * on getting 0x100 and 0x101, we try for 0x108 and 0x109,
+ * allocating keys until we get the ones we want and then freeing
+ * the ones we didn't want.
+ *
+ * Thus the final offsets to use in %gs references are
+ * 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g. The code
+ * below verifies that the constants are correct once it has
+ * obtained the keys. Known to ../cmd/8l/obj.c:/468
+ * and to ../pkg/runtime/darwin/386/sys.s:/468
+ *
+ * This is truly disgusting and a bit fragile, but taking care
+ * of it here protects the rest of the system from damage.
+ * The alternative would be to use a global variable that
+ * held the offset and refer to that variable each time we
+ * need a %gs variable (m or g). That approach would
+ * require an extra instruction and memory reference in
+ * every stack growth prolog and would also require
+ * rewriting the code that 8c generates for extern registers.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ abort();
+ }
+ if(k == 0x108) {
+ havek1 = 1;
+ k1 = k;
+ continue;
+ }
+ if(k == 0x109) {
+ havek2 = 1;
+ k2 = k;
+ continue;
+ }
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\twanted 0x108 and 0x109\n");
+ fprintf(stderr, "\tgot");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#lx", tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+
+ /*
+ * We got the keys we wanted. Make sure that we observe
+ * updates to k1 at 0x468, to verify that the TLS array
+ * offset from %gs hasn't changed.
+ */
+ pthread_setspecific(k1, (void*)0x12345678);
+ asm volatile("movl %%gs:0x468, %0" : "=r"(x));
+
+ pthread_setspecific(k1, (void*)0x87654321);
+ asm volatile("movl %%gs:0x468, %0" : "=r"(y));
+
+ if(x != 0x12345678 || y != 0x87654321) {
+ printf("libcgo: thread-local storage %#lx not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y);
+ abort();
+ }
+}
+
+static void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ pthread_setspecific(k1, (void*)ts.g);
+ pthread_setspecific(k2, (void*)ts.m);
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
new file mode 100644
index 000000000..253a1b252
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -0,0 +1,125 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+static void
+inittls(void)
+{
+ uint64 x, y;
+ pthread_key_t tofree[16], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Same logic, code as darwin_386.c:/inittls, except that words
+ * are 8 bytes long now, and the thread-local storage starts at 0x60.
+ * So the offsets are
+ * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g. The code
+ * below verifies that the constants are correct once it has
+ * obtained the keys. Known to ../cmd/6l/obj.c:/8a0
+ * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
+ *
+ * As disgusting as on the 386; same justification.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ abort();
+ }
+ if(k == 0x108) {
+ havek1 = 1;
+ k1 = k;
+ continue;
+ }
+ if(k == 0x109) {
+ havek2 = 1;
+ k2 = k;
+ continue;
+ }
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\twanted 0x108 and 0x109\n");
+ fprintf(stderr, "\tgot");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+
+ /*
+ * We got the keys we wanted. Make sure that we observe
+ * updates to k1 at 0x8a0, to verify that the TLS array
+ * offset from %gs hasn't changed.
+ */
+ pthread_setspecific(k1, (void*)0x123456789abcdef0ULL);
+ asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
+
+ pthread_setspecific(k2, (void*)0x0fedcba987654321);
+ asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
+
+ if(x != 0x123456789abcdef0ULL || y != 0x0fedcba987654321) {
+ printf("libcgo: thread-local storage %#x not at %%gs:0x8a0 - x=%#llx y=%#llx\n", (unsigned)k1, x, y);
+ abort();
+ }
+}
+
+void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ pthread_setspecific(k1, (void*)ts.g);
+ pthread_setspecific(k2, (void*)ts.m);
+
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd.c b/src/pkg/runtime/cgo/freebsd.c
new file mode 100644
index 000000000..dfcfa3a21
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd.c
@@ -0,0 +1,13 @@
+// Copyright 2010 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.
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/freebsd_386.c
new file mode 100644
index 000000000..d08e1dee8
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_386.c
@@ -0,0 +1,59 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On FreeBSD/ELF, the thread local storage
+ * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
+ * for the two words g and m at %gs:-8 and %gs:-4.
+ */
+ asm volatile (
+ "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
+ "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/freebsd_amd64.c
new file mode 100644
index 000000000..fe6ce391f
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_amd64.c
@@ -0,0 +1,58 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On FreeBSD/ELF, the thread local storage
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
+ */
+ asm volatile (
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/iscgo.c b/src/pkg/runtime/cgo/iscgo.c
new file mode 100644
index 000000000..eb6f5c09d
--- /dev/null
+++ b/src/pkg/runtime/cgo/iscgo.c
@@ -0,0 +1,14 @@
+// Copyright 2010 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 an uninitialized definition
+// for runtime·iscgo. Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break. This variable is a
+// backup: it depends only on old C style static linking rules.
+
+#include "../runtime.h"
+
+bool runtime·iscgo = 1;
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
new file mode 100644
index 000000000..91032959c
--- /dev/null
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -0,0 +1,60 @@
+// 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef uintptr_t uintptr;
+
+/*
+ * The beginning of the per-goroutine structure,
+ * as defined in ../pkg/runtime/runtime.h.
+ * Just enough to edit these two fields.
+ */
+typedef struct G G;
+struct G
+{
+ uintptr stackguard;
+ uintptr stackbase;
+};
+
+/*
+ * Arguments to the libcgo_thread_start call.
+ * Also known to ../pkg/runtime/runtime.h.
+ */
+typedef struct ThreadStart ThreadStart;
+struct ThreadStart
+{
+ uintptr m;
+ G *g;
+ void (*fn)(void);
+};
+
+/*
+ * Called by 5c/6c/8c world.
+ * Makes a local copy of the ThreadStart and
+ * calls libcgo_sys_thread_start(ts).
+ */
+void (*libcgo_thread_start)(ThreadStart *ts);
+
+/*
+ * Creates the new operating system thread (OS, arch dependent).
+ */
+void libcgo_sys_thread_start(ThreadStart *ts);
+
+/*
+ * Call fn in the 6c world.
+ */
+void crosscall_amd64(void (*fn)(void));
+
+/*
+ * Call fn in the 8c world.
+ */
+void crosscall_386(void (*fn)(void));
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/linux_386.c
new file mode 100644
index 000000000..00322d4b7
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_386.c
@@ -0,0 +1,68 @@
+// 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 <pthread.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ // Not sure why the memset is necessary here,
+ // but without it, we get a bogus stack size
+ // out of pthread_attr_getstacksize. C'est la Linux.
+ memset(&attr, 0, sizeof attr);
+ pthread_attr_init(&attr);
+ size = 0;
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On Linux/ELF, the thread local storage
+ * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
+ * for the two words g and m at %gs:-8 and %gs:-4.
+ * Xen requires us to access those words indirect from %gs:0
+ * which points at itself.
+ */
+ asm volatile (
+ "movl %%gs:0, %%eax\n" // MOVL 0(GS), tmp
+ "movl %0, -8(%%eax)\n" // MOVL g, -8(GS)
+ "movl %1, -4(%%eax)\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/linux_amd64.c
new file mode 100644
index 000000000..e77c5ddfe
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_amd64.c
@@ -0,0 +1,58 @@
+// 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 <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys. On Linux/ELF, the thread local storage
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
+ */
+ asm volatile (
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/linux_arm.c b/src/pkg/runtime/cgo/linux_arm.c
new file mode 100644
index 000000000..e556c433c
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_arm.c
@@ -0,0 +1,19 @@
+// Copyright 2010 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 "libcgo.h"
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ // unimplemented
+ *(int*)0 = 0;
+}
diff --git a/src/pkg/runtime/cgo/nacl_386.c b/src/pkg/runtime/cgo/nacl_386.c
new file mode 100644
index 000000000..e556c433c
--- /dev/null
+++ b/src/pkg/runtime/cgo/nacl_386.c
@@ -0,0 +1,19 @@
+// Copyright 2010 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 "libcgo.h"
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ // unimplemented
+ *(int*)0 = 0;
+}
diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/util.c
new file mode 100644
index 000000000..0eff19aa6
--- /dev/null
+++ b/src/pkg/runtime/cgo/util.c
@@ -0,0 +1,51 @@
+// 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 "libcgo.h"
+
+/* Stub for calling malloc from Go */
+static void
+x_cgo_malloc(void *p)
+{
+ struct a {
+ long long n;
+ void *ret;
+ } *a = p;
+
+ a->ret = malloc(a->n);
+}
+
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
+/* Stub for calling from Go */
+static void
+x_cgo_free(void *p)
+{
+ struct a {
+ void *arg;
+ } *a = p;
+
+ free(a->arg);
+}
+
+void (*_cgo_free)(void*) = x_cgo_free;
+
+/* Stub for creating a new thread */
+static void
+xlibcgo_thread_start(ThreadStart *arg)
+{
+ ThreadStart *ts;
+
+ /* Make our own copy that can persist after we return. */
+ ts = malloc(sizeof *ts);
+ if(ts == nil) {
+ fprintf(stderr, "libcgo: out of memory in thread_start\n");
+ abort();
+ }
+ *ts = *arg;
+
+ libcgo_sys_thread_start(ts); /* OS-dependent half */
+}
+
+void (*libcgo_thread_start)(ThreadStart*) = xlibcgo_thread_start;
diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/windows_386.c
new file mode 100755
index 000000000..5f5235bd2
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_386.c
@@ -0,0 +1,57 @@
+// 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 WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 1MB is default for 32-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (1*1024*1024)
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ asm volatile (
+ "MOVL %%fs:0x2c, %%eax\n" // MOVL 0x24(FS), tmp
+ "movl %0, 0(%%eax)\n" // MOVL g, 0(FS)
+ "movl %1, 4(%%eax)\n" // MOVL m, 4(FS)
+ :: "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
new file mode 100755
index 000000000..dafe8cd9d
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -0,0 +1,47 @@
+// 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 WIN64_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 2MB is default for 64-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (2*1024*1024)
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ ts.g->stackbase = (uintptr)&ts;
+
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index f673d1b6e..80ae97e7a 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -7,16 +7,19 @@
void *initcgo; /* filled in by dynamic linker when Cgo is available */
int64 ncgocall;
-void ·entersyscall(void);
-void ·exitsyscall(void);
+void runtime·entersyscall(void);
+void runtime·exitsyscall(void);
void
-cgocall(void (*fn)(void*), void *arg)
+runtime·cgocall(void (*fn)(void*), void *arg)
{
G *oldlock;
- if(initcgo == nil)
- throw("cgocall unavailable");
+ if(!runtime·iscgo)
+ runtime·throw("cgocall unavailable");
+
+ if(fn == 0)
+ runtime·throw("cgocall nil");
ncgocall++;
@@ -34,9 +37,9 @@ cgocall(void (*fn)(void*), void *arg)
* M to run goroutines while we are in the
* foreign code.
*/
- ·entersyscall();
- runcgo(fn, arg);
- ·exitsyscall();
+ runtime·entersyscall();
+ runtime·runcgo(fn, arg);
+ runtime·exitsyscall();
m->lockedg = oldlock;
if(oldlock == nil)
@@ -51,37 +54,38 @@ cgocall(void (*fn)(void*), void *arg)
// arguments back where they came from, and finally returns to the old
// stack.
void
-cgocallback(void (*fn)(void), void *arg, int32 argsize)
+runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
{
- Gobuf oldsched;
+ Gobuf oldsched, oldg1sched;
G *g1;
void *sp;
if(g != m->g0)
- throw("bad g in cgocallback");
-
- oldsched = m->sched;
+ runtime·throw("bad g in cgocallback");
g1 = m->curg;
+ oldsched = m->sched;
+ oldg1sched = g1->sched;
- startcgocallback(g1);
+ runtime·startcgocallback(g1);
sp = g1->sched.sp - argsize;
if(sp < g1->stackguard)
- throw("g stack overflow in cgocallback");
- mcpy(sp, arg, argsize);
+ runtime·throw("g stack overflow in cgocallback");
+ runtime·mcpy(sp, arg, argsize);
- runcgocallback(g1, sp, fn);
+ runtime·runcgocallback(g1, sp, fn);
- mcpy(arg, sp, argsize);
+ runtime·mcpy(arg, sp, argsize);
- endcgocallback(g1);
+ runtime·endcgocallback(g1);
m->sched = oldsched;
+ g1->sched = oldg1sched;
}
void
-·Cgocalls(int64 ret)
+runtime·Cgocalls(int64 ret)
{
ret = ncgocall;
FLUSH(&ret);
@@ -91,22 +95,22 @@ void (*_cgo_malloc)(void*);
void (*_cgo_free)(void*);
void*
-cmalloc(uintptr n)
+runtime·cmalloc(uintptr n)
{
- struct a {
+ struct {
uint64 n;
void *ret;
} a;
a.n = n;
a.ret = nil;
- cgocall(_cgo_malloc, &a);
+ runtime·cgocall(_cgo_malloc, &a);
return a.ret;
}
void
-cfree(void *p)
+runtime·cfree(void *p)
{
- cgocall(_cgo_free, p);
+ runtime·cgocall(_cgo_free, p);
}
diff --git a/src/pkg/runtime/cgocall.h b/src/pkg/runtime/cgocall.h
index 9cdb409a3..1ad954eb1 100644
--- a/src/pkg/runtime/cgocall.h
+++ b/src/pkg/runtime/cgocall.h
@@ -6,7 +6,7 @@
* Cgo interface.
*/
-void cgocall(void (*fn)(void*), void*);
-void cgocallback(void (*fn)(void), void*, int32);
-void *cmalloc(uintptr);
-void cfree(void*);
+void runtime·cgocall(void (*fn)(void*), void*);
+void runtime·cgocallback(void (*fn)(void), void*, int32);
+void *runtime·cmalloc(uintptr);
+void runtime·cfree(void*);
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index 08cd75a6e..94ea513e7 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -90,24 +90,24 @@ static uint32 fastrand2(void);
static void destroychan(Hchan*);
Hchan*
-makechan(Type *elem, int64 hint)
+runtime·makechan_c(Type *elem, int64 hint)
{
Hchan *c;
int32 i;
if(hint < 0 || (int32)hint != hint || hint > ((uintptr)-1) / elem->size)
- panicstring("makechan: size out of range");
+ runtime·panicstring("makechan: size out of range");
- if(elem->alg >= nelem(algarray)) {
- printf("chan(alg=%d)\n", elem->alg);
- throw("runtime.makechan: unsupported elem type");
+ if(elem->alg >= nelem(runtime·algarray)) {
+ runtime·printf("chan(alg=%d)\n", elem->alg);
+ runtime·throw("runtime.makechan: unsupported elem type");
}
- c = mal(sizeof(*c));
- addfinalizer(c, destroychan, 0);
+ c = runtime·mal(sizeof(*c));
+ runtime·addfinalizer(c, destroychan, 0);
c->elemsize = elem->size;
- c->elemalg = &algarray[elem->alg];
+ c->elemalg = &runtime·algarray[elem->alg];
c->elemalign = elem->align;
if(hint > 0) {
@@ -117,7 +117,7 @@ makechan(Type *elem, int64 hint)
b = nil;
e = nil;
for(i=0; i<hint; i++) {
- d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
+ d = runtime·mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
if(e == nil)
e = d;
d->link = b;
@@ -131,7 +131,7 @@ makechan(Type *elem, int64 hint)
}
if(debug)
- printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
+ runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz);
return c;
@@ -140,15 +140,15 @@ makechan(Type *elem, int64 hint)
static void
destroychan(Hchan *c)
{
- destroylock(&c->Lock);
+ runtime·destroylock(&c->Lock);
}
// makechan(elem *Type, hint int64) (hchan *chan any);
void
-·makechan(Type *elem, int64 hint, Hchan *ret)
+runtime·makechan(Type *elem, int64 hint, Hchan *ret)
{
- ret = makechan(elem, hint);
+ ret = runtime·makechan_c(elem, hint);
FLUSH(&ret);
}
@@ -158,7 +158,7 @@ incerr(Hchan* c)
c->closed += Eincr;
if(c->closed & Emax) {
// Note that channel locks may still be held at this point.
- throw("too many operations on a closed channel");
+ runtime·throw("too many operations on a closed channel");
}
}
@@ -177,21 +177,24 @@ incerr(Hchan* c)
* the operation; we'll see that it's now closed.
*/
void
-chansend(Hchan *c, byte *ep, bool *pres)
+runtime·chansend(Hchan *c, byte *ep, bool *pres)
{
SudoG *sg;
G* gp;
- if(gcwaiting)
- gosched();
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug) {
- printf("chansend: chan=%p; elem=", c);
+ runtime·printf("chansend: chan=%p; elem=", c);
c->elemalg->print(c->elemsize, ep);
- prints("\n");
+ runtime·prints("\n");
}
- lock(c);
+ runtime·lock(c);
loop:
if(c->closed & Wclosed)
goto closed;
@@ -206,8 +209,8 @@ loop:
gp = sg->g;
gp->param = sg;
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
@@ -215,7 +218,7 @@ loop:
}
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
*pres = false;
return;
}
@@ -226,15 +229,15 @@ loop:
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
sg = g->param;
if(sg == nil)
goto loop;
freesg(c, sg);
- unlock(c);
+ runtime·unlock(c);
return;
asynch:
@@ -243,17 +246,17 @@ asynch:
if(c->qcount >= c->dataqsiz) {
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
*pres = false;
return;
}
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
goto asynch;
}
if(ep != nil)
@@ -265,10 +268,10 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
} else
- unlock(c);
+ runtime·unlock(c);
if(pres != nil)
*pres = true;
return;
@@ -277,22 +280,25 @@ closed:
incerr(c);
if(pres != nil)
*pres = true;
- unlock(c);
+ runtime·unlock(c);
}
void
-chanrecv(Hchan* c, byte *ep, bool* pres)
+runtime·chanrecv(Hchan* c, byte *ep, bool* pres)
{
SudoG *sg;
G *gp;
- if(gcwaiting)
- gosched();
+ if(c == nil)
+ runtime·panicstring("receive from nil channel");
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug)
- printf("chanrecv: chan=%p\n", c);
+ runtime·printf("chanrecv: chan=%p\n", c);
- lock(c);
+ runtime·lock(c);
loop:
if(c->dataqsiz > 0)
goto asynch;
@@ -307,8 +313,8 @@ loop:
gp = sg->g;
gp->param = sg;
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
@@ -316,7 +322,7 @@ loop:
}
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
c->elemalg->copy(c->elemsize, ep, nil);
*pres = false;
return;
@@ -326,10 +332,10 @@ loop:
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
sg = g->param;
if(sg == nil)
goto loop;
@@ -337,7 +343,7 @@ loop:
c->elemalg->copy(c->elemsize, ep, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil);
freesg(c, sg);
- unlock(c);
+ runtime·unlock(c);
return;
asynch:
@@ -346,7 +352,7 @@ asynch:
goto closed;
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
c->elemalg->copy(c->elemsize, ep, nil);
*pres = false;
return;
@@ -354,10 +360,10 @@ asynch:
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
goto asynch;
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
@@ -368,14 +374,14 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
return;
}
- unlock(c);
+ runtime·unlock(c);
if(pres != nil)
*pres = true;
return;
@@ -386,96 +392,102 @@ closed:
incerr(c);
if(pres != nil)
*pres = true;
- unlock(c);
+ runtime·unlock(c);
}
// chansend1(hchan *chan any, elem any);
#pragma textflag 7
void
-·chansend1(Hchan* c, ...)
+runtime·chansend1(Hchan* c, ...)
{
int32 o;
byte *ae;
- o = rnd(sizeof(c), c->elemalign);
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ o = runtime·rnd(sizeof(c), c->elemalign);
ae = (byte*)&c + o;
- chansend(c, ae, nil);
+ runtime·chansend(c, ae, nil);
}
// chansend2(hchan *chan any, elem any) (pres bool);
#pragma textflag 7
void
-·chansend2(Hchan* c, ...)
+runtime·chansend2(Hchan* c, ...)
{
int32 o;
byte *ae, *ap;
- o = rnd(sizeof(c), c->elemalign);
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ o = runtime·rnd(sizeof(c), c->elemalign);
ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, Structrnd);
+ o = runtime·rnd(o+c->elemsize, Structrnd);
ap = (byte*)&c + o;
- chansend(c, ae, ap);
+ runtime·chansend(c, ae, ap);
}
// chanrecv1(hchan *chan any) (elem any);
#pragma textflag 7
void
-·chanrecv1(Hchan* c, ...)
+runtime·chanrecv1(Hchan* c, ...)
{
int32 o;
byte *ae;
- o = rnd(sizeof(c), Structrnd);
+ o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
- chanrecv(c, ae, nil);
+ runtime·chanrecv(c, ae, nil);
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
#pragma textflag 7
void
-·chanrecv2(Hchan* c, ...)
+runtime·chanrecv2(Hchan* c, ...)
{
int32 o;
byte *ae, *ap;
- o = rnd(sizeof(c), Structrnd);
+ o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, 1);
+ o = runtime·rnd(o+c->elemsize, 1);
ap = (byte*)&c + o;
- chanrecv(c, ae, ap);
+ runtime·chanrecv(c, ae, ap);
}
// newselect(size uint32) (sel *byte);
#pragma textflag 7
void
-·newselect(int32 size, ...)
+runtime·newselect(int32 size, ...)
{
int32 n, o;
Select **selp;
Select *sel;
- o = rnd(sizeof(size), Structrnd);
+ o = runtime·rnd(sizeof(size), Structrnd);
selp = (Select**)((byte*)&size + o);
n = 0;
if(size > 1)
n = size-1;
- sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+ sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
sel->tcase = size;
sel->ncase = 0;
*selp = sel;
if(debug)
- printf("newselect s=%p size=%d\n", sel, size);
+ runtime·printf("newselect s=%p size=%d\n", sel, size);
}
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
#pragma textflag 7
void
-·selectsend(Select *sel, Hchan *c, ...)
+runtime·selectsend(Select *sel, Hchan *c, ...)
{
int32 i, eo;
Scase *cas;
@@ -487,31 +499,31 @@ void
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectsend: too many cases");
+ runtime·throw("selectsend: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
+ cas = runtime·mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), c->elemsize);
- cas->so = rnd(eo+c->elemsize, Structrnd);
+ eo = runtime·rnd(sizeof(sel), sizeof(c));
+ eo = runtime·rnd(eo+sizeof(c), c->elemsize);
+ cas->so = runtime·rnd(eo+c->elemsize, Structrnd);
cas->send = 1;
ae = (byte*)&sel + eo;
c->elemalg->copy(c->elemsize, cas->u.elem, ae);
if(debug)
- printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n",
+ runtime·printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send);
}
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag 7
void
-·selectrecv(Select *sel, Hchan *c, ...)
+runtime·selectrecv(Select *sel, Hchan *c, ...)
{
int32 i, eo;
Scase *cas;
@@ -522,21 +534,21 @@ void
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectrecv: too many cases");
+ runtime·throw("selectrecv: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas);
+ cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), sizeof(byte*));
- cas->so = rnd(eo+sizeof(byte*), Structrnd);
+ eo = runtime·rnd(sizeof(sel), sizeof(c));
+ eo = runtime·rnd(eo+sizeof(c), sizeof(byte*));
+ cas->so = runtime·rnd(eo+sizeof(byte*), Structrnd);
cas->send = 0;
cas->u.elemp = *(byte**)((byte*)&sel + eo);
if(debug)
- printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n",
+ runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send);
}
@@ -544,26 +556,26 @@ void
// selectdefaul(sel *byte) (selected bool);
#pragma textflag 7
void
-·selectdefault(Select *sel, ...)
+runtime·selectdefault(Select *sel, ...)
{
int32 i;
Scase *cas;
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectdefault: too many cases");
+ runtime·throw("selectdefault: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas);
+ cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = nil;
- cas->so = rnd(sizeof(sel), Structrnd);
+ cas->so = runtime·rnd(sizeof(sel), Structrnd);
cas->send = 2;
cas->u.elemp = nil;
if(debug)
- printf("selectdefault s=%p pc=%p so=%d send=%d\n",
+ runtime·printf("selectdefault s=%p pc=%p so=%d send=%d\n",
sel, cas->pc, cas->so, cas->send);
}
@@ -573,8 +585,8 @@ freesel(Select *sel)
uint32 i;
for(i=0; i<sel->ncase; i++)
- free(sel->scase[i]);
- free(sel);
+ runtime·free(sel->scase[i]);
+ runtime·free(sel);
}
static void
@@ -587,7 +599,7 @@ sellock(Select *sel)
for(i=0; i<sel->ncase; i++) {
if(sel->scase[i]->chan != c) {
c = sel->scase[i]->chan;
- lock(c);
+ runtime·lock(c);
}
}
}
@@ -602,14 +614,20 @@ selunlock(Select *sel)
for(i=sel->ncase; i>0; i--) {
if(sel->scase[i-1]->chan && sel->scase[i-1]->chan != c) {
c = sel->scase[i-1]->chan;
- unlock(c);
+ runtime·unlock(c);
}
}
}
// selectgo(sel *byte);
+//
+// overwrites return pc on stack to signal which case of the select
+// to run, so cannot appear at the top of a split stack.
+// frame has 6 pointers and 4 int32 so 64 bytes max.
+// that's less than StackGuard-StackSmall, so okay.
+#pragma textflag 7
void
-·selectgo(Select *sel)
+runtime·selectgo(Select *sel)
{
uint32 p, o, i, j;
Scase *cas, *dfl;
@@ -618,16 +636,18 @@ void
G *gp;
byte *as;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug)
- printf("select: sel=%p\n", sel);
+ runtime·printf("select: sel=%p\n", sel);
if(sel->ncase < 2) {
- if(sel->ncase < 1)
- throw("select: no cases");
- // make special case of one.
+ if(sel->ncase < 1) {
+ g->status = Gwaiting; // forever
+ runtime·gosched();
+ }
+ // TODO: make special case of one.
}
// select a (relative) prime
@@ -636,7 +656,7 @@ void
if(gcd(p, sel->ncase) == 1)
break;
if(i > 1000)
- throw("select: failed to select prime");
+ runtime·throw("select: failed to select prime");
}
// select an initial offset
@@ -716,10 +736,10 @@ loop:
case 0: // recv
if(c->dataqsiz > 0) {
if(c->qcount > 0)
- throw("select: pass 2 async recv");
+ runtime·throw("select: pass 2 async recv");
} else {
if(dequeue(&c->sendq, c))
- throw("select: pass 2 sync recv");
+ runtime·throw("select: pass 2 sync recv");
}
enqueue(&c->recvq, sg);
break;
@@ -727,10 +747,10 @@ loop:
case 1: // send
if(c->dataqsiz > 0) {
if(c->qcount < c->dataqsiz)
- throw("select: pass 2 async send");
+ runtime·throw("select: pass 2 async send");
} else {
if(dequeue(&c->recvq, c))
- throw("select: pass 2 sync send");
+ runtime·throw("select: pass 2 sync send");
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
}
enqueue(&c->sendq, sg);
@@ -745,7 +765,7 @@ loop:
g->param = nil;
g->status = Gwaiting;
selunlock(sel);
- gosched();
+ runtime·gosched();
sellock(sel);
sg = g->param;
@@ -780,7 +800,7 @@ loop:
}
if(debug)
- printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n",
+ runtime·printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n",
sel, c, cas, cas->send, o);
if(!cas->send) {
@@ -803,7 +823,7 @@ asyncrecv:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
goto retc;
@@ -817,20 +837,20 @@ asyncsend:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
goto retc;
syncrecv:
// can receive from sleeping sender (sg)
if(debug)
- printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
+ runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil);
gp = sg->g;
gp->param = sg;
- ready(gp);
+ runtime·ready(gp);
goto retc;
rclose:
@@ -844,13 +864,13 @@ rclose:
syncsend:
// can send to sleeping receiver (sg)
if(debug)
- printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
+ runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(c->closed & Wclosed)
goto sclose;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g;
gp->param = sg;
- ready(gp);
+ runtime·ready(gp);
goto retc;
sclose:
@@ -862,7 +882,7 @@ retc:
selunlock(sel);
// return to pc corresponding to chosen case
- ·setcallerpc(&sel, cas->pc);
+ runtime·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
freesel(sel);
*as = true;
@@ -870,15 +890,15 @@ retc:
// closechan(sel *byte);
void
-·closechan(Hchan *c)
+runtime·closechan(Hchan *c)
{
SudoG *sg;
G* gp;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
incerr(c);
c->closed |= Wclosed;
@@ -890,7 +910,7 @@ void
gp = sg->g;
gp->param = nil;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
// release all writers
@@ -901,32 +921,32 @@ void
gp = sg->g;
gp->param = nil;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
- unlock(c);
+ runtime·unlock(c);
}
void
-chanclose(Hchan *c)
+runtime·chanclose(Hchan *c)
{
- ·closechan(c);
+ runtime·closechan(c);
}
bool
-chanclosed(Hchan *c)
+runtime·chanclosed(Hchan *c)
{
return (c->closed & Rclosed) != 0;
}
int32
-chanlen(Hchan *c)
+runtime·chanlen(Hchan *c)
{
return c->qcount;
}
int32
-chancap(Hchan *c)
+runtime·chancap(Hchan *c)
{
return c->dataqsiz;
}
@@ -934,9 +954,9 @@ chancap(Hchan *c)
// closedchan(sel *byte) bool;
void
-·closedchan(Hchan *c, bool closed)
+runtime·closedchan(Hchan *c, bool closed)
{
- closed = chanclosed(c);
+ closed = runtime·chanclosed(c);
FLUSH(&closed);
}
@@ -952,7 +972,7 @@ loop:
q->first = sgp->link;
// if sgp is stale, ignore it
- if(!cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) {
+ if(!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) {
//prints("INVALID PSEUDOG POINTER\n");
freesg(c, sgp);
goto loop;
@@ -997,7 +1017,7 @@ allocsg(Hchan *c)
if(sg != nil) {
c->free = sg->link;
} else
- sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
+ sg = runtime·mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
sg->selgen = g->selgen;
sg->g = g;
sg->offset = 0;
@@ -1011,7 +1031,7 @@ freesg(Hchan *c, SudoG *sg)
{
if(sg != nil) {
if(sg->isfree)
- throw("chan.freesg: already free");
+ runtime·throw("chan.freesg: already free");
sg->isfree = 1;
sg->link = c->free;
c->free = sg;
diff --git a/src/pkg/runtime/chan_defs.go b/src/pkg/runtime/chan_defs.go
new file mode 100644
index 000000000..5cfea6e15
--- /dev/null
+++ b/src/pkg/runtime/chan_defs.go
@@ -0,0 +1,56 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is chan.c
+
+package runtime
+
+type sudoG struct {
+ g *g_
+ selgen uint32
+ offset int16
+ isfree int8
+ link *sudoG
+ elem [8]byte
+}
+
+type waitQ struct {
+ first *sudoG
+ last *sudoG
+}
+
+type hChan struct {
+ qcount uint32
+ dataqsiz uint32
+ elemsize uint16
+ closed uint16
+ elemalign uint8
+ elemalg *alg
+ senddataq *link
+ recvdataq *link
+ recvq waitQ
+ sendq waitQ
+ free sudoG
+ lock
+}
+
+type link struct {
+ link *link
+ elem [8]byte
+}
+
+type scase struct {
+ chan_ *hChan
+ pc *byte
+ send uint16
+ so uint16
+ elemp *byte // union elem [8]byte
+}
+
+type select_ struct {
+ tcase uint16
+ ncase uint16
+ link *select_
+ scase [1]*scase
+}
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.c
index 2240d9fb8..eeb943940 100644
--- a/src/pkg/runtime/complex.c
+++ b/src/pkg/runtime/complex.c
@@ -7,34 +7,34 @@
typedef struct Complex128 Complex128;
void
-·complex128div(Complex128 n, Complex128 d, Complex128 q)
+runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
{
int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom;
// Special cases as in C99.
- ninf = isInf(n.real, 0) || isInf(n.imag, 0);
- dinf = isInf(d.real, 0) || isInf(d.imag, 0);
+ ninf = runtime·isInf(n.real, 0) || runtime·isInf(n.imag, 0);
+ dinf = runtime·isInf(d.real, 0) || runtime·isInf(d.imag, 0);
- nnan = !ninf && (isNaN(n.real) || isNaN(n.imag));
- dnan = !dinf && (isNaN(d.real) || isNaN(d.imag));
+ nnan = !ninf && (runtime·isNaN(n.real) || runtime·isNaN(n.imag));
+ dnan = !dinf && (runtime·isNaN(d.real) || runtime·isNaN(d.imag));
if(nnan || dnan) {
- q.real = NaN();
- q.imag = NaN();
+ q.real = runtime·NaN();
+ q.imag = runtime·NaN();
} else if(ninf && !dinf && !dnan) {
- q.real = Inf(0);
- q.imag = Inf(0);
+ q.real = runtime·Inf(0);
+ q.imag = runtime·Inf(0);
} else if(!ninf && !nnan && dinf) {
q.real = 0;
q.imag = 0;
} else if(d.real == 0 && d.imag == 0) {
if(n.real == 0 && n.imag == 0) {
- q.real = NaN();
- q.imag = NaN();
+ q.real = runtime·NaN();
+ q.imag = runtime·NaN();
} else {
- q.real = Inf(0);
- q.imag = Inf(0);
+ q.real = runtime·Inf(0);
+ q.imag = runtime·Inf(0);
}
} else {
// Standard complex arithmetic, factored to avoid unnecessary overflow.
diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h
index 371f650a8..f9d874d85 100644
--- a/src/pkg/runtime/darwin/386/defs.h
+++ b/src/pkg/runtime/darwin/386/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
MACH_MSG_TYPE_MOVE_SEND = 0x11,
MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/darwin/386/rt0.s
index 5b52e912c..30b497f5e 100644
--- a/src/pkg/runtime/darwin/386/rt0.s
+++ b/src/pkg/runtime/darwin/386/rt0.s
@@ -4,5 +4,5 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_darwin(SB),7,$0
+TEXT _rt0_386_darwin(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c
index f7ee3c448..53a4e2f17 100644
--- a/src/pkg/runtime/darwin/386/signal.c
+++ b/src/pkg/runtime/darwin/386/signal.c
@@ -8,39 +8,38 @@
#include "signals.h"
void
-dumpregs(Regs *r)
+runtime·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);
+ runtime·printf("eax %x\n", r->eax);
+ runtime·printf("ebx %x\n", r->ebx);
+ runtime·printf("ecx %x\n", r->ecx);
+ runtime·printf("edx %x\n", r->edx);
+ runtime·printf("edi %x\n", r->edi);
+ runtime·printf("esi %x\n", r->esi);
+ runtime·printf("ebp %x\n", r->ebp);
+ runtime·printf("esp %x\n", r->esp);
+ runtime·printf("eip %x\n", r->eip);
+ runtime·printf("eflags %x\n", r->eflags);
+ runtime·printf("cs %x\n", r->cs);
+ runtime·printf("fs %x\n", r->fs);
+ runtime·printf("gs %x\n", r->gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Mcontext *mc;
Regs *r;
uintptr *sp;
- void (*fn)(void);
G *gp;
byte *pc;
@@ -48,7 +47,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
mc = uc->uc_mcontext;
r = &mc->ss;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
@@ -68,91 +67,91 @@ sighandler(int32 sig, Siginfo *info, void *context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->eip != 0.
+ // Only push runtime·sigpanic if r->eip != 0.
// If r->eip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->eip != 0) {
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->esp = (uintptr)sp;
}
- r->eip = (uintptr)sigpanic;
+ r->eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG){
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
}else{
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- printf("pc: %x\n", r->eip);
- printf("\n");
+ runtime·printf("pc: %x\n", r->eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(int32, Siginfo*, void*)
+runtime·sigignore(int32, Siginfo*, void*)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
StackT st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
int32 i;
static Sigaction sa;
- siginit();
+ runtime·siginit();
sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
sa.sa_mask = 0xFFFFFFFFU;
- sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue)) {
- sa.__sigaction_u.__sa_sigaction = sighandler;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) {
+ sa.__sigaction_u.__sa_sigaction = runtime·sighandler;
} else {
- sa.__sigaction_u.__sa_sigaction = sigignore;
+ sa.__sigaction_u.__sa_sigaction = runtime·sigignore;
}
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
index 4e0a0b3fd..79bbfb68b 100644
--- a/src/pkg/runtime/darwin/386/sys.s
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -8,42 +8,45 @@
#include "386/asm.h"
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$0
+TEXT runtime·exit(SB),7,$0
MOVL $1, AX
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
-TEXT exit1(SB),7,$0
+TEXT runtime·exit1(SB),7,$0
MOVL $361, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVL $4, AX
INT $0x80
- JAE 2(PC)
- CALL notok(SB)
RET
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVL $197, AX
INT $0x80
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVL $73, AX
+ INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// void gettime(int64 *sec, int32 *usec)
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
LEAL 12(SP), AX // must be non-nil, unused
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
@@ -58,11 +61,11 @@ TEXT gettime(SB), 7, $32
MOVL DX, (DI)
RET
-TEXT sigaction(SB),7,$0
+TEXT runtime·sigaction(SB),7,$0
MOVL $46, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Sigtramp's job is to call the actual signal handler.
@@ -73,7 +76,7 @@ TEXT sigaction(SB),7,$0
// 12(FP) signal number
// 16(FP) siginfo
// 20(FP) context
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
// save g
@@ -109,19 +112,19 @@ TEXT sigtramp(SB),7,$40
MOVL BX, 8(SP)
MOVL $184, AX // sigreturn(ucontext, infostyle)
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·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
+TEXT runtime·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
@@ -150,7 +153,7 @@ TEXT bsdthread_create(SB),7,$32
// DI = stack top
// SI = flags (= 0x1000000)
// SP = stack - C_32_STK_ALIGN
-TEXT bsdthread_start(SB),7,$0
+TEXT runtime·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].
@@ -162,7 +165,7 @@ TEXT bsdthread_start(SB),7,$0
PUSHL $32 // sizeof tls
PUSHL BP // &tls
PUSHL DI // tls #
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -173,18 +176,18 @@ TEXT bsdthread_start(SB),7,$0
MOVL AX, g(BP)
MOVL DX, m(BP)
MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
- CALL stackcheck(SB) // smashes AX
+ CALL runtime·stackcheck(SB) // smashes AX
CALL CX // fn()
- CALL exit1(SB)
+ CALL runtime·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
+TEXT runtime·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 $runtime·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) // dummy_value [sic]
@@ -192,7 +195,7 @@ TEXT bsdthread_register(SB),7,$40
MOVL $0, 24(SP) // dispatchqueue_offset
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Invoke Mach system call.
@@ -206,57 +209,57 @@ TEXT bsdthread_register(SB),7,$40
// 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
+TEXT runtime·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
+TEXT runtime·mach_msg_trap(SB),7,$0
MOVL $-31, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
-TEXT mach_reply_port(SB),7,$0
+TEXT runtime·mach_reply_port(SB),7,$0
MOVL $-26, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
-TEXT mach_task_self(SB),7,$0
+TEXT runtime·mach_task_self(SB),7,$0
MOVL $-28, AX
- CALL sysenter(SB)
+ CALL runtime·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
+TEXT runtime·mach_semaphore_wait(SB),7,$0
MOVL $-36, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
-TEXT mach_semaphore_timedwait(SB),7,$0
+TEXT runtime·mach_semaphore_timedwait(SB),7,$0
MOVL $-38, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_signal(uint32)
-TEXT mach_semaphore_signal(SB),7,$0
+TEXT runtime·mach_semaphore_signal(SB),7,$0
MOVL $-33, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_signal_all(uint32)
-TEXT mach_semaphore_signal_all(SB),7,$0
+TEXT runtime·mach_semaphore_signal_all(SB),7,$0
MOVL $-34, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// setldt(int entry, int address, int limit)
// entry and limit are ignored.
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
/*
diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h
index 0b5fde85c..09e595988 100644
--- a/src/pkg/runtime/darwin/amd64/defs.h
+++ b/src/pkg/runtime/darwin/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
MACH_MSG_TYPE_MOVE_SEND = 0x11,
MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/darwin/amd64/rt0.s
index 1b706365a..4cfab5876 100644
--- a/src/pkg/runtime/darwin/amd64/rt0.s
+++ b/src/pkg/runtime/darwin/amd64/rt0.s
@@ -4,7 +4,7 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_darwin(SB),7,$-8
+TEXT _rt0_amd64_darwin(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c
index 648ef207c..474a1bd5c 100644
--- a/src/pkg/runtime/darwin/amd64/signal.c
+++ b/src/pkg/runtime/darwin/amd64/signal.c
@@ -8,41 +8,41 @@
#include "signals.h"
void
-dumpregs(Regs *r)
+runtime·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);
+ runtime·printf("rax %X\n", r->rax);
+ runtime·printf("rbx %X\n", r->rbx);
+ runtime·printf("rcx %X\n", r->rcx);
+ runtime·printf("rdx %X\n", r->rdx);
+ runtime·printf("rdi %X\n", r->rdi);
+ runtime·printf("rsi %X\n", r->rsi);
+ runtime·printf("rbp %X\n", r->rbp);
+ runtime·printf("rsp %X\n", r->rsp);
+ runtime·printf("r8 %X\n", r->r8 );
+ runtime·printf("r9 %X\n", r->r9 );
+ runtime·printf("r10 %X\n", r->r10);
+ runtime·printf("r11 %X\n", r->r11);
+ runtime·printf("r12 %X\n", r->r12);
+ runtime·printf("r13 %X\n", r->r13);
+ runtime·printf("r14 %X\n", r->r14);
+ runtime·printf("r15 %X\n", r->r15);
+ runtime·printf("rip %X\n", r->rip);
+ runtime·printf("rflags %X\n", r->rflags);
+ runtime·printf("cs %X\n", r->cs);
+ runtime·printf("fs %X\n", r->fs);
+ runtime·printf("gs %X\n", r->gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Mcontext *mc;
@@ -55,7 +55,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
mc = uc->uc_mcontext;
r = &mc->ss;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
@@ -77,91 +77,91 @@ sighandler(int32 sig, Siginfo *info, void *context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->rip != 0.
+ // Only push runtime·sigpanic if r->rip != 0.
// If r->rip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->rip != 0) {
sp = (uintptr*)r->rsp;
*--sp = r->rip;
r->rsp = (uintptr)sp;
}
- r->rip = (uintptr)sigpanic;
+ r->rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG){
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
}else{
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- printf("pc: %X\n", r->rip);
- printf("\n");
+ runtime·printf("pc: %X\n", r->rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15);
- tracebackothers((void*)r->r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(int32, Siginfo*, void*)
+runtime·sigignore(int32, Siginfo*, void*)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
StackT st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
int32 i;
static Sigaction sa;
- siginit();
+ runtime·siginit();
sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
sa.sa_mask = 0xFFFFFFFFU;
- sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue)) {
- sa.__sigaction_u.__sa_sigaction = sighandler;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) {
+ sa.__sigaction_u.__sa_sigaction = runtime·sighandler;
} else {
- sa.__sigaction_u.__sa_sigaction = sigignore;
+ sa.__sigaction_u.__sa_sigaction = runtime·sigignore;
}
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s
index 1654fa2b0..05dbc7b93 100644
--- a/src/pkg/runtime/darwin/amd64/sys.s
+++ b/src/pkg/runtime/darwin/amd64/sys.s
@@ -7,38 +7,39 @@
// 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.
//
+// The low 24 bits are the system call number.
+// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
+//
#include "amd64/asm.h"
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$0
+TEXT runtime·exit(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
-TEXT exit1(SB),7,$0
+TEXT runtime·exit1(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVL 8(SP), DI // arg 1 fd
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
// void gettime(int64 *sec, int32 *usec)
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVQ SP, DI // must be non-nil, unused
MOVQ $0, SI
MOVQ $(0x2000000+116), AX
@@ -49,7 +50,7 @@ TEXT gettime(SB), 7, $32
MOVL DX, (DI)
RET
-TEXT sigaction(SB),7,$0
+TEXT runtime·sigaction(SB),7,$0
MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act
MOVQ 24(SP), DX // arg 3 oact
@@ -58,24 +59,40 @@ TEXT sigaction(SB),7,$0
MOVL $(0x2000000+46), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$40
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), BP
+ MOVQ BP, 40(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
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
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), BP
+ MOVQ BP, g(BX)
+
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 ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVQ 8(SP), DI // arg 1 addr
MOVQ 16(SP), SI // arg 2 len
MOVL 24(SP), DX // arg 3 prot
@@ -84,26 +101,33 @@ TEXT ·mmap(SB),7,$0
MOVL 36(SP), R9 // arg 6 offset
MOVL $(0x2000000+197), AX // syscall entry
SYSCALL
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL $(0x2000000+73), AX // syscall entry
+ SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVQ new+8(SP), DI
MOVQ old+16(SP), SI
MOVQ $(0x2000000+53), AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
-TEXT bsdthread_create(SB),7,$0
+TEXT runtime·bsdthread_create(SB),7,$0
// 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.
@@ -132,21 +156,36 @@ TEXT bsdthread_create(SB),7,$0
// R8 = stack
// R9 = flags (= 0)
// SP = stack - C_64_REDZONE_LEN (= stack - 128)
-TEXT bsdthread_start(SB),7,$0
+TEXT runtime·bsdthread_start(SB),7,$0
MOVQ R8, SP // empirically, SP is very wrong but R8 is right
- MOVQ CX, m
- MOVQ m_g0(m), g
- CALL stackcheck(SB)
- MOVQ SI, m_procid(m) // thread port is m->procid
+
+ PUSHQ DX
+ PUSHQ CX
+ PUSHQ SI
+
+ // set up thread local storage pointing at m->tls.
+ LEAQ m_tls(CX), DI
+ CALL runtime·settls(SB)
+
+ POPQ SI
+ POPQ CX
+ POPQ DX
+
+ get_tls(BX)
+ MOVQ CX, m(BX)
+ MOVQ SI, m_procid(CX) // thread port is m->procid
+ MOVQ m_g0(CX), AX
+ MOVQ AX, g(BX)
+ CALL runtime·stackcheck(SB) // smashes AX, CX
CALL DX // fn
- CALL exit1(SB)
+ CALL runtime·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,$0
- MOVQ $bsdthread_start(SB), DI // threadstart
+TEXT runtime·bsdthread_register(SB),7,$0
+ MOVQ $runtime·bsdthread_start(SB), DI // threadstart
MOVQ $0, SI // wqthread, not used by us
MOVQ $0, DX // pthsize, not used by us
MOVQ $0, R10 // dummy_value [sic]
@@ -155,13 +194,13 @@ TEXT bsdthread_register(SB),7,$0
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·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
+TEXT runtime·mach_msg_trap(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -175,17 +214,17 @@ TEXT mach_msg_trap(SB),7,$0
POPQ R11
RET
-TEXT mach_task_self(SB),7,$0
+TEXT runtime·mach_task_self(SB),7,$0
MOVL $(0x1000000+28), AX // task_self_trap
SYSCALL
RET
-TEXT mach_thread_self(SB),7,$0
+TEXT runtime·mach_thread_self(SB),7,$0
MOVL $(0x1000000+27), AX // thread_self_trap
SYSCALL
RET
-TEXT mach_reply_port(SB),7,$0
+TEXT runtime·mach_reply_port(SB),7,$0
MOVL $(0x1000000+26), AX // mach_reply_port
SYSCALL
RET
@@ -194,14 +233,14 @@ TEXT mach_reply_port(SB),7,$0
// instead of requiring the use of RPC.
// uint32 mach_semaphore_wait(uint32)
-TEXT mach_semaphore_wait(SB),7,$0
+TEXT runtime·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
+TEXT runtime·mach_semaphore_timedwait(SB),7,$0
MOVL 8(SP), DI
MOVL 12(SP), SI
MOVL 16(SP), DX
@@ -210,15 +249,28 @@ TEXT mach_semaphore_timedwait(SB),7,$0
RET
// uint32 mach_semaphore_signal(uint32)
-TEXT mach_semaphore_signal(SB),7,$0
+TEXT runtime·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
+TEXT runtime·mach_semaphore_signal_all(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
SYSCALL
RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$32
+ /*
+ * Same as in ../386/sys.s:/ugliness, different constant.
+ * See ../../../../libcgo/darwin_amd64.c for the derivation
+ * of the constant.
+ */
+ SUBQ $0x8a0, DI
+
+ MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3
+ SYSCALL
+ RET
diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c
index 8735e7857..1a1cdf880 100644
--- a/src/pkg/runtime/darwin/defs.c
+++ b/src/pkg/runtime/darwin/defs.c
@@ -26,6 +26,7 @@ enum {
$MAP_ANON = MAP_ANON,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE,
$MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND,
diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c
index 52e351a7d..7fb2c2807 100644
--- a/src/pkg/runtime/darwin/mem.c
+++ b/src/pkg/runtime/darwin/mem.c
@@ -4,14 +4,21 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
+ void *v;
+
mstats.sys += n;
- return runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ runtime·printf("mmap: errno=%p\n", v);
+ runtime·throw("mmap");
+ }
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -19,10 +26,14 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/darwin/os.h
index 51a164c33..35ef4e6d9 100644
--- a/src/pkg/runtime/darwin/os.h
+++ b/src/pkg/runtime/darwin/os.h
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-int32 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);
+int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void));
+void runtime·bsdthread_register(void);
+int32 runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
+uint32 runtime·mach_reply_port(void);
+void runtime·mach_semacquire(uint32);
+uint32 runtime·mach_semcreate(void);
+void runtime·mach_semdestroy(uint32);
+void runtime·mach_semrelease(uint32);
+void runtime·mach_semreset(uint32);
+uint32 runtime·mach_task_self(void);
+uint32 runtime·mach_task_self(void);
+uint32 runtime·mach_thread_self(void);
+uint32 runtime·mach_thread_self(void);
struct Sigaction;
-void sigaction(uintptr, struct Sigaction*, struct Sigaction*);
+void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
struct StackT;
-void sigaltstack(struct StackT*, struct StackT*);
-void sigtramp(void);
-void sigpanic(void);
+void runtime·sigaltstack(struct StackT*, struct StackT*);
+void runtime·sigtramp(void);
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/darwin/runtime_defs.go b/src/pkg/runtime/darwin/runtime_defs.go
new file mode 100644
index 000000000..cf0b414a9
--- /dev/null
+++ b/src/pkg/runtime/darwin/runtime_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type usema struct {
+ u uint32
+ k uint32
+}
+
+
+type note struct {
+ wakeup int32
+ sema usema
+}
diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h
index ac9e5d606..035027fad 100644
--- a/src/pkg/runtime/darwin/signals.h
+++ b/src/pkg/runtime/darwin/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c
index e51d53019..d69c62412 100644
--- a/src/pkg/runtime/darwin/thread.c
+++ b/src/pkg/runtime/darwin/thread.c
@@ -6,13 +6,13 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
+extern SigTab runtime·sigtab[];
static void
unimplemented(int8 *name)
{
- prints(name);
- prints(" not implemented\n");
+ runtime·prints(name);
+ runtime·prints(" not implemented\n");
*(int32*)1231 = 1231;
}
@@ -29,10 +29,10 @@ initsema(uint32 *psema)
if(*psema != 0) // already have one
return;
- sema = mach_semcreate();
- if(!cas(psema, 0, sema)){
+ sema = runtime·mach_semcreate();
+ if(!runtime·cas(psema, 0, sema)){
// Someone else filled it in. Use theirs.
- mach_semdestroy(sema);
+ runtime·mach_semdestroy(sema);
return;
}
}
@@ -52,40 +52,40 @@ initsema(uint32 *psema)
// in Plan 9's user-level locks.
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
- if(xadd(&l->key, 1) > 1) { // someone else has it; wait
+ if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait
// Allocate semaphore if needed.
if(l->sema == 0)
initsema(&l->sema);
- mach_semacquire(l->sema);
+ runtime·mach_semacquire(l->sema);
}
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
- if(xadd(&l->key, -1) > 0) { // someone else is waiting
+ if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting
// Allocate semaphore if needed.
if(l->sema == 0)
initsema(&l->sema);
- mach_semrelease(l->sema);
+ runtime·mach_semrelease(l->sema);
}
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock *l)
{
if(l->sema != 0) {
- mach_semdestroy(l->sema);
+ runtime·mach_semdestroy(l->sema);
l->sema = 0;
}
}
@@ -95,79 +95,84 @@ destroylock(Lock *l)
// 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)
+runtime·usemacquire(Usema *s)
{
- if((int32)xadd(&s->u, -1) < 0) {
+ if((int32)runtime·xadd(&s->u, -1) < 0) {
if(s->k == 0)
initsema(&s->k);
- mach_semacquire(s->k);
+ runtime·mach_semacquire(s->k);
}
}
void
-usemrelease(Usema *s)
+runtime·usemrelease(Usema *s)
{
- if((int32)xadd(&s->u, 1) <= 0) {
+ if((int32)runtime·xadd(&s->u, 1) <= 0) {
if(s->k == 0)
initsema(&s->k);
- mach_semrelease(s->k);
+ runtime·mach_semrelease(s->k);
}
}
// Event notifications.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->wakeup = 0;
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
while(!n->wakeup)
- usemacquire(&n->sema);
+ runtime·usemacquire(&n->sema);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
n->wakeup = 1;
- usemrelease(&n->sema);
+ runtime·usemrelease(&n->sema);
}
// BSD interface for threading.
void
-osinit(void)
+runtime·osinit(void)
{
// Register our thread-creation callback (see {amd64,386}/sys.s)
// but only if we're not using cgo. If we are using cgo we need
// to let the C pthread libary install its own thread-creation callback.
- extern void (*libcgo_thread_start)(void*);
- if(libcgo_thread_start == nil)
- bsdthread_register();
+ if(!runtime·iscgo)
+ runtime·bsdthread_register();
}
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
m->tls[0] = m->id; // so 386 asm can find it
if(0){
- printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, m, g, fn, m->id, m->tls[0], &m);
}
- if(bsdthread_create(stk, m, g, fn) < 0)
- throw("cannot create new OS thread");
+ if(runtime·bsdthread_create(stk, m, g, fn) < 0)
+ runtime·throw("cannot create new OS thread");
}
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling.
- m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
// Mach IPC, to get at semaphores
@@ -176,8 +181,8 @@ minit(void)
static void
macherror(int32 r, int8 *fn)
{
- printf("mach error %s: %d\n", fn, r);
- throw("mach error");
+ runtime·printf("mach error %s: %d\n", fn, r);
+ runtime·throw("mach error");
}
enum
@@ -199,7 +204,7 @@ mach_msg(MachHeader *h,
uint32 notify)
{
// TODO: Loop on interrupt.
- return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+ return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
}
// Mach RPC (MIG)
@@ -229,7 +234,7 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
CodeMsg *c;
if((port = m->machport) == 0){
- port = mach_reply_port();
+ port = runtime·mach_reply_port();
m->machport = port;
}
@@ -240,48 +245,48 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
if(DebugMach){
p = (uint32*)h;
- prints("send:\t");
+ runtime·prints("send:\t");
for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- prints(" ");
- ·printpointer((void*)p[i]);
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
if(i%8 == 7)
- prints("\n\t");
+ runtime·prints("\n\t");
}
if(i%8)
- prints("\n");
+ runtime·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 ");
- ·printint(ret);
- prints("\n");
+ runtime·prints("mach_msg error ");
+ runtime·printint(ret);
+ runtime·prints("\n");
}
return ret;
}
if(DebugMach){
p = (uint32*)h;
- prints("recv:\t");
+ runtime·prints("recv:\t");
for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- prints(" ");
- ·printpointer((void*)p[i]);
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
if(i%8 == 7)
- prints("\n\t");
+ runtime·prints("\n\t");
}
if(i%8)
- prints("\n");
+ runtime·prints("\n");
}
if(h->msgh_id != id+Reply){
if(DebugMach){
- prints("mach_msg reply id mismatch ");
- ·printint(h->msgh_id);
- prints(" != ");
- ·printint(id+Reply);
- prints("\n");
+ runtime·prints("mach_msg reply id mismatch ");
+ runtime·printint(h->msgh_id);
+ runtime·prints(" != ");
+ runtime·printint(id+Reply);
+ runtime·prints("\n");
}
return -303; // MIG_REPLY_MISMATCH
}
@@ -296,20 +301,20 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
if(h->msgh_size == sizeof(CodeMsg)
&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
if(DebugMach){
- prints("mig result ");
- ·printint(c->code);
- prints("\n");
+ runtime·prints("mig result ");
+ runtime·printint(c->code);
+ runtime·prints("\n");
}
return c->code;
}
if(h->msgh_size != rxsize){
if(DebugMach){
- prints("mach_msg reply size mismatch ");
- ·printint(h->msgh_size);
- prints(" != ");
- ·printint(rxsize);
- prints("\n");
+ runtime·prints("mach_msg reply size mismatch ");
+ runtime·printint(h->msgh_size);
+ runtime·prints(" != ");
+ runtime·printint(rxsize);
+ runtime·prints("\n");
}
return -307; // MIG_ARRAY_TOO_LARGE
}
@@ -363,7 +368,7 @@ struct Tmach_semdestroyMsg
#pragma pack off
uint32
-mach_semcreate(void)
+runtime·mach_semcreate(void)
{
union {
Tmach_semcreateMsg tx;
@@ -374,7 +379,7 @@ mach_semcreate(void)
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_remote_port = runtime·mach_task_self();
m.tx.h.msgh_id = Tmach_semcreate;
m.tx.ndr = zerondr;
@@ -392,7 +397,7 @@ mach_semcreate(void)
}
void
-mach_semdestroy(uint32 sem)
+runtime·mach_semdestroy(uint32 sem)
{
union {
Tmach_semdestroyMsg tx;
@@ -402,7 +407,7 @@ mach_semdestroy(uint32 sem)
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_remote_port = runtime·mach_task_self();
m.tx.h.msgh_id = Tmach_semdestroy;
m.tx.body.msgh_descriptor_count = 1;
m.tx.semaphore.name = sem;
@@ -417,17 +422,17 @@ mach_semdestroy(uint32 sem)
}
// 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);
+int32 runtime·mach_semaphore_wait(uint32 sema);
+int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
+int32 runtime·mach_semaphore_signal(uint32 sema);
+int32 runtime·mach_semaphore_signal_all(uint32 sema);
void
-mach_semacquire(uint32 sem)
+runtime·mach_semacquire(uint32 sem)
{
int32 r;
- while((r = mach_semaphore_wait(sem)) != 0) {
+ while((r = runtime·mach_semaphore_wait(sem)) != 0) {
if(r == KERN_ABORTED) // interrupted
continue;
macherror(r, "semaphore_wait");
@@ -435,11 +440,11 @@ mach_semacquire(uint32 sem)
}
void
-mach_semrelease(uint32 sem)
+runtime·mach_semrelease(uint32 sem)
{
int32 r;
- while((r = mach_semaphore_signal(sem)) != 0) {
+ while((r = runtime·mach_semaphore_signal(sem)) != 0) {
if(r == KERN_ABORTED) // interrupted
continue;
macherror(r, "semaphore_signal");
@@ -447,25 +452,27 @@ mach_semrelease(uint32 sem)
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go
index b65cc6693..3ce35cc5b 100644
--- a/src/pkg/runtime/debug.go
+++ b/src/pkg/runtime/debug.go
@@ -4,6 +4,8 @@
package runtime
+import "unsafe"
+
// Breakpoint() executes a breakpoint trap.
func Breakpoint()
@@ -26,6 +28,9 @@ func GOMAXPROCS(n int) int
// Cgocalls returns the number of cgo calls made by the current process.
func Cgocalls() int64
+// Goroutines returns the number of goroutines that currently exist.
+func Goroutines() int32
+
type MemStatsType struct {
// General statistics.
// Not locked during update; approximate.
@@ -36,10 +41,11 @@ type MemStatsType struct {
Mallocs uint64 // number of mallocs
// Main allocation heap statistics.
- HeapAlloc uint64 // bytes allocated and still in use
- HeapSys uint64 // bytes obtained from system
- HeapIdle uint64 // bytes in idle spans
- HeapInuse uint64 // bytes in non-idle span
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapObjects uint64 // total number of allocated objects
// Low-level fixed-size structure allocator statistics.
// Inuse is bytes used now.
@@ -69,6 +75,15 @@ type MemStatsType struct {
}
}
+var sizeof_C_MStats int // filled in by malloc.goc
+
+func init() {
+ if sizeof_C_MStats != unsafe.Sizeof(MemStats) {
+ println(sizeof_C_MStats, unsafe.Sizeof(MemStats))
+ panic("MStats vs MemStatsType size mismatch")
+ }
+}
+
// MemStats holds statistics about the memory system.
// The statistics are only approximate, as they are not interlocked on update.
var MemStats MemStatsType
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index 673e77b2c..289d78f49 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -111,6 +111,8 @@ type stringer interface {
String() string
}
+func typestring(interface{}) string
+
// For calling from C.
// Prints an argument passed to panic.
// There's room for arbitrary complexity here, but we keep it
@@ -126,6 +128,6 @@ func printany(i interface{}) {
case string:
print(v)
default:
- print(i)
+ print("(", typestring(i), ") ", i)
}
}
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
new file mode 100644
index 000000000..58631c7b4
--- /dev/null
+++ b/src/pkg/runtime/export_test.go
@@ -0,0 +1,17 @@
+// Copyright 2010 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.
+
+// Export guts for testing.
+
+package runtime
+
+var Fadd64 = fadd64
+var Fsub64 = fsub64
+var Fmul64 = fmul64
+var Fdiv64 = fdiv64
+var F64to32 = f64to32
+var F32to64 = f32to64
+var Fcmp64 = fcmp64
+var Fintto64 = fintto64
+var F64toint = f64toint
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index d3d1dabdf..77c3e8e3a 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -35,24 +35,6 @@ func Callers(skip int, pc []uintptr) int
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func
-// NOTE(rsc): Func must match struct Func in runtime.h
-
-// Func records information about a function in the program,
-// in particular the mapping from program counters to source
-// line numbers within that function.
-type Func struct {
- name string
- typ string
- src string
- pcln []byte
- entry uintptr
- pc0 uintptr
- ln0 int32
- frame int32
- args int32
- locals int32
-}
-
// Name returns the name of the function.
func (f *Func) Name() string { return f.name }
@@ -66,13 +48,17 @@ func (f *Func) Entry() uintptr { return f.entry }
func (f *Func) FileLine(pc uintptr) (file string, line int) {
// NOTE(rsc): If you edit this function, also edit
// symtab.c:/^funcline.
- const PcQuant = 1
+ var pcQuant uintptr = 1
+ if GOARCH == "arm" {
+ pcQuant = 4
+ }
+ targetpc := pc
p := f.pcln
- pc1 := f.pc0
+ pc = f.pc0
line = int(f.ln0)
file = f.src
- for i := 0; i < len(p) && pc1 <= pc; i++ {
+ for i := 0; i < len(p) && pc <= targetpc; i++ {
switch {
case p[i] == 0:
line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
@@ -80,11 +66,11 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) {
case p[i] <= 64:
line += int(p[i])
case p[i] <= 128:
- line += int(p[i] - 64)
+ line -= int(p[i] - 64)
default:
- line += PcQuant * int(p[i]-129)
+ pc += pcQuant * uintptr(p[i]-129)
}
- pc += PcQuant
+ pc += pcQuant
}
return
}
@@ -105,13 +91,13 @@ func Semrelease(s *uint32)
// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
-// with an associated finalizer, it clears the association and creates
-// a new goroutine running f(x). Creating the new goroutine makes
-// x reachable again, but now without an associated finalizer.
-// Assuming that SetFinalizer is not called again, the next time
-// the garbage collector sees that x is unreachable, it will free x.
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine. This makes x reachable again, but
+// now without an associated finalizer. Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
//
-// SetFinalizer(x, nil) clears any finalizer associated with f.
+// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
@@ -142,7 +128,6 @@ func Semrelease(s *uint32)
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
//
-// TODO(rsc): make os.File use SetFinalizer
// TODO(rsc): allow f to have (ignored) return values
//
func SetFinalizer(x, f interface{})
@@ -165,4 +150,14 @@ func GOROOT() string {
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
-func Version() string { return defaultVersion }
+func Version() string {
+ return theVersion
+}
+
+// GOOS is the Go tree's operating system target:
+// one of darwin, freebsd, linux, and so on.
+const GOOS string = theGoos
+
+// GOARCH is the Go tree's architecture target:
+// 386, amd64, or arm.
+const GOARCH string = theGoarch
diff --git a/src/pkg/runtime/float.c b/src/pkg/runtime/float.c
index 5122f359a..f481519f6 100644
--- a/src/pkg/runtime/float.c
+++ b/src/pkg/runtime/float.c
@@ -9,7 +9,7 @@ static uint64 uvinf = 0x7FF0000000000000ULL;
static uint64 uvneginf = 0xFFF0000000000000ULL;
uint32
-float32tobits(float32 f)
+runtime·float32tobits(float32 f)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -22,7 +22,7 @@ float32tobits(float32 f)
}
uint64
-float64tobits(float64 f)
+runtime·float64tobits(float64 f)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -35,7 +35,7 @@ float64tobits(float64 f)
}
float64
-float64frombits(uint64 i)
+runtime·float64frombits(uint64 i)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -48,7 +48,7 @@ float64frombits(uint64 i)
}
float32
-float32frombits(uint32 i)
+runtime·float32frombits(uint32 i)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -61,11 +61,11 @@ float32frombits(uint32 i)
}
bool
-isInf(float64 f, int32 sign)
+runtime·isInf(float64 f, int32 sign)
{
uint64 x;
- x = float64tobits(f);
+ x = runtime·float64tobits(f);
if(sign == 0)
return x == uvinf || x == uvneginf;
if(sign > 0)
@@ -74,27 +74,27 @@ isInf(float64 f, int32 sign)
}
float64
-NaN(void)
+runtime·NaN(void)
{
- return float64frombits(uvnan);
+ return runtime·float64frombits(uvnan);
}
bool
-isNaN(float64 f)
+runtime·isNaN(float64 f)
{
uint64 x;
- x = float64tobits(f);
- return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0);
+ x = runtime·float64tobits(f);
+ return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !runtime·isInf(f, 0);
}
float64
-Inf(int32 sign)
+runtime·Inf(int32 sign)
{
if(sign >= 0)
- return float64frombits(uvinf);
+ return runtime·float64frombits(uvinf);
else
- return float64frombits(uvneginf);
+ return runtime·float64frombits(uvneginf);
}
enum
@@ -105,7 +105,7 @@ enum
};
float64
-frexp(float64 d, int32 *ep)
+runtime·frexp(float64 d, int32 *ep)
{
uint64 x;
@@ -113,36 +113,36 @@ frexp(float64 d, int32 *ep)
*ep = 0;
return 0;
}
- x = float64tobits(d);
+ x = runtime·float64tobits(d);
*ep = (int32)((x >> SHIFT) & MASK) - BIAS;
x &= ~((uint64)MASK << SHIFT);
x |= (uint64)BIAS << SHIFT;
- return float64frombits(x);
+ return runtime·float64frombits(x);
}
float64
-ldexp(float64 d, int32 e)
+runtime·ldexp(float64 d, int32 e)
{
uint64 x;
if(d == 0)
return 0;
- x = float64tobits(d);
+ x = runtime·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);
+ return runtime·Inf(-1);
+ return runtime·Inf(1);
}
x &= ~((uint64)MASK << SHIFT);
x |= (uint64)e << SHIFT;
- return float64frombits(x);
+ return runtime·float64frombits(x);
}
float64
-modf(float64 d, float64 *ip)
+runtime·modf(float64 d, float64 *ip)
{
float64 dd;
uint64 x;
@@ -150,7 +150,7 @@ modf(float64 d, float64 *ip)
if(d < 1) {
if(d < 0) {
- d = modf(-d, ip);
+ d = runtime·modf(-d, ip);
*ip = -*ip;
return -d;
}
@@ -158,7 +158,7 @@ modf(float64 d, float64 *ip)
return d;
}
- x = float64tobits(d);
+ x = runtime·float64tobits(d);
e = (int32)((x >> SHIFT) & MASK) - BIAS;
/*
@@ -166,7 +166,7 @@ modf(float64 d, float64 *ip)
*/
if(e <= 64-11)
x &= ~(((uint64)1 << (64LL-11LL-e))-1);
- dd = float64frombits(x);
+ dd = runtime·float64frombits(x);
*ip = dd;
return d - dd;
}
diff --git a/src/pkg/runtime/freebsd/386/defs.h b/src/pkg/runtime/freebsd/386/defs.h
index 76c55721f..128be9cc9 100644
--- a/src/pkg/runtime/freebsd/386/defs.h
+++ b/src/pkg/runtime/freebsd/386/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/freebsd/386/rt0.s
index 67c5f912c..3ca981b3a 100644
--- a/src/pkg/runtime/freebsd/386/rt0.s
+++ b/src/pkg/runtime/freebsd/386/rt0.s
@@ -4,6 +4,6 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_freebsd(SB),7,$0
+TEXT _rt0_386_freebsd(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c
index 4fc6d9e12..52b820df1 100644
--- a/src/pkg/runtime/freebsd/386/signal.c
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -7,7 +7,7 @@
#include "signals.h"
#include "os.h"
-extern void sigtramp(void);
+extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
@@ -19,33 +19,33 @@ typedef struct sigaction {
} Sigaction;
void
-dumpregs(Mcontext *r)
+runtime·dumpregs(Mcontext *r)
{
- printf("eax %x\n", r->mc_eax);
- printf("ebx %x\n", r->mc_ebx);
- printf("ecx %x\n", r->mc_ecx);
- printf("edx %x\n", r->mc_edx);
- printf("edi %x\n", r->mc_edi);
- printf("esi %x\n", r->mc_esi);
- printf("ebp %x\n", r->mc_ebp);
- printf("esp %x\n", r->mc_esp);
- printf("eip %x\n", r->mc_eip);
- printf("eflags %x\n", r->mc_eflags);
- printf("cs %x\n", r->mc_cs);
- printf("fs %x\n", r->mc_fs);
- printf("gs %x\n", r->mc_gs);
+ runtime·printf("eax %x\n", r->mc_eax);
+ runtime·printf("ebx %x\n", r->mc_ebx);
+ runtime·printf("ecx %x\n", r->mc_ecx);
+ runtime·printf("edx %x\n", r->mc_edx);
+ runtime·printf("edi %x\n", r->mc_edi);
+ runtime·printf("esi %x\n", r->mc_esi);
+ runtime·printf("ebp %x\n", r->mc_ebp);
+ runtime·printf("esp %x\n", r->mc_esp);
+ runtime·printf("eip %x\n", r->mc_eip);
+ runtime·printf("eflags %x\n", r->mc_eflags);
+ runtime·printf("cs %x\n", r->mc_cs);
+ runtime·printf("fs %x\n", r->mc_fs);
+ runtime·printf("gs %x\n", r->mc_gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *r;
@@ -55,7 +55,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -64,91 +64,91 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->mc_eip != 0.
+ // Only push runtime·sigpanic if r->mc_eip != 0.
// If r->mc_eip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->mc_eip != 0) {
sp = (uintptr*)r->mc_esp;
*--sp = r->mc_eip;
r->mc_esp = (uintptr)sp;
}
- r->mc_eip = (uintptr)sigpanic;
+ r->mc_eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->mc_eip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->mc_eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(void)
+runtime·sigignore(void)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
sa.sa_mask = ~0x0ull;
for(i = 0; i < NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigtramp;
else
- sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigignore;
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
index a0860db81..7110e6924 100644
--- a/src/pkg/runtime/freebsd/386/sys.s
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -8,17 +8,17 @@
#include "386/asm.h"
-TEXT sys_umtx_op(SB),7,$-4
+TEXT runtime·sys_umtx_op(SB),7,$-4
MOVL $454, AX
INT $0x80
RET
-TEXT thr_new(SB),7,$-4
+TEXT runtime·thr_new(SB),7,$-4
MOVL $455, AX
INT $0x80
RET
-TEXT thr_start(SB),7,$0
+TEXT runtime·thr_start(SB),7,$0
MOVL mm+0(FP), AX
MOVL m_g0(AX), BX
LEAL m_tls(AX), BP
@@ -28,7 +28,7 @@ TEXT thr_start(SB),7,$0
PUSHL $32
PUSHL BP
PUSHL DI
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -37,43 +37,57 @@ TEXT thr_start(SB),7,$0
MOVL BX, g(CX)
MOVL AX, m(CX)
- CALL stackcheck(SB) // smashes AX
- CALL mstart(SB)
+ CALL runtime·stackcheck(SB) // smashes AX
+ CALL runtime·mstart(SB)
MOVL 0, AX // crash (not reached)
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$-4
+TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT exit1(SB),7,$-4
+TEXT runtime·exit1(SB),7,$-4
MOVL $431, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$-4
+TEXT runtime·write(SB),7,$-4
MOVL $4, AX
INT $0x80
- JAE 2(PC)
- CALL notok(SB)
RET
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
-TEXT ·mmap(SB),7,$-4
+TEXT runtime·mmap(SB),7,$32
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
MOVL $477, AX
INT $0x80
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX
+ INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
@@ -90,14 +104,14 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT sigaction(SB),7,$-4
+TEXT runtime·sigaction(SB),7,$-4
MOVL $416, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
// g = m->gsignal
get_tls(DX)
MOVL m(DX), BP
@@ -111,7 +125,7 @@ TEXT sigtramp(SB),7,$40
MOVL AX, 0(SP)
MOVL BX, 4(SP)
MOVL CX, 8(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
// g = m->curg
get_tls(DX)
@@ -125,14 +139,14 @@ TEXT sigtramp(SB),7,$40
MOVL AX, 4(SP)
MOVL $417, AX // sigreturn(ucontext)
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
/*
@@ -152,7 +166,7 @@ int i386_set_ldt(int, const union ldt_entry *, int);
*/
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
// see comment in linux/386/sys.s; freebsd is similar
ADDL $0x8, BX
@@ -177,7 +191,7 @@ TEXT setldt(SB),7,$32
MOVL $0xffffffff, 0(SP) // auto-allocate entry and return in AX
MOVL AX, 4(SP)
MOVL $1, 8(SP)
- CALL i386_set_ldt(SB)
+ CALL runtime·i386_set_ldt(SB)
// compute segment selector - (entry*8+7)
SHLL $3, AX
@@ -185,7 +199,7 @@ TEXT setldt(SB),7,$32
MOVW AX, GS
RET
-TEXT i386_set_ldt(SB),7,$16
+TEXT runtime·i386_set_ldt(SB),7,$16
LEAL args+0(FP), AX // 0(FP) == 4(SP) before SP got moved
MOVL $0, 0(SP) // syscall gap
MOVL $1, 4(SP)
@@ -197,4 +211,4 @@ TEXT i386_set_ldt(SB),7,$16
INT $3
RET
-GLOBL tlsoffset(SB),$4
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/freebsd/amd64/defs.h
index 18b68b355..2a295a479 100644
--- a/src/pkg/runtime/freebsd/amd64/defs.h
+++ b/src/pkg/runtime/freebsd/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/freebsd/amd64/rt0.s
index 7903b7ccc..5d2eeeeff 100644
--- a/src/pkg/runtime/freebsd/amd64/rt0.s
+++ b/src/pkg/runtime/freebsd/amd64/rt0.s
@@ -4,6 +4,6 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_freebsd(SB),7,$-8
+TEXT _rt0_amd64_freebsd(SB),7,$-8
MOVQ $_rt0_amd64(SB), DX
JMP DX
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c
index 57bfcfb55..c74ddad0b 100644
--- a/src/pkg/runtime/freebsd/amd64/signal.c
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -7,7 +7,7 @@
#include "signals.h"
#include "os.h"
-extern void sigtramp(void);
+extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
@@ -19,41 +19,41 @@ typedef struct sigaction {
} Sigaction;
void
-dumpregs(Mcontext *r)
+runtime·dumpregs(Mcontext *r)
{
- printf("rax %X\n", r->mc_rax);
- printf("rbx %X\n", r->mc_rbx);
- printf("rcx %X\n", r->mc_rcx);
- printf("rdx %X\n", r->mc_rdx);
- printf("rdi %X\n", r->mc_rdi);
- printf("rsi %X\n", r->mc_rsi);
- printf("rbp %X\n", r->mc_rbp);
- printf("rsp %X\n", r->mc_rsp);
- printf("r8 %X\n", r->mc_r8 );
- printf("r9 %X\n", r->mc_r9 );
- printf("r10 %X\n", r->mc_r10);
- printf("r11 %X\n", r->mc_r11);
- printf("r12 %X\n", r->mc_r12);
- printf("r13 %X\n", r->mc_r13);
- printf("r14 %X\n", r->mc_r14);
- printf("r15 %X\n", r->mc_r15);
- printf("rip %X\n", r->mc_rip);
- printf("rflags %X\n", r->mc_flags);
- printf("cs %X\n", r->mc_cs);
- printf("fs %X\n", r->mc_fs);
- printf("gs %X\n", r->mc_gs);
+ runtime·printf("rax %X\n", r->mc_rax);
+ runtime·printf("rbx %X\n", r->mc_rbx);
+ runtime·printf("rcx %X\n", r->mc_rcx);
+ runtime·printf("rdx %X\n", r->mc_rdx);
+ runtime·printf("rdi %X\n", r->mc_rdi);
+ runtime·printf("rsi %X\n", r->mc_rsi);
+ runtime·printf("rbp %X\n", r->mc_rbp);
+ runtime·printf("rsp %X\n", r->mc_rsp);
+ runtime·printf("r8 %X\n", r->mc_r8 );
+ runtime·printf("r9 %X\n", r->mc_r9 );
+ runtime·printf("r10 %X\n", r->mc_r10);
+ runtime·printf("r11 %X\n", r->mc_r11);
+ runtime·printf("r12 %X\n", r->mc_r12);
+ runtime·printf("r13 %X\n", r->mc_r13);
+ runtime·printf("r14 %X\n", r->mc_r14);
+ runtime·printf("r15 %X\n", r->mc_r15);
+ runtime·printf("rip %X\n", r->mc_rip);
+ runtime·printf("rflags %X\n", r->mc_flags);
+ runtime·printf("cs %X\n", r->mc_cs);
+ runtime·printf("fs %X\n", r->mc_fs);
+ runtime·printf("gs %X\n", r->mc_gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *r;
@@ -63,7 +63,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -72,91 +72,91 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->mc_rip != 0.
+ // Only push runtime·sigpanic if r->mc_rip != 0.
// If r->mc_rip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->mc_rip != 0) {
sp = (uintptr*)r->mc_rsp;
*--sp = r->mc_rip;
r->mc_rsp = (uintptr)sp;
}
- r->mc_rip = (uintptr)sigpanic;
+ r->mc_rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->mc_rip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->mc_rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, (void*)r->mc_r15);
- tracebackothers((void*)r->mc_r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(void)
+runtime·sigignore(void)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
sa.sa_mask = ~0x0ull;
for(i = 0; i < NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigtramp;
else
- sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigignore;
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s
index 604b763ab..b9cf3832d 100644
--- a/src/pkg/runtime/freebsd/amd64/sys.s
+++ b/src/pkg/runtime/freebsd/amd64/sys.s
@@ -8,7 +8,7 @@
#include "amd64/asm.h"
-TEXT sys_umtx_op(SB),7,$0
+TEXT runtime·sys_umtx_op(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -18,47 +18,54 @@ TEXT sys_umtx_op(SB),7,$0
SYSCALL
RET
-TEXT thr_new(SB),7,$0
+TEXT runtime·thr_new(SB),7,$0
MOVQ 8(SP), DI
MOVQ 16(SP), SI
MOVL $455, AX
SYSCALL
RET
-TEXT thr_start(SB),7,$0
- MOVQ DI, m
- MOVQ m_g0(m), g
- CALL stackcheck(SB)
- CALL mstart(SB)
- MOVQ 0, AX // crash (not reached)
+TEXT runtime·thr_start(SB),7,$0
+ MOVQ DI, R13 // m
+
+ // set up FS to point at m->tls
+ LEAQ m_tls(R13), DI
+ CALL runtime·settls(SB) // smashes DI
+ // set up m, g
+ get_tls(CX)
+ MOVQ R13, m(CX)
+ MOVQ m_g0(R13), DI
+ MOVQ DI, g(CX)
+
+ CALL runtime·stackcheck(SB)
+ CALL runtime·mstart(SB)
+ MOVQ 0, AX // crash (not reached)
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$-8
+TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $1, AX
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT exit1(SB),7,$-8
+TEXT runtime·exit1(SB),7,$-8
MOVQ 8(SP), DI // arg 1 exit status
MOVL $431, AX
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$-8
+TEXT runtime·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 fd
MOVQ 16(SP), SI // arg 2 buf
MOVL 24(SP), DX // arg 3 count
MOVL $4, AX
SYSCALL
- JCC 2(PC)
- CALL notok(SB)
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $116, AX
LEAQ 8(SP), DI
MOVQ $0, SI
@@ -73,25 +80,28 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT sigaction(SB),7,$-8
+TEXT runtime·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
MOVL $416, AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$24-16
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$24-16
+ get_tls(CX)
+ MOVQ m(CX), AX
+ MOVQ m_gsignal(AX), AX
+ MOVQ AX, g(CX)
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
RET
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVQ 8(SP), DI // arg 1 addr
MOVQ 16(SP), SI // arg 2 len
MOVL 24(SP), DX // arg 3 prot
@@ -100,20 +110,39 @@ TEXT ·mmap(SB),7,$0
MOVL 36(SP), R9 // arg 6 offset
MOVL $477, AX
SYSCALL
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL $73, AX
+ SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT notok(SB),7,$-8
+TEXT runtime·notok(SB),7,$-8
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·sigaltstack(SB),7,$-8
MOVQ new+8(SP), DI
MOVQ old+16(SP), SI
MOVQ $53, AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$8
+ ADDQ $16, DI // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+ MOVQ DI, 0(SP)
+ MOVQ SP, SI
+ MOVQ $129, DI // AMD64_SET_FSBASE
+ MOVQ $165, AX // sysarch
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
RET
diff --git a/src/pkg/runtime/freebsd/defs.c b/src/pkg/runtime/freebsd/defs.c
index 36e69093e..32a80f475 100644
--- a/src/pkg/runtime/freebsd/defs.c
+++ b/src/pkg/runtime/freebsd/defs.c
@@ -28,6 +28,7 @@ enum {
$MAP_ANON = MAP_ANON,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_SIGINFO = SA_SIGINFO,
$SA_RESTART = SA_RESTART,
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
index 52e351a7d..7fb2c2807 100644
--- a/src/pkg/runtime/freebsd/mem.c
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -4,14 +4,21 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
+ void *v;
+
mstats.sys += n;
- return runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ runtime·printf("mmap: errno=%p\n", v);
+ runtime·throw("mmap");
+ }
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -19,10 +26,14 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
index 47bf7d56f..455355bc7 100644
--- a/src/pkg/runtime/freebsd/os.h
+++ b/src/pkg/runtime/freebsd/os.h
@@ -1,5 +1,5 @@
-int32 thr_new(ThrParam*, int32);
-void sigpanic(void);
-void sigaltstack(Sigaltstack*, Sigaltstack*);
+int32 runtime·thr_new(ThrParam*, int32);
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
-void sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
diff --git a/src/pkg/runtime/freebsd/runtime_defs.go b/src/pkg/runtime/freebsd/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/freebsd/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 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.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/freebsd/signals.h
index 0c41daf84..63a84671d 100644
--- a/src/pkg/runtime/freebsd/signals.h
+++ b/src/pkg/runtime/freebsd/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
index 334043312..9bd883833 100644
--- a/src/pkg/runtime/freebsd/thread.c
+++ b/src/pkg/runtime/freebsd/thread.c
@@ -5,8 +5,8 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
-extern int32 sys_umtx_op(uint32*, int32, uint32, void*, void*);
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
// thus the code is largely similar. See linux/thread.c for comments.
@@ -16,11 +16,11 @@ umtx_wait(uint32 *addr, uint32 val)
{
int32 ret;
- ret = sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
if(ret >= 0 || ret == -EINTR)
return;
- printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
+ runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
*(int32*)0x1005 = 0x1005;
}
@@ -29,11 +29,11 @@ umtx_wake(uint32 *addr)
{
int32 ret;
- ret = sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
if(ret >= 0)
return;
- printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+ runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
*(int32*)0x1006 = 0x1006;
}
@@ -46,12 +46,12 @@ umtx_lock(Lock *l)
again:
v = l->key;
if((v&1) == 0){
- if(cas(&l->key, v, v|1))
+ if(runtime·cas(&l->key, v, v|1))
return;
goto again;
}
- if(!cas(&l->key, v, v+2))
+ if(!runtime·cas(&l->key, v, v+2))
goto again;
umtx_wait(&l->key, v+2);
@@ -59,8 +59,8 @@ again:
for(;;){
v = l->key;
if(v < 2)
- throw("bad lock key");
- if(cas(&l->key, v, v-2))
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
break;
}
@@ -75,8 +75,8 @@ umtx_unlock(Lock *l)
again:
v = l->key;
if((v&1) == 0)
- throw("unlock of unlocked lock");
- if(!cas(&l->key, v, v&~1))
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
goto again;
if(v&~1)
@@ -84,53 +84,53 @@ again:
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
umtx_lock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
umtx_unlock(l);
}
void
-destroylock(Lock*)
+runtime·destroylock(Lock*)
{
}
// Event notifications.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0;
umtx_lock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
umtx_lock(&n->lock);
umtx_unlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
umtx_unlock(&n->lock);
}
-void thr_start(void*);
+void runtime·thr_start(void*);
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
ThrParam param;
@@ -138,13 +138,13 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
USED(g); // thr_start assumes g == m->g0
if(0){
- printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, m, g, fn, m->id, m->tls[0], &m);
}
- runtime_memclr((byte*)&param, sizeof param);
+ runtime·memclr((byte*)&param, sizeof param);
- param.start_func = thr_start;
+ param.start_func = runtime·thr_start;
param.arg = m;
param.stack_base = (int8*)g->stackbase;
param.stack_size = (byte*)stk - (byte*)g->stackbase;
@@ -155,43 +155,51 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
m->tls[0] = m->id; // so 386 asm can find it
- thr_new(&param, sizeof param);
+ runtime·thr_new(&param, sizeof param);
}
void
-osinit(void)
+runtime·osinit(void)
{
}
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling
- m->gsignal = malg(32*1024);
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c
index a4489213f..826ceff3a 100644
--- a/src/pkg/runtime/goc2c.c
+++ b/src/pkg/runtime/goc2c.c
@@ -2,7 +2,7 @@
// 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
+/* Translate a .goc file into a .c file. A .goc file is a combination
of a limited form of Go with C. */
/*
@@ -28,7 +28,7 @@ static int gcc;
/* File and line number */
static const char *file;
-static unsigned int lineno;
+static unsigned int lineno = 1;
/* List of names and types. */
struct params {
@@ -669,7 +669,7 @@ process_file(void)
static void
usage(void)
{
- fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n");
+ fprintf(stderr, "Usage: goc2c [--6g | --gc] [file]\n");
exit(1);
}
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index eb98ab54a..a03202ed6 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -139,7 +139,7 @@ hash_init (struct hash *h,
if(datasize < sizeof (void *))
datasize = sizeof (void *);
- datasize = rnd(datasize, sizeof (void *));
+ datasize = runtime·rnd(datasize, sizeof (void *));
init_sizes (hint, &init_power, &max_power);
h->datasize = datasize;
h->max_power = max_power;
@@ -289,7 +289,7 @@ hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags)
free (old_st);
}
-int32
+static int32
hash_lookup (struct hash *h, void *data, void **pres)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -330,7 +330,7 @@ hash_lookup (struct hash *h, void *data, void **pres)
return (0);
}
-int32
+static int32
hash_remove (struct hash *h, void *data, void *arg)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -454,7 +454,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
}
}
-int32
+static 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);
@@ -463,7 +463,7 @@ hash_insert (struct hash *h, void *data, void **pres)
return (rc);
}
-uint32
+static uint32
hash_count (struct hash *h)
{
return (h->count);
@@ -503,7 +503,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
sub->e = e;
}
-void *
+static void *
hash_next (struct hash_iter *it)
{
int32 elemsize = it->elemsize;
@@ -570,7 +570,7 @@ hash_next (struct hash_iter *it)
}
}
-void
+static void
hash_iter_init (struct hash *h, struct hash_iter *it)
{
it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -606,7 +606,7 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
*used += lused;
}
-void
+static void
hash_destroy (struct hash *h)
{
int32 slots = 0;
@@ -645,7 +645,7 @@ hash_visit_internal (struct hash_subtable *st,
}
}
-void
+static 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);
@@ -692,31 +692,31 @@ static int32 debug = 0;
// makemap(key, val *Type, hint uint32) (hmap *map[any]any);
Hmap*
-makemap(Type *key, Type *val, int64 hint)
+runtime·makemap_c(Type *key, Type *val, int64 hint)
{
Hmap *h;
int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
void (*data_del)(uint32, void*, void*);
if(hint < 0 || (int32)hint != hint)
- panicstring("makemap: size out of range");
+ runtime·panicstring("makemap: size out of range");
keyalg = key->alg;
valalg = val->alg;
keysize = key->size;
valsize = val->size;
- if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
- printf("map(keyalg=%d)\n", keyalg);
- throw("runtime.makemap: unsupported map key type");
+ if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) {
+ runtime·printf("map(keyalg=%d)\n", keyalg);
+ runtime·throw("runtime.makemap: unsupported map key type");
}
- if(valalg >= nelem(algarray)) {
- printf("map(valalg=%d)\n", valalg);
- throw("runtime.makemap: unsupported map value type");
+ if(valalg >= nelem(runtime·algarray)) {
+ runtime·printf("map(valalg=%d)\n", valalg);
+ runtime·throw("runtime.makemap: unsupported map value type");
}
- h = mal(sizeof(*h));
+ h = runtime·mal(sizeof(*h));
valsize_in_hash = valsize;
data_del = donothing;
@@ -730,38 +730,38 @@ makemap(Type *key, Type *val, int64 hint)
// might remove in the future and just assume datavo == keysize.
h->datavo = keysize;
if(valsize_in_hash >= sizeof(void*))
- h->datavo = rnd(keysize, sizeof(void*));
+ h->datavo = runtime·rnd(keysize, sizeof(void*));
hash_init(h, h->datavo+valsize_in_hash,
- algarray[keyalg].hash,
- algarray[keyalg].equal,
+ runtime·algarray[keyalg].hash,
+ runtime·algarray[keyalg].equal,
data_del,
hint);
h->keysize = keysize;
h->valsize = valsize;
- h->keyalg = &algarray[keyalg];
- h->valalg = &algarray[valalg];
+ h->keyalg = &runtime·algarray[keyalg];
+ h->valalg = &runtime·algarray[valalg];
// these calculations are compiler dependent.
// figure out offsets of map call arguments.
// func() (key, val)
- h->ko0 = rnd(sizeof(h), Structrnd);
- h->vo0 = rnd(h->ko0+keysize, val->align);
+ h->ko0 = runtime·rnd(sizeof(h), Structrnd);
+ h->vo0 = runtime·rnd(h->ko0+keysize, val->align);
// func(key) (val[, pres])
- h->ko1 = rnd(sizeof(h), key->align);
- h->vo1 = rnd(h->ko1+keysize, Structrnd);
- h->po1 = rnd(h->vo1+valsize, 1);
+ h->ko1 = runtime·rnd(sizeof(h), key->align);
+ h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
+ h->po1 = runtime·rnd(h->vo1+valsize, 1);
// func(key, val[, pres])
- h->ko2 = rnd(sizeof(h), key->align);
- h->vo2 = rnd(h->ko2+keysize, val->align);
- h->po2 = rnd(h->vo2+valsize, 1);
+ h->ko2 = runtime·rnd(sizeof(h), key->align);
+ h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
+ h->po2 = runtime·rnd(h->vo2+valsize, 1);
if(debug) {
- printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
+ runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2);
}
@@ -770,19 +770,19 @@ makemap(Type *key, Type *val, int64 hint)
// makemap(key, val *Type, hint int64) (hmap *map[any]any);
void
-·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
+runtime·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
{
- ret = makemap(key, val, hint);
+ ret = runtime·makemap_c(key, val, hint);
FLUSH(&ret);
}
void
-mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
+runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
{
byte *res;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
res = nil;
if(hash_lookup(h, ak, (void**)&res)) {
@@ -797,7 +797,7 @@ mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
// mapaccess1(hmap *map[any]any, key any) (val any);
#pragma textflag 7
void
-·mapaccess1(Hmap *h, ...)
+runtime·mapaccess1(Hmap *h, ...)
{
byte *ak, *av;
bool pres;
@@ -805,25 +805,25 @@ void
ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1;
- mapaccess(h, ak, av, &pres);
+ runtime·mapaccess(h, ak, av, &pres);
if(debug) {
- prints("runtime.mapaccess1: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("runtime.mapaccess1: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; pres=");
- ·printbool(pres);
- prints("\n");
+ runtime·prints("; pres=");
+ runtime·printbool(pres);
+ runtime·prints("\n");
}
}
// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
#pragma textflag 7
void
-·mapaccess2(Hmap *h, ...)
+runtime·mapaccess2(Hmap *h, ...)
{
byte *ak, *av, *ap;
@@ -831,29 +831,29 @@ void
av = (byte*)&h + h->vo1;
ap = (byte*)&h + h->po1;
- mapaccess(h, ak, av, ap);
+ runtime·mapaccess(h, ak, av, ap);
if(debug) {
- prints("runtime.mapaccess2: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("runtime.mapaccess2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; pres=");
- ·printbool(*ap);
- prints("\n");
+ runtime·prints("; pres=");
+ runtime·printbool(*ap);
+ runtime·prints("\n");
}
}
void
-mapassign(Hmap *h, byte *ak, byte *av)
+runtime·mapassign(Hmap *h, byte *ak, byte *av)
{
byte *res;
int32 hit;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
res = nil;
if(av == nil) {
@@ -863,42 +863,42 @@ mapassign(Hmap *h, byte *ak, byte *av)
hit = hash_insert(h, ak, (void**)&res);
if(!hit && h->indirectval)
- *(void**)(res+h->datavo) = mal(h->valsize);
+ *(void**)(res+h->datavo) = runtime·mal(h->valsize);
h->keyalg->copy(h->keysize, res, ak);
h->valalg->copy(h->valsize, hash_indirect(h, res+h->datavo), av);
if(debug) {
- prints("mapassign: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("mapassign: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; hit=");
- ·printint(hit);
- prints("; res=");
- ·printpointer(res);
- prints("\n");
+ runtime·prints("; hit=");
+ runtime·printint(hit);
+ runtime·prints("; res=");
+ runtime·printpointer(res);
+ runtime·prints("\n");
}
}
// mapassign1(hmap *map[any]any, key any, val any);
#pragma textflag 7
void
-·mapassign1(Hmap *h, ...)
+runtime·mapassign1(Hmap *h, ...)
{
byte *ak, *av;
ak = (byte*)&h + h->ko2;
av = (byte*)&h + h->vo2;
- mapassign(h, ak, av);
+ runtime·mapassign(h, ak, av);
}
// mapassign2(hmap *map[any]any, key any, val any, pres bool);
#pragma textflag 7
void
-·mapassign2(Hmap *h, ...)
+runtime·mapassign2(Hmap *h, ...)
{
byte *ak, *av, *ap;
@@ -909,86 +909,69 @@ void
if(*ap == false)
av = nil; // delete
- mapassign(h, ak, av);
+ runtime·mapassign(h, ak, av);
if(debug) {
- prints("mapassign2: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("mapassign2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("\n");
+ runtime·prints("\n");
}
}
-void*
-hash_next_and_deref(struct hash_iter *it)
-{
- void *p;
-
- p = hash_next(it);
- if(it->h->indirectval)
- p = *(void**)p;
- return p;
-}
-
// mapiterinit(hmap *map[any]any, hiter *any);
void
-·mapiterinit(Hmap *h, struct hash_iter *it)
+runtime·mapiterinit(Hmap *h, struct hash_iter *it)
{
if(h == nil) {
it->data = nil;
return;
}
hash_iter_init(h, it);
- it->data = hash_next_and_deref(it);
+ it->data = hash_next(it);
if(debug) {
- prints("runtime.mapiterinit: map=");
- ·printpointer(h);
- prints("; iter=");
- ·printpointer(it);
- prints("; data=");
- ·printpointer(it->data);
- prints("\n");
+ runtime·prints("runtime.mapiterinit: map=");
+ runtime·printpointer(h);
+ runtime·prints("; iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
}
}
struct hash_iter*
-mapiterinit(Hmap *h)
+runtime·newmapiterinit(Hmap *h)
{
struct hash_iter *it;
- it = mal(sizeof *it);
- ·mapiterinit(h, it);
+ it = runtime·mal(sizeof *it);
+ runtime·mapiterinit(h, it);
return it;
}
// mapiternext(hiter *any);
void
-·mapiternext(struct hash_iter *it)
+runtime·mapiternext(struct hash_iter *it)
{
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
- it->data = hash_next_and_deref(it);
+ it->data = hash_next(it);
if(debug) {
- prints("runtime.mapiternext: iter=");
- ·printpointer(it);
- prints("; data=");
- ·printpointer(it->data);
- prints("\n");
+ runtime·prints("runtime.mapiternext: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
}
}
-void
-mapiternext(struct hash_iter *it)
-{
- ·mapiternext(it);
-}
-
// mapiter1(hiter *any) (key any);
#pragma textflag 7
void
-·mapiter1(struct hash_iter *it, ...)
+runtime·mapiter1(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *res;
@@ -998,21 +981,21 @@ void
res = it->data;
if(res == nil)
- throw("runtime.mapiter1: key:val nil pointer");
+ runtime·throw("runtime.mapiter1: key:val nil pointer");
h->keyalg->copy(h->keysize, ak, res);
if(debug) {
- prints("mapiter2: iter=");
- ·printpointer(it);
- prints("; map=");
- ·printpointer(h);
- prints("\n");
+ runtime·prints("mapiter2: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; map=");
+ runtime·printpointer(h);
+ runtime·prints("\n");
}
}
bool
-mapiterkey(struct hash_iter *it, void *ak)
+runtime·mapiterkey(struct hash_iter *it, void *ak)
{
Hmap *h;
byte *res;
@@ -1028,7 +1011,7 @@ mapiterkey(struct hash_iter *it, void *ak)
// mapiter2(hiter *any) (key any, val any);
#pragma textflag 7
void
-·mapiter2(struct hash_iter *it, ...)
+runtime·mapiter2(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *av, *res;
@@ -1039,16 +1022,16 @@ void
res = it->data;
if(res == nil)
- throw("runtime.mapiter2: key:val nil pointer");
+ runtime·throw("runtime.mapiter2: key:val nil pointer");
h->keyalg->copy(h->keysize, ak, res);
h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
if(debug) {
- prints("mapiter2: iter=");
- ·printpointer(it);
- prints("; map=");
- ·printpointer(h);
- prints("\n");
+ runtime·prints("mapiter2: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; map=");
+ runtime·printpointer(h);
+ runtime·prints("\n");
}
}
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 906de4764..0737535b5 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -63,11 +63,12 @@
}
*/
-#define malloc mal
-#define offsetof(s,m) (uint32)(&(((s*)0)->m))
-#define memset(a,b,c) ·memclr((byte*)(a), (uint32)(c))
-#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c))
-#define assert(a) if(!(a)) throw("assert")
+#define malloc runtime·mal
+#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
+#define memcpy(a,b,c) runtime·mcpy((byte*)(a),(byte*)(b),(uint32)(c))
+#define assert(a) if(!(a)) runtime·throw("assert")
+#define free(x) runtime·free(x)
+#define memmove(a,b,c) runtime·memmove(a, b, c)
struct hash; /* opaque */
struct hash_subtable; /* opaque */
@@ -114,12 +115,12 @@ struct hash_iter {
/* 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);
+// 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);
+// 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
@@ -129,10 +130,10 @@ int32 hash_remove (struct hash *h, void *data, void *arg);
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);
+// int32 hash_insert (struct hash *h, void *data, void **pres);
/* Return the number of elements in the table. */
-uint32 hash_count (struct hash *h);
+// uint32 hash_count (struct hash *h);
/* The following call is useful only if not using garbage collection on the
table.
@@ -141,18 +142,18 @@ uint32 hash_count (struct hash *h);
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);
+// void hash_destroy (struct hash *h);
/*----- iteration -----*/
/* Initialize *it from *h. */
-void hash_iter_init (struct hash *h, struct hash_iter *it);
+// 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);
+// 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);
+// void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
diff --git a/src/pkg/runtime/hashmap_defs.go b/src/pkg/runtime/hashmap_defs.go
new file mode 100644
index 000000000..57780df87
--- /dev/null
+++ b/src/pkg/runtime/hashmap_defs.go
@@ -0,0 +1,51 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is hashmap.[c,h]
+
+package runtime
+
+type hash_hash uintptr
+
+type hash_entry struct {
+ hash hash_hash
+ key byte // dwarf.c substitutes the real type
+ val byte // for key and val
+}
+
+type hash_subtable struct {
+ power uint8
+ used uint8
+ datasize uint8
+ max_probes uint8
+ limit_bytes int16
+ end *hash_entry
+ entry hash_entry // TODO: [0]hash_entry
+}
+
+type hash struct {
+ count uint32
+ datasize uint8
+ max_power uint8
+ max_probes uint8
+ indirectval uint8
+ changes int32
+ data_hash func(uint32, uintptr) hash_hash
+ data_eq func(uint32, uintptr, uintptr) uint32
+ data_del func(uint32, uintptr, uintptr)
+ st *hash_subtable
+ keysize uint32
+ valsize uint32
+ datavo uint32
+ ko0 uint32
+ vo0 uint32
+ ko1 uint32
+ vo1 uint32
+ po1 uint32
+ ko2 uint32
+ vo2 uint32
+ po2 uint32
+ keyalg *alg
+ valalg *alg
+}
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 35a710eca..aa36df68e 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -6,16 +6,16 @@
#include "type.h"
#include "malloc.h"
-static void
-printiface(Iface i)
+void
+runtime·printiface(Iface i)
{
- printf("(%p,%p)", i.tab, i.data);
+ runtime·printf("(%p,%p)", i.tab, i.data);
}
-static void
-printeface(Eface e)
+void
+runtime·printeface(Eface e)
{
- printf("(%p,%p)", e.type, e.data);
+ runtime·printf("(%p,%p)", e.type, e.data);
}
/*
@@ -49,7 +49,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
Eface err;
if(inter->mhdr.len == 0)
- throw("internal error - misuse of itab");
+ runtime·throw("internal error - misuse of itab");
locked = 0;
@@ -72,7 +72,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
// common case will be no lock contention.
for(locked=0; locked<2; locked++) {
if(locked)
- lock(&ifacelock);
+ runtime·lock(&ifacelock);
for(m=hash[h]; m!=nil; m=m->link) {
if(m->inter == inter && m->type == type) {
if(m->bad) {
@@ -89,14 +89,14 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
}
}
if(locked)
- unlock(&ifacelock);
+ runtime·unlock(&ifacelock);
return m;
}
}
}
ni = inter->mhdr.len;
- m = malloc(sizeof(*m) + ni*sizeof m->fun[0]);
+ m = runtime·malloc(sizeof(*m) + ni*sizeof m->fun[0]);
m->inter = inter;
m->type = type;
@@ -117,12 +117,12 @@ search:
if(!canfail) {
throw:
// didn't find method
- ·newTypeAssertionError(nil, type, inter,
+ runtime·newTypeAssertionError(nil, type, inter,
nil, type->string, inter->string,
iname, &err);
if(locked)
- unlock(&ifacelock);
- ·panic(err);
+ runtime·unlock(&ifacelock);
+ runtime·panic(err);
return nil; // not reached
}
m->bad = 1;
@@ -139,7 +139,7 @@ out:
m->link = hash[h];
hash[h] = m;
if(locked)
- unlock(&ifacelock);
+ runtime·unlock(&ifacelock);
if(m->bad)
return nil;
return m;
@@ -155,10 +155,10 @@ copyin(Type *t, void *src, void **dst)
alg = t->alg;
if(wid <= sizeof(*dst))
- algarray[alg].copy(wid, dst, src);
+ runtime·algarray[alg].copy(wid, dst, src);
else {
- p = mal(wid);
- algarray[alg].copy(wid, p, src);
+ p = runtime·mal(wid);
+ runtime·algarray[alg].copy(wid, p, src);
*dst = p;
}
}
@@ -172,15 +172,15 @@ copyout(Type *t, void **src, void *dst)
alg = t->alg;
if(wid <= sizeof(*src))
- algarray[alg].copy(wid, dst, src);
+ runtime·algarray[alg].copy(wid, dst, src);
else
- algarray[alg].copy(wid, dst, *src);
+ runtime·algarray[alg].copy(wid, dst, *src);
}
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
#pragma textflag 7
void
-·convT2I(Type *t, InterfaceType *inter, ...)
+runtime·convT2I(Type *t, InterfaceType *inter, ...)
{
byte *elem;
Iface *ret;
@@ -188,7 +188,7 @@ void
elem = (byte*)(&inter+1);
wid = t->size;
- ret = (Iface*)(elem + rnd(wid, Structrnd));
+ ret = (Iface*)(elem + runtime·rnd(wid, Structrnd));
ret->tab = itab(inter, t, 0);
copyin(t, elem, &ret->data);
}
@@ -196,7 +196,7 @@ void
// func convT2E(typ *byte, elem any) (ret any)
#pragma textflag 7
void
-·convT2E(Type *t, ...)
+runtime·convT2E(Type *t, ...)
{
byte *elem;
Eface *ret;
@@ -204,7 +204,7 @@ void
elem = (byte*)(&t+1);
wid = t->size;
- ret = (Eface*)(elem + rnd(wid, Structrnd));
+ ret = (Eface*)(elem + runtime·rnd(wid, Structrnd));
ret->type = t;
copyin(t, elem, &ret->data);
}
@@ -212,7 +212,7 @@ void
// func ifaceI2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2T(Type *t, Iface i, ...)
+runtime·assertI2T(Type *t, Iface i, ...)
{
Itab *tab;
byte *ret;
@@ -221,16 +221,16 @@ void
ret = (byte*)(&i+1);
tab = i.tab;
if(tab == nil) {
- ·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(nil, nil, t,
nil, nil, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
if(tab->type != t) {
- ·newTypeAssertionError(tab->inter, tab->type, t,
+ runtime·newTypeAssertionError(tab->inter, tab->type, t,
tab->inter->string, tab->type->string, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
copyout(t, &i.data, ret);
}
@@ -238,7 +238,7 @@ void
// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2T2(Type *t, Iface i, ...)
+runtime·assertI2T2(Type *t, Iface i, ...)
{
byte *ret;
bool *ok;
@@ -246,11 +246,11 @@ void
ret = (byte*)(&i+1);
wid = t->size;
- ok = (bool*)(ret+rnd(wid, 1));
+ ok = (bool*)(ret+runtime·rnd(wid, 1));
if(i.tab == nil || i.tab->type != t) {
*ok = false;
- ·memclr(ret, wid);
+ runtime·memclr(ret, wid);
return;
}
@@ -261,7 +261,7 @@ void
// func ifaceE2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2T(Type *t, Eface e, ...)
+runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
Eface err;
@@ -269,16 +269,16 @@ void
ret = (byte*)(&e+1);
if(e.type == nil) {
- ·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(nil, nil, t,
nil, nil, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
if(e.type != t) {
- ·newTypeAssertionError(nil, e.type, t,
+ runtime·newTypeAssertionError(nil, e.type, t,
nil, e.type->string, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
copyout(t, &e.data, ret);
}
@@ -286,7 +286,7 @@ void
// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag 7
void
-·assertE2T2(Type *t, Eface e, ...)
+runtime·assertE2T2(Type *t, Eface e, ...)
{
byte *ret;
bool *ok;
@@ -294,11 +294,11 @@ void
ret = (byte*)(&e+1);
wid = t->size;
- ok = (bool*)(ret+rnd(wid, 1));
+ ok = (bool*)(ret+runtime·rnd(wid, 1));
if(t != e.type) {
*ok = false;
- ·memclr(ret, wid);
+ runtime·memclr(ret, wid);
return;
}
@@ -309,7 +309,7 @@ void
// func convI2E(elem any) (ret any)
#pragma textflag 7
void
-·convI2E(Iface i, Eface ret)
+runtime·convI2E(Iface i, Eface ret)
{
Itab *tab;
@@ -324,7 +324,7 @@ void
// func ifaceI2E(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2E(InterfaceType* inter, Iface i, Eface ret)
+runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
{
Itab *tab;
Eface err;
@@ -332,10 +332,10 @@ void
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret.data = i.data;
ret.type = tab->type;
@@ -345,7 +345,7 @@ void
// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
+runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
{
Itab *tab;
@@ -366,7 +366,7 @@ void
// func convI2I(typ *byte, elem any) (ret any)
#pragma textflag 7
void
-·convI2I(InterfaceType* inter, Iface i, Iface ret)
+runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
{
Itab *tab;
@@ -381,7 +381,7 @@ void
}
void
-ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
+runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
{
Itab *tab;
Eface err;
@@ -389,10 +389,10 @@ ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret->data = i.data;
ret->tab = itab(inter, tab->type, 0);
@@ -401,15 +401,15 @@ ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
// func ifaceI2I(sigi *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2I(InterfaceType* inter, Iface i, Iface ret)
+runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
{
- ifaceI2I(inter, i, &ret);
+ runtime·ifaceI2I(inter, i, &ret);
}
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
+runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
Itab *tab;
@@ -428,7 +428,7 @@ void
}
void
-ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
+runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
{
Type *t;
Eface err;
@@ -436,10 +436,10 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret->data = e.data;
ret->tab = itab(inter, t, 0);
@@ -448,15 +448,15 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
// func ifaceE2I(sigi *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2I(InterfaceType* inter, Eface e, Iface ret)
+runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
{
- ifaceE2I(inter, e, &ret);
+ runtime·ifaceE2I(inter, e, &ret);
}
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
+runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
if(e.type == nil) {
ok = 0;
@@ -476,7 +476,7 @@ void
// func ifaceE2E(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2E(InterfaceType* inter, Eface e, Eface ret)
+runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
{
Type *t;
Eface err;
@@ -484,10 +484,10 @@ void
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret = e;
FLUSH(&ret);
@@ -496,7 +496,7 @@ void
// func ifaceE2E2(iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
+runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
USED(inter);
ret = e;
@@ -516,19 +516,19 @@ ifacehash1(void *data, Type *t)
alg = t->alg;
wid = t->size;
- if(algarray[alg].hash == nohash) {
+ if(runtime·algarray[alg].hash == runtime·nohash) {
// calling nohash will panic too,
// but we can print a better error.
- ·newErrorString(catstring(gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
+ runtime·panic(err);
}
if(wid <= sizeof(data))
- return algarray[alg].hash(wid, &data);
- return algarray[alg].hash(wid, data);
+ return runtime·algarray[alg].hash(wid, &data);
+ return runtime·algarray[alg].hash(wid, data);
}
uintptr
-ifacehash(Iface a)
+runtime·ifacehash(Iface a)
{
if(a.tab == nil)
return 0;
@@ -536,7 +536,7 @@ ifacehash(Iface a)
}
uintptr
-efacehash(Eface a)
+runtime·efacehash(Eface a)
{
return ifacehash1(a.data, a.type);
}
@@ -550,20 +550,20 @@ ifaceeq1(void *data1, void *data2, Type *t)
alg = t->alg;
wid = t->size;
- if(algarray[alg].equal == noequal) {
+ if(runtime·algarray[alg].equal == runtime·noequal) {
// calling noequal will panic too,
// but we can print a better error.
- ·newErrorString(catstring(gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
+ runtime·panic(err);
}
if(wid <= sizeof(data1))
- return algarray[alg].equal(wid, &data1, &data2);
- return algarray[alg].equal(wid, data1, data2);
+ return runtime·algarray[alg].equal(wid, &data1, &data2);
+ return runtime·algarray[alg].equal(wid, data1, data2);
}
bool
-ifaceeq(Iface i1, Iface i2)
+runtime·ifaceeq_c(Iface i1, Iface i2)
{
if(i1.tab != i2.tab)
return false;
@@ -573,7 +573,7 @@ ifaceeq(Iface i1, Iface i2)
}
bool
-efaceeq(Eface e1, Eface e2)
+runtime·efaceeq_c(Eface e1, Eface e2)
{
if(e1.type != e2.type)
return false;
@@ -584,23 +584,23 @@ efaceeq(Eface e1, Eface e2)
// ifaceeq(i1 any, i2 any) (ret bool);
void
-·ifaceeq(Iface i1, Iface i2, bool ret)
+runtime·ifaceeq(Iface i1, Iface i2, bool ret)
{
- ret = ifaceeq(i1, i2);
+ ret = runtime·ifaceeq_c(i1, i2);
FLUSH(&ret);
}
// efaceeq(i1 any, i2 any) (ret bool)
void
-·efaceeq(Eface e1, Eface e2, bool ret)
+runtime·efaceeq(Eface e1, Eface e2, bool ret)
{
- ret = efaceeq(e1, e2);
+ ret = runtime·efaceeq_c(e1, e2);
FLUSH(&ret);
}
// ifacethash(i1 any) (ret uint32);
void
-·ifacethash(Iface i1, uint32 ret)
+runtime·ifacethash(Iface i1, uint32 ret)
{
Itab *tab;
@@ -613,7 +613,7 @@ void
// efacethash(e1 any) (ret uint32)
void
-·efacethash(Eface e1, uint32 ret)
+runtime·efacethash(Eface e1, uint32 ret)
{
Type *t;
@@ -625,18 +625,6 @@ void
}
void
-·printiface(Iface i)
-{
- printiface(i);
-}
-
-void
-·printeface(Eface e)
-{
- printeface(e);
-}
-
-void
unsafe·Typeof(Eface e, Eface ret)
{
if(e.type == nil) {
@@ -662,17 +650,17 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
if(e.type->size <= sizeof(uintptr)) {
// Copy data into x ...
x = 0;
- algarray[e.type->alg].copy(e.type->size, &x, &e.data);
+ runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
// but then build pointer to x so that Reflect
// always returns pointer to data.
- p = mal(sizeof(uintptr));
+ p = runtime·mal(sizeof(uintptr));
*p = x;
} else {
// Already a pointer, but still make a copy,
// to preserve value semantics for interface data.
- p = mal(e.type->size);
- algarray[e.type->alg].copy(e.type->size, p, e.data);
+ p = runtime·mal(e.type->size);
+ runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
}
retaddr = p;
}
@@ -692,7 +680,7 @@ unsafe·Unreflect(Eface typ, void *addr, Eface e)
// Interface holds either pointer to data
// or copy of original data.
if(e.type->size <= sizeof(uintptr))
- algarray[e.type->alg].copy(e.type->size, &e.data, addr);
+ runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
else {
// Easier: already a pointer to data.
// TODO(rsc): Should this make a copy?
@@ -714,9 +702,9 @@ unsafe·New(Eface typ, void *ret)
t = (Type*)((Eface*)typ.data-1);
if(t->kind&KindNoPointers)
- ret = mallocgc(t->size, RefNoPointers, 1, 1);
+ ret = runtime·mallocgc(t->size, RefNoPointers, 1, 1);
else
- ret = mal(t->size);
+ ret = runtime·mal(t->size);
FLUSH(&ret);
}
@@ -734,8 +722,8 @@ unsafe·NewArray(Eface typ, uint32 n, void *ret)
size = n*t->size;
if(t->kind&KindNoPointers)
- ret = mallocgc(size, RefNoPointers, 1, 1);
+ ret = runtime·mallocgc(size, RefNoPointers, 1, 1);
else
- ret = mal(size);
+ ret = runtime·mal(size);
FLUSH(&ret);
}
diff --git a/src/pkg/runtime/iface_defs.go b/src/pkg/runtime/iface_defs.go
new file mode 100644
index 000000000..69d52ef9a
--- /dev/null
+++ b/src/pkg/runtime/iface_defs.go
@@ -0,0 +1,18 @@
+// Copyright 2010 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 runtime
+
+/*
+ * Must match iface.c:/Itable and compilers.
+ * NOTE: type.go has an Itable, that is the version of Itab used by the reflection code.
+ */
+type itab struct {
+ Itype *Type
+ Type *Type
+ link *itab
+ bad int32
+ unused int32
+ Fn func() // TODO: [0]func()
+}
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h
index ef8ef05d0..c1f58b2a0 100644
--- a/src/pkg/runtime/linux/386/defs.h
+++ b/src/pkg/runtime/linux/386/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s
index 4d2345d8c..0f82d6a1c 100644
--- a/src/pkg/runtime/linux/386/rt0.s
+++ b/src/pkg/runtime/linux/386/rt0.s
@@ -4,6 +4,14 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_linux(SB),7,$0
+TEXT _rt0_386_linux(SB),7,$0
+ // Linux starts the FPU in extended double precision.
+ // Other operating systems use double precision.
+ // Change to double precision to match them,
+ // and to match other hardware that only has double.
+ PUSHL $0x27F
+ FLDCW 0(SP)
+ POPL AX
+
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c
index 6bc95d0d7..0dbfcf9ff 100644
--- a/src/pkg/runtime/linux/386/signal.c
+++ b/src/pkg/runtime/linux/386/signal.c
@@ -8,41 +8,41 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·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);
+ runtime·printf("eax %x\n", r->eax);
+ runtime·printf("ebx %x\n", r->ebx);
+ runtime·printf("ecx %x\n", r->ecx);
+ runtime·printf("edx %x\n", r->edx);
+ runtime·printf("edi %x\n", r->edi);
+ runtime·printf("esi %x\n", r->esi);
+ runtime·printf("ebp %x\n", r->ebp);
+ runtime·printf("esp %x\n", r->esp);
+ runtime·printf("eip %x\n", r->eip);
+ runtime·printf("eflags %x\n", r->eflags);
+ runtime·printf("cs %x\n", r->cs);
+ runtime·printf("fs %x\n", r->fs);
+ runtime·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
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Sigcontext *r;
@@ -52,7 +52,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -61,84 +61,84 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[3];
- // Only push sigpanic if r->eip != 0.
+ // Only push runtime·sigpanic if r->eip != 0.
// If r->eip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->eip != 0) {
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->esp = (uintptr)sp;
}
- r->eip = (uintptr)sigpanic;
+ r->eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->eip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.k_sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.k_sa_handler = (void*)runtime·sigtramp;
else
- sa.k_sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.k_sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index 57ffc4aa4..a1505b0b0 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -8,21 +8,21 @@
#include "386/asm.h"
-TEXT exit(SB),7,$0
+TEXT runtime·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
+TEXT runtime·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
+TEXT runtime·write(SB),7,$0
MOVL $4, AX // syscall - write
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -30,7 +30,7 @@ TEXT write(SB),7,$0
INT $0x80
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $78, AX // syscall - gettimeofday
LEAL 8(SP), BX
MOVL $0, CX
@@ -47,7 +47,7 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT rt_sigaction(SB),7,$0
+TEXT runtime·rt_sigaction(SB),7,$0
MOVL $174, AX // syscall - rt_sigaction
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -56,7 +56,7 @@ TEXT rt_sigaction(SB),7,$0
INT $0x80
RET
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
// save g
@@ -76,7 +76,7 @@ TEXT sigtramp(SB),7,$40
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
// restore g
get_tls(CX)
@@ -85,16 +85,16 @@ TEXT sigtramp(SB),7,$40
RET
-TEXT sigignore(SB),7,$0
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVL $173, AX // rt_sigreturn
INT $0x80
INT $3 // not reached
RET
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVL $192, AX // mmap2
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -110,9 +110,19 @@ TEXT ·mmap(SB),7,$0
INCL AX
RET
+TEXT runtime·munmap(SB),7,$0
+ MOVL $91, AX // munmap
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVL $240, AX // futex
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -124,7 +134,7 @@ TEXT futex(SB),7,$0
RET
// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVL $120, AX // clone
MOVL flags+4(SP), BX
MOVL stack+8(SP), CX
@@ -161,12 +171,12 @@ TEXT clone(SB),7,$0
// In child on new stack. Reload registers (paranoia).
MOVL 0(SP), BX // m
MOVL 4(SP), DX // g
- MOVL 8(SP), CX // fn
+ MOVL 8(SP), SI // fn
MOVL AX, m_procid(BX) // save tid as m->procid
// set up ldt 7+id to point at m->tls.
- // m->tls is at m+40. newosproc left the id in tls[0].
+ // newosproc left the id in tls[0].
LEAL m_tls(BX), BP
MOVL 0(BP), DI
ADDL $7, DI // m0 is LDT#7. count up.
@@ -175,7 +185,7 @@ TEXT clone(SB),7,$0
PUSHL $32 // sizeof tls
PUSHL BP // &tls
PUSHL DI // tls #
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -186,21 +196,21 @@ TEXT clone(SB),7,$0
MOVL DX, g(AX)
MOVL BX, m(AX)
- CALL stackcheck(SB) // smashes AX
+ CALL runtime·stackcheck(SB) // smashes AX, CX
MOVL 0(DX), DX // paranoia; check they are not nil
MOVL 0(BX), BX
// more paranoia; check that stack splitting code works
PUSHAL
- CALL emptyfunc(SB)
+ CALL runtime·emptyfunc(SB)
POPAL
- CALL CX // fn()
- CALL exit1(SB)
+ CALL SI // fn()
+ CALL runtime·exit1(SB)
MOVL $0x1234, 0x1005
RET
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·sigaltstack(SB),7,$-8
MOVL $186, AX // sigaltstack
MOVL new+4(SP), BX
MOVL old+8(SP), CX
@@ -233,7 +243,7 @@ TEXT sigaltstack(SB),7,$-8
#define USEABLE 0x40
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL entry+0(FP), BX // entry
MOVL address+4(FP), CX // base address
@@ -247,8 +257,11 @@ TEXT setldt(SB),7,$32
* To accommodate that rewrite, we translate
* the address here and bump the limit to 0xffffffff (no limit)
* so that -8(GS) maps to 0(address).
+ * Also, the final 0(GS) (current 8(CX)) has to point
+ * to itself, to mimic ELF.
*/
ADDL $0x8, CX // address
+ MOVL CX, 0(CX)
// set up user_desc
LEAL 16(SP), AX // struct user_desc
diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h
index c08e6b25d..3e3d32f0d 100644
--- a/src/pkg/runtime/linux/amd64/defs.h
+++ b/src/pkg/runtime/linux/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/linux/amd64/rt0.s
index 2190b4414..dac9ae181 100644
--- a/src/pkg/runtime/linux/amd64/rt0.s
+++ b/src/pkg/runtime/linux/amd64/rt0.s
@@ -4,7 +4,7 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_linux(SB),7,$-8
+TEXT _rt0_amd64_linux(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c
index 63c3a2e6e..e78bbda9d 100644
--- a/src/pkg/runtime/linux/amd64/signal.c
+++ b/src/pkg/runtime/linux/amd64/signal.c
@@ -8,49 +8,49 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·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);
+ runtime·printf("rax %X\n", r->rax);
+ runtime·printf("rbx %X\n", r->rbx);
+ runtime·printf("rcx %X\n", r->rcx);
+ runtime·printf("rdx %X\n", r->rdx);
+ runtime·printf("rdi %X\n", r->rdi);
+ runtime·printf("rsi %X\n", r->rsi);
+ runtime·printf("rbp %X\n", r->rbp);
+ runtime·printf("rsp %X\n", r->rsp);
+ runtime·printf("r8 %X\n", r->r8 );
+ runtime·printf("r9 %X\n", r->r9 );
+ runtime·printf("r10 %X\n", r->r10);
+ runtime·printf("r11 %X\n", r->r11);
+ runtime·printf("r12 %X\n", r->r12);
+ runtime·printf("r13 %X\n", r->r13);
+ runtime·printf("r14 %X\n", r->r14);
+ runtime·printf("r15 %X\n", r->r15);
+ runtime·printf("rip %X\n", r->rip);
+ runtime·printf("rflags %X\n", r->eflags);
+ runtime·printf("cs %X\n", (uint64)r->cs);
+ runtime·printf("fs %X\n", (uint64)r->fs);
+ runtime·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
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
@@ -62,7 +62,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
mc = &uc->uc_mcontext;
r = (Sigcontext*)mc; // same layout, more conveient names
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -71,84 +71,84 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[2];
- // Only push sigpanic if r->rip != 0.
+ // Only push runtime·sigpanic if r->rip != 0.
// If r->rip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->rip != 0) {
sp = (uintptr*)r->rsp;
*--sp = r->rip;
r->rsp = (uintptr)sp;
}
- r->rip = (uintptr)sigpanic;
+ r->rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->rip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15);
- tracebackothers((void*)r->r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.sa_handler = (void*)runtime·sigtramp;
else
- sa.sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
index dd0473158..170b659fc 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -8,19 +8,19 @@
#include "amd64/asm.h"
-TEXT exit(SB),7,$0-8
+TEXT runtime·exit(SB),7,$0-8
MOVL 8(SP), DI
MOVL $231, AX // exitgroup - force all os threads to exit
SYSCALL
RET
-TEXT exit1(SB),7,$0-8
+TEXT runtime·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
+TEXT runtime·open(SB),7,$0-16
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -28,7 +28,7 @@ TEXT open(SB),7,$0-16
SYSCALL
RET
-TEXT write(SB),7,$0-24
+TEXT runtime·write(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -36,7 +36,7 @@ TEXT write(SB),7,$0-24
SYSCALL
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
LEAQ 8(SP), DI
MOVQ $0, SI
MOVQ $0xffffffffff600000, AX
@@ -51,7 +51,7 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT rt_sigaction(SB),7,$0-32
+TEXT runtime·rt_sigaction(SB),7,$0-32
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
@@ -60,23 +60,38 @@ TEXT rt_sigaction(SB),7,$0-32
SYSCALL
RET
-TEXT sigtramp(SB),7,$24-16
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), BP
+ MOVQ BP, 40(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), BP
+ MOVQ BP, g(BX)
RET
-TEXT sigignore(SB),7,$0
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVL $15, AX // rt_sigreturn
SYSCALL
INT $3 // not reached
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVQ 8(SP), DI
MOVQ $0, SI
MOVQ 16(SP), SI
@@ -85,7 +100,7 @@ TEXT ·mmap(SB),7,$0
MOVL 32(SP), R8
MOVL 36(SP), R9
- MOVL $9, AX // syscall entry
+ MOVL $9, AX // mmap
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 3(PC)
@@ -93,14 +108,24 @@ TEXT ·mmap(SB),7,$0
INCQ AX
RET
-TEXT notok(SB),7,$0
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ $11, AX // munmap
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$0
MOVQ $0xf1, BP
MOVQ BP, (BP)
RET
// int64 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -112,7 +137,7 @@ TEXT futex(SB),7,$0
RET
// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVL flags+8(SP), DI
MOVQ stack+16(SP), SI
@@ -129,17 +154,24 @@ TEXT clone(SB),7,$0
CMPQ AX, $0
JEQ 2(PC)
RET
-
- // In child, set up new stack
+
+ // In child, on new stack.
MOVQ SI, SP
- MOVQ R8, m
- MOVQ R9, g
- CALL stackcheck(SB)
-
+
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
- MOVQ AX, m_procid(m)
+ MOVQ AX, m_procid(R8)
+
+ // Set FS to point at m->tls.
+ LEAQ m_tls(R8), DI
+ CALL runtime·settls(SB)
+
+ // In child, set up new stack
+ get_tls(CX)
+ MOVQ R8, m(CX)
+ MOVQ R9, g(CX)
+ CALL runtime·stackcheck(SB)
// Call fn
CALL R12
@@ -150,12 +182,26 @@ TEXT clone(SB),7,$0
SYSCALL
JMP -3(PC) // keep exiting
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·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)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$32
+ ADDQ $16, DI // ELF wants to use -16(FS), -8(FS)
+
+ MOVQ DI, SI
+ MOVQ $0x1002, DI // ARCH_SET_FS
+ MOVQ $158, AX // arch_prctl
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL runtime·notok(SB)
RET
+
diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/linux/arm/defs.h
index b13985171..ff43d689a 100644
--- a/src/pkg/runtime/linux/arm/defs.h
+++ b/src/pkg/runtime/linux/arm/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
@@ -44,19 +45,19 @@ enum {
SIGIO = 0x1d,
SIGPWR = 0x1e,
SIGSYS = 0x1f,
- FPE_INTDIV = 0x30001,
- FPE_INTOVF = 0x30002,
- FPE_FLTDIV = 0x30003,
- FPE_FLTOVF = 0x30004,
- FPE_FLTUND = 0x30005,
- FPE_FLTRES = 0x30006,
- FPE_FLTINV = 0x30007,
- FPE_FLTSUB = 0x30008,
- BUS_ADRALN = 0x30001,
- BUS_ADRERR = 0x30002,
- BUS_OBJERR = 0x30003,
- SEGV_MAPERR = 0x30001,
- SEGV_ACCERR = 0x30002,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
};
// Types
diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/linux/arm/rt0.s
index 024547ddd..8838b4891 100644
--- a/src/pkg/runtime/linux/arm/rt0.s
+++ b/src/pkg/runtime/linux/arm/rt0.s
@@ -2,5 +2,5 @@
// 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
+TEXT _rt0_arm_linux(SB),7,$0
B _rt0_arm(SB)
diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c
index a9dccae4a..c65aff913 100644
--- a/src/pkg/runtime/linux/arm/signal.c
+++ b/src/pkg/runtime/linux/arm/signal.c
@@ -8,49 +8,49 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·dumpregs(Sigcontext *r)
{
- printf("trap %x\n", r->trap_no);
- printf("error %x\n", r->error_code);
- printf("oldmask %x\n", r->oldmask);
- printf("r0 %x\n", r->arm_r0);
- printf("r1 %x\n", r->arm_r1);
- printf("r2 %x\n", r->arm_r2);
- printf("r3 %x\n", r->arm_r3);
- printf("r4 %x\n", r->arm_r4);
- printf("r5 %x\n", r->arm_r5);
- printf("r6 %x\n", r->arm_r6);
- printf("r7 %x\n", r->arm_r7);
- printf("r8 %x\n", r->arm_r8);
- printf("r9 %x\n", r->arm_r9);
- printf("r10 %x\n", r->arm_r10);
- printf("fp %x\n", r->arm_fp);
- printf("ip %x\n", r->arm_ip);
- printf("sp %x\n", r->arm_sp);
- printf("lr %x\n", r->arm_lr);
- printf("pc %x\n", r->arm_pc);
- printf("cpsr %x\n", r->arm_cpsr);
- printf("fault %x\n", r->fault_address);
+ runtime·printf("trap %x\n", r->trap_no);
+ runtime·printf("error %x\n", r->error_code);
+ runtime·printf("oldmask %x\n", r->oldmask);
+ runtime·printf("r0 %x\n", r->arm_r0);
+ runtime·printf("r1 %x\n", r->arm_r1);
+ runtime·printf("r2 %x\n", r->arm_r2);
+ runtime·printf("r3 %x\n", r->arm_r3);
+ runtime·printf("r4 %x\n", r->arm_r4);
+ runtime·printf("r5 %x\n", r->arm_r5);
+ runtime·printf("r6 %x\n", r->arm_r6);
+ runtime·printf("r7 %x\n", r->arm_r7);
+ runtime·printf("r8 %x\n", r->arm_r8);
+ runtime·printf("r9 %x\n", r->arm_r9);
+ runtime·printf("r10 %x\n", r->arm_r10);
+ runtime·printf("fp %x\n", r->arm_fp);
+ runtime·printf("ip %x\n", r->arm_ip);
+ runtime·printf("sp %x\n", r->arm_sp);
+ runtime·printf("lr %x\n", r->arm_lr);
+ runtime·printf("pc %x\n", r->arm_pc);
+ runtime·printf("cpsr %x\n", r->arm_cpsr);
+ runtime·printf("fault %x\n", r->fault_address);
}
/*
* 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
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Sigcontext *r;
@@ -59,7 +59,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -75,75 +75,75 @@ sighandler(int32 sig, Siginfo *info, void *context)
// old link register is more useful in the stack trace.
if(r->arm_pc != 0)
r->arm_lr = r->arm_pc;
- r->arm_pc = (uintptr)sigpanic;
+ r->arm_pc = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%x\n", r->arm_pc);
- printf("\n");
+ runtime·printf("PC=%x\n", r->arm_pc);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg);
- tracebackothers(m->curg);
- printf("\n");
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·printf("\n");
+ runtime·dumpregs(r);
}
// breakpoint();
- exit(2);
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask.sig[0] = 0xFFFFFFFF;
sa.sa_mask.sig[1] = 0xFFFFFFFF;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.sa_handler = (void*)runtime·sigtramp;
else
- sa.sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index f30aed001..b25cf81aa 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -25,11 +25,12 @@
#define SYS_gettid (SYS_BASE + 224)
#define SYS_futex (SYS_BASE + 240)
#define SYS_exit_group (SYS_BASE + 248)
+#define SYS_munmap (SYS_BASE + 91)
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -37,7 +38,7 @@ TEXT write(SB),7,$0
SWI $0
RET
-TEXT exit(SB),7,$-4
+TEXT runtime·exit(SB),7,$-4
MOVW 0(FP), R0
MOVW $SYS_exit_group, R7
SWI $0
@@ -45,7 +46,7 @@ TEXT exit(SB),7,$-4
MOVW $1002, R1
MOVW R0, (R1) // fail hard
-TEXT exit1(SB),7,$-4
+TEXT runtime·exit1(SB),7,$-4
MOVW 0(FP), R0
MOVW $SYS_exit, R7
SWI $0
@@ -53,7 +54,7 @@ TEXT exit1(SB),7,$-4
MOVW $1003, R1
MOVW R0, (R1) // fail hard
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -64,7 +65,14 @@ TEXT ·mmap(SB),7,$0
SWI $0
RET
-TEXT gettime(SB),7,$32
+TEXT runtime·munmap(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_munmap, R7
+ SWI $0
+ RET
+
+TEXT runtime·gettime(SB),7,$32
/* dummy version - return 0,0 */
MOVW $0, R1
MOVW 0(FP), R0
@@ -93,7 +101,7 @@ TEXT gettime(SB),7,$32
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVW 4(SP), R0
MOVW 8(SP), R1
MOVW 12(SP), R2
@@ -106,7 +114,7 @@ TEXT futex(SB),7,$0
// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVW flags+0(FP), R0
MOVW stack+4(FP), R1
MOVW $0, R2 // parent tid ptr
@@ -139,7 +147,7 @@ TEXT clone(SB),7,$0
MOVW $1234, R1
CMP R0, R1
BEQ 2(PC)
- B abort(SB)
+ BL runtime·abort(SB)
MOVW 0(R13), m
MOVW 4(R13), g
@@ -148,7 +156,7 @@ TEXT clone(SB),7,$0
MOVW 0(m), R0
MOVW 0(g), R0
- BL emptyfunc(SB) // fault if stack check is wrong
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
// Initialize m->procid to Linux tid
MOVW $SYS_gettid, R7
@@ -162,7 +170,7 @@ TEXT clone(SB),7,$0
MOVW $0, R0
MOVW R0, 4(R13)
- BL exit1(SB)
+ BL runtime·exit1(SB)
// It shouldn't return
MOVW $1234, R0
@@ -170,7 +178,7 @@ TEXT clone(SB),7,$0
MOVW R0, (R1)
-TEXT cacheflush(SB),7,$0
+TEXT runtime·cacheflush(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW $0, R2
@@ -178,30 +186,25 @@ TEXT cacheflush(SB),7,$0
SWI $0
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW $SYS_sigaltstack, R7
SWI $0
RET
-TEXT sigignore(SB),7,$0
- RET
-
-TEXT sigreturn(SB),7,$0
- MOVW R0, R0
- B abort(SB)
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigtramp(SB),7,$24
+TEXT runtime·sigtramp(SB),7,$24
MOVW m_gsignal(m), g
MOVW R0, 4(R13)
MOVW R1, 8(R13)
MOVW R2, 12(R13)
- BL sighandler(SB)
+ BL runtime·sighandler(SB)
RET
-TEXT rt_sigaction(SB),7,$0
+TEXT runtime·rt_sigaction(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -210,7 +213,7 @@ TEXT rt_sigaction(SB),7,$0
SWI $0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVW $SYS_rt_sigreturn, R7
SWI $0
RET
diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c
index f3bdb61fa..2044fd60c 100644
--- a/src/pkg/runtime/linux/defs.c
+++ b/src/pkg/runtime/linux/defs.c
@@ -27,6 +27,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c
index 4cfe4a7ed..3c0b110fc 100644
--- a/src/pkg/runtime/linux/defs2.c
+++ b/src/pkg/runtime/linux/defs2.c
@@ -47,6 +47,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c
index 2b197272c..a5897d6d0 100644
--- a/src/pkg/runtime/linux/defs_arm.c
+++ b/src/pkg/runtime/linux/defs_arm.c
@@ -31,6 +31,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
@@ -67,22 +68,22 @@ enum {
$SIGIO = SIGIO,
$SIGPWR = SIGPWR,
$SIGSYS = SIGSYS,
+
+ $FPE_INTDIV = FPE_INTDIV & 0xFFFF,
+ $FPE_INTOVF = FPE_INTOVF & 0xFFFF,
+ $FPE_FLTDIV = FPE_FLTDIV & 0xFFFF,
+ $FPE_FLTOVF = FPE_FLTOVF & 0xFFFF,
+ $FPE_FLTUND = FPE_FLTUND & 0xFFFF,
+ $FPE_FLTRES = FPE_FLTRES & 0xFFFF,
+ $FPE_FLTINV = FPE_FLTINV & 0xFFFF,
+ $FPE_FLTSUB = FPE_FLTSUB & 0xFFFF,
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
+ $BUS_ADRALN = BUS_ADRALN & 0xFFFF,
+ $BUS_ADRERR = BUS_ADRERR & 0xFFFF,
+ $BUS_OBJERR = BUS_OBJERR & 0xFFFF,
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
+ $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF,
+ $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF,
};
typedef sigset_t $Sigset;
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index 7f837bd45..e750f97ea 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -4,26 +4,26 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
void *p;
mstats.sys += n;
- p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096) {
if(p == (void*)EACCES) {
- printf("mmap: access denied\n");
- printf("If you're running SELinux, enable execmem for this process.\n");
- } else {
- printf("mmap: errno=%p\n", p);
+ runtime·printf("mmap: access denied\n");
+ runtime·printf("If you're running SELinux, enable execmem for this process.\n");
+ runtime·exit(2);
}
- exit(2);
+ runtime·printf("mmap: errno=%p\n", p);
+ runtime·throw("mmap");
}
return p;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -31,10 +31,13 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/linux/os.h
index 8ca26b748..772ade7da 100644
--- a/src/pkg/runtime/linux/os.h
+++ b/src/pkg/runtime/linux/os.h
@@ -3,11 +3,11 @@
// license that can be found in the LICENSE file.
// Linux-specific system calls
-int32 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
-int32 clone(int32, void*, M*, G*, void(*)(void));
+int32 runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
-void rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
+void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
-void sigaltstack(Sigaltstack*, Sigaltstack*);
-void sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/linux/runtime_defs.go b/src/pkg/runtime/linux/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/linux/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 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.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h
index 788f68240..1fc5f8c87 100644
--- a/src/pkg/runtime/linux/signals.h
+++ b/src/pkg/runtime/linux/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c
index a849125f9..979260ba1 100644
--- a/src/pkg/runtime/linux/thread.c
+++ b/src/pkg/runtime/linux/thread.c
@@ -6,7 +6,7 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
+extern SigTab runtime·sigtab[];
// Linux futex.
//
@@ -48,7 +48,7 @@ futexsleep(uint32 *addr, uint32 val)
// as an errno. Libpthread ignores the return value
// here, and so can we: as it says a few lines up,
// spurious wakeups are allowed.
- futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+ runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
}
// If any procs are sleeping on addr, wake up at least one.
@@ -57,7 +57,7 @@ futexwakeup(uint32 *addr)
{
int64 ret;
- ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
+ ret = runtime·futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
if(ret >= 0)
return;
@@ -66,11 +66,11 @@ futexwakeup(uint32 *addr)
// EAGAIN or EINTR, but if it does, it would be
// safe to loop and call futex again.
- prints("futexwakeup addr=");
- ·printpointer(addr);
- prints(" returned ");
- ·printint(ret);
- prints("\n");
+ runtime·prints("futexwakeup addr=");
+ runtime·printpointer(addr);
+ runtime·prints(" returned ");
+ runtime·printint(ret);
+ runtime·prints("\n");
*(int32*)0x1006 = 0x1006;
}
@@ -83,7 +83,7 @@ futexwakeup(uint32 *addr)
// 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
+// A reminder: compare-and-swap runtime·cas(addr, old, new) does
// if(*addr == old) { *addr = new; return 1; }
// else return 0;
// but atomically.
@@ -96,7 +96,7 @@ futexlock(Lock *l)
again:
v = l->key;
if((v&1) == 0){
- if(cas(&l->key, v, v|1)){
+ if(runtime·cas(&l->key, v, v|1)){
// Lock wasn't held; we grabbed it.
return;
}
@@ -104,7 +104,7 @@ again:
}
// Lock was held; try to add ourselves to the waiter count.
- if(!cas(&l->key, v, v+2))
+ if(!runtime·cas(&l->key, v, v+2))
goto again;
// We're accounted for, now sleep in the kernel.
@@ -122,8 +122,8 @@ again:
for(;;){
v = l->key;
if(v < 2)
- throw("bad lock key");
- if(cas(&l->key, v, v-2))
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
break;
}
@@ -140,8 +140,8 @@ futexunlock(Lock *l)
again:
v = l->key;
if((v&1) == 0)
- throw("unlock of unlocked lock");
- if(!cas(&l->key, v, v&~1))
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
goto again;
// If there were waiters, wake one.
@@ -150,25 +150,25 @@ again:
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
futexlock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
futexunlock(l);
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock*)
{
}
@@ -186,20 +186,20 @@ destroylock(Lock *l)
// you unlock the lock.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0; // memset(n, 0, sizeof *n)
futexlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
futexunlock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
futexlock(&n->lock);
futexunlock(&n->lock); // Let other sleepers find out too.
@@ -230,7 +230,7 @@ enum
};
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int32 ret;
int32 flags;
@@ -248,50 +248,58 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
m->tls[0] = m->id; // so 386 asm can find it
if(0){
- printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, clone, m->id, m->tls[0], &m);
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·clone, m->id, m->tls[0], &m);
}
- ret = clone(flags, stk, m, g, fn);
+ ret = runtime·clone(flags, stk, m, g, fn);
if(ret < 0)
*(int32*)123 = 123;
}
void
-osinit(void)
+runtime·osinit(void)
{
}
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling.
- m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index 59aeba739..f5ca9f918 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -12,10 +12,10 @@ package runtime
#include "defs.h"
#include "type.h"
-MHeap mheap;
-MStats mstats;
+MHeap runtime·mheap;
+extern MStats mstats; // defined in extern.go
-extern volatile int32 ·MemProfileRate;
+extern volatile int32 runtime·MemProfileRate;
// Same algorithm from chan.c, but a different
// instance of the static uint32 x.
@@ -36,7 +36,7 @@ fastrand1(void)
// Small objects are allocated from the per-thread cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
void*
-mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
+runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
{
int32 sizeclass, rate;
MCache *c;
@@ -45,10 +45,10 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
void *v;
uint32 *ref;
- if(gcwaiting && g != m->g0 && m->locks == 0)
- gosched();
+ if(runtime·gcwaiting && g != m->g0 && m->locks == 0)
+ runtime·gosched();
if(m->mallocing)
- throw("malloc/free - deadlock");
+ runtime·throw("malloc/free - deadlock");
m->mallocing = 1;
if(size == 0)
size = 1;
@@ -56,19 +56,19 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
mstats.nmalloc++;
if(size <= MaxSmallSize) {
// Allocate from mcache free lists.
- sizeclass = SizeToClass(size);
- size = class_to_size[sizeclass];
+ sizeclass = runtime·SizeToClass(size);
+ size = runtime·class_to_size[sizeclass];
c = m->mcache;
- v = MCache_Alloc(c, sizeclass, size, zeroed);
+ v = runtime·MCache_Alloc(c, sizeclass, size, zeroed);
if(v == nil)
- throw("out of memory");
+ runtime·throw("out of memory");
mstats.alloc += size;
mstats.total_alloc += size;
mstats.by_size[sizeclass].nmalloc++;
- if(!mlookup(v, nil, nil, nil, &ref)) {
- printf("malloc %D; mlookup failed\n", (uint64)size);
- throw("malloc mlookup");
+ if(!runtime·mlookup(v, nil, nil, nil, &ref)) {
+ runtime·printf("malloc %D; runtime·mlookup failed\n", (uint64)size);
+ runtime·throw("malloc runtime·mlookup");
}
*ref = RefNone | refflag;
} else {
@@ -78,9 +78,9 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
npages = size >> PageShift;
if((size & PageMask) != 0)
npages++;
- s = MHeap_Alloc(&mheap, npages, 0, 1);
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1);
if(s == nil)
- throw("out of memory");
+ runtime·throw("out of memory");
size = npages<<PageShift;
mstats.alloc += size;
mstats.total_alloc += size;
@@ -93,7 +93,7 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
m->mallocing = 0;
- if(!(refflag & RefNoProfiling) && (rate = ·MemProfileRate) > 0) {
+ if(!(refflag & RefNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
if(size >= rate)
goto profile;
if(m->mcache->next_sample > size)
@@ -105,24 +105,24 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
m->mcache->next_sample = fastrand1() % (2*rate);
profile:
*ref |= RefProfiled;
- MProf_Malloc(v, size);
+ runtime·MProf_Malloc(v, size);
}
}
if(dogc && mstats.heap_alloc >= mstats.next_gc)
- gc(0);
+ runtime·gc(0);
return v;
}
void*
-malloc(uintptr size)
+runtime·malloc(uintptr size)
{
- return mallocgc(size, 0, 0, 1);
+ return runtime·mallocgc(size, 0, 0, 1);
}
// Free the object whose base pointer is v.
void
-free(void *v)
+runtime·free(void *v)
{
int32 sizeclass, size;
MSpan *s;
@@ -133,12 +133,12 @@ free(void *v)
return;
if(m->mallocing)
- throw("malloc/free - deadlock");
+ runtime·throw("malloc/free - deadlock");
m->mallocing = 1;
- if(!mlookup(v, nil, nil, &s, &ref)) {
- printf("free %p: not an allocated block\n", v);
- throw("free mlookup");
+ if(!runtime·mlookup(v, nil, nil, &s, &ref)) {
+ runtime·printf("free %p: not an allocated block\n", v);
+ runtime·throw("free runtime·mlookup");
}
prof = *ref & RefProfiled;
*ref = RefFree;
@@ -148,34 +148,34 @@ free(void *v)
if(sizeclass == 0) {
// Large object.
if(prof)
- MProf_Free(v, s->npages<<PageShift);
+ runtime·MProf_Free(v, s->npages<<PageShift);
mstats.alloc -= s->npages<<PageShift;
- runtime_memclr(v, s->npages<<PageShift);
- MHeap_Free(&mheap, s, 1);
+ runtime·memclr(v, s->npages<<PageShift);
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
} else {
// Small object.
c = m->mcache;
- size = class_to_size[sizeclass];
+ size = runtime·class_to_size[sizeclass];
if(size > sizeof(uintptr))
((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
if(prof)
- MProf_Free(v, size);
+ runtime·MProf_Free(v, size);
mstats.alloc -= size;
mstats.by_size[sizeclass].nfree++;
- MCache_Free(c, v, sizeclass, size);
+ runtime·MCache_Free(c, v, sizeclass, size);
}
m->mallocing = 0;
}
int32
-mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
+runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
{
uintptr n, nobj, i;
byte *p;
MSpan *s;
mstats.nlookup++;
- s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift);
+ s = runtime·MHeap_LookupMaybe(&runtime·mheap, (uintptr)v>>PageShift);
if(sp)
*sp = s;
if(s == nil) {
@@ -206,7 +206,7 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
return 0;
}
- n = class_to_size[s->sizeclass];
+ n = runtime·class_to_size[s->sizeclass];
i = ((byte*)v - p)/n;
if(base)
*base = p + i*n;
@@ -217,12 +217,12 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
if(0) {
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",
+ runtime·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",
+ runtime·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");
+ runtime·throw("bad gcref");
}
}
if(ref)
@@ -232,37 +232,42 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
}
MCache*
-allocmcache(void)
+runtime·allocmcache(void)
{
MCache *c;
- c = FixAlloc_Alloc(&mheap.cachealloc);
- mstats.mcache_inuse = mheap.cachealloc.inuse;
- mstats.mcache_sys = mheap.cachealloc.sys;
+ runtime·lock(&runtime·mheap);
+ c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
+ mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
+ mstats.mcache_sys = runtime·mheap.cachealloc.sys;
+ runtime·unlock(&runtime·mheap);
return c;
}
+int32 runtime·sizeof_C_MStats = sizeof(MStats);
+
void
-mallocinit(void)
+runtime·mallocinit(void)
{
- InitSizes();
- MHeap_Init(&mheap, SysAlloc);
- m->mcache = allocmcache();
+ runtime·SysMemInit();
+ runtime·InitSizes();
+ runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc);
+ m->mcache = runtime·allocmcache();
// See if it works.
- free(malloc(1));
+ runtime·free(runtime·malloc(1));
}
// Runtime stubs.
void*
-mal(uintptr n)
+runtime·mal(uintptr n)
{
- return mallocgc(n, 0, 1, 1);
+ return runtime·mallocgc(n, 0, 1, 1);
}
-func mal(n uint32) (ret *uint8) {
- ret = mal(n);
+func new(n uint32) (ret *uint8) {
+ ret = runtime·mal(n);
}
// Stack allocator uses malloc/free most of the time,
@@ -272,66 +277,66 @@ func mal(n uint32) (ret *uint8) {
// 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 {
+static struct {
Lock;
FixAlloc;
} stacks;
void*
-stackalloc(uint32 n)
+runtime·stackalloc(uint32 n)
{
void *v;
uint32 *ref;
if(m->mallocing || m->gcing) {
- lock(&stacks);
+ runtime·lock(&stacks);
if(stacks.size == 0)
- FixAlloc_Init(&stacks, n, SysAlloc, nil, nil);
+ runtime·FixAlloc_Init(&stacks, n, runtime·SysAlloc, nil, nil);
if(stacks.size != n) {
- printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
- throw("stackalloc");
+ runtime·printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
+ runtime·throw("stackalloc");
}
- v = FixAlloc_Alloc(&stacks);
+ v = runtime·FixAlloc_Alloc(&stacks);
mstats.stacks_inuse = stacks.inuse;
mstats.stacks_sys = stacks.sys;
- unlock(&stacks);
+ runtime·unlock(&stacks);
return v;
}
- v = mallocgc(n, RefNoProfiling, 0, 0);
- if(!mlookup(v, nil, nil, nil, &ref))
- throw("stackalloc mlookup");
+ v = runtime·mallocgc(n, RefNoProfiling, 0, 0);
+ if(!runtime·mlookup(v, nil, nil, nil, &ref))
+ runtime·throw("stackalloc runtime·mlookup");
*ref = RefStack;
return v;
}
void
-stackfree(void *v)
+runtime·stackfree(void *v)
{
if(m->mallocing || m->gcing) {
- lock(&stacks);
- FixAlloc_Free(&stacks, v);
+ runtime·lock(&stacks);
+ runtime·FixAlloc_Free(&stacks, v);
mstats.stacks_inuse = stacks.inuse;
mstats.stacks_sys = stacks.sys;
- unlock(&stacks);
+ runtime·unlock(&stacks);
return;
}
- free(v);
+ runtime·free(v);
}
func Alloc(n uintptr) (p *byte) {
- p = malloc(n);
+ p = runtime·malloc(n);
}
func Free(p *byte) {
- free(p);
+ runtime·free(p);
}
func Lookup(p *byte) (base *byte, size uintptr) {
- mlookup(p, &base, &size, nil, nil);
+ runtime·mlookup(p, &base, &size, nil, nil);
}
func GC() {
- gc(1);
+ runtime·gc(1);
}
func SetFinalizer(obj Eface, finalizer Eface) {
@@ -342,23 +347,23 @@ func SetFinalizer(obj Eface, finalizer Eface) {
Type *t;
if(obj.type == nil) {
- printf("runtime.SetFinalizer: first argument is nil interface\n");
+ runtime·printf("runtime.SetFinalizer: first argument is nil interface\n");
throw:
- throw("runtime.SetFinalizer");
+ runtime·throw("runtime.SetFinalizer");
}
if(obj.type->kind != KindPtr) {
- printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
+ runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
goto throw;
}
- if(!mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) {
- printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
+ if(!runtime·mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) {
+ runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
goto throw;
}
nret = 0;
if(finalizer.type != nil) {
if(finalizer.type->kind != KindFunc) {
badfunc:
- printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+ runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
goto throw;
}
ft = (FuncType*)finalizer.type;
@@ -373,10 +378,10 @@ func SetFinalizer(obj Eface, finalizer Eface) {
}
nret = (nret + sizeof(void*)-1) & ~(sizeof(void*)-1);
- if(getfinalizer(obj.data, 0)) {
- printf("runtime.SetFinalizer: finalizer already set");
+ if(runtime·getfinalizer(obj.data, 0)) {
+ runtime·printf("runtime.SetFinalizer: finalizer already set");
goto throw;
}
}
- addfinalizer(obj.data, finalizer.data, nret);
+ runtime·addfinalizer(obj.data, finalizer.data, nret);
}
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 473e8a836..0cee6c0dd 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -135,10 +135,10 @@ struct MLink
// 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);
-
+void* runtime·SysAlloc(uintptr nbytes);
+void runtime·SysFree(void *v, uintptr nbytes);
+void runtime·SysUnused(void *v, uintptr nbytes);
+void runtime·SysMemInit(void);
// FixAlloc is a simple free-list allocator for fixed size objects.
// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
@@ -161,9 +161,9 @@ struct FixAlloc
uintptr sys; // bytes obtained from system
};
-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);
+void runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void* runtime·FixAlloc_Alloc(FixAlloc *f);
+void runtime·FixAlloc_Free(FixAlloc *f, void *p);
// Statistics.
@@ -183,6 +183,7 @@ struct MStats
uint64 heap_sys; // bytes obtained from system
uint64 heap_idle; // bytes in idle spans
uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_objects; // total number of allocated objects
// Statistics about allocation of low-level fixed-size structures.
// Protected by FixAlloc locks.
@@ -212,7 +213,7 @@ struct MStats
} by_size[NumSizeClasses];
};
-#define mstats ·MemStats /* name shared with Go */
+#define mstats runtime·MemStats /* name shared with Go */
extern MStats mstats;
@@ -229,11 +230,11 @@ extern MStats mstats;
// 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);
+int32 runtime·SizeToClass(int32);
+extern int32 runtime·class_to_size[NumSizeClasses];
+extern int32 runtime·class_to_allocnpages[NumSizeClasses];
+extern int32 runtime·class_to_transfercount[NumSizeClasses];
+extern void runtime·InitSizes(void);
// Per-thread (in Go, per-M) cache for small objects.
@@ -251,12 +252,13 @@ struct MCache
MCacheList list[NumSizeClasses];
uint64 size;
int64 local_alloc; // bytes allocated (or freed) since last lock of heap
+ int64 local_objects; // objects allocated (or freed) since last lock of heap
int32 next_sample; // trigger heap sample after allocating this many bytes
};
-void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
-void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
-void MCache_ReleaseAll(MCache *c);
+void* runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
+void runtime·MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+void runtime·MCache_ReleaseAll(MCache *c);
// An MSpan is a run of pages.
enum
@@ -283,15 +285,15 @@ struct MSpan
};
};
-void MSpan_Init(MSpan *span, PageID start, uintptr npages);
+void runtime·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
+void runtime·MSpanList_Init(MSpan *list);
+bool runtime·MSpanList_IsEmpty(MSpan *list);
+void runtime·MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in
// Central list of free objects of a given size.
@@ -304,9 +306,9 @@ struct MCentral
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);
+void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
+int32 runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *first);
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
@@ -325,10 +327,6 @@ struct MHeap
byte *min;
byte *max;
- // range of addresses we might see in a Native Client closure
- byte *closure_min;
- byte *closure_max;
-
// central free lists for small size classes.
// the union makes sure that the MCentrals are
// spaced 64 bytes apart, so that each MCentral.Lock
@@ -341,22 +339,22 @@ struct MHeap
FixAlloc spanalloc; // allocator for Span*
FixAlloc cachealloc; // allocator for MCache*
};
-extern MHeap mheap;
+extern MHeap runtime·mheap;
-void MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
-MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
-void MHeap_Free(MHeap *h, MSpan *s, int32 acct);
-MSpan* MHeap_Lookup(MHeap *h, PageID p);
-MSpan* MHeap_LookupMaybe(MHeap *h, PageID p);
-void MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
+void runtime·MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+MSpan* runtime·MHeap_Lookup(MHeap *h, PageID p);
+MSpan* runtime·MHeap_LookupMaybe(MHeap *h, PageID p);
+void runtime·MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
-void* mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
-int32 mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
-void gc(int32 force);
+void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
+int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
+void runtime·gc(int32 force);
-void* SysAlloc(uintptr);
-void SysUnused(void*, uintptr);
-void SysFree(void*, uintptr);
+void* runtime·SysAlloc(uintptr);
+void runtime·SysUnused(void*, uintptr);
+void runtime·SysFree(void*, uintptr);
enum
{
@@ -373,8 +371,8 @@ enum
RefFlags = 0xFFFF0000U,
};
-void MProf_Malloc(void*, uintptr);
-void MProf_Free(void*, uintptr);
+void runtime·MProf_Malloc(void*, uintptr);
+void runtime·MProf_Free(void*, uintptr);
// Malloc profiling settings.
// Must match definition in extern.go.
@@ -383,7 +381,7 @@ enum {
MProf_Sample = 1,
MProf_All = 2,
};
-extern int32 malloc_profile;
+extern int32 runtime·malloc_profile;
typedef struct Finalizer Finalizer;
struct Finalizer
@@ -394,4 +392,4 @@ struct Finalizer
int32 nret;
};
-Finalizer* getfinalizer(void*, bool);
+Finalizer* runtime·getfinalizer(void*, bool);
diff --git a/src/pkg/runtime/malloc_defs.go b/src/pkg/runtime/malloc_defs.go
new file mode 100644
index 000000000..bfb96f409
--- /dev/null
+++ b/src/pkg/runtime/malloc_defs.go
@@ -0,0 +1,130 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is malloc.h
+
+package runtime
+
+import "unsafe"
+
+const (
+ pageShift = 12
+ pageSize = 1 << pageShift
+ pageMask = pageSize - 1
+)
+
+type pageID uintptr
+
+const (
+ numSizeClasses = 67
+ maxSmallSize = 32 << 10
+ fixAllocChunk = 128 << 10
+ maxMCacheListLen = 256
+ maxMCacheSize = 2 << 20
+ maxMHeapList = 1 << 8 // 1 << (20 - pageShift)
+ heapAllocChunk = 1 << 20
+)
+
+type mLink struct {
+ next *mLink
+}
+
+type fixAlloc struct {
+ size uintptr
+ alloc func(uintptr)
+ first func(unsafe.Pointer, *byte)
+ arg unsafe.Pointer
+ list *mLink
+ chunk *byte
+ nchunk uint32
+ inuse uintptr
+ sys uintptr
+}
+
+
+// MStats? used to be in extern.go
+
+type mCacheList struct {
+ list *mLink
+ nlist uint32
+ nlistmin uint32
+}
+
+type mCache struct {
+ list [numSizeClasses]mCacheList
+ size uint64
+ local_alloc int64
+ local_objects int64
+ next_sample int32
+}
+
+type mSpan struct {
+ next *mSpan
+ prev *mSpan
+ allnext *mSpan
+ start pageID
+ npages uintptr
+ freelist *mLink
+ ref uint32
+ sizeclass uint32
+ state uint32
+ // union {
+ gcref *uint32 // sizeclass > 0
+ // gcref0 uint32; // sizeclass == 0
+ // }
+}
+
+type mCentral struct {
+ lock
+ sizeclass int32
+ nonempty mSpan
+ empty mSpan
+ nfree int32
+}
+
+type mHeap struct {
+ lock
+ free [maxMHeapList]mSpan
+ large mSpan
+ allspans *mSpan
+ map_ mHeapMap
+ min *byte
+ max *byte
+ closure_min *byte
+ closure_max *byte
+
+ central [numSizeClasses]struct {
+ pad [64]byte
+ // union: mCentral
+ }
+
+ spanalloc fixAlloc
+ cachealloc fixAlloc
+}
+
+const (
+ refFree = iota
+ refStack
+ refNone
+ refSome
+ refcountOverhead = 4
+ refNoPointers = 0x80000000
+ refHasFinalizer = 0x40000000
+ refProfiled = 0x20000000
+ refNoProfiling = 0x10000000
+ refFlags = 0xFFFF0000
+)
+
+const (
+ mProf_None = iota
+ mProf_Sample
+ mProf_All
+)
+
+type finalizer struct {
+ next *finalizer
+ fn func(unsafe.Pointer)
+ arg unsafe.Pointer
+ nret int32
+}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 202936f6e..0f41a0ebc 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -10,7 +10,7 @@
#include "malloc.h"
void*
-MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
+runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
{
MCacheList *l;
MLink *first, *v;
@@ -20,8 +20,8 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
l = &c->list[sizeclass];
if(l->list == nil) {
// Replenish using central lists.
- n = MCentral_AllocList(&mheap.central[sizeclass],
- class_to_transfercount[sizeclass], &first);
+ n = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass],
+ runtime·class_to_transfercount[sizeclass], &first);
l->list = first;
l->nlist = n;
c->size += n*size;
@@ -39,7 +39,7 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
if(zeroed) {
// block is zeroed iff second word is zero ...
if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
- runtime_memclr((byte*)v, size);
+ runtime·memclr((byte*)v, size);
else {
// ... except for the link pointer
// that we used above; zero that.
@@ -47,6 +47,7 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
}
}
c->local_alloc += size;
+ c->local_objects++;
return v;
}
@@ -67,14 +68,14 @@ ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
l->nlist -= n;
if(l->nlist < l->nlistmin)
l->nlistmin = l->nlist;
- c->size -= n*class_to_size[sizeclass];
+ c->size -= n*runtime·class_to_size[sizeclass];
// Return them to central free list.
- MCentral_FreeList(&mheap.central[sizeclass], n, first);
+ runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], n, first);
}
void
-MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
{
int32 i, n;
MCacheList *l;
@@ -88,10 +89,11 @@ MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
l->nlist++;
c->size += size;
c->local_alloc -= size;
+ c->local_objects--;
if(l->nlist >= MaxMCacheListLen) {
// Release a chunk back.
- ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass);
+ ReleaseN(c, l, runtime·class_to_transfercount[sizeclass], sizeclass);
}
if(c->size >= MaxMCacheSize) {
@@ -116,16 +118,11 @@ MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
}
void
-MCache_ReleaseAll(MCache *c)
+runtime·MCache_ReleaseAll(MCache *c)
{
int32 i;
MCacheList *l;
- lock(&mheap);
- mstats.heap_alloc += c->local_alloc;
- c->local_alloc = 0;
- unlock(&mheap);
-
for(i=0; i<NumSizeClasses; i++) {
l = &c->list[i];
ReleaseN(c, l, l->nlist, i);
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 1e1784cc6..8855dc663 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -23,11 +23,11 @@ static void MCentral_Free(MCentral *c, void *v);
// Initialize a single central free list.
void
-MCentral_Init(MCentral *c, int32 sizeclass)
+runtime·MCentral_Init(MCentral *c, int32 sizeclass)
{
c->sizeclass = sizeclass;
- MSpanList_Init(&c->nonempty);
- MSpanList_Init(&c->empty);
+ runtime·MSpanList_Init(&c->nonempty);
+ runtime·MSpanList_Init(&c->empty);
}
// Allocate up to n objects from the central free list.
@@ -35,16 +35,16 @@ MCentral_Init(MCentral *c, int32 sizeclass)
// 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)
+runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
{
MLink *first, *last, *v;
int32 i;
- lock(c);
+ runtime·lock(c);
// Replenish central list if empty.
- if(MSpanList_IsEmpty(&c->nonempty)) {
+ if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
if(!MCentral_Grow(c)) {
- unlock(c);
+ runtime·unlock(c);
*pfirst = nil;
return 0;
}
@@ -61,7 +61,7 @@ MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
last->next = nil;
c->nfree -= i;
- unlock(c);
+ runtime·unlock(c);
*pfirst = first;
return i;
}
@@ -73,15 +73,15 @@ MCentral_Alloc(MCentral *c)
MSpan *s;
MLink *v;
- if(MSpanList_IsEmpty(&c->nonempty))
+ if(runtime·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);
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->empty, s);
}
return v;
}
@@ -91,7 +91,7 @@ MCentral_Alloc(MCentral *c)
// 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)
+runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start)
{
MLink *v, *next;
@@ -100,12 +100,12 @@ MCentral_FreeList(MCentral *c, int32 n, MLink *start)
// the transfer cache optimization in the TODO above.
USED(n);
- lock(c);
+ runtime·lock(c);
for(v=start; v; v=next) {
next = v->next;
MCentral_Free(c, v);
}
- unlock(c);
+ runtime·unlock(c);
}
// Helper: free one object back into the central free list.
@@ -119,14 +119,14 @@ MCentral_Free(MCentral *c, void *v)
// Find span for v.
page = (uintptr)v >> PageShift;
- s = MHeap_Lookup(&mheap, page);
+ s = runtime·MHeap_Lookup(&runtime·mheap, page);
if(s == nil || s->ref == 0)
- throw("invalid free");
+ runtime·throw("invalid free");
// Move to nonempty if necessary.
if(s->freelist == nil) {
- MSpanList_Remove(s);
- MSpanList_Insert(&c->nonempty, s);
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
}
// Add v back to s's free list.
@@ -137,34 +137,34 @@ MCentral_Free(MCentral *c, void *v)
// If s is completely freed, return it to the heap.
if(--s->ref == 0) {
- size = class_to_size[c->sizeclass];
- MSpanList_Remove(s);
+ size = runtime·class_to_size[c->sizeclass];
+ runtime·MSpanList_Remove(s);
// The second word of each freed block indicates
// whether it needs to be zeroed. The first word
// is the link pointer and must always be cleared.
for(p=s->freelist; p; p=next) {
next = p->next;
if(size > sizeof(uintptr) && ((uintptr*)p)[1] != 0)
- runtime_memclr((byte*)p, size);
+ runtime·memclr((byte*)p, size);
else
p->next = nil;
}
s->freelist = nil;
c->nfree -= (s->npages << PageShift) / size;
- unlock(c);
- MHeap_Free(&mheap, s, 0);
- lock(c);
+ runtime·unlock(c);
+ runtime·MHeap_Free(&runtime·mheap, s, 0);
+ runtime·lock(c);
}
}
void
-MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
+runtime·MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
{
int32 size;
int32 npages;
- npages = class_to_allocnpages[sizeclass];
- size = class_to_size[sizeclass];
+ npages = runtime·class_to_allocnpages[sizeclass];
+ size = runtime·class_to_size[sizeclass];
*npagesp = npages;
*sizep = size;
*nobj = (npages << PageShift) / (size + RefcountOverhead);
@@ -180,12 +180,12 @@ MCentral_Grow(MCentral *c)
byte *p;
MSpan *s;
- unlock(c);
- MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
- s = MHeap_Alloc(&mheap, npages, c->sizeclass, 0);
+ runtime·unlock(c);
+ runtime·MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0);
if(s == nil) {
// TODO(rsc): Log out of memory
- lock(c);
+ runtime·lock(c);
return false;
}
@@ -201,8 +201,8 @@ MCentral_Grow(MCentral *c)
}
*tailp = nil;
- lock(c);
+ runtime·lock(c);
c->nfree += n;
- MSpanList_Insert(&c->nonempty, s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
return true;
}
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
index 03c1e1044..f73561b3c 100644
--- a/src/pkg/runtime/mfinal.c
+++ b/src/pkg/runtime/mfinal.c
@@ -5,7 +5,7 @@
#include "runtime.h"
#include "malloc.h"
-Lock finlock;
+static Lock finlock;
// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
// Table size is power of 3 so that hash can be key % max.
@@ -44,7 +44,7 @@ addfintab(Fintab *t, void *k, Finalizer *v)
}
// cannot happen - table is known to be non-full
- throw("finalizer table inconsistent");
+ runtime·throw("finalizer table inconsistent");
ret:
t->key[i] = k;
@@ -77,7 +77,7 @@ lookfintab(Fintab *t, void *k, bool del)
}
// cannot happen - table is known to be non-full
- throw("finalizer table inconsistent");
+ runtime·throw("finalizer table inconsistent");
return nil;
}
@@ -85,7 +85,7 @@ static Fintab fintab;
// add finalizer; caller is responsible for making sure not already in table
void
-addfinalizer(void *p, void (*f)(void*), int32 nret)
+runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
{
Fintab newtab;
int32 i;
@@ -95,28 +95,28 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
e = nil;
if(f != nil) {
- e = mal(sizeof *e);
+ e = runtime·mal(sizeof *e);
e->fn = f;
e->nret = nret;
}
- lock(&finlock);
- if(!mlookup(p, &base, nil, nil, &ref) || p != base) {
- unlock(&finlock);
- throw("addfinalizer on invalid pointer");
+ runtime·lock(&finlock);
+ if(!runtime·mlookup(p, &base, nil, nil, &ref) || p != base) {
+ runtime·unlock(&finlock);
+ runtime·throw("addfinalizer on invalid pointer");
}
if(f == nil) {
if(*ref & RefHasFinalizer) {
lookfintab(&fintab, p, 1);
*ref &= ~RefHasFinalizer;
}
- unlock(&finlock);
+ runtime·unlock(&finlock);
return;
}
if(*ref & RefHasFinalizer) {
- unlock(&finlock);
- throw("double finalizer");
+ runtime·unlock(&finlock);
+ runtime·throw("double finalizer");
}
*ref |= RefHasFinalizer;
@@ -124,7 +124,7 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
// keep table at most 3/4 full:
// allocate new table and rehash.
- runtime_memclr((byte*)&newtab, sizeof newtab);
+ runtime·memclr((byte*)&newtab, sizeof newtab);
newtab.max = fintab.max;
if(newtab.max == 0)
newtab.max = 3*3*3;
@@ -134,8 +134,8 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
newtab.max *= 3;
}
- newtab.key = mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
- newtab.val = mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+ newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
+ newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
for(i=0; i<fintab.max; i++) {
void *k;
@@ -144,39 +144,39 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
if(k != nil && k != (void*)-1)
addfintab(&newtab, k, fintab.val[i]);
}
- free(fintab.key);
- free(fintab.val);
+ runtime·free(fintab.key);
+ runtime·free(fintab.val);
fintab = newtab;
}
addfintab(&fintab, p, e);
- unlock(&finlock);
+ runtime·unlock(&finlock);
}
// get finalizer; if del, delete finalizer.
// caller is responsible for updating RefHasFinalizer bit.
Finalizer*
-getfinalizer(void *p, bool del)
+runtime·getfinalizer(void *p, bool del)
{
Finalizer *f;
- lock(&finlock);
+ runtime·lock(&finlock);
f = lookfintab(&fintab, p, del);
- unlock(&finlock);
+ runtime·unlock(&finlock);
return f;
}
void
-walkfintab(void (*fn)(void*))
+runtime·walkfintab(void (*fn)(void*))
{
void **key;
void **ekey;
- lock(&finlock);
+ runtime·lock(&finlock);
key = fintab.key;
ekey = key + fintab.max;
for(; key < ekey; key++)
if(*key != nil && *key != ((void*)-1))
fn(*key);
- unlock(&finlock);
+ runtime·unlock(&finlock);
}
diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c
index 8347a1539..ab9df3196 100644
--- a/src/pkg/runtime/mfixalloc.c
+++ b/src/pkg/runtime/mfixalloc.c
@@ -12,7 +12,7 @@
// 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)
+runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
{
f->size = size;
f->alloc = alloc;
@@ -26,7 +26,7 @@ FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(
}
void*
-FixAlloc_Alloc(FixAlloc *f)
+runtime·FixAlloc_Alloc(FixAlloc *f)
{
void *v;
@@ -40,7 +40,7 @@ FixAlloc_Alloc(FixAlloc *f)
f->sys += FixAllocChunk;
f->chunk = f->alloc(FixAllocChunk);
if(f->chunk == nil)
- throw("out of memory (FixAlloc)");
+ runtime·throw("out of memory (FixAlloc)");
f->nchunk = FixAllocChunk;
}
v = f->chunk;
@@ -53,7 +53,7 @@ FixAlloc_Alloc(FixAlloc *f)
}
void
-FixAlloc_Free(FixAlloc *f, void *p)
+runtime·FixAlloc_Free(FixAlloc *f, void *p)
{
f->inuse -= f->size;
*(void**)p = f->list;
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 2324eff29..6dcb61091 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -19,6 +19,13 @@ enum {
Debug = 0
};
+typedef struct BlockList BlockList;
+struct BlockList
+{
+ byte *obj;
+ uintptr size;
+};
+
extern byte data[];
extern byte etext[];
extern byte end[];
@@ -26,8 +33,8 @@ extern byte end[];
static G *fing;
static Finalizer *finq;
static int32 fingwait;
+static BlockList *bl, *ebl;
-static void sweepblock(byte*, int64, uint32*, int32);
static void runfinq(void);
enum {
@@ -35,7 +42,7 @@ enum {
};
static void
-scanblock(int32 depth, byte *b, int64 n)
+scanblock(byte *b, int64 n)
{
int32 off;
void *obj;
@@ -43,48 +50,49 @@ scanblock(int32 depth, byte *b, int64 n)
uint32 *refp, ref;
void **vp;
int64 i;
-
- if(Debug > 1)
- 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++) {
- obj = vp[i];
- if(obj == nil)
- continue;
- if(mheap.closure_min != nil && mheap.closure_min <= (byte*)obj && (byte*)obj < mheap.closure_max) {
- if((((uintptr)obj) & 63) != 0)
- continue;
-
- // Looks like a Native Client closure.
- // Actual pointer is pointed at by address in first instruction.
- // Embedded pointer starts at byte 2.
- // If it is f4f4f4f4 then that space hasn't been
- // used for a closure yet (f4 is the HLT instruction).
- // See nacl/386/closure.c for more.
- void **pp;
- pp = *(void***)((byte*)obj+2);
- if(pp == (void**)0xf4f4f4f4) // HLT... - not a closure after all
- continue;
- obj = *pp;
+ BlockList *w;
+
+ w = bl;
+ w->obj = b;
+ w->size = n;
+ w++;
+
+ while(w > bl) {
+ w--;
+ b = w->obj;
+ n = w->size;
+
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D\n", b, n);
+ off = (uint32)(uintptr)b & (PtrSize-1);
+ if(off) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
}
- if(mheap.min <= (byte*)obj && (byte*)obj < mheap.max) {
- if(mlookup(obj, &obj, &size, nil, &refp)) {
- ref = *refp;
- switch(ref & ~RefFlags) {
- case RefNone:
- if(Debug > 1)
- printf("%d found at %p: ", depth, &vp[i]);
- *refp = RefSome | (ref & RefFlags);
- if(!(ref & RefNoPointers))
- scanblock(depth+1, obj, size);
- break;
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ obj = vp[i];
+ if(obj == nil)
+ continue;
+ if(runtime·mheap.min <= (byte*)obj && (byte*)obj < runtime·mheap.max) {
+ if(runtime·mlookup(obj, &obj, &size, nil, &refp)) {
+ ref = *refp;
+ switch(ref & ~RefFlags) {
+ case RefNone:
+ if(Debug > 1)
+ runtime·printf("found at %p: ", &vp[i]);
+ *refp = RefSome | (ref & RefFlags);
+ if(!(ref & RefNoPointers)) {
+ if(w >= ebl)
+ runtime·throw("scanblock: garbage collection stack overflow");
+ w->obj = obj;
+ w->size = size;
+ w++;
+ }
+ break;
+ }
}
}
}
@@ -102,10 +110,10 @@ scanstack(G *gp)
else
sp = gp->sched.sp;
if(Debug > 1)
- printf("scanstack %d %p\n", gp->goid, sp);
+ runtime·printf("scanstack %d %p\n", gp->goid, sp);
stk = (Stktop*)gp->stackbase;
while(stk) {
- scanblock(0, sp, (byte*)stk - sp);
+ scanblock(sp, (byte*)stk - sp);
sp = stk->gobuf.sp;
stk = (Stktop*)stk->stackbase;
}
@@ -119,36 +127,57 @@ markfin(void *v)
size = 0;
refp = nil;
- if(!mlookup(v, &v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
- throw("mark - finalizer inconsistency");
+ if(!runtime·mlookup(v, &v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
+ runtime·throw("mark - finalizer inconsistency");
// do not mark the finalizer block itself. just mark the things it points at.
- scanblock(1, v, size);
+ scanblock(v, size);
}
static void
mark(void)
{
G *gp;
+ uintptr blsize, nobj;
+
+ // Figure out how big an object stack we need.
+ // Get a new one if we need more than we have
+ // or we need significantly less than we have.
+ nobj = mstats.heap_objects;
+ if(nobj > ebl - bl || nobj < (ebl-bl)/4) {
+ if(bl != nil)
+ runtime·SysFree(bl, (byte*)ebl - (byte*)bl);
+
+ // While we're allocated a new object stack,
+ // add 20% headroom and also round up to
+ // the nearest page boundary, since mmap
+ // will anyway.
+ nobj = nobj * 12/10;
+ blsize = nobj * sizeof *bl;
+ blsize = (blsize + 4095) & ~4095;
+ nobj = blsize / sizeof *bl;
+ bl = runtime·SysAlloc(blsize);
+ ebl = bl + nobj;
+ }
// mark data+bss.
- // skip mheap itself, which has no interesting pointers
+ // skip runtime·mheap itself, which has no interesting pointers
// and is mostly zeroed and would not otherwise be paged in.
- scanblock(0, data, (byte*)&mheap - data);
- scanblock(0, (byte*)(&mheap+1), end - (byte*)(&mheap+1));
+ scanblock(data, (byte*)&runtime·mheap - data);
+ scanblock((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1));
// mark stacks
- for(gp=allg; gp!=nil; gp=gp->alllink) {
+ for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
switch(gp->status){
default:
- printf("unexpected G.status %d\n", gp->status);
- throw("mark - bad status");
+ runtime·printf("unexpected G.status %d\n", gp->status);
+ runtime·throw("mark - bad status");
case Gdead:
break;
case Grunning:
case Grecovery:
if(gp != g)
- throw("mark - world not stopped");
+ runtime·throw("mark - world not stopped");
scanstack(gp);
break;
case Grunnable:
@@ -160,7 +189,7 @@ mark(void)
}
// mark things pointed at by objects with finalizers
- walkfintab(markfin);
+ runtime·walkfintab(markfin);
}
// free RefNone, free & queue finalizers for RefNone|RefHasFinalizer, reset RefSome
@@ -181,16 +210,16 @@ sweepspan(MSpan *s)
case RefNone:
// Free large object.
mstats.alloc -= s->npages<<PageShift;
- runtime_memclr(p, s->npages<<PageShift);
+ runtime·memclr(p, s->npages<<PageShift);
if(ref & RefProfiled)
- MProf_Free(p, s->npages<<PageShift);
+ runtime·MProf_Free(p, s->npages<<PageShift);
s->gcref0 = RefFree;
- MHeap_Free(&mheap, s, 1);
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
break;
case RefNone|RefHasFinalizer:
- f = getfinalizer(p, 1);
+ f = runtime·getfinalizer(p, 1);
if(f == nil)
- throw("finalizer inconsistency");
+ runtime·throw("finalizer inconsistency");
f->arg = p;
f->next = finq;
finq = f;
@@ -205,7 +234,7 @@ sweepspan(MSpan *s)
}
// Chunk full of small blocks.
- MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
+ runtime·MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
gcrefp = s->gcref;
gcrefep = s->gcref + n;
for(; gcrefp < gcrefep; gcrefp++, p += size) {
@@ -216,19 +245,19 @@ sweepspan(MSpan *s)
case RefNone:
// Free small object.
if(ref & RefProfiled)
- MProf_Free(p, size);
+ runtime·MProf_Free(p, size);
*gcrefp = RefFree;
c = m->mcache;
if(size > sizeof(uintptr))
((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
mstats.alloc -= size;
mstats.by_size[s->sizeclass].nfree++;
- MCache_Free(c, p, s->sizeclass, size);
+ runtime·MCache_Free(c, p, s->sizeclass, size);
break;
case RefNone|RefHasFinalizer:
- f = getfinalizer(p, 1);
+ f = runtime·getfinalizer(p, 1);
if(f == nil)
- throw("finalizer inconsistency");
+ runtime·throw("finalizer inconsistency");
f->arg = p;
f->next = finq;
finq = f;
@@ -247,7 +276,7 @@ sweep(void)
{
MSpan *s;
- for(s = mheap.allspans; s != nil; s = s->allnext)
+ for(s = runtime·mheap.allspans; s != nil; s = s->allnext)
if(s->state == MSpanInUse)
sweepspan(s);
}
@@ -273,12 +302,27 @@ stealcache(void)
{
M *m;
- for(m=allm; m; m=m->alllink)
- MCache_ReleaseAll(m->mcache);
+ for(m=runtime·allm; m; m=m->alllink)
+ runtime·MCache_ReleaseAll(m->mcache);
+}
+
+static void
+cachestats(void)
+{
+ M *m;
+ MCache *c;
+
+ for(m=runtime·allm; m; m=m->alllink) {
+ c = m->mcache;
+ mstats.heap_alloc += c->local_alloc;
+ c->local_alloc = 0;
+ mstats.heap_objects += c->local_objects;
+ c->local_objects = 0;
+ }
}
void
-gc(int32 force)
+runtime·gc(int32 force)
{
int64 t0, t1;
byte *p;
@@ -292,28 +336,29 @@ gc(int32 force)
// 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)
+ if(!mstats.enablegc || m->locks > 0 || runtime·panicking)
return;
if(gcpercent == -2) { // first time through
- p = getenv("GOGC");
+ p = runtime·getenv("GOGC");
if(p == nil || p[0] == '\0')
gcpercent = 100;
- else if(strcmp(p, (byte*)"off") == 0)
+ else if(runtime·strcmp(p, (byte*)"off") == 0)
gcpercent = -1;
else
- gcpercent = atoi(p);
+ gcpercent = runtime·atoi(p);
}
if(gcpercent < 0)
return;
- semacquire(&gcsema);
- t0 = nanotime();
+ runtime·semacquire(&gcsema);
+ t0 = runtime·nanotime();
m->gcing = 1;
- stoptheworld();
- if(mheap.Lock.key != 0)
- throw("mheap locked during gc");
+ runtime·stoptheworld();
+ if(runtime·mheap.Lock.key != 0)
+ runtime·throw("runtime·mheap locked during gc");
if(force || mstats.heap_alloc >= mstats.next_gc) {
+ cachestats();
mark();
sweep();
stealcache();
@@ -326,25 +371,25 @@ gc(int32 force)
if(fp != nil) {
// kick off or wake up goroutine to run queued finalizers
if(fing == nil)
- fing = newproc1((byte*)runfinq, nil, 0, 0);
+ fing = runtime·newproc1((byte*)runfinq, nil, 0, 0);
else if(fingwait) {
fingwait = 0;
- ready(fing);
+ runtime·ready(fing);
}
}
m->locks--;
- t1 = nanotime();
+ t1 = runtime·nanotime();
mstats.numgc++;
mstats.pause_ns += t1 - t0;
if(mstats.debuggc)
- printf("pause %D\n", t1-t0);
- semrelease(&gcsema);
- starttheworld();
+ runtime·printf("pause %D\n", t1-t0);
+ runtime·semrelease(&gcsema);
+ runtime·starttheworld();
// give the queued finalizers, if any, a chance to run
if(fp != nil)
- gosched();
+ runtime·gosched();
}
static void
@@ -365,20 +410,20 @@ runfinq(void)
if(f == nil) {
fingwait = 1;
g->status = Gwaiting;
- gosched();
+ runtime·gosched();
continue;
}
for(; f; f=next) {
next = f->next;
- frame = mal(sizeof(uintptr) + f->nret);
+ frame = runtime·mal(sizeof(uintptr) + f->nret);
*(void**)frame = f->arg;
reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret);
- free(frame);
+ runtime·free(frame);
f->fn = nil;
f->arg = nil;
f->next = nil;
- free(f);
+ runtime·free(f);
}
- gc(1); // trigger another gc to clean up the finalized objects, if possible
+ runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
}
}
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index 44817ddd5..4bb7f14e3 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -35,38 +35,42 @@ RecordSpan(void *vh, byte *p)
// Initialize the heap; fetch memory using alloc.
void
-MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+runtime·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);
+ runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+ runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+ runtime·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);
+ runtime·MSpanList_Init(&h->free[i]);
+ runtime·MSpanList_Init(&h->large);
for(i=0; i<nelem(h->central); i++)
- MCentral_Init(&h->central[i], i);
+ runtime·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, int32 acct)
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
{
MSpan *s;
- lock(h);
+ runtime·lock(h);
mstats.heap_alloc += m->mcache->local_alloc;
m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
mstats.heap_inuse += npage<<PageShift;
- if(acct)
+ if(acct) {
+ mstats.heap_objects++;
mstats.heap_alloc += npage<<PageShift;
+ }
}
- unlock(h);
+ runtime·unlock(h);
return s;
}
@@ -78,7 +82,7 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
// Try in fixed-size lists up to max.
for(n=npage; n < nelem(h->free); n++) {
- if(!MSpanList_IsEmpty(&h->free[n])) {
+ if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
s = h->free[n].next;
goto HaveSpan;
}
@@ -95,22 +99,22 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
HaveSpan:
// Mark span in use.
if(s->state != MSpanFree)
- throw("MHeap_AllocLocked - MSpan not free");
+ runtime·throw("MHeap_AllocLocked - MSpan not free");
if(s->npages < npage)
- throw("MHeap_AllocLocked - bad npages");
- MSpanList_Remove(s);
+ runtime·throw("MHeap_AllocLocked - bad npages");
+ runtime·MSpanList_Remove(s);
s->state = MSpanInUse;
if(s->npages > npage) {
// Trim extra and put it back in the heap.
- t = FixAlloc_Alloc(&h->spanalloc);
+ t = runtime·FixAlloc_Alloc(&h->spanalloc);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
- MSpan_Init(t, s->start + npage, s->npages - npage);
+ runtime·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);
+ runtime·MHeapMap_Set(&h->map, t->start - 1, s);
+ runtime·MHeapMap_Set(&h->map, t->start, t);
+ runtime·MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
t->state = MSpanInUse;
MHeap_FreeLocked(h, t);
}
@@ -119,7 +123,7 @@ HaveSpan:
// 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);
+ runtime·MHeapMap_Set(&h->map, s->start+n, s);
return s;
}
@@ -161,17 +165,17 @@ MHeap_Grow(MHeap *h, uintptr npage)
// 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.
- // For Native Client, allocate a multiple of 64kB (16 pages).
+ // Allocate a multiple of 64kB (16 pages).
npage = (npage+15)&~15;
ask = npage<<PageShift;
if(ask < HeapAllocChunk)
ask = HeapAllocChunk;
- v = SysAlloc(ask);
+ v = runtime·SysAlloc(ask);
if(v == nil) {
if(ask > (npage<<PageShift)) {
ask = npage<<PageShift;
- v = SysAlloc(ask);
+ v = runtime·SysAlloc(ask);
}
if(v == nil)
return false;
@@ -186,19 +190,19 @@ MHeap_Grow(MHeap *h, uintptr npage)
// 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);
+ if(!runtime·MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+ runtime·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);
+ s = runtime·FixAlloc_Alloc(&h->spanalloc);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
- 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);
+ runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+ runtime·MHeapMap_Set(&h->map, s->start, s);
+ runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
s->state = MSpanInUse;
MHeap_FreeLocked(h, s);
return true;
@@ -208,9 +212,9 @@ MHeap_Grow(MHeap *h, uintptr npage)
// 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)
+runtime·MHeap_Lookup(MHeap *h, PageID p)
{
- return MHeapMap_Get(&h->map, p);
+ return runtime·MHeapMap_Get(&h->map, p);
}
// Look up the span at the given page number.
@@ -221,11 +225,11 @@ MHeap_Lookup(MHeap *h, PageID p)
// other garbage in their middles, so we have to
// check for that.
MSpan*
-MHeap_LookupMaybe(MHeap *h, PageID p)
+runtime·MHeap_LookupMaybe(MHeap *h, PageID p)
{
MSpan *s;
- s = MHeapMap_GetMaybe(&h->map, p);
+ s = runtime·MHeapMap_GetMaybe(&h->map, p);
if(s == nil || p < s->start || p - s->start >= s->npages)
return nil;
if(s->state != MSpanInUse)
@@ -235,16 +239,20 @@ MHeap_LookupMaybe(MHeap *h, PageID p)
// Free the span back into the heap.
void
-MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
{
- lock(h);
+ runtime·lock(h);
mstats.heap_alloc += m->mcache->local_alloc;
m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
mstats.heap_inuse -= s->npages<<PageShift;
- if(acct)
+ if(acct) {
mstats.heap_alloc -= s->npages<<PageShift;
+ mstats.heap_objects--;
+ }
MHeap_FreeLocked(h, s);
- unlock(h);
+ runtime·unlock(h);
}
static void
@@ -253,45 +261,45 @@ 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");
+ runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ runtime·throw("MHeap_FreeLocked - invalid free");
}
s->state = MSpanFree;
- MSpanList_Remove(s);
+ runtime·MSpanList_Remove(s);
// Coalesce with earlier, later spans.
- if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
+ if((t = runtime·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);
+ runtime·MHeapMap_Set(&h->map, s->start, s);
+ runtime·MSpanList_Remove(t);
t->state = MSpanDead;
- FixAlloc_Free(&h->spanalloc, t);
+ runtime·FixAlloc_Free(&h->spanalloc, t);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
}
- if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
+ if((t = runtime·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);
+ runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ runtime·MSpanList_Remove(t);
t->state = MSpanDead;
- FixAlloc_Free(&h->spanalloc, t);
+ runtime·FixAlloc_Free(&h->spanalloc, t);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
}
// Insert s into appropriate list.
if(s->npages < nelem(h->free))
- MSpanList_Insert(&h->free[s->npages], s);
+ runtime·MSpanList_Insert(&h->free[s->npages], s);
else
- MSpanList_Insert(&h->large, s);
+ runtime·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)
+runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
{
span->next = nil;
span->prev = nil;
@@ -305,7 +313,7 @@ MSpan_Init(MSpan *span, PageID start, uintptr npages)
// Initialize an empty doubly-linked list.
void
-MSpanList_Init(MSpan *list)
+runtime·MSpanList_Init(MSpan *list)
{
list->state = MSpanListHead;
list->next = list;
@@ -313,7 +321,7 @@ MSpanList_Init(MSpan *list)
}
void
-MSpanList_Remove(MSpan *span)
+runtime·MSpanList_Remove(MSpan *span)
{
if(span->prev == nil && span->next == nil)
return;
@@ -324,16 +332,16 @@ MSpanList_Remove(MSpan *span)
}
bool
-MSpanList_IsEmpty(MSpan *list)
+runtime·MSpanList_IsEmpty(MSpan *list)
{
return list->next == list;
}
void
-MSpanList_Insert(MSpan *list, MSpan *span)
+runtime·MSpanList_Insert(MSpan *list, MSpan *span)
{
if(span->next != nil || span->prev != nil)
- throw("MSpanList_Insert");
+ runtime·throw("MSpanList_Insert");
span->next = list->next;
span->prev = list;
span->next->prev = span;
diff --git a/src/pkg/runtime/mheapmap32.c b/src/pkg/runtime/mheapmap32.c
index 4481e11f6..323f8b87a 100644
--- a/src/pkg/runtime/mheapmap32.c
+++ b/src/pkg/runtime/mheapmap32.c
@@ -10,13 +10,13 @@
// 3-level radix tree mapping page ids to Span*.
void
-MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
{
m->allocator = allocator;
}
MSpan*
-MHeapMap_Get(MHeapMap *m, PageID k)
+runtime·MHeapMap_Get(MHeapMap *m, PageID k)
{
int32 i1, i2;
@@ -25,13 +25,13 @@ MHeapMap_Get(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
return m->p[i1]->s[i2];
}
MSpan*
-MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k)
{
int32 i1, i2;
MHeapMapNode2 *p2;
@@ -41,7 +41,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
p2 = m->p[i1];
if(p2 == nil)
@@ -50,7 +50,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
}
void
-MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
{
int32 i1, i2;
@@ -59,7 +59,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Set");
+ runtime·throw("MHeapMap_Set");
m->p[i1]->s[i2] = s;
}
@@ -67,7 +67,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *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)
+runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
{
uintptr end;
int32 i1;
diff --git a/src/pkg/runtime/mheapmap32.h b/src/pkg/runtime/mheapmap32.h
index cb8a830d0..29e619071 100644
--- a/src/pkg/runtime/mheapmap32.h
+++ b/src/pkg/runtime/mheapmap32.h
@@ -32,10 +32,10 @@ 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);
+void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
diff --git a/src/pkg/runtime/mheapmap32_defs.go b/src/pkg/runtime/mheapmap32_defs.go
new file mode 100644
index 000000000..755725b46
--- /dev/null
+++ b/src/pkg/runtime/mheapmap32_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 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 runtime
+
+const (
+ mHeapMap_Level1Bits = 10
+ mHeapMap_Level2Bits = 10
+ mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits
+
+ mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1
+ mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+type mHeapMapNode2 struct {
+ s [1 << mHeapMap_Level2Bits]*mSpan
+}
diff --git a/src/pkg/runtime/mheapmap64.c b/src/pkg/runtime/mheapmap64.c
index d5590a2d8..e45ac9413 100644
--- a/src/pkg/runtime/mheapmap64.c
+++ b/src/pkg/runtime/mheapmap64.c
@@ -10,13 +10,13 @@
// 3-level radix tree mapping page ids to Span*.
void
-MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
{
m->allocator = allocator;
}
MSpan*
-MHeapMap_Get(MHeapMap *m, PageID k)
+runtime·MHeapMap_Get(MHeapMap *m, PageID k)
{
int32 i1, i2, i3;
@@ -27,13 +27,13 @@ MHeapMap_Get(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
return m->p[i1]->p[i2]->s[i3];
}
MSpan*
-MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k)
{
int32 i1, i2, i3;
MHeapMapNode2 *p2;
@@ -46,7 +46,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
p2 = m->p[i1];
if(p2 == nil)
@@ -58,7 +58,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
}
void
-MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
{
int32 i1, i2, i3;
@@ -69,7 +69,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Set");
+ runtime·throw("MHeapMap_Set");
m->p[i1]->p[i2]->s[i3] = s;
}
@@ -77,7 +77,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *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)
+runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
{
uintptr end;
int32 i1, i2;
diff --git a/src/pkg/runtime/mheapmap64.h b/src/pkg/runtime/mheapmap64.h
index fefeae65d..a9934d2b1 100644
--- a/src/pkg/runtime/mheapmap64.h
+++ b/src/pkg/runtime/mheapmap64.h
@@ -51,10 +51,10 @@ 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);
+void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
diff --git a/src/pkg/runtime/mheapmap64_defs.go b/src/pkg/runtime/mheapmap64_defs.go
new file mode 100644
index 000000000..d7ba2b420
--- /dev/null
+++ b/src/pkg/runtime/mheapmap64_defs.go
@@ -0,0 +1,31 @@
+// Copyright 2010 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 runtime
+
+const (
+ 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
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+
+type mHeapMapNode2 struct {
+ p [1 << mHeapMap_Level2Bits]*mHeapMapNode3
+}
+
+
+type mHeapMapNode3 struct {
+ s [1 << mHeapMap_Level3Bits]*mSpan
+}
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index aae773cfe..3ed5f74c9 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -16,14 +16,44 @@ case "$GOARCH" in
# The offsets 0 and 4 are also known to:
# nacl/thread.c:/^newosproc
# ../../cmd/8l/pass.c:/D_GS
- # ../../libcgo/linux_386.c:/^start
- # ../../libcgo/darwin_386.c:/^start
+ # ../../libcgo/linux_386.c:/^threadentry
+ # ../../libcgo/darwin_386.c:/^threadentry
case "$GOOS" in
windows)
echo '#define get_tls(r) MOVL 0x2c(FS), r'
echo '#define g(r) 0(r)'
echo '#define m(r) 4(r)'
;;
+ plan9)
+ echo '#define get_tls(r)'
+ echo '#define g(r) 0xdfffefc0'
+ echo '#define m(r) 0xdfffefc4'
+ ;;
+ linux)
+ # On Linux systems, what we call 0(GS) and 4(GS) for g and m
+ # turn into %gs:-8 and %gs:-4 (using gcc syntax to denote
+ # what the machine sees as opposed to 8l input).
+ # 8l rewrites 0(GS) and 4(GS) into these.
+ #
+ # On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4
+ # directly. Instead, we have to store %gs:0 into a temporary
+ # register and then use -8(%reg) and -4(%reg). This kind
+ # of addressing is correct even when not running Xen.
+ #
+ # 8l can rewrite MOVL 0(GS), CX into the appropriate pair
+ # of mov instructions, using CX as the intermediate register
+ # (safe because CX is about to be written to anyway).
+ # But 8l cannot handle other instructions, like storing into 0(GS),
+ # which is where these macros come into play.
+ # get_tls sets up the temporary and then g and r use it.
+ #
+ # The final wrinkle is that get_tls needs to read from %gs:0,
+ # but in 8l input it's called 8(GS), because 8l is going to
+ # subtract 8 from all the offsets, as described above.
+ echo '#define get_tls(r) MOVL 8(GS), r'
+ echo '#define g(r) -8(r)'
+ echo '#define m(r) -4(r)'
+ ;;
*)
echo '#define get_tls(r)'
echo '#define g(r) 0(GS)'
@@ -32,10 +62,14 @@ case "$GOARCH" in
esac
;;
amd64)
- # These registers are also known to:
- # ../../libcgo/linux_amd64.c:/^start
- echo '#define g R15'
- echo '#define m R14'
+ # The offsets 0 and 8 are known to:
+ # ../../cmd/6l/pass.c:/D_GS
+ # ../../libcgo/linux_amd64.c:/^threadentry
+ # ../../libcgo/darwin_amd64.c:/^threadentry
+ #
+ echo '#define get_tls(r)'
+ echo '#define g(r) 0(GS)'
+ echo '#define m(r) 8(GS)'
;;
arm)
echo '#define g R10'
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
index bf33c0f85..9790d3f09 100644
--- a/src/pkg/runtime/mkversion.c
+++ b/src/pkg/runtime/mkversion.c
@@ -5,11 +5,13 @@ char *template =
"// generated by mkversion.c; do not edit.\n"
"package runtime\n"
"const defaultGoroot = \"%s\"\n"
- "const defaultVersion = \"%s\"\n";
+ "const theVersion = \"%s\"\n"
+ "const theGoarch = \"%s\"\n"
+ "const theGoos = \"%s\"\n";
void
main(void)
{
- print(template, getgoroot(), getgoversion());
+ print(template, getgoroot(), getgoversion(), getgoarch(), getgoos());
exits(0);
}
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 61a5132b7..f4581e98d 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -45,7 +45,7 @@ stkbucket(uintptr *stk, int32 nstk)
Bucket *b;
if(buckhash == nil) {
- buckhash = SysAlloc(BuckHashSize*sizeof buckhash[0]);
+ buckhash = runtime·SysAlloc(BuckHashSize*sizeof buckhash[0]);
mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
}
@@ -62,12 +62,12 @@ stkbucket(uintptr *stk, int32 nstk)
i = h%BuckHashSize;
for(b = buckhash[i]; b; b=b->next)
if(b->hash == h && b->nstk == nstk &&
- mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
+ runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
- b = mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
+ b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
bucketmem += sizeof *b + nstk*sizeof stk[0];
- memmove(b->stk, stk, nstk*sizeof stk[0]);
+ runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
b->hash = h;
b->nstk = nstk;
b->next = buckhash[i];
@@ -132,7 +132,7 @@ setaddrbucket(uintptr addr, Bucket *b)
if(ah->addr == (addr>>20))
goto found;
- ah = mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
+ ah = runtime·mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
addrmem += sizeof *ah;
ah->next = addrhash[h];
ah->addr = addr>>20;
@@ -140,7 +140,7 @@ setaddrbucket(uintptr addr, Bucket *b)
found:
if((e = addrfree) == nil) {
- e = mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
+ e = runtime·mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
addrmem += 64*sizeof *e;
for(i=0; i+1<64; i++)
e[i].next = &e[i+1];
@@ -185,7 +185,7 @@ found:
// Called by malloc to record a profiled block.
void
-MProf_Malloc(void *p, uintptr size)
+runtime·MProf_Malloc(void *p, uintptr size)
{
int32 nstk;
uintptr stk[32];
@@ -195,19 +195,19 @@ MProf_Malloc(void *p, uintptr size)
return;
m->nomemprof++;
- nstk = callers(1, stk, 32);
- lock(&proflock);
+ nstk = runtime·callers(1, stk, 32);
+ runtime·lock(&proflock);
b = stkbucket(stk, nstk);
b->allocs++;
b->alloc_bytes += size;
setaddrbucket((uintptr)p, b);
- unlock(&proflock);
+ runtime·unlock(&proflock);
m->nomemprof--;
}
// Called when freeing a profiled block.
void
-MProf_Free(void *p, uintptr size)
+runtime·MProf_Free(void *p, uintptr size)
{
Bucket *b;
@@ -215,13 +215,13 @@ MProf_Free(void *p, uintptr size)
return;
m->nomemprof++;
- lock(&proflock);
+ runtime·lock(&proflock);
b = getaddrbucket((uintptr)p);
if(b != nil) {
b->frees++;
b->free_bytes += size;
}
- unlock(&proflock);
+ runtime·unlock(&proflock);
m->nomemprof--;
}
@@ -257,7 +257,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
Bucket *b;
Record *r;
- lock(&proflock);
+ runtime·lock(&proflock);
n = 0;
for(b=buckets; b; b=b->allnext)
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
@@ -270,5 +270,5 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
record(r++, b);
}
- unlock(&proflock);
+ runtime·unlock(&proflock);
}
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index aebc15416..ec85eb373 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -28,9 +28,9 @@
#include "runtime.h"
#include "malloc.h"
-int32 class_to_size[NumSizeClasses];
-int32 class_to_allocnpages[NumSizeClasses];
-int32 class_to_transfercount[NumSizeClasses];
+int32 runtime·class_to_size[NumSizeClasses];
+int32 runtime·class_to_allocnpages[NumSizeClasses];
+int32 runtime·class_to_transfercount[NumSizeClasses];
// The SizeToClass lookup is implemented using two arrays,
// one mapping sizes <= 1024 to their class and one mapping
@@ -45,24 +45,24 @@ static int32 size_to_class8[1024/8 + 1];
static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
int32
-SizeToClass(int32 size)
+runtime·SizeToClass(int32 size)
{
if(size > MaxSmallSize)
- throw("SizeToClass - invalid size");
+ runtime·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)
+runtime·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;
+ // Initialize the runtime·class_to_size table (and choose class sizes in the process).
+ runtime·class_to_size[0] = 0;
sizeclass = 1; // 0 means no class
align = 8;
for(size = align; size <= MaxSmallSize; size += align) {
@@ -75,7 +75,7 @@ InitSizes(void)
align = 16; // required for x86 SSE instructions, if we want to use them
}
if((align&(align-1)) != 0)
- throw("InitSizes - bug");
+ runtime·throw("InitSizes - bug");
// Make the allocnpages big enough that
// the leftover is less than 1/8 of the total,
@@ -92,78 +92,78 @@ InitSizes(void)
// 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;
+ && npages == runtime·class_to_allocnpages[sizeclass-1]
+ && allocsize/osize == allocsize/(runtime·class_to_size[sizeclass-1]+RefcountOverhead)) {
+ runtime·class_to_size[sizeclass-1] = size;
continue;
}
- class_to_allocnpages[sizeclass] = npages;
- class_to_size[sizeclass] = size;
+ runtime·class_to_allocnpages[sizeclass] = npages;
+ runtime·class_to_size[sizeclass] = size;
sizeclass++;
}
if(sizeclass != NumSizeClasses) {
- printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
- throw("InitSizes - bad NumSizeClasses");
+ runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ runtime·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)
+ for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
size_to_class8[nextsize/8] = sizeclass;
if(nextsize >= 1024)
- for(; nextsize <= class_to_size[sizeclass]; nextsize += 128)
+ for(; nextsize <= runtime·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");
+ sizeclass = runtime·SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·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");
+ if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·printf("SizeToClass too big");
goto dump;
}
}
}
// Copy out for statistics table.
- for(i=0; i<nelem(class_to_size); i++)
- mstats.by_size[i].size = class_to_size[i];
+ for(i=0; i<nelem(runtime·class_to_size); i++)
+ mstats.by_size[i].size = runtime·class_to_size[i];
- // Initialize the class_to_transfercount table.
+ // Initialize the runtime·class_to_transfercount table.
for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
- n = 64*1024 / class_to_size[sizeclass];
+ n = 64*1024 / runtime·class_to_size[sizeclass];
if(n < 2)
n = 2;
if(n > 32)
n = 32;
- class_to_transfercount[sizeclass] = n;
+ runtime·class_to_transfercount[sizeclass] = n;
}
return;
dump:
if(1){
- printf("NumSizeClasses=%d\n", NumSizeClasses);
- printf("class_to_size:");
+ runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
+ runtime·printf("runtime·class_to_size:");
for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
- printf(" %d", class_to_size[sizeclass]);
- printf("\n\n");
- printf("size_to_class8:");
+ runtime·printf(" %d", runtime·class_to_size[sizeclass]);
+ runtime·printf("\n\n");
+ runtime·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:");
+ runtime·printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], runtime·class_to_size[size_to_class8[i]]);
+ runtime·printf("\n");
+ runtime·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");
+ runtime·printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], runtime·class_to_size[size_to_class128[i]]);
+ runtime·printf("\n");
}
- throw("InitSizes failed");
+ runtime·throw("InitSizes failed");
}
diff --git a/src/pkg/runtime/nacl/386/closure.c b/src/pkg/runtime/nacl/386/closure.c
deleted file mode 100644
index 6a27d6ec6..000000000
--- a/src/pkg/runtime/nacl/386/closure.c
+++ /dev/null
@@ -1,247 +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.
-
-/*
- * Closure implementation for Native Client.
- * Native Client imposes some interesting restrictions.
- *
- * First, we can only add new code to the code segment
- * through a special system call, and we have to pick the
- * maximum amount of code we're going to add that way
- * at link time (8l reserves 512 kB for us).
- *
- * Second, once we've added the code we can't ever
- * change it or delete it. If we want to garbage collect
- * the memory and then reuse it for another closure,
- * we have to do so without editing the code.
- *
- * To address both of these, we fill the code segment pieces
- * with very stylized closures. Each has the form given below
- * in the comments on the closasm array, with ** replaced by
- * a pointer to a single word of memory. The garbage collector
- * treats a pointer to such a closure as equivalent to the value
- * held in **. This tiled run of closures is called the closure array.
- *
- * The ptr points at a ClosureData structure, defined below,
- * which gives the function, arguments, and size for the
- * closuretramp function. The ClosureData structure has
- * in it a pointer to a ClosureFreeList structure holding the index
- * of the closure in the closure array (but not a pointer to it).
- * That structure has a finalizer: when the garbage collector
- * notices that the ClosureFreeList structure is not referenced
- * anymore, that means the closure is not referenced, so it
- * can be reused. To do that, the ClosureFreeList entry is put
- * onto an actual free list.
- */
-#include "runtime.h"
-#include "malloc.h"
-
-// NaCl system call to copy data into text segment.
-extern int32 dyncode_copy(void*, void*, int32);
-
-enum{
- // Allocate chunks of 4096 bytes worth of closures:
- // at 64 bytes each, that's 64 closures.
- ClosureChunk = 4096,
- ClosureSize = 64,
-};
-
-typedef struct ClosureFreeList ClosureFreeList;
-struct ClosureFreeList
-{
- ClosureFreeList *next;
- int32 index; // into closure array
-};
-
-// Known to closasm
-typedef struct ClosureData ClosureData;
-struct ClosureData
-{
- ClosureFreeList *free;
- byte *fn;
- int32 siz;
- // then args
-};
-
-// List of the closure data pointer blocks we've allocated
-// and hard-coded in the closure text segments.
-// The list keeps the pointer blocks from getting collected.
-typedef struct ClosureDataList ClosureDataList;
-struct ClosureDataList
-{
- ClosureData **block;
- ClosureDataList *next;
-};
-
-static struct {
- Lock;
- byte *code;
- byte *ecode;
- ClosureFreeList *free;
- ClosureDataList *datalist;
- byte buf[ClosureChunk];
-} clos;
-
-static byte closasm[64] = {
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x8b, 0x4b, 8, // MOVL 8(BX), CX
- 0x8d, 0x73, 12, // LEAL 12(BX), SI
- 0x29, 0xcc, // SUBL CX, SP
- 0x89, 0xe7, // MOVL SP, DI
- 0xc1, 0xe9, 2, // SHRL $2, CX
- 0xf3, 0xa5, // REP MOVSL
- 0x8b, 0x5b, 4, // MOVL 4(BX), BX
- 0x90, 0x90, 0x90, // NOP...
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xd3, // CALL *BX
- // --- 32-byte boundary
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x03, 0x63, 8, // ADDL 8(BX), SP
- 0x5b, // POPL BX
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xe3, // JMP *BX
- 0xf4, // HLT...
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- // --- 32-byte boundary
-};
-
-// Returns immediate pointer from closure code block.
-// Triple pointer:
-// p is the instruction stream
-// p+2 is the location of the immediate value
-// *(p+2) is the immediate value, a word in the pointer block
-// permanently associated with this closure.
-// **(p+2) is the ClosureData* pointer temporarily associated
-// with this closure.
-//
-#define codeptr(p) *(ClosureData***)((byte*)(p)+2)
-
-void
-finclosure(void *v)
-{
- byte *p;
- ClosureFreeList *f;
-
- f = v;
- p = clos.code + f->index*ClosureSize;
- *codeptr(p) = nil;
-
- lock(&clos);
- f->next = clos.free;
- clos.free = f;
- unlock(&clos);
-}
-
-#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
-·closure(int32 siz, byte *fn, byte *arg0)
-{
- byte *p, **ret;
- int32 e, i, n, off;
- extern byte data[], etext[];
- ClosureData *d, **block;
- ClosureDataList *l;
- ClosureFreeList *f;
-
- 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");
- }
-
- lock(&clos);
- if(clos.free == nil) {
- // Allocate more closures.
- if(clos.code == nil) {
- // First time: find closure space, between end of text
- // segment and beginning of data.
- clos.code = (byte*)(((uintptr)etext + 65535) & ~65535);
- clos.ecode = clos.code;
- mheap.closure_min = clos.code;
- mheap.closure_max = data;
- }
- if(clos.ecode+ClosureChunk > data) {
- // Last ditch effort: garbage collect and hope.
- unlock(&clos);
- gc(1);
- lock(&clos);
- if(clos.free != nil)
- goto alloc;
- throw("ran out of room for closures in text segment");
- }
-
- n = ClosureChunk/ClosureSize;
-
- // Allocate the pointer block as opaque to the
- // garbage collector. Finalizers will clean up.
- block = mallocgc(n*sizeof block[0], RefNoPointers, 1, 1);
-
- // Pointers into the pointer block are getting added
- // to the text segment; keep a pointer here in the data
- // segment so that the garbage collector doesn't free
- // the block itself.
- l = mal(sizeof *l);
- l->block = block;
- l->next = clos.datalist;
- clos.datalist = l;
-
- p = clos.buf;
- off = (clos.ecode - clos.code)/ClosureSize;
- for(i=0; i<n; i++) {
- f = mal(sizeof *f);
- f->index = off++;
- f->next = clos.free;
- clos.free = f;
-
- // There are two hard-coded immediate values in
- // the assembly that need to be pp+i, one 2 bytes in
- // and one 2 bytes after the 32-byte boundary.
- mcpy(p, closasm, ClosureSize);
- *(ClosureData***)(p+2) = block+i;
- *(ClosureData***)(p+32+2) = block+i;
- p += ClosureSize;
- }
-
- if(p != clos.buf+sizeof clos.buf)
- throw("bad buf math in closure");
-
- e = dyncode_copy(clos.ecode, clos.buf, ClosureChunk);
- if(e != 0) {
- fd = 2;
- printf("dyncode_copy: error %d\n", e);
- throw("dyncode_copy");
- }
- clos.ecode += ClosureChunk;
- }
-
-alloc:
- // Grab a free closure and save the data pointer in its indirect pointer.
- f = clos.free;
- clos.free = f->next;
- f->next = nil;
- p = clos.code + f->index*ClosureSize;
-
- d = mal(sizeof(*d)+siz);
- d->free = f;
- d->fn = fn;
- d->siz = siz;
- mcpy((byte*)(d+1), (byte*)&arg0, siz);
- *codeptr(p) = d;
- addfinalizer(f, finclosure, 0);
- unlock(&clos);
-
- *ret = p;
-}
-
-
diff --git a/src/pkg/runtime/nacl/386/defs.h b/src/pkg/runtime/nacl/386/defs.h
deleted file mode 100644
index 420b6910b..000000000
--- a/src/pkg/runtime/nacl/386/defs.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// godefs -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client 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,
-};
-
-// Types
-#pragma pack on
-#pragma pack off
diff --git a/src/pkg/runtime/nacl/386/rt0.s b/src/pkg/runtime/nacl/386/rt0.s
deleted file mode 100644
index d967bafd4..000000000
--- a/src/pkg/runtime/nacl/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.
-
-// Native Client and Linux use the same linkage to main
-
-TEXT _rt0_386_nacl(SB),7,$0
- JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/nacl/386/signal.c b/src/pkg/runtime/nacl/386/signal.c
deleted file mode 100644
index 4dda63fcf..000000000
--- a/src/pkg/runtime/nacl/386/signal.c
+++ /dev/null
@@ -1,14 +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
-initsig(int32 queue)
-{
-}
-
diff --git a/src/pkg/runtime/nacl/386/sys.s b/src/pkg/runtime/nacl/386/sys.s
deleted file mode 100644
index e855351b9..000000000
--- a/src/pkg/runtime/nacl/386/sys.s
+++ /dev/null
@@ -1,138 +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
-//
-
-#include "386/asm.h"
-
-// http://code.google.com/p/nativeclient/source/browse/trunk/src/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
-#define SYS_exit 30
-#define SYS_mmap 21
-#define SYS_thread_create 80
-#define SYS_thread_exit 81
-#define SYS_tls_init 82
-#define SYS_write 13
-#define SYS_close 11
-#define SYS_mutex_create 70
-#define SYS_mutex_lock 71
-#define SYS_mutex_unlock 73
-#define SYS_gettimeofday 40
-#define SYS_dyncode_copy 104
-
-
-#define SYSCALL(x) $(0x10000+SYS_/**/x * 32)
-
-TEXT exit(SB),7,$4
- MOVL code+0(FP), AX
- MOVL AX, 0(SP)
- CALL SYSCALL(exit)
- INT $3 // not reached
- RET
-
-TEXT exit1(SB),7,$4
- MOVL code+0(FP), AX
- MOVL AX, 0(SP)
- CALL SYSCALL(thread_exit)
- INT $3 // not reached
- RET
-
-TEXT write(SB),7,$0
- JMP SYSCALL(write)
-
-TEXT close(SB),7,$0
- JMP SYSCALL(close)
-
-TEXT mutex_create(SB),7,$0
- JMP SYSCALL(mutex_create)
-
-TEXT mutex_lock(SB),7,$0
- JMP SYSCALL(mutex_lock)
-
-TEXT mutex_unlock(SB),7,$0
- JMP SYSCALL(mutex_unlock)
-
-TEXT thread_create(SB),7,$0
- JMP SYSCALL(thread_create)
-
-TEXT dyncode_copy(SB),7,$0
- JMP SYSCALL(dyncode_copy)
-
-// For Native Client: a simple no-op function.
-// Inserting a call to this no-op is a simple way
-// to trigger an alignment.
-TEXT ·naclnop(SB),7,$0
- RET
-
-TEXT ·mmap(SB),7,$24
- MOVL a1+0(FP), BX
- MOVL a2+4(FP), CX // round up to 64 kB boundary; silences nacl warning
- ADDL $(64*1024-1), CX
- ANDL $~(64*1024-1), CX
- MOVL a3+8(FP), DX
- MOVL a4+12(FP), SI
- MOVL a5+16(FP), DI
- MOVL a6+20(FP), BP
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- MOVL DX, 8(SP)
- MOVL SI, 12(SP)
- MOVL DI, 16(SP)
- MOVL BP, 20(SP)
- CALL SYSCALL(mmap)
- CMPL AX, $0xfffff001
- JLS 6(PC)
- MOVL $1, 0(SP)
- MOVL $mmap_failed(SB), 4(SP)
- MOVL $12, 8(SP) // "mmap failed\n"
- CALL SYSCALL(write)
- INT $3
- RET
-
-TEXT gettime(SB),7,$32
- LEAL 8(SP), BX
- MOVL BX, 0(SP)
- MOVL $0, 4(SP)
- CALL SYSCALL(gettimeofday)
-
- MOVL 8(SP), BX // sec
- MOVL sec+0(FP), DI
- MOVL BX, (DI)
- MOVL $0, 4(DI) // zero extend 32 -> 64 bits
-
- MOVL 12(SP), BX // usec
- MOVL usec+4(FP), DI
- MOVL BX, (DI)
- RET
-
-// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
- // entry is ignored - nacl tells us the
- // segment selector to use and stores it in GS.
- MOVL address+4(FP), BX
- MOVL limit+8(FP), CX
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- CALL SYSCALL(tls_init)
- CMPL AX, $0xfffff001
- JLS 6(PC)
- MOVL $1, 0(SP)
- MOVL $tls_init_failed(SB), 4(SP)
- MOVL $16, 8(SP) // "tls_init failed\n"
- CALL SYSCALL(write)
- INT $3
- RET
-
-// There's no good way (yet?) to get stack traces out of a
-// broken NaCl process, so if something goes wrong,
-// print an error string before dying.
-
-DATA mmap_failed(SB)/8, $"mmap fai"
-DATA mmap_failed+8(SB)/4, $"led\n"
-GLOBL mmap_failed(SB), $12
-
-DATA tls_init_failed(SB)/8, $"tls_init"
-DATA tls_init_failed+8(SB)/8, $" failed\n"
-GLOBL tls_init_failed(SB), $16
diff --git a/src/pkg/runtime/nacl/defs.c b/src/pkg/runtime/nacl/defs.c
deleted file mode 100644
index bcaddd74f..000000000
--- a/src/pkg/runtime/nacl/defs.c
+++ /dev/null
@@ -1,27 +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/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client defs.c >386/defs.h
-*/
-
-#define __native_client__ 1
-
-#define suseconds_t nacl_suseconds_t_1
-#include <sys/types.h>
-#undef suseconds_t
-
-#include <sys/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,
-};
diff --git a/src/pkg/runtime/nacl/mem.c b/src/pkg/runtime/nacl/mem.c
deleted file mode 100644
index 52e351a7d..000000000
--- a/src/pkg/runtime/nacl/mem.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "malloc.h"
-
-void*
-SysAlloc(uintptr n)
-{
- mstats.sys += n;
- return runtime_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
-}
-
diff --git a/src/pkg/runtime/nacl/os.h b/src/pkg/runtime/nacl/os.h
deleted file mode 100644
index eb4af57b2..000000000
--- a/src/pkg/runtime/nacl/os.h
+++ /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.
-
-int32 thread_create(void(*fn)(void), void *stk, void *tls, int32 tlssize);
-void close(int32);
-int32 mutex_create(void);
-int32 mutex_lock(int32);
-int32 mutex_unlock(int32);
diff --git a/src/pkg/runtime/nacl/signals.h b/src/pkg/runtime/nacl/signals.h
deleted file mode 100644
index e69de29bb..000000000
--- a/src/pkg/runtime/nacl/signals.h
+++ /dev/null
diff --git a/src/pkg/runtime/nacl/thread.c b/src/pkg/runtime/nacl/thread.c
deleted file mode 100644
index 392be870f..000000000
--- a/src/pkg/runtime/nacl/thread.c
+++ /dev/null
@@ -1,164 +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"
-
-int8 *goos = "nacl";
-
-// Thread-safe allocation of a mutex.
-// (The name sema is left over from the Darwin implementation.
-// Native Client implements semaphores too, but it is just a shim
-// over the host implementation, which on some hosts imposes a very
-// low limit on how many semaphores can be created.)
-//
-// Psema points at a mutex descriptor.
-// It starts out zero, meaning no mutex.
-// 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 = mutex_create();
- if((int32)sema < 0) {
- printf("mutex_create failed\n");
- breakpoint();
- }
- // mutex_create returns a file descriptor;
- // shift it up and add the 1 bit so that can
- // distinguish unintialized from fd 0.
- sema = (sema<<1) | 1;
- if(!cas(psema, 0, sema)){
- // Someone else filled it in. Use theirs.
- close(sema);
- return;
- }
-}
-
-// Lock and unlock.
-// Defer entirely to Native Client.
-// The expense of a call into Native Client is more like
-// a function call than a system call, so as long as the
-// Native Client lock implementation is good, we can't
-// do better ourselves.
-
-static void
-xlock(int32 fd)
-{
- if(mutex_lock(fd) < 0) {
- printf("mutex_lock failed\n");
- breakpoint();
- }
-}
-
-static void
-xunlock(int32 fd)
-{
- if(mutex_unlock(fd) < 0) {
- printf("mutex_lock failed\n");
- breakpoint();
- }
-}
-
-void
-lock(Lock *l)
-{
- if(m->locks < 0)
- throw("lock count");
- m->locks++;
- if(l->sema == 0)
- initsema(&l->sema);
- xlock(l->sema>>1);
-}
-
-void
-unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- throw("lock count");
- xunlock(l->sema>>1);
-}
-
-void
-destroylock(Lock*)
-{
-}
-
-// 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.
-//
-// Native Client does not require that the thread acquiring
-// a lock be the thread that releases the lock, so this is safe.
-
-void
-noteclear(Note *n)
-{
- if(n->lock.sema == 0)
- initsema(&n->lock.sema);
- xlock(n->lock.sema>>1);
-}
-
-void
-notewakeup(Note *n)
-{
- if(n->lock.sema == 0) {
- printf("notewakeup without noteclear");
- breakpoint();
- }
- xunlock(n->lock.sema>>1);
-}
-
-void
-notesleep(Note *n)
-{
- if(n->lock.sema == 0) {
- printf("notesleep without noteclear");
- breakpoint();
- }
- xlock(n->lock.sema>>1);
- xunlock(n->lock.sema>>1); // Let other sleepers find out too.
-}
-
-void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- void **vstk;
-
- // I wish every OS made thread creation this easy.
- m->tls[0] = (uint32)g;
- m->tls[1] = (uint32)m;
- vstk = stk;
- *--vstk = nil;
- if(thread_create(fn, vstk, m->tls, sizeof m->tls) < 0) {
- printf("thread_create failed\n");
- breakpoint();
- }
-}
-
-void
-osinit(void)
-{
-}
-
-// Called to initialize a new m (including the bootstrap m).
-void
-minit(void)
-{
-}
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h
new file mode 100644
index 000000000..5df757613
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/defs.h
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/plan9/386/rt0.s
new file mode 100644
index 000000000..b56c8b325
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/rt0.s
@@ -0,0 +1,32 @@
+// Copyright 2010 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_plan9(SB),7, $0
+ MOVL AX, _tos(SB)
+
+ // move arguments down to make room for
+ // m and g at top of stack, right before Tos.
+ MOVL SP, SI
+ SUBL $8, SP
+ MOVL SP, DI
+
+ MOVL AX, CX
+ SUBL SI, CX
+ CLD
+ REP; MOVSB
+
+ // adjust argv
+ SUBL SI, DI
+ MOVL newargc+0(SP), CX
+ LEAL newargv+4(SP), BP
+argv_fix:
+ ADDL DI, 0(BP)
+ ADDL $4, BP
+ LOOP argv_fix
+
+ JMP _rt0_386(SB)
+
+DATA runtime·isplan9(SB)/4, $1
+GLOBL runtime·isplan9(SB), $4
+GLOBL _tos(SB), $4
diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/plan9/386/signal.c
new file mode 100644
index 000000000..6bde09846
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/signal.c
@@ -0,0 +1,16 @@
+// Copyright 2010 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
+runtime·gettime(int64*, int32*)
+{
+}
+
+String
+runtime·signame(int32)
+{
+ return runtime·emptystring;
+}
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
new file mode 100644
index 000000000..867b8940f
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/sys.s
@@ -0,0 +1,76 @@
+// Copyright 2010 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 "defs.h"
+#include "386/asm.h"
+
+// setldt(int entry, int address, int limit)
+TEXT runtime·setldt(SB),7,$0
+ RET
+
+TEXT runtime·write(SB),7,$0
+ MOVL $20, AX
+ INT $64
+ RET
+
+TEXT runtime·exits(SB),7,$0
+ MOVL $8, AX
+ INT $64
+ RET
+
+TEXT runtime·brk_(SB),7,$0
+ MOVL $24, AX
+ INT $64
+ RET
+
+TEXT runtime·plan9_semacquire(SB),7,$0
+ MOVL $37, AX
+ INT $64
+ RET
+
+TEXT runtime·plan9_semrelease(SB),7,$0
+ MOVL $38, AX
+ INT $64
+ RET
+
+TEXT runtime·rfork(SB),7,$0
+ MOVL $19, AX // rfork
+ INT $64
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child on old stack.
+ MOVL mm+12(SP), BX // m
+ MOVL gg+16(SP), DX // g
+ MOVL fn+20(SP), SI // fn
+
+ // set SP to be on the new child stack
+ MOVL stack+8(SP), CX
+ MOVL CX, SP
+
+ // Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ // Initialize AX from _tos->pid
+ MOVL 0xdfffeff8, AX
+ MOVL AX, m_procid(BX) // save pid as m->procid
+
+ CALL runtime·stackcheck(SB) // smashes AX, CX
+
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL runtime·emptyfunc(SB)
+ POPAL
+
+ CALL SI // fn()
+ CALL runtime·exit(SB)
+ RET
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
new file mode 100644
index 000000000..651e6728e
--- /dev/null
+++ b/src/pkg/runtime/plan9/mem.c
@@ -0,0 +1,49 @@
+// Copyright 2010 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"
+
+extern byte end[];
+static byte *bloc = { end };
+
+enum
+{
+ Round = 7
+};
+
+void*
+runtime·SysAlloc(uintptr ask)
+{
+ uintptr bl;
+
+ // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+ bl = ((uintptr)bloc + Round) & ~Round;
+ if(runtime·brk_((void*)(bl + ask)) < 0)
+ return (void*)-1;
+ bloc = (byte*)bl + ask;
+ return (void*)bl;
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ // from tiny/mem.c
+ // Push pointer back if this is a free
+ // of the most recent SysAlloc.
+ n += (n + Round) & ~Round;
+ if(bloc == (byte*)v+n)
+ bloc -= n;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v, n);
+}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h
new file mode 100644
index 000000000..9444acc98
--- /dev/null
+++ b/src/pkg/runtime/plan9/os.h
@@ -0,0 +1,27 @@
+// Copyright 2010 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.
+
+extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes);
+extern void runtime·exits(int8* msg);
+extern int32 runtime·brk_(void*);
+
+/* rfork */
+enum
+{
+ RFNAMEG = (1<<0),
+ RFENVG = (1<<1),
+ RFFDG = (1<<2),
+ RFNOTEG = (1<<3),
+ RFPROC = (1<<4),
+ RFMEM = (1<<5),
+ RFNOWAIT = (1<<6),
+ RFCNAMEG = (1<<10),
+ RFCENVG = (1<<11),
+ RFCFDG = (1<<12),
+ RFREND = (1<<13),
+ RFNOMNT = (1<<14)
+};
+extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
+extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
+extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
diff --git a/src/pkg/runtime/plan9/runtime_defs.go b/src/pkg/runtime/plan9/runtime_defs.go
new file mode 100644
index 000000000..cf0b414a9
--- /dev/null
+++ b/src/pkg/runtime/plan9/runtime_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type usema struct {
+ u uint32
+ k uint32
+}
+
+
+type note struct {
+ wakeup int32
+ sema usema
+}
diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/plan9/signals.h
new file mode 100644
index 000000000..5df757613
--- /dev/null
+++ b/src/pkg/runtime/plan9/signals.h
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
new file mode 100644
index 000000000..fa96552a9
--- /dev/null
+++ b/src/pkg/runtime/plan9/thread.c
@@ -0,0 +1,140 @@
+// Copyright 2010 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 "os.h"
+
+int8 *goos = "plan9";
+
+void
+runtime·minit(void)
+{
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+}
+
+void
+runtime·initsig(int32 queue)
+{
+}
+
+void
+runtime·exit(int32)
+{
+ runtime·exits(nil);
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ USED(m, g, stk, fn);
+
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
+ }
+
+ if (runtime·rfork(RFPROC | RFMEM, stk, m, g, fn) < 0 )
+ runtime·throw("newosproc: rfork failed");
+}
+
+// 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.
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+
+ if(runtime·xadd(&l->key, 1) == 1)
+ return; // changed from 0 -> 1; we hold lock
+ // otherwise wait in kernel
+ while(runtime·plan9_semacquire(&l->sema, 1) < 0) {
+ /* interrupted; try again */
+ }
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+
+ if(runtime·xadd(&l->key, -1) == 0)
+ return; // changed from 1 -> 0: no contention
+
+ runtime·plan9_semrelease(&l->sema, 1);
+}
+
+
+void
+runtime·destroylock(Lock *l)
+{
+ // nothing
+}
+
+// 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
+runtime·usemacquire(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, -1) < 0)
+ while(runtime·plan9_semacquire(&s->k, 1) < 0) {
+ /* interrupted; try again */
+ }
+}
+
+void
+runtime·usemrelease(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, 1) <= 0)
+ runtime·plan9_semrelease(&s->k, 1);
+}
+
+
+// Event notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->wakeup = 0;
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ while(!n->wakeup)
+ runtime·usemacquire(&n->sema);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ n->wakeup = 1;
+ runtime·usemrelease(&n->sema);
+}
+
diff --git a/src/pkg/runtime/pprof/Makefile b/src/pkg/runtime/pprof/Makefile
index daffde79d..8bccc0cc0 100644
--- a/src/pkg/runtime/pprof/Makefile
+++ b/src/pkg/runtime/pprof/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=runtime/pprof
GOFILES=\
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index aa207e312..3b4bb103d 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -10,31 +10,31 @@
static void vprintf(int8*, byte*);
void
-dump(byte *p, int32 n)
+runtime·dump(byte *p, int32 n)
{
int32 i;
for(i=0; i<n; i++) {
- ·printpointer((byte*)(p[i]>>4));
- ·printpointer((byte*)(p[i]&0xf));
+ runtime·printpointer((byte*)(p[i]>>4));
+ runtime·printpointer((byte*)(p[i]&0xf));
if((i&15) == 15)
- prints("\n");
+ runtime·prints("\n");
else
- prints(" ");
+ runtime·prints(" ");
}
if(n & 15)
- prints("\n");
+ runtime·prints("\n");
}
void
-prints(int8 *s)
+runtime·prints(int8 *s)
{
- write(fd, s, findnull((byte*)s));
+ runtime·write(2, s, runtime·findnull((byte*)s));
}
#pragma textflag 7
void
-printf(int8 *s, ...)
+runtime·printf(int8 *s, ...)
{
byte *arg;
@@ -65,7 +65,7 @@ vprintf(int8 *s, byte *arg)
if(*p != '%')
continue;
if(p > lp)
- write(fd, lp, p-lp);
+ runtime·write(2, lp, p-lp);
p++;
narg = nil;
switch(*p) {
@@ -109,107 +109,104 @@ vprintf(int8 *s, byte *arg)
}
switch(*p) {
case 'a':
- ·printslice(*(Slice*)arg);
+ runtime·printslice(*(Slice*)arg);
break;
case 'd':
- ·printint(*(int32*)arg);
+ runtime·printint(*(int32*)arg);
break;
case 'D':
- ·printint(*(int64*)arg);
+ runtime·printint(*(int64*)arg);
break;
case 'e':
- ·printeface(*(Eface*)arg);
+ runtime·printeface(*(Eface*)arg);
break;
case 'f':
- ·printfloat(*(float64*)arg);
+ runtime·printfloat(*(float64*)arg);
break;
case 'C':
- ·printcomplex(*(Complex128*)arg);
+ runtime·printcomplex(*(Complex128*)arg);
break;
case 'i':
- ·printiface(*(Iface*)arg);
+ runtime·printiface(*(Iface*)arg);
break;
case 'p':
- ·printpointer(*(void**)arg);
+ runtime·printpointer(*(void**)arg);
break;
case 's':
- prints(*(int8**)arg);
+ runtime·prints(*(int8**)arg);
break;
case 'S':
- ·printstring(*(String*)arg);
+ runtime·printstring(*(String*)arg);
break;
case 't':
- ·printbool(*(bool*)arg);
+ runtime·printbool(*(bool*)arg);
break;
case 'U':
- ·printuint(*(uint64*)arg);
+ runtime·printuint(*(uint64*)arg);
break;
case 'x':
- ·printhex(*(uint32*)arg);
+ runtime·printhex(*(uint32*)arg);
break;
case 'X':
- ·printhex(*(uint64*)arg);
+ runtime·printhex(*(uint64*)arg);
break;
- case '!':
- panic(-1);
}
arg = narg;
lp = p+1;
}
if(p > lp)
- write(fd, lp, p-lp);
+ runtime·write(2, lp, p-lp);
// unlock(&debuglock);
}
#pragma textflag 7
void
-·printf(String s, ...)
+runtime·goprintf(String s, ...)
{
// Can assume s has terminating NUL because only
- // the Go compiler generates calls to ·printf, using
+ // the Go compiler generates calls to runtime·goprintf, using
// string constants, and all the string constants have NULs.
vprintf((int8*)s.str, (byte*)(&s+1));
}
void
-·printpc(void *p)
+runtime·printpc(void *p)
{
- prints("PC=");
- ·printhex((uint64)·getcallerpc(p));
+ runtime·prints("PC=");
+ runtime·printhex((uint64)runtime·getcallerpc(p));
}
void
-·printbool(bool v)
+runtime·printbool(bool v)
{
if(v) {
- write(fd, (byte*)"true", 4);
+ runtime·write(2, (byte*)"true", 4);
return;
}
- write(fd, (byte*)"false", 5);
+ runtime·write(2, (byte*)"false", 5);
}
void
-·printfloat(float64 v)
+runtime·printfloat(float64 v)
{
byte buf[20];
int32 e, s, i, n;
float64 h;
- if(isNaN(v)) {
- write(fd, "NaN", 3);
+ if(runtime·isNaN(v)) {
+ runtime·write(2, "NaN", 3);
return;
}
- if(isInf(v, 1)) {
- write(fd, "+Inf", 4);
+ if(runtime·isInf(v, 1)) {
+ runtime·write(2, "+Inf", 4);
return;
}
- if(isInf(v, -1)) {
- write(fd, "-Inf", 4);
+ if(runtime·isInf(v, -1)) {
+ runtime·write(2, "-Inf", 4);
return;
}
-
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
@@ -234,6 +231,7 @@ void
h = 5;
for(i=0; i<n; i++)
h /= 10;
+
v += h;
if(v >= 10) {
e++;
@@ -264,20 +262,20 @@ void
buf[n+4] = (e/100) + '0';
buf[n+5] = (e/10)%10 + '0';
buf[n+6] = (e%10) + '0';
- write(fd, buf, n+7);
+ runtime·write(2, buf, n+7);
}
void
-·printcomplex(Complex128 v)
+runtime·printcomplex(Complex128 v)
{
- write(fd, "(", 1);
- ·printfloat(v.real);
- ·printfloat(v.imag);
- write(fd, "i)", 2);
+ runtime·write(2, "(", 1);
+ runtime·printfloat(v.real);
+ runtime·printfloat(v.imag);
+ runtime·write(2, "i)", 2);
}
void
-·printuint(uint64 v)
+runtime·printuint(uint64 v)
{
byte buf[100];
int32 i;
@@ -288,21 +286,21 @@ void
break;
v = v/10;
}
- write(fd, buf+i, nelem(buf)-i);
+ runtime·write(2, buf+i, nelem(buf)-i);
}
void
-·printint(int64 v)
+runtime·printint(int64 v)
{
if(v < 0) {
- write(fd, "-", 1);
+ runtime·write(2, "-", 1);
v = -v;
}
- ·printuint(v);
+ runtime·printuint(v);
}
void
-·printhex(uint64 v)
+runtime·printhex(uint64 v)
{
static int8 *dig = "0123456789abcdef";
byte buf[100];
@@ -315,36 +313,44 @@ void
buf[--i] = '0';
buf[--i] = 'x';
buf[--i] = '0';
- write(fd, buf+i, nelem(buf)-i);
+ runtime·write(2, buf+i, nelem(buf)-i);
}
void
-·printpointer(void *p)
+runtime·printpointer(void *p)
{
- ·printhex((uint64)p);
+ runtime·printhex((uint64)p);
}
void
-·printstring(String v)
+runtime·printstring(String v)
{
- extern int32 maxstring;
+ extern int32 runtime·maxstring;
- if(v.len > maxstring) {
- write(fd, "[invalid string]", 16);
+ if(v.len > runtime·maxstring) {
+ runtime·write(2, "[invalid string]", 16);
return;
}
if(v.len > 0)
- write(fd, v.str, v.len);
+ runtime·write(2, v.str, v.len);
+}
+
+void
+runtime·printsp(void)
+{
+ runtime·write(2, " ", 1);
}
void
-·printsp(void)
+runtime·printnl(void)
{
- write(fd, " ", 1);
+ runtime·write(2, "\n", 1);
}
void
-·printnl(void)
+runtime·typestring(Eface e, String s)
{
- write(fd, "\n", 1);
+ s = *e.type->string;
+ FLUSH(&s);
}
+
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 2abb28307..e9a19d950 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -3,20 +3,23 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch.h"
#include "defs.h"
#include "malloc.h"
#include "os.h"
+bool runtime·iscgo;
+
static void unwindstack(G*, byte*);
typedef struct Sched Sched;
-M m0;
-G g0; // idle goroutine for m0
+M runtime·m0;
+G runtime·g0; // idle goroutine for m0
static int32 debug = 0;
-int32 gcwaiting;
+int32 runtime·gcwaiting;
// Go scheduler
//
@@ -35,7 +38,7 @@ int32 gcwaiting;
//
// 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),
+// sieve will use as many ms as there are primes (up to runtime·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
@@ -69,7 +72,7 @@ struct Sched {
int32 waitstop; // after setting this flag
};
-Sched sched;
+Sched runtime·sched;
// Scheduling helpers. Sched must be locked.
static void gput(G*); // put/get on ghead/gtail
@@ -90,7 +93,7 @@ static void scheduler(void);
// call osinit
// call schedinit
// make & queue new G
-// call mstart
+// call runtime·mstart
//
// The new G does:
//
@@ -98,66 +101,67 @@ static void scheduler(void);
// call initdone
// call main·main
void
-schedinit(void)
+runtime·schedinit(void)
{
int32 n;
byte *p;
- allm = m;
+ runtime·allm = m;
m->nomemprof++;
- mallocinit();
- goargs();
+ runtime·mallocinit();
+ runtime·goargs();
+ runtime·goenvs();
// For debugging:
// 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;
+ runtime·sched.gomaxprocs = 1;
+ p = runtime·getenv("GOMAXPROCS");
+ if(p != nil && (n = runtime·atoi(p)) != 0)
+ runtime·sched.gomaxprocs = n;
+ runtime·sched.mcpumax = runtime·sched.gomaxprocs;
+ runtime·sched.mcount = 1;
+ runtime·sched.predawn = 1;
m->nomemprof--;
}
// Called after main·init_function; main·main will be called on return.
void
-initdone(void)
+runtime·initdone(void)
{
// Let's go.
- sched.predawn = 0;
+ runtime·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);
+ runtime·lock(&runtime·sched);
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
void
-goexit(void)
+runtime·goexit(void)
{
g->status = Gmoribund;
- gosched();
+ runtime·gosched();
}
void
-tracebackothers(G *me)
+runtime·tracebackothers(G *me)
{
G *g;
- for(g = allg; g != nil; g = g->alllink) {
+ for(g = runtime·allg; g != nil; g = g->alllink) {
if(g == me || g->status == Gdead)
continue;
- printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
- traceback(g->sched.pc, g->sched.sp, 0, g);
+ runtime·printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
+ runtime·traceback(g->sched.pc, g->sched.sp, 0, g);
}
}
@@ -168,18 +172,18 @@ gput(G *g)
M *m;
// If g is wired, hand it off directly.
- if(sched.mcpu < sched.mcpumax && (m = g->lockedm) != nil) {
+ if(runtime·sched.mcpu < runtime·sched.mcpumax && (m = g->lockedm) != nil) {
mnextg(m, g);
return;
}
g->schedlink = nil;
- if(sched.ghead == nil)
- sched.ghead = g;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.ghead = g;
else
- sched.gtail->schedlink = g;
- sched.gtail = g;
- sched.gwait++;
+ runtime·sched.gtail->schedlink = g;
+ runtime·sched.gtail = g;
+ runtime·sched.gwait++;
}
// Get from `g' queue. Sched must be locked.
@@ -188,12 +192,12 @@ gget(void)
{
G *g;
- g = sched.ghead;
+ g = runtime·sched.ghead;
if(g){
- sched.ghead = g->schedlink;
- if(sched.ghead == nil)
- sched.gtail = nil;
- sched.gwait--;
+ runtime·sched.ghead = g->schedlink;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.gtail = nil;
+ runtime·sched.gwait--;
}
return g;
}
@@ -202,9 +206,9 @@ gget(void)
static void
mput(M *m)
{
- m->schedlink = sched.mhead;
- sched.mhead = m;
- sched.mwait++;
+ m->schedlink = runtime·sched.mhead;
+ runtime·sched.mhead = m;
+ runtime·sched.mwait++;
}
// Get an `m' to run `g'. Sched must be locked.
@@ -218,20 +222,20 @@ mget(G *g)
return m;
// otherwise use general m pool.
- if((m = sched.mhead) != nil){
- sched.mhead = m->schedlink;
- sched.mwait--;
+ if((m = runtime·sched.mhead) != nil){
+ runtime·sched.mhead = m->schedlink;
+ runtime·sched.mwait--;
}
return m;
}
// Mark g ready to run.
void
-ready(G *g)
+runtime·ready(G *g)
{
- lock(&sched);
+ runtime·lock(&runtime·sched);
readylocked(g);
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// Mark g ready to run. Sched is already locked.
@@ -249,11 +253,11 @@ readylocked(G *g)
// Mark runnable.
if(g->status == Grunnable || g->status == Grunning || g->status == Grecovery)
- throw("bad g->status in ready");
+ runtime·throw("bad g->status in ready");
g->status = Grunnable;
gput(g);
- if(!sched.predawn)
+ if(!runtime·sched.predawn)
matchmg();
}
@@ -276,11 +280,11 @@ newprocreadylocked(G *g)
static void
mnextg(M *m, G *g)
{
- sched.mcpu++;
+ runtime·sched.mcpu++;
m->nextg = g;
if(m->waitnextg) {
m->waitnextg = 0;
- notewakeup(&m->havenextg);
+ runtime·notewakeup(&m->havenextg);
}
}
@@ -293,15 +297,15 @@ nextgandunlock(void)
{
G *gp;
- if(sched.mcpu < 0)
- throw("negative sched.mcpu");
+ if(runtime·sched.mcpu < 0)
+ runtime·throw("negative runtime·sched.mcpu");
// If there is a g waiting as m->nextg,
- // mnextg took care of the sched.mcpu++.
+ // mnextg took care of the runtime·sched.mcpu++.
if(m->nextg != nil) {
gp = m->nextg;
m->nextg = nil;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return gp;
}
@@ -309,36 +313,36 @@ nextgandunlock(void)
// We can only run one g, and it's not available.
// Make sure some other cpu is running to handle
// the ordinary run queue.
- if(sched.gwait != 0)
+ if(runtime·sched.gwait != 0)
matchmg();
} else {
// Look for work on global queue.
- while(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) {
+ while(runtime·sched.mcpu < runtime·sched.mcpumax && (gp=gget()) != nil) {
if(gp->lockedm) {
mnextg(gp->lockedm, gp);
continue;
}
- sched.mcpu++; // this m will run gp
- unlock(&sched);
+ runtime·sched.mcpu++; // this m will run gp
+ runtime·unlock(&runtime·sched);
return gp;
}
// Otherwise, wait on global m queue.
mput(m);
}
- if(sched.mcpu == 0 && sched.msyscall == 0)
- throw("all goroutines are asleep - deadlock!");
+ if(runtime·sched.mcpu == 0 && runtime·sched.msyscall == 0)
+ runtime·throw("all goroutines are asleep - deadlock!");
m->nextg = nil;
m->waitnextg = 1;
- noteclear(&m->havenextg);
- if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
- sched.waitstop = 0;
- notewakeup(&sched.stopped);
+ runtime·noteclear(&m->havenextg);
+ if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+ runtime·sched.waitstop = 0;
+ runtime·notewakeup(&runtime·sched.stopped);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
- notesleep(&m->havenextg);
+ runtime·notesleep(&m->havenextg);
if((gp = m->nextg) == nil)
- throw("bad m->nextg in nextgoroutine");
+ runtime·throw("bad m->nextg in nextgoroutine");
m->nextg = nil;
return gp;
}
@@ -346,46 +350,46 @@ nextgandunlock(void)
// TODO(rsc): Remove. This is only temporary,
// for the mark and sweep collector.
void
-stoptheworld(void)
+runtime·stoptheworld(void)
{
- lock(&sched);
- gcwaiting = 1;
- sched.mcpumax = 1;
- while(sched.mcpu > 1) {
+ runtime·lock(&runtime·sched);
+ runtime·gcwaiting = 1;
+ runtime·sched.mcpumax = 1;
+ while(runtime·sched.mcpu > 1) {
// It would be unsafe for multiple threads to be using
// the stopped note at once, but there is only
// ever one thread doing garbage collection,
// so this is okay.
- noteclear(&sched.stopped);
- sched.waitstop = 1;
- unlock(&sched);
- notesleep(&sched.stopped);
- lock(&sched);
+ runtime·noteclear(&runtime·sched.stopped);
+ runtime·sched.waitstop = 1;
+ runtime·unlock(&runtime·sched);
+ runtime·notesleep(&runtime·sched.stopped);
+ runtime·lock(&runtime·sched);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// TODO(rsc): Remove. This is only temporary,
// for the mark and sweep collector.
void
-starttheworld(void)
+runtime·starttheworld(void)
{
- lock(&sched);
- gcwaiting = 0;
- sched.mcpumax = sched.gomaxprocs;
+ runtime·lock(&runtime·sched);
+ runtime·gcwaiting = 0;
+ runtime·sched.mcpumax = runtime·sched.gomaxprocs;
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// Called to start an M.
void
-mstart(void)
+runtime·mstart(void)
{
if(g != m->g0)
- throw("bad mstart");
+ runtime·throw("bad runtime·mstart");
if(m->mcache == nil)
- m->mcache = allocmcache();
- minit();
+ m->mcache = runtime·allocmcache();
+ runtime·minit();
scheduler();
}
@@ -413,29 +417,36 @@ matchmg(void)
if(m->mallocing || m->gcing)
return;
- while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){
+ while(runtime·sched.mcpu < runtime·sched.mcpumax && (g = gget()) != nil){
M *m;
// Find the m that will run g.
if((m = mget(g)) == nil){
- m = malloc(sizeof(M));
- // Add to allm so garbage collector doesn't free m
+ m = runtime·malloc(sizeof(M));
+ // Add to runtime·allm so garbage collector doesn't free m
// when it is just in a register (R14 on amd64).
- m->alllink = allm;
- allm = m;
- m->id = sched.mcount++;
+ m->alllink = runtime·allm;
+ runtime·allm = m;
+ m->id = runtime·sched.mcount++;
- if(libcgo_thread_start != nil) {
+ if(runtime·iscgo) {
CgoThreadStart ts;
+
+ if(libcgo_thread_start == nil)
+ runtime·throw("libcgo_thread_start missing");
// pthread_create will make us a stack.
- m->g0 = malg(-1);
+ m->g0 = runtime·malg(-1);
ts.m = m;
ts.g = m->g0;
- ts.fn = mstart;
- runcgo(libcgo_thread_start, &ts);
+ ts.fn = runtime·mstart;
+ runtime·runcgo(libcgo_thread_start, &ts);
} else {
- m->g0 = malg(8192);
- newosproc(m, m->g0, m->g0->stackbase, mstart);
+ if(Windows)
+ // windows will layout sched stack on os stack
+ m->g0 = runtime·malg(-1);
+ else
+ m->g0 = runtime·malg(8192);
+ runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart);
}
}
mnextg(m, g);
@@ -448,8 +459,8 @@ scheduler(void)
{
G* gp;
- lock(&sched);
- if(gosave(&m->sched) != 0){
+ runtime·lock(&runtime·sched);
+ if(runtime·gosave(&m->sched) != 0){
gp = m->curg;
if(gp->status == Grecovery) {
// switched to scheduler to get stack unwound.
@@ -470,31 +481,31 @@ scheduler(void)
// each call to deferproc.
// (the pc we're returning to does pop pop
// before it tests the return value.)
- gp->sched.sp = getcallersp(d->sp - 2*sizeof(uintptr));
+ gp->sched.sp = runtime·getcallersp(d->sp - 2*sizeof(uintptr));
gp->sched.pc = d->pc;
gp->status = Grunning;
- free(d);
- gogo(&gp->sched, 1);
+ runtime·free(d);
+ runtime·gogo(&gp->sched, 1);
}
- // Jumped here via gosave/gogo, so didn't
- // execute lock(&sched) above.
- lock(&sched);
+ // Jumped here via runtime·gosave/gogo, so didn't
+ // execute lock(&runtime·sched) above.
+ runtime·lock(&runtime·sched);
- if(sched.predawn)
- throw("init sleeping");
+ if(runtime·sched.predawn)
+ runtime·throw("init sleeping");
// Just finished running gp.
gp->m = nil;
- sched.mcpu--;
+ runtime·sched.mcpu--;
- if(sched.mcpu < 0)
- throw("sched.mcpu < 0 in scheduler");
+ if(runtime·sched.mcpu < 0)
+ runtime·throw("runtime·sched.mcpu < 0 in scheduler");
switch(gp->status){
case Grunnable:
case Gdead:
// Shouldn't have been running!
- throw("bad gp->status in sched");
+ runtime·throw("bad gp->status in sched");
case Grunning:
gp->status = Grunnable;
gput(gp);
@@ -507,8 +518,8 @@ scheduler(void)
}
unwindstack(gp, nil);
gfput(gp);
- if(--sched.gcount == 0)
- exit(0);
+ if(--runtime·sched.gcount == 0)
+ runtime·exit(0);
break;
}
if(gp->readyonstop){
@@ -517,15 +528,16 @@ scheduler(void)
}
}
- // Find (or wait for) g to run. Unlocks sched.
+ // Find (or wait for) g to run. Unlocks runtime·sched.
gp = nextgandunlock();
gp->readyonstop = 0;
gp->status = Grunning;
m->curg = gp;
gp->m = m;
- if(gp->sched.pc == (byte*)goexit) // kickoff
- gogocall(&gp->sched, (void(*)(void))gp->entry);
- gogo(&gp->sched, 1);
+ if(gp->sched.pc == (byte*)runtime·goexit) { // kickoff
+ runtime·gogocall(&gp->sched, (void(*)(void))gp->entry);
+ }
+ runtime·gogo(&gp->sched, 1);
}
// Enter scheduler. If g->status is Grunning,
@@ -533,42 +545,45 @@ scheduler(void)
// before running g again. If g->status is Gmoribund,
// kills off g.
void
-gosched(void)
+runtime·gosched(void)
{
if(m->locks != 0)
- throw("gosched holding locks");
+ runtime·throw("gosched holding locks");
if(g == m->g0)
- throw("gosched of g0");
- if(gosave(&g->sched) == 0)
- gogo(&m->sched, 1);
+ runtime·throw("gosched of g0");
+ if(runtime·gosave(&g->sched) == 0)
+ runtime·gogo(&m->sched, 1);
}
// 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 and cgocall,
// not from the low-level system calls used by the runtime.
+// Entersyscall cannot split the stack: the runtime·gosave must
+// make g->sched refer to the caller's stack pointer.
+#pragma textflag 7
void
-·entersyscall(void)
+runtime·entersyscall(void)
{
- lock(&sched);
+ runtime·lock(&runtime·sched);
// Leave SP around for gc and traceback.
// Do before notewakeup so that gc
// never sees Gsyscall with wrong stack.
- gosave(&g->sched);
- if(sched.predawn) {
- unlock(&sched);
+ runtime·gosave(&g->sched);
+ if(runtime·sched.predawn) {
+ runtime·unlock(&runtime·sched);
return;
}
g->status = Gsyscall;
- sched.mcpu--;
- sched.msyscall++;
- if(sched.gwait != 0)
+ runtime·sched.mcpu--;
+ runtime·sched.msyscall++;
+ if(runtime·sched.gwait != 0)
matchmg();
- if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
- sched.waitstop = 0;
- notewakeup(&sched.stopped);
+ if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+ runtime·sched.waitstop = 0;
+ runtime·notewakeup(&runtime·sched.stopped);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// The goroutine g exited its system call.
@@ -576,19 +591,19 @@ void
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
void
-·exitsyscall(void)
+runtime·exitsyscall(void)
{
- lock(&sched);
- if(sched.predawn) {
- unlock(&sched);
+ runtime·lock(&runtime·sched);
+ if(runtime·sched.predawn) {
+ runtime·unlock(&runtime·sched);
return;
}
- sched.msyscall--;
- sched.mcpu++;
+ runtime·sched.msyscall--;
+ runtime·sched.mcpu++;
// Fast path - if there's room for this m, we're done.
- if(sched.mcpu <= sched.mcpumax) {
+ if(runtime·sched.mcpu <= runtime·sched.mcpumax) {
g->status = Grunning;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return;
}
// Tell scheduler to put g back on the run queue:
@@ -596,35 +611,68 @@ void
// but keeps the garbage collector from thinking
// that g is running right now, which it's not.
g->readyonstop = 1;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
// Slow path - all the cpus are taken.
// The scheduler will ready g and put this m to sleep.
// When the scheduler takes g away from m,
- // it will undo the sched.mcpu++ above.
- gosched();
+ // it will undo the runtime·sched.mcpu++ above.
+ runtime·gosched();
+}
+
+// Restore the position of m's scheduler stack if we unwind the stack
+// through a cgo callback.
+static void
+runtime·unwindcgocallback(void **spaddr, void *sp)
+{
+ *spaddr = sp;
}
// Start scheduling g1 again for a cgo callback.
void
-startcgocallback(G* g1)
+runtime·startcgocallback(G* g1)
{
- lock(&sched);
+ Defer *d;
+ uintptr arg;
+
+ runtime·lock(&runtime·sched);
g1->status = Grunning;
- sched.msyscall--;
- sched.mcpu++;
- unlock(&sched);
+ runtime·sched.msyscall--;
+ runtime·sched.mcpu++;
+ runtime·unlock(&runtime·sched);
+
+ // Add an entry to the defer stack which restores the old
+ // position of m's scheduler stack. This is so that if the
+ // code we are calling panics, we won't lose the space on the
+ // scheduler stack. Note that we are locked to this m here.
+ d = runtime·malloc(sizeof(*d) + 2*sizeof(void*) - sizeof(d->args));
+ d->fn = (byte*)runtime·unwindcgocallback;
+ d->siz = 2 * sizeof(uintptr);
+ ((void**)d->args)[0] = &m->sched.sp;
+ ((void**)d->args)[1] = m->sched.sp;
+ d->link = g1->defer;
+ g1->defer = d;
}
// Stop scheduling g1 after a cgo callback.
void
-endcgocallback(G* g1)
+runtime·endcgocallback(G* g1)
{
- lock(&sched);
+ Defer *d;
+
+ runtime·lock(&runtime·sched);
g1->status = Gsyscall;
- sched.mcpu--;
- sched.msyscall++;
- unlock(&sched);
+ runtime·sched.mcpu--;
+ runtime·sched.msyscall++;
+ runtime·unlock(&runtime·sched);
+
+ // Remove the entry on the defer stack added by
+ // startcgocallback.
+ d = g1->defer;
+ if (d == nil || d->fn != (byte*)runtime·unwindcgocallback)
+ runtime·throw("bad defer entry in endcgocallback");
+ g1->defer = d->link;
+ runtime·free(d);
}
/*
@@ -697,7 +745,7 @@ enum
};
void
-oldstack(void)
+runtime·oldstack(void)
{
Stktop *top, old;
uint32 args;
@@ -714,20 +762,20 @@ oldstack(void)
args = old.args;
if(args > 0) {
sp -= args;
- mcpy(top->fp, sp, args);
+ runtime·mcpy(top->fp, sp, args);
}
goid = old.gobuf.g->goid; // fault if g is bad, before gogo
if(old.free)
- stackfree(g1->stackguard - StackGuard);
+ runtime·stackfree(g1->stackguard - StackGuard);
g1->stackbase = old.stackbase;
g1->stackguard = old.stackguard;
- gogo(&old.gobuf, m->cret);
+ runtime·gogo(&old.gobuf, m->cret);
}
void
-newstack(void)
+runtime·newstack(void)
{
int32 frame, args;
Stktop *top;
@@ -740,6 +788,8 @@ newstack(void)
args = m->moreargs;
g1 = m->curg;
+ if(m->morebuf.sp < g1->stackguard - StackGuard)
+ runtime·throw("split stack overflow");
if(frame == 1 && args > 0 && m->morebuf.sp - sizeof(Stktop) - args - 32 > g1->stackguard) {
// special case: called from reflect.call (frame == 1)
@@ -758,12 +808,13 @@ newstack(void)
if(frame < StackBig)
frame = StackBig;
frame += 1024; // room for more functions, Stktop.
- stk = stackalloc(frame);
+ stk = runtime·stackalloc(frame);
top = (Stktop*)(stk+frame-sizeof(*top));
free = true;
}
-//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
+//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n",
+//frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
top->stackbase = g1->stackbase;
top->stackguard = g1->stackguard;
@@ -782,32 +833,32 @@ newstack(void)
sp = (byte*)top;
if(args > 0) {
sp -= args;
- mcpy(sp, m->morefp, args);
+ runtime·mcpy(sp, m->morefp, args);
}
// Continue as if lessstack had just called m->morepc
// (the PC that decided to grow the stack).
label.sp = sp;
- label.pc = (byte*)·lessstack;
+ label.pc = (byte*)runtime·lessstack;
label.g = m->curg;
- gogocall(&label, m->morepc);
+ runtime·gogocall(&label, m->morepc);
*(int32*)345 = 123; // never return
}
G*
-malg(int32 stacksize)
+runtime·malg(int32 stacksize)
{
G *g;
byte *stk;
- g = malloc(sizeof(G));
+ g = runtime·malloc(sizeof(G));
if(stacksize >= 0) {
- stk = stackalloc(stacksize + StackGuard);
+ stk = runtime·stackalloc(stacksize + StackGuard);
g->stack0 = stk;
g->stackguard = stk + StackGuard;
g->stackbase = stk + StackGuard + stacksize - sizeof(Stktop);
- runtime_memclr(g->stackbase, sizeof(Stktop));
+ runtime·memclr(g->stackbase, sizeof(Stktop));
}
return g;
}
@@ -823,13 +874,13 @@ malg(int32 stacksize)
*/
#pragma textflag 7
void
-·newproc(int32 siz, byte* fn, ...)
+runtime·newproc(int32 siz, byte* fn, ...)
{
- newproc1(fn, (byte*)(&fn+1), siz, 0);
+ runtime·newproc1(fn, (byte*)(&fn+1), siz, 0);
}
G*
-newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
+runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
{
byte *sp;
G *newg;
@@ -839,36 +890,36 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
siz = narg + nret;
siz = (siz+7) & ~7;
if(siz > 1024)
- throw("runtime.newproc: too many args");
+ runtime·throw("runtime.newproc: too many args");
- lock(&sched);
+ runtime·lock(&runtime·sched);
if((newg = gfget()) != nil){
newg->status = Gwaiting;
if(newg->stackguard - StackGuard != newg->stack0)
- throw("invalid stack in newg");
+ runtime·throw("invalid stack in newg");
} else {
- newg = malg(4096);
+ newg = runtime·malg(4096);
newg->status = Gwaiting;
- newg->alllink = allg;
- allg = newg;
+ newg->alllink = runtime·allg;
+ runtime·allg = newg;
}
sp = newg->stackbase;
sp -= siz;
- mcpy(sp, argp, narg);
+ runtime·mcpy(sp, argp, narg);
newg->sched.sp = sp;
- newg->sched.pc = (byte*)goexit;
+ newg->sched.pc = (byte*)runtime·goexit;
newg->sched.g = newg;
newg->entry = fn;
- sched.gcount++;
- goidgen++;
- newg->goid = goidgen;
+ runtime·sched.gcount++;
+ runtime·goidgen++;
+ newg->goid = runtime·goidgen;
newprocreadylocked(newg);
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return newg;
//printf(" goid=%d\n", newg->goid);
@@ -876,16 +927,16 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
#pragma textflag 7
uintptr
-·deferproc(int32 siz, byte* fn, ...)
+runtime·deferproc(int32 siz, byte* fn, ...)
{
Defer *d;
- d = malloc(sizeof(*d) + siz - sizeof(d->args));
+ d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args));
d->fn = fn;
d->sp = (byte*)(&fn+1);
d->siz = siz;
- d->pc = ·getcallerpc(&siz);
- mcpy(d->args, d->sp, d->siz);
+ d->pc = runtime·getcallerpc(&siz);
+ runtime·mcpy(d->args, d->sp, d->siz);
d->link = g->defer;
g->defer = d;
@@ -901,7 +952,7 @@ uintptr
#pragma textflag 7
void
-·deferreturn(uintptr arg0)
+runtime·deferreturn(uintptr arg0)
{
Defer *d;
byte *sp, *fn;
@@ -909,14 +960,14 @@ void
d = g->defer;
if(d == nil)
return;
- sp = getcallersp(&arg0);
+ sp = runtime·getcallersp(&arg0);
if(d->sp != sp)
return;
- mcpy(d->sp, d->args, d->siz);
+ runtime·mcpy(d->sp, d->args, d->siz);
g->defer = d->link;
fn = d->fn;
- free(d);
- jmpdefer(fn, sp);
+ runtime·free(d);
+ runtime·jmpdefer(fn, sp);
}
static void
@@ -927,7 +978,7 @@ rundefer(void)
while((d = g->defer) != nil) {
g->defer = d->link;
reflect·call(d->fn, d->args, d->siz);
- free(d);
+ runtime·free(d);
}
}
@@ -941,7 +992,7 @@ unwindstack(G *gp, byte *sp)
// Must be called from a different goroutine, usually m->g0.
if(g == gp)
- throw("unwindstack on self");
+ runtime·throw("unwindstack on self");
while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
stk = gp->stackguard - StackGuard;
@@ -949,12 +1000,13 @@ unwindstack(G *gp, byte *sp)
break;
gp->stackbase = top->stackbase;
gp->stackguard = top->stackguard;
- free(stk);
+ if(top->free)
+ runtime·stackfree(stk);
}
if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) {
- printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
- throw("bad unwindstack");
+ runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
+ runtime·throw("bad unwindstack");
}
}
@@ -963,22 +1015,22 @@ printpanics(Panic *p)
{
if(p->link) {
printpanics(p->link);
- printf("\t");
+ runtime·printf("\t");
}
- printf("panic: ");
- ·printany(p->arg);
+ runtime·printf("panic: ");
+ runtime·printany(p->arg);
if(p->recovered)
- printf(" [recovered]");
- printf("\n");
+ runtime·printf(" [recovered]");
+ runtime·printf("\n");
}
void
-·panic(Eface e)
+runtime·panic(Eface e)
{
Defer *d;
Panic *p;
- p = mal(sizeof *p);
+ p = runtime·mal(sizeof *p);
p->arg = e;
p->link = g->panic;
p->stackbase = g->stackbase;
@@ -991,35 +1043,37 @@ void
// take defer off list in case of recursive panic
g->defer = d->link;
g->ispanic = true; // rock for newstack, where reflect.call ends up
- reflect·call(d->fn, d->args, d->siz);
+ if(thechar == '5')
+ reflect·call(d->fn, d->args+4, d->siz-4); // reflect.call does not expect LR
+ else
+ reflect·call(d->fn, d->args, d->siz);
if(p->recovered) {
g->panic = p->link;
- free(p);
+ runtime·free(p);
// put recovering defer back on list
// for scheduler to find.
d->link = g->defer;
g->defer = d;
g->status = Grecovery;
- gosched();
- throw("recovery failed"); // gosched should not return
+ runtime·gosched();
+ runtime·throw("recovery failed"); // gosched should not return
}
- free(d);
+ runtime·free(d);
}
// ran out of deferred calls - old-school panic now
- fd = 2;
printpanics(g->panic);
- panic(0);
+ runtime·dopanic(0);
}
#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */
void
-·recover(byte *fp, Eface ret)
+runtime·recover(byte *fp, Eface ret)
{
Stktop *top, *oldtop;
Panic *p;
- fp = getcallersp(fp);
+ fp = runtime·getcallersp(fp);
// Must be a panic going on.
if((p = g->panic) == nil || p->recovered)
@@ -1090,9 +1144,9 @@ static void
gfput(G *g)
{
if(g->stackguard - StackGuard != g->stack0)
- throw("invalid stack in gfput");
- g->schedlink = sched.gfree;
- sched.gfree = g;
+ runtime·throw("invalid stack in gfput");
+ g->schedlink = runtime·sched.gfree;
+ runtime·sched.gfree = g;
}
// Get from gfree list. Sched must be locked.
@@ -1101,69 +1155,69 @@ gfget(void)
{
G *g;
- g = sched.gfree;
+ g = runtime·sched.gfree;
if(g)
- sched.gfree = g->schedlink;
+ runtime·sched.gfree = g->schedlink;
return g;
}
void
-·Breakpoint(void)
+runtime·Breakpoint(void)
{
- breakpoint();
+ runtime·breakpoint();
}
void
-·Goexit(void)
+runtime·Goexit(void)
{
rundefer();
- goexit();
+ runtime·goexit();
}
void
-·Gosched(void)
+runtime·Gosched(void)
{
- gosched();
+ runtime·gosched();
}
void
-·LockOSThread(void)
+runtime·LockOSThread(void)
{
- if(sched.predawn)
- throw("cannot wire during init");
+ if(runtime·sched.predawn)
+ runtime·throw("cannot wire during init");
m->lockedg = g;
g->lockedm = m;
}
// delete when scheduler is stronger
int32
-gomaxprocsfunc(int32 n)
+runtime·gomaxprocsfunc(int32 n)
{
int32 ret;
- lock(&sched);
- ret = sched.gomaxprocs;
+ runtime·lock(&runtime·sched);
+ ret = runtime·sched.gomaxprocs;
if (n <= 0)
n = ret;
- sched.gomaxprocs = n;
- sched.mcpumax = n;
+ runtime·sched.gomaxprocs = n;
+ runtime·sched.mcpumax = n;
// handle fewer procs?
- if(sched.mcpu > sched.mcpumax) {
- unlock(&sched);
+ if(runtime·sched.mcpu > runtime·sched.mcpumax) {
+ runtime·unlock(&runtime·sched);
// just give up the cpu.
// we'll only get rescheduled once the
// number has come down.
- gosched();
+ runtime·gosched();
return ret;
}
// handle more procs
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return ret;
}
void
-·UnlockOSThread(void)
+runtime·UnlockOSThread(void)
{
m->lockedg = nil;
g->lockedm = nil;
@@ -1171,8 +1225,15 @@ void
// for testing of wire, unwire
void
-·mid(uint32 ret)
+runtime·mid(uint32 ret)
{
ret = m->id;
FLUSH(&ret);
}
+
+void
+runtime·Goroutines(int32 ret)
+{
+ ret = runtime·sched.gcount;
+ FLUSH(&ret);
+}
diff --git a/src/pkg/runtime/reflect.goc b/src/pkg/runtime/reflect.goc
index 51222f1c4..a2e3c6ee1 100644
--- a/src/pkg/runtime/reflect.goc
+++ b/src/pkg/runtime/reflect.goc
@@ -24,11 +24,11 @@ gettype(void *typ)
*/
func mapaccess(map *byte, key *byte, val *byte) (pres bool) {
- mapaccess((Hmap*)map, key, val, &pres);
+ runtime·mapaccess((Hmap*)map, key, val, &pres);
}
func mapassign(map *byte, key *byte, val *byte) {
- mapassign((Hmap*)map, key, val);
+ runtime·mapassign((Hmap*)map, key, val);
}
func maplen(map *byte) (len int32) {
@@ -37,22 +37,22 @@ func maplen(map *byte) (len int32) {
}
func mapiterinit(map *byte) (it *byte) {
- it = (byte*)mapiterinit((Hmap*)map);
+ it = (byte*)runtime·newmapiterinit((Hmap*)map);
}
func mapiternext(it *byte) {
- mapiternext((struct hash_iter*)it);
+ runtime·mapiternext((struct hash_iter*)it);
}
func mapiterkey(it *byte, key *byte) (ok bool) {
- ok = mapiterkey((struct hash_iter*)it, key);
+ ok = runtime·mapiterkey((struct hash_iter*)it, key);
}
func makemap(typ *byte) (map *byte) {
MapType *t;
t = (MapType*)gettype(typ);
- map = (byte*)makemap(t->key, t->elem, 0);
+ map = (byte*)runtime·makemap_c(t->key, t->elem, 0);
}
/*
@@ -67,31 +67,31 @@ func makechan(typ *byte, size uint32) (ch *byte) {
// in front of the raw ChanType. the -2 below backs up
// to the interface value header.
t = (ChanType*)gettype(typ);
- ch = (byte*)makechan(t->elem, size);
+ ch = (byte*)runtime·makechan_c(t->elem, size);
}
func chansend(ch *byte, val *byte, pres *bool) {
- chansend((Hchan*)ch, val, pres);
+ runtime·chansend((Hchan*)ch, val, pres);
}
func chanrecv(ch *byte, val *byte, pres *bool) {
- chanrecv((Hchan*)ch, val, pres);
+ runtime·chanrecv((Hchan*)ch, val, pres);
}
func chanclose(ch *byte) {
- chanclose((Hchan*)ch);
+ runtime·chanclose((Hchan*)ch);
}
func chanclosed(ch *byte) (r bool) {
- r = chanclosed((Hchan*)ch);
+ r = runtime·chanclosed((Hchan*)ch);
}
func chanlen(ch *byte) (r int32) {
- r = chanlen((Hchan*)ch);
+ r = runtime·chanlen((Hchan*)ch);
}
func chancap(ch *byte) (r int32) {
- r = chancap((Hchan*)ch);
+ r = runtime·chancap((Hchan*)ch);
}
@@ -114,5 +114,5 @@ func setiface(typ *byte, x *byte, ret *byte) {
((Iface*)ret)->data = nil;
return;
}
- ifaceE2I((InterfaceType*)gettype(typ), *(Eface*)x, (Iface*)ret);
+ runtime·ifaceE2I((InterfaceType*)gettype(typ), *(Eface*)x, (Iface*)ret);
}
diff --git a/src/pkg/runtime/rune.c b/src/pkg/runtime/rune.c
index 598edc6f3..86ee76ddd 100644
--- a/src/pkg/runtime/rune.c
+++ b/src/pkg/runtime/rune.c
@@ -39,8 +39,7 @@ enum
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 */
+ Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
@@ -72,7 +71,7 @@ enum
* reasons, we return 1 instead of 0.
*/
int32
-charntorune(int32 *rune, uint8 *str, int32 length)
+runtime·charntorune(int32 *rune, uint8 *str, int32 length)
{
int32 c, c1, c2, c3, l;
@@ -168,7 +167,7 @@ badlen:
}
int32
-runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
+runtime·runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
{
/* Runes are signed, so convert to unsigned for range check. */
uint32 c;
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
new file mode 100644
index 000000000..a7ca94cdb
--- /dev/null
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -0,0 +1,398 @@
+# Copyright 2010 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.
+
+"""GDB Pretty printers and convencience functions for Go's runtime structures.
+
+This script is loaded by GDB when it finds a .debug_gdb_scripts
+section in the compiled binary. The [68]l linkers emit this with a
+path to this file based on the path to the runtime package.
+"""
+
+# Known issues:
+# - pretty printing only works for the 'native' strings. E.g. 'type
+# foo string' will make foo a plain struct in the eyes of gdb,
+# circumventing the pretty print triggering.
+# -
+
+import sys, re
+
+print >>sys.stderr, "Loading Go Runtime support."
+
+# allow to manually reload while developing
+goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
+goobjfile.pretty_printers = []
+
+#
+# Pretty Printers
+#
+
+class StringTypePrinter:
+ "Pretty print Go strings."
+
+ pattern = re.compile(r'^struct string$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'string'
+
+ def to_string(self):
+ return self.val['str']
+
+
+class SliceTypePrinter:
+ "Pretty print slices."
+
+ pattern = re.compile(r'^struct \[\]')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'array'
+
+ def to_string(self):
+ return str(self.val.type)[6:] # skip 'struct '
+
+ def children(self):
+ ptr = self.val["array"]
+ for idx in range(self.val["len"]):
+ yield ('[%d]' % idx, (ptr + idx).dereference())
+
+
+class MapTypePrinter:
+ """Pretty print map[K]V types.
+
+ Map-typed go variables are really pointers. dereference them in gdb
+ to inspect their contents with this pretty printer.
+ """
+
+ pattern = re.compile(r'^struct hash<.*>$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'map'
+
+ def to_string(self):
+ return str(self.val.type)
+
+ def children(self):
+ stab = self.val['st']
+ i = 0
+ for v in self.traverse_hash(stab):
+ yield ("[%d]" % i, v['key'])
+ yield ("[%d]" % (i + 1), v['val'])
+ i += 2
+
+ def traverse_hash(self, stab):
+ ptr = stab['entry'].address
+ end = stab['end']
+ while ptr < end:
+ v = ptr.dereference()
+ ptr = ptr + 1
+ if v['hash'] == 0: continue
+ if v['hash'] & 63 == 63: # subtable
+ for v in self.traverse_hash(v['key'].cast(self.val['st'].type)):
+ yield v
+ else:
+ yield v
+
+
+class ChanTypePrinter:
+ """Pretty print chan[T] types.
+
+ Chan-typed go variables are really pointers. dereference them in gdb
+ to inspect their contents with this pretty printer.
+ """
+
+ pattern = re.compile(r'^struct hchan<.*>$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'array'
+
+ def to_string(self):
+ return str(self.val.type)
+
+ def children(self):
+ ptr = self.val['recvdataq']
+ for idx in range(self.val["qcount"]):
+ yield ('[%d]' % idx, ptr['elem'])
+ ptr = ptr['link']
+
+#
+# Register all the *Printer classes above.
+#
+
+def makematcher(klass):
+ def matcher(val):
+ try:
+ if klass.pattern.match(str(val.type)):
+ return klass(val)
+ except:
+ pass
+ return matcher
+
+goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
+
+#
+# For reference, this is what we're trying to do:
+# eface: p *(*(struct 'runtime.commonType'*)'main.e'->type_->data)->string
+# iface: p *(*(struct 'runtime.commonType'*)'main.s'->tab->Type->data)->string
+#
+# interface types can't be recognized by their name, instead we check
+# if they have the expected fields. Unfortunately the mapping of
+# fields to python attributes in gdb.py isn't complete: you can't test
+# for presence other than by trapping.
+
+
+def is_iface(val):
+ try:
+ return str(val['tab'].type) == "struct runtime.itab *" \
+ and str(val['data'].type) == "void *"
+ except:
+ pass
+
+def is_eface(val):
+ try:
+ return str(val['type_'].type) == "runtime.Type *" \
+ and str(val['data'].type) == "void *"
+ except:
+ pass
+
+def lookup_type(name):
+ try:
+ return gdb.lookup_type(name)
+ except:
+ pass
+ try:
+ return gdb.lookup_type('struct ' + name)
+ except:
+ pass
+ try:
+ return gdb.lookup_type('struct ' + name[1:]).pointer()
+ except:
+ pass
+
+
+def iface_dtype(obj):
+ "Decode type of the data field of an eface or iface struct."
+
+ if is_iface(obj):
+ go_type_ptr = obj['tab']['Type']
+ elif is_eface(obj):
+ go_type_ptr = obj['type_']
+ else:
+ return
+
+ ct = gdb.lookup_type("struct runtime.commonType").pointer()
+ dynamic_go_type = go_type_ptr['data'].cast(ct).dereference()
+ dtype_name = dynamic_go_type['string'].dereference()['str'].string()
+ type_size = int(dynamic_go_type['size'])
+ uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
+ dynamic_gdb_type = lookup_type(dtype_name)
+ if type_size > uintptr_size:
+ dynamic_gdb_type = dynamic_gdb_type.pointer()
+ return dynamic_gdb_type
+
+
+class IfacePrinter:
+ """Pretty print interface values
+
+ Casts the data field to the appropriate dynamic type."""
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'string'
+
+ def to_string(self):
+ try:
+ dtype = iface_dtype(self.val)
+ except:
+ return "<bad dynamic type>"
+ try:
+ return self.val['data'].cast(dtype).dereference()
+ except:
+ pass
+ return self.val['data'].cast(dtype)
+
+
+def ifacematcher(val):
+ if is_iface(val) or is_eface(val):
+ return IfacePrinter(val)
+
+goobjfile.pretty_printers.append(ifacematcher)
+
+#
+# Convenience Functions
+#
+
+class GoLenFunc(gdb.Function):
+ "Length of strings, slices, maps or channels"
+
+ how = ((StringTypePrinter, 'len' ),
+ (SliceTypePrinter, 'len'),
+ (MapTypePrinter, 'count'),
+ (ChanTypePrinter, 'qcount'))
+
+ def __init__(self):
+ super(GoLenFunc, self).__init__("len")
+
+ def invoke(self, obj):
+ typename = str(obj.type)
+ for klass, fld in self.how:
+ if klass.pattern.match(typename):
+ return obj[fld]
+
+class GoCapFunc(gdb.Function):
+ "Capacity of slices or channels"
+
+ how = ((SliceTypePrinter, 'cap'),
+ (ChanTypePrinter, 'dataqsiz'))
+
+ def __init__(self):
+ super(GoCapFunc, self).__init__("cap")
+
+ def invoke(self, obj):
+ typename = str(obj.type)
+ for klass, fld in self.how:
+ if klass.pattern.match(typename):
+ return obj[fld]
+
+class DTypeFunc(gdb.Function):
+ """Cast Interface values to their dynamic type.
+
+ For non-interface types this behaves as the identity operation.
+ """
+
+ def __init__(self):
+ super(DTypeFunc, self).__init__("dtype")
+
+ def invoke(self, obj):
+ try:
+ return obj['data'].cast(iface_dtype(obj))
+ except:
+ pass
+ return obj
+
+#
+# Commands
+#
+
+sts = ( 'idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+
+def linked_list(ptr, linkfield):
+ while ptr:
+ yield ptr
+ ptr = ptr[linkfield]
+
+
+class GoroutinesCmd(gdb.Command):
+ "List all goroutines."
+
+ def __init__(self):
+ super(GoroutinesCmd, self).__init__("info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ # args = gdb.string_to_argv(arg)
+ vp = gdb.lookup_type('void').pointer()
+ for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+ if ptr['status'] == 6: # 'gdead'
+ continue
+ m = ptr['m']
+ s = ' '
+ if m:
+ pc = m['sched']['pc'].cast(vp)
+ sp = m['sched']['sp'].cast(vp)
+ s = '*'
+ else:
+ pc = ptr['sched']['pc'].cast(vp)
+ sp = ptr['sched']['sp'].cast(vp)
+ blk = gdb.block_for_pc(long((pc)))
+ print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
+
+def find_goroutine(goid):
+ vp = gdb.lookup_type('void').pointer()
+ for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+ if ptr['status'] == 6: # 'gdead'
+ continue
+ if ptr['goid'] == goid:
+ return [(ptr['m'] or ptr)['sched'][x].cast(vp) for x in 'pc', 'sp']
+ return None, None
+
+
+class GoroutineCmd(gdb.Command):
+ """Execute gdb command in the context of goroutine <goid>.
+
+ Switch PC and SP to the ones in the goroutine's G structure,
+ execute an arbitrary gdb command, and restore PC and SP.
+
+ Usage: (gdb) goroutine <goid> <gdbcmd>
+
+ Note that it is ill-defined to modify state in the context of a goroutine.
+ Restrict yourself to inspecting values.
+ """
+
+ def __init__(self):
+ super(GoroutineCmd, self).__init__("goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ goid, cmd = arg.split(None, 1)
+ pc, sp = find_goroutine(int(goid))
+ if not pc:
+ print "No such goroutine: ", goid
+ return
+ save_frame = gdb.selected_frame()
+ gdb.parse_and_eval('$save_pc = $pc')
+ gdb.parse_and_eval('$save_sp = $sp')
+ gdb.parse_and_eval('$pc = 0x%x' % long(pc))
+ gdb.parse_and_eval('$sp = 0x%x' % long(sp))
+ try:
+ gdb.execute(cmd)
+ finally:
+ gdb.parse_and_eval('$pc = $save_pc')
+ gdb.parse_and_eval('$sp = $save_sp')
+ save_frame.select()
+
+
+class GoIfaceCmd(gdb.Command):
+ "Print Static and dynamic interface types"
+
+ def __init__(self):
+ super(GoIfaceCmd, self).__init__("iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+
+ def invoke(self, arg, from_tty):
+ for obj in gdb.string_to_argv(arg):
+ try:
+ #TODO fix quoting for qualified variable names
+ obj = gdb.parse_and_eval("%s" % obj)
+ except Exception, e:
+ print "Can't parse ", obj, ": ", e
+ continue
+
+ dtype = iface_dtype(obj)
+ if not dtype:
+ print "Not an interface: ", obj.type
+ continue
+
+ print "%s: %s" % (obj.type, dtype)
+
+# TODO: print interface's methods and dynamic type's func pointers thereof.
+#rsc: "to find the number of entries in the itab's Fn field look at itab.inter->numMethods
+#i am sure i have the names wrong but look at the interface type and its method count"
+# so Itype will start with a commontype which has kind = interface
+
+#
+# Register all convience functions and CLI commands
+#
+for k in vars().values():
+ if hasattr(k, 'invoke'):
+ k()
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 25a6f26bd..9d3efe966 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -4,87 +4,87 @@
#include "runtime.h"
-int32 panicking = 0;
-int32 maxround = sizeof(uintptr);
-int32 fd = 1;
+enum {
+ maxround = sizeof(uintptr),
+};
+
+int32 runtime·panicking = 0;
int32
-gotraceback(void)
+runtime·gotraceback(void)
{
byte *p;
- p = getenv("GOTRACEBACK");
+ p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
- return atoi(p);
+ return runtime·atoi(p);
}
void
-panic(int32 unused)
+runtime·dopanic(int32 unused)
{
- fd = 2;
- if(panicking) {
- printf("double panic\n");
- exit(3);
+ if(runtime·panicking) {
+ runtime·printf("double panic\n");
+ runtime·exit(3);
}
- panicking++;
+ runtime·panicking++;
- printf("\npanic PC=%X\n", (uint64)(uintptr)&unused);
- if(gotraceback()){
- traceback(·getcallerpc(&unused), getcallersp(&unused), 0, g);
- tracebackothers(g);
+ runtime·printf("\npanic PC=%X\n", (uint64)(uintptr)&unused);
+ if(runtime·gotraceback()){
+ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ runtime·tracebackothers(g);
}
- breakpoint(); // so we can grab it in a debugger
- exit(2);
+ runtime·breakpoint(); // so we can grab it in a debugger
+ runtime·exit(2);
}
void
-·panicindex(void)
+runtime·panicindex(void)
{
- panicstring("index out of range");
+ runtime·panicstring("index out of range");
}
void
-·panicslice(void)
+runtime·panicslice(void)
{
- panicstring("slice bounds out of range");
+ runtime·panicstring("slice bounds out of range");
}
void
-·throwreturn(void)
+runtime·throwreturn(void)
{
// can only happen if compiler is broken
- throw("no return at end of a typed function - compiler is broken");
+ runtime·throw("no return at end of a typed function - compiler is broken");
}
void
-·throwinit(void)
+runtime·throwinit(void)
{
// can only happen with linker skew
- throw("recursive call during initialization - linker skew");
+ runtime·throw("recursive call during initialization - linker skew");
}
void
-throw(int8 *s)
+runtime·throw(int8 *s)
{
- fd = 2;
- printf("throw: %s\n", s);
- panic(-1);
+ runtime·printf("throw: %s\n", s);
+ runtime·dopanic(0);
*(int32*)0 = 0; // not reached
- exit(1); // even more not reached
+ runtime·exit(1); // even more not reached
}
void
-panicstring(int8 *s)
+runtime·panicstring(int8 *s)
{
Eface err;
- ·newErrorString(gostringnocopy((byte*)s), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
+ runtime·panic(err);
}
void
-mcpy(byte *t, byte *f, uint32 n)
+runtime·mcpy(byte *t, byte *f, uint32 n)
{
while(n > 0) {
*t = *f;
@@ -95,7 +95,7 @@ mcpy(byte *t, byte *f, uint32 n)
}
int32
-mcmp(byte *s1, byte *s2, uint32 n)
+runtime·mcmp(byte *s1, byte *s2, uint32 n)
{
uint32 i;
byte c1, c2;
@@ -113,7 +113,7 @@ mcmp(byte *s1, byte *s2, uint32 n)
byte*
-mchr(byte *p, byte c, byte *ep)
+runtime·mchr(byte *p, byte c, byte *ep)
{
for(; p < ep; p++)
if(*p == c)
@@ -122,7 +122,7 @@ mchr(byte *p, byte c, byte *ep)
}
uint32
-rnd(uint32 n, uint32 m)
+runtime·rnd(uint32 n, uint32 m)
{
uint32 r;
@@ -141,54 +141,65 @@ Slice os·Args;
Slice os·Envs;
void
-args(int32 c, uint8 **v)
+runtime·args(int32 c, uint8 **v)
{
argc = c;
argv = v;
}
+int32 runtime·isplan9;
+
void
-goargs(void)
+runtime·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]);
+ String *s;
+ int32 i;
+
+ // for windows implementation see "os" package
+ if(Windows)
+ return;
+ s = runtime·malloc(argc*sizeof s[0]);
for(i=0; i<argc; i++)
- gargv[i] = gostringnocopy(argv[i]);
- os·Args.array = (byte*)gargv;
+ s[i] = runtime·gostringnocopy(argv[i]);
+ os·Args.array = (byte*)s;
os·Args.len = argc;
os·Args.cap = argc;
+}
- for(i=0; i<envc; i++)
- genvv[i] = gostringnocopy(argv[argc+1+i]);
- os·Envs.array = (byte*)genvv;
- os·Envs.len = envc;
- os·Envs.cap = envc;
+void
+runtime·goenvs_unix(void)
+{
+ String *s;
+ int32 i, n;
+
+ for(n=0; argv[argc+1+n] != 0; n++)
+ ;
+
+ s = runtime·malloc(n*sizeof s[0]);
+ for(i=0; i<n; i++)
+ s[i] = runtime·gostringnocopy(argv[argc+1+i]);
+ os·Envs.array = (byte*)s;
+ os·Envs.len = n;
+ os·Envs.cap = n;
}
// Atomic add and return new value.
uint32
-xadd(uint32 volatile *val, int32 delta)
+runtime·xadd(uint32 volatile *val, int32 delta)
{
uint32 oval, nval;
for(;;){
oval = *val;
nval = oval + delta;
- if(cas(val, oval, nval))
+ if(runtime·cas(val, oval, nval))
return nval;
}
}
byte*
-getenv(int8 *s)
+runtime·getenv(int8 *s)
{
int32 i, j, len;
byte *v, *bs;
@@ -196,7 +207,7 @@ getenv(int8 *s)
int32 envc;
bs = (byte*)s;
- len = findnull(bs);
+ len = runtime·findnull(bs);
envv = (String*)os·Envs.array;
envc = os·Envs.len;
for(i=0; i<envc; i++){
@@ -215,17 +226,17 @@ getenv(int8 *s)
}
void
-·getgoroot(String out)
+runtime·getgoroot(String out)
{
byte *p;
- p = getenv("GOROOT");
- out = gostringnocopy(p);
+ p = runtime·getenv("GOROOT");
+ out = runtime·gostringnocopy(p);
FLUSH(&out);
}
int32
-atoi(byte *p)
+runtime·atoi(byte *p)
{
int32 n;
@@ -236,7 +247,7 @@ atoi(byte *p)
}
void
-check(void)
+runtime·check(void)
{
int8 a;
uint8 b;
@@ -250,35 +261,44 @@ check(void)
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");
+ struct x1 {
+ byte x;
+ };
+ struct y1 {
+ struct x1 x1;
+ byte y;
+ };
+
+ if(sizeof(a) != 1) runtime·throw("bad a");
+ if(sizeof(b) != 1) runtime·throw("bad b");
+ if(sizeof(c) != 2) runtime·throw("bad c");
+ if(sizeof(d) != 2) runtime·throw("bad d");
+ if(sizeof(e) != 4) runtime·throw("bad e");
+ if(sizeof(f) != 4) runtime·throw("bad f");
+ if(sizeof(g) != 8) runtime·throw("bad g");
+ if(sizeof(h) != 8) runtime·throw("bad h");
+ if(sizeof(i) != 4) runtime·throw("bad i");
+ if(sizeof(j) != 8) runtime·throw("bad j");
+ if(sizeof(k) != sizeof(uintptr)) runtime·throw("bad k");
+ if(sizeof(l) != sizeof(uintptr)) runtime·throw("bad l");
+ if(sizeof(struct x1) != 1) runtime·throw("bad sizeof x1");
+ if(offsetof(struct y1, y) != 1) runtime·throw("bad offsetof y1.y");
+ if(sizeof(struct y1) != 2) runtime·throw("bad sizeof y1");
uint32 z;
z = 1;
- if(!cas(&z, 1, 2))
- throw("cas1");
+ if(!runtime·cas(&z, 1, 2))
+ runtime·throw("cas1");
if(z != 2)
- throw("cas2");
+ runtime·throw("cas2");
z = 4;
- if(cas(&z, 5, 6))
- throw("cas3");
+ if(runtime·cas(&z, 5, 6))
+ runtime·throw("cas3");
if(z != 4)
- throw("cas4");
+ runtime·throw("cas4");
- initsig(0);
+ runtime·initsig(0);
}
/*
@@ -310,14 +330,19 @@ memhash(uint32 s, void *a)
static uint32
memequal(uint32 s, void *a, void *b)
{
- byte *ba, *bb;
- uint32 i;
+ byte *ba, *bb, *aend;
+ if(a == b)
+ return 1;
ba = a;
bb = b;
- for(i=0; i<s; i++)
- if(ba[i] != bb[i])
+ aend = ba+s;
+ while(ba != aend) {
+ if(*ba != *bb)
return 0;
+ ba++;
+ bb++;
+ }
return 1;
}
@@ -341,7 +366,7 @@ memprint(uint32 s, void *a)
v = *(uint64*)a;
break;
}
- ·printint(v);
+ runtime·printint(v);
}
static void
@@ -361,6 +386,24 @@ memcopy(uint32 s, void *a, void *b)
ba[i] = bb[i];
}
+static uint32
+memwordequal(uint32 s, void *a, void *b)
+{
+ USED(s);
+ return *(uintptr*)(a) == *(uintptr*)(b);
+}
+
+static void
+memwordcopy(uint32 s, void *a, void *b)
+{
+ USED(s);
+ if (b == nil) {
+ *(uintptr*)(a) = 0;
+ return;
+ }
+ *(uintptr*)(a) = *(uintptr*)(b);
+}
+
static uintptr
strhash(uint32 s, String *a)
{
@@ -371,119 +414,118 @@ strhash(uint32 s, String *a)
static uint32
strequal(uint32 s, String *a, String *b)
{
+ int32 alen;
+
USED(s);
- return cmpstring(*a, *b) == 0;
+ alen = a->len;
+ if(alen != b->len)
+ return false;
+ return memequal(alen, a->str, b->str);
}
static void
strprint(uint32 s, String *a)
{
USED(s);
- ·printstring(*a);
+ runtime·printstring(*a);
}
static uintptr
interhash(uint32 s, Iface *a)
{
USED(s);
- return ifacehash(*a);
+ return runtime·ifacehash(*a);
}
static void
interprint(uint32 s, Iface *a)
{
USED(s);
- ·printiface(*a);
+ runtime·printiface(*a);
}
static uint32
interequal(uint32 s, Iface *a, Iface *b)
{
USED(s);
- return ifaceeq(*a, *b);
+ return runtime·ifaceeq_c(*a, *b);
}
static uintptr
nilinterhash(uint32 s, Eface *a)
{
USED(s);
- return efacehash(*a);
+ return runtime·efacehash(*a);
}
static void
nilinterprint(uint32 s, Eface *a)
{
USED(s);
- ·printeface(*a);
+ runtime·printeface(*a);
}
static uint32
nilinterequal(uint32 s, Eface *a, Eface *b)
{
USED(s);
- return efaceeq(*a, *b);
+ return runtime·efaceeq_c(*a, *b);
}
uintptr
-nohash(uint32 s, void *a)
+runtime·nohash(uint32 s, void *a)
{
USED(s);
USED(a);
- panicstring("hash of unhashable type");
+ runtime·panicstring("hash of unhashable type");
return 0;
}
uint32
-noequal(uint32 s, void *a, void *b)
+runtime·noequal(uint32 s, void *a, void *b)
{
USED(s);
USED(a);
USED(b);
- panicstring("comparing uncomparable types");
+ runtime·panicstring("comparing uncomparable types");
return 0;
}
Alg
-algarray[] =
+runtime·algarray[] =
{
[AMEM] { memhash, memequal, memprint, memcopy },
-[ANOEQ] { nohash, noequal, memprint, memcopy },
+[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy },
[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
+[AMEMWORD] { memhash, memwordequal, memprint, memwordcopy },
};
-#pragma textflag 7
-void
-FLUSH(void *v)
-{
- USED(v);
-}
-
int64
-nanotime(void)
+runtime·nanotime(void)
{
int64 sec;
int32 usec;
sec = 0;
usec = 0;
- gettime(&sec, &usec);
+ runtime·gettime(&sec, &usec);
return sec*1000000000 + (int64)usec*1000;
}
void
-·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
+runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
{
Func *f;
- if(callers(1+skip, &retpc, 1) == 0 || (f = findfunc(retpc-1)) == nil) {
- retfile = emptystring;
+ if(runtime·callers(1+skip, &retpc, 1) == 0 || (f = runtime·findfunc(retpc-1)) == nil) {
+ retfile = runtime·emptystring;
retline = 0;
retbool = false;
} else {
retfile = f->src;
- retline = funcline(f, retpc-1);
+ retline = runtime·funcline(f, retpc-1);
retbool = true;
}
FLUSH(&retfile);
@@ -492,15 +534,15 @@ void
}
void
-·Callers(int32 skip, Slice pc, int32 retn)
+runtime·Callers(int32 skip, Slice pc, int32 retn)
{
- retn = callers(skip, (uintptr*)pc.array, pc.len);
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
FLUSH(&retn);
}
void
-·FuncForPC(uintptr pc, void *retf)
+runtime·FuncForPC(uintptr pc, void *retf)
{
- retf = findfunc(pc);
+ retf = runtime·findfunc(pc);
FLUSH(&retf);
}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index a774d96d5..bde62833e 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -76,7 +76,7 @@ typedef struct Complex128 Complex128;
* segment register.
*
* amd64: allocated downwards from R15
- * x86: allocated upwards from 0(FS)
+ * x86: allocated upwards from 0(GS)
* arm: allocated downwards from R10
*
* every C file linked into a Go program must include runtime.h
@@ -230,11 +230,11 @@ struct M
uint32 machport; // Return address for Mach IPC (OS X)
MCache *mcache;
G* lockedg;
- uint64 freg[8]; // Floating point register storage used by ARM software fp routines
+ uint32 freglo[16]; // D[i] lsb and F[i]
+ uint32 freghi[16]; // D[i] msb and F[i+16]
+ uint32 fflag; // floating point compare flags
#ifdef __WINDOWS__
- void* return_address; // saved return address and stack
- void* stack_pointer; // pointer for Windows stdcall
- void* os_stack_pointer;
+ void* gostack; // bookmark to keep track of go stack during stdcall
#endif
};
struct Stktop
@@ -289,6 +289,16 @@ struct Func
int32 locals; // number of 32-bit locals
};
+#ifdef __WINDOWS__
+enum {
+ Windows = 1
+};
+#else
+enum {
+ Windows = 0
+};
+#endif
+
/*
* defined macros
* you need super-goru privilege
@@ -296,6 +306,7 @@ struct Func
*/
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
+#define offsetof(s,m) (uint32)(&(((s*)0)->m))
/*
* known to compiler
@@ -307,6 +318,7 @@ enum
ASTRING,
AINTER,
ANILINTER,
+ AMEMWORD,
Amax
};
@@ -342,110 +354,110 @@ struct Panic
/*
* external data
*/
-extern Alg algarray[Amax];
-extern String emptystring;
-G* allg;
-M* allm;
-int32 goidgen;
-extern int32 gomaxprocs;
-extern int32 panicking;
-extern int32 maxround;
-extern int32 fd; // usually 1; set to 2 when panicking
-extern int32 gcwaiting; // gc is waiting to run
-int8* goos;
+extern Alg runtime·algarray[Amax];
+extern String runtime·emptystring;
+G* runtime·allg;
+M* runtime·allm;
+int32 runtime·goidgen;
+extern int32 runtime·gomaxprocs;
+extern int32 runtime·panicking;
+extern int32 runtime·gcwaiting; // gc is waiting to run
+int8* runtime·goos;
+extern bool runtime·iscgo;
/*
* common functions and data
*/
-int32 strcmp(byte*, byte*);
-int32 findnull(byte*);
-int32 findnullw(uint16*);
-void dump(byte*, int32);
-int32 runetochar(byte*, int32);
-int32 charntorune(int32*, uint8*, int32);
+int32 runtime·strcmp(byte*, byte*);
+int32 runtime·findnull(byte*);
+int32 runtime·findnullw(uint16*);
+void runtime·dump(byte*, int32);
+int32 runtime·runetochar(byte*, int32);
+int32 runtime·charntorune(int32*, uint8*, int32);
/*
* very low level c-called
*/
-void gogo(Gobuf*, uintptr);
-void gogocall(Gobuf*, void(*)(void));
-uintptr gosave(Gobuf*);
-void ·lessstack(void);
-void goargs(void);
-void FLUSH(void*);
-void* getu(void);
-void throw(int8*);
-void panicstring(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 memmove(void*, void*, uint32);
-void* mal(uintptr);
-uint32 cmpstring(String, String);
-String catstring(String, String);
-String gostring(byte*);
-String gostringnocopy(byte*);
-String gostringw(uint16*);
-void initsig(int32);
-int32 gotraceback(void);
-void traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
-void tracebackothers(G*);
-int32 open(byte*, int32, ...);
-int32 write(int32, void*, int32);
-bool cas(uint32*, uint32, uint32);
-bool casp(void**, void*, void*);
-uint32 xadd(uint32 volatile*, int32);
-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 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 free(void *v);
-void addfinalizer(void*, void(*fn)(void*), int32);
-void walkfintab(void (*fn)(void*));
-void runpanic(Panic*);
-void* getcallersp(void*);
-
-void exit(int32);
-void breakpoint(void);
-void gosched(void);
-void goexit(void);
-void runcgo(void (*fn)(void*), void*);
-void runcgocallback(G*, void*, void (*fn)());
-void ·entersyscall(void);
-void ·exitsyscall(void);
-void startcgocallback(G*);
-void endcgocallback(G*);
-G* newproc1(byte*, byte*, int32, int32);
-void siginit(void);
-bool sigsend(int32 sig);
-void gettime(int64*, int32*);
-int32 callers(int32, uintptr*, int32);
-int64 nanotime(void);
-void panic(int32);
-
-#pragma varargck argpos printf 1
-
+#define FLUSH(x) USED(x)
+
+void runtime·gogo(Gobuf*, uintptr);
+void runtime·gogocall(Gobuf*, void(*)(void));
+uintptr runtime·gosave(Gobuf*);
+void runtime·lessstack(void);
+void runtime·goargs(void);
+void runtime·goenvs(void);
+void runtime·goenvs_unix(void);
+void* runtime·getu(void);
+void runtime·throw(int8*);
+void runtime·panicstring(int8*);
+uint32 runtime·rnd(uint32, uint32);
+void runtime·prints(int8*);
+void runtime·printf(int8*, ...);
+byte* runtime·mchr(byte*, byte, byte*);
+void runtime·mcpy(byte*, byte*, uint32);
+int32 runtime·mcmp(byte*, byte*, uint32);
+void runtime·memmove(void*, void*, uint32);
+void* runtime·mal(uintptr);
+String runtime·catstring(String, String);
+String runtime·gostring(byte*);
+String runtime·gostringn(byte*, int32);
+String runtime·gostringnocopy(byte*);
+String runtime·gostringw(uint16*);
+void runtime·initsig(int32);
+int32 runtime·gotraceback(void);
+void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
+void runtime·tracebackothers(G*);
+int32 runtime·write(int32, void*, int32);
+bool runtime·cas(uint32*, uint32, uint32);
+bool runtime·casp(void**, void*, void*);
+uint32 runtime·xadd(uint32 volatile*, int32);
+void runtime·jmpdefer(byte*, void*);
+void runtime·exit1(int32);
+void runtime·ready(G*);
+byte* runtime·getenv(int8*);
+int32 runtime·atoi(byte*);
+void runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void));
+void runtime·signalstack(byte*, int32);
+G* runtime·malg(int32);
+void runtime·minit(void);
+Func* runtime·findfunc(uintptr);
+int32 runtime·funcline(Func*, uint64);
+void* runtime·stackalloc(uint32);
+void runtime·stackfree(void*);
+MCache* runtime·allocmcache(void);
+void runtime·mallocinit(void);
+bool runtime·ifaceeq_c(Iface, Iface);
+bool runtime·efaceeq_c(Eface, Eface);
+uintptr runtime·ifacehash(Iface);
+uintptr runtime·efacehash(Eface);
+uintptr runtime·nohash(uint32, void*);
+uint32 runtime·noequal(uint32, void*, void*);
+void* runtime·malloc(uintptr size);
+void runtime·free(void *v);
+void runtime·addfinalizer(void*, void(*fn)(void*), int32);
+void runtime·walkfintab(void (*fn)(void*));
+void runtime·runpanic(Panic*);
+void* runtime·getcallersp(void*);
+
+void runtime·exit(int32);
+void runtime·breakpoint(void);
+void runtime·gosched(void);
+void runtime·goexit(void);
+void runtime·runcgo(void (*fn)(void*), void*);
+void runtime·runcgocallback(G*, void*, void (*fn)());
+void runtime·entersyscall(void);
+void runtime·exitsyscall(void);
+void runtime·startcgocallback(G*);
+void runtime·endcgocallback(G*);
+G* runtime·newproc1(byte*, byte*, int32, int32);
+void runtime·siginit(void);
+bool runtime·sigsend(int32 sig);
+void runtime·gettime(int64*, int32*);
+int32 runtime·callers(int32, uintptr*, int32);
+int64 runtime·nanotime(void);
+void runtime·dopanic(int32);
+
+#pragma varargck argpos runtime·printf 1
#pragma varargck type "d" int32
#pragma varargck type "d" uint32
#pragma varargck type "D" int64
@@ -462,8 +474,8 @@ void panic(int32);
// TODO(rsc): Remove. These are only temporary,
// for the mark and sweep collector.
-void stoptheworld(void);
-void starttheworld(void);
+void runtime·stoptheworld(void);
+void runtime·starttheworld(void);
/*
* mutual exclusion locks. in the uncontended case,
@@ -471,9 +483,9 @@ void starttheworld(void);
* 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*);
-void destroylock(Lock*);
+void runtime·lock(Lock*);
+void runtime·unlock(Lock*);
+void runtime·destroylock(Lock*);
/*
* sleep and wakeup on one-time events.
@@ -484,32 +496,9 @@ void destroylock(Lock*);
* 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 runtime_memclr ·memclr
-#define runtime_getcallerpc ·getcallerpc
-#define runtime_mmap ·mmap
-#define runtime_printslice ·printslice
-#define runtime_printbool ·printbool
-#define runtime_printfloat ·printfloat
-#define runtime_printhex ·printhex
-#define runtime_printint ·printint
-#define runtime_printiface ·printiface
-#define runtime_printeface ·printeface
-#define runtime_printpc ·printpc
-#define runtime_printpointer ·printpointer
-#define runtime_printstring ·printstring
-#define runtime_printuint ·printuint
-#define runtime_printcomplex ·printcomplex
-#define runtime_setcallerpc ·setcallerpc
-#endif
+void runtime·noteclear(Note*);
+void runtime·notesleep(Note*);
+void runtime·notewakeup(Note*);
/*
* This is consistent across Linux and BSD.
@@ -521,72 +510,83 @@ void notewakeup(Note*);
/*
* low level go-called
*/
-uint8* runtime_mmap(byte*, uintptr, int32, int32, int32, uint32);
-void runtime_memclr(byte*, uint32);
-void runtime_setcallerpc(void*, void*);
-void* runtime_getcallerpc(void*);
+uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
+void runtime·munmap(uint8*, uintptr);
+void runtime·memclr(byte*, uint32);
+void runtime·setcallerpc(void*, void*);
+void* runtime·getcallerpc(void*);
/*
* runtime go-called
*/
-void runtime_printbool(bool);
-void runtime_printfloat(float64);
-void runtime_printint(int64);
-void runtime_printiface(Iface);
-void runtime_printeface(Eface);
-void runtime_printstring(String);
-void runtime_printpc(void*);
-void runtime_printpointer(void*);
-void runtime_printuint(uint64);
-void runtime_printhex(uint64);
-void runtime_printslice(Slice);
-void runtime_printcomplex(Complex128);
+void runtime·printbool(bool);
+void runtime·printfloat(float64);
+void runtime·printint(int64);
+void runtime·printiface(Iface);
+void runtime·printeface(Eface);
+void runtime·printstring(String);
+void runtime·printpc(void*);
+void runtime·printpointer(void*);
+void runtime·printuint(uint64);
+void runtime·printhex(uint64);
+void runtime·printslice(Slice);
+void runtime·printcomplex(Complex128);
void reflect·call(byte*, byte*, uint32);
-void ·panic(Eface);
-void ·panicindex(void);
-void ·panicslice(void);
+void runtime·panic(Eface);
+void runtime·panicindex(void);
+void runtime·panicslice(void);
+
/*
* runtime c-called (but written in Go)
*/
-void ·newError(String, Eface*);
-void ·printany(Eface);
-void ·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
-void ·newErrorString(String, Eface*);
+void runtime·newError(String, Eface*);
+void runtime·printany(Eface);
+void runtime·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
+void runtime·newErrorString(String, Eface*);
+void runtime·fadd64c(uint64, uint64, uint64*);
+void runtime·fsub64c(uint64, uint64, uint64*);
+void runtime·fmul64c(uint64, uint64, uint64*);
+void runtime·fdiv64c(uint64, uint64, uint64*);
+void runtime·fneg64c(uint64, uint64*);
+void runtime·f32to64c(uint32, uint64*);
+void runtime·f64to32c(uint64, uint32*);
+void runtime·fcmp64c(uint64, uint64, int32*, bool*);
+void runtime·fintto64c(int64, uint64*);
+void runtime·f64tointc(uint64, int64*, bool*);
/*
* 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*);
-String signame(int32 sig);
-int32 gomaxprocsfunc(int32 n);
-
-
-void mapassign(Hmap*, byte*, byte*);
-void mapaccess(Hmap*, byte*, byte*, bool*);
-struct hash_iter* mapiterinit(Hmap*);
-void mapiternext(struct hash_iter*);
-bool mapiterkey(struct hash_iter*, void*);
-void mapiterkeyvalue(struct hash_iter*, void*, void*);
-Hmap* makemap(Type*, Type*, int64);
-
-Hchan* makechan(Type*, int64);
-void chansend(Hchan*, void*, bool*);
-void chanrecv(Hchan*, void*, bool*);
-void chanclose(Hchan*);
-bool chanclosed(Hchan*);
-int32 chanlen(Hchan*);
-int32 chancap(Hchan*);
-
-void ifaceE2I(struct InterfaceType*, Eface, Iface*);
+float64 runtime·Inf(int32 sign);
+float64 runtime·NaN(void);
+float32 runtime·float32frombits(uint32 i);
+uint32 runtime·float32tobits(float32 f);
+float64 runtime·float64frombits(uint64 i);
+uint64 runtime·float64tobits(float64 f);
+float64 runtime·frexp(float64 d, int32 *ep);
+bool runtime·isInf(float64 f, int32 sign);
+bool runtime·isNaN(float64 f);
+float64 runtime·ldexp(float64 d, int32 e);
+float64 runtime·modf(float64 d, float64 *ip);
+void runtime·semacquire(uint32*);
+void runtime·semrelease(uint32*);
+String runtime·signame(int32 sig);
+int32 runtime·gomaxprocsfunc(int32 n);
+
+void runtime·mapassign(Hmap*, byte*, byte*);
+void runtime·mapaccess(Hmap*, byte*, byte*, bool*);
+struct hash_iter* runtime·newmapiterinit(Hmap*);
+void runtime·mapiternext(struct hash_iter*);
+bool runtime·mapiterkey(struct hash_iter*, void*);
+void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
+Hmap* runtime·makemap_c(Type*, Type*, int64);
+
+Hchan* runtime·makechan_c(Type*, int64);
+void runtime·chansend(Hchan*, void*, bool*);
+void runtime·chanrecv(Hchan*, void*, bool*);
+void runtime·chanclose(Hchan*);
+bool runtime·chanclosed(Hchan*);
+int32 runtime·chanlen(Hchan*);
+int32 runtime·chancap(Hchan*);
+
+void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*);
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index 548844329..da2d0c572 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -6,5 +6,5 @@ package runtime
#include "runtime.h"
func GOMAXPROCS(n int32) (ret int32) {
- ret = gomaxprocsfunc(n);
+ ret = runtime·gomaxprocsfunc(n);
}
diff --git a/src/pkg/runtime/runtime_defs.go b/src/pkg/runtime/runtime_defs.go
new file mode 100644
index 000000000..ba3c3ed75
--- /dev/null
+++ b/src/pkg/runtime/runtime_defs.go
@@ -0,0 +1,200 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is runtime.h
+
+// TODO(lvd): automate conversion to all the _defs.go files
+
+package runtime
+
+import "unsafe"
+
+const (
+ gidle = iota
+ grunnable
+ grunning
+ gsyscall
+ gwaiting
+ gmoribund
+ gdead
+ grecovery
+)
+
+// const ( Structrnd = sizeof(uintptr) )
+
+type string_ struct {
+ str *byte
+ len int32
+}
+
+type iface struct {
+ tab *itab
+ data unsafe.Pointer
+}
+
+type eface struct {
+ type_ *Type
+ data unsafe.Pointer
+}
+
+type complex64 struct {
+ real float32
+ imag float32
+}
+
+type complex128 struct {
+ real float64
+ imag float64
+}
+
+type slice struct {
+ array *byte
+ len uint32
+ cap uint32
+}
+
+type gobuf struct {
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ g *g_
+}
+
+type g_ struct {
+ stackguard unsafe.Pointer
+ stackbase unsafe.Pointer
+ defer_ *defer_
+ panic_ *panic_
+ sched gobuf
+ stack0 unsafe.Pointer
+ entry unsafe.Pointer
+ alllink *g_
+ param unsafe.Pointer
+ status int16
+ goid int32
+ selgen uint32
+ schedlink *g_
+ readyonstop bool
+ ispanic bool
+ m *m_
+ lockedm *m_
+ sig int32
+ sigcode0 uintptr
+ sigcode1 uintptr
+}
+
+type m_ struct {
+ g0 *g_
+ morepc unsafe.Pointer
+ morefp unsafe.Pointer
+ morebuf gobuf
+ moreframe uint32
+ moreargs uint32
+ cret uintptr
+ procid uint64
+ gsignal *g_
+ tls [8]uint32
+ sched gobuf
+ curg *g_
+ id int32
+ mallocing int32
+ gcing int32
+ locks int32
+ nomemprof int32
+ waitnextg int32
+ havenextg note
+ nextg *g_
+ alllink *m_
+ schedlink *m_
+ machport uint32
+ mcache *mCache
+ lockedg *g_
+ freg [8]uint64
+ // gostack unsafe.Pointer // __WINDOWS__
+}
+
+type stktop struct {
+ stackguard *uint8
+ stackbase *uint8
+ gobuf gobuf
+ args uint32
+ fp *uint8
+ free bool
+ panic_ bool
+}
+
+type alg struct {
+ hash func(uint32, unsafe.Pointer) uintptr
+ equal func(uint32, unsafe.Pointer, unsafe.Pointer) uint32
+ print func(uint32, unsafe.Pointer)
+ copy func(uint32, unsafe.Pointer, unsafe.Pointer)
+}
+
+type sigtab struct {
+ flags int32
+ name *int8
+}
+
+const (
+ sigCatch = (1 << iota)
+ sigIgnore
+ sigRestart
+ sigQueue
+ sigPanic
+)
+
+type Func struct {
+ name string
+ typ string
+ src string
+ pcln []byte
+ entry uintptr
+ pc0 uintptr
+ ln0 int32
+ frame int32
+ args int32
+ locals int32
+}
+
+const (
+ aMEM = iota
+ aNOEQ
+ aSTRING
+ aINTER
+ aNILINTER
+ aMEMWORD
+ amax
+)
+
+type defer_ struct {
+ siz int32
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ fn unsafe.Pointer
+ link *defer_
+ args [8]byte // padded to actual size
+}
+
+type panic_ struct {
+ arg eface
+ stackbase unsafe.Pointer
+ link *panic_
+ recovered bool
+}
+
+/*
+ * External data.
+ */
+
+var (
+ algarray [amax]alg
+ emptystring string
+ allg *g_
+ allm *m_
+ goidgen int32
+ gomaxprocs int32
+ panicking int32
+ fd int32
+ gcwaiting int32
+ goos *int8
+)
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 71395ce77..1c77e87a5 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -39,7 +39,7 @@ semqueue(uint32 *addr, Sema *s)
s->addr = addr;
s->g = nil;
- lock(&semlock);
+ runtime·lock(&semlock);
s->prev = semlast;
s->next = nil;
if(semlast)
@@ -47,13 +47,13 @@ semqueue(uint32 *addr, Sema *s)
else
semfirst = s;
semlast = s;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
static void
semdequeue(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
if(s->next)
s->next->prev = s->prev;
else
@@ -64,7 +64,7 @@ semdequeue(Sema *s)
semfirst = s->next;
s->prev = nil;
s->next = nil;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
static void
@@ -72,15 +72,15 @@ semwakeup(uint32 *addr)
{
Sema *s;
- lock(&semlock);
+ runtime·lock(&semlock);
for(s=semfirst; s; s=s->next) {
if(s->addr == addr && s->g) {
- ready(s->g);
+ runtime·ready(s->g);
s->g = nil;
break;
}
}
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Step 1 of sleep: make ourselves available for wakeup.
@@ -90,16 +90,16 @@ semwakeup(uint32 *addr)
static void
semsleep1(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
s->g = g;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Decided not to go through with it: undo step 1.
static void
semsleepundo1(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
if(s->g != nil) {
s->g = nil; // back ourselves out
} else {
@@ -111,7 +111,7 @@ semsleepundo1(Sema *s)
*(int32*)0x555 = 555;
g->readyonstop = 0;
}
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Step 2: wait for the wakeup.
@@ -120,7 +120,7 @@ semsleep2(Sema *s)
{
USED(s);
g->status = Gwaiting;
- gosched();
+ runtime·gosched();
}
static int32
@@ -129,7 +129,7 @@ cansemacquire(uint32 *addr)
uint32 v;
while((v = *addr) > 0)
- if(cas(addr, v, v-1))
+ if(runtime·cas(addr, v, v-1))
return 1;
return 0;
}
@@ -137,7 +137,7 @@ cansemacquire(uint32 *addr)
// For now has no return value.
// Might return an ok (not interrupted) bool in the future?
void
-semacquire(uint32 *addr)
+runtime·semacquire(uint32 *addr)
{
Sema s;
@@ -164,22 +164,22 @@ semacquire(uint32 *addr)
}
void
-semrelease(uint32 *addr)
+runtime·semrelease(uint32 *addr)
{
uint32 v;
for(;;) {
v = *addr;
- if(cas(addr, v, v+1))
+ if(runtime·cas(addr, v, v+1))
break;
}
semwakeup(addr);
}
func Semacquire(addr *uint32) {
- semacquire(addr);
+ runtime·semacquire(addr);
}
func Semrelease(addr *uint32) {
- semrelease(addr);
+ runtime·semrelease(addr);
}
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
index 572daab52..504590a54 100644
--- a/src/pkg/runtime/sigqueue.goc
+++ b/src/pkg/runtime/sigqueue.goc
@@ -47,14 +47,14 @@ static struct {
} sig;
void
-siginit(void)
+runtime·siginit(void)
{
- noteclear(&sig);
+ runtime·noteclear(&sig);
}
// Called from sighandler to send a signal back out of the signal handling thread.
bool
-sigsend(int32 s)
+runtime·sigsend(int32 s)
{
uint32 bit, mask;
@@ -65,11 +65,11 @@ sigsend(int32 s)
mask = sig.mask;
if(mask & bit)
break; // signal already in queue
- if(cas(&sig.mask, mask, mask|bit)) {
+ if(runtime·cas(&sig.mask, mask, mask|bit)) {
// Added to queue.
// Only send a wakeup for the first signal in each round.
if(mask == 0)
- notewakeup(&sig);
+ runtime·notewakeup(&sig);
break;
}
}
@@ -78,22 +78,22 @@ sigsend(int32 s)
// Called to receive a bitmask of queued signals.
func Sigrecv() (m uint32) {
- ·entersyscall();
- notesleep(&sig);
- ·exitsyscall();
- noteclear(&sig);
+ runtime·entersyscall();
+ runtime·notesleep(&sig);
+ runtime·exitsyscall();
+ runtime·noteclear(&sig);
for(;;) {
m = sig.mask;
- if(cas(&sig.mask, m, 0))
+ if(runtime·cas(&sig.mask, m, 0))
break;
}
}
func Signame(sig int32) (name String) {
- name = signame(sig);
+ name = runtime·signame(sig);
}
func Siginit() {
- initsig(SigQueue);
+ runtime·initsig(SigQueue);
sig.inuse = true; // enable reception of signals; cannot disable
}
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 4162b8daa..051075479 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -8,60 +8,124 @@
static int32 debug = 0;
+static void makeslice1(SliceType*, int32, int32, Slice*);
+ void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
+
// see also unsafe·NewArray
// makeslice(typ *Type, len, cap int64) (ary []any);
void
-·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
+runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{
- uintptr size;
-
if(len < 0 || (int32)len != len)
- panicstring("makeslice: len out of range");
+ runtime·panicstring("makeslice: len out of range");
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
- panicstring("makeslice: cap out of range");
+ runtime·panicstring("makeslice: cap out of range");
+
+ makeslice1(t, len, cap, &ret);
+
+ if(debug) {
+ runtime·printf("makeslice(%S, %D, %D); ret=",
+ *t->string, len, cap);
+ runtime·printslice(ret);
+ }
+}
+
+static void
+makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
+{
+ uintptr size;
size = cap*t->elem->size;
- ret.len = len;
- ret.cap = cap;
+ ret->len = len;
+ ret->cap = cap;
if((t->elem->kind&KindNoPointers))
- ret.array = mallocgc(size, RefNoPointers, 1, 1);
+ ret->array = runtime·mallocgc(size, RefNoPointers, 1, 1);
else
- ret.array = mal(size);
+ ret->array = runtime·mal(size);
+}
- FLUSH(&ret);
+static void appendslice1(SliceType*, Slice, Slice, Slice*);
- if(debug) {
- printf("makeslice(%S, %D, %D); ret=",
- *t->string, len, cap);
- ·printslice(ret);
+// append(type *Type, n int, old []T, ...,) []T
+#pragma textflag 7
+void
+runtime·append(SliceType *t, int32 n, Slice old, ...)
+{
+ Slice sl;
+ Slice *ret;
+
+ sl.len = n;
+ sl.array = (byte*)(&old+1);
+ ret = (Slice*)(sl.array + ((t->elem->size*n+sizeof(uintptr)-1) & ~(sizeof(uintptr)-1)));
+ appendslice1(t, old, sl, ret);
+}
+
+// appendslice(type *Type, x, y, []T) []T
+void
+runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
+{
+ appendslice1(t, x, y, &ret);
+}
+
+static void
+appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
+{
+ Slice newx;
+ int32 m;
+ uintptr w;
+
+ if(x.len+y.len < x.len)
+ runtime·throw("append: slice overflow");
+
+ w = t->elem->size;
+ if(x.len+y.len > x.cap) {
+ m = x.cap;
+ if(m == 0)
+ m = y.len;
+ else {
+ do {
+ if(x.len < 1024)
+ m += m;
+ else
+ m += m/4;
+ } while(m < x.len+y.len);
+ }
+ makeslice1(t, x.len, m, &newx);
+ runtime·memmove(newx.array, x.array, x.len*w);
+ x = newx;
}
+ runtime·memmove(x.array+x.len*w, y.array, y.len*w);
+ x.len += y.len;
+ *ret = x;
}
-// sliceslice(old []any, lb int, hb int, width int) (ary []any);
+
+
+// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
void
-·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)
+runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
{
if(hb > old.cap || lb > hb) {
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("\n");
-
- prints("oldarray: nel=");
- ·printint(old.len);
- prints("; cap=");
- ·printint(old.cap);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
+
+ runtime·prints("oldarray: nel=");
+ runtime·printint(old.len);
+ runtime·prints("; cap=");
+ runtime·printint(old.cap);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -72,41 +136,41 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
-// sliceslice1(old []any, lb int, width int) (ary []any);
+// sliceslice1(old []any, lb uint64, width uint64) (ary []any);
void
-·sliceslice1(Slice old, uint32 lb, uint32 width, Slice ret)
+runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret)
{
if(lb > old.len) {
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; width=");
- ·printint(width);
- prints("\n");
-
- prints("oldarray: nel=");
- ·printint(old.len);
- prints("; cap=");
- ·printint(old.cap);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
+
+ runtime·prints("oldarray: nel=");
+ runtime·printint(old.len);
+ runtime·prints("; cap=");
+ runtime·printint(old.cap);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -117,21 +181,21 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
-// slicearray(old *any, nel int, lb int, hb int, width int) (ary []any);
+// slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any);
void
-·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Slice ret)
+runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, Slice ret)
{
if(nel > 0 && old == nil) {
// crash if old == nil.
@@ -143,19 +207,19 @@ void
if(hb > nel || lb > hb) {
if(debug) {
- prints("runtime.slicearray: old=");
- ·printpointer(old);
- prints("; nel=");
- ·printint(nel);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("\n");
+ runtime·prints("runtime.slicearray: old=");
+ runtime·printpointer(old);
+ runtime·prints("; nel=");
+ runtime·printint(nel);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -166,25 +230,25 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.slicearray: old=");
- ·printpointer(old);
- prints("; nel=");
- ·printint(nel);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.slicearray: old=");
+ runtime·printpointer(old);
+ runtime·prints("; nel=");
+ runtime·printint(nel);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
// slicecopy(to any, fr any, wid uint32) int
void
-·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
+runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
{
if(fm.len == 0 || to.len == 0 || width == 0) {
ret = 0;
@@ -198,32 +262,50 @@ void
if(ret == 1 && width == 1) { // common case worth about 2x to do here
*to.array = *fm.array; // known to be a byte pointer
} else {
- memmove(to.array, fm.array, ret*width);
+ runtime·memmove(to.array, fm.array, ret*width);
}
out:
FLUSH(&ret);
if(debug) {
- prints("main·copy: to=");
- ·printslice(to);
- prints("; fm=");
- ·printslice(fm);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printint(ret);
- prints("\n");
+ runtime·prints("main·copy: to=");
+ runtime·printslice(to);
+ runtime·prints("; fm=");
+ runtime·printslice(fm);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printint(ret);
+ runtime·prints("\n");
+ }
+}
+
+void
+runtime·slicestringcopy(Slice to, String fm, int32 ret)
+{
+ if(fm.len == 0 || to.len == 0) {
+ ret = 0;
+ goto out;
}
+
+ ret = fm.len;
+ if(to.len < ret)
+ ret = to.len;
+
+ runtime·memmove(to.array, fm.str, ret);
+
+out:
+ FLUSH(&ret);
}
void
-·printslice(Slice a)
+runtime·printslice(Slice a)
{
- prints("[");
- ·printint(a.len);
- prints("/");
- ·printint(a.cap);
- prints("]");
- ·printpointer(a.array);
+ runtime·prints("[");
+ runtime·printint(a.len);
+ runtime·prints("/");
+ runtime·printint(a.cap);
+ runtime·prints("]");
+ runtime·printpointer(a.array);
}
diff --git a/src/pkg/runtime/softfloat64.go b/src/pkg/runtime/softfloat64.go
new file mode 100644
index 000000000..d9bbe5def
--- /dev/null
+++ b/src/pkg/runtime/softfloat64.go
@@ -0,0 +1,498 @@
+// Copyright 2010 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.
+
+// Software IEEE754 64-bit floating point.
+// Only referred to (and thus linked in) by arm port
+// and by gotest in this directory.
+
+package runtime
+
+const (
+ mantbits64 uint = 52
+ expbits64 uint = 11
+ bias64 = -1<<(expbits64-1) + 1
+
+ nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1
+ inf64 uint64 = (1<<expbits64 - 1) << mantbits64
+ neg64 uint64 = 1 << (expbits64 + mantbits64)
+
+ mantbits32 uint = 23
+ expbits32 uint = 8
+ bias32 = -1<<(expbits32-1) + 1
+
+ nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1
+ inf32 uint32 = (1<<expbits32 - 1) << mantbits32
+ neg32 uint32 = 1 << (expbits32 + mantbits32)
+)
+
+func funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits64 + expbits64))
+ mant = f & (1<<mantbits64 - 1)
+ exp = int(f>>mantbits64) & (1<<expbits64 - 1)
+
+ switch exp {
+ case 1<<expbits64 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias64 + 1
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits64
+ exp += bias64
+ }
+ return
+}
+
+func funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits32 + expbits32))
+ mant = f & (1<<mantbits32 - 1)
+ exp = int(f>>mantbits32) & (1<<expbits32 - 1)
+
+ switch exp {
+ case 1<<expbits32 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias32 + 1
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits32
+ exp += bias32
+ }
+ return
+}
+
+func fpack64(sign, mant uint64, exp int, trunc uint64) uint64 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits64 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits64 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits64-1+bias64 {
+ return sign ^ inf64
+ }
+ if exp < bias64+1 {
+ if exp < bias64-int(mantbits64) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits64 {
+ return sign | mant
+ }
+ }
+ return sign | uint64(exp-bias64)<<mantbits64 | mant&(1<<mantbits64-1)
+}
+
+func fpack32(sign, mant uint32, exp int, trunc uint32) uint32 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits32 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits32 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits32-1+bias32 {
+ return sign ^ inf32
+ }
+ if exp < bias32+1 {
+ if exp < bias32-int(mantbits32) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits32 {
+ return sign | mant
+ }
+ }
+ return sign | uint32(exp-bias32)<<mantbits32 | mant&(1<<mantbits32-1)
+}
+
+func fadd64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN + x or x + NaN = NaN
+ return nan64
+
+ case fi && gi && fs != gs: // +Inf + -Inf or -Inf + +Inf = NaN
+ return nan64
+
+ case fi: // ±Inf + g = ±Inf
+ return f
+
+ case gi: // f + ±Inf = ±Inf
+ return g
+
+ case fm == 0 && gm == 0 && fs != 0 && gs != 0: // -0 + -0 = -0
+ return f
+
+ case fm == 0: // 0 + g = g but 0 + -0 = +0
+ if gm == 0 {
+ g ^= gs
+ }
+ return g
+
+ case gm == 0: // f + 0 = f
+ return f
+
+ }
+
+ if fe < ge || fe == ge && fm < gm {
+ f, g, fs, fm, fe, gs, gm, ge = g, f, gs, gm, ge, fs, fm, fe
+ }
+
+ shift := uint(fe - ge)
+ fm <<= 2
+ gm <<= 2
+ trunc := gm & (1<<shift - 1)
+ gm >>= shift
+ if fs == gs {
+ fm += gm
+ } else {
+ fm -= gm
+ if trunc != 0 {
+ fm--
+ }
+ }
+ if fm == 0 {
+ fs = 0
+ }
+ return fpack64(fs, fm, fe-2, trunc)
+}
+
+func fsub64(f, g uint64) uint64 {
+ return fadd64(f, fneg64(g))
+}
+
+func fneg64(f uint64) uint64 {
+ return f ^ (1 << (mantbits64 + expbits64))
+}
+
+func fmul64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN * g or f * NaN = NaN
+ return nan64
+
+ case fi && gi: // Inf * Inf = Inf (with sign adjusted)
+ return f ^ gs
+
+ case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN
+ return nan64
+
+ case fm == 0: // 0 * x = 0 (with sign adjusted)
+ return f ^ gs
+
+ case gm == 0: // x * 0 = 0 (with sign adjusted)
+ return g ^ fs
+ }
+
+ // 53-bit * 53-bit = 107- or 108-bit
+ lo, hi := mullu(fm, gm)
+ shift := mantbits64 - 1
+ trunc := lo & (1<<shift - 1)
+ mant := hi<<(64-shift) | lo>>shift
+ return fpack64(fs^gs, mant, fe+ge-1, trunc)
+}
+
+func fdiv64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN / g = f / NaN = NaN
+ return nan64
+
+ case fi && gi: // ±Inf / ±Inf = NaN
+ return nan64
+
+ case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN
+ return nan64
+
+ case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf
+ return fs ^ gs ^ inf64
+
+ case gi, fm == 0: // f / Inf = 0 / g = Inf
+ return fs ^ gs ^ 0
+ }
+ _, _, _, _ = fi, fn, gi, gn
+
+ // 53-bit<<54 / 53-bit = 53- or 54-bit.
+ shift := mantbits64 + 2
+ q, r := divlu(fm>>(64-shift), fm<<shift, gm)
+ return fpack64(fs^gs, q, fe-ge-2, r)
+}
+
+func f64to32(f uint64) uint32 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ if fn {
+ return nan32
+ }
+ fs32 := uint32(fs >> 32)
+ if fi {
+ return fs32 ^ inf32
+ }
+ const d = mantbits64 - mantbits32 - 1
+ return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1<<d-1)))
+}
+
+func f32to64(f uint32) uint64 {
+ const d = mantbits64 - mantbits32
+ fs, fm, fe, fi, fn := funpack32(f)
+ if fn {
+ return nan64
+ }
+ fs64 := uint64(fs) << 32
+ if fi {
+ return fs64 ^ inf64
+ }
+ return fpack64(fs64, uint64(fm)<<d, fe, 0)
+}
+
+func fcmp64(f, g uint64) (cmp int, isnan bool) {
+ fs, fm, _, fi, fn := funpack64(f)
+ gs, gm, _, gi, gn := funpack64(g)
+
+ switch {
+ case fn, gn: // flag NaN
+ return 0, true
+
+ case !fi && !gi && fm == 0 && gm == 0: // ±0 == ±0
+ return 0, false
+
+ case fs > gs: // f < 0, g > 0
+ return -1, false
+
+ case fs < gs: // f > 0, g < 0
+ return +1, false
+
+ // Same sign, not NaN.
+ // Can compare encodings directly now.
+ // Reverse for sign.
+ case fs == 0 && f < g, fs != 0 && f > g:
+ return -1, false
+
+ case fs == 0 && f > g, fs != 0 && f < g:
+ return +1, false
+ }
+
+ // f == g
+ return 0, false
+}
+
+func f64toint(f uint64) (val int64, ok bool) {
+ fs, fm, fe, fi, fn := funpack64(f)
+
+ switch {
+ case fi, fn: // NaN
+ return 0, false
+
+ case fe < -1: // f < 0.5
+ return 0, false
+
+ case fe > 63: // f >= 2^63
+ if fs != 0 && fm == 0 { // f == -2^63
+ return -1 << 63, true
+ }
+ if fs != 0 {
+ return 0, false
+ }
+ return 0, false
+ }
+
+ for fe > int(mantbits64) {
+ fe--
+ fm <<= 1
+ }
+ for fe < int(mantbits64) {
+ fe++
+ fm >>= 1
+ }
+ val = int64(fm)
+ if fs != 0 {
+ val = -val
+ }
+ return val, true
+}
+
+func fintto64(val int64) (f uint64) {
+ fs := uint64(val) & (1 << 63)
+ mant := uint64(val)
+ if fs != 0 {
+ mant = -mant
+ }
+ return fpack64(fs, mant, int(mantbits64), 0)
+}
+
+// 64x64 -> 128 multiply.
+// adapted from hacker's delight.
+func mullu(u, v uint64) (lo, hi uint64) {
+ const (
+ s = 32
+ mask = 1<<s - 1
+ )
+ u0 := u & mask
+ u1 := u >> s
+ v0 := v & mask
+ v1 := v >> s
+ w0 := u0 * v0
+ t := u1*v0 + w0>>s
+ w1 := t & mask
+ w2 := t >> s
+ w1 += u0 * v1
+ return u * v, u1*v1 + w2 + w1>>s
+}
+
+// 128/64 -> 64 quotient, 64 remainder.
+// adapted from hacker's delight
+func divlu(u1, u0, v uint64) (q, r uint64) {
+ const b = 1 << 32
+
+ if u1 >= v {
+ return 1<<64 - 1, 1<<64 - 1
+ }
+
+ // s = nlz(v); v <<= s
+ s := uint(0)
+ for v&(1<<63) == 0 {
+ s++
+ v <<= 1
+ }
+
+ vn1 := v >> 32
+ vn0 := v & (1<<32 - 1)
+ un32 := u1<<s | u0>>(64-s)
+ un10 := u0 << s
+ un1 := un10 >> 32
+ un0 := un10 & (1<<32 - 1)
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
+
+again1:
+ if q1 >= b || q1*vn0 > b*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < b {
+ goto again1
+ }
+ }
+
+ un21 := un32*b + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
+
+again2:
+ if q0 >= b || q0*vn0 > b*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < b {
+ goto again2
+ }
+ }
+
+ return q1*b + q0, (un21*b + un0 - q0*v) >> s
+}
+
+// callable from C
+
+func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/src/pkg/runtime/softfloat64_test.go b/src/pkg/runtime/softfloat64_test.go
new file mode 100644
index 000000000..fb7f3d3c0
--- /dev/null
+++ b/src/pkg/runtime/softfloat64_test.go
@@ -0,0 +1,198 @@
+// Copyright 2010 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 runtime_test
+
+import (
+ "math"
+ "rand"
+ . "runtime"
+ "testing"
+)
+
+// turn uint64 op into float64 op
+func fop(f func(x, y uint64) uint64) func(x, y float64) float64 {
+ return func(x, y float64) float64 {
+ bx := math.Float64bits(x)
+ by := math.Float64bits(y)
+ return math.Float64frombits(f(bx, by))
+ }
+}
+
+func add(x, y float64) float64 { return x + y }
+func sub(x, y float64) float64 { return x - y }
+func mul(x, y float64) float64 { return x * y }
+func div(x, y float64) float64 { return x / y }
+
+func TestFloat64(t *testing.T) {
+ base := []float64{
+ 0,
+ math.Copysign(0, -1),
+ -1,
+ 1,
+ math.NaN(),
+ math.Inf(+1),
+ math.Inf(-1),
+ 0.1,
+ 1.5,
+ 1.9999999999999998, // all 1s mantissa
+ 1.3333333333333333, // 1.010101010101...
+ 1.1428571428571428, // 1.001001001001...
+ 1.112536929253601e-308, // first normal
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256,
+ 3,
+ 12,
+ 1234,
+ 123456,
+ -0.1,
+ -1.5,
+ -1.9999999999999998,
+ -1.3333333333333333,
+ -1.1428571428571428,
+ -2,
+ -3,
+ 1e-200,
+ 1e-300,
+ 1e-310,
+ 5e-324,
+ 1e-105,
+ 1e-305,
+ 1e+200,
+ 1e+306,
+ 1e+307,
+ 1e+308,
+ }
+ all := make([]float64, 200)
+ copy(all, base)
+ for i := len(base); i < len(all); i++ {
+ all[i] = rand.NormFloat64()
+ }
+
+ test(t, "+", add, fop(Fadd64), all)
+ test(t, "-", sub, fop(Fsub64), all)
+ if GOARCH != "386" { // 386 is not precise!
+ test(t, "*", mul, fop(Fmul64), all)
+ test(t, "/", div, fop(Fdiv64), all)
+ }
+}
+
+// 64 -hw-> 32 -hw-> 64
+func trunc32(f float64) float64 {
+ return float64(float32(f))
+}
+
+// 64 -sw->32 -hw-> 64
+func to32sw(f float64) float64 {
+ return float64(math.Float32frombits(F64to32(math.Float64bits(f))))
+}
+
+// 64 -hw->32 -sw-> 64
+func to64sw(f float64) float64 {
+ return math.Float64frombits(F32to64(math.Float32bits(float32(f))))
+}
+
+// float64 -hw-> int64 -hw-> float64
+func hwint64(f float64) float64 {
+ return float64(int64(f))
+}
+
+// float64 -hw-> int32 -hw-> float64
+func hwint32(f float64) float64 {
+ return float64(int32(f))
+}
+
+// float64 -sw-> int64 -hw-> float64
+func toint64sw(f float64) float64 {
+ i, ok := F64toint(math.Float64bits(f))
+ if !ok {
+ // There's no right answer for out of range.
+ // Match the hardware to pass the test.
+ i = int64(f)
+ }
+ return float64(i)
+}
+
+// float64 -hw-> int64 -sw-> float64
+func fromint64sw(f float64) float64 {
+ return math.Float64frombits(Fintto64(int64(f)))
+}
+
+var nerr int
+
+func err(t *testing.T, format string, args ...interface{}) {
+ t.Errorf(format, args...)
+
+ // cut errors off after a while.
+ // otherwise we spend all our time
+ // allocating memory to hold the
+ // formatted output.
+ if nerr++; nerr >= 10 {
+ t.Fatal("too many errors")
+ }
+}
+
+func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) {
+ for _, f := range all {
+ for _, g := range all {
+ h := hw(f, g)
+ s := sw(f, g)
+ if !same(h, s) {
+ err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h)
+ }
+ testu(t, "to32", trunc32, to32sw, h)
+ testu(t, "to64", trunc32, to64sw, h)
+ testu(t, "toint64", hwint64, toint64sw, h)
+ testu(t, "fromint64", hwint64, fromint64sw, h)
+ testcmp(t, f, h)
+ testcmp(t, h, f)
+ testcmp(t, g, h)
+ testcmp(t, h, g)
+ }
+ }
+}
+
+func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) {
+ h := hw(v)
+ s := sw(v)
+ if !same(h, s) {
+ err(t, "%s %g = sw %g, hw %g\n", op, v, s, h)
+ }
+}
+
+func hwcmp(f, g float64) (cmp int, isnan bool) {
+ switch {
+ case f < g:
+ return -1, false
+ case f > g:
+ return +1, false
+ case f == g:
+ return 0, false
+ }
+ return 0, true // must be NaN
+}
+
+func testcmp(t *testing.T, f, g float64) {
+ hcmp, hisnan := hwcmp(f, g)
+ scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
+ if hcmp != scmp || hisnan != sisnan {
+ err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
+ }
+}
+
+func same(f, g float64) bool {
+ if math.IsNaN(f) && math.IsNaN(g) {
+ return true
+ }
+ if math.Copysign(1, f) != math.Copysign(1, g) {
+ return false
+ }
+ return f == g
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index 1a4847322..916559eb2 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -6,10 +6,10 @@ package runtime
#include "runtime.h"
#include "malloc.h"
-String emptystring;
+String runtime·emptystring;
int32
-findnull(byte *s)
+runtime·findnull(byte *s)
{
int32 l;
@@ -21,7 +21,7 @@ findnull(byte *s)
}
int32
-findnullw(uint16 *s)
+runtime·findnullw(uint16 *s)
{
int32 l;
@@ -32,46 +32,56 @@ findnullw(uint16 *s)
return l;
}
-int32 maxstring = 256;
+int32 runtime·maxstring = 256;
String
-gostringsize(int32 l)
+runtime·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)
+ return runtime·emptystring;
+ s.str = runtime·mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
s.len = l;
- if(l > maxstring)
- maxstring = l;
+ if(l > runtime·maxstring)
+ runtime·maxstring = l;
return s;
}
String
-gostring(byte *str)
+runtime·gostring(byte *str)
{
int32 l;
String s;
- l = findnull(str);
- s = gostringsize(l);
- mcpy(s.str, str, l);
+ l = runtime·findnull(str);
+ s = runtime·gostringsize(l);
+ runtime·mcpy(s.str, str, l);
return s;
}
String
-gostringnocopy(byte *str)
+runtime·gostringn(byte *str, int32 l)
+{
+ String s;
+
+ s = runtime·gostringsize(l);
+ runtime·mcpy(s.str, str, l);
+ return s;
+}
+
+String
+runtime·gostringnocopy(byte *str)
{
String s;
s.str = str;
- s.len = findnull(str);
+ s.len = runtime·findnull(str);
return s;
}
String
-gostringw(uint16 *str)
+runtime·gostringw(uint16 *str)
{
int32 n, i;
byte buf[8];
@@ -79,17 +89,17 @@ gostringw(uint16 *str)
n = 0;
for(i=0; str[i]; i++)
- n += runetochar(buf, str[i]);
- s = gostringsize(n+4);
+ n += runtime·runetochar(buf, str[i]);
+ s = runtime·gostringsize(n+4);
n = 0;
for(i=0; str[i]; i++)
- n += runetochar(s.str+n, str[i]);
+ n += runtime·runetochar(s.str+n, str[i]);
s.len = n;
return s;
}
String
-catstring(String s1, String s2)
+runtime·catstring(String s1, String s2)
{
String s3;
@@ -98,18 +108,42 @@ catstring(String s1, String s2)
if(s2.len == 0)
return s1;
- s3 = gostringsize(s1.len + s2.len);
- mcpy(s3.str, s1.str, s1.len);
- mcpy(s3.str+s1.len, s2.str, s2.len);
+ s3 = runtime·gostringsize(s1.len + s2.len);
+ runtime·mcpy(s3.str, s1.str, s1.len);
+ runtime·mcpy(s3.str+s1.len, s2.str, s2.len);
return s3;
}
+static String
+concatstring(int32 n, String *s)
+{
+ int32 i, l;
+ String out;
+
+ l = 0;
+ for(i=0; i<n; i++) {
+ if(l + s[i].len < l)
+ runtime·throw("string concatenation too long");
+ l += s[i].len;
+ }
+
+ out = runtime·gostringsize(l);
+ l = 0;
+ for(i=0; i<n; i++) {
+ runtime·mcpy(out.str+l, s[i].str, s[i].len);
+ l += s[i].len;
+ }
+ return out;
+}
-func catstring(s1 String, s2 String) (s3 String) {
- s3 = catstring(s1, s2);
+#pragma textflag 7
+// s1 is the first of n strings.
+// the output string follows.
+func concatstring(n int32, s1 String) {
+ (&s1)[n] = concatstring(n, &s1);
}
-uint32
+static int32
cmpstring(String s1, String s2)
{
uint32 i, l;
@@ -138,7 +172,7 @@ func cmpstring(s1 String, s2 String) (v int32) {
}
int32
-strcmp(byte *s1, byte *s2)
+runtime·strcmp(byte *s1, byte *s2)
{
uint32 i;
byte c1, c2;
@@ -160,57 +194,41 @@ func slicestring(si String, lindex int32, hindex int32) (so String) {
if(lindex < 0 || lindex > si.len ||
hindex < lindex || hindex > si.len) {
- ·panicslice();
+ runtime·panicslice();
}
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);
}
func slicestring1(si String, lindex int32) (so String) {
int32 l;
if(lindex < 0 || lindex > si.len) {
- ·panicslice();
+ runtime·panicslice();
}
l = si.len-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);
-}
-
-func indexstring(s String, i int32) (b byte) {
- if(i < 0 || i >= s.len) {
- ·panicindex();
- }
-
- b = s.str[i];
}
func intstring(v int64) (s String) {
- s = gostringsize(8);
- s.len = runetochar(s.str, v);
+ s = runtime·gostringsize(8);
+ s.len = runtime·runetochar(s.str, v);
}
func slicebytetostring(b Slice) (s String) {
- s = gostringsize(b.len);
- mcpy(s.str, b.array, s.len);
+ s = runtime·gostringsize(b.len);
+ runtime·mcpy(s.str, b.array, s.len);
}
func stringtoslicebyte(s String) (b Slice) {
- b.array = mallocgc(s.len, RefNoPointers, 1, 1);
+ b.array = runtime·mallocgc(s.len, RefNoPointers, 1, 1);
b.len = s.len;
b.cap = s.len;
- mcpy(b.array, s.str, s.len);
+ runtime·mcpy(b.array, s.str, s.len);
}
func sliceinttostring(b Slice) (s String) {
@@ -221,16 +239,16 @@ func sliceinttostring(b Slice) (s String) {
a = (int32*)b.array;
siz1 = 0;
for(i=0; i<b.len; i++) {
- siz1 += runetochar(dum, a[i]);
+ siz1 += runtime·runetochar(dum, a[i]);
}
- s = gostringsize(siz1+4);
+ s = runtime·gostringsize(siz1+4);
siz2 = 0;
for(i=0; i<b.len; i++) {
// check for race
if(siz2 >= siz1)
break;
- siz2 += runetochar(s.str+siz2, a[i]);
+ siz2 += runtime·runetochar(s.str+siz2, a[i]);
}
s.len = siz2;
}
@@ -246,17 +264,17 @@ func stringtosliceint(s String) (b Slice) {
ep = s.str+s.len;
n = 0;
while(p < ep) {
- p += charntorune(&dum, p, ep-p);
+ p += runtime·charntorune(&dum, p, ep-p);
n++;
}
- b.array = mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
+ b.array = runtime·mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
b.len = n;
b.cap = n;
p = s.str;
r = (int32*)b.array;
while(p < ep)
- p += charntorune(r++, p, ep-p);
+ p += runtime·charntorune(r++, p, ep-p);
}
enum
@@ -280,7 +298,7 @@ func stringiter(s String, k int32) (retk int32) {
}
// multi-char rune
- retk = k + charntorune(&l, s.str+k, s.len-k);
+ retk = k + runtime·charntorune(&l, s.str+k, s.len-k);
out:
}
@@ -300,7 +318,7 @@ func stringiter2(s String, k int32) (retk int32, retv int32) {
}
// multi-char rune
- retk = k + charntorune(&retv, s.str+k, s.len-k);
+ retk = k + runtime·charntorune(&retv, s.str+k, s.len-k);
out:
}
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 5a35f635b..b2cccd3cf 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -17,7 +17,7 @@
#include "os.h"
#include "arch.h"
-extern int32 symdat[];
+extern byte pclntab[], epclntab[], symtab[], esymtab[];
typedef struct Sym Sym;
struct Sym
@@ -32,25 +32,16 @@ struct Sym
static void
walksymtab(void (*fn)(Sym*))
{
- int32 *v;
byte *p, *ep, *q;
Sym s;
- if(symdat == nil)
- return;
-
-#ifdef __WINDOWS__
- v = get_symdat_addr();
- p = (byte*)v+8;
-#else
- v = symdat;
- p = (byte*)(symdat+2);
-#endif
- ep = p + v[0];
+ p = symtab;
+ ep = esymtab;
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;
@@ -69,7 +60,7 @@ walksymtab(void (*fn)(Sym*))
}
p = q+2;
}else{
- q = mchr(p, '\0', ep);
+ q = runtime·mchr(p, '\0', ep);
if(q == nil)
break;
p = q+1;
@@ -99,14 +90,14 @@ dofunc(Sym *sym)
case 'T':
case 'l':
case 'L':
- if(strcmp(sym->name, (byte*)"etext") == 0)
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
break;
if(func == nil) {
nfunc++;
break;
}
f = &func[nfunc++];
- f->name = gostringnocopy(sym->name);
+ f->name = runtime·gostringnocopy(sym->name);
f->entry = sym->value;
if(sym->symtype == 'L' || sym->symtype == 'l')
f->frame = -sizeof(uintptr);
@@ -127,8 +118,13 @@ dofunc(Sym *sym)
break;
case 'f':
if(fname == nil) {
- if(sym->value >= nfname)
+ if(sym->value >= nfname) {
+ if(sym->value >= 0x10000) {
+ runtime·printf("invalid symbol file index %p\n", sym->value);
+ runtime·throw("mangled symbol table");
+ }
nfname = sym->value+1;
+ }
break;
}
fname[sym->value] = sym->name;
@@ -158,12 +154,12 @@ makepath(byte *buf, int32 nbuf, byte *path)
if(n >= nfname)
break;
q = fname[n];
- len = findnull(q);
+ len = runtime·findnull(q);
if(p+1+len >= ep)
break;
if(p > buf && p[-1] != '/')
*p++ = '/';
- mcpy(p, q, len+1);
+ runtime·mcpy(p, q, len+1);
p += len;
}
}
@@ -189,7 +185,7 @@ dosrcline(Sym *sym)
switch(sym->symtype) {
case 't':
case 'T':
- if(strcmp(sym->name, (byte*)"etext") == 0)
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
break;
f = &func[nfunc++];
// find source file
@@ -208,7 +204,7 @@ dosrcline(Sym *sym)
nfile = 0;
if(nfile == nelem(files))
return;
- files[nfile].srcstring = gostring(srcbuf);
+ files[nfile].srcstring = runtime·gostring(srcbuf);
files[nfile].aline = 0;
files[nfile++].delta = 0;
} else {
@@ -219,7 +215,7 @@ dosrcline(Sym *sym)
incstart = sym->value;
if(nhist == 0 && nfile < nelem(files)) {
// new top-level file
- files[nfile].srcstring = gostring(srcbuf);
+ files[nfile].srcstring = runtime·gostring(srcbuf);
files[nfile].aline = sym->value;
// this is "line 0"
files[nfile++].delta = sym->value - 1;
@@ -240,9 +236,11 @@ splitpcln(void)
uintptr pc;
byte *p, *ep;
Func *f, *ef;
- int32 *v;
int32 pcquant;
+ if(pclntab == epclntab || nfunc == 0)
+ return;
+
switch(thechar) {
case '5':
pcquant = 4;
@@ -252,19 +250,9 @@ splitpcln(void)
break;
}
- if(symdat == nil)
- return;
-
// pc/ln table bounds
-#ifdef __WINDOWS__
- v = get_symdat_addr();
- p = (byte*)v+8;
-#else
- v = symdat;
- p = (byte*)(symdat+2);
-#endif
- p += v[0];
- ep = p+v[1];
+ p = pclntab;
+ ep = epclntab;
f = func;
ef = func + nfunc;
@@ -305,7 +293,7 @@ splitpcln(void)
// (Source file is f->src.)
// NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
int32
-funcline(Func *f, uint64 targetpc)
+runtime·funcline(Func *f, uint64 targetpc)
{
byte *p, *ep;
uintptr pc;
@@ -360,9 +348,9 @@ buildfuncs(void)
walksymtab(dofunc);
// initialize tables
- func = mal((nfunc+1)*sizeof func[0]);
+ func = runtime·mal((nfunc+1)*sizeof func[0]);
func[nfunc].entry = (uint64)etext;
- fname = mal(nfname*sizeof fname[0]);
+ fname = runtime·mal(nfname*sizeof fname[0]);
nfunc = 0;
walksymtab(dofunc);
@@ -376,15 +364,15 @@ buildfuncs(void)
}
Func*
-findfunc(uintptr addr)
+runtime·findfunc(uintptr addr)
{
Func *f;
int32 nf, n;
- lock(&funclock);
+ runtime·lock(&funclock);
if(func == nil)
buildfuncs();
- unlock(&funclock);
+ runtime·unlock(&funclock);
if(nfunc == 0)
return nil;
@@ -410,6 +398,6 @@ findfunc(uintptr addr)
// 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");
+ runtime·prints("findfunc unreachable\n");
return nil;
}
diff --git a/src/pkg/runtime/tiny/386/rt0.s b/src/pkg/runtime/tiny/386/rt0.s
index ff7aae7ac..524ac7664 100644
--- a/src/pkg/runtime/tiny/386/rt0.s
+++ b/src/pkg/runtime/tiny/386/rt0.s
@@ -11,18 +11,18 @@ TEXT _rt0_386_tiny(SB), 7, $0
MOVL AX, SP
// Set up memory hardware.
- CALL msetup(SB)
+ CALL runtime·msetup(SB)
// _rt0_386 expects to find argc, argv, envv on stack.
// Set up argv=["kernel"] and envv=[].
SUBL $64, SP
MOVL $1, 0(SP)
- MOVL $kernel(SB), 4(SP)
+ MOVL $runtime·kernel(SB), 4(SP)
MOVL $0, 8(SP)
MOVL $0, 12(SP)
JMP _rt0_386(SB)
-DATA kernel+0(SB)/7, $"kernel\z"
-GLOBL kernel(SB), $7
+DATA runtime·kernel(SB)/7, $"kernel\z"
+GLOBL runtime·kernel(SB), $7
diff --git a/src/pkg/runtime/tiny/386/signal.c b/src/pkg/runtime/tiny/386/signal.c
index de06ba8db..88e634e9d 100644
--- a/src/pkg/runtime/tiny/386/signal.c
+++ b/src/pkg/runtime/tiny/386/signal.c
@@ -4,16 +4,16 @@
#include "runtime.h"
-extern void ·write(int32 fd, void *v, int32 len, int32 cap); // slice, spelled out
+extern void runtime·write(int32 fd, void *v, int32 len, int32 cap); // slice, spelled out
int32
-write(int32 fd, void *v, int32 len)
+runtime·write(int32 fd, void *v, int32 len)
{
- ·write(fd, v, len, len);
+ runtime·write(fd, v, len, len);
return len;
}
void
-gettime(int64*, int32*)
+runtime·gettime(int64*, int32*)
{
}
diff --git a/src/pkg/runtime/tiny/386/sys.s b/src/pkg/runtime/tiny/386/sys.s
index c51a5ec3e..851171476 100644
--- a/src/pkg/runtime/tiny/386/sys.s
+++ b/src/pkg/runtime/tiny/386/sys.s
@@ -17,8 +17,8 @@
// Called to set up memory hardware.
// Already running in 32-bit mode thanks to boot block,
// but we need to install our new GDT that we can modify.
-TEXT msetup(SB), 7, $0
- MOVL gdtptr(SB), GDTR
+TEXT runtime·msetup(SB), 7, $0
+ MOVL runtime·gdtptr(SB), GDTR
MOVL $(1*8+0), AX
MOVW AX, DS
MOVW AX, ES
@@ -29,14 +29,14 @@ TEXT msetup(SB), 7, $0
// long jmp to cs:mret
BYTE $0xEA
- LONG $mret(SB)
+ LONG $runtime·mret(SB)
WORD $(2*8+0)
-TEXT mret(SB), 7, $0
+TEXT runtime·mret(SB), 7, $0
RET
// GDT memory
-TEXT gdt(SB), 7, $0
+TEXT runtime·gdt(SB), 7, $0
// null segment
LONG $0
LONG $0
@@ -54,14 +54,14 @@ TEXT gdt(SB), 7, $0
LONG $0
// GDT pseudo-descriptor
-TEXT gdtptr(SB), 7, $0
+TEXT runtime·gdtptr(SB), 7, $0
WORD $(4*8)
- LONG $gdt(SB)
+ LONG $runtime·gdt(SB)
// Called to establish the per-thread segment.
// Write to gdt[3] and reload the gdt register.
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
MOVL limit+8(FP), CX
@@ -83,7 +83,7 @@ TEXT setldt(SB),7,$32
MOVB CX, 6(AX)
MOVB $0xF2, 5(AX) // r/w data descriptor, dpl=3, present
- MOVL gdtptr(SB), GDTR
+ MOVL runtime·gdtptr(SB), GDTR
// Compute segment selector - (entry*8+0)
MOVL $(3*8+0), AX
diff --git a/src/pkg/runtime/tiny/README b/src/pkg/runtime/tiny/README
index bbe00f3ea..cf001d1e6 100755
--- a/src/pkg/runtime/tiny/README
+++ b/src/pkg/runtime/tiny/README
@@ -6,8 +6,7 @@ for 386 and arm.
386
It is very primitive but can run go/test/sieve.go, the concurrent
-prime sieve, on a uniprocessor. It has only been tested using the
-Bochs emulator.
+prime sieve, on a uniprocessor.
To run, first build the tools by running all.bash with GOARCH=386
and GOOS set to your normal GOOS (linux, darwin). Then:
@@ -22,14 +21,41 @@ and GOOS set to your normal GOOS (linux, darwin). Then:
8l -a sieve.8 >sieve.asm # can consult sieve.asm for debugging
dd if=/dev/zero of=disk count=10000
cat bootblock 8.out | dd of=disk conv=notrunc
- bochs
Use the built-in print(text string) function to print to the
console.
+
+BOCHS
+
You may have to tweak the .bochsrc depending on your system,
and you may need to install the Bochs emulator.
+ $ cp dot-bochsrc .bochsrc
+ $ $EDITOR .bochsrc # tweak it if required
+ $ bochs
+
+
+ORACLE xVM VIRTUALBOX
+
+Install VirtualBox. Then:
+
+ Build 'disk' (described above under '386').
+
+ $ VBoxManage convertfromraw disk go-tiny.vdi
+ $ VirtualBox
+ create a new VM; as disk use the go-tiny.vdi image.
+ start the vm.
+
+
+QEMU / KVM
+
+This should work the same for qemu and kvm (really: qemu-kvm).
+
+ Build 'disk' (described above under '386').
+
+ $ qemu -hda disk
+
ARM
diff --git a/src/pkg/runtime/tiny/mem.c b/src/pkg/runtime/tiny/mem.c
index a66a4a731..7abecfba0 100644
--- a/src/pkg/runtime/tiny/mem.c
+++ b/src/pkg/runtime/tiny/mem.c
@@ -8,34 +8,43 @@
// Assume there's an arbitrary amount of memory starting at "end".
// Sizing PC memory is beyond the scope of this demo.
+static byte *allocp;
+
void*
-SysAlloc(uintptr ask)
+runtime·SysAlloc(uintptr ask)
{
- static byte *p;
extern byte end[];
byte *q;
- if(p == nil) {
- p = end;
- p += 7 & -(uintptr)p;
+ if(allocp == nil) {
+ allocp = end;
+ allocp += 7 & -(uintptr)allocp;
}
ask += 7 & -ask;
- q = p;
- p += ask;
- ·memclr(q, ask);
+ q = allocp;
+ allocp += ask;
+ runtime·memclr(q, ask);
return q;
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v, n);
+ // Push pointer back if this is a free
+ // of the most recent SysAlloc.
+ n += 7 & -n;
+ if(allocp == (byte*)v+n)
+ allocp -= n;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v, n);
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/tiny/runtime_defs.go b/src/pkg/runtime/tiny/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/tiny/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 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.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/tiny/thread.c b/src/pkg/runtime/tiny/thread.c
index e4b58256f..0572ecb77 100644
--- a/src/pkg/runtime/tiny/thread.c
+++ b/src/pkg/runtime/tiny/thread.c
@@ -7,22 +7,28 @@
int8 *goos = "tiny";
void
-minit(void)
+runtime·minit(void)
{
}
void
-osinit(void)
+runtime·osinit(void)
{
}
void
-initsig(int32 queue)
+runtime·goenvs(void)
{
+ runtime·goenvs_unix();
}
void
-exit(int32)
+runtime·initsig(int32 queue)
+{
+}
+
+void
+runtime·exit(int32)
{
for(;;);
}
@@ -31,50 +37,56 @@ exit(int32)
// so no need for real concurrency or atomicity
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
USED(m, g, stk, fn);
- throw("newosproc");
+ runtime·throw("newosproc");
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
if(l->key != 0)
- throw("deadlock");
+ runtime·throw("deadlock");
l->key = 1;
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
if(l->key != 1)
- throw("unlock of unlocked lock");
+ runtime·throw("unlock of unlocked lock");
l->key = 0;
}
+void
+runtime·destroylock(Lock *l)
+{
+ // nothing
+}
+
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0;
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
n->lock.key = 1;
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
if(n->lock.key != 1)
- throw("notesleep");
+ runtime·throw("notesleep");
}
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 5efbfaf83..d92fe5f2a 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -9,6 +9,7 @@
* data structures and must be kept in sync with this file:
*
* ../../cmd/gc/reflect.c
+ * ../../cmd/ld/dwarf.c
* ../reflect/type.go
* type.h
*/
@@ -53,6 +54,9 @@ const (
kindFloat
kindFloat32
kindFloat64
+ kindComplex
+ kindComplex64
+ kindComplex128
kindArray
kindChan
kindFunc
@@ -191,6 +195,8 @@ type StructType struct {
/*
* Must match iface.c:/Itab and compilers.
+ * NOTE: this is the version used by the reflection code, there is another
+ * one in iface_defs.go that is closer to the original C version.
*/
type Itable struct {
Itype *Type // (*tab.inter).(*InterfaceType) is the interface type
diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/windows/386/rt0.s
index 4e6850416..e379830fb 100644
--- a/src/pkg/runtime/windows/386/rt0.s
+++ b/src/pkg/runtime/windows/386/rt0.s
@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_386_windows(SB),7,$0
+TEXT _rt0_386_windows(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c
index 278bb7fc4..2ae79e5b5 100644
--- a/src/pkg/runtime/windows/386/signal.c
+++ b/src/pkg/runtime/windows/386/signal.c
@@ -5,6 +5,13 @@
#include "runtime.h"
void
-initsig(int32 queue)
+runtime·initsig(int32)
{
}
+
+String
+runtime·signame(int32)
+{
+ return runtime·emptystring;
+}
+
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s
index e36ef53e0..7f99b34de 100644
--- a/src/pkg/runtime/windows/386/sys.s
+++ b/src/pkg/runtime/windows/386/sys.s
@@ -4,105 +4,112 @@
#include "386/asm.h"
-TEXT get_kernel_module(SB),7,$0
- MOVL 0x30(FS), AX // get PEB
- MOVL 0x0c(AX), AX // get PEB_LDR_DATA
- MOVL 0x1c(AX), AX // get init order module list
- MOVL (AX), AX // get next entry (kernel module)
- MOVL 0x08(AX), AX // get base of module
- RET
-
-// void *stdcall_raw(void *fn, ...);
-// Call fn with stdcall calling convention.
-// fn parameters are on stack.
-TEXT stdcall_raw(SB),7,$0
- get_tls(CX)
- MOVL m(CX), CX
- POPL m_return_address(CX) // save return address
- POPL AX // first arg is function pointer
- MOVL SP, m_stack_pointer(CX) // save stack pointer
- CALL AX
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_stack_pointer(CX), SP
- PUSHL AX
- PUSHL m_return_address(CX)
- RET
+// void *stdcall_raw(void *fn, int32 count, uintptr *args)
+TEXT runtime·stdcall_raw(SB),7,$4
+ // Copy arguments from stack.
+ MOVL fn+0(FP), AX
+ MOVL count+4(FP), CX // words
+ MOVL args+8(FP), BP
-// void syscall(StdcallParams *p);
-// Call p.fn syscall + GetLastError on os stack.
-TEXT syscall(SB),7,$16
- MOVL p+0(FP), AX
- MOVL SP, CX
-
- // Figure out if we need to switch to m->g0 stack.
+ // Switch to m->g0 if needed.
get_tls(DI)
MOVL m(DI), DX
+ MOVL g(DI), SI
+ MOVL SI, 0(SP) // save g
+ MOVL SP, m_gostack(DX) // save SP
MOVL m_g0(DX), SI
CMPL g(DI), SI
- JEQ 2(PC)
+ JEQ 3(PC)
MOVL (m_sched+gobuf_sp)(DX), SP
-
- // Now on a scheduling stack (an os stack).
- MOVL g(DI), BP
- MOVL BP, 8(SP)
MOVL SI, g(DI)
- MOVL CX, 4(SP)
- MOVL AX, 0(SP)
- CALL call_syscall(SB)
-
- // Back; switch to original g and stack, re-establish
- // "DF is clear" invariant.
+
+ // Copy args to new stack.
+ SUBL $(10*4), SP // padding
+ MOVL CX, BX
+ SALL $2, BX
+ SUBL BX, SP // room for args
+ MOVL SP, DI
+ MOVL BP, SI
CLD
+ REP; MOVSL
+
+ // Call stdcall function.
+ CALL AX
+
+ // Restore original SP, g.
get_tls(DI)
- MOVL 8(SP), SI
+ MOVL m(DI), DX
+ MOVL m_gostack(DX), SP // restore SP
+ MOVL 0(SP), SI // restore g
MOVL SI, g(DI)
- MOVL 4(SP), SP
- RET
-TEXT threadstart(SB),7,$0
- MOVL 4(SP), AX // threadstart param
- MOVL 0(AX), BX // newosproc arg stack
- MOVL 0(BX), CX // m
- MOVL 4(BX), DX // g
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ RET
+
+// void tstart(M *newm);
+TEXT runtime·tstart(SB),7,$0
+ MOVL newm+4(SP), CX // m
+ MOVL m_g0(CX), DX // g
+
+ MOVL SP, DI // remember stack
- // set up tls
+ // Layout new m scheduler stack on os stack.
+ MOVL SP, AX
+ SUBL $256, AX // just some space for ourselves
+ MOVL AX, g_stackbase(DX)
+ SUBL $8192, AX // stack size
+ MOVL AX, g_stackguard(DX)
+
+ // Set up tls.
LEAL m_tls(CX), SI
MOVL SI, 0x2c(FS)
MOVL CX, m(SI)
MOVL DX, g(SI)
- MOVL SP, m_os_stack_pointer(CX)
-
- PUSHL 8(BX) // stk
- PUSHL 12(BX) // fn
- PUSHL 4(AX) // event_handle
-
- // signal that we're done with thread args
- MOVL SetEvent(SB), BX
- CALL BX // SetEvent(event_handle)
- POPL BX // fn
- POPL SP // stk
-
- CALL stackcheck(SB) // clobbers AX,CX
- CALL BX // fn()
-
- // cleanup stack before returning as we are stdcall
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_os_stack_pointer(CX), SP
- POPL AX // return address
- MOVL AX, (SP)
- XORL AX, AX
+
+ // Use scheduler stack now.
+ MOVL g_stackbase(DX), SP
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ PUSHL DI // original stack
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+
+ CALL runtime·mstart(SB)
+
+ POPL DI // original stack
+ MOVL DI, SP
+
+ RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT runtime·tstart_stdcall(SB),7,$0
+ MOVL newm+4(SP), BX
+
+ PUSHL BX
+ CALL runtime·tstart(SB)
+ POPL BX
+
+ // Adjust stack for stdcall to return properly.
+ MOVL (SP), AX // save return address
+ ADDL $4, SP // remove single parameter
+ MOVL AX, (SP) // restore return address
+
+ XORL AX, AX // return 0 == success
+
RET
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$0
+TEXT runtime·setldt(SB),7,$0
MOVL address+4(FP), CX
MOVL CX, 0x2c(FS)
RET
// for now, return 0,0. only used for internal performance monitoring.
-TEXT gettime(SB),7,$0
+TEXT runtime·gettime(SB),7,$0
MOVL sec+0(FP), DI
MOVL $0, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64 bits
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c
index 982344fa0..ba89887ea 100644
--- a/src/pkg/runtime/windows/mem.c
+++ b/src/pkg/runtime/windows/mem.c
@@ -7,23 +7,58 @@
#include "defs.h"
#include "malloc.h"
+enum {
+ MEM_COMMIT = 0x1000,
+ MEM_RESERVE = 0x2000,
+ MEM_RELEASE = 0x8000,
+
+ PAGE_EXECUTE_READWRITE = 0x40,
+};
+
+static void
+abort(int8 *name)
+{
+ uintptr errno;
+
+ errno = (uintptr)runtime·stdcall(runtime·GetLastError, 0);
+ runtime·printf("%s failed with errno=%d\n", name, errno);
+ runtime·throw(name);
+}
+
+#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
+#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+extern void *runtime·VirtualAlloc;
+extern void *runtime·VirtualFree;
+
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
- return stdcall(VirtualAlloc, 4, nil, n, 0x3000, 0x40);
+ void *v;
+
+ v = runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if(v == 0)
+ abort("VirtualAlloc");
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
+ uintptr r;
+
+ r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, 0, MEM_RELEASE);
+ if(r == 0)
+ abort("VirtualFree");
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
index 931f4991c..77d0d32a0 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/windows/os.h
@@ -2,28 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The following function allows one to dynamically
-// resolve DLL function names.
-// The arguments are strings.
-void *get_proc_addr(void *library, void *name);
-
-extern void *VirtualAlloc;
-extern void *LoadLibraryEx;
-extern void *GetProcAddress;
-extern void *GetLastError;
-
-#define goargs windows_goargs
-void windows_goargs(void);
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetLastError;
// Get start address of symbol data in memory.
-void *get_symdat_addr(void);
-
-// Call a Windows function with stdcall conventions.
-void *stdcall_raw(void *fn, ...);
+void *runtime·get_symdat_addr(void);
// Call a Windows function with stdcall conventions,
// and switch to os stack during the call.
-void *stdcall(void *fn, int32 count, ...);
+void *runtime·stdcall_raw(void *fn, int32 count, uintptr *args);
+void *runtime·stdcall(void *fn, int32 count, ...);
+
+// Function to be called by windows CreateTread
+// to start new os thread.
+uint32 runtime·tstart_stdcall(M *newm);
// Call stdcall Windows function StdcallParams.fn
// with params StdcallParams.args,
@@ -34,9 +27,10 @@ typedef struct StdcallParams StdcallParams;
struct StdcallParams
{
void *fn;
- uintptr args[9];
+ uintptr args[12];
+ int32 n;
uintptr r;
uintptr err;
};
-void call_syscall(void *args);
-void syscall(StdcallParams *p);
+
+void runtime·syscall(StdcallParams *p);
diff --git a/src/pkg/runtime/windows/runtime_defs.go b/src/pkg/runtime/windows/runtime_defs.go
new file mode 100644
index 000000000..34a9b3259
--- /dev/null
+++ b/src/pkg/runtime/windows/runtime_defs.go
@@ -0,0 +1,22 @@
+// Copyright 2010 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.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+import "unsafe"
+
+const (
+ Windows = 1
+)
+
+// const ( Structrnd = sizeof(uintptr) )
+
+type lock struct {
+ key uint32
+ event unsafe.Pointer
+}
+
+type note lock
diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc
index 362217e6b..d3057c540 100644
--- a/src/pkg/runtime/windows/syscall.goc
+++ b/src/pkg/runtime/windows/syscall.goc
@@ -8,24 +8,22 @@ package syscall
func loadlibraryex(filename uintptr) (handle uint32) {
StdcallParams p;
- p.fn = (void*)LoadLibraryEx;
+ p.fn = (void*)runtime·LoadLibraryEx;
p.args[0] = filename;
p.args[1] = 0;
p.args[2] = 0;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 3;
+ runtime·syscall(&p);
handle = p.r;
}
func getprocaddress(handle uint32, procname uintptr) (proc uintptr) {
StdcallParams p;
- p.fn = (void*)GetProcAddress;
+ p.fn = (void*)runtime·GetProcAddress;
p.args[0] = handle;
p.args[1] = procname;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 2;
+ runtime·syscall(&p);
proc = p.r;
}
@@ -35,9 +33,8 @@ func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 u
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 3;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
@@ -52,9 +49,8 @@ func Syscall6(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u
p.args[3] = a4;
p.args[4] = a5;
p.args[5] = a6;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 6;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
@@ -72,9 +68,30 @@ func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u
p.args[6] = a7;
p.args[7] = a8;
p.args[8] = a9;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 9;
+ runtime·syscall(&p);
+ r1 = p.r;
+ r2 = 0;
+ lasterr = p.err;
+}
+
+func Syscall12(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, lasterr uintptr) {
+ StdcallParams p;
+ p.fn = (void*)trap;
+ p.args[0] = a1;
+ p.args[1] = a2;
+ p.args[2] = a3;
+ p.args[3] = a4;
+ p.args[4] = a5;
+ p.args[5] = a6;
+ p.args[6] = a7;
+ p.args[7] = a8;
+ p.args[8] = a9;
+ p.args[9] = a10;
+ p.args[10] = a11;
+ p.args[11] = a12;
+ p.n = 12;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
lasterr = p.err;
@@ -86,7 +103,8 @@ func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
- syscall(&p);
+ p.n = 3;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index c65f665b1..9b5181337 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -5,130 +5,84 @@
#include "runtime.h"
#include "os.h"
-extern void *get_kernel_module(void);
+#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+#pragma dynimport runtime·GetLastError GetLastError "kernel32.dll"
+#pragma dynimport runtime·SetLastError SetLastError "kernel32.dll"
// Also referenced by external packages
-void *CloseHandle;
-void *ExitProcess;
-void *GetStdHandle;
-void *SetEvent;
-void *WriteFile;
-void *VirtualAlloc;
-void *LoadLibraryEx;
-void *GetProcAddress;
-void *GetLastError;
-
-static void *CreateEvent;
-static void *CreateThread;
-static void *GetModuleHandle;
-static void *WaitForSingleObject;
-
-static void*
-get_proc_addr2(byte *base, byte *name)
-{
- byte *pe_header, *exports;
- uint32 entries, *addr, *names, i;
- uint16 *ordinals;
-
- pe_header = base+*(uint32*)(base+0x3c);
- exports = base+*(uint32*)(pe_header+0x78);
- entries = *(uint32*)(exports+0x18);
- addr = (uint32*)(base+*(uint32*)(exports+0x1c));
- names = (uint32*)(base+*(uint32*)(exports+0x20));
- ordinals = (uint16*)(base+*(uint32*)(exports+0x24));
- for(i=0; i<entries; i++) {
- byte *s = base+names[i];
- if(!strcmp(name, s))
- break;
- }
- if(i == entries)
- return 0;
- return base+addr[ordinals[i]];
-}
+extern void *runtime·CloseHandle;
+extern void *runtime·ExitProcess;
+extern void *runtime·GetStdHandle;
+extern void *runtime·SetEvent;
+extern void *runtime·WriteFile;
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetLastError;
+extern void *runtime·SetLastError;
+
+#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
+#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
+
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·WaitForSingleObject;
void
-osinit(void)
+runtime·osinit(void)
{
- void *base;
-
- base = get_kernel_module();
- GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
- LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
- CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
- CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
- CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
- ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
- GetModuleHandle = get_proc_addr("kernel32.dll", "GetModuleHandleA");
- GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
- SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
- VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
- WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
- WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
- GetLastError = get_proc_addr("kernel32.dll", "GetLastError");
}
-// The arguments are strings.
-void*
-get_proc_addr(void *library, void *name)
-{
- void *base;
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
- base = stdcall_raw(LoadLibraryEx, library, 0, 0);
- return stdcall_raw(GetProcAddress, base, name);
-}
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·FreeEnvironmentStringsW;
void
-windows_goargs(void)
+runtime·goenvs(void)
{
- extern Slice os·Args;
extern Slice os·Envs;
- void *gcl, *clta, *ges;
- uint16 *cmd, *env, **argv;
- String *gargv;
- String *genvv;
- int32 i, argc, envc;
- uint16 *envp;
-
- gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
- clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
- ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
-
- cmd = stdcall(gcl, 0);
- env = stdcall(ges, 0);
- argv = stdcall(clta, 2, cmd, &argc);
-
- envc = 0;
- for(envp=env; *envp; envc++)
- envp += findnullw(envp)+1;
-
- gargv = malloc(argc*sizeof gargv[0]);
- genvv = malloc(envc*sizeof genvv[0]);
-
- for(i=0; i<argc; i++)
- gargv[i] = gostringw(argv[i]);
- os·Args.array = (byte*)gargv;
- os·Args.len = argc;
- os·Args.cap = argc;
-
- envp = env;
- for(i=0; i<envc; i++) {
- genvv[i] = gostringw(envp);
- envp += findnullw(envp)+1;
+ uint16 *env;
+ String *s;
+ int32 i, n;
+ uint16 *p;
+
+ env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
+
+ n = 0;
+ for(p=env; *p; n++)
+ p += runtime·findnullw(p)+1;
+
+ s = runtime·malloc(n*sizeof s[0]);
+
+ p = env;
+ for(i=0; i<n; i++) {
+ s[i] = runtime·gostringw(p);
+ p += runtime·findnullw(p)+1;
}
- os·Envs.array = (byte*)genvv;
- os·Envs.len = envc;
- os·Envs.cap = envc;
+ os·Envs.array = (byte*)s;
+ os·Envs.len = n;
+ os·Envs.cap = n;
+
+ runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
}
void
-exit(int32 code)
+runtime·exit(int32 code)
{
- stdcall(ExitProcess, 1, code);
+ runtime·stdcall(runtime·ExitProcess, 1, code);
}
int32
-write(int32 fd, void *buf, int32 n)
+runtime·write(int32 fd, void *buf, int32 n)
{
void *handle;
uint32 written;
@@ -136,46 +90,28 @@ write(int32 fd, void *buf, int32 n)
written = 0;
switch(fd) {
case 1:
- handle = stdcall(GetStdHandle, 1, -11);
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, -11);
break;
case 2:
- handle = stdcall(GetStdHandle, 1, -12);
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, -12);
break;
default:
return -1;
}
- stdcall(WriteFile, 5, handle, buf, n, &written, 0);
+ runtime·stdcall(runtime·WriteFile, 5, handle, buf, n, &written, 0);
return written;
}
-void*
-get_symdat_addr(void)
-{
- byte *mod, *p;
- uint32 peh, add;
- uint16 oph;
-
- mod = stdcall(GetModuleHandle, 1, 0);
- peh = *(uint32*)(mod+0x3c);
- p = mod+peh+4;
- oph = *(uint16*)(p+0x10);
- p += 0x14+oph;
- while(strcmp(p, (byte*)".symdat"))
- p += 40;
- add = *(uint32*)(p+0x0c);
- return mod+add;
-}
-
// Thread-safe allocation of an event.
static void
initevent(void **pevent)
{
void *event;
- event = stdcall(CreateEvent, 4, 0, 0, 0, 0);
- if(!casp(pevent, 0, event)) {
+ event = runtime·stdcall(runtime·CreateEvent, 4, 0, 0, 0, 0);
+ if(!runtime·casp(pevent, 0, event)) {
// Someone else filled it in. Use theirs.
- stdcall(CloseHandle, 1, event);
+ runtime·stdcall(runtime·CloseHandle, 1, event);
}
}
@@ -186,106 +122,96 @@ eventlock(Lock *l)
if(l->event == 0)
initevent(&l->event);
- if(xadd(&l->key, 1) > 1) // someone else has it; wait
- stdcall(WaitForSingleObject, 2, l->event, -1);
+ if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
+ runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, -1);
}
static void
eventunlock(Lock *l)
{
- if(xadd(&l->key, -1) > 0) // someone else is waiting
- stdcall(SetEvent, 1, l->event);
+ if(runtime·xadd(&l->key, -1) > 0) // someone else is waiting
+ runtime·stdcall(runtime·SetEvent, 1, l->event);
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
eventlock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
eventunlock(l);
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock *l)
{
if(l->event != 0)
- stdcall(CloseHandle, 1, l->event);
+ runtime·stdcall(runtime·CloseHandle, 1, l->event);
}
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
eventlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
eventunlock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
eventlock(&n->lock);
eventunlock(&n->lock); // Let other sleepers find out too.
}
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- struct {
- void *args;
- void *event_handle;
- } param = { &m };
- extern uint32 threadstart(void *p);
-
- USED(g, stk, fn);
- param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0);
- stdcall(CreateThread, 6, 0, 0, threadstart, &param, 0, 0);
- stdcall(WaitForSingleObject, 2, param.event_handle, -1);
- stdcall(CloseHandle, 1, param.event_handle);
+ USED(stk);
+ USED(g); // assuming g = m->g0
+ USED(fn); // assuming fn = mstart
+
+ runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
}
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
}
// Calling stdcall on os stack.
#pragma textflag 7
void *
-stdcall(void *fn, int32 count, ...)
+runtime·stdcall(void *fn, int32 count, ...)
{
- uintptr *a;
- StdcallParams p;
-
- p.fn = fn;
- a = (uintptr*)(&count + 1);
- while(count > 0) {
- count--;
- p.args[count] = a[count];
- }
- syscall(&p);
- return (void*)(p.r);
+ return runtime·stdcall_raw(fn, count, (uintptr*)(&count + 1));
}
void
-call_syscall(void *args)
-{
- StdcallParams *p = (StdcallParams*)args;
- p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8]);
- p->err = (uintptr)stdcall_raw(GetLastError);
- return;
+runtime·syscall(StdcallParams *p)
+{
+ uintptr a;
+
+ runtime·entersyscall();
+ // TODO(brainman): Move calls to SetLastError and GetLastError
+ // to stdcall_raw to speed up syscall.
+ a = 0;
+ runtime·stdcall_raw(runtime·SetLastError, 1, &a);
+ p->r = (uintptr)runtime·stdcall_raw((void*)p->fn, p->n, p->args);
+ p->err = (uintptr)runtime·stdcall_raw(runtime·GetLastError, 0, &a);
+ runtime·exitsyscall();
}