diff --git a/cl/compile_test.go b/cl/compile_test.go index 8c4f9706..ad15268c 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -19,7 +19,6 @@ package cl_test import ( "os" "path/filepath" - "runtime" "testing" "github.com/goplus/llgo/cl" @@ -71,13 +70,11 @@ func TestPython(t *testing.T) { cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll") } -func TestGoLibMath(t *testing.T) { - if runtime.GOOS == "darwin" { // TODO(xsw): support linux/windows - root, _ := filepath.Abs("..") - os.Setenv("LLGOROOT", root) - conf := build.NewDefaultConf(build.ModeInstall) - build.Do([]string{"math"}, conf) - } +func TestGoPkgMath(t *testing.T) { + root, _ := filepath.Abs("..") + os.Setenv("LLGOROOT", root) + conf := build.NewDefaultConf(build.ModeInstall) + build.Do([]string{"math"}, conf) } func TestVar(t *testing.T) { diff --git a/internal/packages/load.go b/internal/packages/load.go index 92ba808a..8f8640eb 100644 --- a/internal/packages/load.go +++ b/internal/packages/load.go @@ -99,13 +99,33 @@ type loader struct { requestedMode LoadMode } -type Deduper struct { +type cachedPackage struct { + Types *types.Package + TypesInfo *types.Info + Syntax []*ast.File } -func NewDeduper() *Deduper { +type aDeduper struct { + cache sync.Map +} + +type Deduper = *aDeduper + +func NewDeduper() Deduper { + return &aDeduper{} +} + +func (p Deduper) check(pkgPath string) *cachedPackage { + if v, ok := p.cache.Load(pkgPath); ok { + return v.(*cachedPackage) + } return nil } +func (p Deduper) set(pkgPath string, cp *cachedPackage) { + p.cache.Store(pkgPath, cp) +} + //go:linkname defaultDriver golang.org/x/tools/go/packages.defaultDriver func defaultDriver(cfg *Config, patterns ...string) (*packages.DriverResponse, bool, error) @@ -130,7 +150,7 @@ type importerFunc func(path string) (*types.Package, error) func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } -func loadPackageEx(dedup *Deduper, ld *loader, lpkg *loaderPackage) { +func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) { if lpkg.PkgPath == "unsafe" { // Fill in the blanks to avoid surprises. lpkg.Types = types.Unsafe @@ -141,6 +161,26 @@ func loadPackageEx(dedup *Deduper, ld *loader, lpkg *loaderPackage) { return } + if dedup != nil { + if cp := dedup.check(lpkg.PkgPath); cp != nil { + lpkg.Types = cp.Types + lpkg.Fset = ld.Fset + lpkg.TypesInfo = cp.TypesInfo + lpkg.Syntax = cp.Syntax + lpkg.TypesSizes = ld.sizes + return + } + defer func() { + if !lpkg.IllTyped && lpkg.needtypes && lpkg.needsrc { + dedup.set(lpkg.PkgPath, &cachedPackage{ + Types: lpkg.Types, + TypesInfo: lpkg.TypesInfo, + Syntax: lpkg.Syntax, + }) + } + }() + } + // Call NewPackage directly with explicit name. // This avoids skew between golist and go/types when the files' // package declarations are inconsistent. @@ -404,7 +444,7 @@ func loadPackageEx(dedup *Deduper, ld *loader, lpkg *loaderPackage) { lpkg.IllTyped = illTyped } -func loadRecursiveEx(dedup *Deduper, ld *loader, lpkg *loaderPackage) { +func loadRecursiveEx(dedup Deduper, ld *loader, lpkg *loaderPackage) { lpkg.loadOnce.Do(func() { // Load the direct dependencies, in parallel. var wg sync.WaitGroup @@ -421,7 +461,7 @@ func loadRecursiveEx(dedup *Deduper, ld *loader, lpkg *loaderPackage) { }) } -func refineEx(dedup *Deduper, ld *loader, response *packages.DriverResponse) ([]*Package, error) { +func refineEx(dedup Deduper, ld *loader, response *packages.DriverResponse) ([]*Package, error) { roots := response.Roots rootMap := make(map[string]int, len(roots)) for i, root := range roots { @@ -641,7 +681,7 @@ func refineEx(dedup *Deduper, ld *loader, response *packages.DriverResponse) ([] // return an error. Clients may need to handle such errors before // proceeding with further analysis. The PrintErrors function is // provided for convenient display of all errors. -func LoadEx(dedup *Deduper, sizes func(types.Sizes) types.Sizes, cfg *Config, patterns ...string) ([]*Package, error) { +func LoadEx(dedup Deduper, sizes func(types.Sizes) types.Sizes, cfg *Config, patterns ...string) ([]*Package, error) { ld := newLoader(cfg) response, external, err := defaultDriver(&ld.Config, patterns...) if err != nil {