Skip to content

Commit ae2f54a

Browse files
committedOct 22, 2015
cmd/compile/internal/gc: compact binary export format
The binary import/export format is significantly more compact than the existing textual format. It should also be faster to read and write (to be measured). Use -newexport to enable, for instance: export GO_GCFLAGS=-newexport; make.bash The compiler can import packages using both the old and the new format ("mixed mode"). Missing: export info for inlined functions bodies (performance issue, does not affect correctness). Disabled by default until we have inlined function bodies and confirmation of no regression and equality of binaries. For golang#6110. For golang#1909. This change depends on: https://go-review.googlesource.com/16220 https://go-review.googlesource.com/16222 (already submitted) for all.bash to work. Some initial export data sizes for std lib packages. This data is without exported functions with inlineable function bodies. Package old new new/old archive/tar.................................13875.....3883 28% archive/zip.................................19464.....5046 26% bufio....................................... 7733.....2222 29% bytes.......................................10342.....3347 32% cmd/addr2line.................................242.......26 11% cmd/api.....................................39305....10368 26% cmd/asm/internal/arch.......................27732.....7939 29% cmd/asm/internal/asm........................35264....10295 29% cmd/asm/internal/flags........................629......178 28% cmd/asm/internal/lex........................39248....11128 28% cmd/asm.......................................306.......26 8% cmd/cgo.....................................40197....10570 26% cmd/compile/internal/amd64...................1106......214 19% cmd/compile/internal/arm....................27891.....7710 28% cmd/compile/internal/arm64....................891......153 17% cmd/compile/internal/big....................21637.....8336 39% cmd/compile/internal/gc....................109845....29727 27% cmd/compile/internal/mips64...................972......168 17% cmd/compile/internal/ppc64....................972......168 17% cmd/compile/internal/x86.....................1104......195 18% cmd/compile...................................329.......26 8% cmd/cover...................................12986.....3749 29% cmd/dist......................................477.......67 14% cmd/doc.....................................23043.....6793 29% cmd/expdump...................................167.......26 16% cmd/fix......................................1190......208 17% cmd/go......................................26399.....5629 21% cmd/gofmt.....................................499.......26 5% cmd/internal/gcprog..........................1342......490 37% cmd/internal/goobj...........................2690......980 36% cmd/internal/obj/arm........................32740....10057 31% cmd/internal/obj/arm64......................46542....15364 33% cmd/internal/obj/mips.......................42140....13731 33% cmd/internal/obj/ppc64......................42140....13731 33% cmd/internal/obj/x86........................52732....19015 36% cmd/internal/obj............................36729....11690 32% cmd/internal/objfile........................36365....10287 28% cmd/link/internal/amd64.....................45893....12220 27% cmd/link/internal/arm.........................307.......96 31% cmd/link/internal/arm64.......................345.......98 28% cmd/link/internal/ld.......................109300....46326 42% cmd/link/internal/ppc64.......................344.......99 29% cmd/link/internal/x86.........................334......107 32% cmd/link......................................314.......26 8% cmd/newlink..................................8110.....2544 31% cmd/nm........................................210.......26 12% cmd/objdump...................................244.......26 11% cmd/pack....................................14248.....4066 29% cmd/pprof/internal/commands..................5239.....1285 25% cmd/pprof/internal/driver...................37967.....8860 23% cmd/pprof/internal/fetch....................30962.....7337 24% cmd/pprof/internal/plugin...................47734.....7719 16% cmd/pprof/internal/profile..................22286.....6922 31% cmd/pprof/internal/report...................31187.....7838 25% cmd/pprof/internal/svg.......................4315......965 22% cmd/pprof/internal/symbolizer...............30051.....7397 25% cmd/pprof/internal/symbolz..................28545.....6949 24% cmd/pprof/internal/tempfile.................12550.....3356 27% cmd/pprof.....................................563.......26 5% cmd/trace....................................1455......636 44% cmd/vendor/golang.org/x/arch/arm/armasm....168035....64737 39% cmd/vendor/golang.org/x/arch/x86/x86asm.....26871.....8578 32% cmd/vet.....................................38980.....9913 25% cmd/vet/whitelist.............................102.......49 48% cmd/yacc.....................................2518......926 37% compress/bzip2...............................6326......129 2% compress/flate...............................7069.....2541 36% compress/gzip...............................20143.....5069 25% compress/lzw..................................828......295 36% compress/zlib...............................10676.....2692 25% container/heap................................523......181 35% container/list...............................3517......740 21% container/ring................................881......229 26% crypto/aes....................................550......187 34% crypto/cipher................................1966......825 42% crypto.......................................1836......646 35% crypto/des....................................632......235 37% crypto/dsa..................................18718.....5035 27% crypto/ecdsa................................23131.....6097 26% crypto/elliptic.............................20790.....5740 28% crypto/hmac...................................455......186 41% crypto/md5...................................1375......171 12% crypto/rand.................................18132.....4748 26% crypto/rc4....................................561......240 43% crypto/rsa..................................22094.....6380 29% crypto/sha1..................................1416......172 12% crypto/sha256.................................551......238 43% crypto/sha512.................................839......378 45% crypto/subtle................................1153......250 22% crypto/tls..................................58203....17984 31% crypto/x509/pkix............................29447.....8161 28% database/sql/driver..........................3318.....1096 33% database/sql................................11258.....3942 35% debug/dwarf.................................18416.....7006 38% debug/elf...................................57530....21014 37% debug/gosym..................................4992.....2058 41% debug/macho.................................23037.....6538 28% debug/pe....................................21063.....6619 31% debug/plan9obj...............................2467......802 33% encoding/ascii85.............................1523......360 24% encoding/asn1................................1718......527 31% encoding/base32..............................2642......686 26% encoding/base64..............................3077......800 26% encoding/binary..............................4727.....1040 22% encoding/csv................................12223.....2850 23% encoding......................................383......217 57% encoding/gob................................37563....10113 27% encoding/hex.................................1327......390 29% encoding/json...............................30897.....7804 25% encoding/pem..................................595......200 34% encoding/xml................................37798.....9336 25% errors........................................274.......36 13% expvar.......................................3155.....1021 32% flag........................................19860.....2849 14% fmt..........................................3137.....1263 40% go/ast......................................44729....13422 30% go/build....................................16336.....4657 29% go/constant..................................3703......846 23% go/doc.......................................9877.....2807 28% go/format....................................5472.....1575 29% go/importer..................................4980.....1301 26% go/internal/gccgoimporter....................5587.....1525 27% go/internal/gcimporter.......................8979.....2186 24% go/parser...................................20692.....5304 26% go/printer...................................7015.....2029 29% go/scanner...................................9719.....2824 29% go/token.....................................7933.....2465 31% go/types....................................64569....19978 31% hash/adler32.................................1176......176 15% hash/crc32...................................1663......360 22% hash/crc64...................................1587......306 19% hash/fnv.....................................3964......260 7% hash..........................................591......278 47% html..........................................217.......74 34% html/template...............................69623....12588 18% image/color/palette...........................315.......98 31% image/color..................................5565.....1036 19% image/draw...................................6917.....1028 15% image/gif....................................8894.....1654 19% image/internal/imageutil.....................9112.....1476 16% image/jpeg...................................6647.....1026 15% image/png....................................6906.....1069 15% image.......................................28992.....6139 21% index/suffixarray...........................17106.....4773 28% internal/singleflight........................1614......506 31% internal/testenv............................12212.....3152 26% internal/trace...............................2762.....1323 48% io/ioutil...................................13502.....3682 27% io...........................................6765.....2482 37% log.........................................11620.....3317 29% log/syslog..................................13516.....3821 28% math/big....................................21819.....8320 38% math/cmplx...................................2816......438 16% math/rand....................................2317......929 40% math.........................................7511.....2444 33% mime/multipart..............................12679.....3360 27% mime/quotedprintable.........................5458.....1235 23% mime.........................................6076.....1628 27% net/http/cgi................................59796....17173 29% net/http/cookiejar..........................14781.....3739 25% net/http/fcgi...............................57861....16426 28% net/http/httptest...........................84100....24365 29% net/http/httputil...........................67763....18869 28% net/http/internal............................6907......637 9% net/http/pprof..............................57945....16316 28% net/http....................................95391....30210 32% net/internal/socktest........................4555.....1453 32% net/mail....................................14481.....3608 25% net/rpc/jsonrpc.............................33335......988 3% net/rpc.....................................79950....23106 29% net/smtp....................................57790....16468 28% net/textproto...............................11356.....3248 29% net/url......................................3123.....1009 32% os/exec.....................................20738.....5769 28% os/signal.....................................437......167 38% os..........................................24875.....6668 27% path/filepath...............................11340.....2826 25% path..........................................778......285 37% reflect.....................................15469.....5198 34% regexp......................................13627.....4661 34% regexp/syntax................................5539.....2249 41% runtime/debug................................9275.....2322 25% runtime/pprof................................1355......477 35% runtime/race...................................39.......17 44% runtime/trace.................................228.......92 40% runtime.....................................13498.....1821 13% sort.........................................2848......842 30% strconv......................................2947.....1252 42% strings......................................7983.....2456 31% sync/atomic..................................2666.....1149 43% sync.........................................2568......845 33% syscall.....................................81252....38398 47% testing/iotest...............................2444......302 12% testing/quick...............................18890.....5076 27% testing.....................................16502.....4800 29% text/scanner.................................6849.....2052 30% text/tabwriter...............................6607.....1863 28% text/template/parse.........................22978.....6183 27% text/template...............................64153....11518 18% time........................................12103.....3546 29% unicode......................................9706.....3320 34% unicode/utf16................................1055......148 14% unicode/utf8.................................1118......513 46% vendor/golang.org/x/net/http2/hpack..........8905.....2636 30% All packages 3518505 1017774 29% Change-Id: Id657334f276383ff1e6fa91472d3d1db5a03349c Reviewed-on: https://go-review.googlesource.com/13937 Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Chris Manghane <[email protected]>
1 parent 28ef4c3 commit ae2f54a

