Skip to content

Commit

Permalink
runtime: revise partial of runtime source for go1.12
Browse files Browse the repository at this point in the history
Update: #3
  • Loading branch information
changkun committed Jan 27, 2019
1 parent d9baa4a commit a740361
Show file tree
Hide file tree
Showing 32 changed files with 307 additions and 261 deletions.
3 changes: 2 additions & 1 deletion content/7-lang/defer.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ func deferreturn(arg0 uintptr) {
只是函数的入口地址和参数,以及它的调用方 `deferreturn` 的 sp:

```asm
// void jmpdefer(fn, sp);
// func jmpdefer(fv *funcval, argp uintptr)
// argp 为调用方 SP
// 从 deferreturn 调用
// 1. 出栈调用方
// 2. 替换调用方返回的 5 个字节
Expand Down
7 changes: 2 additions & 5 deletions gosrc/runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,8 @@ P 可以理解一个 OS 调度器中的 CPU,`p` 类型的内容类似于每个

在非托管内存中分配对象**不得包含**堆指针,除非遵循下列原则:

1. 任何来自非托管内存的堆指针必须在 `runtime.markroot` 中添加为显式垃圾回收的 root。
2. If the memory is reused, the heap pointers must be zero-initialized
before they become visible as GC roots. Otherwise, the GC may
observe stale heap pointers. See "Zero-initialization versus
zeroing". 如果内存被重用,那么堆指针必须进行在他们作为 GC root 可见前进行零初始化。否则,GC 可能会回收已经过时的堆指针。请参考「零初始化与归零」
1. 任何来自非托管内存的指向堆的指针必须为垃圾回收的 root。具体而言,所有指针必须要么能够被一个全局变量访问到,要么能够在 `runtime.markroot` 中添加为显式垃圾回收的 root。
2. 如果内存被重用,那么堆指针必须进行在他们作为 GC root 可见前进行零初始化。否则,GC 可能会回收已经过时的堆指针。请参考「零初始化与归零」

零初始化 v.s. 归零
==================================
Expand Down
4 changes: 4 additions & 0 deletions gosrc/runtime/alg.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ func alginit() {
}

func initAlgAES() {
if GOOS == "aix" {
// runtime.algarray is immutable on AIX: see cmd/link/internal/ld/xcoff.go
return
}
useAeshash = true
algarray[alg_MEM32].hash = aeshash32
algarray[alg_MEM64].hash = aeshash64
Expand Down
8 changes: 8 additions & 0 deletions gosrc/runtime/asm.s
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ GLOBL runtime·memstats(SB), NOPTR, $0
// This function must be sizeofSkipFunction bytes.
TEXT runtime·skipPleaseUseCallersFrames(SB),NOSPLIT,$0-0
SKIP64; SKIP64; SKIP64; SKIP64

// abi0Syms is a dummy symbol that creates ABI0 wrappers for Go
// functions called from assembly in other packages.
TEXT abi0Syms<>(SB),NOSPLIT,$0-0
// obj assumes it can call morestack* using ABI0, but
// morestackc is actually defined in Go.
CALL ·morestackc(SB)
// References from syscall are automatically collected by cmd/go.
29 changes: 17 additions & 12 deletions gosrc/runtime/asm_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ TEXT runtime·asminit(SB),NOSPLIT,$0-0
* go-routine
*/

// void gosave(Gobuf*)
// func gosave(buf *gobuf)
// save state in Gobuf; setjmp
TEXT runtime·gosave(SB), NOSPLIT, $0-8
MOVQ buf+0(FP), AX // gobuf
Expand All @@ -249,7 +249,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
MOVQ BX, gobuf_g(AX)
RET

// void gogo(Gobuf*)
// func gosave(buf *gobuf)
// 从 Gobuf 恢复状态; longjmp
TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVQ buf+0(FP), BX // 运行现场
Expand Down Expand Up @@ -448,9 +448,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.

TEXT reflect·call(SB), NOSPLIT, $0-0
JMP ·reflectcall(SB)

TEXT ·reflectcall(SB), NOSPLIT, $0-32
MOVLQZX argsize+24(FP), CX
DISPATCH(runtime·call32, 32)
Expand Down Expand Up @@ -560,7 +557,8 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
// compile barrier.
RET

// void jmpdefer(fn, sp);
// func jmpdefer(fv *funcval, argp uintptr)
// argp 为调用方 SP
// 从 deferreturn 调用
// 1. 出栈调用方
// 2. 替换调用方返回的 5 个字节
Expand Down Expand Up @@ -662,7 +660,7 @@ nosave:
MOVL AX, ret+16(FP)
RET

// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
// func cgocallback(fn, frame unsafe.Pointer, framesize, ctxt uintptr)
// Turn the fn into a Go func (by taking its address) and call
// cgocallback_gofunc.
TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
Expand All @@ -678,7 +676,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
CALL AX
RET

// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
// func cgocallback_gofunc(fn, frame, framesize, ctxt uintptr)
// See cgocall.go for more details.
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
NO_LOCAL_POINTERS
Expand Down Expand Up @@ -708,7 +706,7 @@ needm:
get_tls(CX)
MOVQ g(CX), BX
MOVQ g_m(BX), BX

// Set m->sched.sp = SP, so that if a panic happens
// during the function we are about to execute, it will
// have a valid SP to run on the g0 stack.
Expand Down Expand Up @@ -803,7 +801,8 @@ havem:
// Done!
RET

// void setg(G*); set g. for use by needm.
// func setg(gg *g)
// set g. for use by needm.
TEXT runtime·setg(SB), NOSPLIT, $0-8
MOVQ gg+0(FP), BX
#ifdef GOOS_windows
Expand Down Expand Up @@ -858,13 +857,15 @@ done:
MOVQ AX, ret+0(FP)
RET

// func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
// hash function using AES hardware instructions
TEXT runtime·aeshash(SB),NOSPLIT,$0-32
MOVQ p+0(FP), AX // ptr to data
MOVQ s+16(FP), CX // size
LEAQ ret+24(FP), DX
JMP runtime·aeshashbody(SB)

// func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
MOVQ p+0(FP), AX // ptr to string struct
MOVQ 8(AX), CX // length of string
Expand Down Expand Up @@ -1202,7 +1203,8 @@ aesloop:
PXOR X9, X8
MOVQ X8, (DX)
RET


// func aeshash32(p unsafe.Pointer, h uintptr) uintptr
TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
MOVQ p+0(FP), AX // ptr to data
MOVQ h+8(FP), X0 // seed
Expand All @@ -1213,6 +1215,7 @@ TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
MOVQ X0, ret+16(FP)
RET

// func aeshash64(p unsafe.Pointer, h uintptr) uintptr
TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
MOVQ p+0(FP), AX // ptr to data
MOVQ h+8(FP), X0 // seed
Expand Down Expand Up @@ -1258,6 +1261,7 @@ DATA masks<>+0xf0(SB)/8, $0xffffffffffffffff
DATA masks<>+0xf8(SB)/8, $0x00ffffffffffffff
GLOBL masks<>(SB),RODATA,$256

// func checkASM() bool
TEXT ·checkASM(SB),NOSPLIT,$0-1
// check that masks<>(SB) and shifts<>(SB) are aligned to 16-byte
MOVQ $masks<>(SB), AX
Expand Down Expand Up @@ -1457,7 +1461,7 @@ GLOBL debugCallFrameTooLarge<>(SB), RODATA, $0x14 // Size duplicated below
// This function communicates back to the debugger by setting RAX and
// invoking INT3 to raise a breakpoint signal. See the comments in the
// implementation for the protocol the debugger is expected to
// follow. InjectDebugCall in the runtime tests demonstates this protocol.
// follow. InjectDebugCall in the runtime tests demonstrates this protocol.
//
// The debugger must ensure that any pointers passed to the function
// obey escape analysis requirements. Specifically, it must not pass
Expand Down Expand Up @@ -1608,6 +1612,7 @@ DEBUG_CALL_FN(debugCall16384<>, 16384)
DEBUG_CALL_FN(debugCall32768<>, 32768)
DEBUG_CALL_FN(debugCall65536<>, 65536)

// func debugCallPanicked(val interface{})
TEXT runtime·debugCallPanicked(SB),NOSPLIT,$16-16
// Copy the panic value to the top of stack.
MOVQ val_type+0(FP), AX
Expand Down
3 changes: 0 additions & 3 deletions gosrc/runtime/asm_wasm.s
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,6 @@ TEXT ·cgocallback_gofunc(SB), NOSPLIT, $16-32
JMP NAME(SB); \
End

TEXT reflect·call(SB), NOSPLIT, $0-0
JMP ·reflectcall(SB)

TEXT ·reflectcall(SB), NOSPLIT, $0-32
I64Load fn+8(FP)
I64Eqz
Expand Down
12 changes: 0 additions & 12 deletions gosrc/runtime/atomic_pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

// 这些函数不能拥有 go:noescape 标记,因为虽然 ptr 没有逃逸,但是 new 会逃逸。
// 如果 new 被标记为非逃逸,则编译器将不正确的对该指针变量存储的值进行逃逸分析决策。
// 相反,他们实际上是围绕原子 (casp1 等) 的封装,它们使用 noescape 来传递哪些参数不会逃逸。

// atomicwb 在原子指针写入之前执行 write barrier,调用方应使用 "if writeBarrier.enabled" 对调用
// 进行保护
Expand All @@ -34,17 +33,6 @@ func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
atomic.StorepNoWB(noescape(ptr), new)
}

//go:nosplit
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
// The write barrier is only necessary if the CAS succeeds,
// but since it needs to happen before the write becomes
// public, we have to do it conservatively all the time.
if writeBarrier.enabled {
atomicwb(ptr, new)
}
return atomic.Casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new)
}

// Like above, but implement in terms of sync/atomic's uintptr operations.
// We cannot just call the runtime routines, because the race detector expects
// to be able to intercept the sync/atomic forms but not the runtime forms.
Expand Down
27 changes: 15 additions & 12 deletions gosrc/runtime/chan.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ func makechan(t *chantype, size int) *hchan {
throw("makechan: bad alignment")
}

if size < 0 || uintptr(size) > maxSliceCap(elem.size) || uintptr(size)*elem.size > maxAlloc-hchanSize {
mem, overflow := math.MulUintptr(elem.size, uintptr(size))
if overflow || mem > maxAlloc-hchanSize || size < 0 {
panic(plainError("makechan: size out of range"))
}

Expand All @@ -135,20 +136,20 @@ func makechan(t *chantype, size int) *hchan {
// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
var c *hchan
switch {
case size == 0 || elem.size == 0:
case mem == 0:
// Queue or element size is zero.
c = (*hchan)(mallocgc(hchanSize, nil, true))
// Race detector uses this location for synchronization.
c.buf = c.raceaddr()
case elem.kind&kindNoPointers != 0:
// Elements do not contain pointers.
// Allocate hchan and buf in one call.
c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true))
c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
c.buf = add(unsafe.Pointer(c), hchanSize)
default:
// 元素包含指针
c = new(hchan)
c.buf = mallocgc(uintptr(size)*elem.size, elem, true)
c.buf = mallocgc(mem, elem, true)
}

c.elemsize = uint16(elem.size)
Expand Down Expand Up @@ -277,6 +278,11 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
gp.param = nil
c.sendq.enqueue(mysg)
goparkunlock(&c.lock, waitReasonChanSend, traceEvGoBlockSend, 3)
// Ensure the value being sent is kept alive until the
// receiver copies it out. The sudog has a pointer to the
// stack object, but sudogs aren't considered as roots of the
// stack tracer.
KeepAlive(ep)

// someone woke us up.
if mysg != gp.waiting {
Expand Down Expand Up @@ -388,7 +394,7 @@ func closechan(c *hchan) {

c.closed = 1

var glist *g
var glist gList

// release all readers
for {
Expand All @@ -408,8 +414,7 @@ func closechan(c *hchan) {
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
gp.schedlink.set(glist)
glist = gp
glist.push(gp)
}

// release all writers (they will panic)
Expand All @@ -427,15 +432,13 @@ func closechan(c *hchan) {
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
gp.schedlink.set(glist)
glist = gp
glist.push(gp)
}
unlock(&c.lock)

// Ready all Gs now that we've dropped the channel lock.
for glist != nil {
gp := glist
glist = glist.schedlink.ptr()
for !glist.empty() {
gp := glist.pop()
gp.schedlink = 0
goready(gp, 3)
}
Expand Down
1 change: 1 addition & 0 deletions gosrc/runtime/defs_linux_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
_MAP_FIXED = 0x10

_MADV_DONTNEED = 0x4
_MADV_FREE = 0x8
_MADV_HUGEPAGE = 0xe
_MADV_NOHUGEPAGE = 0xf

Expand Down
27 changes: 25 additions & 2 deletions gosrc/runtime/env_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows

package runtime

Expand All @@ -14,13 +14,36 @@ func gogetenv(key string) string {
throw("getenv before env init")
}
for _, s := range env {
if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
if len(s) > len(key) && s[len(key)] == '=' && envKeyEqual(s[:len(key)], key) {
return s[len(key)+1:]
}
}
return ""
}

// envKeyEqual reports whether a == b, with ASCII-only case insensitivity
// on Windows. The two strings must have the same length.
func envKeyEqual(a, b string) bool {
if GOOS == "windows" { // case insensitive
for i := 0; i < len(a); i++ {
ca, cb := a[i], b[i]
if ca == cb || lowerASCII(ca) == lowerASCII(cb) {
continue
}
return false
}
return true
}
return a == b
}

func lowerASCII(c byte) byte {
if 'A' <= c && c <= 'Z' {
return c + ('a' - 'A')
}
return c
}

var _cgo_setenv unsafe.Pointer // 指向 C 函数的指针
var _cgo_unsetenv unsafe.Pointer // 指向 C 函数的指针

Expand Down
Loading

0 comments on commit a740361

Please sign in to comment.