Skip to content

Commit 971778f

Browse files
Serialization updates
1 parent 3c9b135 commit 971778f

File tree

8 files changed

+317
-89
lines changed

8 files changed

+317
-89
lines changed

build/build.go

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"sort"
2222
"strconv"
2323
"strings"
24+
"sync"
2425
"time"
2526

2627
"github.com/fsnotify/fsnotify"
@@ -938,23 +939,40 @@ func (s *Session) buildImportPathWithSrcDir(path string, srcDir string) (*Packag
938939
return pkg, archive, nil
939940
}
940941

942+
// getExeModTime will determine the mod time of the GopherJS binary
943+
// the first time this is called and cache the result for subsequent calls.
944+
var getExeModTime = func() func() time.Time {
945+
var (
946+
once sync.Once
947+
result time.Time
948+
)
949+
getTime := func() {
950+
var fileInfo os.FileInfo
951+
gopherjsBinary, err := os.Executable()
952+
if err == nil {
953+
fileInfo, err = os.Stat(gopherjsBinary)
954+
if err == nil {
955+
result = fileInfo.ModTime()
956+
return
957+
}
958+
}
959+
os.Stderr.WriteString("Could not get GopherJS binary's modification timestamp. Please report issue.\n")
960+
result = time.Now()
961+
}
962+
return func() time.Time {
963+
once.Do(getTime)
964+
return result
965+
}
966+
}()
967+
941968
// BuildPackage compiles an already loaded package.
942969
func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
943970
if archive, ok := s.UpToDateArchives[pkg.ImportPath]; ok {
944971
return archive, nil
945972
}
946973

