diff options
author | David Crawshaw <crawshaw@golang.org> | 2016-06-14 10:20:11 -0400 |
---|---|---|
committer | David Crawshaw <crawshaw@golang.org> | 2016-06-14 15:32:34 +0000 |
commit | af0fc83985860776551d15be3a8fefde35514bcb (patch) | |
tree | 8d3448bd28b0cc6deaf8ef74b3e36199be609d2e | |
parent | 53242e49b127ede6d7b258c7e90c39a5afa70c25 (diff) | |
download | go-af0fc83985860776551d15be3a8fefde35514bcb.tar.gz go-af0fc83985860776551d15be3a8fefde35514bcb.zip |
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>
-rw-r--r-- | src/cmd/compile/internal/gc/reflect.go | 10 | ||||
-rw-r--r-- | src/cmd/link/internal/ld/decodesym.go | 4 | ||||
-rw-r--r-- | src/reflect/type.go | 6 | ||||
-rw-r--r-- | src/runtime/type.go | 4 | ||||
-rw-r--r-- | test/fixedbugs/issue16037_run.go | 70 |
5 files changed, 85 insertions, 9 deletions
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index ceed55a2a5..c4268f646f 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -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 } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 551ff802d7..a1eef031e7 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -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) diff --git a/src/reflect/type.go b/src/reflect/type.go index b70887fbba..7996ae284b 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -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, ' ') diff --git a/src/runtime/type.go b/src/runtime/type.go index d7ec5573a9..786f2b96f6 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -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 { diff --git a/test/fixedbugs/issue16037_run.go b/test/fixedbugs/issue16037_run.go new file mode 100644 index 0000000000..23fff5925b --- /dev/null +++ b/test/fixedbugs/issue16037_run.go @@ -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) + } +} |