Skip to content

Commit

Permalink
Merge pull request #228 from goplus/linkname
Browse files Browse the repository at this point in the history
support go:linkname
  • Loading branch information
visualfc committed Mar 26, 2023
2 parents 54296b1 + 4f1a6d5 commit 557bbeb
Show file tree
Hide file tree
Showing 12 changed files with 1,293 additions and 662 deletions.
3 changes: 2 additions & 1 deletion cmd/igop/gox_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ type positioner interface {
func checker_infer(check *types.Checker, posn positioner, tparams []*types.TypeParam, targs []types.Type, params *types.Tuple, args []*operand) (result []types.Type)

func init() {
igop.RegisterExternal("github.com/goplus/gox.checker_infer", checker_infer)
// support github.com/goplus/gox.checker_infer
igop.RegisterExternal("go/types.(*Checker).infer", checker_infer)
}
35 changes: 22 additions & 13 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"go/token"
"go/types"
"io"
"log"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -108,6 +109,7 @@ type sourcePackage struct {
Info *types.Info
Dir string
Files []*ast.File
Links []*load.LinkSym
}

func (sp *sourcePackage) Load() (err error) {
Expand Down Expand Up @@ -140,6 +142,9 @@ func (sp *sourcePackage) Load() (err error) {
}
}
types.NewChecker(conf, sp.Context.FileSet, sp.Package, sp.Info).Files(sp.Files)
if err == nil {
sp.Links, err = load.ParseLinkname(sp.Context.FileSet, sp.Package.Path(), sp.Files)
}
}
return
}
Expand All @@ -161,7 +166,7 @@ func NewContext(mode Mode) *Context {
ctx.BuilderMode |= ssa.PrintFunctions
}
if mode&ExperimentalSupportGC != 0 {
ctx.SetOverrideFunction("runtime.GC", runtimeGC)
ctx.RegisterExternal("runtime.GC", runtimeGC)
}
ctx.sizes = types.SizesFor("gc", runtime.GOARCH)
ctx.Lookup = new(load.ListDriver).Lookup
Expand Down Expand Up @@ -192,15 +197,19 @@ func (ctx *Context) SetDebug(fn func(*DebugInfo)) {
ctx.debugFunc = fn
}

// SetOverrideFunction register external function to override function.
// match func fullname and signature
func (ctx *Context) SetOverrideFunction(key string, fn interface{}) {
ctx.override[key] = reflect.ValueOf(fn)
}

// ClearOverrideFunction reset override function
func (ctx *Context) ClearOverrideFunction(key string) {
delete(ctx.override, key)
// RegisterExternal register external value must variable address or func.
func (ctx *Context) RegisterExternal(key string, i interface{}) {
if i == nil {
delete(ctx.override, key)
return
}
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Func, reflect.Ptr:
ctx.override[key] = v
default:
log.Printf("register external must variable address or func. not %v\n", v.Kind())
}
}

