Skip to content

Commit

Permalink
allow nested trap while avoiding infinite recursion (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Apr 13, 2024
1 parent f174b18 commit 5d31729
Show file tree
Hide file tree
Showing 25 changed files with 751 additions and 406 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ xgo version
# 1.0.x
```

If `xgo` is not found, you may need to check if `$GOPATH/bin` is added to your `PATH` variable.

There are other options,see [doc/INSTALLATION.md](./doc/INSTALLATION.md).

# Requirement
Expand All @@ -60,7 +62,6 @@ xgo version
# output
# 1.0.x
```
If `xgo` is not found, you may need to add `~/.xgo/bin` to your `PATH` variable.

2. Init a go project:
```sh
Expand All @@ -70,7 +71,7 @@ go mod init demo
```
3. Add `demo_test.go` with following code:
```go
package demo
package demo_test

import (
"context"
Expand All @@ -83,6 +84,7 @@ import (
func MyFunc() string {
return "my func"
}

func TestFuncMock(t *testing.T) {
mock.Mock(MyFunc, func(ctx context.Context, fn *core.FuncInfo, args core.Object, results core.Object) error {
results.GetFieldIndex(0).Set("mock func")
Expand Down Expand Up @@ -303,7 +305,7 @@ func TestMethodMock(t *testing.T){
}
```

**Notice for mocking stdlib**: due to performance and security impact, only a few packages and functions of stdlib can be mocked, the list can be found at [runtime/mock/stdlib.md](./runtime/mock/stdlib.md). If you want to mock additional stdlib functions, please discussion in [Issue#6](https://github.com/xhd2015/xgo/issues/6).
**Notice for mocking stdlib**: due to performance and security impact, only a few packages and functions of stdlib can be mocked, the list can be found at [runtime/mock/stdlib.md](./runtime/mock/stdlib.md). If you want to mock additional stdlib functions, please file a discussion in [Issue#6](https://github.com/xhd2015/xgo/issues/6).

## Patch
The `runtime/mock` package also provides another api:
Expand Down
5 changes: 3 additions & 2 deletions README_zh_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ xgo version
# 输出:
# 1.0.x
```
如果未找到`xgo`, 你可能需要查看`$GOPATH/bin`是否已经添加到你的`PATH`变量中。

更多安装方式, 参考[doc/INSTALLATION.md](./doc/INSTALLATION.md).

Expand All @@ -57,7 +58,6 @@ xgo version
# 输出
# 1.0.x
```
如果未找到`xgo`, 你可能需要将`~/.xgo/bin`添加到你的环境变量中。

2. 创建一个demo工程:
```sh
Expand All @@ -67,7 +67,7 @@ go mod init demo
```
3. 将下面的内容添加到文件`demo_test.go`中:
```go
package demo
package demo_test

import (
"context"
Expand All @@ -80,6 +80,7 @@ import (
func MyFunc() string {
return "my func"
}

func TestFuncMock(t *testing.T) {
mock.Mock(MyFunc, func(ctx context.Context, fn *core.FuncInfo, args core.Object, results core.Object) error {
results.GetFieldIndex(0).Set("mock func")
Expand Down
4 changes: 2 additions & 2 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package main
import "fmt"

const VERSION = "1.0.22"
const REVISION = "f34bf4ca38af8b5adcf36b67de5ea6fb853e4823+1"
const NUMBER = 174
const REVISION = "f174b18f76bff4bd8acddffd03835b760dad03d8+1"
const NUMBER = 175

func getRevision() string {
revSuffix := ""
Expand Down
12 changes: 11 additions & 1 deletion doc/INSTALLATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Standard installation
```sh
go install github.com/xhd2015/xgo/cmd/xgo@latest
```

# Install Prebuilt Binaries
Install prebuilt:
For environments like CI, xgo can be installed from pre-built binaries:
```sh
# macOS and Linux (and WSL)
curl -fsSL https://github.com/xhd2015/xgo/raw/master/install.sh | bash
Expand All @@ -8,6 +13,8 @@ curl -fsSL https://github.com/xhd2015/xgo/raw/master/install.sh | bash
powershell -c "irm github.com/xhd2015/xgo/raw/master/install.ps1|iex"
```

After installation, `~/.xgo/bin/xgo` will be available.

# Upgrade if you've already installed
If you've already installed `xgo`, you can upgrade it with:

Expand All @@ -22,4 +29,7 @@ If you want to build from source, run with:
git clone https://github.com/xhd2015/xgo
cd xgo
go run ./script/build-release --local

# check build version
~/.xgo/bin/xgo version
```
8 changes: 8 additions & 0 deletions patch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# patch
This directory contains code to patch the go runtime and compiler:
- [./](./)
- patch the compiler IR
- [syntax](syntax)
- patch the compiler AST
- [trap_runtime](trap_runtime)
- patch go runtime
24 changes: 21 additions & 3 deletions patch/ir.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ func convToEFace(pos src.XPos, x ir.Node, t *types.Type, ptr bool) *ir.ConvExpr

func isFirstStmtSkipTrap(nodes ir.Nodes) bool {
// NOTE: for performance reason, only check the first
if len(nodes) > 0 && isCallTo(nodes[0], xgoRuntimeTrapPkg, "Skip") {
return true
if len(nodes) > 0 {
firstNode := nodes[0]
if isCallTo(firstNode, xgoRuntimeTrapPkg, "Skip") || isCallToName(firstNode, "__xgo_trap_skip") {
return true
}
}
if false {
for _, node := range nodes {
Expand All @@ -157,6 +160,12 @@ func isFirstStmtSkipTrap(nodes ir.Nodes) bool {
}

func isCallTo(node ir.Node, pkgPath string, name string) bool {
return checkCall(node, pkgPath, name, true)
}
func isCallToName(node ir.Node, name string) bool {
return checkCall(node, "", name, false)
}
func checkCall(node ir.Node, pkgPath string, name string, checkPkg bool) bool {
callNode, ok := node.(*ir.CallExpr)
if !ok {
return false
Expand All @@ -169,7 +178,16 @@ func isCallTo(node ir.Node, pkgPath string, name string) bool {
if sym == nil {
return false
}
return sym.Pkg != nil && sym.Name == name && sym.Pkg.Path == pkgPath
if sym.Name != name {
return false
}
if !checkPkg {
return true
}
if sym.Pkg != nil && sym.Pkg.Path == pkgPath {
return true
}
return false
}

func newNilInterface(pos src.XPos) ir.Expr {
Expand Down
13 changes: 11 additions & 2 deletions patch/syntax/helper_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ type __xgo_local_func_stub struct {
Line int
}

func init() {
// ensure early init
var _ = func() bool {
__xgo_trap_skip()
__xgo_link_generate_init_regs_body()
}
return true
}()

// func init() {
// __xgo_link_generate_init_regs_body()
// }

// TODO: ensure safety for this
func __xgo_link_generate_init_regs_body() {
Expand Down Expand Up @@ -63,6 +70,8 @@ func __xgo_local_register_func(pkgPath string, identityName string, fn interface
__xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, IdentityName: identityName, Fn: fn, Closure: closure, RecvName: recvName, ArgNames: argNames, ResNames: resNames, File: file, Line: line})
}

func __xgo_trap_skip() {}

// not used
// func __xgo_local_register_interface(pkgPath string, interfaceName string, file string, line int) {
// __xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, Interface: true, File: file, Line: line})
Expand Down
13 changes: 11 additions & 2 deletions patch/syntax/helper_code_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions patch/trap_runtime/xgo_trap.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,29 @@ func __xgo_set_trap_var(trap func(pkgPath string, name string, tmpVarAddr interf

// NOTE: runtime has problem when using slice
var __xgo_registered_func_infos []interface{}
var __xgo_register_func_callback func(info interface{})

// a function cannot have too many params, so use a struct to wrap them
// the client should use reflect to retrieve these fields respectively

func __xgo_register_func(info interface{}) {
if __xgo_register_func_callback != nil {
__xgo_register_func_callback(info)
return
}
__xgo_registered_func_infos = append(__xgo_registered_func_infos, info)
}

func __xgo_retrieve_all_funcs_and_clear(f func(info interface{})) {
for _, fn := range __xgo_registered_func_infos {
if __xgo_register_func_callback != nil {
panic("__xgo_register_func_callback already set")
}
__xgo_register_func_callback = f
funcInfos := __xgo_registered_func_infos
__xgo_registered_func_infos = nil // clear
for _, fn := range funcInfos {
f(fn)
}
// clear
__xgo_registered_func_infos = nil
}

var __xgo_is_init_finished bool
Expand Down
4 changes: 2 additions & 2 deletions runtime/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

const VERSION = "1.0.22"
const REVISION = "f34bf4ca38af8b5adcf36b67de5ea6fb853e4823+1"
const NUMBER = 174
const REVISION = "f174b18f76bff4bd8acddffd03835b760dad03d8+1"
const NUMBER = 175

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down
Loading

0 comments on commit 5d31729

Please sign in to comment.