Skip to content

Commit

Permalink
make runtime build with go1.14
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Apr 3, 2024
1 parent d56f35b commit 7784829
Show file tree
Hide file tree
Showing 21 changed files with 261 additions and 401 deletions.
6 changes: 3 additions & 3 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package main

import "fmt"

const VERSION = "1.0.16"
const REVISION = "b27192a64f46ddf3ddd2b02ca6fe52c8c4e03ffd+1"
const NUMBER = 154
const VERSION = "1.0.17"
const REVISION = "d56f35be1d57233e6b58145879ebe0fedf976361+1"
const NUMBER = 155

func getRevision() string {
return fmt.Sprintf("%s %s BUILD_%d", VERSION, REVISION, NUMBER)
Expand Down
6 changes: 3 additions & 3 deletions runtime/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"os"
)

const VERSION = "1.0.16"
const REVISION = "b27192a64f46ddf3ddd2b02ca6fe52c8c4e03ffd+1"
const NUMBER = 154
const VERSION = "1.0.17"
const REVISION = "d56f35be1d57233e6b58145879ebe0fedf976361+1"
const NUMBER = 155

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down
2 changes: 1 addition & 1 deletion runtime/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/xhd2015/xgo/runtime

go 1.18
go 1.14
1 change: 1 addition & 0 deletions runtime/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github.com/xhd2015/xgo v1.0.16 h1:JioCNN+n9weuV7lG3RNEceG23ynfOieZDjTpT2cHK2c=
138 changes: 135 additions & 3 deletions runtime/mock/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,72 @@ import (
"context"
"fmt"
"reflect"
"strings"

"github.com/xhd2015/xgo/runtime/core"
)

// Patch replaces `fn` with `replacer` in current goroutine,
// it returns a cleanup function to remove `replacer`.
// the `replacer` will be automatically cleared when current
// gorotuine exits if the returned cleanup function is not
// called.
func Patch(fn interface{}, replacer interface{}) func() {
if fn == nil {
panic("fn cannot be nil")
}
if replacer == nil {
panic("replacer cannot be nil")
}
fnType := reflect.TypeOf(fn)
if fnType.Kind() != reflect.Func {
panic(fmt.Errorf("fn should be func, actual: %T", fn))
}
if fnType != reflect.TypeOf(replacer) {
panic(fmt.Errorf("replacer should have type: %T, actual: %T", fn, replacer))
}

recvPtr, fnInfo, funcPC, trappingPC := getFunc(fn)
return mock(recvPtr, fnInfo, funcPC, trappingPC, buildInterceptorFromPatch(recvPtr, replacer))
}

func PatchByName(pkgPath string, funcName string, replacer interface{}) func() {
if replacer == nil {
panic("replacer cannot be nil")
}
t := reflect.TypeOf(replacer)
if t.Kind() != reflect.Func {
panic(fmt.Errorf("replacer should be func, actual: %T", replacer))
}

// check type
recvPtr, funcInfo, funcPC, trappingPC := getFuncByName(pkgPath, funcName)
if funcInfo.Func != nil {
calledType, replacerType, match := checkFuncTypeMatch(reflect.TypeOf(funcInfo.Func), t, recvPtr != nil)
if !match {
panic(fmt.Errorf("replacer should have type: %s, actual: %s", calledType, replacerType))
}
}
return mock(recvPtr, funcInfo, funcPC, trappingPC, buildInterceptorFromPatch(recvPtr, replacer))
}

func PatchMethodByName(instance interface{}, method string, replacer interface{}) func() {
if replacer == nil {
panic("replacer cannot be nil")
}
t := reflect.TypeOf(replacer)
if t.Kind() != reflect.Func {
panic(fmt.Errorf("replacer should be func, actual: %T", replacer))
}

// check type
recvPtr, funcInfo, funcPC, trappingPC := getMethodByName(instance, method)
if funcInfo.Func != nil {
calledType, replacerType, match := checkFuncTypeMatch(reflect.TypeOf(funcInfo.Func), t, recvPtr != nil)
if !match {
panic(fmt.Errorf("replacer should have type: %s, actual: %s", calledType, replacerType))
}
}
return mock(recvPtr, funcInfo, funcPC, trappingPC, buildInterceptorFromPatch(recvPtr, replacer))
}

