1
0
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:
Russ Cox 2015-03-02 16:21:15 -05:00
parent bed1f90d08
commit d0b59deb71
10 changed files with 118 additions and 160 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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
}

View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}