Source file src/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  	"strconv"
    12  	"sync"
    13  )
    14  
    15  // pkgMap maps a package path to a package.
    16  var pkgMap = make(map[string]*Pkg)
    17  
    18  type Pkg struct {
    19  	Path    string // string literal used in import statement, e.g. "runtime/internal/sys"
    20  	Name    string // package name, e.g. "sys"
    21  	Prefix  string // escaped path for use in symbol table
    22  	Syms    map[string]*Sym
    23  	Pathsym *obj.LSym
    24  
    25  	Direct bool // imported directly
    26  }
    27  
    28  // NewPkg returns a new Pkg for the given package path and name.
    29  // Unless name is the empty string, if the package exists already,
    30  // the existing package name and the provided name must match.
    31  func NewPkg(path, name string) *Pkg {
    32  	if p := pkgMap[path]; p != nil {
    33  		if name != "" && p.Name != name {
    34  			panic(fmt.Sprintf("conflicting package names %s and %s for path %q", p.Name, name, path))
    35  		}
    36  		return p
    37  	}
    38  
    39  	p := new(Pkg)
    40  	p.Path = path
    41  	p.Name = name
    42  	if path == "go.shape" {
    43  		// Don't escape "go.shape", since it's not needed (it's a builtin
    44  		// package), and we don't want escape codes showing up in shape type
    45  		// names, which also appear in names of function/method
    46  		// instantiations.
    47  		p.Prefix = path
    48  	} else {
    49  		p.Prefix = objabi.PathToPrefix(path)
    50  	}
    51  	p.Syms = make(map[string]*Sym)
    52  	pkgMap[path] = p
    53  
    54  	return p
    55  }
    56  
    57  func PkgMap() map[string]*Pkg {
    58  	return pkgMap
    59  }
    60  
    61  var nopkg = &Pkg{
    62  	Syms: make(map[string]*Sym),
    63  }
    64  
    65  func (pkg *Pkg) Lookup(name string) *Sym {
    66  	s, _ := pkg.LookupOK(name)
    67  	return s
    68  }
    69  
    70  // LookupOK looks up name in pkg and reports whether it previously existed.
    71  func (pkg *Pkg) LookupOK(name string) (s *Sym, existed bool) {
    72  	// TODO(gri) remove this check in favor of specialized lookup
    73  	if pkg == nil {
    74  		pkg = nopkg
    75  	}
    76  	if s := pkg.Syms[name]; s != nil {
    77  		return s, true
    78  	}
    79  
    80  	s = &Sym{
    81  		Name: name,
    82  		Pkg:  pkg,
    83  	}
    84  	pkg.Syms[name] = s
    85  	return s, false
    86  }
    87  
    88  func (pkg *Pkg) LookupBytes(name []byte) *Sym {
    89  	// TODO(gri) remove this check in favor of specialized lookup
    90  	if pkg == nil {
    91  		pkg = nopkg
    92  	}
    93  	if s := pkg.Syms[string(name)]; s != nil {
    94  		return s
    95  	}
    96  	str := InternString(name)
    97  	return pkg.Lookup(str)
    98  }
    99  
   100  // LookupNum looks up the symbol starting with prefix and ending with
   101  // the decimal n. If prefix is too long, LookupNum panics.
   102  func (pkg *Pkg) LookupNum(prefix string, n int) *Sym {
   103  	var buf [20]byte // plenty long enough for all current users
   104  	copy(buf[:], prefix)
   105  	b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
   106  	return pkg.LookupBytes(b)
   107  }
   108  
   109  // Selector looks up a selector identifier.
   110  func (pkg *Pkg) Selector(name string) *Sym {
   111  	if IsExported(name) {
   112  		pkg = LocalPkg
   113  	}
   114  	return pkg.Lookup(name)
   115  }
   116  
   117  var (
   118  	internedStringsmu sync.Mutex // protects internedStrings
   119  	internedStrings   = map[string]string{}
   120  )
   121  
   122  func InternString(b []byte) string {
   123  	internedStringsmu.Lock()
   124  	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
   125  	if !ok {
   126  		s = string(b)
   127  		internedStrings[s] = s
   128  	}
   129  	internedStringsmu.Unlock()
   130  	return s
   131  }
   132  

View as plain text