mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile, etc: handle many struct fields
This adds 8 bytes of binary size to every type that has methods. It is the smallest change I could come up with for 1.7. Fixes #16037 Change-Id: Ibe15c3165854a21768596967757864b880dbfeed Reviewed-on: https://go-review.googlesource.com/24070 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
53242e49b1
commit
af0fc83985
5 changed files with 85 additions and 9 deletions
|
|
@ -75,7 +75,7 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
|
|||
if t.Sym == nil && len(methods(t)) == 0 {
|
||||
return 0
|
||||
}
|
||||
return 4 + 2 + 2
|
||||
return 4 + 2 + 2 + 4 + 4
|
||||
}
|
||||
|
||||
func makefield(name string, t *Type) *Field {
|
||||
|
|
@ -604,17 +604,19 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
|
|||
|
||||
ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
|
||||
|
||||
dataAdd += 4 + 2 + 2
|
||||
dataAdd += uncommonSize(t)
|
||||
mcount := len(m)
|
||||
if mcount != int(uint16(mcount)) {
|
||||
Fatalf("too many methods on %s: %d", t, mcount)
|
||||
}
|
||||
if dataAdd != int(uint16(dataAdd)) {
|
||||
if dataAdd != int(uint32(dataAdd)) {
|
||||
Fatalf("methods are too far away on %s: %d", t, dataAdd)
|
||||
}
|
||||
|
||||
ot = duint16(s, ot, uint16(mcount))
|
||||
ot = duint16(s, ot, uint16(dataAdd))
|
||||
ot = duint16(s, ot, 0)
|
||||
ot = duint32(s, ot, uint32(dataAdd))
|
||||
ot = duint32(s, ot, 0)
|
||||
return ot
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func decode_inuxi(p []byte, sz int) uint64 {
|
|||
|
||||
func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
|
||||
func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
|
||||
func uncommonSize() int { return 4 + 2 + 2 } // runtime.uncommontype
|
||||
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_kind(s *LSym) uint8 {
|
||||
|
|
@ -362,7 +362,7 @@ func decodetype_methods(s *LSym) []methodsig {
|
|||
}
|
||||
|
||||
mcount := int(decode_inuxi(s.P[off+4:], 2))
|
||||
moff := int(decode_inuxi(s.P[off+4+2:], 2))
|
||||
moff := int(decode_inuxi(s.P[off+4+2+2:], 4))
|
||||
off += moff // offset to array of reflect.method values
|
||||
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
||||
return decode_methodsig(s, off, sizeofMethod, mcount)
|
||||
|
|
|
|||
|
|
@ -313,7 +313,9 @@ type method struct {
|
|||
type uncommonType struct {
|
||||
pkgPath nameOff // import path; empty for built-in types like int, string
|
||||
mcount uint16 // number of methods
|
||||
moff uint16 // offset from this uncommontype to [mcount]method
|
||||
_ uint16 // unused
|
||||
moff uint32 // offset from this uncommontype to [mcount]method
|
||||
_ uint32 // unused
|
||||
}
|
||||
|
||||
// ChanDir represents a channel type's direction.
|
||||
|
|
@ -2584,7 +2586,7 @@ func StructOf(fields []StructField) Type {
|
|||
panic("reflect.StructOf: too many methods")
|
||||
}
|
||||
ut.mcount = uint16(len(methods))
|
||||
ut.moff = uint16(unsafe.Sizeof(uncommonType{}))
|
||||
ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
|
||||
|
||||
if len(fs) > 0 {
|
||||
repr = append(repr, ' ')
|
||||
|
|
|
|||
|
|
@ -323,7 +323,9 @@ type method struct {
|
|||
type uncommontype struct {
|
||||
pkgpath nameOff
|
||||
mcount uint16 // number of methods
|
||||
moff uint16 // offset from this uncommontype to [mcount]method
|
||||
_ uint16 // unused
|
||||
moff uint32 // offset from this uncommontype to [mcount]method
|
||||
_ uint32 // unused
|
||||
}
|
||||
|
||||
type imethod struct {
|
||||
|
|
|
|||
70
test/fixedbugs/issue16037_run.go
Normal file
70
test/fixedbugs/issue16037_run.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// +build !nacl,!android
|
||||
// run
|
||||
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var tmpl = template.Must(template.New("main").Parse(`
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
{{range .Names}}
|
||||
{{.Name}} *string
|
||||
{{end}}
|
||||
}
|
||||
|
||||
{{range .Names}}
|
||||
func (t *T) Get{{.Name}}() string {
|
||||
if t.{{.Name}} == nil {
|
||||
return ""
|
||||
}
|
||||
return *t.{{.Name}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
func main() {}
|
||||
`))
|
||||
|
||||
func main() {
|
||||
const n = 5000
|
||||
|
||||
type Name struct{ Name string }
|
||||
var t struct{ Names []Name }
|
||||
for i := 0; i < n; i++ {
|
||||
t.Names = append(t.Names, Name{Name: fmt.Sprintf("H%06X", i)})
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := tmpl.Execute(buf, t); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "issue16037-")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
path := filepath.Join(dir, "ridiculous_number_of_fields.go")
|
||||
if err := ioutil.WriteFile(path, buf.Bytes(), 0664); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
out, err := exec.Command("go", "build", "-o="+filepath.Join(dir, "out"), path).CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatalf("build failed: %v\n%s", err, out)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue