]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, etc: handle many struct fields
authorDavid Crawshaw <crawshaw@golang.org>
Tue, 14 Jun 2016 14:20:11 +0000 (10:20 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Tue, 14 Jun 2016 15:32:34 +0000 (15:32 +0000)
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>

src/cmd/compile/internal/gc/reflect.go
src/cmd/link/internal/ld/decodesym.go
src/reflect/type.go
src/runtime/type.go
test/fixedbugs/issue16037_run.go [new file with mode: 0644]

index ceed55a2a54cd76674292e680b7f67d1b2fac136..c4268f646f5fcc412646a8f2b042a2964d68f2b4 100644 (file)
@@ -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
 }
 
index 551ff802d7fb69c910e4b31795c30a5c6d7b9bab..a1eef031e777f8649cede60bd7c84ef83b7d7bfe 100644 (file)
@@ -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)
index b70887fbba0f5e2b215664cb9d357a22fa5e98c7..7996ae284b328f623fdaef999051b84688cd782e 100644 (file)
@@ -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, ' ')
index d7ec5573a9d851c921e81faaa234529d6a883d39..786f2b96f6155c6c076ec02a35112ca1ac14a396 100644 (file)
@@ -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 (file)
index 0000000..23fff59
--- /dev/null
@@ -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)
+       }
+}