Skip to content

Commit

Permalink
fix mocking elminated closure
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Mar 30, 2024
1 parent b74c3b3 commit 1bc959a
Show file tree
Hide file tree
Showing 26 changed files with 358 additions and 187 deletions.
6 changes: 5 additions & 1 deletion cmd/xgo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,12 @@ func handleBuild(cmd string, args []string) error {

setupDone := make(chan struct{})
go func() {
d := 1 * time.Second
if isDevelopment {
d = 5 * time.Second
}
select {
case <-time.After(1 * time.Second):
case <-time.After(d):
fmt.Fprintf(os.Stderr, "xgo is taking a while to setup, please wait...\n")
case <-setupDone:
}
Expand Down
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.10"
const REVISION = "32788b163e5dd0f4ab1c34ebd5ff1781237ccdd1+1"
const NUMBER = 124
const VERSION = "1.0.11"
const REVISION = "b74c3b3830780e4793716b2b48505f22502528f2+1"
const NUMBER = 125

func getRevision() string {
return fmt.Sprintf("%s %s BUILD_%d", VERSION, REVISION, NUMBER)
Expand Down
2 changes: 2 additions & 0 deletions patch/adapter_go1.17_18_19_20_21.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,5 @@ func NewNameAt(pos src.XPos, sym *types.Sym, typ *types.Type) *ir.Name {
n.SetType(typ)
return n
}

const closureMayBeEleminatedDueToIfConst = true
1 change: 1 addition & 0 deletions patch/adapter_go1.22.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const goMajor = 1
const goMinor = 22

const genericTrapNeedsWorkaround = true
const closureMayBeEleminatedDueToIfConst = false

func forEachFunc(callback func(fn *ir.Func) bool) {
for _, fn := range typecheck.Target.Funcs {
Expand Down
34 changes: 34 additions & 0 deletions patch/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"cmd/compile/internal/types"

xgo_ctxt "cmd/compile/internal/xgo_rewrite_internal/patch/ctxt"
xgo_record "cmd/compile/internal/xgo_rewrite_internal/patch/record"
xgo_syntax "cmd/compile/internal/xgo_rewrite_internal/patch/syntax"
)

Expand Down Expand Up @@ -171,3 +172,36 @@ func regFuncsV1() {
// }
prependInit(base.AutogeneratedPos, typecheck.Target, regNodes)
}

func debugReplaceBody(fn *ir.Func) {
// debug
if false {
str := NewStringLit(fn.Pos(), "debug")
nd := fn.Body[0]
ue := nd.(*ir.UnaryExpr)
ce := ue.X.(*ir.ConvExpr)
ce.X = str
xgo_record.SetRewrittenBody(fn, fn.Body)
return
}
if false {
fn.Body = []ir.Node{
debugPrint("replaced body x\n"),
}
typeCheckBody(fn)
xgo_record.SetRewrittenBody(fn, fn.Body)
return
}
debugBody := ifConstant(fn.Pos(), true, []ir.Node{
debugPrint("replaced body 1\n"),
debugPrint("replaced body 2\n"),
ir.NewReturnStmt(base.AutogeneratedPos, nil),
fn.Body[0],
debugPrint("replaced body 3\n"),
// ir.NewReturnStmt(fn.Pos(), nil),
}, nil)
// debugBody := debugPrint("replaced body\n")
fn.Body = []ir.Node{debugBody}
typeCheckBody(fn)
xgo_record.SetRewrittenBody(fn, fn.Body)
}
4 changes: 2 additions & 2 deletions patch/syntax/helper_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ func __xgo_link_generated_register_func(fn interface{}) {
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, File: file, Line: line})
func __xgo_local_register_func(pkgPath string, identiyName 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, IdentityName: identiyName, Fn: fn, Closure: closure, RecvName: recvName, ArgNames: argNames, ResNames: resNames, File: file, Line: line})
}

// not used
Expand Down
4 changes: 2 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.

46 changes: 10 additions & 36 deletions patch/trap.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,11 @@ func InsertTrapForFunc(fn *ir.Func, forGeneric bool) bool {
identityName = decl.IdentityName()
generic = decl.Generic
}
if identityName == "" && isClosure {
identityName = fnSym.Name
}

if !isClosure && identityName == "" {
if identityName == "" {
return false
}
if genericTrapNeedsWorkaround && generic != forGeneric {
Expand Down Expand Up @@ -402,9 +405,11 @@ func initClosureRegs() {
argNames := getFieldNames(fn, fnType.Params())
resNames := getFieldNames(fn, fnType.Results())
// TODO: why fn.Name() always returns nil?
var fnRef ir.Node = convToEFace(pos, fn.Nname, fn.Type(), false)
if false {
// debug
var fnRef ir.Node
if !closureMayBeEleminatedDueToIfConst {
fnRef = convToEFace(pos, fn.Nname, fn.Type(), false)
} else {
// closure may be elminated
fnRef = newNilInterface(pos)
}
if false {
Expand All @@ -413,6 +418,7 @@ func initClosureRegs() {
}
registerNode := ir.NewCallExpr(pos, ir.OCALL, locRegFn, []ir.Node{
pkgPathLit,
NewStringLit(pos, fn.Sym().Name),
fnRef,
trueLit, // is closure
emptyStrLit, // no recv name
Expand Down Expand Up @@ -447,38 +453,6 @@ func findTestingPkg() *types.Pkg {
}
panic("testing package not imported")
}
func debugReplaceBody(fn *ir.Func) {
// debug
if false {
str := NewStringLit(fn.Pos(), "debug")
nd := fn.Body[0]
ue := nd.(*ir.UnaryExpr)
ce := ue.X.(*ir.ConvExpr)
ce.X = str
xgo_record.SetRewrittenBody(fn, fn.Body)
return
}
if false {
fn.Body = []ir.Node{
debugPrint("replaced body x\n"),
}
typeCheckBody(fn)
xgo_record.SetRewrittenBody(fn, fn.Body)
return
}
debugBody := ifConstant(fn.Pos(), true, []ir.Node{
debugPrint("replaced body 1\n"),
debugPrint("replaced body 2\n"),
ir.NewReturnStmt(base.AutogeneratedPos, nil),
fn.Body[0],
debugPrint("replaced body 3\n"),
// ir.NewReturnStmt(fn.Pos(), nil),
}, nil)
// debugBody := debugPrint("replaced body\n")
fn.Body = []ir.Node{debugBody}
typeCheckBody(fn)
xgo_record.SetRewrittenBody(fn, fn.Body)
}

func typeCheckBody(fn *ir.Func) {
savedFunc := ir.CurFunc
Expand Down
8 changes: 4 additions & 4 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.9"
const REVISION = "32788b163e5dd0f4ab1c34ebd5ff1781237ccdd1+1"
const NUMBER = 124
const VERSION = "1.0.11"
const REVISION = "b74c3b3830780e4793716b2b48505f22502528f2+1"
const NUMBER = 125

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand All @@ -24,7 +24,7 @@ func init() {
}
err := checkVersion()
if err != nil {
fmt.Fprintf(os.Stderr, "WARNING: xgo toolchain: %v\nnote: this message can be turned off by setting %s=true", err, XGO_CHECK_TOOLCHAIN_VERSION)
fmt.Fprintf(os.Stderr, "WARNING: xgo toolchain: %v\nnote: this message can be turned off by setting %s=true\n", err, XGO_CHECK_TOOLCHAIN_VERSION)
}
}

Expand Down
24 changes: 15 additions & 9 deletions runtime/functab/functab.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,24 @@ func ensureMapping() {
var pc uintptr
var fullName string
if !generic && !interface_ {
if closure {
// TODO: move all ctx, err check logic here
ft := reflect.TypeOf(f)
if ft.NumIn() > 0 && ft.In(0).Implements(ctxType) {
firstArgCtx = true
if f != nil {
if closure {
// TODO: move all ctx, err check logic here
ft := reflect.TypeOf(f)
if ft.NumIn() > 0 && ft.In(0).Implements(ctxType) {
firstArgCtx = true
}
if ft.NumOut() > 0 && ft.Out(ft.NumOut()-1).Implements(errType) {
lastResErr = true
}
}
if ft.NumOut() > 0 && ft.Out(ft.NumOut()-1).Implements(errType) {
lastResErr = true
pc = getFuncPC(f)
fullName = __xgo_link_get_pc_name(pc)
} else {
if closure && identityName != "" {
fullName = pkgPath + "." + identityName
}
}
pc = getFuncPC(f)
fullName = __xgo_link_get_pc_name(pc)
}
recvName := rv.FieldByName("RecvName").String()
argNames := rv.FieldByName("ArgNames").Interface().([]string)
Expand Down
5 changes: 4 additions & 1 deletion runtime/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,12 @@ func mock(mockRecvPtr interface{}, mockFnInfo *core.FuncInfo, funcPC uintptr, tr
Pre: func(ctx context.Context, f *core.FuncInfo, args, result core.Object) (data interface{}, err error) {
if f.PC == 0 {
if !f.Generic {
return nil, nil
if !f.Closure || trap.ClosureHasFunc {
return nil, nil
}
}
// may atch generic
// or closure without PC
}
if f != mockFnInfo {
// no match
Expand Down
30 changes: 30 additions & 0 deletions runtime/test/debug/debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// debug test is a convienent package
// you can paste your minimal code your
// to focus only the problemtic part of
// failing code

package debug

import (
"testing"

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

type struct_ struct {
}

func (c *struct_) F() {
panic("should never call me")
}

func TestDebug(t *testing.T) {
s := &struct_{}
srecv, sf := trap.Inspect(s.F)
if sf == nil {
t.Fatalf("struct_.F not found")
}
if srecv == nil {
t.Fatalf("expect receive for struct_.F not nil, actual: %v", srecv)
}
}
28 changes: 28 additions & 0 deletions runtime/test/mock_closure/mock_closuer_with_if_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mock_closuer

import "testing"

// see https://github.com/xhd2015/xgo/issues/13
func TestClosuerWithIfFalse(t *testing.T) {
// assert this function
var a int
if false {
func() {
a = 10
}()
}
if a != 0 {
t.Fatalf("expect a to be 0, actual: %d", a)
}
}
func TestClosuerWithIfTrue(t *testing.T) {
var a int
if true {
func() {
a = 10
}()
}
if a != 10 {
t.Fatalf("expect a to be 10, actual: %d", a)
}
}
40 changes: 40 additions & 0 deletions runtime/test/mock_closure/mock_defer_go_closuer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package mock_closuer

import (
"fmt"
"testing"
)

func TestImmediatelyCalledClosure(t *testing.T) {
// assert the compiler can compile
// and run this code
text := func(a int) string {
return fmt.Sprintf("%d", a)
}(10)
if text != "10" {
t.Logf("expect text to be %s, actual: %s", "10", text)
}
}

func TestDeferNoArgCall(t *testing.T) {
var b int
defer func() {
if b != 10 {
t.Fatalf("expect b to be %d, actual: %d", 10, b)
}
}()

b = 10
}

func TestDeferArgCall(t *testing.T) {
var b int
defer func(b int) {
if b != 10 {
t.Fatalf("expect b to be %d, actual: %d", 10, b)
}
}(10)

b = 11
_ = b
}
24 changes: 0 additions & 24 deletions runtime/test/mock_generic_debug/mock_generic_test.go

This file was deleted.

6 changes: 6 additions & 0 deletions runtime/trap/closure_go1.17_18_19_20_21.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !go1.22
// +build !go1.22

package trap

const ClosureHasFunc = false
6 changes: 6 additions & 0 deletions runtime/trap/closure_go1.22.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build go1.22
// +build go1.22

package trap

const ClosureHasFunc = true
Loading

0 comments on commit 1bc959a

Please sign in to comment.