move curPkgCache out of the global scope

loadPkgCache also uses different pkgCache variables
depending on whether it finds a direct cache hit or not.

Now we only initialize an entirely new pkgCache
with the first two ReflectAPIs entries when we get a direct cache miss,
since a direct cache hit will already load those from the cache.
pull/757/head
Daniel Martí 1 year ago
parent 4f743b0861
commit c5af68cd80

@ -913,7 +913,7 @@ func (tf *transformer) transformCompile(args []string) ([]string, error) {
return nil, err return nil, err
} }
if err := loadPkgCache(tf.curPkg, tf.pkg, files, tf.info); err != nil { if tf.curPkgCache, err = loadPkgCache(tf.curPkg, tf.pkg, files, tf.info); err != nil {
return nil, err return nil, err
} }
@ -1283,15 +1283,6 @@ type pkgCache struct {
EmbeddedAliasFields map[objectString]typeName EmbeddedAliasFields map[objectString]typeName
} }
var curPkgCache = pkgCache{
ReflectAPIs: map[funcFullName]map[int]bool{
"reflect.TypeOf": {0: true},
"reflect.ValueOf": {0: true},
},
ReflectObjects: map[objectString]struct{}{},
EmbeddedAliasFields: map[objectString]typeName{},
}
func openCache() (*cache.Cache, error) { func openCache() (*cache.Cache, error) {
dir := os.Getenv("GARBLE_CACHE") // e.g. "~/.cache/garble" dir := os.Getenv("GARBLE_CACHE") // e.g. "~/.cache/garble"
if dir == "" { if dir == "" {
@ -1311,24 +1302,26 @@ func openCache() (*cache.Cache, error) {
return cache.Open(dir) return cache.Open(dir)
} }
func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, info *types.Info) error { func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, info *types.Info) (pkgCache, error) {
fsCache, err := openCache() fsCache, err := openCache()
if err != nil { if err != nil {
return err return pkgCache{}, err
} }
filename, _, err := fsCache.GetFile(lpkg.GarbleActionID) filename, _, err := fsCache.GetFile(lpkg.GarbleActionID)
// Already in the cache; load it directly. // Already in the cache; load it directly.
if err == nil { if err == nil {
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return err return pkgCache{}, err
} }
defer f.Close() defer f.Close()
if err := gob.NewDecoder(f).Decode(&curPkgCache); err != nil { var loaded pkgCache
return fmt.Errorf("gob decode: %w", err) if err := gob.NewDecoder(f).Decode(&loaded); err != nil {
return pkgCache{}, fmt.Errorf("gob decode: %w", err)
} }
return nil return loaded, nil
} }
// Not yet in the cache. Load the cache entries for all direct dependencies, // Not yet in the cache. Load the cache entries for all direct dependencies,
// build our cache entry, and write it to disk. // build our cache entry, and write it to disk.
// Note that practically all errors from Cache.GetFile are a cache miss; // Note that practically all errors from Cache.GetFile are a cache miss;
@ -1339,6 +1332,14 @@ func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, in
// then loading the gob files from both B and C is unnecessary; // then loading the gob files from both B and C is unnecessary;
// loading B's gob file would be enough. Is there an easy way to do that? // loading B's gob file would be enough. Is there an easy way to do that?
startTime := time.Now() startTime := time.Now()
computed := pkgCache{
ReflectAPIs: map[funcFullName]map[int]bool{
"reflect.TypeOf": {0: true},
"reflect.ValueOf": {0: true},
},
ReflectObjects: map[objectString]struct{}{},
EmbeddedAliasFields: map[objectString]typeName{},
}
loaded := 0 loaded := 0
for _, path := range lpkg.Imports { for _, path := range lpkg.Imports {
if path == "C" { if path == "C" {
@ -1364,12 +1365,12 @@ func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, in
} }
defer f.Close() defer f.Close()
// Decode appends new entries to the existing maps // Decode appends new entries to the existing maps
if err := gob.NewDecoder(f).Decode(&curPkgCache); err != nil { if err := gob.NewDecoder(f).Decode(&computed); err != nil {
return fmt.Errorf("gob decode: %w", err) return fmt.Errorf("gob decode: %w", err)
} }
return nil return nil
}(); err != nil { }(); err != nil {
return fmt.Errorf("cannot load cache entry for %s: %w", path, err) return pkgCache{}, fmt.Errorf("cannot load cache entry for %s: %w", path, err)
} }
loaded++ loaded++
} }
@ -1393,7 +1394,7 @@ func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, in
PkgPath: obj.Pkg().Path(), PkgPath: obj.Pkg().Path(),
Name: obj.Name(), Name: obj.Name(),
} }
curPkgCache.EmbeddedAliasFields[vrStr] = aliasTypeName computed.EmbeddedAliasFields[vrStr] = aliasTypeName
} }
// Fill the reflect info from SSA, which builds on top of the syntax tree and type info. // Fill the reflect info from SSA, which builds on top of the syntax tree and type info.
@ -1418,19 +1419,19 @@ func loadPkgCache(lpkg *listedPackage, pkg *types.Package, files []*ast.File, in
inspector := reflectInspector{ inspector := reflectInspector{
pkg: pkg, pkg: pkg,
checkedAPIs: make(map[string]bool), checkedAPIs: make(map[string]bool),
result: curPkgCache, // append the results result: computed, // append the results
} }
inspector.recordReflection(ssaPkg) inspector.recordReflection(ssaPkg)
// Unlikely that we could stream the gob encode, as cache.Put wants an io.ReadSeeker. // Unlikely that we could stream the gob encode, as cache.Put wants an io.ReadSeeker.
var buf bytes.Buffer var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(curPkgCache); err != nil { if err := gob.NewEncoder(&buf).Encode(computed); err != nil {
return err return pkgCache{}, err
} }
if err := fsCache.PutBytes(lpkg.GarbleActionID, buf.Bytes()); err != nil { if err := fsCache.PutBytes(lpkg.GarbleActionID, buf.Bytes()); err != nil {
return err return pkgCache{}, err
} }
return nil return computed, nil
} }
// cmd/bundle will include a go:generate directive in its output by default. // cmd/bundle will include a go:generate directive in its output by default.
@ -1493,6 +1494,9 @@ type transformer struct {
// curPkg holds basic information about the package being currently compiled or linked. // curPkg holds basic information about the package being currently compiled or linked.
curPkg *listedPackage curPkg *listedPackage
// curPkgCache is the pkgCache for curPkg.
curPkgCache pkgCache
// The type-checking results; the package itself, and the Info struct. // The type-checking results; the package itself, and the Info struct.
pkg *types.Package pkg *types.Package
info *types.Info info *types.Info
@ -1749,7 +1753,7 @@ func (tf *transformer) transformGoFile(file *ast.File) *ast.File {
// Alternatively, if we don't have an alias, we still want to // Alternatively, if we don't have an alias, we still want to
// use the embedded type, not the field. // use the embedded type, not the field.
vrStr := recordedObjectString(vr) vrStr := recordedObjectString(vr)
aliasTypeName, ok := curPkgCache.EmbeddedAliasFields[vrStr] aliasTypeName, ok := tf.curPkgCache.EmbeddedAliasFields[vrStr]
if ok { if ok {
pkg2 := tf.pkg pkg2 := tf.pkg
if path := aliasTypeName.PkgPath; pkg2.Path() != path { if path := aliasTypeName.PkgPath; pkg2.Path() != path {
@ -1818,7 +1822,7 @@ func (tf *transformer) transformGoFile(file *ast.File) *ast.File {
} }
// The package that declared this object did not obfuscate it. // The package that declared this object did not obfuscate it.
if usedForReflect(obj) { if usedForReflect(tf.curPkgCache, obj) {
return true return true
} }

@ -375,7 +375,7 @@ func (ri *reflectInspector) recursivelyRecordUsedForReflect(t types.Type) {
if obj.Pkg() == nil || obj.Pkg() != ri.pkg { if obj.Pkg() == nil || obj.Pkg() != ri.pkg {
return // not from the specified package return // not from the specified package
} }
if usedForReflect(obj) { if usedForReflect(ri.result, obj) {
return // prevent endless recursion return // prevent endless recursion
} }
ri.recordUsedForReflect(obj) ri.recordUsedForReflect(obj)
@ -454,11 +454,11 @@ func (ri *reflectInspector) recordUsedForReflect(obj types.Object) {
ri.result.ReflectObjects[objStr] = struct{}{} ri.result.ReflectObjects[objStr] = struct{}{}
} }
func usedForReflect(obj types.Object) bool { func usedForReflect(cache pkgCache, obj types.Object) bool {
objStr := recordedObjectString(obj) objStr := recordedObjectString(obj)
if objStr == "" { if objStr == "" {
return false return false
} }
_, ok := curPkgCache.ReflectObjects[objStr] _, ok := cache.ReflectObjects[objStr]
return ok return ok
} }

Loading…
Cancel
Save