看go源码时,会经常看到很多这种 go:xxx 的注释
//go:linkname reflect_typehash reflect.typehash
//go:noescape
//go:nosplit
//go:nowritebarrierrec
//go:yeswritebarrierrec
//go:noinline
//go:norace
通过网上冲浪收集整理的知识如下:
//go:linkname localname [importpath.name]使用[importpath.name]作为源代码中声明的localname的变量或函数。由于该指令可以破坏类型系统和包模块化。因此只有引用了 unsafe 包才可以使用。
以在time包中定义了runtimeNano的函数为例
time/time.go
//go:linkname runtimeNano runtime.nanotime
func runtimeNano() int64
它的实际实现代码在runtime包下的sys_darwin.go中
runtime/sys_darwin.go
//go:nosplit
//go:cgo_unsafe_args
func nanotime() int64 {
var r struct {
t int64 // raw timer
numer, denom uint32 // conversion factors. nanoseconds = t * numer / denom.
}
libcCall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r))
// Note: Apple seems unconcerned about overflow here. See
// https://developer.apple.com/library/content/qa/qa1398/_index.html
// Note also, numer == denom == 1 is common.
t := r.t
if r.numer != 1 {
t *= int64(r.numer)
}
if r.denom != 1 {
t /= int64(r.denom)
}
return t
}
下面自己也来实现一个,目录结构如下
其中i.s为空文件,因为go build无法编译go:linkname,必须用单独的compile命令进行编译,因为go build会加上-complete参数,这个参数会检查到没有方法体的方法,并且不通过。
go:linkname可以跨包使用,当跨包使用时,目标方法或者变量必须导入有方法体的包,这个编译器才可以识别到链接
_ “LJ/golink/linkname”
文件内容如下:
a.go
package linkname
import (
"fmt"
_ "unsafe"
)
//go:linkname hello LJ/golink/outer.helloF
func hello() string {
fmt.Println("hello,world!")
return "asdsad"
}
world.go
package outer
import (
_ "LJ/golink/linkname"
"fmt"
)
func helloF() string
func World() {
fmt.Println(helloF())
}
main.go
package main
import (
"LJ/golink/outer"
)
func main() {
outer.World()
}
运行代码:
noescape的作用就是禁止逃逸,指定文件中的下一个声明必须是不带主题的func(意味着该声明的实现不是用Go编写的),不允许将作为参数传递的任何指针逃逸到堆或函数的返回值上。
runtime/os_dragonfly.go
//go:noescape
func lwp_create(param *lwpparams) int32
//go:noescape
func sigaltstack(new, old *stackt)
//go:noescape
func sigaction(sig uint32, new, old *sigactiont)
//go:nosplit
指定文件中声明的函数不得进行堆栈溢出检查,这是一个在不安全抢占调用goroutine时常用的做法。
runtime/chan.go
//go:nosplit
func chansend1(c *hchan, elem unsafe.Pointer) {
chansend(c, elem, true, getcallerpc())
}
//go:nowritebarrierrec
//go:yeswritebarrierrec指示编译器如果发现在下面的函数中包含写屏障, 产生一个错误。 (这不能阻止写屏障的产生,这只是个断言)
//go:noinline与nowritebarrierrec相对,遇到写屏障会产生错误
//go:norace禁止内联,将函数调用处替换为被调用函数主体的一种编译器优化手段。
跳过竞态检测
参考连接
https://golang.org/cmd/compile/
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)