这篇文章主要介绍“Go编译原理之函数内联怎么实现”,在日常操作中,相信很多人在Go编译原理之函数内联怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go编译原理之函数内联怎么实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!我们知道每一个高级编程语言的函数调用,成本都是在与需要为它分配栈内存来存储参数、返回值、局部变量等等,Go的函数调用的成本在于参数与返回值栈复制、较小的栈寄存器开销以及函数序言部分的检查栈扩容(Go语言中的栈是可以动态扩容的,因为Go在分配栈内存不是逐渐增加的,而是一次性分配,这样是为了避免访问越界,它会一次性分配,当检查到分配的栈内存不够用时,它会扩容一个足够大的栈空间,并将原来栈中的内容拷贝过来)下边写一段代码,通过Go的基准测试来测一下函数内联带来的效率提升在编译的过程中,Go的编译器其实会计算函数内联花费的成本,所以只有简单的函数,才会触发函数内联。在后边函数内联的源码实现中,我们可以看到下边这些情况不会被内联:递归函数函数前有如下注释的:go:noinline
、go:norace
、go:nocheckptr
、go:uintptrescapes
等没有函数体函数声明的抽象语法树中节点数大于5000(我的Go版本是1.16.6)(也就是函数内部语句太多的情况,也不会被内联)函数中包含闭包(OCLOSURE
)、range(ORANGE
)、select(OSELECT
)、go(OGO
)、defer(ODEFER
)、type(ODCLTYPE
)、返回值是函数(ORETJMP
)的,都不会内联我们也可以构建或编译的时候,通过参数去控制它是否可以内联。如果希望程序中所有的函数都不执行内联操作同样我们在编译时,也可以查看哪些函数内联了,哪些函数没内联,以及原因是什么看一个例子可以看到test1这个函数是可以内联的,因为它的函数体很简单。step这个函数因为是递归函数,所以它不会进行内联这里边其实每一个函数调用链都很深,我这里不会一行一行的解释代码的含义,仅仅会将一些核心的方法拿出来介绍一下,感兴趣的小伙伴可以自己去调试一下(前边有发相关文章)(Go源码调试方法)还是前边提到多次的Go编译入口文件,你可以在入口文件中找到这段代码下边就看一下每个方法都在做哪些事情该方法有两个参数:xtop
:前边已经见过它了,它存放的是每个声明语句的抽象语法树的根节点数组第二个参数是一个函数(该函数也有两个参数,一个是满足是函数类型声明的抽象语法树根节点数组,一个是bool值,true表示是递归函免费云主机域名数,false表示不是递归函数)进入到visitBottomUp方法中,你会发现它主要是遍历xtop,并对每个抽象语法树的根节点调用了visit
这个方法(仅针对是函数类型声明的抽象语法树)而visit
方法的核心是调用了inspectList
方法,通过inspectList
对抽象语法树按照深度优先搜索进行遍历,并将每一个节点作为inspectList
方法的第二个参数(是一个函数)的参数,比如验证这个函数里边是否有递归调用等(具体就是下边的switch case)后边通过调用visitBottomUp
的第二个参数传递的方法,对抽象语法树进行内联的判断及内联操作,具体就是caninl
和inlcalls
这两个方法该方法的作用就是验证是函数类型声明的抽象语法树是否可以内联这个方法的实现很简单,首先是通过很多的if语句验证函数前边是否有像go:noinline
等这种标记这里边还有一个主要的方法就是visitList
,它是用来验证函数里边是否有我们上边提到的go、select、range等等这些语句。对于满足内联条件的,它会将改写该函数声明抽闲语法树的内联字段(Inl
)该方法中就是具体的内联操作,比如将函数的参数和返回值转换为调用者中的声明语句等。里边的调用和实现都比较复杂,这里不粘代码了,大家可自行去看。函数内联的核心方法都在如下文件中到此,关于“Go编译原理之函数内联怎么实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注百云主机网站,小编会继续努力为大家带来更多实用的文章!
这篇文章主要介绍了es6中promise怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇es6中promise怎么使用文章都会有所收获,下面我们一起来看看吧。 es6 promise用于异步编程。Promise是异步编程的一…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。