mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
10 changed files with 118 additions and 160 deletions
|
|
@ -372,12 +372,9 @@ func dumpexport() {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(bout, "\n")
|
fmt.Fprintf(bout, "\n")
|
||||||
|
|
||||||
var p *Pkg
|
for _, p := range pkgs {
|
||||||
for i := int32(0); i < int32(len(phash)); i++ {
|
if p.Direct != 0 {
|
||||||
for p = phash[i]; p != nil; p = p.Link {
|
dumppkg(p)
|
||||||
if p.Direct != 0 {
|
|
||||||
dumppkg(p)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,6 +429,8 @@ func pkgtype(s *Sym) *Type {
|
||||||
return s.Def.Type
|
return s.Def.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var numImport = make(map[string]int)
|
||||||
|
|
||||||
func importimport(s *Sym, path string) {
|
func importimport(s *Sym, path string) {
|
||||||
// Informational: record package name
|
// Informational: record package name
|
||||||
// associated with import path, for use in
|
// associated with import path, for use in
|
||||||
|
|
@ -443,7 +442,7 @@ func importimport(s *Sym, path string) {
|
||||||
p := mkpkg(path)
|
p := mkpkg(path)
|
||||||
if p.Name == "" {
|
if p.Name == "" {
|
||||||
p.Name = s.Name
|
p.Name = s.Name
|
||||||
Pkglookup(s.Name, nil).Npkg++
|
numImport[s.Name]++
|
||||||
} else if p.Name != s.Name {
|
} else if p.Name != s.Name {
|
||||||
Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
|
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 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)
|
return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
|
||||||
}
|
}
|
||||||
var fp string
|
var fp string
|
||||||
|
|
|
||||||
|
|
@ -110,11 +110,11 @@ type Pkg struct {
|
||||||
Path string
|
Path string
|
||||||
Pathsym *Sym
|
Pathsym *Sym
|
||||||
Prefix string
|
Prefix string
|
||||||
Link *Pkg
|
|
||||||
Imported uint8
|
Imported uint8
|
||||||
Exported int8
|
Exported int8
|
||||||
Direct int8
|
Direct int8
|
||||||
Safe bool
|
Safe bool
|
||||||
|
Syms map[string]*Sym
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sym struct {
|
type Sym struct {
|
||||||
|
|
@ -122,7 +122,6 @@ type Sym struct {
|
||||||
Flags uint8
|
Flags uint8
|
||||||
Sym uint8
|
Sym uint8
|
||||||
Link *Sym
|
Link *Sym
|
||||||
Npkg int32
|
|
||||||
Uniqgen uint32
|
Uniqgen uint32
|
||||||
Importdef *Pkg
|
Importdef *Pkg
|
||||||
Linkname string
|
Linkname string
|
||||||
|
|
@ -753,8 +752,6 @@ var debugstr string
|
||||||
|
|
||||||
var Debug_checknil int
|
var Debug_checknil int
|
||||||
|
|
||||||
var hash [NHASH]*Sym
|
|
||||||
|
|
||||||
var importmyname *Sym // my name for package
|
var importmyname *Sym // my name for package
|
||||||
|
|
||||||
var localpkg *Pkg // package being compiled
|
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 rawpkg *Pkg // fake package for raw symbol names
|
||||||
|
|
||||||
var phash [128]*Pkg
|
|
||||||
|
|
||||||
var Tptr int // either TPTR32 or TPTR64
|
var Tptr int // either TPTR32 or TPTR64
|
||||||
|
|
||||||
var myimportpath string
|
var myimportpath string
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ import_package:
|
||||||
{
|
{
|
||||||
if importpkg.Name == "" {
|
if importpkg.Name == "" {
|
||||||
importpkg.Name = $2.Name;
|
importpkg.Name = $2.Name;
|
||||||
Pkglookup($2.Name, nil).Npkg++;
|
numImport[$2.Name]++
|
||||||
} else if importpkg.Name != $2.Name {
|
} else if importpkg.Name != $2.Name {
|
||||||
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, $2.Name, importpkg.Path);
|
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
|
// are there any imported init functions
|
||||||
for h := uint32(0); h < NHASH; h++ {
|
for _, s := range initSyms {
|
||||||
for s = hash[h]; s != nil; s = s.Link {
|
if s.Def != nil {
|
||||||
if s.Name[0] != 'i' || s.Name != "init" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if s.Def == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,22 +155,10 @@ func fninit(n *NodeList) {
|
||||||
r = list(r, a)
|
r = list(r, a)
|
||||||
|
|
||||||
// (7)
|
// (7)
|
||||||
var s *Sym
|
for _, s := range initSyms {
|
||||||
for h := uint32(0); h < NHASH; h++ {
|
if s.Def != nil && s != initsym {
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// could check that it is fn of no args/returns
|
// could check that it is fn of no args/returns
|
||||||
a = Nod(OCALL, s.Def, nil)
|
a = Nod(OCALL, s.Def, nil)
|
||||||
|
|
||||||
r = list(r, a)
|
r = list(r, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -188,7 +170,7 @@ func fninit(n *NodeList) {
|
||||||
// could check that it is fn of no args/returns
|
// could check that it is fn of no args/returns
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
namebuf = fmt.Sprintf("init.%d", i)
|
namebuf = fmt.Sprintf("init.%d", i)
|
||||||
s = Lookup(namebuf)
|
s := Lookup(namebuf)
|
||||||
if s.Def == nil {
|
if s.Def == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1377,7 +1377,7 @@ talph:
|
||||||
cp = nil
|
cp = nil
|
||||||
ungetc(c)
|
ungetc(c)
|
||||||
|
|
||||||
s = Lookup(lexbuf.String())
|
s = LookupBytes(lexbuf.Bytes())
|
||||||
switch s.Lexical {
|
switch s.Lexical {
|
||||||
case LIGNORE:
|
case LIGNORE:
|
||||||
goto l0
|
goto l0
|
||||||
|
|
@ -3120,36 +3120,33 @@ func mkpackage(pkgname string) {
|
||||||
if pkgname != localpkg.Name {
|
if pkgname != localpkg.Name {
|
||||||
Yyerror("package %s; expected %s", pkgname, localpkg.Name)
|
Yyerror("package %s; expected %s", pkgname, localpkg.Name)
|
||||||
}
|
}
|
||||||
var s *Sym
|
for _, s := range localpkg.Syms {
|
||||||
for h := int32(0); h < NHASH; h++ {
|
if s.Def == nil {
|
||||||
for s = hash[h]; s != nil; s = s.Link {
|
continue
|
||||||
if s.Def == nil || s.Pkg != localpkg {
|
}
|
||||||
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 {
|
s.Def = nil
|
||||||
// throw away top-level package name leftover
|
continue
|
||||||
// from previous file.
|
}
|
||||||
// leave s->block set to cause redeclaration
|
|
||||||
// errors if a conflicting top-level name is
|
if s.Def.Sym != s {
|
||||||
// introduced by a different file.
|
// throw away top-level name left over
|
||||||
if s.Def.Used == 0 && nsyntaxerrors == 0 {
|
// from previous import . "x"
|
||||||
pkgnotused(int(s.Def.Lineno), s.Def.Pkg.Path, s.Name)
|
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 = nil
|
s.Def.Pack.Used = 1
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Def.Sym != s {
|
s.Def = nil
|
||||||
// throw away top-level name left over
|
continue
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1246,12 +1246,9 @@ func dumptypestructs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate import strings for imported packages
|
// generate import strings for imported packages
|
||||||
var p *Pkg
|
for _, p := range pkgs {
|
||||||
for i := 0; i < len(phash); i++ {
|
if p.Direct != 0 {
|
||||||
for p = phash[i]; p != nil; p = p.Link {
|
dimportpath(p)
|
||||||
if p.Direct != 0 {
|
|
||||||
dimportpath(p)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -275,54 +275,54 @@ func setlineno(n *Node) int32 {
|
||||||
return lno
|
return lno
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringhash(p string) uint32 {
|
func Lookup(name string) *Sym {
|
||||||
var c int
|
return localpkg.Lookup(name)
|
||||||
|
|
||||||
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 {
|
func LookupBytes(name []byte) *Sym {
|
||||||
return Pkglookup(name, localpkg)
|
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 {
|
func Pkglookup(name string, pkg *Pkg) *Sym {
|
||||||
h := stringhash(name) % NHASH
|
return pkg.Lookup(name)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func restrictlookup(name string, pkg *Pkg) *Sym {
|
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
|
// find all the exported symbols in package opkg
|
||||||
// and make them available in the current package
|
// and make them available in the current package
|
||||||
func importdot(opkg *Pkg, pack *Node) {
|
func importdot(opkg *Pkg, pack *Node) {
|
||||||
var s *Sym
|
|
||||||
var s1 *Sym
|
var s1 *Sym
|
||||||
var pkgerror string
|
var pkgerror string
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
for h := uint32(0); h < NHASH; h++ {
|
for _, s := range opkg.Syms {
|
||||||
for s = hash[h]; s != nil; s = s.Link {
|
if s.Def == nil {
|
||||||
if s.Pkg != opkg {
|
continue
|
||||||
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++
|
|
||||||
}
|
}
|
||||||
|
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 {
|
if n == 0 {
|
||||||
|
|
@ -3583,19 +3577,19 @@ func pathtoprefix(s string) string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pkgMap = make(map[string]*Pkg)
|
||||||
|
var pkgs []*Pkg
|
||||||
|
|
||||||
func mkpkg(path string) *Pkg {
|
func mkpkg(path string) *Pkg {
|
||||||
h := int(stringhash(path) & uint32(len(phash)-1))
|
if p := pkgMap[path]; p != nil {
|
||||||
for p := phash[h]; p != nil; p = p.Link {
|
return p
|
||||||
if p.Path == path {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p := new(Pkg)
|
p := new(Pkg)
|
||||||
p.Path = path
|
p.Path = path
|
||||||
p.Prefix = pathtoprefix(path)
|
p.Prefix = pathtoprefix(path)
|
||||||
p.Link = phash[h]
|
pkgMap[path] = p
|
||||||
phash[h] = p
|
pkgs = append(pkgs, p)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2659,21 +2659,16 @@ toomany:
|
||||||
/*
|
/*
|
||||||
* type check composite
|
* type check composite
|
||||||
*/
|
*/
|
||||||
func fielddup(n *Node, hash []*Node) {
|
func fielddup(n *Node, hash map[string]bool) {
|
||||||
if n.Op != ONAME {
|
if n.Op != ONAME {
|
||||||
Fatal("fielddup: not ONAME")
|
Fatal("fielddup: not ONAME")
|
||||||
}
|
}
|
||||||
s := n.Sym.Name
|
name := n.Sym.Name
|
||||||
h := uint(stringhash(s) % uint32(len(hash)))
|
if hash[name] {
|
||||||
for a := hash[h]; a != nil; a = a.Ntest {
|
Yyerror("duplicate field name in struct literal: %s", name)
|
||||||
if a.Sym.Name == s {
|
return
|
||||||
Yyerror("duplicate field name in struct literal: %s", s)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hash[name] = true
|
||||||
n.Ntest = hash[h]
|
|
||||||
hash[h] = n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func keydup(n *Node, hash []*Node) {
|
func keydup(n *Node, hash []*Node) {
|
||||||
|
|
@ -3019,8 +3014,7 @@ func typecheckcomplit(np **Node) {
|
||||||
Yyerror("too few values in struct initializer")
|
Yyerror("too few values in struct initializer")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var autohash [101]*Node
|
hash := make(map[string]bool)
|
||||||
hash := inithash(n, autohash[:])
|
|
||||||
|
|
||||||
// keyed list
|
// keyed list
|
||||||
var s *Sym
|
var s *Sym
|
||||||
|
|
|
||||||
|
|
@ -1226,7 +1226,7 @@ yydefault:
|
||||||
{
|
{
|
||||||
if importpkg.Name == "" {
|
if importpkg.Name == "" {
|
||||||
importpkg.Name = yyDollar[2].sym.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 {
|
} 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)
|
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, yyDollar[2].sym.Name, importpkg.Path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue