From fe18c35dab9cef89dc50ffe59caa7ff20489f63e Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 28 Jun 2024 15:14:30 +0800 Subject: [PATCH] patch: Clone/Merge --- _demo/iodemo/io.go | 14 +++++++ cl/builtin_test.go | 2 +- cl/compile.go | 46 ++++++++++++++++++----- cl/import.go | 4 +- internal/build/build.go | 7 ++-- internal/typepatch/patch.go | 75 ++++++++++--------------------------- 6 files changed, 78 insertions(+), 70 deletions(-) create mode 100644 _demo/iodemo/io.go diff --git a/_demo/iodemo/io.go b/_demo/iodemo/io.go new file mode 100644 index 00000000..a9d7492e --- /dev/null +++ b/_demo/iodemo/io.go @@ -0,0 +1,14 @@ +package main + +import ( + "io" + "os" +) + +func f(w io.Writer) { + w.Write([]byte("Hello, world\n")) +} + +func main() { + f(os.Stdout) +} diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 75604b3a..ad51a3e6 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -227,7 +227,7 @@ func TestErrImport(t *testing.T) { alt.Scope().Insert( types.NewConst(0, alt, "LLGoPackage", types.Typ[types.String], constant.MakeString("noinit")), ) - ctx.patches = Patches{"foo": &ssa.Package{Pkg: alt}} + ctx.patches = Patches{"foo": Patch{Alt: &ssa.Package{Pkg: alt}, Types: alt}} ctx.importPkg(pkg, &pkgInfo{}) } diff --git a/cl/compile.go b/cl/compile.go index 4517303e..b2407bd8 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -77,7 +77,7 @@ type pkgInfo struct { kind int } -type none struct{} +type none = struct{} type context struct { prog llssa.Program @@ -539,9 +539,10 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue } } } - t := p.prog.Type(v.Type(), llssa.InGo) + prog := p.prog + t := prog.Type(v.Type(), llssa.InGo) x := p.compileValue(b, v.X) - ret = b.MakeInterface(t, x) + ret = b.MakeInterface(t, patchValue(p, x)) case *ssa.MakeSlice: var nCap llssa.Expr t := p.prog.Type(v.Type(), llssa.InGo) @@ -737,8 +738,14 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) // ----------------------------------------------------------------------------- +// Patch is a patch of some package. +type Patch struct { + Alt *ssa.Package + Types *types.Package +} + // Patches is patches of some packages. -type Patches = map[string]*ssa.Package +type Patches = map[string]Patch // NewPackage compiles a Go package to LLVM IR package. func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { @@ -749,12 +756,13 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { pkgProg := pkg.Prog pkgTypes := pkg.Pkg + oldTypes := pkgTypes pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes) - alt, hasPatch := patches[pkgPath] + patch, hasPatch := patches[pkgPath] if hasPatch { - pkgTypes = typepatch.Pkg(pkgTypes, alt.Pkg) + pkgTypes = patch.Types pkg.Pkg = pkgTypes - alt.Pkg = pkgTypes + patch.Alt.Pkg = pkgTypes } if pkgPath == llssa.PkgRuntime { prog.SetRuntime(pkgTypes) @@ -781,12 +789,13 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [ if hasPatch { skips := ctx.skips + typepatch.Merge(pkgTypes, oldTypes, skips, ctx.skipall) ctx.skips = nil ctx.state = pkgInPatch if _, ok := skips["init"]; ok || ctx.skipall { ctx.state |= pkgFNoOldInit } - processPkg(ctx, ret, alt) + processPkg(ctx, ret, patch.Alt) ctx.state = pkgHasPatch ctx.skips = skips } @@ -847,10 +856,29 @@ func globalType(gbl *ssa.Global) types.Type { if t, ok := t.(*types.Named); ok { o := t.Obj() if pkg := o.Pkg(); typepatch.IsPatched(pkg) { - return gbl.Pkg.Pkg.Scope().Lookup(o.Name()).Type() + if patch := gbl.Pkg.Pkg.Scope().Lookup(o.Name()); patch != nil { + return patch.Type() + } } } return t } +func patchValue(ctx *context, v llssa.Expr) llssa.Expr { + /* TODO(xsw): + t := v.RawType() + if t, ok := t.(*types.Named); ok { + o := t.Obj() + if pkg := o.Pkg(); typepatch.IsPatched(pkg) { + if patch, ok := ctx.patches[pkg.Path()]; ok { + if obj := patch.Types.Scope().Lookup(o.Name()); obj != nil { + v.Type = ctx.prog.Type(obj.Type(), llssa.InGo) + } + } + } + } + */ + return v +} + // ----------------------------------------------------------------------------- diff --git a/cl/import.go b/cl/import.go index e1d3e77c..938d74bf 100644 --- a/cl/import.go +++ b/cl/import.go @@ -132,8 +132,8 @@ func (p *context) importPkg(pkg *types.Package, i *pkgInfo) { scope := pkg.Scope() kind, _ := pkgKindByScope(scope) if kind == PkgNormal { - if alt, ok := p.patches[pkgPath]; ok { - pkg = alt.Pkg + if patch, ok := p.patches[pkgPath]; ok { + pkg = patch.Alt.Pkg scope = pkg.Scope() if kind, _ = pkgKindByScope(scope); kind != PkgNormal { goto start diff --git a/internal/build/build.go b/internal/build/build.go index a47174e5..604ea0bd 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -36,6 +36,7 @@ import ( "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/packages" + "github.com/goplus/llgo/internal/typepatch" "github.com/goplus/llgo/ssa/abi" "github.com/goplus/llgo/xtool/clang" "github.com/goplus/llgo/xtool/env" @@ -449,14 +450,14 @@ func altPkgs(initial []*packages.Package, alts ...string) []string { func altSSAPkgs(prog *ssa.Program, patches cl.Patches, alts []*packages.Package, verbose bool) { packages.Visit(alts, nil, func(p *packages.Package) { - if p.Types != nil && !p.IllTyped { + if typs := p.Types; typs != nil && !p.IllTyped { if debugBuild || verbose { log.Println("==> BuildSSA", p.PkgPath) } - pkgSSA := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) + pkgSSA := prog.CreatePackage(typs, p.Syntax, p.TypesInfo, true) if strings.HasPrefix(p.PkgPath, altPkgPathPrefix) { path := p.PkgPath[len(altPkgPathPrefix):] - patches[path] = pkgSSA + patches[path] = cl.Patch{Alt: pkgSSA, Types: typepatch.Clone(typs)} if debugBuild || verbose { log.Println("==> Patching", path) } diff --git a/internal/typepatch/patch.go b/internal/typepatch/patch.go index e6f42e9a..9a94f8f3 100644 --- a/internal/typepatch/patch.go +++ b/internal/typepatch/patch.go @@ -43,20 +43,6 @@ type typesScope struct { isFunc bool } -/* -type object struct { - parent *types.Scope - pos token.Pos - pkg *types.Package // TODO(xsw): ensure offset of pkg - unused [8]byte -} - -type iface struct { - tab unsafe.Pointer - data unsafe.Pointer -} -*/ - const ( tagPatched = 0x17 ) @@ -79,25 +65,6 @@ func setScope(pkg *types.Package, scope *types.Scope) { p.scope = scope } -/* -func setPath(pkg *types.Package, path string) { - p := (*typesPackage)(unsafe.Pointer(pkg)) - p.path = path -} - -/* -func setPkg(o types.Object, pkg *types.Package) { - data := (*iface)(unsafe.Pointer(&o)).data - (*object)(data).pkg = pkg -} - -func setPkgAndParent(o types.Object, pkg *types.Package, parent *types.Scope) { - data := (*iface)(unsafe.Pointer(&o)).data - (*object)(data).pkg = pkg - (*object)(data).parent = parent -} -*/ - func getElems(scope *types.Scope) map[string]types.Object { s := (*typesScope)(unsafe.Pointer(scope)) return s.elems @@ -108,35 +75,33 @@ func setElems(scope *types.Scope, elems map[string]types.Object) { s.elems = elems } -func Pkg(pkg, alt *types.Package) *types.Package { - ret := *pkg - scope := *pkg.Scope() +func Clone(alt *types.Package) *types.Package { + ret := *alt + return &ret +} +func Merge(alt, pkg *types.Package, skips map[string]struct{}, skipall bool) { + setPatched(pkg) + if skipall { + return + } + + scope := *alt.Scope() old := getElems(&scope) elems := make(map[string]types.Object, len(old)) for name, o := range old { elems[name] = o } + setElems(&scope, elems) + setScope(alt, &scope) - altScope := alt.Scope() - for name, o := range getElems(altScope) { - /* - switch o := o.(type) { - case *types.TypeName: - if t, ok := o.Type().(*types.Named); ok { - for i, n := 0, t.NumMethods(); i < n; i++ { - m := t.Method(i) - setPkg(m, &ret) - } - } - } - setPkgAndParent(o, &ret, &scope) - */ + for name, o := range getElems(pkg.Scope()) { + if _, ok := elems[name]; ok { + continue + } + if _, ok := skips[name]; ok { + continue + } elems[name] = o } - setElems(&scope, elems) - setScope(&ret, &scope) - setPatched(pkg) - // setPath(alt, ret.Path()) - return &ret }