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 {
|
if t.Sym == nil && len(methods(t)) == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return 4 + 2 + 2
|
return 4 + 2 + 2 + 4 + 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func makefield(name string, t *Type) *Field {
|
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))
|
ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
|
||||||
|
|
||||||
dataAdd += 4 + 2 + 2
|
dataAdd += uncommonSize(t)
|
||||||
mcount := len(m)
|
mcount := len(m)
|
||||||
if mcount != int(uint16(mcount)) {
|
if mcount != int(uint16(mcount)) {
|
||||||
Fatalf("too many methods on %s: %d", t, 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)
|
Fatalf("methods are too far away on %s: %d", t, dataAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
ot = duint16(s, ot, uint16(mcount))
|
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
|
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 commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
|
||||||
func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
|
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
|
// Type.commonType.kind
|
||||||
func decodetype_kind(s *LSym) uint8 {
|
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))
|
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
|
off += moff // offset to array of reflect.method values
|
||||||
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
||||||
return decode_methodsig(s, off, sizeofMethod, mcount)
|
return decode_methodsig(s, off, sizeofMethod, mcount)
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,9 @@ type method struct {
|
||||||
type uncommonType struct {
|
type uncommonType struct {
|
||||||
pkgPath nameOff // import path; empty for built-in types like int, string
|
pkgPath nameOff // import path; empty for built-in types like int, string
|
||||||
mcount uint16 // number of methods
|
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.
|
// ChanDir represents a channel type's direction.
|
||||||
|
|
@ -2584,7 +2586,7 @@ func StructOf(fields []StructField) Type {
|
||||||
panic("reflect.StructOf: too many methods")
|
panic("reflect.StructOf: too many methods")
|
||||||
}
|
}
|
||||||
ut.mcount = uint16(len(methods))
|
ut.mcount = uint16(len(methods))
|
||||||
ut.moff = uint16(unsafe.Sizeof(uncommonType{}))
|
ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
|
||||||
|
|
||||||
if len(fs) > 0 {
|
if len(fs) > 0 {
|
||||||
repr = append(repr, ' ')
|
repr = append(repr, ' ')
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,9 @@ type method struct {
|
||||||
type uncommontype struct {
|
type uncommontype struct {
|
||||||
pkgpath nameOff
|
pkgpath nameOff
|
||||||
mcount uint16 // number of methods
|
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 {
|
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