这里为了可读性调解了格式,实际生成的代码,一般追加在文件大概已有行的尾部,不会影响原代码的行号。
以上面的伪代码为例,我们看看各开源实现是怎么对代码插桩的。
Go test cover实现方案
Go test cover插桩逻辑可以在go源码中看到
插桩完成后的代码如下
//line api.go:1
package cover_example
import "fmt"
func method() {GoCover.Count[0]++;
n := 100
k := 10
sum := 0
for i := 0; i < n; i++ {GoCover.Count[2]++;
if i%k == 0 {GoCover.Count[3]++;
sum += i
} else{ GoCover.Count[4]++;{
sum += 1
}}
}
GoCover.Count[1]++;fmt.Println(sum)
}
var GoCover = struct {
Count [5]uint32
Pos [3 * 5]uint32
NumStmt [5]uint16
} {
Pos: [3 * 5]uint32{
5, 9, 0x19000f, // [0]
16, 16, 0x120002, // [1]
9, 10, 0xf0019, // [2]
10, 12, 0x4000f, // [3]
12, 14, 0x40009, // [4]
},
NumStmt: [5]uint16{
4, // 0
1, // 1
1, // 2
1, // 3
1, // 4
},
}
复制代码
七牛云GOC
https://github.com/qiniu/goc
焦点逻辑跟Go test cover雷同的,部分代码也是复用的go test cover源码:pkg/cover/internal/tool/cover.go。
七牛云cover需要有main package才能插桩,实现原理与go test cover一致。不过七牛云将探针数组生成到了一个单独的文件,而不是像go test coverI 具追加到源码文件尾部