Skip to content

Commit 58c2277

Browse files
adding changed indicator and encoder/decoder
1 parent 321fa3d commit 58c2277

File tree

6 files changed

+117
-33
lines changed

6 files changed

+117
-33
lines changed

build/build.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ func (s *Session) LoadPackages(pkg *PackageData) (*sources.Sources, error) {
10841084
var srcs *sources.Sources
10851085
if s.buildCache != nil {
10861086
cachedSrcs := &sources.Sources{
1087-
CacheData: compiler.NewDeclCache(true),
1087+
DeclCache: compiler.NewDeclCache(true),
10881088
}
10891089
if s.buildCache.Load(cachedSrcs, pkg.ImportPath, pkg.SrcModTime) {
10901090
srcs = cachedSrcs
@@ -1113,7 +1113,7 @@ func (s *Session) LoadPackages(pkg *PackageData) (*sources.Sources, error) {
11131113
Files: files,
11141114
FileSet: fileSet,
11151115
JSFiles: append(pkg.JSFiles, overlayJsFiles...),
1116-
CacheData: compiler.NewDeclCache(s.buildCache != nil),
1116+
DeclCache: compiler.NewDeclCache(s.buildCache != nil),
11171117
}
11181118
}
11191119

@@ -1178,7 +1178,8 @@ func (s *Session) CompilePackage(srcs *sources.Sources, tContext *types.Context)
11781178

11791179
// Store the built package sources in the cache for future use.
11801180
// The sources should contain all cachable declarations at this point.
1181-
if s.buildCache != nil {
1181+
// Skip storing cache if the sources haven't changed since read from cache.
1182+
if s.buildCache != nil && srcs.Changed() {
11821183
s.buildCache.Store(srcs, srcs.ImportPath, time.Now())
11831184
}
11841185

compiler/declCache.go

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,100 @@ package compiler
33
import (
44
"encoding/gob"
55
"fmt"
6+
"sort"
67
)
78

89
type DeclCache struct {
910
enabled bool
1011
decls map[string]*Decl
12+
changed bool
1113
}
1214

1315
func init() {
16+
// Register any types that are referenced by an interface so that
17+
// the gob encoder/decoder can handle them.
1418
gob.Register(&DeclCache{})
1519
}
1620

17-
func NewDeclCache(enable bool) *DeclCache {
18-
return &DeclCache{
19-
enabled: enable,
20-
decls: map[string]*Decl{},
21-
}
21+
func NewDeclCache(enabled bool) *DeclCache {
22+
return &DeclCache{enabled: enabled}
2223
}
2324

2425
func (dc *DeclCache) GetDecl(fullname string) *Decl {
26+
if dc == nil || !dc.enabled {
27+
return nil // cache is disabled
28+
}
2529
return dc.decls[fullname]
2630
}
2731

2832
func (dc *DeclCache) PutDecl(decl *Decl) {
29-
if !dc.enabled {
30-
// If not enabled, do nothing since the cache is not being stored.
31-
return
33+
if dc == nil || !dc.enabled {
34+
return // cache is disabled
3235
}
3336

37+
if dc.decls == nil {
38+
dc.decls = map[string]*Decl{}
39+
}
3440
if existing, ok := dc.decls[decl.FullName]; ok {
3541
if existing != decl {
3642
panic(fmt.Errorf(`decl cache conflict: different decls with same name: %q`, decl.FullName))
3743
}
3844
return
3945
}
4046
dc.decls[decl.FullName] = decl
47+
dc.changed = true
48+
}
49+
50+
func (dc *DeclCache) Changed() bool {
51+
return dc != nil && dc.changed
4152
}
4253

4354
func (dc *DeclCache) Read(decode func(any) error) error {
44-
// TODO: Implement decl cache serialization.
55+
if dc == nil || !dc.enabled {
56+
return nil // cache is disabled
57+
}
58+
59+
var count int
60+
if err := decode(&count); err != nil {
61+
return err
62+
}
63+
64+
if dc.decls == nil {
65+
dc.decls = map[string]*Decl{}
66+
}
67+
for i := 0; i < count; i++ {
68+
decl := &Decl{}
69+
if err := decode(decl); err != nil {
70+
return err
71+
}
72+
fmt.Printf("Read decl from cache: %s\n", decl.FullName) // TODO(grantnelson-wf): REMOVE
73+
dc.decls[decl.FullName] = decl
74+
}
75+
4576
return nil
4677
}
4778

4879
func (dc *DeclCache) Write(encode func(any) error) error {
49-
// TODO: Implement decl cache serialization.
80+
if dc == nil || !dc.enabled {
81+
return nil // cache is disabled
82+
}
83+
84+
count := len(dc.decls)
85+
if err := encode(count); err != nil {
86+
return err
87+
}
88+
89+
names := make([]string, 0, count)
90+
for name := range dc.decls {
91+
names = append(names, name)
92+
}
93+
sort.Strings(names)
94+
95+
for _, name := range names {
96+
fmt.Printf("Wrote decl to cache: %s\n", name) // TODO(grantnelson-wf): REMOVE
97+
if err := encode(dc.decls[name]); err != nil {
98+
return err
99+
}
100+
}
50101
return nil
51102
}

compiler/package.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,7 @@ type funcContext struct {
119119
}
120120

121121
func newRootCtx(tContext *types.Context, srcs *sources.Sources, minify bool) *funcContext {
122-
declCache, ok := srcs.CacheData.(*DeclCache)
123-
if !ok {
124-
declCache = NewDeclCache(false)
125-
}
126-
122+
declCache, _ := srcs.DeclCache.(*DeclCache)
127123
funcCtx := &funcContext{
128124
FuncInfo: srcs.TypeInfo.InitFuncInfo,
129125
pkgCtx: &pkgContext{

compiler/sources/serializer.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,37 @@ package sources
33
import (
44
"bytes"
55
"encoding/gob"
6+
"errors"
67
"go/ast"
78
"go/token"
89
"sync"
10+
11+
"github.com/gopherjs/gopherjs/build/cache"
912
)
1013

14+
// DeclCache represents additional data, a collection of precompiled
15+
// declarations, to be cached along with the sources.
16+
//
17+
// The interface is used to prevent circular dependencies between packages.
18+
type DeclCache interface {
19+
cache.Cacheable
20+
21+
// Changed indicates whether the cache data has changed since it was loaded.
22+
Changed() bool
23+
}
24+
25+
// Changed indicates whether the sources was loaded from the cache and
26+
// if it has been modified since then.
27+
// The cache will not check this automatically, so that the sources can be
28+
// stored even if it hasn't changed.
29+
// This should check this before calling cache.Store to avoid unnecessary work.
30+
//
31+
// This does not include changes to the type information or other information
32+
// that is not part of the cached data.
33+
func (s *Sources) Changed() bool {
34+
return s != nil && (!s.loadedFromCache || s.DeclCache.Changed())
35+
}
36+
1137
func (s *Sources) GobEncode() ([]byte, error) {
1238
buf := &bytes.Buffer{}
1339
err := s.Write(gob.NewEncoder(buf).Encode)
@@ -51,7 +77,10 @@ func (s *Sources) Write(encode func(any) error) error {
5177
if err := encode(s.JSFiles); err != nil {
5278
return err
5379
}
54-
if err := s.CacheData.Write(encode); err != nil {
80+
if s.DeclCache == nil {
81+
return errors.New(`may not write the sources' DeclCache with a nil DeclCache`)
82+
}
83+
if err := s.DeclCache.Write(encode); err != nil {
5584
return err
5685
}
5786
return nil
@@ -87,7 +116,14 @@ func (s *Sources) Read(decode func(any) error) error {
87116
if err := decode(&s.JSFiles); err != nil {
88117
return err
89118
}
90-
return s.CacheData.Read(decode)
119+
if s.DeclCache == nil {
120+
return errors.New(`may not read the sources' DeclCache with a nil DeclCache`)
121+
}
122+
if err := s.DeclCache.Read(decode); err != nil {
123+
return err
124+
}
125+
s.loadedFromCache = true
126+
return nil
91127
}
92128

93129
// prepareFile is run when serializing a source to remove fields that can be

compiler/sources/serializer_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestRoundTrip(t *testing.T) {
4545
Files: pkgs.Syntax,
4646
FileSet: pkgs.Fset,
4747
JSFiles: jsFiles,
48-
CacheData: &cacheDataStub{},
48+
DeclCache: &cacheDataStub{},
4949
}
5050

5151
// Serialize sources
@@ -56,7 +56,7 @@ func TestRoundTrip(t *testing.T) {
5656

5757
// Deserialize sources
5858
srcs1 := &Sources{
59-
CacheData: &cacheDataStub{},
59+
DeclCache: &cacheDataStub{},
6060
}
6161
if err := srcs1.Read(gob.NewDecoder(buf).Decode); err != nil {
6262
t.Fatalf("failed to deserialize sources: %v", err)
@@ -130,6 +130,10 @@ func checkSourcesAreEqual(t *testing.T, orig, other *Sources) {
130130

131131
type cacheDataStub struct{}
132132

133+
func (t *cacheDataStub) Changed() bool {
134+
return false
135+
}
136+
133137
func (t *cacheDataStub) Write(encode func(any) error) error {
134138
return nil
135139
}

compiler/sources/sources.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/neelance/astrewrite"
1111

12-
"github.com/gopherjs/gopherjs/build/cache"
1312
"github.com/gopherjs/gopherjs/compiler/incjs"
1413
"github.com/gopherjs/gopherjs/compiler/internal/analysis"
1514
"github.com/gopherjs/gopherjs/compiler/internal/typeparams"
@@ -59,16 +58,13 @@ type Sources struct {
5958
// This is nil until set by ParseGoLinknames.
6059
GoLinknames []linkname.GoLinkname
6160

62-
// CacheData is a object that holds any additional cacheable data
63-
// for these sources. This must be set to a non-nil instances of the
64-
// additional cache prior to encoding/decoding.
65-
//
66-
// Mainly this is used to store precompiled declarations,
67-
// see [compiler/declCache.go].
68-
//
69-
// Warning: Make sure that any data stored here has had its types
70-
// registered with the gob package for Gob encoding/decoding.
71-
CacheData cache.Cacheable
61+
// loadedFromCache indicates whether the sources were loaded from cache.
62+
loadedFromCache bool
63+
64+
// DeclCache is a object that holds any additional cacheable data,
65+
// such as precompiled declarations, for these sources.
66+
// See [compiler/declCache.go].
67+
DeclCache DeclCache
7268
}
7369

7470
type Importer func(path, srcDir string) (*Sources, error)

0 commit comments

Comments
 (0)