...

Source file src/pkg/cmd/compile/internal/types/pkg.go

     1	// Copyright 2017 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package types
     6	
     7	import (
     8		"cmd/internal/obj"
     9		"cmd/internal/objabi"
    10		"fmt"
    11		"sort"
    12		"sync"
    13	)
    14	
    15	// pkgMap maps a package path to a package.
    16	var pkgMap = make(map[string]*Pkg)
    17	
    18	// MaxPkgHeight is a height greater than any likely package height.
    19	const MaxPkgHeight = 1e9
    20	
    21	type Pkg struct {
    22		Path    string // string literal used in import statement, e.g. "runtime/internal/sys"
    23		Name    string // package name, e.g. "sys"
    24		Prefix  string // escaped path for use in symbol table
    25		Syms    map[string]*Sym
    26		Pathsym *obj.LSym
    27	
    28		// Height is the package's height in the import graph. Leaf
    29		// packages (i.e., packages with no imports) have height 0,
    30		// and all other packages have height 1 plus the maximum
    31		// height of their imported packages.
    32		Height int
    33	
    34		Imported bool // export data of this package was parsed
    35		Direct   bool // imported directly
    36	}
    37	
    38	// NewPkg returns a new Pkg for the given package path and name.
    39	// Unless name is the empty string, if the package exists already,
    40	// the existing package name and the provided name must match.
    41	func NewPkg(path, name string) *Pkg {
    42		if p := pkgMap[path]; p != nil {
    43			if name != "" && p.Name != name {
    44				panic(fmt.Sprintf("conflicting package names %s and %s for path %q", p.Name, name, path))
    45			}
    46			return p
    47		}
    48	
    49		p := new(Pkg)
    50		p.Path = path
    51		p.Name = name
    52		p.Prefix = objabi.PathToPrefix(path)
    53		p.Syms = make(map[string]*Sym)
    54		pkgMap[path] = p
    55	
    56		return p
    57	}
    58	
    59	// ImportedPkgList returns the list of directly imported packages.
    60	// The list is sorted by package path.
    61	func ImportedPkgList() []*Pkg {
    62		var list []*Pkg
    63		for _, p := range pkgMap {
    64			if p.Direct {
    65				list = append(list, p)
    66			}
    67		}
    68		sort.Sort(byPath(list))
    69		return list
    70	}
    71	
    72	type byPath []*Pkg
    73	
    74	func (a byPath) Len() int           { return len(a) }
    75	func (a byPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
    76	func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    77	
    78	var nopkg = &Pkg{
    79		Syms: make(map[string]*Sym),
    80	}
    81	
    82	func (pkg *Pkg) Lookup(name string) *Sym {
    83		s, _ := pkg.LookupOK(name)
    84		return s
    85	}
    86	
    87	// List of .inittask entries in imported packages, in source code order.
    88	var InitSyms []*Sym
    89	
    90	// LookupOK looks up name in pkg and reports whether it previously existed.
    91	func (pkg *Pkg) LookupOK(name string) (s *Sym, existed bool) {
    92		// TODO(gri) remove this check in favor of specialized lookup
    93		if pkg == nil {
    94			pkg = nopkg
    95		}
    96		if s := pkg.Syms[name]; s != nil {
    97			return s, true
    98		}
    99	
   100		s = &Sym{
   101			Name: name,
   102			Pkg:  pkg,
   103		}
   104		if name == ".inittask" {
   105			InitSyms = append(InitSyms, s)
   106		}
   107		pkg.Syms[name] = s
   108		return s, false
   109	}
   110	
   111	func (pkg *Pkg) LookupBytes(name []byte) *Sym {
   112		// TODO(gri) remove this check in favor of specialized lookup
   113		if pkg == nil {
   114			pkg = nopkg
   115		}
   116		if s := pkg.Syms[string(name)]; s != nil {
   117			return s
   118		}
   119		str := InternString(name)
   120		return pkg.Lookup(str)
   121	}
   122	
   123	var (
   124		internedStringsmu sync.Mutex // protects internedStrings
   125		internedStrings   = map[string]string{}
   126	)
   127	
   128	func InternString(b []byte) string {
   129		internedStringsmu.Lock()
   130		s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
   131		if !ok {
   132			s = string(b)
   133			internedStrings[s] = s
   134		}
   135		internedStringsmu.Unlock()
   136		return s
   137	}
   138	
   139	// CleanroomDo invokes f in an environment with no preexisting packages.
   140	// For testing of import/export only.
   141	func CleanroomDo(f func()) {
   142		saved := pkgMap
   143		pkgMap = make(map[string]*Pkg)
   144		f()
   145		pkgMap = saved
   146	}
   147	

View as plain text