blob: c7be2deaa2c37bfcf28bdac6769e446e76496cb5 [file] [log] [blame]
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Binary package export.
Brad Fitzpatrickb3309872016-03-08 18:57:19 +00006// (see fmt.go, parser.go as "documentation" for how to use/setup data structures)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07007
Robert Griesemerae2f54a2015-08-13 19:05:37 -07008/*
Robert Griesemera689f6b2016-05-25 11:23:56 -070091) Export data encoding principles:
Robert Griesemerae2f54a2015-08-13 19:05:37 -070010
11The export data is a serialized description of the graph of exported
Robert Griesemera9ea36a2016-03-18 17:21:32 -070012"objects": constants, types, variables, and functions. In general,
13types - but also objects referred to from inlined function bodies -
14can be reexported and so we need to know which package they are coming
Robert Griesemerae2f54a2015-08-13 19:05:37 -070015from. Therefore, packages are also part of the export graph.
16
Robert Griesemera9ea36a2016-03-18 17:21:32 -070017The roots of the graph are two lists of objects. The 1st list (phase 1,
18see Export) contains all objects that are exported at the package level.
19These objects are the full representation of the package's API, and they
20are the only information a platform-independent tool (e.g., go/types)
21needs to know to type-check against a package.
22
23The 2nd list of objects contains all objects referred to from exported
24inlined function bodies. These objects are needed by the compiler to
25make sense of the function bodies; the exact list contents are compiler-
26specific.
27
28Finally, the export data contains a list of representations for inlined
29function bodies. The format of this representation is compiler specific.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070030
31The graph is serialized in in-order fashion, starting with the roots.
32Each object in the graph is serialized by writing its fields sequentially.
33If the field is a pointer to another object, that object is serialized,
34recursively. Otherwise the field is written. Non-pointer fields are all
Robert Griesemera9ea36a2016-03-18 17:21:32 -070035encoded as integer or string values.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070036
Robert Griesemer5c593a32016-04-13 17:53:03 -070037Some objects (packages, types) may be referred to more than once. When
38reaching an object that was not serialized before, an integer _index_
Robert Griesemer45983822015-10-22 18:56:45 -070039is assigned to it, starting at 0. In this case, the encoding starts
40with an integer _tag_ < 0. The tag value indicates the kind of object
Robert Griesemer5c593a32016-04-13 17:53:03 -070041that follows and that this is the first time that we see this object.
42If the object was already serialized, the encoding is simply the object
43index >= 0. An importer can trivially determine if an object needs to
44be read in for the first time (tag < 0) and entered into the respective
45object table, or if the object was seen already (index >= 0), in which
46case the index is used to look up the object in a table.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070047
48Before exporting or importing, the type tables are populated with the
49predeclared types (int, string, error, unsafe.Pointer, etc.). This way
50they are automatically encoded with a known and fixed type index.
51
Robert Griesemera689f6b2016-05-25 11:23:56 -0700522) Encoding format:
Robert Griesemerae2f54a2015-08-13 19:05:37 -070053
54The export data starts with a single byte indicating the encoding format
55(compact, or with debugging information), followed by a version string
Robert Griesemereb79f212016-04-12 21:58:44 -070056(so we can evolve the encoding if need be), and then the package object
57for the exported package (with an empty path).
Robert Griesemerae2f54a2015-08-13 19:05:37 -070058
Robert Griesemera9ea36a2016-03-18 17:21:32 -070059After this header, two lists of objects and the list of inlined function
60bodies follows.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070061
62The encoding of objects is straight-forward: Constants, variables, and
63functions start with their name, type, and possibly a value. Named types
64record their name and package so that they can be canonicalized: If the
65same type was imported before via another import, the importer must use
66the previously imported type pointer so that we have exactly one version
67(i.e., one pointer) for each named type (and read but discard the current
68type encoding). Unnamed types simply encode their respective fields.
69
Robert Griesemer5c593a32016-04-13 17:53:03 -070070In the encoding, some lists start with the list length. Some lists are
71terminated with an end marker (usually for lists where we may not know
72the length a priori).
Robert Griesemerae2f54a2015-08-13 19:05:37 -070073
Robert Griesemer5c593a32016-04-13 17:53:03 -070074Integers use variable-length encoding for compact representation.
75
76Strings are canonicalized similar to objects that may occur multiple times:
77If the string was exported already, it is represented by its index only.
78Otherwise, the export data starts with the negative string length (negative,
79so we can distinguish from string index), followed by the string bytes.
80The empty string is mapped to index 0.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070081
Robert Griesemerae2f54a2015-08-13 19:05:37 -070082The exporter and importer are completely symmetric in implementation: For
Robert Griesemer45983822015-10-22 18:56:45 -070083each encoding routine there is a matching and symmetric decoding routine.
Robert Griesemerae2f54a2015-08-13 19:05:37 -070084This symmetry makes it very easy to change or extend the format: If a new
85field needs to be encoded, a symmetric change can be made to exporter and
86importer.
Robert Griesemera689f6b2016-05-25 11:23:56 -070087
883) Making changes to the encoding format:
89
90Any change to the encoding format requires a respective change in the
91exporter below and a corresponding symmetric change to the importer in
92bimport.go.
93
94Furthermore, it requires a corresponding change to go/internal/gcimporter
95and golang.org/x/tools/go/gcimporter15. Changes to the latter must preserve
96compatibility with both the last release of the compiler, and with the
97corresponding compiler at tip. That change is necessarily more involved,
98as it must switch based on the version number in the export data file.
99
100It is recommended to turn on debugFormat when working on format changes
101as it will help finding encoding/decoding inconsistencies quickly.
102
103Special care must be taken to update builtin.go when the export format
104changes: builtin.go contains the export data obtained by compiling the
105builtin/runtime.go and builtin/unsafe.go files; those compilations in
106turn depend on importing the data in builtin.go. Thus, when the export
107data format changes, the compiler must be able to import the data in
108builtin.go even if its format has not yet changed. Proceed in several
109steps as follows:
110
111- Change the exporter to use the new format, and use a different version
112 string as well.
113- Update the importer accordingly, but accept both the old and the new
114 format depending on the version string.
115- all.bash should pass at this point.
116- Run mkbuiltin.go: this will create a new builtin.go using the new
117 export format.
118- go test -run Builtin should pass at this point.
119- Remove importer support for the old export format and (maybe) revert
120 the version string again (it's only needed to mark the transition).
121- all.bash should still pass.
122
123Don't forget to set debugFormat to false.
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700124*/
125
126package gc
127
128import (
Dave Cheneyca397bb2016-04-08 19:30:41 +1000129 "bufio"
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700130 "bytes"
131 "cmd/compile/internal/big"
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700132 "encoding/binary"
133 "fmt"
134 "sort"
135 "strings"
136)
137
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700138// If debugFormat is set, each integer and string value is preceded by a marker
139// and position information in the encoding. This mechanism permits an importer
140// to recognize immediately when it is out of sync. The importer recognizes this
141// mode automatically (i.e., it can import export data produced with debugging
142// support even if debugFormat is not set at the time of import). This mode will
143// lead to massively larger export data (by a factor of 2 to 3) and should only
144// be enabled during development and debugging.
145//
146// NOTE: This flag is the first flag to enable if importing dies because of
147// (suspected) format errors, and whenever a change is made to the format.
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700148const debugFormat = false // default: false
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700149
Robert Griesemerd78c84c2016-04-25 15:59:42 -0700150// forceObjFileStability enforces additional constraints in export data
151// and other parts of the compiler to eliminate object file differences
152// only due to the choice of export format.
153// TODO(gri) disable and remove once there is only one export format again
154const forceObjFileStability = true
Robert Griesemer0b8c0762016-04-25 14:39:51 -0700155
Robert Griesemer45983822015-10-22 18:56:45 -0700156const exportVersion = "v0"
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700157
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700158// exportInlined enables the export of inlined function bodies and related
159// dependencies. The compiler should work w/o any loss of functionality with
160// the flag disabled, but the generated code will lose access to inlined
161// function bodies across packages, leading to performance bugs.
162// Leave for debugging.
163const exportInlined = true // default: true
164
Robert Griesemer394ac812016-05-05 18:03:59 -0700165// trackAllTypes enables cycle tracking for all types, not just named
166// types. The existing compiler invariants assume that unnamed types
167// that are not completely set up are not used, or else there are spurious
168// errors.
169// If disabled, only named types are tracked, possibly leading to slightly
170// less efficient encoding in rare cases. It also prevents the export of
171// some corner-case type declarations (but those are not handled correctly
172// with with the textual export format either).
173// TODO(gri) enable and remove once issues caused by it are fixed
174const trackAllTypes = false
175
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700176type exporter struct {
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700177 out *bufio.Writer
178
Robert Griesemer5c593a32016-04-13 17:53:03 -0700179 // object -> index maps, indexed in order of serialization
180 strIndex map[string]int
181 pkgIndex map[*Pkg]int
182 typIndex map[*Type]int
183 funcList []*Func
184
185 // position encoding
Robert Griesemer86c93c92016-04-26 22:31:02 -0700186 posInfoFormat bool
187 prevFile string
188 prevLine int
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700189
190 // debugging support
191 written int // bytes written
192 indent int // for p.trace
193 trace bool
194}
195
Dave Cheney49e07f22016-04-08 20:09:10 +1000196// export writes the exportlist for localpkg to out and returns the number of bytes written.
Dave Cheneyca397bb2016-04-08 19:30:41 +1000197func export(out *bufio.Writer, trace bool) int {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700198 p := exporter{
199 out: out,
Robert Griesemer5c593a32016-04-13 17:53:03 -0700200 strIndex: map[string]int{"": 0}, // empty string is mapped to 0
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700201 pkgIndex: make(map[*Pkg]int),
202 typIndex: make(map[*Type]int),
Robert Griesemer86c93c92016-04-26 22:31:02 -0700203 // don't emit pos info for builtin packages
204 // (not needed and avoids path name diffs in builtin.go between
205 // Windows and non-Windows machines, exposed via builtin_test.go)
206 posInfoFormat: Debug['A'] == 0,
207 trace: trace,
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700208 }
209
Robert Griesemer394ac812016-05-05 18:03:59 -0700210 // TODO(gri) clean up the ad-hoc encoding of the file format below
211 // (we need this so we can read the builtin package export data
212 // easily w/o being affected by format changes)
213
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700214 // first byte indicates low-level encoding format
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700215 var format byte = 'c' // compact
216 if debugFormat {
217 format = 'd'
218 }
Robert Griesemer5c593a32016-04-13 17:53:03 -0700219 p.rawByte(format)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700220
Robert Griesemer394ac812016-05-05 18:03:59 -0700221 format = 'n' // track named types only
222 if trackAllTypes {
223 format = 'a'
224 }
225 p.rawByte(format)
226
Robert Griesemer889c0a62016-04-22 14:50:20 -0700227 // posInfo exported or not?
Robert Griesemer86c93c92016-04-26 22:31:02 -0700228 p.bool(p.posInfoFormat)
Robert Griesemer889c0a62016-04-22 14:50:20 -0700229
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700230 // --- generic export data ---
231
232 if p.trace {
Robert Griesemer45983822015-10-22 18:56:45 -0700233 p.tracef("\n--- package ---\n")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700234 if p.indent != 0 {
Robert Griesemer45983822015-10-22 18:56:45 -0700235 Fatalf("exporter: incorrect indentation %d", p.indent)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700236 }
237 }
238
Robert Griesemer45983822015-10-22 18:56:45 -0700239 if p.trace {
240 p.tracef("version = ")
241 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700242 p.string(exportVersion)
243 if p.trace {
244 p.tracef("\n")
245 }
246
247 // populate type map with predeclared "known" types
248 predecl := predeclared()
249 for index, typ := range predecl {
250 p.typIndex[typ] = index
251 }
252 if len(p.typIndex) != len(predecl) {
Robert Griesemer45983822015-10-22 18:56:45 -0700253 Fatalf("exporter: duplicate entries in type map?")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700254 }
255
256 // write package data
257 if localpkg.Path != "" {
Robert Griesemer45983822015-10-22 18:56:45 -0700258 Fatalf("exporter: local package path not empty: %q", localpkg.Path)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700259 }
260 p.pkg(localpkg)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700261 if p.trace {
262 p.tracef("\n")
263 }
264
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700265 // export objects
Robert Griesemerb1851a32016-04-12 11:31:16 -0700266 //
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700267 // First, export all exported (package-level) objects; i.e., all objects
268 // in the current exportlist. These objects represent all information
269 // required to import this package and type-check against it; i.e., this
270 // is the platform-independent export data. The format is generic in the
271 // sense that different compilers can use the same representation.
272 //
273 // During this first phase, more objects may be added to the exportlist
274 // (due to inlined function bodies and their dependencies). Export those
275 // objects in a second phase. That data is platform-specific as it depends
276 // on the inlining decisions of the compiler and the representation of the
277 // inlined function bodies.
278
279 // remember initial exportlist length
280 var numglobals = len(exportlist)
281
282 // Phase 1: Export objects in _current_ exportlist; exported objects at
283 // package level.
284 // Use range since we want to ignore objects added to exportlist during
285 // this phase.
286 objcount := 0
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700287 for _, n := range exportlist {
288 sym := n.Sym
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700289
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700290 if sym.Flags&SymExported != 0 {
291 continue
292 }
293 sym.Flags |= SymExported
294
295 // TODO(gri) Closures have dots in their names;
296 // e.g., TestFloatZeroValue.func1 in math/big tests.
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700297 if strings.Contains(sym.Name, ".") {
Robert Griesemer45983822015-10-22 18:56:45 -0700298 Fatalf("exporter: unexpected symbol: %v", sym)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700299 }
300
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700301 // TODO(gri) Should we do this check?
302 // if sym.Flags&SymExport == 0 {
303 // continue
304 // }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700305
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700306 if sym.Def == nil {
307 Fatalf("exporter: unknown export symbol: %v", sym)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700308 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700309
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700310 // TODO(gri) Optimization: Probably worthwhile collecting
311 // long runs of constants and export them "in bulk" (saving
312 // tags and types, and making import faster).
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700313
Robert Griesemer45983822015-10-22 18:56:45 -0700314 if p.trace {
315 p.tracef("\n")
316 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700317 p.obj(sym)
318 objcount++
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700319 }
320
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700321 // indicate end of list
Robert Griesemer45983822015-10-22 18:56:45 -0700322 if p.trace {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700323 p.tracef("\n")
Robert Griesemer45983822015-10-22 18:56:45 -0700324 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700325 p.tag(endTag)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700326
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700327 // for self-verification only (redundant)
328 p.int(objcount)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700329
330 // --- compiler-specific export data ---
331
332 if p.trace {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700333 p.tracef("\n--- compiler-specific export data ---\n[ ")
334 if p.indent != 0 {
335 Fatalf("exporter: incorrect indentation")
336 }
337 }
338
Robert Griesemerb1851a32016-04-12 11:31:16 -0700339 // write compiler-specific flags
Matthew Dempsky980ab122016-04-13 18:37:18 -0700340 p.bool(safemode)
Robert Griesemerb1851a32016-04-12 11:31:16 -0700341 if p.trace {
342 p.tracef("\n")
343 }
344
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700345 // Phase 2: Export objects added to exportlist during phase 1.
346 // Don't use range since exportlist may grow during this phase
347 // and we want to export all remaining objects.
348 objcount = 0
349 for i := numglobals; exportInlined && i < len(exportlist); i++ {
350 n := exportlist[i]
351 sym := n.Sym
352
353 // TODO(gri) The rest of this loop body is identical with
354 // the loop body above. Leave alone for now since there
355 // are different optimization opportunities, but factor
356 // eventually.
357
358 if sym.Flags&SymExported != 0 {
359 continue
360 }
361 sym.Flags |= SymExported
362
363 // TODO(gri) Closures have dots in their names;
364 // e.g., TestFloatZeroValue.func1 in math/big tests.
365 if strings.Contains(sym.Name, ".") {
366 Fatalf("exporter: unexpected symbol: %v", sym)
367 }
368
369 // TODO(gri) Should we do this check?
370 // if sym.Flags&SymExport == 0 {
371 // continue
372 // }
373
374 if sym.Def == nil {
375 Fatalf("exporter: unknown export symbol: %v", sym)
376 }
377
378 // TODO(gri) Optimization: Probably worthwhile collecting
379 // long runs of constants and export them "in bulk" (saving
380 // tags and types, and making import faster).
381
382 if p.trace {
383 p.tracef("\n")
384 }
385 p.obj(sym)
386 objcount++
387 }
388
389 // indicate end of list
390 if p.trace {
391 p.tracef("\n")
392 }
393 p.tag(endTag)
394
395 // for self-verification only (redundant)
396 p.int(objcount)
397
398 // --- inlined function bodies ---
399
400 if p.trace {
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700401 p.tracef("\n--- inlined function bodies ---\n")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700402 if p.indent != 0 {
Robert Griesemer45983822015-10-22 18:56:45 -0700403 Fatalf("exporter: incorrect indentation")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700404 }
405 }
406
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700407 // write inlineable function bodies
408 objcount = 0
409 for i, f := range p.funcList {
410 if f != nil {
411 // function has inlineable body:
412 // write index and body
413 if p.trace {
Dave Cheney2da642a2016-04-27 15:15:47 +1000414 p.tracef("\n----\nfunc { %s }\n", hconv(f.Inl, FmtSharp))
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700415 }
416 p.int(i)
417 p.stmtList(f.Inl)
418 if p.trace {
419 p.tracef("\n")
420 }
421 objcount++
422 }
423 }
424
425 // indicate end of list
Robert Griesemer45983822015-10-22 18:56:45 -0700426 if p.trace {
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700427 p.tracef("\n")
Robert Griesemer45983822015-10-22 18:56:45 -0700428 }
Robert Griesemerae980452016-04-13 16:57:23 -0700429 p.int(-1) // invalid index terminates list
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700430
431 // for self-verification only (redundant)
432 p.int(objcount)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700433
434 if p.trace {
Robert Griesemer45983822015-10-22 18:56:45 -0700435 p.tracef("\n--- end ---\n")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700436 }
437
438 // --- end of export data ---
439
440 return p.written
441}
442
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700443func (p *exporter) pkg(pkg *Pkg) {
444 if pkg == nil {
Robert Griesemer45983822015-10-22 18:56:45 -0700445 Fatalf("exporter: unexpected nil pkg")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700446 }
447
448 // if we saw the package before, write its index (>= 0)
449 if i, ok := p.pkgIndex[pkg]; ok {
450 p.index('P', i)
451 return
452 }
453
454 // otherwise, remember the package, write the package tag (< 0) and package data
455 if p.trace {
456 p.tracef("P%d = { ", len(p.pkgIndex))
457 defer p.tracef("} ")
458 }
459 p.pkgIndex[pkg] = len(p.pkgIndex)
460
461 p.tag(packageTag)
462 p.string(pkg.Name)
463 p.string(pkg.Path)
464}
465
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700466func unidealType(typ *Type, val Val) *Type {
467 // Untyped (ideal) constants get their own type. This decouples
468 // the constant type from the encoding of the constant value.
469 if typ == nil || typ.IsUntyped() {
470 typ = untype(val.Ctype())
471 }
472 return typ
473}
474
475func (p *exporter) obj(sym *Sym) {
476 // Exported objects may be from different packages because they
477 // may be re-exported as depencies when exporting inlined function
478 // bodies. Thus, exported object names must be fully qualified.
479 //
480 // TODO(gri) This can only happen if exportInlined is enabled
481 // (default), and during phase 2 of object export. Objects exported
482 // in phase 1 (compiler-indendepent objects) are by definition only
483 // the objects from the current package and not pulled in via inlined
484 // function bodies. In that case the package qualifier is not needed.
485 // Possible space optimization.
486
487 n := sym.Def
488 switch n.Op {
489 case OLITERAL:
490 // constant
491 // TODO(gri) determine if we need the typecheck call here
492 n = typecheck(n, Erv)
493 if n == nil || n.Op != OLITERAL {
494 Fatalf("exporter: dumpexportconst: oconst nil: %v", sym)
495 }
496
497 p.tag(constTag)
Robert Griesemer5c593a32016-04-13 17:53:03 -0700498 p.pos(n)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700499 // TODO(gri) In inlined functions, constants are used directly
500 // so they should never occur as re-exported objects. We may
501 // not need the qualified name here. See also comment above.
502 // Possible space optimization.
503 p.qualifiedName(sym)
504 p.typ(unidealType(n.Type, n.Val()))
505 p.value(n.Val())
506
507 case OTYPE:
508 // named type
509 t := n.Type
510 if t.Etype == TFORW {
511 Fatalf("exporter: export of incomplete type %v", sym)
512 }
513
514 p.tag(typeTag)
515 p.typ(t)
516
517 case ONAME:
518 // variable or function
519 n = typecheck(n, Erv|Ecall)
520 if n == nil || n.Type == nil {
521 Fatalf("exporter: variable/function exported but not defined: %v", sym)
522 }
523
524 if n.Type.Etype == TFUNC && n.Class == PFUNC {
525 // function
526 p.tag(funcTag)
Robert Griesemer5c593a32016-04-13 17:53:03 -0700527 p.pos(n)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700528 p.qualifiedName(sym)
529
530 sig := sym.Def.Type
531 inlineable := isInlineable(sym.Def)
532
533 p.paramList(sig.Params(), inlineable)
534 p.paramList(sig.Results(), inlineable)
535
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700536 var f *Func
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700537 if inlineable {
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700538 f = sym.Def.Func
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700539 // TODO(gri) re-examine reexportdeplist:
540 // Because we can trivially export types
541 // in-place, we don't need to collect types
542 // inside function bodies in the exportlist.
543 // With an adjusted reexportdeplist used only
544 // by the binary exporter, we can also avoid
545 // the global exportlist.
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700546 reexportdeplist(f.Inl)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700547 }
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700548 p.funcList = append(p.funcList, f)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700549 } else {
550 // variable
551 p.tag(varTag)
Robert Griesemer5c593a32016-04-13 17:53:03 -0700552 p.pos(n)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700553 p.qualifiedName(sym)
554 p.typ(sym.Def.Type)
555 }
556
557 default:
Dave Cheneyd3c79d32016-04-27 15:10:10 +1000558 Fatalf("exporter: unexpected export symbol: %v %v", n.Op, sym)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700559 }
560}
561
Robert Griesemer5c593a32016-04-13 17:53:03 -0700562func (p *exporter) pos(n *Node) {
Robert Griesemer86c93c92016-04-26 22:31:02 -0700563 if !p.posInfoFormat {
Robert Griesemer889c0a62016-04-22 14:50:20 -0700564 return
565 }
566
Robert Griesemer6c11e272016-04-28 12:43:12 -0700567 file, line := fileLine(n)
568 if file == p.prevFile {
569 // common case: write line delta
570 // delta == 0 means different file or no line change
571 delta := line - p.prevLine
572 p.int(delta)
573 if delta == 0 {
574 p.int(-1) // -1 means no file change
575 }
576 } else {
577 // different file
578 p.int(0)
579 // Encode filename as length of common prefix with previous
580 // filename, followed by (possibly empty) suffix. Filenames
581 // frequently share path prefixes, so this can save a lot
582 // of space and make export data size less dependent on file
583 // path length. The suffix is unlikely to be empty because
584 // file names tend to end in ".go".
585 n := commonPrefixLen(p.prevFile, file)
586 p.int(n) // n >= 0
587 p.string(file[n:]) // write suffix only
588 p.prevFile = file
589 p.int(line)
590 }
591 p.prevLine = line
592}
593
594func fileLine(n *Node) (file string, line int) {
Robert Griesemer5c593a32016-04-13 17:53:03 -0700595 if n != nil {
Alan Donovan6e4a8612016-04-25 18:31:36 -0400596 file, line = Ctxt.LineHist.AbsFileLine(int(n.Lineno))
Robert Griesemer5c593a32016-04-13 17:53:03 -0700597 }
Robert Griesemer6c11e272016-04-28 12:43:12 -0700598 return
599}
Robert Griesemer5c593a32016-04-13 17:53:03 -0700600
Robert Griesemer6c11e272016-04-28 12:43:12 -0700601func commonPrefixLen(a, b string) int {
602 if len(a) > len(b) {
603 a, b = b, a
Robert Griesemer5c593a32016-04-13 17:53:03 -0700604 }
Robert Griesemer6c11e272016-04-28 12:43:12 -0700605 // len(a) <= len(b)
606 i := 0
607 for i < len(a) && a[i] == b[i] {
608 i++
609 }
610 return i
Robert Griesemer5c593a32016-04-13 17:53:03 -0700611}
612
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700613func isInlineable(n *Node) bool {
Josh Bleecher Snyder1da62af2016-04-24 13:50:26 -0700614 if exportInlined && n != nil && n.Func != nil && n.Func.Inl.Len() != 0 {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700615 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
616 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
617 if Debug['l'] < 2 {
618 typecheckinl(n)
619 }
620 return true
621 }
622 return false
623}
624
Robert Griesemerbbd1dcd2016-06-01 13:46:49 -0700625var errorInterface *Type // lazily initialized
626
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700627func (p *exporter) typ(t *Type) {
628 if t == nil {
Robert Griesemer45983822015-10-22 18:56:45 -0700629 Fatalf("exporter: nil type")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700630 }
631
632 // Possible optimization: Anonymous pointer types *T where
633 // T is a named type are common. We could canonicalize all
634 // such types *T to a single type PT = *T. This would lead
635 // to at most one *T entry in typIndex, and all future *T's
636 // would be encoded as the respective index directly. Would
637 // save 1 byte (pointerTag) per *T and reduce the typIndex
638 // size (at the cost of a canonicalization map). We can do
639 // this later, without encoding format change.
640
641 // if we saw the type before, write its index (>= 0)
642 if i, ok := p.typIndex[t]; ok {
643 p.index('T', i)
644 return
645 }
646
647 // otherwise, remember the type, write the type tag (< 0) and type data
Robert Griesemer394ac812016-05-05 18:03:59 -0700648 if trackAllTypes {
649 if p.trace {
650 p.tracef("T%d = {>\n", len(p.typIndex))
651 defer p.tracef("<\n} ")
652 }
653 p.typIndex[t] = len(p.typIndex)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700654 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700655
656 // pick off named types
Robert Griesemer81aacb82016-04-06 15:27:30 -0700657 if tsym := t.Sym; tsym != nil {
Robert Griesemer394ac812016-05-05 18:03:59 -0700658 if !trackAllTypes {
659 // if we don't track all types, track named types now
660 p.typIndex[t] = len(p.typIndex)
661 }
662
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700663 // Predeclared types should have been found in the type map.
664 if t.Orig == t {
Robert Griesemer45983822015-10-22 18:56:45 -0700665 Fatalf("exporter: predeclared type missing from type map?")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700666 }
Robert Griesemer5c593a32016-04-13 17:53:03 -0700667
Robert Griesemera5386f32016-04-18 13:55:40 -0700668 n := typenod(t)
669 if n.Type != t {
670 Fatalf("exporter: named type definition incorrectly set up")
671 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700672
673 p.tag(namedTag)
Robert Griesemera5386f32016-04-18 13:55:40 -0700674 p.pos(n)
Robert Griesemer81aacb82016-04-06 15:27:30 -0700675 p.qualifiedName(tsym)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700676
677 // write underlying type
Robert Griesemerbbd1dcd2016-06-01 13:46:49 -0700678 orig := t.Orig
679 if orig == errortype {
680 // The error type is the only predeclared type which has
681 // a composite underlying type. When we encode that type,
682 // make sure to encode the underlying interface rather than
683 // the named type again. See also the comment in universe.go
684 // regarding the errortype and issue #15920.
685 if errorInterface == nil {
686 errorInterface = makeErrorInterface()
687 }
688 orig = errorInterface
689 }
690 p.typ(orig)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700691
692 // interfaces don't have associated methods
Matthew Dempsky3efefd92016-03-30 14:56:08 -0700693 if t.Orig.IsInterface() {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700694 return
695 }
696
697 // sort methods for reproducible export format
698 // TODO(gri) Determine if they are already sorted
699 // in which case we can drop this step.
Matthew Dempsky2e936902016-03-14 01:20:49 -0700700 var methods []*Field
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -0700701 for _, m := range t.Methods().Slice() {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700702 methods = append(methods, m)
703 }
704 sort.Sort(methodbyname(methods))
705 p.int(len(methods))
706
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800707 if p.trace && len(methods) > 0 {
708 p.tracef("associated methods {>")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700709 }
710
711 for _, m := range methods {
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800712 if p.trace {
713 p.tracef("\n")
714 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700715 if strings.Contains(m.Sym.Name, ".") {
716 Fatalf("invalid symbol name: %s (%v)", m.Sym.Name, m.Sym)
717 }
718
Robert Griesemere8d4ffb2016-04-27 17:30:20 -0700719 p.pos(m.Nname)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700720 p.fieldSym(m.Sym, false)
721
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800722 sig := m.Type
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700723 mfn := sig.Nname()
724 inlineable := isInlineable(mfn)
725
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800726 p.paramList(sig.Recvs(), inlineable)
727 p.paramList(sig.Params(), inlineable)
728 p.paramList(sig.Results(), inlineable)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700729
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700730 var f *Func
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800731 if inlineable {
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700732 f = mfn.Func
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700733 reexportdeplist(mfn.Func.Inl)
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800734 }
Robert Griesemer7d0d1222016-04-12 18:00:04 -0700735 p.funcList = append(p.funcList, f)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700736 }
737
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800738 if p.trace && len(methods) > 0 {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700739 p.tracef("<\n} ")
740 }
741
742 return
743 }
744
745 // otherwise we have a type literal
746 switch t.Etype {
747 case TARRAY:
Josh Bleecher Snyder272df152016-03-27 17:57:42 -0700748 if t.isDDDArray() {
749 Fatalf("array bounds should be known at export time: %v", t)
750 }
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -0700751 p.tag(arrayTag)
752 p.int64(t.NumElem())
753 p.typ(t.Elem())
754
755 case TSLICE:
756 p.tag(sliceTag)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700757 p.typ(t.Elem())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700758
Josh Bleecher Snydera6377172016-03-27 12:30:16 -0700759 case TDDDFIELD:
760 // see p.param use of TDDDFIELD
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700761 p.tag(dddTag)
Josh Bleecher Snyderf38f43d2016-04-01 20:11:30 -0700762 p.typ(t.DDDField())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700763
764 case TSTRUCT:
765 p.tag(structTag)
766 p.fieldList(t)
767
768 case TPTR32, TPTR64: // could use Tptr but these are constants
769 p.tag(pointerTag)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700770 p.typ(t.Elem())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700771
772 case TFUNC:
773 p.tag(signatureTag)
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800774 p.paramList(t.Params(), false)
775 p.paramList(t.Results(), false)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700776
777 case TINTER:
778 p.tag(interfaceTag)
779
780 // gc doesn't separate between embedded interfaces
781 // and methods declared explicitly with an interface
782 p.int(0) // no embedded interfaces
783 p.methodList(t)
784
785 case TMAP:
786 p.tag(mapTag)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700787 p.typ(t.Key())
788 p.typ(t.Val())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700789
790 case TCHAN:
791 p.tag(chanTag)
Josh Bleecher Snyder29267c22016-04-02 16:26:30 -0700792 p.int(int(t.ChanDir()))
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700793 p.typ(t.Elem())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700794
795 default:
Robert Griesemer45983822015-10-22 18:56:45 -0700796 Fatalf("exporter: unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700797 }
798}
799
800func (p *exporter) qualifiedName(sym *Sym) {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700801 if strings.Contains(sym.Name, ".") {
802 Fatalf("exporter: invalid symbol name: %s", sym.Name)
803 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700804 p.string(sym.Name)
805 p.pkg(sym.Pkg)
806}
807
808func (p *exporter) fieldList(t *Type) {
Matthew Dempskydbed1c62016-03-17 13:26:08 -0700809 if p.trace && t.NumFields() > 0 {
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800810 p.tracef("fields {>")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700811 defer p.tracef("<\n} ")
812 }
813
Matthew Dempskydbed1c62016-03-17 13:26:08 -0700814 p.int(t.NumFields())
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -0700815 for _, f := range t.Fields().Slice() {
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800816 if p.trace {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700817 p.tracef("\n")
818 }
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800819 p.field(f)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700820 }
821}
822
Matthew Dempsky2e936902016-03-14 01:20:49 -0700823func (p *exporter) field(f *Field) {
Robert Griesemere8d4ffb2016-04-27 17:30:20 -0700824 p.pos(f.Nname)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700825 p.fieldName(f.Sym, f)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700826 p.typ(f.Type)
Matthew Dempskye48a2952016-04-25 13:24:48 -0700827 p.string(f.Note)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700828}
829
830func (p *exporter) methodList(t *Type) {
Matthew Dempskydbed1c62016-03-17 13:26:08 -0700831 if p.trace && t.NumFields() > 0 {
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800832 p.tracef("methods {>")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700833 defer p.tracef("<\n} ")
834 }
835
Matthew Dempskydbed1c62016-03-17 13:26:08 -0700836 p.int(t.NumFields())
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -0700837 for _, m := range t.Fields().Slice() {
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800838 if p.trace {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700839 p.tracef("\n")
840 }
Matthew Dempskyde4317c2016-03-11 03:25:00 -0800841 p.method(m)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700842 }
843}
844
Matthew Dempsky2e936902016-03-14 01:20:49 -0700845func (p *exporter) method(m *Field) {
Robert Griesemere8d4ffb2016-04-27 17:30:20 -0700846 p.pos(m.Nname)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700847 p.fieldName(m.Sym, m)
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800848 p.paramList(m.Type.Params(), false)
849 p.paramList(m.Type.Results(), false)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700850}
851
852// fieldName is like qualifiedName but it doesn't record the package
853// for blank (_) or exported names.
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700854func (p *exporter) fieldName(sym *Sym, t *Field) {
855 if t != nil && sym != t.Sym {
856 Fatalf("exporter: invalid fieldName parameters")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700857 }
858
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700859 name := sym.Name
860 if t != nil {
861 if t.Embedded == 0 {
862 name = sym.Name
863 } else if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
864 // anonymous field with unexported base type name: use "?" as field name
865 // (bname != "" per spec, but we are conservative in case of errors)
866 name = "?"
867 } else {
868 name = ""
869 }
870 }
871
872 if strings.Contains(name, ".") {
873 Fatalf("exporter: invalid symbol name: %s", name)
874 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700875 p.string(name)
876 if name == "?" || name != "_" && name != "" && !exportname(name) {
877 p.pkg(sym.Pkg)
878 }
879}
880
881func basetypeName(t *Type) string {
882 s := t.Sym
Matthew Dempskye76fc1b2016-03-30 15:09:25 -0700883 if s == nil && t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700884 s = t.Elem().Sym // deref
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700885 }
886 if s != nil {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700887 if strings.Contains(s.Name, ".") {
888 Fatalf("exporter: invalid symbol name: %s", s.Name)
889 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700890 return s.Name
891 }
892 return ""
893}
894
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800895func (p *exporter) paramList(params *Type, numbered bool) {
Josh Bleecher Snyderfda831e2016-04-05 16:44:07 -0700896 if !params.IsFuncArgStruct() {
Robert Griesemer45983822015-10-22 18:56:45 -0700897 Fatalf("exporter: parameter list expected")
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700898 }
899
900 // use negative length to indicate unnamed parameters
901 // (look at the first parameter only since either all
902 // names are present or all are absent)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700903 //
904 // TODO(gri) If we don't have an exported function
905 // body, the parameter names are irrelevant for the
906 // compiler (though they may be of use for other tools).
907 // Possible space optimization.
Matthew Dempskydbed1c62016-03-17 13:26:08 -0700908 n := params.NumFields()
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800909 if n > 0 && parName(params.Field(0), numbered) == "" {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700910 n = -n
911 }
912 p.int(n)
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -0700913 for _, q := range params.Fields().Slice() {
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800914 p.param(q, n, numbered)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700915 }
916}
917
Robert Griesemereb4d1be2016-03-11 13:40:01 -0800918func (p *exporter) param(q *Field, n int, numbered bool) {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700919 t := q.Type
920 if q.Isddd {
921 // create a fake type to encode ... just for the p.typ call
Josh Bleecher Snyderf38f43d2016-04-01 20:11:30 -0700922 t = typDDDField(t.Elem())
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700923 }
924 p.typ(t)
925 if n > 0 {
Robert Griesemer15f7a662016-05-02 17:03:36 -0700926 name := parName(q, numbered)
927 if name == "" {
928 // Sometimes we see an empty name even for n > 0.
929 // This appears to happen for interface methods
930 // with _ (blank) parameter names. Make sure we
931 // have a proper name and package so we don't crash
932 // during import (see also issue #15470).
933 // (parName uses "" instead of "?" as in fmt.go)
934 // TODO(gri) review parameter name encoding
935 name = "_"
936 }
937 p.string(name)
938 if name != "_" {
Robert Griesemer80e9a7f2016-04-27 22:04:49 -0700939 // Because of (re-)exported inlined functions
940 // the importpkg may not be the package to which this
941 // function (and thus its parameter) belongs. We need to
942 // supply the parameter package here. We need the package
943 // when the function is inlined so we can properly resolve
Robert Griesemer15f7a662016-05-02 17:03:36 -0700944 // the name. The _ (blank) parameter cannot be accessed, so
945 // we don't need to export a package.
946 //
Robert Griesemer80e9a7f2016-04-27 22:04:49 -0700947 // TODO(gri) This is compiler-specific. Try using importpkg
948 // here and then update the symbols if we find an inlined
949 // body only. Otherwise, the parameter name is ignored and
950 // the package doesn't matter. This would remove an int
951 // (likely 1 byte) for each named parameter.
952 p.pkg(q.Sym.Pkg)
Robert Griesemer80e9a7f2016-04-27 22:04:49 -0700953 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700954 }
955 // TODO(gri) This is compiler-specific (escape info).
956 // Move into compiler-specific section eventually?
957 // (Not having escape info causes tests to fail, e.g. runtime GCInfoTest)
Matthew Dempskye48a2952016-04-25 13:24:48 -0700958 p.string(q.Note)
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700959}
960
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700961func parName(f *Field, numbered bool) string {
962 s := f.Sym
963 if s == nil {
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700964 return ""
965 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700966
967 // Take the name from the original, lest we substituted it with ~r%d or ~b%d.
968 // ~r%d is a (formerly) unnamed result.
969 if f.Nname != nil {
970 if f.Nname.Orig != nil {
971 s = f.Nname.Orig.Sym
972 if s != nil && s.Name[0] == '~' {
973 if s.Name[1] == 'r' { // originally an unnamed result
974 return "" // s = nil
975 } else if s.Name[1] == 'b' { // originally the blank identifier _
Robert Griesemer15f7a662016-05-02 17:03:36 -0700976 return "_" // belongs to localpkg
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700977 }
978 }
979 } else {
980 return "" // s = nil
Robert Griesemerae2f54a2015-08-13 19:05:37 -0700981 }
982 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700983
984 if s == nil {
985 return ""
986 }
987
988 // print symbol with Vargen number or not as desired
989 name := s.Name
990 if strings.Contains(name, ".") {
Robert Griesemer87a2ae12016-05-08 20:59:53 -0700991 Fatalf("invalid symbol name: %s", name)
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700992 }
993
994 // Functions that can be inlined use numbered parameters so we can distingish them
995 // from other names in their context after inlining (i.e., the parameter numbering
996 // is a form of parameter rewriting). See issue 4326 for an example and test case.
Robert Griesemerd78c84c2016-04-25 15:59:42 -0700997 if forceObjFileStability || numbered {
Robert Griesemera9ea36a2016-03-18 17:21:32 -0700998 if !strings.Contains(name, "·") && f.Nname != nil && f.Nname.Name != nil && f.Nname.Name.Vargen > 0 {
999 name = fmt.Sprintf("%s·%d", name, f.Nname.Name.Vargen) // append Vargen
1000 }
1001 } else {
Robert Griesemereb4d1be2016-03-11 13:40:01 -08001002 if i := strings.Index(name, "·"); i > 0 {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001003 name = name[:i] // cut off Vargen
Robert Griesemereb4d1be2016-03-11 13:40:01 -08001004 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001005 }
1006 return name
1007}
1008
1009func (p *exporter) value(x Val) {
1010 if p.trace {
1011 p.tracef("= ")
1012 }
1013
1014 switch x := x.U.(type) {
1015 case bool:
1016 tag := falseTag
1017 if x {
1018 tag = trueTag
1019 }
1020 p.tag(tag)
1021
1022 case *Mpint:
Matthew Dempskyd3253872016-03-20 13:55:42 -07001023 if Minintval[TINT64].Cmp(x) <= 0 && x.Cmp(Maxintval[TINT64]) <= 0 {
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001024 // common case: x fits into an int64 - use compact encoding
1025 p.tag(int64Tag)
Matthew Dempskyd3253872016-03-20 13:55:42 -07001026 p.int64(x.Int64())
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001027 return
1028 }
1029 // uncommon case: large x - use float encoding
1030 // (powers of 2 will be encoded efficiently with exponent)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001031 f := newMpflt()
Matthew Dempskyd3253872016-03-20 13:55:42 -07001032 f.SetInt(x)
Robert Griesemer45983822015-10-22 18:56:45 -07001033 p.tag(floatTag)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001034 p.float(f)
1035
1036 case *Mpflt:
1037 p.tag(floatTag)
1038 p.float(x)
1039
1040 case *Mpcplx:
1041 p.tag(complexTag)
1042 p.float(&x.Real)
1043 p.float(&x.Imag)
1044
1045 case string:
1046 p.tag(stringTag)
1047 p.string(x)
1048
Robert Griesemer45983822015-10-22 18:56:45 -07001049 case *NilVal:
1050 // not a constant but used in exported function bodies
1051 p.tag(nilTag)
1052
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001053 default:
Robert Griesemer45983822015-10-22 18:56:45 -07001054 Fatalf("exporter: unexpected value %v (%T)", x, x)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001055 }
1056}
1057
1058func (p *exporter) float(x *Mpflt) {
Robert Griesemer79a3b562015-10-22 14:14:41 -07001059 // extract sign (there is no -0)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001060 f := &x.Val
1061 sign := f.Sign()
1062 if sign == 0 {
Robert Griesemer79a3b562015-10-22 14:14:41 -07001063 // x == 0
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001064 p.int(0)
1065 return
1066 }
1067 // x != 0
1068
1069 // extract exponent such that 0.5 <= m < 1.0
1070 var m big.Float
1071 exp := f.MantExp(&m)
1072
1073 // extract mantissa as *big.Int
1074 // - set exponent large enough so mant satisfies mant.IsInt()
1075 // - get *big.Int from mant
1076 m.SetMantExp(&m, int(m.MinPrec()))
1077 mant, acc := m.Int(nil)
1078 if acc != big.Exact {
Robert Griesemer45983822015-10-22 18:56:45 -07001079 Fatalf("exporter: internal error")
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001080 }
1081
1082 p.int(sign)
1083 p.int(exp)
1084 p.string(string(mant.Bytes()))
1085}
1086
1087// ----------------------------------------------------------------------------
1088// Inlined function bodies
1089
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001090// Approach: More or less closely follow what fmt.go is doing for FExp mode
1091// but instead of emitting the information textually, emit the node tree in
1092// binary form.
1093
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001094// TODO(gri) Improve tracing output. The current format is difficult to read.
1095
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001096// stmtList may emit more (or fewer) than len(list) nodes.
1097func (p *exporter) stmtList(list Nodes) {
1098 if p.trace {
1099 if list.Len() == 0 {
1100 p.tracef("{}")
1101 } else {
1102 p.tracef("{>")
1103 defer p.tracef("<\n}")
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001104 }
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001105 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001106
1107 for _, n := range list.Slice() {
1108 if p.trace {
1109 p.tracef("\n")
1110 }
1111 // TODO inlining produces expressions with ninits. we can't export these yet.
1112 // (from fmt.go:1461ff)
1113 if opprec[n.Op] < 0 {
1114 p.stmt(n)
1115 } else {
1116 p.expr(n)
1117 }
1118 }
1119
1120 p.op(OEND)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001121}
1122
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001123func (p *exporter) exprList(list Nodes) {
1124 if p.trace {
1125 if list.Len() == 0 {
1126 p.tracef("{}")
1127 } else {
1128 p.tracef("{>")
1129 defer p.tracef("<\n}")
1130 }
1131 }
1132
1133 for _, n := range list.Slice() {
1134 if p.trace {
1135 p.tracef("\n")
1136 }
1137 p.expr(n)
1138 }
1139
1140 p.op(OEND)
1141}
1142
1143func (p *exporter) elemList(list Nodes) {
Robert Griesemer45983822015-10-22 18:56:45 -07001144 if p.trace {
1145 p.tracef("[ ")
1146 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001147 p.int(list.Len())
Robert Griesemer45983822015-10-22 18:56:45 -07001148 if p.trace {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001149 if list.Len() == 0 {
Robert Griesemer45983822015-10-22 18:56:45 -07001150 p.tracef("] {}")
1151 } else {
1152 p.tracef("] {>")
1153 defer p.tracef("<\n}")
1154 }
1155 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001156
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001157 for _, n := range list.Slice() {
Robert Griesemer45983822015-10-22 18:56:45 -07001158 if p.trace {
1159 p.tracef("\n")
1160 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001161 p.fieldSym(n.Left.Sym, false)
1162 p.expr(n.Right)
Robert Griesemer45983822015-10-22 18:56:45 -07001163 }
1164}
1165
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001166func (p *exporter) expr(n *Node) {
1167 if p.trace {
1168 p.tracef("( ")
1169 defer p.tracef(") ")
1170 }
Robert Griesemer45983822015-10-22 18:56:45 -07001171
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001172 // from nodefmt (fmt.go)
1173 //
1174 // nodefmt reverts nodes back to their original - we don't need to do
1175 // it because we are not bound to produce valid Go syntax when exporting
1176 //
1177 // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
1178 // n = n.Orig
1179 // }
1180
1181 // from exprfmt (fmt.go)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001182 for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
1183 n = n.Left
1184 }
Robert Griesemer45983822015-10-22 18:56:45 -07001185
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001186 switch op := n.Op; op {
1187 // expressions
1188 // (somewhat closely following the structure of exprfmt in fmt.go)
1189 case OPAREN:
1190 p.expr(n.Left) // unparen
1191
1192 // case ODDDARG:
1193 // unimplemented - handled by default case
1194
1195 // case OREGISTER:
1196 // unimplemented - handled by default case
Robert Griesemer45983822015-10-22 18:56:45 -07001197
1198 case OLITERAL:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001199 if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
1200 p.expr(n.Orig)
1201 break
1202 }
1203 p.op(OLITERAL)
Robert Griesemer45983822015-10-22 18:56:45 -07001204 p.typ(unidealType(n.Type, n.Val()))
1205 p.value(n.Val())
1206
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001207 case ONAME:
1208 // Special case: name used as local variable in export.
1209 // _ becomes ~b%d internally; print as _ for export
1210 if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
Robert Griesemeref62f642016-05-11 12:40:17 -07001211 p.op(ONAME)
Robert Griesemeraff48892016-05-11 11:28:36 -07001212 p.string("_") // inlined and customized version of p.sym(n)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001213 break
Robert Griesemer45983822015-10-22 18:56:45 -07001214 }
1215
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001216 if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
Robert Griesemeref62f642016-05-11 12:40:17 -07001217 p.op(ONAME)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001218 p.sym(n)
1219 break
1220 }
Robert Griesemer45983822015-10-22 18:56:45 -07001221
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001222 // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
1223 // but for export, this should be rendered as (*pkg.T).meth.
1224 // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
1225 if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
Robert Griesemeraff48892016-05-11 11:28:36 -07001226 p.op(OXDOT)
1227 p.expr(n.Left) // n.Left.Op == OTYPE
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001228 p.fieldSym(n.Right.Sym, true)
1229 break
1230 }
1231
Robert Griesemeref62f642016-05-11 12:40:17 -07001232 p.op(ONAME)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001233 p.sym(n)
1234
Robert Griesemeref62f642016-05-11 12:40:17 -07001235 // case OPACK, ONONAME:
1236 // should have been resolved by typechecking - handled by default case
1237
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001238 case OTYPE:
1239 p.op(OTYPE)
1240 if p.bool(n.Type == nil) {
1241 p.sym(n)
Robert Griesemer45983822015-10-22 18:56:45 -07001242 } else {
1243 p.typ(n.Type)
1244 }
1245
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001246 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
1247 // should have been resolved by typechecking - handled by default case
Robert Griesemer45983822015-10-22 18:56:45 -07001248
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001249 // case OCLOSURE:
1250 // unimplemented - handled by default case
1251
1252 // case OCOMPLIT:
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001253 // should have been resolved by typechecking - handled by default case
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001254
1255 case OPTRLIT:
1256 p.op(OPTRLIT)
1257 p.expr(n.Left)
1258 p.bool(n.Implicit)
1259
1260 case OSTRUCTLIT:
1261 p.op(OSTRUCTLIT)
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001262 p.typ(n.Type)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001263 p.elemList(n.List) // special handling of field names
1264
1265 case OARRAYLIT, OMAPLIT:
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001266 p.op(OCOMPLIT)
1267 p.typ(n.Type)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001268 p.exprList(n.List)
1269
1270 case OKEY:
1271 p.op(OKEY)
1272 p.exprsOrNil(n.Left, n.Right)
1273
1274 // case OCALLPART:
1275 // unimplemented - handled by default case
1276
1277 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
1278 p.op(OXDOT)
1279 p.expr(n.Left)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001280 p.fieldSym(n.Sym, true)
1281
1282 case ODOTTYPE, ODOTTYPE2:
1283 p.op(ODOTTYPE)
1284 p.expr(n.Left)
1285 if p.bool(n.Right != nil) {
1286 p.expr(n.Right)
1287 } else {
1288 p.typ(n.Type)
1289 }
1290
1291 case OINDEX, OINDEXMAP:
1292 p.op(OINDEX)
1293 p.expr(n.Left)
1294 p.expr(n.Right)
1295
1296 case OSLICE, OSLICESTR, OSLICEARR:
1297 p.op(OSLICE)
1298 p.expr(n.Left)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001299 low, high, _ := n.SliceBounds()
1300 p.exprsOrNil(low, high)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001301
1302 case OSLICE3, OSLICE3ARR:
1303 p.op(OSLICE3)
1304 p.expr(n.Left)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001305 low, high, max := n.SliceBounds()
1306 p.exprsOrNil(low, high)
1307 p.expr(max)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001308
1309 case OCOPY, OCOMPLEX:
Robert Griesemer21d78102016-05-11 13:39:36 -07001310 // treated like other builtin calls (see e.g., OREAL)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001311 p.op(op)
1312 p.expr(n.Left)
1313 p.expr(n.Right)
Robert Griesemer21d78102016-05-11 13:39:36 -07001314 p.op(OEND)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001315
1316 case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
1317 p.op(OCONV)
1318 p.typ(n.Type)
Robert Griesemer21d78102016-05-11 13:39:36 -07001319 if n.Left != nil {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001320 p.expr(n.Left)
Robert Griesemer21d78102016-05-11 13:39:36 -07001321 p.op(OEND)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001322 } else {
Robert Griesemer21d78102016-05-11 13:39:36 -07001323 p.exprList(n.List) // emits terminating OEND
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001324 }
1325
1326 case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
1327 p.op(op)
Robert Griesemer21d78102016-05-11 13:39:36 -07001328 if n.Left != nil {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001329 p.expr(n.Left)
Robert Griesemer21d78102016-05-11 13:39:36 -07001330 p.op(OEND)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001331 } else {
Robert Griesemer21d78102016-05-11 13:39:36 -07001332 p.exprList(n.List) // emits terminating OEND
1333 }
1334 // only append() calls may contain '...' arguments
1335 if op == OAPPEND {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001336 p.bool(n.Isddd)
Robert Griesemer21d78102016-05-11 13:39:36 -07001337 } else if n.Isddd {
1338 Fatalf("exporter: unexpected '...' with %s call", opnames[op])
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001339 }
Robert Griesemer45983822015-10-22 18:56:45 -07001340
1341 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001342 p.op(OCALL)
1343 p.expr(n.Left)
1344 p.exprList(n.List)
Robert Griesemer45983822015-10-22 18:56:45 -07001345 p.bool(n.Isddd)
1346
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001347 case OMAKEMAP, OMAKECHAN, OMAKESLICE:
1348 p.op(op) // must keep separate from OMAKE for importer
1349 p.typ(n.Type)
1350 switch {
1351 default:
1352 // empty list
1353 p.op(OEND)
1354 case n.List.Len() != 0: // pre-typecheck
1355 p.exprList(n.List) // emits terminating OEND
1356 case n.Right != nil:
1357 p.expr(n.Left)
1358 p.expr(n.Right)
1359 p.op(OEND)
1360 case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()):
1361 p.expr(n.Left)
1362 p.op(OEND)
1363 }
1364
1365 // unary expressions
1366 case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
1367 p.op(op)
1368 p.expr(n.Left)
1369
1370 // binary expressions
1371 case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
1372 OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
1373 p.op(op)
1374 p.expr(n.Left)
1375 p.expr(n.Right)
1376
1377 case OADDSTR:
1378 p.op(OADDSTR)
1379 p.exprList(n.List)
1380
Robert Griesemer45983822015-10-22 18:56:45 -07001381 case OCMPSTR, OCMPIFACE:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001382 p.op(Op(n.Etype))
1383 p.expr(n.Left)
1384 p.expr(n.Right)
Robert Griesemer45983822015-10-22 18:56:45 -07001385
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001386 case ODCLCONST:
1387 // if exporting, DCLCONST should just be removed as its usage
1388 // has already been replaced with literals
1389 // TODO(gri) these should not be exported in the first place
1390 // TODO(gri) why is this considered an expression in fmt.go?
1391 p.op(ODCLCONST)
Robert Griesemer45983822015-10-22 18:56:45 -07001392
1393 default:
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001394 Fatalf("cannot export %s (%d) node\n"+
1395 "==> please file an issue and assign to gri@\n", n.Op, n.Op)
Robert Griesemer45983822015-10-22 18:56:45 -07001396 }
1397}
1398
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001399// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
1400// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
1401func (p *exporter) stmt(n *Node) {
1402 if p.trace {
1403 p.tracef("( ")
1404 defer p.tracef(") ")
1405 }
1406
1407 if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) {
1408 if p.trace {
1409 p.tracef("( /* Ninits */ ")
1410 }
1411
1412 // can't use stmtList here since we don't want the final OEND
1413 for _, n := range n.Ninit.Slice() {
1414 p.stmt(n)
1415 }
1416
1417 if p.trace {
1418 p.tracef(") ")
1419 }
1420 }
1421
1422 switch op := n.Op; op {
1423 case ODCL:
1424 p.op(ODCL)
Russ Coxb6dc3e62016-05-25 01:33:24 -04001425 switch n.Left.Class {
1426 case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001427 // TODO(gri) when is this not PAUTO?
1428 // Also, originally this didn't look like
1429 // the default case. Investigate.
1430 fallthrough
1431 default:
1432 // TODO(gri) Can we ever reach here?
1433 p.bool(false)
1434 p.sym(n.Left)
1435 }
1436 p.typ(n.Left.Type)
1437
1438 // case ODCLFIELD:
1439 // unimplemented - handled by default case
1440
1441 case OAS, OASWB:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001442 // Don't export "v = <N>" initializing statements, hope they're always
1443 // preceded by the DCL which will be re-parsed and typecheck to reproduce
1444 // the "v = <N>" again.
Robert Griesemer6e5027a2016-04-13 13:17:30 -07001445 if n.Right != nil {
1446 p.op(OAS)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001447 p.expr(n.Left)
1448 p.expr(n.Right)
1449 }
1450
1451 case OASOP:
1452 p.op(OASOP)
1453 p.int(int(n.Etype))
1454 p.expr(n.Left)
1455 if p.bool(!n.Implicit) {
1456 p.expr(n.Right)
1457 }
1458
Robert Griesemeref62f642016-05-11 12:40:17 -07001459 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001460 p.op(OAS2)
1461 p.exprList(n.List)
1462 p.exprList(n.Rlist)
1463
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001464 case ORETURN:
1465 p.op(ORETURN)
1466 p.exprList(n.List)
1467
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001468 // case ORETJMP:
1469 // unreachable - generated by compiler for trampolin routines
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001470
1471 case OPROC, ODEFER:
1472 p.op(op)
1473 p.expr(n.Left)
1474
1475 case OIF:
1476 p.op(OIF)
1477 p.stmtList(n.Ninit)
1478 p.expr(n.Left)
1479 p.stmtList(n.Nbody)
1480 p.stmtList(n.Rlist)
1481
1482 case OFOR:
1483 p.op(OFOR)
1484 p.stmtList(n.Ninit)
1485 p.exprsOrNil(n.Left, n.Right)
1486 p.stmtList(n.Nbody)
1487
1488 case ORANGE:
1489 p.op(ORANGE)
1490 p.stmtList(n.List)
1491 p.expr(n.Right)
1492 p.stmtList(n.Nbody)
1493
1494 case OSELECT, OSWITCH:
1495 p.op(op)
1496 p.stmtList(n.Ninit)
1497 p.exprsOrNil(n.Left, nil)
1498 p.stmtList(n.List)
1499
1500 case OCASE, OXCASE:
Robert Griesemer6e5027a2016-04-13 13:17:30 -07001501 p.op(OXCASE)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001502 p.stmtList(n.List)
1503 p.stmtList(n.Nbody)
1504
Robert Griesemer30282b02016-05-25 16:38:02 -07001505 case OFALL, OXFALL:
1506 p.op(OXFALL)
Robert Griesemer6e5027a2016-04-13 13:17:30 -07001507
Robert Griesemer30282b02016-05-25 16:38:02 -07001508 case OBREAK, OCONTINUE:
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001509 p.op(op)
1510 p.exprsOrNil(n.Left, nil)
1511
1512 case OEMPTY:
Robert Griesemer87a2ae12016-05-08 20:59:53 -07001513 // nothing to emit
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001514
Robert Griesemer30282b02016-05-25 16:38:02 -07001515 case OGOTO, OLABEL:
1516 p.op(op)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001517 p.expr(n.Left)
1518
1519 default:
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -07001520 Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001521 }
1522}
1523
1524func (p *exporter) exprsOrNil(a, b *Node) {
Robert Griesemer45983822015-10-22 18:56:45 -07001525 ab := 0
1526 if a != nil {
1527 ab |= 1
1528 }
1529 if b != nil {
1530 ab |= 2
1531 }
1532 p.int(ab)
1533 if ab&1 != 0 {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001534 p.expr(a)
Robert Griesemer45983822015-10-22 18:56:45 -07001535 }
1536 if ab&2 != 0 {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001537 p.expr(b)
Robert Griesemer45983822015-10-22 18:56:45 -07001538 }
1539}
1540
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001541func (p *exporter) fieldSym(s *Sym, short bool) {
Robert Griesemer45983822015-10-22 18:56:45 -07001542 name := s.Name
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001543
1544 // remove leading "type." in method names ("(T).m" -> "m")
1545 if short {
1546 if i := strings.LastIndex(name, "."); i >= 0 {
1547 name = name[i+1:]
1548 }
1549 }
1550
Robert Griesemer15f7a662016-05-02 17:03:36 -07001551 // we should never see a _ (blank) here - these are accessible ("read") fields
1552 // TODO(gri) can we assert this with an explicit check?
Robert Griesemer45983822015-10-22 18:56:45 -07001553 p.string(name)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001554 if !exportname(name) {
1555 p.pkg(s.Pkg)
1556 }
1557}
1558
Robert Griesemeraff48892016-05-11 11:28:36 -07001559// sym must encode the _ (blank) identifier as a single string "_" since
1560// encoding for some nodes is based on this assumption (e.g. ONAME nodes).
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001561func (p *exporter) sym(n *Node) {
1562 s := n.Sym
1563 if s.Pkg != nil {
1564 if len(s.Name) > 0 && s.Name[0] == '.' {
1565 Fatalf("exporter: exporting synthetic symbol %s", s.Name)
1566 }
1567 }
1568
1569 if p.trace {
1570 p.tracef("{ SYM ")
1571 defer p.tracef("} ")
1572 }
1573
1574 name := s.Name
1575
1576 // remove leading "type." in method names ("(T).m" -> "m")
1577 if i := strings.LastIndex(name, "."); i >= 0 {
1578 name = name[i+1:]
1579 }
1580
1581 if strings.Contains(name, "·") && n.Name.Vargen > 0 {
1582 Fatalf("exporter: unexpected · in symbol name")
1583 }
1584
1585 if i := n.Name.Vargen; i > 0 {
1586 name = fmt.Sprintf("%s·%d", name, i)
1587 }
1588
1589 p.string(name)
1590 if name != "_" {
Robert Griesemer45983822015-10-22 18:56:45 -07001591 p.pkg(s.Pkg)
1592 }
1593}
1594
1595func (p *exporter) bool(b bool) bool {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001596 if p.trace {
1597 p.tracef("[")
1598 defer p.tracef("= %v] ", b)
1599 }
1600
Robert Griesemer45983822015-10-22 18:56:45 -07001601 x := 0
1602 if b {
1603 x = 1
1604 }
1605 p.int(x)
1606 return b
1607}
1608
1609func (p *exporter) op(op Op) {
Robert Griesemer45983822015-10-22 18:56:45 -07001610 if p.trace {
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001611 p.tracef("[")
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -07001612 defer p.tracef("= %s] ", op)
Robert Griesemer45983822015-10-22 18:56:45 -07001613 }
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001614
1615 p.int(int(op))
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001616}
1617
1618// ----------------------------------------------------------------------------
1619// Low-level encoders
1620
1621func (p *exporter) index(marker byte, index int) {
1622 if index < 0 {
Robert Griesemer45983822015-10-22 18:56:45 -07001623 Fatalf("exporter: invalid index < 0")
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001624 }
1625 if debugFormat {
1626 p.marker('t')
1627 }
1628 if p.trace {
1629 p.tracef("%c%d ", marker, index)
1630 }
1631 p.rawInt64(int64(index))
1632}
1633
1634func (p *exporter) tag(tag int) {
1635 if tag >= 0 {
Robert Griesemer45983822015-10-22 18:56:45 -07001636 Fatalf("exporter: invalid tag >= 0")
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001637 }
1638 if debugFormat {
1639 p.marker('t')
1640 }
1641 if p.trace {
1642 p.tracef("%s ", tagString[-tag])
1643 }
1644 p.rawInt64(int64(tag))
1645}
1646
1647func (p *exporter) int(x int) {
1648 p.int64(int64(x))
1649}
1650
1651func (p *exporter) int64(x int64) {
1652 if debugFormat {
1653 p.marker('i')
1654 }
1655 if p.trace {
1656 p.tracef("%d ", x)
1657 }
1658 p.rawInt64(x)
1659}
1660
1661func (p *exporter) string(s string) {
1662 if debugFormat {
1663 p.marker('s')
1664 }
1665 if p.trace {
1666 p.tracef("%q ", s)
1667 }
Robert Griesemer5c593a32016-04-13 17:53:03 -07001668 // if we saw the string before, write its index (>= 0)
1669 // (the empty string is mapped to 0)
1670 if i, ok := p.strIndex[s]; ok {
1671 p.rawInt64(int64(i))
1672 return
1673 }
1674 // otherwise, remember string and write its negative length and bytes
1675 p.strIndex[s] = len(p.strIndex)
1676 p.rawInt64(-int64(len(s)))
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001677 for i := 0; i < len(s); i++ {
Robert Griesemer5c593a32016-04-13 17:53:03 -07001678 p.rawByte(s[i])
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001679 }
1680}
1681
1682// marker emits a marker byte and position information which makes
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001683// it easy for a reader to detect if it is "out of sync". Used only
1684// if debugFormat is set.
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001685func (p *exporter) marker(m byte) {
Robert Griesemer5c593a32016-04-13 17:53:03 -07001686 p.rawByte(m)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001687 // Uncomment this for help tracking down the location
1688 // of an incorrect marker when running in debugFormat.
1689 // if p.trace {
1690 // p.tracef("#%d ", p.written)
1691 // }
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001692 p.rawInt64(int64(p.written))
1693}
1694
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001695// rawInt64 should only be used by low-level encoders
1696func (p *exporter) rawInt64(x int64) {
1697 var tmp [binary.MaxVarintLen64]byte
1698 n := binary.PutVarint(tmp[:], x)
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001699 for i := 0; i < n; i++ {
Robert Griesemer5c593a32016-04-13 17:53:03 -07001700 p.rawByte(tmp[i])
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001701 }
1702}
1703
Robert Griesemer5c593a32016-04-13 17:53:03 -07001704// rawByte is the bottleneck interface to write to p.out.
1705// rawByte escapes b as follows (any encoding does that
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001706// hides '$'):
1707//
1708// '$' => '|' 'S'
1709// '|' => '|' '|'
1710//
1711// Necessary so other tools can find the end of the
1712// export data by searching for "$$".
Robert Griesemer5c593a32016-04-13 17:53:03 -07001713// rawByte should only be used by low-level encoders.
1714func (p *exporter) rawByte(b byte) {
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001715 switch b {
1716 case '$':
1717 // write '$' as '|' 'S'
1718 b = 'S'
1719 fallthrough
1720 case '|':
1721 // write '|' as '|' '|'
Matthew Dempsky4b7e36c2016-04-06 21:45:29 -07001722 p.out.WriteByte('|')
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001723 p.written++
1724 }
Matthew Dempsky4b7e36c2016-04-06 21:45:29 -07001725 p.out.WriteByte(b)
Robert Griesemere6ccfc12015-10-23 16:01:09 -07001726 p.written++
1727}
1728
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001729// tracef is like fmt.Printf but it rewrites the format string
1730// to take care of indentation.
1731func (p *exporter) tracef(format string, args ...interface{}) {
Nathan VanBenschotenb04f3b02015-12-22 02:40:47 -05001732 if strings.ContainsAny(format, "<>\n") {
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001733 var buf bytes.Buffer
1734 for i := 0; i < len(format); i++ {
1735 // no need to deal with runes
1736 ch := format[i]
1737 switch ch {
1738 case '>':
1739 p.indent++
1740 continue
1741 case '<':
1742 p.indent--
1743 continue
1744 }
1745 buf.WriteByte(ch)
1746 if ch == '\n' {
1747 for j := p.indent; j > 0; j-- {
1748 buf.WriteString(". ")
1749 }
1750 }
1751 }
1752 format = buf.String()
1753 }
1754 fmt.Printf(format, args...)
1755}
1756
1757// ----------------------------------------------------------------------------
1758// Export format
1759
1760// Tags. Must be < 0.
1761const (
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001762 // Objects
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001763 packageTag = -(iota + 1)
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001764 constTag
1765 typeTag
1766 varTag
1767 funcTag
1768 endTag
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001769
1770 // Types
1771 namedTag
1772 arrayTag
1773 sliceTag
1774 dddTag
1775 structTag
1776 pointerTag
1777 signatureTag
1778 interfaceTag
1779 mapTag
1780 chanTag
1781
1782 // Values
1783 falseTag
1784 trueTag
1785 int64Tag
1786 floatTag
1787 fractionTag // not used by gc
1788 complexTag
1789 stringTag
Robert Griesemer45983822015-10-22 18:56:45 -07001790 nilTag
Alan Donovana5cd53a2016-03-18 11:13:24 -04001791 unknownTag // not used by gc (only appears in packages with errors)
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001792)
1793
1794// Debugging support.
1795// (tagString is only used when tracing is enabled)
1796var tagString = [...]string{
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001797 // Objects
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001798 -packageTag: "package",
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001799 -constTag: "const",
1800 -typeTag: "type",
1801 -varTag: "var",
1802 -funcTag: "func",
1803 -endTag: "end",
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001804
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001805 // Types
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001806 -namedTag: "named type",
1807 -arrayTag: "array",
1808 -sliceTag: "slice",
1809 -dddTag: "ddd",
1810 -structTag: "struct",
1811 -pointerTag: "pointer",
1812 -signatureTag: "signature",
1813 -interfaceTag: "interface",
1814 -mapTag: "map",
1815 -chanTag: "chan",
1816
Robert Griesemera9ea36a2016-03-18 17:21:32 -07001817 // Values
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001818 -falseTag: "false",
1819 -trueTag: "true",
1820 -int64Tag: "int64",
1821 -floatTag: "float",
1822 -fractionTag: "fraction",
1823 -complexTag: "complex",
1824 -stringTag: "string",
Alan Donovana5cd53a2016-03-18 11:13:24 -04001825 -nilTag: "nil",
1826 -unknownTag: "unknown",
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001827}
1828
1829// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
1830// (we can't use an pre-initialized array because we must be sure all types are
1831// set up)
Robert Griesemer53d43cb2015-10-26 16:00:59 -07001832func untype(ctype Ctype) *Type {
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001833 switch ctype {
1834 case CTINT:
1835 return idealint
1836 case CTRUNE:
1837 return idealrune
1838 case CTFLT:
1839 return idealfloat
1840 case CTCPLX:
1841 return idealcomplex
1842 case CTSTR:
1843 return idealstring
1844 case CTBOOL:
1845 return idealbool
1846 case CTNIL:
1847 return Types[TNIL]
1848 }
Robert Griesemer45983822015-10-22 18:56:45 -07001849 Fatalf("exporter: unknown Ctype")
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001850 return nil
1851}
1852
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001853var predecl []*Type // initialized lazily
1854
1855func predeclared() []*Type {
1856 if predecl == nil {
1857 // initialize lazily to be sure that all
1858 // elements have been initialized before
1859 predecl = []*Type{
1860 // basic types
1861 Types[TBOOL],
1862 Types[TINT],
1863 Types[TINT8],
1864 Types[TINT16],
1865 Types[TINT32],
1866 Types[TINT64],
1867 Types[TUINT],
1868 Types[TUINT8],
1869 Types[TUINT16],
1870 Types[TUINT32],
1871 Types[TUINT64],
1872 Types[TUINTPTR],
1873 Types[TFLOAT32],
1874 Types[TFLOAT64],
1875 Types[TCOMPLEX64],
1876 Types[TCOMPLEX128],
1877 Types[TSTRING],
1878
1879 // aliases
1880 bytetype,
1881 runetype,
1882
1883 // error
1884 errortype,
1885
1886 // untyped types
1887 untype(CTBOOL),
1888 untype(CTINT),
1889 untype(CTRUNE),
1890 untype(CTFLT),
1891 untype(CTCPLX),
1892 untype(CTSTR),
1893 untype(CTNIL),
1894
1895 // package unsafe
1896 Types[TUNSAFEPTR],
Matthew Dempskyd930d692015-12-01 12:05:30 -08001897
Alan Donovana5cd53a2016-03-18 11:13:24 -04001898 // invalid type (package contains errors)
1899 Types[Txxx],
1900
Matthew Dempskyd930d692015-12-01 12:05:30 -08001901 // any type, for builtin export data
1902 Types[TANY],
Robert Griesemerae2f54a2015-08-13 19:05:37 -07001903 }
1904 }
1905 return predecl
1906}