aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crawshaw <crawshaw@golang.org>2016-06-14 10:20:11 -0400
committerDavid Crawshaw <crawshaw@golang.org>2016-06-14 15:32:34 +0000
commitaf0fc83985860776551d15be3a8fefde35514bcb (patch)
tree8d3448bd28b0cc6deaf8ef74b3e36199be609d2e
parent53242e49b127ede6d7b258c7e90c39a5afa70c25 (diff)
downloadgo-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.go10
-rw-r--r--src/cmd/link/internal/ld/decodesym.go4
-rw-r--r--src/reflect/type.go6
-rw-r--r--src/runtime/type.go4
-rw-r--r--test/fixedbugs/issue16037_run.go70
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)
+ }
+}