mirror of
https://github.com/golang/go
synced 2024-11-19 05:04:43 -07:00
cmd/internal/gc: replace hash tables with Go maps
The C version of the compiler had just one hash table, indexed by a (name string, pkg *Pkg) pair. Because we always know the pkg during a lookup, replace the one table with a per-Pkg map[string]*Sym. This also lets us do non-allocating []byte key lookups. This CL *does* change the generated object files. In the old code, export data and init calls were emitted in "hash table order". Now they are emitted in the order in which they were added to the table. Change-Id: I5a48d5c9add996dc43ad04a905641d901522de0b Reviewed-on: https://go-review.googlesource.com/6600 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
bed1f90d08
commit
d0b59deb71
@ -372,12 +372,9 @@ func dumpexport() {
|
||||
}
|
||||
fmt.Fprintf(bout, "\n")
|
||||
|
||||
var p *Pkg
|
||||
for i := int32(0); i < int32(len(phash)); i++ {
|
||||
for p = phash[i]; p != nil; p = p.Link {
|
||||
if p.Direct != 0 {
|
||||
dumppkg(p)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p.Direct != 0 {
|
||||
dumppkg(p)
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,6 +429,8 @@ func pkgtype(s *Sym) *Type {
|
||||
return s.Def.Type
|
||||
}
|
||||
|
||||
var numImport = make(map[string]int)
|
||||
|
||||
func importimport(s *Sym, path string) {
|
||||
// Informational: record package name
|
||||
// associated with import path, for use in
|
||||
@ -443,7 +442,7 @@ func importimport(s *Sym, path string) {
|
||||
p := mkpkg(path)
|
||||
if p.Name == "" {
|
||||
p.Name = s.Name
|
||||
Pkglookup(s.Name, nil).Npkg++
|
||||
numImport[s.Name]++
|
||||
} else if p.Name != s.Name {
|
||||
Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ func symfmt(s *Sym, flag int) string {
|
||||
}
|
||||
|
||||
// If the name was used by multiple packages, display the full path,
|
||||
if s.Pkg.Name != "" && Pkglookup(s.Pkg.Name, nil).Npkg > 1 {
|
||||
if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
|
||||
return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
|
||||
}
|
||||
var fp string
|
||||
|
@ -110,11 +110,11 @@ type Pkg struct {
|
||||
Path string
|
||||
Pathsym *Sym
|
||||
Prefix string
|
||||
Link *Pkg
|
||||
Imported uint8
|
||||
Exported int8
|
||||
Direct int8
|
||||
Safe bool
|
||||
Syms map[string]*Sym
|
||||
}
|
||||
|
||||
type Sym struct {
|
||||
@ -122,7 +122,6 @@ type Sym struct {
|
||||
Flags uint8
|
||||
Sym uint8
|
||||
Link *Sym
|
||||
Npkg int32
|
||||
Uniqgen uint32
|
||||
Importdef *Pkg
|
||||
Linkname string
|
||||
@ -753,8 +752,6 @@ var debugstr string
|
||||
|
||||
var Debug_checknil int
|
||||
|
||||
var hash [NHASH]*Sym
|
||||
|
||||
var importmyname *Sym // my name for package
|
||||
|
||||
var localpkg *Pkg // package being compiled
|
||||
@ -787,8 +784,6 @@ var trackpkg *Pkg // fake package for field tracking
|
||||
|
||||
var rawpkg *Pkg // fake package for raw symbol names
|
||||
|
||||
var phash [128]*Pkg
|
||||
|
||||
var Tptr int // either TPTR32 or TPTR64
|
||||
|
||||
var myimportpath string
|
||||
|
@ -249,7 +249,7 @@ import_package:
|
||||
{
|
||||
if importpkg.Name == "" {
|
||||
importpkg.Name = $2.Name;
|
||||
Pkglookup($2.Name, nil).Npkg++;
|
||||
numImport[$2.Name]++
|
||||
} else if importpkg.Name != $2.Name {
|
||||
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, $2.Name, importpkg.Path);
|
||||
}
|
||||
|
@ -88,14 +88,8 @@ func anyinit(n *NodeList) bool {
|
||||
}
|
||||
|
||||
// are there any imported init functions
|
||||
for h := uint32(0); h < NHASH; h++ {
|
||||
for s = hash[h]; s != nil; s = s.Link {
|
||||
if s.Name[0] != 'i' || s.Name != "init" {
|
||||
continue
|
||||
}
|
||||
if s.Def == nil {
|
||||
continue
|
||||
}
|
||||
for _, s := range initSyms {
|
||||
if s.Def != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -161,22 +155,10 @@ func fninit(n *NodeList) {
|
||||
r = list(r, a)
|
||||
|
||||
// (7)
|
||||
var s *Sym
|
||||
for h := uint32(0); h < NHASH; h++ {
|
||||
for s = hash[h]; s != nil; s = s.Link {
|
||||
if s.Name[0] != 'i' || s.Name != "init" {
|
||||
continue
|
||||
}
|
||||
if s.Def == nil {
|
||||
continue
|
||||
}
|
||||
if s == initsym {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, s := range initSyms {
|
||||
if s.Def != nil && s != initsym {
|
||||
// could check that it is fn of no args/returns
|
||||
a = Nod(OCALL, s.Def, nil)
|
||||
|
||||
r = list(r, a)
|
||||
}
|
||||
}
|
||||
@ -188,7 +170,7 @@ func fninit(n *NodeList) {
|
||||
// could check that it is fn of no args/returns
|
||||
for i := 1; ; i++ {
|
||||
namebuf = fmt.Sprintf("init.%d", i)
|
||||
s = Lookup(namebuf)
|
||||
s := Lookup(namebuf)
|
||||
if s.Def == nil {
|
||||
break
|
||||
}
|
||||
|
@ -1377,7 +1377,7 @@ talph:
|
||||
cp = nil
|
||||
ungetc(c)
|
||||
|
||||
s = Lookup(lexbuf.String())
|
||||
s = LookupBytes(lexbuf.Bytes())
|
||||
switch s.Lexical {
|
||||
case LIGNORE:
|
||||
goto l0
|
||||
@ -3120,36 +3120,33 @@ func mkpackage(pkgname string) {
|
||||
if pkgname != localpkg.Name {
|
||||
Yyerror("package %s; expected %s", pkgname, localpkg.Name)
|
||||
}
|
||||
var s *Sym
|
||||
for h := int32(0); h < NHASH; h++ {
|
||||
for s = hash[h]; s != nil; s = s.Link {
|
||||
if s.Def == nil || s.Pkg != localpkg {
|
||||
continue
|
||||
for _, s := range localpkg.Syms {
|
||||
if s.Def == nil {
|
||||
continue
|
||||
}
|
||||
if s.Def.Op == OPACK {
|
||||
// throw away top-level package name leftover
|
||||
// from previous file.
|
||||
// leave s->block set to cause redeclaration
|
||||
// errors if a conflicting top-level name is
|
||||
// introduced by a different file.
|
||||
if s.Def.Used == 0 && nsyntaxerrors == 0 {
|
||||
pkgnotused(int(s.Def.Lineno), s.Def.Pkg.Path, s.Name)
|
||||
}
|
||||
if s.Def.Op == OPACK {
|
||||
// throw away top-level package name leftover
|
||||
// from previous file.
|
||||
// leave s->block set to cause redeclaration
|
||||
// errors if a conflicting top-level name is
|
||||
// introduced by a different file.
|
||||
if s.Def.Used == 0 && nsyntaxerrors == 0 {
|
||||
pkgnotused(int(s.Def.Lineno), s.Def.Pkg.Path, s.Name)
|
||||
}
|
||||
s.Def = nil
|
||||
continue
|
||||
s.Def = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if s.Def.Sym != s {
|
||||
// throw away top-level name left over
|
||||
// from previous import . "x"
|
||||
if s.Def.Pack != nil && s.Def.Pack.Used == 0 && nsyntaxerrors == 0 {
|
||||
pkgnotused(int(s.Def.Pack.Lineno), s.Def.Pack.Pkg.Path, "")
|
||||
s.Def.Pack.Used = 1
|
||||
}
|
||||
|
||||
if s.Def.Sym != s {
|
||||
// throw away top-level name left over
|
||||
// from previous import . "x"
|
||||
if s.Def.Pack != nil && s.Def.Pack.Used == 0 && nsyntaxerrors == 0 {
|
||||
pkgnotused(int(s.Def.Pack.Lineno), s.Def.Pack.Pkg.Path, "")
|
||||
s.Def.Pack.Used = 1
|
||||
}
|
||||
|
||||
s.Def = nil
|
||||
continue
|
||||
}
|
||||
s.Def = nil
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1246,12 +1246,9 @@ func dumptypestructs() {
|
||||
}
|
||||
|
||||
// generate import strings for imported packages
|
||||
var p *Pkg
|
||||
for i := 0; i < len(phash); i++ {
|
||||
for p = phash[i]; p != nil; p = p.Link {
|
||||
if p.Direct != 0 {
|
||||
dimportpath(p)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p.Direct != 0 {
|
||||
dimportpath(p)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,54 +275,54 @@ func setlineno(n *Node) int32 {
|
||||
return lno
|
||||
}
|
||||
|
||||
func stringhash(p string) uint32 {
|
||||
var c int
|
||||
|
||||
h := uint32(0)
|
||||
for {
|
||||
c, p = intstarstringplusplus(p)
|
||||
if c == 0 {
|
||||
break
|
||||
}
|
||||
h = h*PRIME1 + uint32(c)
|
||||
}
|
||||
|
||||
if int32(h) < 0 {
|
||||
h = -h
|
||||
if int32(h) < 0 {
|
||||
h = 0
|
||||
}
|
||||
}
|
||||
|
||||
return h
|
||||
func Lookup(name string) *Sym {
|
||||
return localpkg.Lookup(name)
|
||||
}
|
||||
|
||||
func Lookup(name string) *Sym {
|
||||
return Pkglookup(name, localpkg)
|
||||
func LookupBytes(name []byte) *Sym {
|
||||
return localpkg.LookupBytes(name)
|
||||
}
|
||||
|
||||
var initSyms []*Sym
|
||||
|
||||
var nopkg = new(Pkg)
|
||||
|
||||
func (pkg *Pkg) Lookup(name string) *Sym {
|
||||
if pkg == nil {
|
||||
pkg = nopkg
|
||||
}
|
||||
if s := pkg.Syms[name]; s != nil {
|
||||
return s
|
||||
}
|
||||
|
||||
s := &Sym{
|
||||
Name: name,
|
||||
Pkg: pkg,
|
||||
Lexical: LNAME,
|
||||
}
|
||||
if s.Name == "init" {
|
||||
initSyms = append(initSyms, s)
|
||||
}
|
||||
if pkg.Syms == nil {
|
||||
pkg.Syms = make(map[string]*Sym)
|
||||
}
|
||||
pkg.Syms[name] = s
|
||||
return s
|
||||
}
|
||||
|
||||
func (pkg *Pkg) LookupBytes(name []byte) *Sym {
|
||||
if pkg == nil {
|
||||
pkg = nopkg
|
||||
}
|
||||
if s := pkg.Syms[string(name)]; s != nil {
|
||||
return s
|
||||
}
|
||||
str := internString(name)
|
||||
return pkg.Lookup(str)
|
||||
}
|
||||
|
||||
func Pkglookup(name string, pkg *Pkg) *Sym {
|
||||
h := stringhash(name) % NHASH
|
||||
c := int(name[0])
|
||||
for s := hash[h]; s != nil; s = s.Link {
|
||||
if int(s.Name[0]) != c || s.Pkg != pkg {
|
||||
continue
|
||||
}
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
s := new(Sym)
|
||||
s.Name = name
|
||||
|
||||
s.Pkg = pkg
|
||||
|
||||
s.Link = hash[h]
|
||||
hash[h] = s
|
||||
s.Lexical = LNAME
|
||||
|
||||
return s
|
||||
return pkg.Lookup(name)
|
||||
}
|
||||
|
||||
func restrictlookup(name string, pkg *Pkg) *Sym {
|
||||
@ -335,35 +335,29 @@ func restrictlookup(name string, pkg *Pkg) *Sym {
|
||||
// find all the exported symbols in package opkg
|
||||
// and make them available in the current package
|
||||
func importdot(opkg *Pkg, pack *Node) {
|
||||
var s *Sym
|
||||
var s1 *Sym
|
||||
var pkgerror string
|
||||
|
||||
n := 0
|
||||
for h := uint32(0); h < NHASH; h++ {
|
||||
for s = hash[h]; s != nil; s = s.Link {
|
||||
if s.Pkg != opkg {
|
||||
continue
|
||||
}
|
||||
if s.Def == nil {
|
||||
continue
|
||||
}
|
||||
if !exportname(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
|
||||
continue
|
||||
}
|
||||
s1 = Lookup(s.Name)
|
||||
if s1.Def != nil {
|
||||
pkgerror = fmt.Sprintf("during import %q", opkg.Path)
|
||||
redeclare(s1, pkgerror)
|
||||
continue
|
||||
}
|
||||
|
||||
s1.Def = s.Def
|
||||
s1.Block = s.Block
|
||||
s1.Def.Pack = pack
|
||||
s1.Origpkg = opkg
|
||||
n++
|
||||
for _, s := range opkg.Syms {
|
||||
if s.Def == nil {
|
||||
continue
|
||||
}
|
||||
if !exportname(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
|
||||
continue
|
||||
}
|
||||
s1 = Lookup(s.Name)
|
||||
if s1.Def != nil {
|
||||
pkgerror = fmt.Sprintf("during import %q", opkg.Path)
|
||||
redeclare(s1, pkgerror)
|
||||
continue
|
||||
}
|
||||
|
||||
s1.Def = s.Def
|
||||
s1.Block = s.Block
|
||||
s1.Def.Pack = pack
|
||||
s1.Origpkg = opkg
|
||||
n++
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
@ -3583,19 +3577,19 @@ func pathtoprefix(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
var pkgMap = make(map[string]*Pkg)
|
||||
var pkgs []*Pkg
|
||||
|
||||
func mkpkg(path string) *Pkg {
|
||||
h := int(stringhash(path) & uint32(len(phash)-1))
|
||||
for p := phash[h]; p != nil; p = p.Link {
|
||||
if p.Path == path {
|
||||
return p
|
||||
}
|
||||
if p := pkgMap[path]; p != nil {
|
||||
return p
|
||||
}
|
||||
|
||||
p := new(Pkg)
|
||||
p.Path = path
|
||||
p.Prefix = pathtoprefix(path)
|
||||
p.Link = phash[h]
|
||||
phash[h] = p
|
||||
pkgMap[path] = p
|
||||
pkgs = append(pkgs, p)
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -2659,21 +2659,16 @@ toomany:
|
||||
/*
|
||||
* type check composite
|
||||
*/
|
||||
func fielddup(n *Node, hash []*Node) {
|
||||
func fielddup(n *Node, hash map[string]bool) {
|
||||
if n.Op != ONAME {
|
||||
Fatal("fielddup: not ONAME")
|
||||
}
|
||||
s := n.Sym.Name
|
||||
h := uint(stringhash(s) % uint32(len(hash)))
|
||||
for a := hash[h]; a != nil; a = a.Ntest {
|
||||
if a.Sym.Name == s {
|
||||
Yyerror("duplicate field name in struct literal: %s", s)
|
||||
return
|
||||
}
|
||||
name := n.Sym.Name
|
||||
if hash[name] {
|
||||
Yyerror("duplicate field name in struct literal: %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
n.Ntest = hash[h]
|
||||
hash[h] = n
|
||||
hash[name] = true
|
||||
}
|
||||
|
||||
func keydup(n *Node, hash []*Node) {
|
||||
@ -3019,8 +3014,7 @@ func typecheckcomplit(np **Node) {
|
||||
Yyerror("too few values in struct initializer")
|
||||
}
|
||||
} else {
|
||||
var autohash [101]*Node
|
||||
hash := inithash(n, autohash[:])
|
||||
hash := make(map[string]bool)
|
||||
|
||||
// keyed list
|
||||
var s *Sym
|
||||
|
@ -1226,7 +1226,7 @@ yydefault:
|
||||
{
|
||||
if importpkg.Name == "" {
|
||||
importpkg.Name = yyDollar[2].sym.Name
|
||||
Pkglookup(yyDollar[2].sym.Name, nil).Npkg++
|
||||
numImport[yyDollar[2].sym.Name]++
|
||||
} else if importpkg.Name != yyDollar[2].sym.Name {
|
||||
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, yyDollar[2].sym.Name, importpkg.Path)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user