Expand All @@ -36,15 +91,19 @@ func buildInterceptorFromPatch(recvPtr interface{}, replacer interface{}) func(c
callArgs := make([]reflect.Value, nIn)
src := 0
dst := 0

if fn.RecvType != "" {
if recvPtr != nil {
// patching an instance method
src++
// replacer's does not have receiver
} else {
// set receiver
callArgs[dst] = reflect.ValueOf(args.GetFieldIndex(0).Value())
dst++
src++
if nIn > 0 {
callArgs[dst] = reflect.ValueOf(args.GetFieldIndex(0).Value())
dst++
src++
}
}
}
if fn.FirstArgCtx {
Expand Down Expand Up @@ -80,3 +139,76 @@ func buildInterceptorFromPatch(recvPtr interface{}, replacer interface{}) func(c
return nil
}
}

func checkFuncTypeMatch(a reflect.Type, b reflect.Type, skipAFirst bool) (atype string, btype string, match bool) {
na := a.NumIn()
nb := b.NumIn()

base := 0
if skipAFirst {
base++
}
if na-base != nb {
return formatFuncType(a, skipAFirst), formatFuncType(b, false), false
}

for i := 0; i < na; i++ {
ta := a.In(i + base)
tb := b.In(i)
if ta != tb {
return formatFuncType(a, skipAFirst), formatFuncType(b, false), false
}
}

nouta := a.NumOut()
noutb := b.NumOut()
if nouta != noutb {
return formatFuncType(a, skipAFirst), formatFuncType(b, false), false
}
for i := 0; i < nouta; i++ {
ta := a.Out(i)
tb := b.Out(i)
if ta != tb {
return formatFuncType(a, skipAFirst), formatFuncType(b, false), false
}
}
return "", "", true
}

func formatFuncType(f reflect.Type, skipFirst bool) string {
n := f.NumIn()
i := 0
if skipFirst {
i++
}
var strBuilder strings.Builder
strBuilder.WriteString("func(")
for ; i < n; i++ {
t := f.In(i)
strBuilder.WriteString(t.String())
if i < n-1 {
strBuilder.WriteString(",")
}
}
strBuilder.WriteString(")")

nout := f.NumOut()
if nout > 0 {
strBuilder.WriteString(" ")
if nout > 1 {
strBuilder.WriteString("(")
}
for i := 0; i < nout; i++ {
t := f.Out(i)
strBuilder.WriteString(t.String())
if i < nout-1 {
strBuilder.WriteString(",")
}
}
if nout > 1 {
strBuilder.WriteString(")")
}
}

return strBuilder.String()
}
9 changes: 0 additions & 9 deletions runtime/mock/patch_go1.17.go

This file was deleted.

21 changes: 17 additions & 4 deletions runtime/mock/patch_go1.18.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,20 @@ package mock

// TODO: what if `fn` is a Type function
// instead of an instance method?
func Patch[T any](fn T, replacer T) func() {
recvPtr, fnInfo, funcPC, trappingPC := getFunc(fn)
return mock(recvPtr, fnInfo, funcPC, trappingPC, buildInterceptorFromPatch(recvPtr, replacer))
}
// func Patch[T any](fn T, replacer T) func() {
// recvPtr, fnInfo, funcPC, trappingPC := getFunc(fn)
// return mock(recvPtr, fnInfo, funcPC, trappingPC, buildInterceptorFromPatch(recvPtr, replacer))
// }

// NOTE: as a library targeting under go1.18, the library itself should not
// use any generic thing
//
// situiation:
// go.mod: 1.16
// runtime/go.mod: 1.18
// go version: 1.20

// compile error:
// implicit function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)
// mock.Patch(...)
// because mock.Patch was defined as generic
3 changes: 3 additions & 0 deletions runtime/test/atomic_generic/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build go1.18
// +build go1.18

package main

import (
Expand Down
90 changes: 0 additions & 90 deletions runtime/test/demo/main.go

This file was deleted.

12 changes: 0 additions & 12 deletions runtime/test/demo/main_test.go

This file was deleted.

3 changes: 3 additions & 0 deletions runtime/test/generic/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build go1.18
// +build go1.18

package main

func main() {
Expand Down
Loading

0 comments on commit 7784829

Please sign in to comment.