// SetPrintOutput is captured builtin print/println output
Expand Down Expand Up @@ -379,12 +388,12 @@ func (ctx *Context) loadTestPackage(bp *build.Package, path string, dir string)
if err != nil {
return nil, err
}
f, err := parser.ParseFile(ctx.FileSet, "_testmain.go", data, 0)
f, err := parser.ParseFile(ctx.FileSet, "_testmain.go", data, parser.ParseComments)
if err != nil {
return nil, err
}
return &sourcePackage{
Package: types.NewPackage(path, "main"),
Package: types.NewPackage(path+".test", "main"),
Files: []*ast.File{f},
Dir: dir,
Context: ctx,
Expand All @@ -400,7 +409,7 @@ func (ctx *Context) parseGoFiles(dir string, filenames []string) ([]*ast.File, e
for i, filename := range filenames {
go func(i int, filepath string) {
defer wg.Done()
files[i], errors[i] = parser.ParseFile(ctx.FileSet, filepath, nil, 0)
files[i], errors[i] = parser.ParseFile(ctx.FileSet, filepath, nil, parser.ParseComments)
}(i, filepath.Join(dir, filename))
}
wg.Wait()
Expand Down
49 changes: 43 additions & 6 deletions interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ package igop

import (
"fmt"
"go/ast"
"go/constant"
"go/token"
"go/types"
Expand All @@ -57,6 +58,7 @@ import (
"sync/atomic"
"unsafe"

"github.com/goplus/igop/load"
"github.com/goplus/reflectx"
"github.com/visualfc/goid"
"github.com/visualfc/xtype"
Expand All @@ -82,7 +84,8 @@ type Interp struct {
ctx *Context
mainpkg *ssa.Package // the SSA main package
record *TypesRecord // lookup type and ToType
globals map[ssa.Value]value // addresses of global variables (immutable)
globals map[string]value // addresses of global variables (immutable)
chkinit map[string]bool // init vars
preloadTypes map[types.Type]reflect.Type // preload types.Type -> reflect.Type
funcs map[*ssa.Function]*function // ssa.Function -> *function
msets map[reflect.Type](map[string]*ssa.Function) // user defined type method sets
Expand Down Expand Up @@ -1145,7 +1148,8 @@ func newInterp(ctx *Context, mainpkg *ssa.Package, globals map[string]interface{
i := &Interp{
ctx: ctx,
mainpkg: mainpkg,
globals: make(map[ssa.Value]value),
globals: make(map[string]value),
chkinit: make(map[string]bool),
goroutines: 1,
preloadTypes: make(map[types.Type]reflect.Type),
funcs: make(map[*ssa.Function]*function),
Expand All @@ -1157,6 +1161,7 @@ func newInterp(ctx *Context, mainpkg *ssa.Package, globals map[string]interface{
i.record.Load(mainpkg)

var pkgs []*ssa.Package

for _, pkg := range mainpkg.Prog.AllPackages() {
// skip external pkg
if pkg.Func("init").Blocks == nil {
Expand All @@ -1168,23 +1173,55 @@ func newInterp(ctx *Context, mainpkg *ssa.Package, globals map[string]interface{
switch v := m.(type) {
case *ssa.Global:
typ := i.preToType(deref(v.Type()))
i.globals[v] = reflect.New(typ).Interface()
key := v.String()
if ext, ok := findExternValue(i, key); ok && ext.Kind() == reflect.Ptr && ext.Elem().Type() == typ {
i.globals[key] = ext.Interface()
i.chkinit[key] = true
} else {
i.globals[key] = reflect.New(typ).Interface()
}
}
}
}
// check linkname var
var links []*load.LinkSym
for _, sp := range i.ctx.pkgs {
for _, link := range sp.Links {
if link.Kind == ast.Var {
localName, targetName := link.PkgPath+"."+link.Name, link.Linkname.PkgPath+"."+link.Linkname.Name
if _, ok := i.globals[localName]; ok {
if ext, ok := findExternVar(i, link.Linkname.PkgPath, link.Linkname.Name); ok && ext.Kind() == reflect.Ptr {
i.globals[localName] = ext.Interface()
i.chkinit[targetName] = true
links = append(links, link)
} else if v, ok := i.globals[targetName]; ok {
i.globals[localName] = v
links = append(links, link)
}
}
}
}
}
// check globals for repl
if globals != nil {
for k := range i.globals {
if fv, ok := globals[k.String()]; ok {
if fv, ok := globals[k]; ok {
i.globals[k] = fv
}
}
}

// static types check
err := checkPackages(i, pkgs)
if err != nil {
return i, err
}
// check linkname duplicated definition
for _, link := range links {
localName, targetName := link.PkgPath+"."+link.Name, link.Linkname.PkgPath+"."+link.Linkname.Name
if i.chkinit[localName] && i.chkinit[targetName] {
return i, fmt.Errorf("duplicated definition of symbol %v, from %v and %v", targetName, link.PkgPath, link.Linkname.PkgPath)
}
}
return i, err
}

Expand Down Expand Up @@ -1306,7 +1343,7 @@ func (i *Interp) GetVarAddr(key string) (interface{}, bool) {
if !ok {
return nil, false
}
p, ok := i.globals[v]
p, ok := i.globals[v.String()]
return p, ok
}

Expand Down

0 comments on commit 557bbeb

Please sign in to comment.