]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add package height to export data
authorMatthew Dempsky <mdempsky@google.com>
Thu, 5 Apr 2018 21:29:32 +0000 (14:29 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 9 Apr 2018 23:36:46 +0000 (23:36 +0000)
A package's height is defined as the length of the longest import path
between itself and a leaf package (i.e., package with no imports).

We can't rely on knowing the path of the package being compiled, so
package height is useful for defining a package ordering.

Updates #24693.

Change-Id: I965162c440b6c5397db91b621ea0be7fa63881f1
Reviewed-on: https://go-review.googlesource.com/105038
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/types/pkg.go
src/go/internal/gcimporter/bimport.go

index f37ab3e819145577e8cdad8a4d70d49f73004783..8ec1e36e8446a94f0eaec61f077bdc1cc2e6eb81 100644 (file)
@@ -135,13 +135,14 @@ import (
 const debugFormat = false // default: false
 
 // Current export format version. Increase with each format change.
+// 6: package height (CL 105038)
 // 5: improved position encoding efficiency (issue 20080, CL 41619)
 // 4: type name objects support type aliases, uses aliasTag
 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
 // 2: removed unused bool in ODCL export (compiler only)
 // 1: header format change (more regular), export package for _ struct fields
 // 0: Go1.7 encoding
-const exportVersion = 5
+const exportVersion = 6
 
 // exportInlined enables the export of inlined function bodies and related
 // dependencies. The compiler should work w/o any loss of functionality with
@@ -428,6 +429,7 @@ func (p *exporter) pkg(pkg *types.Pkg) {
        p.tag(packageTag)
        p.string(pkg.Name)
        p.path(pkg.Path)
+       p.int(pkg.Height)
 }
 
 func unidealType(typ *types.Type, val Val) *types.Type {
index ca0f523a791fb76aa4d4388373f5f56e17f75ea3..41a9ce41bde5994c5f06f9780973c08b427cd9e4 100644 (file)
@@ -96,10 +96,10 @@ func Import(imp *types.Pkg, in *bufio.Reader) {
 
        // read version specific flags - extend as necessary
        switch p.version {
-       // case 6:
+       // case 7:
        //      ...
        //      fallthrough
-       case 5, 4, 3, 2, 1:
+       case 6, 5, 4, 3, 2, 1:
                p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
                p.trackAllTypes = p.bool()
                p.posInfoFormat = p.bool()
@@ -281,6 +281,10 @@ func (p *importer) pkg() *types.Pkg {
        } else {
                path = p.string()
        }
+       var height int
+       if p.version >= 6 {
+               height = p.int()
+       }
 
        // we should never see an empty package name
        if name == "" {
@@ -298,6 +302,18 @@ func (p *importer) pkg() *types.Pkg {
                p.formatErrorf("package path %q for pkg index %d", path, len(p.pkgList))
        }
 
+       if p.version >= 6 {
+               if height < 0 || height >= types.MaxPkgHeight {
+                       p.formatErrorf("bad package height %v for package %s", height, name)
+               }
+
+               // reexported packages should always have a lower height than
+               // the main package
+               if len(p.pkgList) != 0 && height >= p.imp.Height {
+                       p.formatErrorf("package %q (height %d) reexports package %q (height %d)", p.imp.Path, p.imp.Height, path, height)
+               }
+       }
+
        // add package to pkgList
        pkg := p.imp
        if path != "" {
@@ -313,6 +329,7 @@ func (p *importer) pkg() *types.Pkg {
                yyerror("import %q: package depends on %q (import cycle)", p.imp.Path, path)
                errorexit()
        }
+       pkg.Height = height
        p.pkgList = append(p.pkgList, pkg)
 
        return pkg
index 52485b088cde354f93e77089521026348a5a1eb5..9496fc9a949b2d964762bbf94ddd504793cef470 100644 (file)
@@ -141,6 +141,11 @@ func Main(archInit func(*Arch)) {
        localpkg = types.NewPkg("", "")
        localpkg.Prefix = "\"\""
 
+       // We won't know localpkg's height until after import
+       // processing. In the mean time, set to MaxPkgHeight to ensure
+       // height comparisons at least work until then.
+       localpkg.Height = types.MaxPkgHeight
+
        // pseudo-package, for scoping
        builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
        builtinpkg.Prefix = "go.builtin"            // not go%2ebuiltin
@@ -925,6 +930,10 @@ func loadsys() {
        inimport = false
 }
 
+// myheight tracks the local package's height based on packages
+// imported so far.
+var myheight int
+
 func importfile(f *Val) *types.Pkg {
        path_, ok := f.U.(string)
        if !ok {
@@ -1117,6 +1126,10 @@ func importfile(f *Val) *types.Pkg {
                errorexit()
        }
 
+       if importpkg.Height >= myheight {
+               myheight = importpkg.Height + 1
+       }
+
        return importpkg
 }
 
index 03d412bfbbed5443b6c44fab933cdf0d245811a5..96b2584074e091198b982b0074178de32ff8cff2 100644 (file)
@@ -65,6 +65,8 @@ func parseFiles(filenames []string) uint {
                testdclstack()
        }
 
+       localpkg.Height = myheight
+
        return lines
 }
 
index 81bf72e9721e4cd05ac0bc852bbb4b2f58fea8f5..e27c1fdba32a4447bb4efd170595a003cea2e089 100644 (file)
@@ -15,14 +15,24 @@ import (
 // pkgMap maps a package path to a package.
 var pkgMap = make(map[string]*Pkg)
 
+// MaxPkgHeight is a height greater than any likely package height.
+const MaxPkgHeight = 1e9
+
 type Pkg struct {
-       Path     string // string literal used in import statement, e.g. "runtime/internal/sys"
-       Name     string // package name, e.g. "sys"
-       Pathsym  *obj.LSym
-       Prefix   string // escaped path for use in symbol table
-       Imported bool   // export data of this package was parsed
-       Direct   bool   // imported directly
-       Syms     map[string]*Sym
+       Path    string // string literal used in import statement, e.g. "runtime/internal/sys"
+       Name    string // package name, e.g. "sys"
+       Prefix  string // escaped path for use in symbol table
+       Syms    map[string]*Sym
+       Pathsym *obj.LSym
+
+       // Height is the package's height in the import graph. Leaf
+       // packages (i.e., packages with no imports) have height 0,
+       // and all other packages have height 1 plus the maximum
+       // height of their imported packages.
+       Height int
+
+       Imported bool // export data of this package was parsed
+       Direct   bool // imported directly
 }
 
 // NewPkg returns a new Pkg for the given package path and name.
index b8d9e318ed165bb2bda5103f900eba49e1cb6b05..5c98da43040f89b7baa6d398af213634f7ead8d4 100644 (file)
@@ -102,10 +102,10 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
        // read version specific flags - extend as necessary
        switch p.version {
-       // case 6:
+       // case 7:
        //      ...
        //      fallthrough
-       case 5, 4, 3, 2, 1:
+       case 6, 5, 4, 3, 2, 1:
                p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
                p.trackAllTypes = p.int() != 0
                p.posInfoFormat = p.int() != 0
@@ -182,6 +182,9 @@ func (p *importer) pkg() *types.Package {
        } else {
                path = p.string()
        }
+       if p.version >= 6 {
+               p.int() // package height; unused by go/types
+       }
 
        // we should never see an empty package name
        if name == "" {