5
5
package gc
6
6
7
7
import (
8
+ "bytes"
8
9
"cmd/internal/obj"
9
10
"fmt"
10
11
"sort"
11
12
"unicode"
12
13
"unicode/utf8"
13
14
)
14
15
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
+
15
30
var asmlist * NodeList
16
31
17
32
// Mark n's symbol as exported
@@ -35,8 +50,8 @@ func exportsym(n *Node) {
35
50
}
36
51
37
52
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'
40
55
}
41
56
r , _ := utf8 .DecodeRuneInString (s )
42
57
return unicode .IsUpper (r )
@@ -87,7 +102,7 @@ func dumppkg(p *Pkg) {
87
102
if ! p .Direct {
88
103
suffix = " // indirect"
89
104
}
90
- fmt . Fprintf ( bout , "\t import %s %q%s\n " , p .Name , p .Path , suffix )
105
+ exportf ( "\t import %s %q%s\n " , p .Name , p .Path , suffix )
91
106
}
92
107
93
108
// Look for anything we need for the inline body
@@ -128,7 +143,7 @@ func reexportdep(n *Node) {
128
143
}
129
144
}
130
145
131
- // Local variables in the bodies need their type.
146
+ // Local variables in the bodies need their type.
132
147
case ODCL :
133
148
t := n .Left .Type
134
149
@@ -167,7 +182,7 @@ func reexportdep(n *Node) {
167
182
exportlist = append (exportlist , n )
168
183
}
169
184
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.
171
186
case OCONV ,
172
187
OCONVIFACE ,
173
188
OCONVNOP ,
@@ -216,9 +231,9 @@ func dumpexportconst(s *Sym) {
216
231
dumpexporttype (t )
217
232
218
233
if t != nil && ! isideal (t ) {
219
- fmt . Fprintf ( bout , "\t const %v %v = %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtSharp ), Vconv (n .Val (), obj .FmtSharp ))
234
+ exportf ( "\t const %v %v = %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtSharp ), Vconv (n .Val (), obj .FmtSharp ))
220
235
} else {
221
- fmt . Fprintf ( bout , "\t const %v = %v\n " , Sconv (s , obj .FmtSharp ), Vconv (n .Val (), obj .FmtSharp ))
236
+ exportf ( "\t const %v = %v\n " , Sconv (s , obj .FmtSharp ), Vconv (n .Val (), obj .FmtSharp ))
222
237
}
223
238
}
224
239
@@ -242,14 +257,14 @@ func dumpexportvar(s *Sym) {
242
257
}
243
258
244
259
// NOTE: The space after %#S here is necessary for ld's export data parser.
245
- fmt . Fprintf ( bout , "\t func %v %v { %v }\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtShort | obj .FmtSharp ), Hconv (n .Func .Inl , obj .FmtSharp ))
260
+ exportf ( "\t func %v %v { %v }\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtShort | obj .FmtSharp ), Hconv (n .Func .Inl , obj .FmtSharp ))
246
261
247
262
reexportdeplist (n .Func .Inl )
248
263
} else {
249
- fmt . Fprintf ( bout , "\t func %v %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtShort | obj .FmtSharp ))
264
+ exportf ( "\t func %v %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtShort | obj .FmtSharp ))
250
265
}
251
266
} else {
252
- fmt . Fprintf ( bout , "\t var %v %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtSharp ))
267
+ exportf ( "\t var %v %v\n " , Sconv (s , obj .FmtSharp ), Tconv (t , obj .FmtSharp ))
253
268
}
254
269
}
255
270
@@ -287,10 +302,10 @@ func dumpexporttype(t *Type) {
287
302
}
288
303
sort .Sort (methodbyname (m ))
289
304
290
- fmt . Fprintf ( bout , "\t type %v %v\n " , Sconv (t .Sym , obj .FmtSharp ), Tconv (t , obj .FmtSharp | obj .FmtLong ))
305
+ exportf ( "\t type %v %v\n " , Sconv (t .Sym , obj .FmtSharp ), Tconv (t , obj .FmtSharp | obj .FmtLong ))
291
306
for _ , f := range m {
292
307
if f .Nointerface {
293
- fmt . Fprintf ( bout , "\t //go:nointerface\n " )
308
+ exportf ( "\t //go:nointerface\n " )
294
309
}
295
310
if f .Type .Nname != nil && f .Type .Nname .Func .Inl != nil { // nname was set by caninl
296
311
@@ -299,10 +314,10 @@ func dumpexporttype(t *Type) {
299
314
if Debug ['l' ] < 2 {
300
315
typecheckinl (f .Type .Nname )
301
316
}
302
- fmt . Fprintf ( bout , "\t func (%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 ( "\t func (%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 ))
303
318
reexportdeplist (f .Type .Nname .Func .Inl )
304
319
} else {
305
- fmt . Fprintf ( bout , "\t func (%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 ( "\t func (%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 ))
306
321
}
307
322
}
308
323
}
@@ -341,33 +356,83 @@ func dumpsym(s *Sym) {
341
356
}
342
357
343
358
func dumpexport () {
344
- lno := lineno
345
-
346
359
if buildid != "" {
347
- fmt .Fprintf (bout , "build id %q\n " , buildid )
348
- }
349
- fmt .Fprintf (bout , "\n $$\n package %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
+ }
354
386
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
+ }
358
418
}
359
- }
360
419
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
367
431
}
368
432
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
+ }
371
436
}
372
437
373
438
/*
0 commit comments