Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

支持 go1.20 下泛型打桩 #14

Merged
merged 3 commits into from
Oct 7, 2023
Merged

支持 go1.20 下泛型打桩 #14

merged 3 commits into from
Oct 7, 2023

Conversation

taoso
Copy link
Member

@taoso taoso commented Oct 4, 2023

Go 调用泛型函数时会先执行 LEA 指令,再执行 CALL 指令。我在上次提交

1f9d72d

中基于此特点跳过了跟 struct 传值产生的 CALL 指令,修复了 struct 传值导致
泛型打桩卡住的问题。

判断的依据是看 CALL 指令前面是否还有 LEA 指令且第一个参数为 RAX。

根据 Ruomenger 的调查,Go1.20 在执行 LEA 指令时,其目的寄存器由 RAX
改为 RBX,从而导致泛型 mock 出错。我还没找到对应的改动以及改动的原因。

Ruomenger 提议在检查 LEA 指令时同时支持 RAX 和 RBX 两种情况。但我认为
这样做不能根除问题,以后 Go 编译器改版可能还会引出新问题。

经过一番研究,我感觉使用函数名来判断可能是一个比较稳定的的办法。
getFirstCallFunc 最终找到泛型底层函数的地址。该地址对应的函数名包含[...]

github.com/go-kiss/monkey_test.add2[...]
github.com/go-kiss/monkey/demo.Add[...]
github.com/go-kiss/monkey_test.(*S2__monkey__[...]).Foo
github.com/go-kiss/monkey/demo.(*S2[...]).Foo

以此为基准来确定函数指针应该没问题。而且 Go 语言提供 runtime.FuncForPC 非常方便。

Fix #12

Go 调用泛型函数时会先执行 LEA 指令,再执行 CALL 指令。我在上次提交

1f9d72d

中基于此特点跳过了跟 struct 传值产生的 CALL 指令,修复了 struct 传值导致
泛型打桩卡住的问题。

判断的依据是看 CALL 指令前面是否还有 LEA 指令且第一个参数为 RAX。

根据 Ruomenger 的调查,Go1.20 在执行 LEA 指令时,其目的寄存器由 RAX
改为 RBX,从而导致泛型 mock 出错。我还没找到对应的改动以及改动的原因。

Ruomenger 提议在检查 LEA 指令时同时支持 RAX 和 RBX 两种情况。但我认为
这样做不能根除问题,以后 Go 编译器改版可能还会引出新问题。

经过一番研究,我感觉使用函数名来判断可能是一个比较稳定的的办法。
getFirstCallFunc 最终找到泛型底层函数的地址。该地址对应的函数名包含`[...]`:

```
github.com/go-kiss/monkey_test.add2[...]
github.com/go-kiss/monkey/demo.Add[...]
github.com/go-kiss/monkey_test.(*S2__monkey__[...]).Foo
github.com/go-kiss/monkey/demo.(*S2[...]).Foo
```

以此为基准来确定函数指针应该没问题。而且 Go 语言提供 runtime.FuncForPC 非常方便。

Fix #12
@Ruomenger
Copy link
Contributor

另外有个小提议,用不同的go版本如1.18、1.19、1.20、1.21进行测试,这样如果有哪个版本下的代码有问题也能及时发现

@taoso
Copy link
Member Author

taoso commented Oct 7, 2023

另外有个小提议,用不同的go版本如1.18、1.19、1.20、1.21进行测试,这样如果有哪个版本下的代码有问题也能及时发现

@Ruomenger 这个没问题。不过最近愚到了另一个困难。monkey 在 go1.20 之后的 win 平台上无法正常运行。我对 win 平台不熟,也没有 win 环境。之前还是 @kkbblzq 出手解决了 win 平台的兼容问题 #3

这次是不是考虑不再支持 win 平台了?可以引导 win 用户使用 wsl 😭

@Ruomenger
Copy link
Contributor

另外有个小提议,用不同的go版本如1.18、1.19、1.20、1.21进行测试,这样如果有哪个版本下的代码有问题也能及时发现

@Ruomenger 这个没问题。不过最近愚到了另一个困难。monkey 在 go1.20 之后的 win 平台上无法正常运行。我对 win 平台不熟,也没有 win 环境。之前还是 @kkbblzq 出手解决了 win 平台的兼容问题 #3

这次是不是考虑不再支持 win 平台了?可以引导 win 用户使用 wsl 😭

我是有windows平台(虽然平常写代码是在wsl2里),这个问题我可以先看下,看是否能解决(如果可以后续再提PR解决)。

感觉目前可以先合并把windows平台下的问题标明在README里,大部分人应该还是在linuxmacos下使用的。

@taoso taoso merged commit c4eda85 into master Oct 7, 2023
8 checks passed
@taoso taoso deleted the fix-go1.20 branch October 7, 2023 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

在go版本>=1.20时generic mock失败
2 participants