947-
var fileInfo os.FileInfo
948-
gopherjsBinary, err := os.Executable()
949-
if err == nil {
950-
fileInfo, err = os.Stat(gopherjsBinary)
951-
if err == nil && fileInfo.ModTime().After(pkg.SrcModTime) {
952-
pkg.SrcModTime = fileInfo.ModTime()
953-
}
954-
}
955-
if err != nil {
956-
os.Stderr.WriteString("Could not get GopherJS binary's modification timestamp. Please report issue.\n")
957-
pkg.SrcModTime = time.Now()
974+
if exeModTime := getExeModTime(); exeModTime.After(pkg.SrcModTime) {
975+
pkg.SrcModTime = exeModTime
958976
}
959977

960978
for _, importedPkgPath := range pkg.Imports {
@@ -966,22 +984,18 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
966984
return nil, err
967985
}
968986

969-
impModTime := importedPkg.SrcModTime
970-
if impModTime.After(pkg.SrcModTime) {
987+
if impModTime := importedPkg.SrcModTime; impModTime.After(pkg.SrcModTime) {
971988
pkg.SrcModTime = impModTime
972989
}
973990
}
974991

975-
if pkg.FileModTime().After(pkg.SrcModTime) {
976-
pkg.SrcModTime = pkg.FileModTime()
992+
if fileModTime := pkg.FileModTime(); fileModTime.After(pkg.SrcModTime) {
993+
pkg.SrcModTime = fileModTime
977994
}
978995

979996
if !s.options.NoCache {
980-
archive := s.buildCache.LoadArchive(pkg.ImportPath)
981-
if archive != nil && !pkg.SrcModTime.After(archive.BuildTime) {
982-
if err := archive.RegisterTypes(s.Types); err != nil {
983-
panic(fmt.Errorf("failed to load type information from %v: %w", archive, err))
984-
}
997+
archive := s.buildCache.LoadArchive(pkg.ImportPath, pkg.SrcModTime, s.Types)
998+
if archive != nil {
985999
s.UpToDateArchives[pkg.ImportPath] = archive
9861000
// Existing archive is up to date, no need to build it from scratch.
9871001
return archive, nil
@@ -1021,7 +1035,8 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
10211035
fmt.Println(pkg.ImportPath)
10221036
}
10231037

1024-
s.buildCache.StoreArchive(archive)
1038+
archiveBuiltTime := time.Now()
1039+
s.buildCache.StoreArchive(archive, archiveBuiltTime)
10251040
s.UpToDateArchives[pkg.ImportPath] = archive
10261041

10271042
return archive, nil

build/cache/cache.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"crypto/sha256"
77
"fmt"
88
"go/build"
9+
"go/types"
910
"os"
1011
"path"
1112
"path/filepath"
13+
"time"
1214

1315
"github.com/gopherjs/gopherjs/compiler"
1416
log "github.com/sirupsen/logrus"
@@ -90,7 +92,7 @@ func (bc BuildCache) String() string {
9092

9193
// StoreArchive compiled archive in the cache. Any error inside this method
9294
// will cause the cache not to be persisted.
93-
func (bc *BuildCache) StoreArchive(a *compiler.Archive) {
95+
func (bc *BuildCache) StoreArchive(a *compiler.Archive, buildTime time.Time) {
9496
if bc == nil {
9597
return // Caching is disabled.
9698
}
@@ -106,7 +108,7 @@ func (bc *BuildCache) StoreArchive(a *compiler.Archive) {
106108
return
107109
}
108110
defer f.Close()
109-
if err := compiler.WriteArchive(a, f); err != nil {
111+
if err := compiler.WriteArchive(a, buildTime, f); err != nil {
110112
log.Warningf("Failed to write build cache archive %q: %v", a, err)
111113
// Make sure we don't leave a half-written archive behind.
112114
os.Remove(f.Name())
@@ -125,7 +127,10 @@ func (bc *BuildCache) StoreArchive(a *compiler.Archive) {
125127
//
126128
// The returned archive would have been built with the same configuration as
127129
// the build cache was.
128-
func (bc *BuildCache) LoadArchive(importPath string) *compiler.Archive {
130+
//
131+
// The imports map is used to resolve package dependencies and may modify the
132+
// map to include the package from the read archive. See [gcexportdata.Read].
133+
func (bc *BuildCache) LoadArchive(importPath string, srcModTime time.Time, imports map[string]*types.Package) *compiler.Archive {
129134
if bc == nil {
130135
return nil // Caching is disabled.
131136
}
@@ -140,12 +145,16 @@ func (bc *BuildCache) LoadArchive(importPath string) *compiler.Archive {
140145
return nil // Cache miss.
141146
}
142147
defer f.Close()
143-
a, err := compiler.ReadArchive(importPath, f)
148+
a, buildTime, err := compiler.ReadArchive(importPath, f, srcModTime, imports)
144149
if err != nil {
145150
log.Warningf("Failed to read cached package archive for %q: %v", importPath, err)
146151
return nil // Invalid/corrupted archive, cache miss.
147152
}
148-
log.Infof("Found cached package archive for %q, built at %v.", importPath, a.BuildTime)
153+
if a == nil {
154+
log.Infof("Found out-of-date package archive for %q, built at %v.", importPath, buildTime)
155+
return nil // Archive is out-of-date, cache miss.
156+
}
157+
log.Infof("Found cached package archive for %q, built at %v.", importPath, buildTime)
149158
return a
150159
}
151160

build/cache/cache_test.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cache
22

33
import (
4+
"go/types"
45
"testing"
6+
"time"
57

68
"github.com/google/go-cmp/cmp"
79
"github.com/gopherjs/gopherjs/compiler"
@@ -15,21 +17,24 @@ func TestStore(t *testing.T) {
1517
Imports: []string{"fake/dep"},
1618
}
1719

20+
srcModTime := newTime(0.0)
21+
buildTime := newTime(5.0)
22+
imports := map[string]*types.Package{}
1823
bc := BuildCache{}
19-
if got := bc.LoadArchive(want.ImportPath); got != nil {
24+
if got := bc.LoadArchive(want.ImportPath, srcModTime, imports); got != nil {
2025
t.Errorf("Got: %s was found in the cache. Want: empty cache.", got.ImportPath)
2126
}
22-
bc.StoreArchive(want)
23-
got := bc.LoadArchive(want.ImportPath)
27+
bc.StoreArchive(want, buildTime)
28+
got := bc.LoadArchive(want.ImportPath, srcModTime, imports)
2429
if got == nil {
25-
t.Errorf("Got: %s wan not found in the cache. Want: archive is can be loaded after store.", want.ImportPath)
30+
t.Errorf("Got: %s was not found in the cache. Want: archive is can be loaded after store.", want.ImportPath)
2631
}
2732
if diff := cmp.Diff(want, got); diff != "" {
2833
t.Errorf("Loaded archive is different from stored (-want,+got):\n%s", diff)
2934
}
3035

3136
// Make sure the package names are a part of the cache key.
32-
if got := bc.LoadArchive("fake/other"); got != nil {
37+
if got := bc.LoadArchive("fake/other", srcModTime, imports); got != nil {
3338
t.Errorf("Got: fake/other was found in cache: %#v. Want: nil for packages that weren't cached.", got)
3439
}
3540
}
@@ -59,20 +64,54 @@ func TestInvalidation(t *testing.T) {
5964
},
6065
}
6166

67+
srcModTime := newTime(0.0)
68+
buildTime := newTime(5.0)
69+
imports := map[string]*types.Package{}
6270
for _, test := range tests {
6371
a := &compiler.Archive{ImportPath: "package/fake"}
64-
test.cache1.StoreArchive(a)
72+
test.cache1.StoreArchive(a, buildTime)
6573

66-
if got := test.cache2.LoadArchive(a.ImportPath); got != nil {
74+
if got := test.cache2.LoadArchive(a.ImportPath, srcModTime, imports); got != nil {
6775
t.Logf("-cache1,+cache2:\n%s", cmp.Diff(test.cache1, test.cache2))
6876
t.Errorf("Got: %v loaded from cache. Want: build parameter change invalidates cache.", got)
6977
}
7078
}
7179
}
7280

81+
func TestOldArchive(t *testing.T) {
82+
cacheForTest(t)
83+
84+
want := &compiler.Archive{
85+
ImportPath: "fake/package",
86+
Imports: []string{"fake/dep"},
87+
}
88+
89+
buildTime := newTime(5.0)
90+
imports := map[string]*types.Package{}
91+
bc := BuildCache{}
92+
bc.StoreArchive(want, buildTime)
93+
94+
oldSrcModTime := newTime(2.0) // older than archive build time, so archive is up-to-date
95+
got := bc.LoadArchive(want.ImportPath, oldSrcModTime, imports)
96+
if got == nil {
97+
t.Errorf("Got: %s was nil. Want: up-to-date archive to be loaded.", want.ImportPath)
98+
}
99+
100+
newerSrcModTime := newTime(7.0) // newer than archive build time, so archive is stale
101+
got = bc.LoadArchive(want.ImportPath, newerSrcModTime, imports)
102+
if got != nil {
103+
t.Errorf("Got: %s was not nil. Want: stale archive to not be loaded.", want.ImportPath)
104+
}
105+
}
106+
73107
func cacheForTest(t *testing.T) {
74108
t.Helper()
75109
originalRoot := cacheRoot
76110
t.Cleanup(func() { cacheRoot = originalRoot })
77111
cacheRoot = t.TempDir()
78112
}
113+
114+
func newTime(seconds float64) time.Time {
115+
return time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC).
116+
Add(time.Duration(seconds * float64(time.Second)))
117+
}

0 commit comments

Comments
 (0)