github.com/goplus/igop@v0.25.0/runtime_test.go (about)

     1  package igop_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/goplus/igop"
     7  	_ "github.com/goplus/igop/pkg/log"
     8  )
     9  
    10  func TestFuncForPC(t *testing.T) {
    11  	src := `package main
    12  
    13  import (
    14  	"fmt"
    15  	"reflect"
    16  	"runtime"
    17  )
    18  
    19  func test() {
    20  	println("hello")
    21  }
    22  
    23  func main() {
    24  	pc := reflect.ValueOf(test).Pointer()
    25  	fn := runtime.FuncForPC(pc)
    26  	if fn == nil {
    27  		panic("error runtime.FuncForPC")
    28  	}
    29  	if fn.Name() != "main.test" {
    30  		panic("error name: " + fn.Name())
    31  	}
    32  	file, line := fn.FileLine(fn.Entry())
    33  	if file != "main.go" {
    34  		panic("error file:" + file)
    35  	}
    36  	if line != 9 {
    37  		panic(fmt.Errorf("error line: %v", line))
    38  	}
    39  }
    40  `
    41  	_, err := igop.RunFile("main.go", src, nil, 0)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  }
    46  
    47  func TestRuntimeCaller(t *testing.T) {
    48  	src := `package main
    49  
    50  import (
    51  	"fmt"
    52  	"path/filepath"
    53  	"runtime"
    54  	"strings"
    55  )
    56  
    57  var t *struct {
    58  	c chan int
    59  }
    60  
    61  var c chan int
    62  
    63  func f() {
    64  	select {
    65  	case <-t.c: // THIS IS LINE 18
    66  		break
    67  	case <-c:
    68  		break
    69  	}
    70  }
    71  
    72  func g() {
    73  	defer func() {
    74  		panic("error g1")
    75  	}()
    76  	defer func() {
    77  		panic("error g2")
    78  	}()
    79  	f()
    80  	panic("unreachable")
    81  }
    82  
    83  func main() {
    84  	defer func() {
    85  		recover()
    86  		var list []string
    87  		for i := 0; ; i++ {
    88  			pc, file, line, ok := runtime.Caller(i)
    89  			if !ok {
    90  				break
    91  			}
    92  			fn := runtime.FuncForPC(pc)
    93  			fnName := fn.Name()
    94  			if fnName == "runtime.gopanic" {
    95  				list = append(list, "runtime.gopanic")
    96  			} else if strings.HasPrefix(fnName, "main.") {
    97  				_, fname := filepath.Split(file)
    98  				list = append(list, fmt.Sprintf("%v %v:%v", fnName, fname, line))
    99  			}
   100  			fmt.Println(pc, fnName, file, line)
   101  		}
   102  		if v := fmt.Sprint(list); v != infos {
   103  			panic(v)
   104  		}
   105  	}()
   106  	g()
   107  }
   108  
   109  var infos = "[main.main.func1 main.go:41 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.g.func2 main.go:30 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:59]"
   110  `
   111  	_, err := igop.RunFile("main.go", src, nil, 0)
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  }
   116  
   117  func TestRuntimeCallers1(t *testing.T) {
   118  	src := `package main
   119  
   120  import (
   121  	"fmt"
   122  	"path/filepath"
   123  	"runtime"
   124  	"strings"
   125  )
   126  
   127  var t *struct {
   128  	c chan int
   129  }
   130  
   131  var c chan int
   132  
   133  func f() {
   134  	select {
   135  	case <-t.c: // THIS IS LINE 18
   136  		break
   137  	case <-c:
   138  		break
   139  	}
   140  }
   141  
   142  func g() {
   143  	// defer func() {
   144  	// 	panic("error g1")
   145  	// }()
   146  	// defer func() {
   147  	// 	panic("error g2")
   148  	// }()
   149  	f()
   150  	panic("unreachable")
   151  }
   152  
   153  func main() {
   154  	defer func() {
   155  		recover()
   156  		rpc := make([]uintptr, 64)
   157  		runtime.Callers(0, rpc)
   158  		fs := runtime.CallersFrames(rpc)
   159  		var list []string
   160  		for {
   161  			f, more := fs.Next()
   162  			if f.Function == "runtime.gopanic" {
   163  				list = append(list, "runtime.gopanic")
   164  			} else if strings.HasPrefix(f.Function, "main.") {
   165  				_, fname := filepath.Split(f.File)
   166  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   167  			}
   168  			fmt.Println(f)
   169  			if !more {
   170  				break
   171  			}
   172  		}
   173  		if v := fmt.Sprint(list); v != infos {
   174  			panic(v)
   175  		}
   176  	}()
   177  	g()
   178  }
   179  
   180  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]"
   181  `
   182  	_, err := igop.RunFile("main.go", src, nil, 0)
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  }
   187  
   188  func TestRuntimeCallers2(t *testing.T) {
   189  	src := `package main
   190  
   191  import (
   192  	"fmt"
   193  	"path/filepath"
   194  	"runtime"
   195  	"strings"
   196  )
   197  
   198  var t *struct {
   199  	c chan int
   200  }
   201  
   202  var c chan int
   203  
   204  func f() {
   205  	select {
   206  	case <-t.c: // THIS IS LINE 18
   207  		break
   208  	case <-c:
   209  		break
   210  	}
   211  }
   212  
   213  func g() {
   214  	defer func() {
   215  		panic("error g1")
   216  	}()
   217  	// defer func() {
   218  	// 	panic("error g2")
   219  	// }()
   220  	f()
   221  	panic("unreachable")
   222  }
   223  
   224  func main() {
   225  	defer func() {
   226  		recover()
   227  		rpc := make([]uintptr, 64)
   228  		runtime.Callers(0, rpc)
   229  		fs := runtime.CallersFrames(rpc)
   230  		var list []string
   231  		for {
   232  			f, more := fs.Next()
   233  			if f.Function == "runtime.gopanic" {
   234  				list = append(list, "runtime.gopanic")
   235  			} else if strings.HasPrefix(f.Function, "main.") {
   236  				_, fname := filepath.Split(f.File)
   237  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   238  			}
   239  			fmt.Println(f)
   240  			if !more {
   241  				break
   242  			}
   243  		}
   244  		if v := fmt.Sprint(list); v != infos {
   245  			panic(v)
   246  		}
   247  	}()
   248  	g()
   249  }
   250  
   251  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]"
   252  `
   253  	_, err := igop.RunFile("main.go", src, nil, 0)
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  }
   258  
   259  func TestRuntimeCallers3(t *testing.T) {
   260  	src := `package main
   261  
   262  import (
   263  	"fmt"
   264  	"path/filepath"
   265  	"runtime"
   266  	"strings"
   267  )
   268  
   269  var t *struct {
   270  	c chan int
   271  }
   272  
   273  var c chan int
   274  
   275  func f() {
   276  	select {
   277  	case <-t.c: // THIS IS LINE 18
   278  		break
   279  	case <-c:
   280  		break
   281  	}
   282  }
   283  
   284  func g() {
   285  	defer func() {
   286  		panic("error g1")
   287  	}()
   288  	defer func() {
   289  		panic("error g2")
   290  	}()
   291  	f()
   292  	panic("unreachable")
   293  }
   294  
   295  func main() {
   296  	defer func() {
   297  		recover()
   298  		rpc := make([]uintptr, 64)
   299  		runtime.Callers(0, rpc)
   300  		fs := runtime.CallersFrames(rpc)
   301  		var list []string
   302  		for {
   303  			f, more := fs.Next()
   304  			if f.Function == "runtime.gopanic" {
   305  				list = append(list, "runtime.gopanic")
   306  			} else if strings.HasPrefix(f.Function, "main.") {
   307  				_, fname := filepath.Split(f.File)
   308  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   309  			}
   310  			fmt.Println(f)
   311  			if !more {
   312  				break
   313  			}
   314  		}
   315  		if v := fmt.Sprint(list); v != infos {
   316  			panic(v)
   317  		}
   318  	}()
   319  	g()
   320  }
   321  
   322  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.g.func2 main.go:30 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]"
   323  `
   324  	_, err := igop.RunFile("main.go", src, nil, 0)
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  }
   329  
   330  func TestRuntimeCallers4(t *testing.T) {
   331  	src := `package main
   332  
   333  import (
   334  	"fmt"
   335  	"path/filepath"
   336  	"runtime"
   337  	"strings"
   338  )
   339  
   340  var t *struct {
   341  	c chan int
   342  }
   343  
   344  var c chan int
   345  
   346  func f() {
   347  	select {
   348  	case <-t.c: // THIS IS LINE 18
   349  		break
   350  	case <-c:
   351  		break
   352  	}
   353  }
   354  
   355  func g() {
   356  	defer func() {
   357  		// panic("error g1")
   358  	}()
   359  	defer func() {
   360  		// panic("error g2")
   361  		f()
   362  	}()
   363  	// f()
   364  }
   365  
   366  func main() {
   367  	defer func() {
   368  		recover()
   369  		rpc := make([]uintptr, 64)
   370  		runtime.Callers(0, rpc)
   371  		fs := runtime.CallersFrames(rpc)
   372  		var list []string
   373  		for {
   374  			f, more := fs.Next()
   375  			if f.Function == "runtime.gopanic" {
   376  				list = append(list, "runtime.gopanic")
   377  			} else if strings.HasPrefix(f.Function, "main.") {
   378  				_, fname := filepath.Split(f.File)
   379  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   380  			}
   381  			fmt.Println(f)
   382  			if !more {
   383  				break
   384  			}
   385  		}
   386  		if v := fmt.Sprint(list); v != infos {
   387  			panic(v)
   388  		}
   389  	}()
   390  	g()
   391  }
   392  
   393  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 main.g main.go:34 main.main main.go:60]"
   394  `
   395  	_, err := igop.RunFile("main.go", src, nil, 0)
   396  	if err != nil {
   397  		t.Fatal(err)
   398  	}
   399  }
   400  
   401  func TestRuntimeCallers5(t *testing.T) {
   402  	src := `package main
   403  
   404  import (
   405  	"fmt"
   406  	"path/filepath"
   407  	"runtime"
   408  	"strings"
   409  )
   410  
   411  var t *struct {
   412  	c chan int
   413  }
   414  
   415  var c chan int
   416  
   417  func f() {
   418  	select {
   419  	case <-t.c: // THIS IS LINE 18
   420  		break
   421  	case <-c:
   422  		break
   423  	}
   424  }
   425  
   426  func g() {
   427  	defer func() {
   428  		// panic("error g1")
   429  	}()
   430  	defer func() {
   431  		// panic("error g2")
   432  		f()
   433  	}()
   434  	f()
   435  }
   436  
   437  func main() {
   438  	defer func() {
   439  		recover()
   440  		rpc := make([]uintptr, 64)
   441  		runtime.Callers(0, rpc)
   442  		fs := runtime.CallersFrames(rpc)
   443  		var list []string
   444  		for {
   445  			f, more := fs.Next()
   446  			if f.Function == "runtime.gopanic" {
   447  				list = append(list, "runtime.gopanic")
   448  			} else if strings.HasPrefix(f.Function, "main.") {
   449  				_, fname := filepath.Split(f.File)
   450  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   451  			}
   452  			fmt.Println(f)
   453  			if !more {
   454  				break
   455  			}
   456  		}
   457  		if v := fmt.Sprint(list); v != infos {
   458  			panic(v)
   459  		}
   460  	}()
   461  	g()
   462  }
   463  
   464  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 runtime.gopanic main.f main.go:18 main.g main.go:33 main.main main.go:60]"
   465  `
   466  	_, err := igop.RunFile("main.go", src, nil, 0)
   467  	if err != nil {
   468  		t.Fatal(err)
   469  	}
   470  }
   471  
   472  func TestRuntimeCallers6(t *testing.T) {
   473  	src := `package main
   474  
   475  import (
   476  	"fmt"
   477  	"path/filepath"
   478  	"runtime"
   479  	"strings"
   480  )
   481  
   482  var t *struct {
   483  	c chan int
   484  }
   485  
   486  var c chan int
   487  
   488  func f() {
   489  	select {
   490  	case <-t.c: // THIS IS LINE 18
   491  		break
   492  	case <-c:
   493  		break
   494  	}
   495  }
   496  
   497  func g() {
   498  	defer func() {
   499  		panic("error g1")
   500  	}()
   501  	defer func() {
   502  		// panic("error g2")
   503  		f()
   504  	}()
   505  	// f()
   506  }
   507  
   508  func main() {
   509  	defer func() {
   510  		recover()
   511  		rpc := make([]uintptr, 64)
   512  		runtime.Callers(0, rpc)
   513  		fs := runtime.CallersFrames(rpc)
   514  		var list []string
   515  		for {
   516  			f, more := fs.Next()
   517  			if f.Function == "runtime.gopanic" {
   518  				list = append(list, "runtime.gopanic")
   519  			} else if strings.HasPrefix(f.Function, "main.") {
   520  				_, fname := filepath.Split(f.File)
   521  				list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line))
   522  			}
   523  			fmt.Println(f)
   524  			if !more {
   525  				break
   526  			}
   527  		}
   528  		if v := fmt.Sprint(list); v != infos {
   529  			panic(v)
   530  		}
   531  	}()
   532  	g()
   533  }
   534  
   535  var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 main.g main.go:34 main.main main.go:60]"
   536  `
   537  	_, err := igop.RunFile("main.go", src, nil, 0)
   538  	if err != nil {
   539  		t.Fatal(err)
   540  	}
   541  }
   542  
   543  func TestRuntimeCallerMethodWrapper(t *testing.T) {
   544  	src := `package main
   545  
   546  import (
   547  	"fmt"
   548  	"reflect"
   549  	"runtime"
   550  	"strings"
   551  )
   552  
   553  type T int
   554  
   555  func (T) f() int { return 0 }
   556  
   557  func (*T) g() int { return 0 }
   558  
   559  type I interface {
   560  	f() int
   561  }
   562  
   563  var (
   564  	index int
   565  )
   566  
   567  func check(v interface{}, name string, autogen bool) {
   568  	index++
   569  	pc := reflect.ValueOf(v).Pointer()
   570  	fn := runtime.FuncForPC(pc)
   571  	typ := reflect.ValueOf(v).Type()
   572  	file, line := fn.FileLine(pc)
   573  	fmt.Println(typ, fn.Name(), file, line)
   574  	if name != "" && name != fn.Name() {
   575  		panic(fmt.Errorf("%v: name got %v, want %v", index, fn.Name(), name))
   576  	}
   577  	if autogen {
   578  		if file != "<autogenerated>" || line != 1 {
   579  			panic(fmt.Errorf("%v: file must autogen %v %v", index, file, line))
   580  		}
   581  	} else {
   582  		if !strings.Contains(file, "main.go") {
   583  			panic(fmt.Errorf("%v: file must main.go %v %v", index, file, line))
   584  		}
   585  	}
   586  }
   587  
   588  func main() {
   589  	ver := runtime.Version()[:6]
   590  	if ver < "go1.18" {
   591  		// $thunk
   592  		check(T.f, "main.T.f", false)
   593  		check((*T).g, "main.(*T).g", false)
   594  		check((struct{ T }).f, "", true)
   595  		check((struct{ *T }).g, "", true)
   596  		// $bound
   597  		check(T(0).f, "main.T.f-fm", false)
   598  		check(new(T).f, "main.T.f-fm", false)
   599  		check(new(T).g, "main.(*T).g-fm", false)
   600  		// wrapper
   601  		check(I.f, "main.I.f", true)
   602  	} else {
   603  		// $thunk
   604  		check(T.f, "main.T.f", false)
   605  		check((*T).g, "main.(*T).g", false)
   606  		check((struct{ T }).f, "", true)
   607  		check((struct{ *T }).g, "", true)
   608  		// $bound
   609  		check(T(0).f, "main.T.f-fm", true)
   610  		check(new(T).f, "main.T.f-fm", true)
   611  		check(new(T).g, "main.(*T).g-fm", true)
   612  		// wrapper
   613  		check(I.f, "main.I.f", true)
   614  	}
   615  }
   616  `
   617  	_, err := igop.RunFile("main.go", src, nil, 0)
   618  	if err != nil {
   619  		t.Fatal(err)
   620  	}
   621  }
   622  
   623  func TestGC15281(t *testing.T) {
   624  	// $GOROOT/test/fixedbugs/issue15281.go
   625  	src := `// run
   626  
   627  // Copyright 2016 The Go Authors.  All rights reserved.
   628  // Use of this source code is governed by a BSD-style
   629  // license that can be found in the LICENSE file.
   630  
   631  package main
   632  
   633  import "runtime"
   634  
   635  func main() {
   636  	{
   637  		x := inuse()
   638  		c := make(chan []byte, 10)
   639  		c <- make([]byte, 10<<20)
   640  		close(c)
   641  		f1(c, x)
   642  	}
   643  	{
   644  		x := inuse()
   645  		c := make(chan []byte, 10)
   646  		c <- make([]byte, 10<<20)
   647  		close(c)
   648  		f2(c, x)
   649  	}
   650  }
   651  
   652  func f1(c chan []byte, start int64) {
   653  	for x := range c {
   654  		if delta := inuse() - start; delta < 9<<20 {
   655  			println("BUG: f1: after alloc: expected delta at least 9MB, got: ", delta)
   656  			println(x)
   657  		}
   658  		x = nil
   659  		if delta := inuse() - start; delta > 1<<20 {
   660  			println("BUG: f1: after alloc: expected delta below 1MB, got: ", delta)
   661  			println(x)
   662  		}
   663  	}
   664  }
   665  
   666  func f2(c chan []byte, start int64) {
   667  	for {
   668  		x, ok := <-c
   669  		if !ok {
   670  			break
   671  		}
   672  		if delta := inuse() - start; delta < 9<<20 {
   673  			println("BUG: f2: after alloc: expected delta at least 9MB, got: ", delta)
   674  			println(x)
   675  		}
   676  		x = nil
   677  		if delta := inuse() - start; delta > 1<<20 {
   678  			println("BUG: f2: after alloc: expected delta below 1MB, got: ", delta)
   679  			println(x)
   680  		}
   681  	}
   682  }
   683  
   684  func inuse() int64 {
   685  	runtime.GC()
   686  	var st runtime.MemStats
   687  	runtime.ReadMemStats(&st)
   688  	return int64(st.Alloc)
   689  }
   690  `
   691  	_, err := igop.RunFile("main.go", src, nil, igop.ExperimentalSupportGC)
   692  	if err != nil {
   693  		t.Fatal(err)
   694  	}
   695  }
   696  
   697  func TestLinknameSource(t *testing.T) {
   698  	pkg := `package pkg
   699  type point struct {
   700  	x int
   701  	y int
   702  }
   703  func (t point) scale(n int) point {
   704  	return point{t.x*n,t.y*n}
   705  }
   706  func (t *point) setScale(n int) {
   707  	t.x *= n
   708  	t.y *= n
   709  }
   710  func (t *point) info() (int,int) {
   711  	return t.x,t.y
   712  }
   713  func add(v ...int) (sum int) {
   714  	for _, n := range v {
   715  		sum += n
   716  	}
   717  	return
   718  }
   719  func New(x int, y int) *point {
   720  	return &point{x,y}
   721  }
   722  `
   723  	src := `package main
   724  import (
   725  	_ "unsafe"
   726  	_ "pkg"
   727  	"fmt"
   728  )
   729  
   730  //go:linkname add pkg.add
   731  func add(v ...int) int
   732  
   733  type point struct {
   734  	x int
   735  	y int
   736  }
   737  
   738  //go:linkname newPoint pkg.New
   739  func newPoint(x int, y int) *point
   740  
   741  //go:linkname scalePoint pkg.point.scale
   742  func scalePoint(point,int) point
   743  
   744  //go:linkname setScale pkg.(*point).setScale
   745  func setScale(*point,int)
   746  
   747  func main() {
   748  	v := add(100,200,300)
   749  	if v != 600 {
   750  		panic(fmt.Errorf("add got %v, must 600",v))
   751  	}
   752  	pt := newPoint(100,200)
   753  	if pt == nil || pt.x != 100 || pt.y != 200 {
   754  		panic(fmt.Errorf("newPoint got %v, must &{100 200}",pt))
   755  	}
   756  	pt2 := scalePoint(*pt,2)
   757  	if pt2.x != 200 || pt2.y != 400 {
   758  		panic(fmt.Errorf("scalePoint got %v, must {200 400}",pt2))
   759  	}
   760  	setScale(pt,3)
   761  	if pt.x != 300 || pt.y != 600 {
   762  		panic(fmt.Errorf("setScale got %v, must &{300 600}",pt))
   763  	}
   764  }
   765  `
   766  	ctx := igop.NewContext(0)
   767  	ctx.AddImportFile("pkg", "pkg.go", pkg)
   768  	_, err := ctx.RunFile("main.go", src, nil)
   769  	if err != nil {
   770  		t.Fatal(err)
   771  	}
   772  }
   773  
   774  func TestLinknameExtern(t *testing.T) {
   775  	pkg := `package pkg
   776  func add(v ...int) (sum int) {
   777  	for _, n := range v {
   778  		sum += n
   779  	}
   780  	return
   781  }
   782  `
   783  	src := `package main
   784  import (
   785  	_ "unsafe"
   786  	_ "pkg"
   787  	"fmt"
   788  )
   789  
   790  //go:linkname add pkg.add
   791  func add(v ...int) int
   792  
   793  type point struct {
   794  	x int
   795  	y int
   796  }
   797  
   798  //go:linkname newPoint pkg.New
   799  func newPoint(x int, y int) *point
   800  
   801  //go:linkname scalePoint pkg.point.scale
   802  func scalePoint(point,int) point
   803  
   804  //go:linkname setScale pkg.(*point).setScale
   805  func setScale(*point,int)
   806  
   807  func main() {
   808  	v := add(100,200,300)
   809  	if v != 600 {
   810  		panic(fmt.Errorf("add got %v, must 600",v))
   811  	}
   812  	pt := newPoint(100,200)
   813  	if pt == nil || pt.x != 100 || pt.y != 200 {
   814  		panic(fmt.Errorf("newPoint got %v, must &{100 200}",pt))
   815  	}
   816  	pt2 := scalePoint(*pt,2)
   817  	if pt2.x != 200 || pt2.y != 400 {
   818  		panic(fmt.Errorf("scalePoint got %v, must {200 400}",pt2))
   819  	}
   820  	setScale(pt,3)
   821  	if pt.x != 300 || pt.y != 600 {
   822  		panic(fmt.Errorf("setScale got %v, must &{300 600}",pt))
   823  	}
   824  }
   825  `
   826  	type point struct {
   827  		x int
   828  		y int
   829  	}
   830  	ctx := igop.NewContext(0)
   831  	ctx.AddImportFile("pkg", "pkg.go", pkg)
   832  	ctx.RegisterExternal("pkg.New", func(x int, y int) *point {
   833  		return &point{x, y}
   834  	})
   835  	ctx.RegisterExternal("pkg.point.scale", func(pt point, n int) point {
   836  		return point{pt.x * n, pt.y * n}
   837  	})
   838  	ctx.RegisterExternal("pkg.(*point).setScale", func(pt *point, n int) {
   839  		pt.x *= n
   840  		pt.y *= n
   841  	})
   842  	_, err := ctx.RunFile("main.go", src, nil)
   843  	if err != nil {
   844  		t.Fatal(err)
   845  	}
   846  }
   847  
   848  func TestLinknameVar(t *testing.T) {
   849  	pkg := `package pkg
   850  var n int = 100
   851  func N() int {
   852  	return n
   853  }
   854  `
   855  	src := `package main
   856  import (
   857  	_ "unsafe"
   858  	"pkg"
   859  	"fmt"
   860  )
   861  
   862  //go:linkname v pkg.n
   863  var v int
   864  
   865  //go:linkname e pkg.e
   866  var e int
   867  
   868  func main() {
   869  	if v != 100 {
   870  		panic(fmt.Errorf("v got %v, must 100",v))
   871  	}
   872  	v = 200
   873  	if pkg.N() != 200 {
   874  		panic(fmt.Errorf("pkg.N got %v, must 200",pkg.N()))
   875  	}
   876  	if e != 100 {
   877  		panic(fmt.Errorf("3 got %v, must 100",e))
   878  	}
   879  }
   880  `
   881  	ctx := igop.NewContext(0)
   882  	ctx.AddImportFile("pkg", "pkg.go", pkg)
   883  	var e int = 100
   884  	ctx.RegisterExternal("pkg.e", &e)
   885  	_, err := ctx.RunFile("main.go", src, nil)
   886  	if err != nil {
   887  		t.Fatal(err)
   888  	}
   889  }
   890  
   891  func TestLinknamePkg(t *testing.T) {
   892  	src := `package main
   893  import (
   894  	_ "unsafe"
   895  	_ "strings"
   896  	"os"
   897  	"bytes"
   898  )
   899  
   900  //go:linkname stdout os.Stdout
   901  var stdout *os.File
   902  
   903  //go:linkname join strings.Join
   904  func join(elems []string, sep string) string
   905  
   906  //go:linkname writeBuffer bytes.(*Buffer).Write
   907  func writeBuffer(buf *bytes.Buffer, data []byte) (n int, err error)
   908  
   909  func main() {
   910  	if stdout != os.Stdout {
   911  		panic("error stdout")
   912  	}
   913  	if v := join([]string{"hello","world"},","); v != "hello,world" {
   914  		panic("error join "+v)
   915  	}
   916  	var buf bytes.Buffer
   917  	writeBuffer(&buf,[]byte("hello"))
   918  	if v := buf.String(); v != "hello" {
   919  		panic("error write buffer "+v)
   920  	}
   921  }
   922  `
   923  	ctx := igop.NewContext(0)
   924  	_, err := ctx.RunFile("main.go", src, nil)
   925  	if err != nil {
   926  		t.Fatal(err)
   927  	}
   928  }
   929  
   930  func TestLinknameError1(t *testing.T) {
   931  	pkg := `package pkg
   932  func add(v ...int) (sum int) {
   933  	for _, n := range v {
   934  		sum += n
   935  	}
   936  	return
   937  }
   938  `
   939  	src := `package main
   940  import (
   941  	_ "pkg"
   942  )
   943  
   944  //go:linkname add pkg.add
   945  func add(v ...int) int
   946  
   947  func main() {
   948  }
   949  `
   950  	ctx := igop.NewContext(0)
   951  	ctx.AddImportFile("pkg", "pkg.go", pkg)
   952  	_, err := ctx.RunFile("main.go", src, nil)
   953  	if err == nil {
   954  		t.Fatal("must error")
   955  	}
   956  	if err.Error() != `main.go:6:1: //go:linkname only allowed in Go files that import "unsafe"` {
   957  		t.Fatal(err)
   958  	}
   959  }
   960  
   961  func TestLinknameError2(t *testing.T) {
   962  	pkg := `package pkg
   963  func add(v ...int) (sum int) {
   964  	for _, n := range v {
   965  		sum += n
   966  	}
   967  	return
   968  }
   969  `
   970  	src := `package main
   971  import (
   972  	_ "unsafe"
   973  	_ "pkg"
   974  )
   975  
   976  //go:linkname add2 pkg.add
   977  func add(v ...int) int
   978  
   979  func main() {
   980  }
   981  `
   982  	ctx := igop.NewContext(0)
   983  	ctx.AddImportFile("pkg", "pkg.go", pkg)
   984  	_, err := ctx.RunFile("main.go", src, nil)
   985  	if err == nil {
   986  		t.Fatal("must error")
   987  	}
   988  	if err.Error() != `main.go:7:1: //go:linkname must refer to declared function or variable` {
   989  		t.Fatal(err)
   990  	}
   991  }
   992  
   993  func TestLinknameError3(t *testing.T) {
   994  	pkg := `package pkg
   995  var v int = 100
   996  `
   997  	src := `package main
   998  import (
   999  	_ "unsafe"
  1000  	_ "pkg"
  1001  )
  1002  
  1003  //go:linkname a pkg.v
  1004  var a int = 200
  1005  
  1006  func main() {
  1007  }
  1008  `
  1009  	ctx := igop.NewContext(0)
  1010  	ctx.AddImportFile("pkg", "pkg.go", pkg)
  1011  	_, err := ctx.RunFile("main.go", src, nil)
  1012  	if err == nil {
  1013  		t.Fatal("must error")
  1014  	}
  1015  	if err.Error() != `duplicated definition of symbol pkg.v, from main and pkg` {
  1016  		t.Fatal(err)
  1017  	}
  1018  }