Golang源码学习(二)----Go源码学习基础
### 本文源码版本为 GO 1.17.8 Windows/amd64;
### 可能参与对比的版本:GO 1.16.2 Linux/amd64一、Golang的编译器究竟是如何工作的? (学习源码有什么意义)1. 能修改go语言程序源码 (从某种意义上来说你可以定制一个属于你的语言)2. 以语言开发者的角度去学习语言本身 (直接感受顶尖的设计思路,实用性算法和数据结构的学习)3. 理解go语言语法糖以及原生性的实现原理 (拒绝八股式面试,直接认识实现逻辑)二、修改go的源码如何在调用fmt.Println()时,自动添加一条"hello"?· 上一章中创建了一个hello.go文件,并使用go build得到可执行文件,./hello之后得到了hello,world的输出。· 进入调试模式,找到调用的函数:分屏1:gdb hello分屏2:vim hello.go可以发现在源码层面位于: (一层)at /root/go/go/src/fmt/print.go:294· 修改源码,重新编译编译器修改为:func Println(a ...interface{}) (n int, err error) {println("hello")return Fprintln(os.Stdout, a...)}重新编译编译器:cd $GOROOT/src.make.bash· 检查执行效果cd ../../reposgo build hello.go./hello显示结果除了 hello,world,在上面还有一行hello,成功!!!三、基本概念· 抽象语法树1. 编程语言 通过 变量 类型 运算符 等基本要素去白标计算机要执行的操作2. 输入的源码文件是一段字符串文本,结果词法分析后识别出哪些字符组成一个单词3. 将的那次组织成语法树(多叉树),并将其中对编译过程无关的语法细节忽略,即组织成一颗抽象语法树4. 抽象语法树就是用来描述语法结构的一种数据结构,是编译器能够识别的输入参数.尝试一下看看go文件是怎么被解析的:func main() {src := `package mainimport "fmt"func main() {v := make(map[string]string, 0)v["hello"] = "world"for k, v := range v {fmt.Printf("k: %v\n", k)fmt.Printf("v: %v\n", v)}}`fileset := token.NewFileSet()f, _ := parser.ParseFile(fileset, "", src, 0)ast.Print(fileset, f)}输出的结构体为*ast.file:type File struct {Doc *CommentGroup // associated documentation; or nilPackage token.Pos // position of "package" keywordName *Ident // package nameDecls []Decl // top-level declarations; or nilScope *Scope // package scope (this file only)Imports []*ImportSpec // imports in this fileUnresolved []*Ident // unresolved identifiers in this fileComments []*CommentGroup // list of all comments in the source file}· 静态单赋值1. 在生成的中间代码中,变量在整个生命周期内被赋值为一次,那么就成此中间代码具有SSA特性。2. 具有SSA特性的中间代码,会为编译器提供更多的优化空间· 指令集1. 汇编代码最终链接为可执行文件,在可执行文件中更多机器码是给处理器识别的操作命令;2. 不同的处理器支持的操作命令集合是不同的,造成了跨平台移植性的问题。四、Go编译器的主流程 (值得注意的是后面的gc指的是Go编译器,不是垃圾收集GC)## src/cmd/compile/README.md · 前端:1. 词法和语法分析a. 将源码字节流输入到词法解析器输出为token序列,去重空格逗号等无效字符;b. 将token序列输入语法分析器按规定好的文法,转换为抽象语法树;c. 在此过程中的语法错误会终止分析过程2. 类型检查与转换ASTa. 遍历AST的节点进行类型检查b. 改写关键字,展开语法糖 · 后端:1. 转换为SSA,生成中间代码将所有文件中的函数抽象出来加入一个队列,用协程并发生成为中间代码2. 生成机器代码链接不同的指令集生成对应平台的机器码· 入口:实际上gc.mian()才是真实实现的逻辑体现https://github.com/golang/go/blob/master/src/cmd/compile/internal/gc/main.gofunc main() {// disable timestamps for reproducible outputlog.SetFlags(0)log.SetPrefix("compile: ")buildcfg.Check()archInit, ok := archInits[buildcfg.GOARCH]if !ok {fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", buildcfg.GOARCH)os.Exit(2)}gc.Main(archInit)base.Exit(0)}五、词法和语法分析· 词法分析输入的字节流会在一个for循环中被迭代,调用scanner对象的next方法获取下一个被识别的token序列。拉取一次,下层才会执行一次,是一个拉模式的解析过程。type scanner struct {sourcemode uintnlsemi bool // if set '\n' and EOF translate to ';'// current token, valid after calling next()line, col uintblank bool // line is blank up to coltok tokenlit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF"); may be malformed if bad is truebad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be malformedkind LitKind // valid if tok is _Literalop Operator // valid if tok is _Operator, _AssignOp, or _IncOpprec int // valid if tok is _Operator, _AssignOp, or _IncOp}· 文法分析所有的go文件都会被解析成一个AST,因此所有的语法顶层都是从一个SourceFile开始的;最顶层的生产规则包含必选的包声明,以及可选的import声明和顶层声明;顶层声明包括 常量、类型、别名、变量、函数 五大类,其中常量和变量声明可以使用语法课。· 分析方法1. 自顶向下2. 自底向上3. 向前查看六、类型检查1. 静态类型强调的是编译期就会对程序的类型系统进行全面检查,而动态类型是指在编译期在将类型信息植入程序中使得在运行期间可以通过反射等方式操作对象实现动态功能。2. 类型检查不仅检查类型的合法型,同时也会完成对节点的类型转换为golang具体的类型系统的映射,并展开其中的语法糖###https://github.com/golang/go/blob/f5978a09589badb927d3aa96998fc785524cae02/src/cmd/compile/internal/gc/typecheck.go#L1726七、 中间代码生成1. 初始化ssa配置2. 函数替换:遍历并替换AST上某些关键字,将其转换为某个具体的运行时函数3. 生成SSA中间代码:经过多轮的迭代,将AST中的节点进行不断的转换,将其中关键词替换成运行包中的具体内建函数的符号引用查看生成的中间代码: go build -gcflags -S hello.go查看编译器的优化过程: GOSSAFUNC=main go build main.go 八、机器码生成
Golang源码学习(二)----Go源码学习基础相关推荐
- Android Glide图片加载框架(二)源码解析之load()
文章目录 一.前言 二.源码分析 1.load() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源 ...
- 汉信码(Hanxin Code)与QR码(QR Code)的终极对决
汉信码是"十五"期间中国物品编码中心主导开发出的不同于QR码的二维马码,主要针对汉字的编码方式进行了优化和扩展.但是从技术上讲与QR码的差别并不是很大,他们之间既有区别又有联系. ...
- sparkcore分区_Spark学习:Spark源码和调优简介 Spark Core (二)
本文基于 Spark 2.4.4 版本的源码,试图分析其 Core 模块的部分实现原理,其中如有错误,请指正.为了简化论述,将部分细节放到了源码中作为注释,因此正文中是主要内容. 第一部分内容见: S ...
- STL源码剖析学习二:空间配置器(allocator)
STL源码剖析学习二:空间配置器(allocator) 标准接口: vlaue_type pointer const_pointer reference const_reference size_ty ...
- 小白学习pytorch源码(二):setup.py最详细解读
小白学习pytorch源码(二) pytorch setup.py最全解析 setup.py与setuptools setup.py最详细解读 setup.py 环境检查 setup.py setup ...
- 【深度学习模型】智云视图中文车牌识别源码解析(二)
[深度学习模型]智云视图中文车牌识别源码解析(二) 感受 HyperLPR可以识别多种中文车牌包括白牌,新能源车牌,使馆车牌,教练车牌,武警车牌等. 代码不可谓不混乱(别忘了这是职业公司的准产品级代码 ...
- Android线程和线程池(二)HandlerThread学习记录 使用+源码
HandlerThreadAndroid线程和线程池(二)HandlerThread学习记录 使用+源码 一.作用 二.工作原理 三.HandlerThread的特点 优势: 劣势: 四.使用 五.源 ...
- 游戏思考17:寻路引擎recast和detour学习二:recast导航网格生成流程\源码剖析流程\局限性,附录计算点线面举例代码
一.recastnavigation使用介绍 1)模式选择 Solo Mesh:单块生成 Tile Mesh:分块生成 Temp Obstacles:分块并支持动态阻挡 这里测试的话选单块生成 2)模 ...
- yara 源码学习(二) 规则编译部分
yara规则的详细信息请参考: https://yara.readthedocs.io/en/stable/writingrules.html 根据官方文档,yara规则长这个样子: [1]:yara ...
最新文章
- Android开发7——android.database.CursorIndexOutOfBoundsException:Index -1 requested
- 介绍Azure服务平台,.NET Services及其中的访问控制服务(Access Control)
- 微信小程序开发学习记录01
- 李洋疯狂C语言之有关“you are come from shanghai”逆序(二)
- KindleConverter:Word批量转换为6寸PDF
- vue.js中H5使用微信摇一摇抽奖,判断摇一摇次数
- A*算法(最佳优先搜索)
- win10定时关机c语言,win10 定时关机命令怎么设置_win10怎么设置定时关机指令-win7之家...
- oracle中那个日期怎么相减_oracle日期相减
- 深富策略:险资密集调研 周期股板块能否崛起?
- 新西兰梅西大学有计算机专业吗,新西兰梅西大学世界排名|怎么样|入学条件_海外院校库-柳橙网...
- 谷歌 draco学习 二 压缩点信息
- java在360运行不了_电脑360安全卫士打不开如何解决_360安全卫士无法打开的处理方法...
- 前端模板标签eq与neq的使用,以及管理系统模块权限控制
- DPDK Rx flexible descriptor 在Intel E810 网卡中的使用
- C++编程易范错误集合
- matlab亥姆霍兹线圈叠加原理,亥姆霍兹线圈仿真剖析.docx
- 使用广播接收者获取短信及拦截电话
- Openwhisk之 -- 创建基于Docker的Action
- 【CS224n】(lecture7)机器翻译NMT,seq2seq和attention