Commit 37d452c3 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: reduce allocs to c85b77c2 (pre-fmt.go change) levels

Linker and reflect info generation (reflect.go) relies on formatting
of types (tconv). The fmt.Format based approach introduces extra
allocations, which matter in those cases. Resurrected sconv and tconv
code from commit c85b77c2 (fmt.go only); and adjusted it slightly.
The formatter-based approach is still used throughout the rest of the
compiler, but reflect.go now uses the tconv method that simply returns
the desired string.

(The timing data below may not be accurate; I've included it only for
comparison with the numbers in issue #16897).

name       old time/op     new time/op     delta
Template       297ms ± 2%      288ms ± 3%  -3.12%        (p=0.000 n=27+29)
Unicode        155ms ± 5%      150ms ± 5%  -3.26%        (p=0.000 n=30+30)
GoTypes        1.00s ± 3%      0.95s ± 3%  -4.51%        (p=0.000 n=28+29)

name       old alloc/op    new alloc/op    delta
Template      46.8MB ± 0%     46.5MB ± 0%  -0.65%        (p=0.000 n=28+30)
Unicode       37.9MB ± 0%     37.8MB ± 0%  -0.24%        (p=0.000 n=29+30)
GoTypes        144MB ± 0%      143MB ± 0%  -0.68%        (p=0.000 n=30+30)

name       old allocs/op   new allocs/op   delta
Template        469k ± 0%       446k ± 0%  -5.01%        (p=0.000 n=29+30)
Unicode         375k ± 0%       369k ± 0%  -1.62%        (p=0.000 n=30+28)
GoTypes        1.47M ± 0%      1.37M ± 0%  -6.29%        (p=0.000 n=30+30)

The code for sconv/tconv in fmt.go now closely match the code from c85b77c2
again; except that the functions are now methods. Removing the use of
the bytes.Buffer in tconv and special-caseing interface{} has helped a
small amount as well:

name       old time/op     new time/op     delta
Template       299ms ± 3%      288ms ± 3%  -3.83%        (p=0.000 n=29+29)
Unicode        156ms ± 5%      150ms ± 5%  -3.56%        (p=0.000 n=30+30)
GoTypes        960ms ± 2%      954ms ± 3%  -0.58%        (p=0.037 n=26+29)

name       old alloc/op    new alloc/op    delta
Template      46.6MB ± 0%     46.5MB ± 0%  -0.22%        (p=0.000 n=30+30)
Unicode       37.8MB ± 0%     37.8MB ± 0%    ~           (p=0.075 n=30+30)
GoTypes        143MB ± 0%      143MB ± 0%  -0.31%        (p=0.000 n=30+30)

name       old allocs/op   new allocs/op   delta
Template        447k ± 0%       446k ± 0%  -0.28%        (p=0.000 n=30+30)
Unicode         369k ± 0%       369k ± 0%  -0.03%        (p=0.032 n=30+28)
GoTypes        1.38M ± 0%      1.37M ± 0%  -0.35%        (p=0.000 n=29+30)

Comparison between c85b77c2 and now (see issue #16897):

name       old time/op     new time/op     delta
Template       307ms ± 4%      288ms ± 3%  -6.24%  (p=0.000 n=29+29)
Unicode        164ms ± 4%      150ms ± 5%  -8.20%  (p=0.000 n=30+30)
GoTypes        1.01s ± 3%      0.95s ± 3%  -5.72%  (p=0.000 n=30+29)

name       old alloc/op    new alloc/op    delta
Template      46.8MB ± 0%     46.5MB ± 0%  -0.66%  (p=0.000 n=29+30)
Unicode       37.8MB ± 0%     37.8MB ± 0%  -0.13%  (p=0.000 n=30+30)
GoTypes        143MB ± 0%      143MB ± 0%  -0.11%  (p=0.000 n=30+30)

name       old allocs/op   new allocs/op   delta
Template        444k ± 0%       446k ± 0%  +0.48%  (p=0.000 n=30+30)
Unicode         369k ± 0%       369k ± 0%  +0.09%  (p=0.000 n=30+28)
GoTypes        1.35M ± 0%      1.37M ± 0%  +1.47%  (p=0.000 n=30+30)

There's still a small increase (< 1.5%) for GoTypes but pending a complete
rewrite of fmt.go, this seems ok again.

Fixes #16897.

Change-Id: I7e0e56cd1b9f981252eded917f5752259d402354
Reviewed-on: https://go-review.googlesource.com/29087
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent c345a391
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package gc package gc
import ( import (
"bytes"
"cmd/internal/obj" "cmd/internal/obj"
"fmt" "fmt"
"strconv" "strconv"
...@@ -506,34 +507,28 @@ func (et EType) String() string { ...@@ -506,34 +507,28 @@ func (et EType) String() string {
return fmt.Sprintf("E-%d", et) return fmt.Sprintf("E-%d", et)
} }
func (s *Sym) symfmt(f fmt.State, flag FmtFlag) { func (s *Sym) symfmt(flag FmtFlag) string {
if s.Pkg != nil && flag&FmtShort == 0 { if s.Pkg != nil && flag&FmtShort == 0 {
switch fmtmode { switch fmtmode {
case FErr: // This is for the user case FErr: // This is for the user
if s.Pkg == builtinpkg || s.Pkg == localpkg { if s.Pkg == builtinpkg || s.Pkg == localpkg {
fmt.Fprint(f, s.Name) return s.Name
return
} }
// 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 != "" && numImport[s.Pkg.Name] > 1 { if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
fmt.Fprintf(f, "%q.%s", s.Pkg.Path, s.Name) return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
return
} }
fmt.Fprint(f, s.Pkg.Name+"."+s.Name) return s.Pkg.Name + "." + s.Name
return
case FDbg: case FDbg:
fmt.Fprint(f, s.Pkg.Name+"."+s.Name) return s.Pkg.Name + "." + s.Name
return
case FTypeId: case FTypeId:
if flag&FmtUnsigned != 0 { if flag&FmtUnsigned != 0 {
fmt.Fprint(f, s.Pkg.Name+"."+s.Name) // dcommontype, typehash return s.Pkg.Name + "." + s.Name // dcommontype, typehash
return
} }
fmt.Fprint(f, s.Pkg.Prefix+"."+s.Name) // (methodsym), typesym, weaksym return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
return
} }
} }
...@@ -546,15 +541,13 @@ func (s *Sym) symfmt(f fmt.State, flag FmtFlag) { ...@@ -546,15 +541,13 @@ func (s *Sym) symfmt(f fmt.State, flag FmtFlag) {
} }
if fmtmode == FDbg { if fmtmode == FDbg {
fmt.Fprintf(f, "@%q.%s", s.Pkg.Path, name) return fmt.Sprintf("@%q.%s", s.Pkg.Path, name)
return
} }
fmt.Fprint(f, name) return name
return
} }
fmt.Fprint(f, s.Name) return s.Name
} }
var basicnames = []string{ var basicnames = []string{
...@@ -581,24 +574,21 @@ var basicnames = []string{ ...@@ -581,24 +574,21 @@ var basicnames = []string{
TBLANK: "blank", TBLANK: "blank",
} }
func (t *Type) typefmt(s fmt.State, flag FmtFlag) { func (t *Type) typefmt(flag FmtFlag) string {
if t == nil { if t == nil {
fmt.Fprint(s, "<T>") return "<T>"
return
} }
if t == bytetype || t == runetype { if t == bytetype || t == runetype {
// in %-T mode collapse rune and byte with their originals. // in %-T mode collapse rune and byte with their originals.
if fmtmode != FTypeId { if fmtmode != FTypeId {
fmt.Fprintf(s, "%S", t.Sym) return t.Sym.sconv(FmtShort)
return
} }
t = Types[t.Etype] t = Types[t.Etype]
} }
if t == errortype { if t == errortype {
fmt.Fprint(s, "error") return "error"
return
} }
// Unless the 'l' flag was specified, if the type has a name, just print that name. // Unless the 'l' flag was specified, if the type has a name, just print that name.
...@@ -607,127 +597,127 @@ func (t *Type) typefmt(s fmt.State, flag FmtFlag) { ...@@ -607,127 +597,127 @@ func (t *Type) typefmt(s fmt.State, flag FmtFlag) {
case FTypeId: case FTypeId:
if flag&FmtShort != 0 { if flag&FmtShort != 0 {
if t.Vargen != 0 { if t.Vargen != 0 {
fmt.Fprintf(s, "%S·%d", t.Sym, t.Vargen) return fmt.Sprintf("%v·%d", t.Sym.sconv(FmtShort), t.Vargen)
return
} }
fmt.Fprintf(s, "%S", t.Sym) return t.Sym.sconv(FmtShort)
return
} }
if flag&FmtUnsigned != 0 { if flag&FmtUnsigned != 0 {
fmt.Fprintf(s, "% v", t.Sym) return t.Sym.sconv(FmtUnsigned)
return
} }
if t.Sym.Pkg == localpkg && t.Vargen != 0 { if t.Sym.Pkg == localpkg && t.Vargen != 0 {
fmt.Fprintf(s, "%v·%d", t.Sym, t.Vargen) return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
return
} }
} }
fmt.Fprint(s, t.Sym) return t.Sym.String()
return
} }
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" { if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
prefix := ""
if fmtmode == FErr && (t == idealbool || t == idealstring) { if fmtmode == FErr && (t == idealbool || t == idealstring) {
fmt.Fprint(s, "untyped ") prefix = "untyped "
} }
fmt.Fprint(s, basicnames[t.Etype]) return prefix + basicnames[t.Etype]
return
} }
if fmtmode == FDbg { if fmtmode == FDbg {
fmtmode = 0 fmtmode = 0
fmt.Fprintf(s, "%v-", t.Etype) str := t.Etype.String() + "-" + t.typefmt(flag)
t.typefmt(s, flag)
fmtmode = FDbg fmtmode = FDbg
return return str
} }
switch t.Etype { switch t.Etype {
case TPTR32, TPTR64: case TPTR32, TPTR64:
if fmtmode == FTypeId && (flag&FmtShort != 0) { if fmtmode == FTypeId && (flag&FmtShort != 0) {
fmt.Fprintf(s, "*%S", t.Elem()) return "*" + t.Elem().tconv(FmtShort)
return
} }
fmt.Fprint(s, "*"+t.Elem().String()) return "*" + t.Elem().String()
case TARRAY: case TARRAY:
if t.isDDDArray() { if t.isDDDArray() {
fmt.Fprint(s, "[...]"+t.Elem().String()) return "[...]" + t.Elem().String()
return
} }
fmt.Fprintf(s, "[%d]%v", t.NumElem(), t.Elem()) return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
case TSLICE: case TSLICE:
fmt.Fprint(s, "[]"+t.Elem().String()) return "[]" + t.Elem().String()
case TCHAN: case TCHAN:
switch t.ChanDir() { switch t.ChanDir() {
case Crecv: case Crecv:
fmt.Fprint(s, "<-chan "+t.Elem().String()) return "<-chan " + t.Elem().String()
return
case Csend: case Csend:
fmt.Fprint(s, "chan<- "+t.Elem().String()) return "chan<- " + t.Elem().String()
return
} }
if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv { if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv {
fmt.Fprint(s, "chan ("+t.Elem().String()+")") return "chan (" + t.Elem().String() + ")"
return
} }
fmt.Fprint(s, "chan "+t.Elem().String()) return "chan " + t.Elem().String()
case TMAP: case TMAP:
fmt.Fprint(s, "map["+t.Key().String()+"]"+t.Val().String()) return "map[" + t.Key().String() + "]" + t.Val().String()
case TINTER: case TINTER:
fmt.Fprint(s, "interface {") if t.IsEmptyInterface() {
return "interface {}"
}
buf := make([]byte, 0, 64)
buf = append(buf, "interface {"...)
for i, f := range t.Fields().Slice() { for i, f := range t.Fields().Slice() {
if i != 0 { if i != 0 {
fmt.Fprint(s, ";") buf = append(buf, ';')
} }
fmt.Fprint(s, " ") buf = append(buf, ' ')
switch { switch {
case f.Sym == nil: case f.Sym == nil:
// Check first that a symbol is defined for this type. // Check first that a symbol is defined for this type.
// Wrong interface definitions may have types lacking a symbol. // Wrong interface definitions may have types lacking a symbol.
break break
case exportname(f.Sym.Name): case exportname(f.Sym.Name):
fmt.Fprintf(s, "%S", f.Sym) buf = append(buf, f.Sym.sconv(FmtShort)...)
default: default:
fmt.Fprintf(s, "% v", f.Sym) buf = append(buf, f.Sym.sconv(FmtUnsigned)...)
} }
fmt.Fprintf(s, "%S", f.Type) buf = append(buf, f.Type.tconv(FmtShort)...)
} }
if t.NumFields() != 0 { if t.NumFields() != 0 {
fmt.Fprint(s, " ") buf = append(buf, ' ')
} }
fmt.Fprint(s, "}") buf = append(buf, '}')
return string(buf)
case TFUNC: case TFUNC:
buf := make([]byte, 0, 64)
if flag&FmtShort != 0 { if flag&FmtShort != 0 {
// no leading func // no leading func
} else { } else {
if t.Recv() != nil { if t.Recv() != nil {
fmt.Fprintf(s, "method %v ", t.Recvs()) buf = append(buf, "method"...)
buf = append(buf, t.Recvs().String()...)
buf = append(buf, ' ')
} }
fmt.Fprint(s, "func") buf = append(buf, "func"...)
} }
fmt.Fprintf(s, "%v", t.Params()) buf = append(buf, t.Params().String()...)
switch t.Results().NumFields() { switch t.Results().NumFields() {
case 0: case 0:
// nothing to do // nothing to do
case 1: case 1:
fmt.Fprintf(s, " %v", t.Results().Field(0).Type) // struct->field->field's type buf = append(buf, ' ')
buf = append(buf, t.Results().Field(0).Type.String()...) // struct->field->field's type
default: default:
fmt.Fprintf(s, " %v", t.Results()) buf = append(buf, ' ')
buf = append(buf, t.Results().String()...)
} }
return string(buf)
case TSTRUCT: case TSTRUCT:
if m := t.StructType().Map; m != nil { if m := t.StructType().Map; m != nil {
...@@ -735,71 +725,68 @@ func (t *Type) typefmt(s fmt.State, flag FmtFlag) { ...@@ -735,71 +725,68 @@ func (t *Type) typefmt(s fmt.State, flag FmtFlag) {
// Format the bucket struct for map[x]y as map.bucket[x]y. // Format the bucket struct for map[x]y as map.bucket[x]y.
// This avoids a recursive print that generates very long names. // This avoids a recursive print that generates very long names.
if mt.Bucket == t { if mt.Bucket == t {
fmt.Fprint(s, "map.bucket["+m.Key().String()+"]"+m.Val().String()) return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
return
} }
if mt.Hmap == t { if mt.Hmap == t {
fmt.Fprint(s, "map.hdr["+m.Key().String()+"]"+m.Val().String()) return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
return
} }
if mt.Hiter == t { if mt.Hiter == t {
fmt.Fprint(s, "map.iter["+m.Key().String()+"]"+m.Val().String()) return "map.iter[" + m.Key().String() + "]" + m.Val().String()
return
} }
Yyerror("unknown internal map type") Yyerror("unknown internal map type")
} }
var buf bytes.Buffer
if t.IsFuncArgStruct() { if t.IsFuncArgStruct() {
fmt.Fprint(s, "(") buf.WriteString("(")
var flag1 FmtFlag var flag1 FmtFlag
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
flag1 = FmtShort flag1 = FmtShort
} }
for i, f := range t.Fields().Slice() { for i, f := range t.Fields().Slice() {
if i != 0 { if i != 0 {
fmt.Fprint(s, ", ") buf.WriteString(", ")
} }
fmt.Fprint(s, Fldconv(f, flag1)) buf.WriteString(Fldconv(f, flag1))
} }
fmt.Fprint(s, ")") buf.WriteString(")")
} else { } else {
fmt.Fprint(s, "struct {") buf.WriteString("struct {")
for i, f := range t.Fields().Slice() { for i, f := range t.Fields().Slice() {
if i != 0 { if i != 0 {
fmt.Fprint(s, ";") buf.WriteString(";")
} }
fmt.Fprint(s, " ") buf.WriteString(" ")
fmt.Fprint(s, Fldconv(f, FmtLong)) buf.WriteString(Fldconv(f, FmtLong))
} }
if t.NumFields() != 0 { if t.NumFields() != 0 {
fmt.Fprint(s, " ") buf.WriteString(" ")
} }
fmt.Fprint(s, "}") buf.WriteString("}")
} }
return buf.String()
case TFORW: case TFORW:
if t.Sym != nil { if t.Sym != nil {
fmt.Fprint(s, "undefined "+t.Sym.String()) return "undefined " + t.Sym.String()
return
} }
fmt.Fprint(s, "undefined") return "undefined"
case TUNSAFEPTR: case TUNSAFEPTR:
fmt.Fprint(s, "unsafe.Pointer") return "unsafe.Pointer"
case TDDDFIELD: case TDDDFIELD:
fmt.Fprintf(s, "%v <%v> %v", t.Etype, t.Sym, t.DDDField()) return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
case Txxx: case Txxx:
fmt.Fprint(s, "Txxx") return "Txxx"
}
default:
// Don't know how to handle - fall back to detailed prints. // Don't know how to handle - fall back to detailed prints.
fmt.Fprintf(s, "%v <%v> %v", t.Etype, t.Sym, t.Elem()) return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
}
} }
// Statements which may be rendered with a simplestmt as init. // Statements which may be rendered with a simplestmt as init.
...@@ -1573,7 +1560,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag) { ...@@ -1573,7 +1560,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
func (s *Sym) Format(f fmt.State, verb rune) { func (s *Sym) Format(f fmt.State, verb rune) {
switch verb { switch verb {
case 'v', 'S': case 'v', 'S':
s.sconv(f, fmtFlag(f, verb)) fmt.Fprint(f, s.sconv(fmtFlag(f, verb)))
default: default:
fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s) fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
...@@ -1581,34 +1568,33 @@ func (s *Sym) Format(f fmt.State, verb rune) { ...@@ -1581,34 +1568,33 @@ func (s *Sym) Format(f fmt.State, verb rune) {
} }
func (s *Sym) String() string { func (s *Sym) String() string {
return fmt.Sprint(s) return s.sconv(0)
} }
// "%S" suppresses qualifying with package // "%S" suppresses qualifying with package
func (s *Sym) sconv(f fmt.State, flag FmtFlag) { func (s *Sym) sconv(flag FmtFlag) string {
if flag&FmtLong != 0 { if flag&FmtLong != 0 {
panic("linksymfmt") panic("linksymfmt")
} }
if s == nil { if s == nil {
fmt.Fprint(f, "<S>") return "<S>"
return
} }
if s.Name == "_" { if s.Name == "_" {
fmt.Fprint(f, "_") return "_"
return
} }
sf := flag sf := flag
sm := setfmode(&flag) sm := setfmode(&flag)
s.symfmt(f, flag) str := s.symfmt(flag)
flag = sf flag = sf
fmtmode = sm fmtmode = sm
return str
} }
func (t *Type) String() string { func (t *Type) String() string {
return fmt.Sprint(t) return t.tconv(0)
} }
func Fldconv(f *Field, flag FmtFlag) string { func Fldconv(f *Field, flag FmtFlag) string {
...@@ -1689,7 +1675,7 @@ func Fldconv(f *Field, flag FmtFlag) string { ...@@ -1689,7 +1675,7 @@ func Fldconv(f *Field, flag FmtFlag) string {
func (t *Type) Format(s fmt.State, verb rune) { func (t *Type) Format(s fmt.State, verb rune) {
switch verb { switch verb {
case 'v', 'S', 'L': case 'v', 'S', 'L':
t.tconv(s, fmtFlag(s, verb)) fmt.Fprint(s, t.tconv(fmtFlag(s, verb)))
default: default:
fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t) fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
...@@ -1699,15 +1685,13 @@ func (t *Type) Format(s fmt.State, verb rune) { ...@@ -1699,15 +1685,13 @@ func (t *Type) Format(s fmt.State, verb rune) {
// "%L" print definition, not name // "%L" print definition, not name
// "%S" omit 'func' and receiver from function types, short type names // "%S" omit 'func' and receiver from function types, short type names
// "% v" package name, not prefix (FTypeId mode, sticky) // "% v" package name, not prefix (FTypeId mode, sticky)
func (t *Type) tconv(s fmt.State, flag FmtFlag) { func (t *Type) tconv(flag FmtFlag) string {
if t == nil { if t == nil {
fmt.Fprint(s, "<T>") return "<T>"
return
} }
if t.Trecur > 4 { if t.Trecur > 4 {
fmt.Fprint(s, "<...>") return "<...>"
return
} }
t.Trecur++ t.Trecur++
...@@ -1721,7 +1705,7 @@ func (t *Type) tconv(s fmt.State, flag FmtFlag) { ...@@ -1721,7 +1705,7 @@ func (t *Type) tconv(s fmt.State, flag FmtFlag) {
flag |= FmtUnsigned flag |= FmtUnsigned
} }
t.typefmt(s, flag) str := t.typefmt(flag)
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) { if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
fmtpkgpfx-- fmtpkgpfx--
...@@ -1730,6 +1714,7 @@ func (t *Type) tconv(s fmt.State, flag FmtFlag) { ...@@ -1730,6 +1714,7 @@ func (t *Type) tconv(s fmt.State, flag FmtFlag) {
flag = sf flag = sf
fmtmode = sm fmtmode = sm
t.Trecur-- t.Trecur--
return str
} }
func (n *Node) String() string { func (n *Node) String() string {
......
...@@ -864,7 +864,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -864,7 +864,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
} }
exported := false exported := false
p := fmt.Sprintf("%- v", t) p := t.tconv(FmtLeft | FmtUnsigned)
// If we're writing out type T, // If we're writing out type T,
// we are very likely to write out type *T as well. // we are very likely to write out type *T as well.
// Use the string "*T"[1:] for "T", so that the two // Use the string "*T"[1:] for "T", so that the two
...@@ -926,22 +926,22 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -926,22 +926,22 @@ func dcommontype(s *Sym, ot int, t *Type) int {
} }
func typesym(t *Type) *Sym { func typesym(t *Type) *Sym {
return Pkglookup(fmt.Sprintf("%-v", t), typepkg) return Pkglookup(t.tconv(FmtLeft), typepkg)
} }
// tracksym returns the symbol for tracking use of field/method f, assumed // tracksym returns the symbol for tracking use of field/method f, assumed
// to be a member of struct/interface type t. // to be a member of struct/interface type t.
func tracksym(t *Type, f *Field) *Sym { func tracksym(t *Type, f *Field) *Sym {
return Pkglookup(fmt.Sprintf("%-v.%s", t, f.Sym.Name), trackpkg) return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg)
} }
func typelinkLSym(t *Type) *obj.LSym { func typelinkLSym(t *Type) *obj.LSym {
name := fmt.Sprintf("go.typelink.%-v", t) // complete, unambiguous type name name := "go.typelink." + t.tconv(FmtLeft) // complete, unambiguous type name
return obj.Linklookup(Ctxt, name, 0) return obj.Linklookup(Ctxt, name, 0)
} }
func typesymprefix(prefix string, t *Type) *Sym { func typesymprefix(prefix string, t *Type) *Sym {
p := fmt.Sprintf("%s.%-v", prefix, t) p := prefix + "." + t.tconv(FmtLeft)
s := Pkglookup(p, typepkg) s := Pkglookup(p, typepkg)
//print("algsym: %s -> %+S\n", p, s); //print("algsym: %s -> %+S\n", p, s);
...@@ -981,7 +981,7 @@ func itabname(t, itype *Type) *Node { ...@@ -981,7 +981,7 @@ func itabname(t, itype *Type) *Node {
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
Fatalf("itabname(%v, %v)", t, itype) Fatalf("itabname(%v, %v)", t, itype)
} }
s := Pkglookup(fmt.Sprintf("%-v,%-v", t, itype), itabpkg) s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg)
if s.Def == nil { if s.Def == nil {
n := newname(s) n := newname(s)
n.Type = Types[TUINT8] n.Type = Types[TUINT8]
...@@ -1406,7 +1406,7 @@ func dumptypestructs() { ...@@ -1406,7 +1406,7 @@ func dumptypestructs() {
// method functions. None are allocated on heap, so we can use obj.NOPTR. // method functions. None are allocated on heap, so we can use obj.NOPTR.
ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR)) ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR))
ilink := Pkglookup(fmt.Sprintf("%-v,%-v", i.t, i.itype), itablinkpkg) ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg)
dsymptr(ilink, 0, i.sym, 0) dsymptr(ilink, 0, i.sym, 0)
ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA)) ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment