//go:开头的注释学习

导读:本篇文章讲解 //go:开头的注释学习,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

看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()
}

运行代码:
在这里插入图片描述

//go:noescape

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

与nowritebarrierrec相对,遇到写屏障会产生错误

//go:noinline

禁止内联,将函数调用处替换为被调用函数主体的一种编译器优化手段。

//go:norace

跳过竞态检测


参考连接

https://golang.org/cmd/compile/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/64661.html

(0)

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!