Commit 37186d91 authored by Russ Cox's avatar Russ Cox

[dev.garbage] runtime: add write barrier to casp

Also rewrite some casp that don't use real pointers
to use casuintptr instead.

LGTM=rlh
R=rlh
CC=golang-codereviews
https://golang.org/cl/166440044
parent 28c53859
...@@ -502,7 +502,7 @@ fail: ...@@ -502,7 +502,7 @@ fail:
// return 1; // return 1;
// }else // }else
// return 0; // return 0;
TEXT runtime·casp(SB), NOSPLIT, $0-13 TEXT runtime·casp1(SB), NOSPLIT, $0-13
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL old+4(FP), AX MOVL old+4(FP), AX
MOVL new+8(FP), CX MOVL new+8(FP), CX
...@@ -537,7 +537,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-12 ...@@ -537,7 +537,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-12
MOVL AX, ret+8(FP) MOVL AX, ret+8(FP)
RET RET
TEXT runtime·xchgp(SB), NOSPLIT, $0-12 TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL new+4(FP), AX MOVL new+4(FP), AX
XCHGL AX, 0(BX) XCHGL AX, 0(BX)
...@@ -555,7 +555,7 @@ again: ...@@ -555,7 +555,7 @@ again:
JNZ again JNZ again
RET RET
TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8 TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL val+4(FP), AX MOVL val+4(FP), AX
XCHGL AX, 0(BX) XCHGL AX, 0(BX)
......
...@@ -489,7 +489,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16 ...@@ -489,7 +489,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
// return 1; // return 1;
// } else // } else
// return 0; // return 0;
TEXT runtime·casp(SB), NOSPLIT, $0-25 TEXT runtime·casp1(SB), NOSPLIT, $0-25
MOVQ ptr+0(FP), BX MOVQ ptr+0(FP), BX
MOVQ old+8(FP), AX MOVQ old+8(FP), AX
MOVQ new+16(FP), CX MOVQ new+16(FP), CX
...@@ -541,7 +541,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24 ...@@ -541,7 +541,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVQ AX, ret+16(FP) MOVQ AX, ret+16(FP)
RET RET
TEXT runtime·xchgp(SB), NOSPLIT, $0-24 TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
MOVQ ptr+0(FP), BX MOVQ ptr+0(FP), BX
MOVQ new+8(FP), AX MOVQ new+8(FP), AX
XCHGQ AX, 0(BX) XCHGQ AX, 0(BX)
...@@ -559,7 +559,7 @@ again: ...@@ -559,7 +559,7 @@ again:
JNZ again JNZ again
RET RET
TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16 TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), BX MOVQ ptr+0(FP), BX
MOVQ val+8(FP), AX MOVQ val+8(FP), AX
XCHGQ AX, 0(BX) XCHGQ AX, 0(BX)
......
...@@ -460,7 +460,7 @@ fail: ...@@ -460,7 +460,7 @@ fail:
// return 1; // return 1;
// } else // } else
// return 0; // return 0;
TEXT runtime·casp(SB), NOSPLIT, $0-17 TEXT runtime·casp1(SB), NOSPLIT, $0-17
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL old+4(FP), AX MOVL old+4(FP), AX
MOVL new+8(FP), CX MOVL new+8(FP), CX
...@@ -512,7 +512,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24 ...@@ -512,7 +512,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVQ AX, ret+16(FP) MOVQ AX, ret+16(FP)
RET RET
TEXT runtime·xchgp(SB), NOSPLIT, $0-12 TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL new+4(FP), AX MOVL new+4(FP), AX
XCHGL AX, 0(BX) XCHGL AX, 0(BX)
...@@ -530,7 +530,7 @@ again: ...@@ -530,7 +530,7 @@ again:
JNZ again JNZ again
RET RET
TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8 TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), BX MOVL ptr+0(FP), BX
MOVL val+4(FP), AX MOVL val+4(FP), AX
XCHGL AX, 0(BX) XCHGL AX, 0(BX)
......
...@@ -472,7 +472,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16 ...@@ -472,7 +472,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
// return 1; // return 1;
// } else // } else
// return 0; // return 0;
TEXT runtime·casp(SB), NOSPLIT, $0-25 TEXT runtime·casp1(SB), NOSPLIT, $0-25
BR runtime·cas64(SB) BR runtime·cas64(SB)
// uint32 xadd(uint32 volatile *val, int32 delta) // uint32 xadd(uint32 volatile *val, int32 delta)
...@@ -529,7 +529,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24 ...@@ -529,7 +529,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
MOVD R3, ret+16(FP) MOVD R3, ret+16(FP)
RETURN RETURN
TEXT runtime·xchgp(SB), NOSPLIT, $0-24 TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
BR runtime·xchg64(SB) BR runtime·xchg64(SB)
TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
...@@ -538,7 +538,7 @@ TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 ...@@ -538,7 +538,7 @@ TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
TEXT runtime·procyield(SB),NOSPLIT,$0-0 TEXT runtime·procyield(SB),NOSPLIT,$0-0
RETURN RETURN
TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16 TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
BR runtime·atomicstore64(SB) BR runtime·atomicstore64(SB)
TEXT runtime·atomicstore(SB), NOSPLIT, $0-12 TEXT runtime·atomicstore(SB), NOSPLIT, $0-12
......
...@@ -20,8 +20,16 @@ func xchg(ptr *uint32, new uint32) uint32 ...@@ -20,8 +20,16 @@ func xchg(ptr *uint32, new uint32) uint32
//go:noescape //go:noescape
func xchg64(ptr *uint64, new uint64) uint64 func xchg64(ptr *uint64, new uint64) uint64
//go:noescape // Cannot use noescape here: ptr does not but new does escape.
func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer // Instead use noescape(ptr) in wrapper below.
func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
//go:nosplit
func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
old := xchgp1(noescape(ptr), new)
writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
return old
}
//go:noescape //go:noescape
func xchguintptr(ptr *uintptr, new uintptr) uintptr func xchguintptr(ptr *uintptr, new uintptr) uintptr
...@@ -47,5 +55,27 @@ func atomicstore(ptr *uint32, val uint32) ...@@ -47,5 +55,27 @@ func atomicstore(ptr *uint32, val uint32)
//go:noescape //go:noescape
func atomicstore64(ptr *uint64, val uint64) func atomicstore64(ptr *uint64, val uint64)
//go:noescape // Cannot use noescape here: ptr does not but val does escape.
func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer) // Instead use noescape(ptr) in wrapper below.
func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
//go:nosplit
func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer) {
atomicstorep1(noescape(ptr), val)
// TODO(rsc): Why does the compiler think writebarrierptr_nostore's dst argument escapes?
writebarrierptr_nostore((*uintptr)(noescape(ptr)), uintptr(val))
}
// Cannot use noescape here: ptr does not but new does escape.
// Instead use noescape(ptr) in wrapper below.
func casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
//go:nosplit
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
ok := casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), old, new)
if !ok {
return false
}
writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
return true
}
...@@ -1098,7 +1098,6 @@ runtime·gcmarkwb_m() ...@@ -1098,7 +1098,6 @@ runtime·gcmarkwb_m()
slot = (byte**)g->m->scalararg[0]; slot = (byte**)g->m->scalararg[0];
ptr = (byte*)g->m->scalararg[1]; ptr = (byte*)g->m->scalararg[1];
*slot = ptr;
switch(runtime·gcphase) { switch(runtime·gcphase) {
default: default:
runtime·throw("gcphasework in bad gcphase"); runtime·throw("gcphasework in bad gcphase");
......
...@@ -92,13 +92,24 @@ const ( ...@@ -92,13 +92,24 @@ const (
// but if we do that, Go inserts a write barrier on *dst = src. // but if we do that, Go inserts a write barrier on *dst = src.
//go:nosplit //go:nosplit
func writebarrierptr(dst *uintptr, src uintptr) { func writebarrierptr(dst *uintptr, src uintptr) {
*dst = src
writebarrierptr_nostore(dst, src)
}
// Like writebarrierptr, but the store has already been applied.
// Do not reapply.
//go:nosplit
func writebarrierptr_nostore(dst *uintptr, src uintptr) {
if getg() == nil { // very low-level startup
return
}
if src != 0 && (src < _PageSize || src == _PoisonGC || src == _PoisonStack) { if src != 0 && (src < _PageSize || src == _PoisonGC || src == _PoisonStack) {
onM(func() { gothrow("bad pointer in write barrier") }) onM(func() { gothrow("bad pointer in write barrier") })
} }
mp := acquirem() mp := acquirem()
if mp.inwb { if mp.inwb {
*dst = src
releasem(mp) releasem(mp)
return return
} }
...@@ -112,7 +123,6 @@ func writebarrierptr(dst *uintptr, src uintptr) { ...@@ -112,7 +123,6 @@ func writebarrierptr(dst *uintptr, src uintptr) {
mp.scalararg[1] = oldscalar1 mp.scalararg[1] = oldscalar1
mp.inwb = false mp.inwb = false
releasem(mp) releasem(mp)
// *dst = src is done inside of the write barrier.
} }
//go:nosplit //go:nosplit
......
...@@ -1060,7 +1060,7 @@ runtime·dropm(void) ...@@ -1060,7 +1060,7 @@ runtime·dropm(void)
unlockextra(mp); unlockextra(mp);
} }
#define MLOCKED ((M*)1) #define MLOCKED 1
// lockextra locks the extra list and returns the list head. // lockextra locks the extra list and returns the list head.
// The caller must unlock the list by storing a new list head // The caller must unlock the list by storing a new list head
...@@ -1071,28 +1071,28 @@ runtime·dropm(void) ...@@ -1071,28 +1071,28 @@ runtime·dropm(void)
static M* static M*
lockextra(bool nilokay) lockextra(bool nilokay)
{ {
M *mp; uintptr mpx;
void (*yield)(void); void (*yield)(void);
for(;;) { for(;;) {
mp = runtime·atomicloadp(&runtime·extram); mpx = runtime·atomicloaduintptr((uintptr*)&runtime·extram);
if(mp == MLOCKED) { if(mpx == MLOCKED) {
yield = runtime·osyield; yield = runtime·osyield;
yield(); yield();
continue; continue;
} }
if(mp == nil && !nilokay) { if(mpx == 0 && !nilokay) {
runtime·usleep(1); runtime·usleep(1);
continue; continue;
} }
if(!runtime·casp(&runtime·extram, mp, MLOCKED)) { if(!runtime·casuintptr((uintptr*)&runtime·extram, mpx, MLOCKED)) {
yield = runtime·osyield; yield = runtime·osyield;
yield(); yield();
continue; continue;
} }
break; break;
} }
return mp; return (M*)mpx;
} }
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
......
...@@ -894,6 +894,7 @@ int32 runtime·round2(int32 x); // round x up to a power of 2. ...@@ -894,6 +894,7 @@ int32 runtime·round2(int32 x); // round x up to a power of 2.
bool runtime·cas(uint32*, uint32, uint32); bool runtime·cas(uint32*, uint32, uint32);
bool runtime·cas64(uint64*, uint64, uint64); bool runtime·cas64(uint64*, uint64, uint64);
bool runtime·casp(void**, void*, void*); bool runtime·casp(void**, void*, void*);
bool runtime·casuintptr(uintptr*, uintptr, uintptr);
// Don't confuse with XADD x86 instruction, // Don't confuse with XADD x86 instruction,
// this one is actually 'addx', that is, add-and-fetch. // this one is actually 'addx', that is, add-and-fetch.
uint32 runtime·xadd(uint32 volatile*, int32); uint32 runtime·xadd(uint32 volatile*, int32);
......
...@@ -48,7 +48,7 @@ runtime·gostringnocopy(byte *str) ...@@ -48,7 +48,7 @@ runtime·gostringnocopy(byte *str)
s.len = runtime·findnull(str); s.len = runtime·findnull(str);
while(true) { while(true) {
ms = runtime·maxstring; ms = runtime·maxstring;
if(s.len <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)s.len)) if(s.len <= ms || runtime·casuintptr(&runtime·maxstring, ms, s.len))
return s; return s;
} }
} }
......
...@@ -213,9 +213,6 @@ func write(fd uintptr, p unsafe.Pointer, n int32) int32 ...@@ -213,9 +213,6 @@ func write(fd uintptr, p unsafe.Pointer, n int32) int32
//go:noescape //go:noescape
func cas(ptr *uint32, old, new uint32) bool func cas(ptr *uint32, old, new uint32) bool
//go:noescape
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
//go:noescape //go:noescape
func casuintptr(ptr *uintptr, old, new uintptr) bool func casuintptr(ptr *uintptr, old, new uintptr) bool
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment