🌐 AI搜索 & 代理 主页
Skip to content

Commit 51bb17e

Browse files
Changing to only caching decls
1 parent 2c925f5 commit 51bb17e

File tree

9 files changed

+114
-135
lines changed

9 files changed

+114
-135
lines changed

build/build.go

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,10 @@ type Session struct {
764764
// The files in these sources haven't been sorted nor simplified yet.
765765
sources map[string]*sources.Sources
766766

767+
// cachedDecls is a map of cached declarations.
768+
// This is keyed using resolved import paths.
769+
cachedDecls map[string]*compiler.DeclCache
770+
767771
// Binary archives produced during the current session and assumed to be
768772
// up to date with input sources and dependencies. In the -w ("watch") mode
769773
// must be cleared upon entering watching.
@@ -779,6 +783,7 @@ func NewSession(options *Options) (*Session, error) {
779783
options: options,
780784
importPaths: make(map[string]map[string]string),
781785
sources: make(map[string]*sources.Sources),
786+
cachedDecls: make(map[string]*compiler.DeclCache),
782787
UpToDateArchives: make(map[string]*compiler.Archive),
783788
}
784789
s.xctx = NewBuildContext(s.InstallSuffix(), s.options.BuildTags)
@@ -1055,7 +1060,7 @@ var getExeModTime = func() func() time.Time {
10551060
// to the session's sources map.
10561061
func (s *Session) LoadPackages(pkg *PackageData) (*sources.Sources, error) {
10571062
if srcs, ok := s.sources[pkg.ImportPath]; ok {
1058-
return srcs, nil
1063+
return srcs, nil // already loaded
10591064
}
10601065

10611066
if exeModTime := getExeModTime(); exeModTime.After(pkg.SrcModTime) {
@@ -1080,46 +1085,39 @@ func (s *Session) LoadPackages(pkg *PackageData) (*sources.Sources, error) {
10801085
pkg.SrcModTime = fileModTime
10811086
}
10821087

1083-
// Try to load the package from the build cache.
1084-
var srcs *sources.Sources
1085-
if s.buildCache != nil {
1086-
cachedSrcs := &sources.Sources{
1087-
DeclCache: compiler.NewDeclCache(true),
1088-
}
1089-
if s.buildCache.Load(cachedSrcs, pkg.ImportPath, pkg.SrcModTime) {
1090-
srcs = cachedSrcs
1091-
}
1092-
}
1093-
10941088
// If the package was not found in the cache, build the package
10951089
// by parsing and augmenting the original files with overlay files.
1096-
if srcs == nil {
1097-
fileSet := token.NewFileSet()
1098-
files, overlayJsFiles, err := parseAndAugment(s.xctx, pkg, pkg.IsTest, fileSet)
1099-
if err != nil {
1100-
return nil, err
1101-
}
1102-
embed, err := embedFiles(pkg, fileSet, files)
1103-
if err != nil {
1104-
return nil, err
1105-
}
1106-
if embed != nil {
1107-
files = append(files, embed)
1108-
}
1090+
fileSet := token.NewFileSet()
1091+
files, overlayJsFiles, err := parseAndAugment(s.xctx, pkg, pkg.IsTest, fileSet)
1092+
if err != nil {
1093+
return nil, err
1094+
}
1095+
embed, err := embedFiles(pkg, fileSet, files)
1096+
if err != nil {
1097+
return nil, err
1098+
}
1099+
if embed != nil {
1100+
files = append(files, embed)
1101+
}
11091102

1110-
srcs = &sources.Sources{
1111-
ImportPath: pkg.ImportPath,
1112-
Dir: pkg.Dir,
1113-
Files: files,
1114-
FileSet: fileSet,
1115-
JSFiles: append(pkg.JSFiles, overlayJsFiles...),
1116-
DeclCache: compiler.NewDeclCache(s.buildCache != nil),
1117-
}
1103+
srcs := &sources.Sources{
1104+
ImportPath: pkg.ImportPath,
1105+
Dir: pkg.Dir,
1106+
Files: files,
1107+
FileSet: fileSet,
1108+
JSFiles: append(pkg.JSFiles, overlayJsFiles...),
11181109
}
11191110

11201111
// Add the sources to the session's sources map.
11211112
s.sources[pkg.ImportPath] = srcs
11221113

1114+
// Try to load the cached decls from the build cache.
1115+
if s.buildCache != nil {
1116+
declCache := &compiler.DeclCache{}
1117+
s.buildCache.Load(declCache, pkg.ImportPath, pkg.SrcModTime)
1118+
s.cachedDecls[pkg.ImportPath] = declCache
1119+
}
1120+
11231121
// Import dependencies from the augmented files,
11241122
// whilst skipping any that have been already imported.
11251123
for _, importedPkgPath := range srcs.UnresolvedImports(pkg.Imports...) {
@@ -1167,7 +1165,8 @@ func (s *Session) CompilePackage(srcs *sources.Sources, tContext *types.Context)
11671165
return archive, nil
11681166
}
11691167

1170-
archive, err := compiler.Compile(srcs, tContext, s.options.Minify)
1168+
declCache := s.cachedDecls[srcs.ImportPath]
1169+
archive, err := compiler.Compile(srcs, declCache, tContext, s.options.Minify)
11711170
if err != nil {
11721171
return nil, err
11731172
}
@@ -1179,8 +1178,11 @@ func (s *Session) CompilePackage(srcs *sources.Sources, tContext *types.Context)
11791178
// Store the built package sources in the cache for future use.
11801179
// The sources should contain all cachable declarations at this point.
11811180
// Skip storing cache if the sources haven't changed since read from cache.
1182-
if s.buildCache != nil && srcs.Changed() {
1183-
s.buildCache.Store(srcs, srcs.ImportPath, time.Now())
1181+
if s.buildCache != nil {
1182+
dc := s.cachedDecls[srcs.ImportPath]
1183+
if dc != nil && dc.Changed() {
1184+
s.buildCache.Store(dc, srcs.ImportPath, time.Now())
1185+
}
11841186
}
11851187

11861188
s.UpToDateArchives[srcs.ImportPath] = archive

build/cache/cache.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ var _ Cache = (*BuildCache)(nil)
9191
// the cache. For example, any artifacts that were cached for a Linux build
9292
// must not be reused for a non-Linux build. GopherJS version change also
9393
// invalidates the cache. It is callers responsibility to ensure that artifacts
94-
// passed the Store function were generated with the same build
94+
// passed to the Store function were generated with the same build
9595
// parameters as the cache is configured.
9696
//
9797
// There is no upper limit for the total cache size. It can be cleared
@@ -117,9 +117,7 @@ type BuildCache struct {
117117
// TestedPackage is the import path of the package being tested, or
118118
// empty when not building for tests. The package under test is built
119119
// with *_test.go sources included so we should always skip reading
120-
// and writing cache in that case. Since we are caching prior to
121-
// type-checking for generics, any package importing the package under
122-
// test should be unaffected.
120+
// and writing cache in that case.
123121
TestedPackage string
124122
}
125123

compiler/compiler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ func compileProject(t *testing.T, root *packages.Package, minify bool) map[strin
11801180

11811181
archives := map[string]*Archive{}
11821182
for _, srcs := range allSrcs {
1183-
a, err := Compile(srcs, tContext, minify)
1183+
a, err := Compile(srcs, nil, tContext, minify)
11841184
if err != nil {
11851185
t.Fatal(`failed to compile:`, err)
11861186
}

compiler/declCache.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,57 @@
11
package compiler
22

33
import (
4-
"encoding/gob"
54
"fmt"
65
"sort"
76
)
87

98
type DeclCache struct {
10-
enabled bool
119
decls map[string]*Decl
1210
changed bool
1311
}
1412

15-
func init() {
16-
// Register any types that are referenced by an interface so that
17-
// the gob encoder/decoder can handle them.
18-
gob.Register(&DeclCache{})
19-
}
20-
21-
func NewDeclCache(enabled bool) *DeclCache {
22-
return &DeclCache{enabled: enabled}
13+
// Chacnged reports whether the cache has had declarations added to it since
14+
// it was created or last read from storage or created empty.
15+
//
16+
// If there have been no changes, the cache does not need to be written back
17+
// to storage. Typically declarations will only be added when the cache is
18+
// empty and not loaded from storage since otherwise all the needed declarations
19+
// (other than those not being cached) would already be present.
20+
func (dc *DeclCache) Changed() bool {
21+
return dc != nil && dc.changed
2322
}
2423

2524
func (dc *DeclCache) GetDecl(fullname string) *Decl {
26-
if dc == nil || !dc.enabled {
25+
if dc == nil {
2726
return nil // cache is disabled
2827
}
2928
return dc.decls[fullname]
3029
}
3130

3231
func (dc *DeclCache) PutDecl(decl *Decl) {
33-
if dc == nil || !dc.enabled {
32+
if dc == nil {
3433
return // cache is disabled
3534
}
3635

36+
if decl.ForGeneric {
37+
// Do not cache declarations for generic instantiations.
38+
// The type arguments may come from a package depending on this one
39+
// and not on one of this package's dependencies.
40+
//
41+
// If one of this package's dependencies changes, the cache will not be used.
42+
// However, currently, changes to packages depending on this one
43+
// may change and this package's cache may still be used.
44+
// Therefore, if the package depending on this one changes a type from
45+
// being blocking to non-blocking or vice versa, the cached declaration
46+
// may be invalid.
47+
return
48+
}
49+
50+
if isUnqueDeclFullName(decl.FullName) {
51+
// Only cache declarations with unique names.
52+
return
53+
}
54+
3755
if dc.decls == nil {
3856
dc.decls = map[string]*Decl{}
3957
}
@@ -47,12 +65,8 @@ func (dc *DeclCache) PutDecl(decl *Decl) {
4765
dc.changed = true
4866
}
4967

50-
func (dc *DeclCache) Changed() bool {
51-
return dc != nil && dc.changed
52-
}
53-
5468
func (dc *DeclCache) Read(decode func(any) error) error {
55-
if dc == nil || !dc.enabled {
69+
if dc == nil {
5670
return nil // cache is disabled
5771
}
5872

@@ -75,7 +89,7 @@ func (dc *DeclCache) Read(decode func(any) error) error {
7589
}
7690

7791
func (dc *DeclCache) Write(encode func(any) error) error {
78-
if dc == nil || !dc.enabled {
92+
if dc == nil {
7993
return nil // cache is disabled
8094
}
8195

compiler/declNames.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@ import (
55
"go/token"
66
"go/types"
77
"path"
8+
"strings"
89

910
"github.com/gopherjs/gopherjs/compiler/internal/symbol"
1011
"github.com/gopherjs/gopherjs/compiler/internal/typeparams"
1112
)
1213

14+
const (
15+
varDeclNotUniqueFullName = `var:blank`
16+
funcVarDeclNotUniqueFullName = `funcVar:init`
17+
mainFuncDeclNotUniqueFullName = `init:main`
18+
funcDeclNotUniqueFullName = `func:init`
19+
typeDeclNestedPrefix = `type:nested:`
20+
)
21+
1322
// importDeclFullName returns a unique name for an import declaration.
1423
// This import name may be duplicated in different packages if they both
1524
// import the same package, they are only unique per package.
@@ -22,7 +31,7 @@ func importDeclFullName(importedPkg *types.Package) string {
2231
//
2332
// If no variables are named, this will attempt to create a unique name
2433
// using the integer value of the first valid position of the blank variables.
25-
// Otherwise the name is `var:blank` and is not unique.
34+
// Otherwise the name is not unique (i.e. varDeclNotUniqueFullName).
2635
func varDeclFullName(init *types.Initializer, fSet *token.FileSet) string {
2736
for _, lhs := range init.Lhs {
2837
if lhs.Name() != `_` {
@@ -36,7 +45,7 @@ func varDeclFullName(init *types.Initializer, fSet *token.FileSet) string {
3645
}
3746
}
3847

39-
return `var:blank`
48+
return varDeclNotUniqueFullName
4049
}
4150

4251
// funcVarDeclFullName returns a name for a package-level variable
@@ -47,30 +56,36 @@ func varDeclFullName(init *types.Initializer, fSet *token.FileSet) string {
4756
// The name is unique unless the function is an `init` function.
4857
// If the name is for an `init` function, the position of the function
4958
// is used to create a unique name if it is valid,
50-
// otherwise the name is not unique.
59+
// otherwise the name is not unique (i.e. funcVarDeclNotUniqueFullName).
5160
func funcVarDeclFullName(o *types.Func, fSet *token.FileSet) string {
5261
name := `funcVar:` + symbol.New(o).String()
5362
if o.Name() == `init` {
5463
name += declFullNameDiscriminator(o.Pos(), fSet)
5564
}
65+
// In the case of an `init` function with an invalid position,
66+
// the name is not unique and will be equal to funcVarDeclNotUnqueName.
5667
return name
5768
}
5869

5970
// mainFuncDeclFullName returns the name for the declaration used to invoke the
6071
// main function of the program. There should only be one decl with this name.
72+
// This will always return mainFuncDeclNotUniqueFullName.
6173
func mainFuncDeclFullName() string {
62-
return `init:main`
74+
return mainFuncDeclNotUniqueFullName
6375
}
6476

6577
// funcDeclFullName returns a name for a package-level function
6678
// declaration for the given instance of a function.
6779
// The name is unique unless the function is an `init` function
6880
// then it tries to use the position of the function to create a unique name.
81+
// Otherwise the name is not unique (i.e. funcDeclNotUniqueFullName).
6982
func funcDeclFullName(inst typeparams.Instance, fSet *token.FileSet) string {
7083
name := `func:` + inst.String()
7184
if inst.IsTrivial() && inst.Object.Name() == `init` {
7285
name += declFullNameDiscriminator(inst.Object.Pos(), fSet)
7386
}
87+
// In the case of an `init` function with an invalid position,
88+
// the name is not unique and will be equal to funcDeclNotUniqueFullName.
7489
return name
7590
}
7691

@@ -87,12 +102,14 @@ func typeVarDeclFullName(o *types.TypeName) string {
87102
// unless the type is a nested type then the name is only unique per the
88103
// function or method it is declared in. In that case, the position of the
89104
// declaration is used to try to create a unique name.
105+
// If the position is invalid, the nested name may be unique or not,
106+
// we cannot guarantee uniqueness in that case.
90107
func typeDeclFullName(inst typeparams.Instance, fSet *token.FileSet) string {
91-
name := `type:` + inst.String()
92108
if typeparams.FindNestingFunc(inst.Object) != nil {
93-
name += declFullNameDiscriminator(inst.Object.Pos(), fSet)
109+
return typeDeclNestedPrefix + inst.String() +
110+
declFullNameDiscriminator(inst.Object.Pos(), fSet)
94111
}
95-
return name
112+
return `type:` + inst.String()
96113
}
97114

98115
// anonTypeDeclFullName returns a unique name for a package-level type
@@ -114,3 +131,16 @@ func declFullNameDiscriminator(pos token.Pos, fSet *token.FileSet) string {
114131
p := fSet.Position(pos)
115132
return fmt.Sprintf("@%s:%d:%d", path.Base(p.Filename), p.Line, p.Column)
116133
}
134+
135+
// isUnqueDeclFullName reports whether the given declaration full name is unique.
136+
// A unique declaration name can be safely cached and reused.
137+
func isUnqueDeclFullName(name string) bool {
138+
switch name {
139+
case ``, varDeclNotUniqueFullName, funcVarDeclNotUniqueFullName,
140+
mainFuncDeclNotUniqueFullName, funcDeclNotUniqueFullName:
141+
return false // not unique since it equals one of the known non-unique names
142+
}
143+
144+
// Check if the name is for a nested type declaration without a position discriminator.
145+
return !strings.HasPrefix(name, typeDeclNestedPrefix) || strings.Contains(name, "@")
146+
}

compiler/package.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ type funcContext struct {
118118
funcLitCounter int
119119
}
120120

121-
func newRootCtx(tContext *types.Context, srcs *sources.Sources, minify bool) *funcContext {
122-
declCache, _ := srcs.DeclCache.(*DeclCache)
121+
func newRootCtx(tContext *types.Context, srcs *sources.Sources, declCache *DeclCache, minify bool) *funcContext {
123122
funcCtx := &funcContext{
124123
FuncInfo: srcs.TypeInfo.InitFuncInfo,
125124
pkgCtx: &pkgContext{
@@ -158,7 +157,7 @@ type flowData struct {
158157
//
159158
// Provided sources must be prepared so that the type information has been determined,
160159
// and the source files have been sorted by name to ensure reproducible JavaScript output.
161-
func Compile(srcs *sources.Sources, tContext *types.Context, minify bool) (_ *Archive, err error) {
160+
func Compile(srcs *sources.Sources, declCache *DeclCache, tContext *types.Context, minify bool) (_ *Archive, err error) {
162161
defer func() {
163162
e := recover()
164163
if e == nil {
@@ -174,7 +173,7 @@ func Compile(srcs *sources.Sources, tContext *types.Context, minify bool) (_ *Ar
174173
err = bailout(fmt.Errorf("unexpected compiler panic while building package %q: %v", srcs.ImportPath, e))
175174
}()
176175

177-
rootCtx := newRootCtx(tContext, srcs, minify)
176+
rootCtx := newRootCtx(tContext, srcs, declCache, minify)
178177

179178
importedPaths, importDecls := rootCtx.importDecls()
180179

0 commit comments

Comments
 (0)