File tree

14 files changed

+2823
-359
lines changed

14 files changed

+2823
-359
lines changed
 

‎src/cmd/compile/internal/gc/bexport.go

+1,035
Large diffs are not rendered by default.

‎src/cmd/compile/internal/gc/bimport.go

+619
Large diffs are not rendered by default.

‎src/cmd/compile/internal/gc/dcl.go

+27-11
Original file line numberDiff line numberDiff line change
@@ -874,11 +874,18 @@ func checkdupfields(t *Type, what string) {
874874
* a type for struct/interface/arglist
875875
*/
876876
func tostruct(l *NodeList) *Type {
877-
var f *Type
878877
t := typ(TSTRUCT)
878+
tostruct0(t, l)
879+
return t
880+
}
881+
882+
func tostruct0(t *Type, l *NodeList) {
883+
if t == nil || t.Etype != TSTRUCT {
884+
Fatalf("struct expected")
885+
}
879886

880887
for tp := &t.Type; l != nil; l = l.Next {
881-
f = structfield(l.N)
888+
f := structfield(l.N)
882889

883890
*tp = f
884891
tp = &f.Down
@@ -896,8 +903,6 @@ func tostruct(l *NodeList) *Type {
896903
if !t.Broke {
897904
checkwidth(t)
898905
}
899-
900-
return t
901906
}
902907

903908
func tofunargs(l *NodeList) *Type {
@@ -996,18 +1001,23 @@ func interfacefield(n *Node) *Type {
9961001
}
9971002

9981003
func tointerface(l *NodeList) *Type {
999-
var f *Type
1000-
var t1 *Type
1001-
10021004
t := typ(TINTER)
1005+
tointerface0(t, l)
1006+
return t
1007+
}
1008+
1009+
func tointerface0(t *Type, l *NodeList) *Type {
1010+
if t == nil || t.Etype != TINTER {
1011+
Fatalf("interface expected")
1012+
}
10031013

10041014
tp := &t.Type
10051015
for ; l != nil; l = l.Next {
1006-
f = interfacefield(l.N)
1016+
f := interfacefield(l.N)
10071017

10081018
if l.N.Left == nil && f.Type.Etype == TINTER {
10091019
// embedded interface, inline methods
1010-
for t1 = f.Type.Type; t1 != nil; t1 = t1.Down {
1020+
for t1 := f.Type.Type; t1 != nil; t1 = t1.Down {
10111021
f = typ(TFIELD)
10121022
f.Type = t1.Type
10131023
f.Broke = t1.Broke
@@ -1200,6 +1210,14 @@ func isifacemethod(f *Type) bool {
12001210
*/
12011211
func functype(this *Node, in *NodeList, out *NodeList) *Type {
12021212
t := typ(TFUNC)
1213+
functype0(t, this, in, out)
1214+
return t
1215+
}
1216+
1217+
func functype0(t *Type, this *Node, in *NodeList, out *NodeList) {
1218+
if t == nil || t.Etype != TFUNC {
1219+
Fatalf("function type expected")
1220+
}
12031221

12041222
var rcvr *NodeList
12051223
if this != nil {
@@ -1230,8 +1248,6 @@ func functype(this *Node, in *NodeList, out *NodeList) *Type {
12301248
t.Outnamed = true
12311249
}
12321250
}
1233-
1234-
return t
12351251
}
12361252

12371253
var methodsym_toppkg *Pkg

‎src/cmd/compile/internal/gc/export.go

+100-35
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,28 @@
55
package gc
66

77
import (
8+
"bytes"
89
"cmd/internal/obj"
910
"fmt"
1011
"sort"
1112
"unicode"
1213
"unicode/utf8"
1314
)
1415

16+
var (
17+
newexport int // if set, use new export format
18+
Debug_export int // if set, print debugging information about export data
19+
exportsize int
20+
)
21+
22+
func exportf(format string, args ...interface{}) {
23+
n, _ := fmt.Fprintf(bout, format, args...)
24+
exportsize += n
25+
if Debug_export != 0 {
26+
fmt.Printf(format, args...)
27+
}
28+
}
29+
1530
var asmlist *NodeList
1631

1732
// Mark n's symbol as exported
@@ -35,8 +50,8 @@ func exportsym(n *Node) {
3550
}
3651

3752
func exportname(s string) bool {
38-
if s[0] < utf8.RuneSelf {
39-
return 'A' <= s[0] && s[0] <= 'Z'
53+
if r := s[0]; r < utf8.RuneSelf {
54+
return 'A' <= r && r <= 'Z'
4055
}
4156
r, _ := utf8.DecodeRuneInString(s)
4257
return unicode.IsUpper(r)
@@ -87,7 +102,7 @@ func dumppkg(p *Pkg) {
87102
if !p.Direct {
88103
suffix = " // indirect"
89104
}
90-
fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
105+
exportf("\timport %s %q%s\n", p.Name, p.Path, suffix)
91106
}
92107

93108
// Look for anything we need for the inline body
@@ -128,7 +143,7 @@ func reexportdep(n *Node) {
128143
}
129144
}
130145

131-
// Local variables in the bodies need their type.
146+
// Local variables in the bodies need their type.
132147
case ODCL:
133148
t := n.Left.Type
134149

@@ -167,7 +182,7 @@ func reexportdep(n *Node) {
167182
exportlist = append(exportlist, n)
168183
}
169184

170-
// for operations that need a type when rendered, put the type on the export list.
185+
// for operations that need a type when rendered, put the type on the export list.
171186
case OCONV,
172187
OCONVIFACE,
173188
OCONVNOP,
@@ -216,9 +231,9 @@ func dumpexportconst(s *Sym) {
216231
dumpexporttype(t)
217232

218233
if t != nil && !isideal(t) {
219-
fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
234+
exportf("\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
220235
} else {
221-
fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
236+
exportf("\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
222237
}
223238
}
224239

@@ -242,14 +257,14 @@ func dumpexportvar(s *Sym) {
242257
}
243258

244259
// NOTE: The space after %#S here is necessary for ld's export data parser.
245-
fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
260+
exportf("\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
246261

247262
reexportdeplist(n.Func.Inl)
248263
} else {
249-
fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
264+
exportf("\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
250265
}
251266
} else {
252-
fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
267+
exportf("\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
253268
}
254269
}
255270

@@ -287,10 +302,10 @@ func dumpexporttype(t *Type) {
287302
}
288303
sort.Sort(methodbyname(m))
289304

290-
fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
305+
exportf("\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
291306
for _, f := range m {
292307
if f.Nointerface {
293-
fmt.Fprintf(bout, "\t//go:nointerface\n")
308+
exportf("\t//go:nointerface\n")
294309
}
295310
if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
296311

@@ -299,10 +314,10 @@ func dumpexporttype(t *Type) {
299314
if Debug['l'] < 2 {
300315
typecheckinl(f.Type.Nname)
301316
}
302-
fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
317+
exportf("\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
303318
reexportdeplist(f.Type.Nname.Func.Inl)
304319
} else {
305-
fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
320+
exportf("\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
306321
}
307322
}
308323
}
@@ -341,33 +356,83 @@ func dumpsym(s *Sym) {
341356
}
342357

343358
func dumpexport() {
344-
lno := lineno
345-
346359
if buildid != "" {
347-
fmt.Fprintf(bout, "build id %q\n", buildid)
348-
}
349-
fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name)
350-
if safemode != 0 {
351-
fmt.Fprintf(bout, " safe")
352-
}
353-
fmt.Fprintf(bout, "\n")
360+
exportf("build id %q\n", buildid)
361+
}
362+
363+
size := 0 // size of export section without enclosing markers
364+
if forceNewExport || newexport != 0 {
365+
// binary export
366+
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
367+
exportf("\n$$B\n") // indicate binary format
368+
const verifyExport = true // enable to check format changes
369+
if verifyExport {
370+
// save a copy of the export data
371+
var copy bytes.Buffer
372+
bcopy := obj.Binitw(&copy)
373+
size = Export(bcopy, Debug_export != 0)
374+
bcopy.Flush() // flushing to bytes.Buffer cannot fail
375+
if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
376+
Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
377+
}
378+
379+
// verify there's no "\n$$\n" inside the export data
380+
// TODO(gri) fragile - the end marker needs to be fixed
381+
// TODO(gri) investigate if exporting a string containing "\n$$\n"
382+
// causes problems (old and new format)
383+
if bytes.Index(copy.Bytes(), []byte("\n$$\n")) >= 0 {
384+
Fatalf("export data contains end marker in its midst")
385+
}
354386

355-
for _, p := range pkgs {
356-
if p.Direct {
357-
dumppkg(p)
387+
// verify that we can read the copied export data back in
388+
// (use empty package map to avoid collisions)
389+
savedPkgMap := pkgMap
390+
savedPkgs := pkgs
391+
pkgMap = make(map[string]*Pkg)
392+
pkgs = nil
393+
importpkg = mkpkg("")
394+
Import(obj.Binitr(&copy)) // must not die
395+
importpkg = nil
396+
pkgs = savedPkgs
397+
pkgMap = savedPkgMap
398+
} else {
399+
size = Export(bout, Debug_export != 0)
400+
}
401+
exportf("\n$$\n")
402+
} else {
403+
// textual export
404+
lno := lineno
405+
406+
exportf("\n$$\n") // indicate textual format
407+
exportsize = 0
408+
exportf("package %s", localpkg.Name)
409+
if safemode != 0 {
410+
exportf(" safe")
411+
}
412+
exportf("\n")
413+
414+
for _, p := range pkgs {
415+
if p.Direct {
416+
dumppkg(p)
417+
}
358418
}
359-
}
360419

361-
// exportlist grows during iteration - cannot use range
362-
for len(exportlist) > 0 {
363-
n := exportlist[0]
364-
exportlist = exportlist[1:]
365-
lineno = n.Lineno
366-
dumpsym(n.Sym)
420+
// exportlist grows during iteration - cannot use range
421+
for len(exportlist) > 0 {
422+
n := exportlist[0]
423+
exportlist = exportlist[1:]
424+
lineno = n.Lineno
425+
dumpsym(n.Sym)
426+
}
427+
428+
size = exportsize
429+
exportf("\n$$\n")
430+
lineno = lno
367431
}
368432

369-
fmt.Fprintf(bout, "\n$$\n")
370-
lineno = lno
433+
if Debug_export != 0 {
434+
fmt.Printf("export data size = %d bytes\n", size)
435+
}
371436
}
372437

373438
/*

‎src/cmd/compile/internal/gc/go.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ const (
288288

289289
TFUNC
290290
TARRAY
291-
T_old_DARRAY
291+
T_old_DARRAY // Doesn't seem to be used in existing code. Used now for Isddd export (see bexport.go). TODO(gri) rename.
292292
TSTRUCT
293293
TCHAN
294294
TMAP

‎src/cmd/compile/internal/gc/go.y

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ import_stmt:
254254
break;
255255
}
256256
if my.Name == "init" {
257+
lineno = int32($1)
257258
Yyerror("cannot import package as init - init must be a func");
258259
break;
259260
}

0 commit comments

Comments
 (0)
Please sign in to comment.