Skip to content

Commit

Permalink
add support to mock closures
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Mar 27, 2024
1 parent 52fa68b commit d6c2b3d
Show file tree
Hide file tree
Showing 17 changed files with 476 additions and 63 deletions.
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.7"
const REVISION = "6101b0a1a4b369d427afd75fed01273d0e09b933+1"
const NUMBER = 114
const REVISION = "52fa68beb627b6fc4246eeeeab191e2bc562cb8a+1"
const NUMBER = 115

func getRevision() string {
return fmt.Sprintf("%s %s BUILD_%d", VERSION, REVISION, NUMBER)
Expand Down
15 changes: 15 additions & 0 deletions patch/adapter_go1.17_18_19_20_21.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ func takeAddrs(fn *ir.Func, t *types.Type, nameOnly bool) ir.Expr {
return wrapListType(ir.NewCompLitExpr(fn.Pos(), ir.OCOMPLIT, typeNode(intfSlice), paramList))
}

func getFieldNames(fn *ir.Func, t *types.Type) ir.Expr {
if t.NumFields() == 0 {
return NewNilExpr(fn.Pos(), strSlice)
}
paramList := make([]ir.Node, t.NumFields())
i := 0
ForEachField(t, func(field *types.Field) bool {
fieldName := getFieldName(fn, field)
paramList[i] = NewStringLit(fn.Pos(), fieldName)
i++
return true
})
return wrapListType(ir.NewCompLitExpr(fn.Pos(), ir.OCOMPLIT, typeNode(strSlice), paramList))
}

func getTypeNames(params *types.Type) []ir.Node {
n := params.NumFields()
paramNames := make([]ir.Node, 0, n)
Expand Down
17 changes: 17 additions & 0 deletions patch/adapter_go1.22.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func NewBasicLit(pos src.XPos, t *types.Type, val constant.Value) ir.Node {
return ir.NewBasicLit(pos, t, val)
}

// NOTE: []*types.Field instead of *types.Type(go1.21)
func takeAddrs(fn *ir.Func, t []*types.Field, nameOnly bool) ir.Expr {
if len(t) == 0 {
return NewNilExpr(fn.Pos(), intfSlice)
Expand All @@ -62,6 +63,22 @@ func takeAddrs(fn *ir.Func, t []*types.Field, nameOnly bool) ir.Expr {
return ir.NewCompLitExpr(fn.Pos(), ir.OCOMPLIT, intfSlice, paramList)
}

// NOTE: []*types.Field instead of *types.Type(go1.21)
func getFieldNames(fn *ir.Func, t []*types.Field) ir.Expr {
if len(t) == 0 {
return NewNilExpr(fn.Pos(), strSlice)
}
paramList := make([]ir.Node, len(t))
i := 0
ForEachField(t, func(field *types.Field) bool {
fieldName := getFieldName(fn, field)
paramList[i] = NewStringLit(fn.Pos(), fieldName)
i++
return true
})
return ir.NewCompLitExpr(fn.Pos(), ir.OCOMPLIT, strSlice, paramList)
}

func getTypeNames(params []*types.Field) []ir.Node {
paramNames := make([]ir.Node, 0, len(params))
for _, p := range params {
Expand Down
71 changes: 67 additions & 4 deletions patch/ir.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package patch

import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
"go/constant"
"runtime"
"strings"
)

func ifConstant(pos src.XPos, b bool, body []ir.Node, els []ir.Node) *ir.IfStmt {
Expand All @@ -20,6 +23,15 @@ func ifConstant(pos src.XPos, b bool, body []ir.Node, els []ir.Node) *ir.IfStmt
func NewStringLit(pos src.XPos, s string) ir.Node {
return NewBasicLit(pos, types.Types[types.TSTRING], constant.MakeString(s))
}

func NewInt64Lit(pos src.XPos, i int64) ir.Node {
return NewBasicLit(pos, types.Types[types.TINT64], constant.MakeInt64(i))
}

func NewIntLit(pos src.XPos, i int) ir.Node {
return NewBasicLit(pos, types.Types[types.TINT], constant.MakeInt64(int64(i)))
}

func NewBoolLit(pos src.XPos, b bool) ir.Node {
return NewBasicLit(pos, types.Types[types.TBOOL], constant.MakeBool(b))
}
Expand All @@ -35,6 +47,10 @@ func NewBoolLit(pos src.XPos, b bool) ir.Node {
// __xgo_autogen.go:2:6: internal compiler error: unexpected initialization statement: (.)
const needToCreateInit = goMajor > 1 || (goMajor == 1 && goMinor >= 22)

// Deprecated: use __xgo_link_generate_init_regs_body instead
// principal: Don't rely too much on IR
// don't add function on the fly, instead, modify existing
// functions body
func prependInit(pos src.XPos, target *ir.Package, body []ir.Node) {
if !needToCreateInit && len(target.Inits) > 0 {
target.Inits[0].Body.Prepend(body...)
Expand All @@ -46,7 +62,12 @@ func prependInit(pos src.XPos, target *ir.Package, body []ir.Node) {
regFunc.Body = body

target.Inits = append(target.Inits, regFunc)
AddFuncs(regFunc)
// must call this in go1.22
if needToCreateInit {
// typecheck.DeclFunc(regFunc)
} else {
AddFuncs(regFunc)
}
}

func takeAddr(fn *ir.Func, field *types.Field, nameOnly bool) ir.Node {
Expand Down Expand Up @@ -91,6 +112,22 @@ func takeAddr(fn *ir.Func, field *types.Field, nameOnly bool) ir.Node {
return convToEFace(pos, arg, field.Type, true)
}

func getFieldName(fn *ir.Func, field *types.Field) string {
if field == nil {
return ""
}
if field.Nname == nil {
return ""
}
if false {
// debug
if field.Sym != nil {
return field.Sym.Name
}
}
return field.Nname.(*ir.Name).Sym().Name
}

func convToEFace(pos src.XPos, x ir.Node, t *types.Type, ptr bool) *ir.ConvExpr {
conv := ir.NewConvExpr(pos, ir.OCONV, types.Types[types.TINTER], x)
conv.SetImplicit(true)
Expand All @@ -105,9 +142,15 @@ func convToEFace(pos src.XPos, x ir.Node, t *types.Type, ptr bool) *ir.ConvExpr
}

func isFirstStmtSkipTrap(nodes ir.Nodes) bool {
for _, node := range nodes {
if isCallTo(node, xgoRuntimeTrapPkg, "Skip") {
return true
// NOTE: for performance reason, only check the first
if len(nodes) > 0 && isCallTo(nodes[0], xgoRuntimeTrapPkg, "Skip") {
return true
}
if false {
for _, node := range nodes {
if isCallTo(node, xgoRuntimeTrapPkg, "Skip") {
return true
}
}
}
return false
Expand All @@ -132,6 +175,26 @@ func isCallTo(node ir.Node, pkgPath string, name string) bool {
func newNilInterface(pos src.XPos) ir.Expr {
return NewNilExpr(pos, types.Types[types.TINTER])
}

func newEmptyStr(pos src.XPos) ir.Node {
return NewStringLit(pos, "")
}

func newNilInterfaceSlice(pos src.XPos) ir.Expr {
return NewNilExpr(pos, types.NewSlice(types.Types[types.TINTER]))
}

func getPosInfo(pos src.XPos) src.Pos {
return base.Ctxt.PosTable.Pos(pos)
}

func getAdjustedFile(f string) string {
if runtime.GOOS != "windows" {
return ""
}
// for windows, posFile has the form:
// C:/a/b/c
// while syncDeclMapping's file has the form:
// C:\a\b\c
return strings.ReplaceAll(f, "/", "\\")
}
22 changes: 18 additions & 4 deletions patch/syntax/helper_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,29 @@ type __xgo_local_func_stub struct {
Line int
}

func init() {
__xgo_link_generate_init_regs_body()
}

// TODO: ensure safety for this
func __xgo_link_generate_init_regs_body() {
// linked later by compiler
// NOTE: if the function is called by init, don't include
// any extra statements, they will be executed
// no matther whether you have replaced it or not
// panic("failed to link __xgo_link_generate_init_regs_body")
}

func __xgo_link_generated_register_func(fn interface{}) {
// linked later by compiler
panic("failed to link __xgo_link_generated_register_func")
}

func __xgo_local_register_func(pkgPath string, fn interface{}, closure bool, recvName string, argNames []string, resNames []string, file string, line int) {
__xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, Fn: fn, Closure: closure, RecvName: recvName, ArgNames: argNames, ResNames: resNames})
__xgo_link_generated_register_func(__xgo_local_func_stub{PkgPath: pkgPath, Fn: fn, Closure: closure, RecvName: recvName, ArgNames: argNames, ResNames: resNames, File: file, Line: line})
}

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})
}
// 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})
// }
19 changes: 15 additions & 4 deletions patch/syntax/helper_code_gen.go

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

7 changes: 6 additions & 1 deletion patch/syntax/syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,14 @@ func generateRegFileCode(pkgName string, fnName string, body string) string {
}

func generateRegHelperCode(pkgName string) string {
code := helperCode
if true {
// debug
code = strings.ReplaceAll(code, "__PKG__", xgo_ctxt.GetPkgPath())
}
autoGenStmts := []string{
"package " + pkgName,
helperCode,
code,
}
return strings.Join(autoGenStmts, "\n")
}
Expand Down
Loading

0 comments on commit d6c2b3d

Please sign in to comment.