github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/gc/export.go (about) 1 // Copyright 2009 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 package gc 6 7 import ( 8 "bufio" 9 "bytes" 10 "cmd/internal/bio" 11 "fmt" 12 "sort" 13 "unicode" 14 "unicode/utf8" 15 ) 16 17 var ( 18 newexport bool // if set, use new export format 19 Debug_export int // if set, print debugging information about export data 20 exportsize int 21 ) 22 23 func exportf(format string, args ...interface{}) { 24 n, _ := fmt.Fprintf(bout, format, args...) 25 exportsize += n 26 if Debug_export != 0 { 27 fmt.Printf(format, args...) 28 } 29 } 30 31 var asmlist []*Node 32 33 // Mark n's symbol as exported 34 func exportsym(n *Node) { 35 if n == nil || n.Sym == nil { 36 return 37 } 38 if n.Sym.Flags&(SymExport|SymPackage) != 0 { 39 if n.Sym.Flags&SymPackage != 0 { 40 Yyerror("export/package mismatch: %v", n.Sym) 41 } 42 return 43 } 44 45 n.Sym.Flags |= SymExport 46 47 if Debug['E'] != 0 { 48 fmt.Printf("export symbol %v\n", n.Sym) 49 } 50 exportlist = append(exportlist, n) 51 } 52 53 func exportname(s string) bool { 54 if r := s[0]; r < utf8.RuneSelf { 55 return 'A' <= r && r <= 'Z' 56 } 57 r, _ := utf8.DecodeRuneInString(s) 58 return unicode.IsUpper(r) 59 } 60 61 func initname(s string) bool { 62 return s == "init" 63 } 64 65 // exportedsym reports whether a symbol will be visible 66 // to files that import our package. 67 func exportedsym(sym *Sym) bool { 68 // Builtins are visible everywhere. 69 if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg { 70 return true 71 } 72 73 return sym.Pkg == localpkg && exportname(sym.Name) 74 } 75 76 func autoexport(n *Node, ctxt Class) { 77 if n == nil || n.Sym == nil { 78 return 79 } 80 if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { 81 return 82 } 83 if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method 84 return 85 } 86 87 // -A is for cmd/gc/mkbuiltin script, so export everything 88 if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) { 89 exportsym(n) 90 } 91 if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 { 92 n.Sym.Flags |= SymAsm 93 asmlist = append(asmlist, n) 94 } 95 } 96 97 func dumppkg(p *Pkg) { 98 if p == nil || p == localpkg || p.Exported || p == builtinpkg { 99 return 100 } 101 p.Exported = true 102 suffix := "" 103 if !p.Direct { 104 suffix = " // indirect" 105 } 106 exportf("\timport %s %q%s\n", p.Name, p.Path, suffix) 107 } 108 109 // Look for anything we need for the inline body 110 func reexportdeplist(ll Nodes) { 111 for _, n := range ll.Slice() { 112 reexportdep(n) 113 } 114 } 115 116 func reexportdep(n *Node) { 117 if n == nil { 118 return 119 } 120 121 //print("reexportdep %+hN\n", n); 122 switch n.Op { 123 case ONAME: 124 switch n.Class { 125 // methods will be printed along with their type 126 // nodes for T.Method expressions 127 case PFUNC: 128 if n.Left != nil && n.Left.Op == OTYPE { 129 break 130 } 131 132 // nodes for method calls. 133 if n.Type == nil || n.Type.Recv() != nil { 134 break 135 } 136 fallthrough 137 138 case PEXTERN: 139 if n.Sym != nil && !exportedsym(n.Sym) { 140 if Debug['E'] != 0 { 141 fmt.Printf("reexport name %v\n", n.Sym) 142 } 143 exportlist = append(exportlist, n) 144 } 145 } 146 147 // Local variables in the bodies need their type. 148 case ODCL: 149 t := n.Left.Type 150 151 if t != Types[t.Etype] && t != idealbool && t != idealstring { 152 if t.IsPtr() { 153 t = t.Elem() 154 } 155 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 156 if Debug['E'] != 0 { 157 fmt.Printf("reexport type %v from declaration\n", t.Sym) 158 } 159 exportlist = append(exportlist, t.Sym.Def) 160 } 161 } 162 163 case OLITERAL: 164 t := n.Type 165 if t != Types[n.Type.Etype] && t != idealbool && t != idealstring { 166 if t.IsPtr() { 167 t = t.Elem() 168 } 169 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 170 if Debug['E'] != 0 { 171 fmt.Printf("reexport literal type %v\n", t.Sym) 172 } 173 exportlist = append(exportlist, t.Sym.Def) 174 } 175 } 176 fallthrough 177 178 case OTYPE: 179 if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) { 180 if Debug['E'] != 0 { 181 fmt.Printf("reexport literal/type %v\n", n.Sym) 182 } 183 exportlist = append(exportlist, n) 184 } 185 186 // for operations that need a type when rendered, put the type on the export list. 187 case OCONV, 188 OCONVIFACE, 189 OCONVNOP, 190 ORUNESTR, 191 OARRAYBYTESTR, 192 OARRAYRUNESTR, 193 OSTRARRAYBYTE, 194 OSTRARRAYRUNE, 195 ODOTTYPE, 196 ODOTTYPE2, 197 OSTRUCTLIT, 198 OARRAYLIT, 199 OPTRLIT, 200 OMAKEMAP, 201 OMAKESLICE, 202 OMAKECHAN: 203 t := n.Type 204 205 switch t.Etype { 206 case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE: 207 if t.Sym == nil { 208 t = t.Elem() 209 } 210 } 211 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 212 if Debug['E'] != 0 { 213 fmt.Printf("reexport type for expression %v\n", t.Sym) 214 } 215 exportlist = append(exportlist, t.Sym.Def) 216 } 217 } 218 219 reexportdep(n.Left) 220 reexportdep(n.Right) 221 reexportdeplist(n.List) 222 reexportdeplist(n.Rlist) 223 reexportdeplist(n.Ninit) 224 reexportdeplist(n.Nbody) 225 } 226 227 func dumpexportconst(s *Sym) { 228 n := typecheck(s.Def, Erv) 229 if n == nil || n.Op != OLITERAL { 230 Fatalf("dumpexportconst: oconst nil: %v", s) 231 } 232 233 t := n.Type // may or may not be specified 234 dumpexporttype(t) 235 236 if t != nil && !t.IsUntyped() { 237 exportf("\tconst %v %v = %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp), vconv(n.Val(), FmtSharp)) 238 } else { 239 exportf("\tconst %v = %v\n", sconv(s, FmtSharp), vconv(n.Val(), FmtSharp)) 240 } 241 } 242 243 func dumpexportvar(s *Sym) { 244 n := s.Def 245 n = typecheck(n, Erv|Ecall) 246 if n == nil || n.Type == nil { 247 Yyerror("variable exported but not defined: %v", s) 248 return 249 } 250 251 t := n.Type 252 dumpexporttype(t) 253 254 if t.Etype == TFUNC && n.Class == PFUNC { 255 if n.Func != nil && n.Func.Inl.Len() != 0 { 256 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 257 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 258 if Debug['l'] < 2 { 259 typecheckinl(n) 260 } 261 262 // NOTE: The space after %#S here is necessary for ld's export data parser. 263 exportf("\tfunc %v %v { %v }\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp), hconv(n.Func.Inl, FmtSharp|FmtBody)) 264 265 reexportdeplist(n.Func.Inl) 266 } else { 267 exportf("\tfunc %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp)) 268 } 269 } else { 270 exportf("\tvar %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp)) 271 } 272 } 273 274 // methodbyname sorts types by symbol name. 275 type methodbyname []*Field 276 277 func (x methodbyname) Len() int { return len(x) } 278 func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 279 func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name } 280 281 func dumpexporttype(t *Type) { 282 if t == nil { 283 return 284 } 285 if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype { 286 return 287 } 288 t.Printed = true 289 290 if t.Sym != nil { 291 dumppkg(t.Sym.Pkg) 292 } 293 294 switch t.Etype { 295 case TSTRUCT, TINTER: 296 for _, f := range t.Fields().Slice() { 297 dumpexporttype(f.Type) 298 } 299 case TFUNC: 300 dumpexporttype(t.Recvs()) 301 dumpexporttype(t.Results()) 302 dumpexporttype(t.Params()) 303 case TMAP: 304 dumpexporttype(t.Val()) 305 dumpexporttype(t.Key()) 306 case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE: 307 dumpexporttype(t.Elem()) 308 } 309 310 if t.Sym == nil { 311 return 312 } 313 314 var m []*Field 315 for _, f := range t.Methods().Slice() { 316 dumpexporttype(f.Type) 317 m = append(m, f) 318 } 319 sort.Sort(methodbyname(m)) 320 321 exportf("\ttype %v %v\n", sconv(t.Sym, FmtSharp), Tconv(t, FmtSharp|FmtLong)) 322 for _, f := range m { 323 if f.Nointerface { 324 exportf("\t//go:nointerface\n") 325 } 326 if f.Type.Nname() != nil && f.Type.Nname().Func.Inl.Len() != 0 { // nname was set by caninl 327 328 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 329 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 330 if Debug['l'] < 2 { 331 typecheckinl(f.Type.Nname()) 332 } 333 exportf("\tfunc %v %v %v { %v }\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp), hconv(f.Type.Nname().Func.Inl, FmtSharp|FmtBody)) 334 reexportdeplist(f.Type.Nname().Func.Inl) 335 } else { 336 exportf("\tfunc %v %v %v\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp)) 337 } 338 } 339 } 340 341 func dumpsym(s *Sym) { 342 if s.Flags&SymExported != 0 { 343 return 344 } 345 s.Flags |= SymExported 346 347 if s.Def == nil { 348 Yyerror("unknown export symbol: %v", s) 349 return 350 } 351 352 // print("dumpsym %O %+S\n", s->def->op, s); 353 dumppkg(s.Pkg) 354 355 switch s.Def.Op { 356 default: 357 Yyerror("unexpected export symbol: %v %v", s.Def.Op, s) 358 359 case OLITERAL: 360 dumpexportconst(s) 361 362 case OTYPE: 363 if s.Def.Type.Etype == TFORW { 364 Yyerror("export of incomplete type %v", s) 365 } else { 366 dumpexporttype(s.Def.Type) 367 } 368 369 case ONAME: 370 dumpexportvar(s) 371 } 372 } 373 374 func dumpexport() { 375 if buildid != "" { 376 exportf("build id %q\n", buildid) 377 } 378 379 size := 0 // size of export section without enclosing markers 380 if newexport { 381 // binary export 382 // The linker also looks for the $$ marker - use char after $$ to distinguish format. 383 exportf("\n$$B\n") // indicate binary format 384 if debugFormat { 385 // save a copy of the export data 386 var copy bytes.Buffer 387 bcopy := bufio.NewWriter(©) 388 size = export(bcopy, Debug_export != 0) 389 bcopy.Flush() // flushing to bytes.Buffer cannot fail 390 if n, err := bout.Write(copy.Bytes()); n != size || err != nil { 391 Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err) 392 } 393 // export data must contain no '$' so that we can find the end by searching for "$$" 394 if bytes.IndexByte(copy.Bytes(), '$') >= 0 { 395 Fatalf("export data contains $") 396 } 397 398 // verify that we can read the copied export data back in 399 // (use empty package map to avoid collisions) 400 savedPkgMap := pkgMap 401 savedPkgs := pkgs 402 pkgMap = make(map[string]*Pkg) 403 pkgs = nil 404 importpkg = mkpkg("") 405 Import(bufio.NewReader(©)) // must not die 406 importpkg = nil 407 pkgs = savedPkgs 408 pkgMap = savedPkgMap 409 } else { 410 size = export(bout.Writer, Debug_export != 0) 411 } 412 exportf("\n$$\n") 413 } else { 414 // textual export 415 lno := lineno 416 417 exportf("\n$$\n") // indicate textual format 418 exportsize = 0 419 exportf("package %s", localpkg.Name) 420 if safemode { 421 exportf(" safe") 422 } 423 exportf("\n") 424 425 for _, p := range pkgs { 426 if p.Direct { 427 dumppkg(p) 428 } 429 } 430 431 // exportlist grows during iteration - cannot use range 432 for i := 0; i < len(exportlist); i++ { 433 n := exportlist[i] 434 lineno = n.Lineno 435 dumpsym(n.Sym) 436 } 437 438 size = exportsize 439 exportf("\n$$\n") 440 lineno = lno 441 } 442 443 if Debug_export != 0 { 444 fmt.Printf("export data size = %d bytes\n", size) 445 } 446 } 447 448 // importsym declares symbol s as an imported object representable by op. 449 func importsym(s *Sym, op Op) { 450 if s.Def != nil && s.Def.Op != op { 451 pkgstr := fmt.Sprintf("during import %q", importpkg.Path) 452 redeclare(s, pkgstr) 453 } 454 455 // mark the symbol so it is not reexported 456 if s.Def == nil { 457 if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) { 458 s.Flags |= SymExport 459 } else { 460 s.Flags |= SymPackage // package scope 461 } 462 } 463 } 464 465 // pkgtype returns the named type declared by symbol s. 466 // If no such type has been declared yet, a forward declaration is returned. 467 func pkgtype(s *Sym) *Type { 468 importsym(s, OTYPE) 469 if s.Def == nil || s.Def.Op != OTYPE { 470 t := typ(TFORW) 471 t.Sym = s 472 s.Def = typenod(t) 473 s.Def.Name = new(Name) 474 } 475 476 if s.Def.Type == nil { 477 Yyerror("pkgtype %v", s) 478 } 479 return s.Def.Type 480 } 481 482 var numImport = make(map[string]int) 483 484 func importimport(s *Sym, path string) { 485 // Informational: record package name 486 // associated with import path, for use in 487 // human-readable messages. 488 489 if isbadimport(path) { 490 errorexit() 491 } 492 p := mkpkg(path) 493 if p.Name == "" { 494 p.Name = s.Name 495 numImport[s.Name]++ 496 } else if p.Name != s.Name { 497 Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path) 498 } 499 500 if incannedimport == 0 && myimportpath != "" && path == myimportpath { 501 Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path) 502 errorexit() 503 } 504 } 505 506 // importconst declares symbol s as an imported constant with type t and value n. 507 func importconst(s *Sym, t *Type, n *Node) { 508 importsym(s, OLITERAL) 509 n = convlit(n, t) 510 511 if s.Def != nil { // TODO: check if already the same. 512 return 513 } 514 515 if n.Op != OLITERAL { 516 Yyerror("expression must be a constant") 517 return 518 } 519 520 if n.Sym != nil { 521 n1 := *n 522 n = &n1 523 } 524 525 n.Orig = newname(s) 526 n.Sym = s 527 declare(n, PEXTERN) 528 529 if Debug['E'] != 0 { 530 fmt.Printf("import const %v\n", s) 531 } 532 } 533 534 // importvar declares symbol s as an imported variable with type t. 535 func importvar(s *Sym, t *Type) { 536 importsym(s, ONAME) 537 if s.Def != nil && s.Def.Op == ONAME { 538 if Eqtype(t, s.Def.Type) { 539 return 540 } 541 Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path) 542 } 543 544 n := newname(s) 545 s.Importdef = importpkg 546 n.Type = t 547 declare(n, PEXTERN) 548 549 if Debug['E'] != 0 { 550 fmt.Printf("import var %v %v\n", s, Tconv(t, FmtLong)) 551 } 552 } 553 554 // importtype and importer.importtype (bimport.go) need to remain in sync. 555 func importtype(pt *Type, t *Type) { 556 // override declaration in unsafe.go for Pointer. 557 // there is no way in Go code to define unsafe.Pointer 558 // so we have to supply it. 559 if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" { 560 t = Types[TUNSAFEPTR] 561 } 562 563 if pt.Etype == TFORW { 564 n := pt.Nod 565 copytype(pt.Nod, t) 566 pt.Nod = n // unzero nod 567 pt.Sym.Importdef = importpkg 568 pt.Sym.Lastlineno = lineno 569 declare(n, PEXTERN) 570 checkwidth(pt) 571 } else if !Eqtype(pt.Orig, t) { 572 Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path) 573 } 574 575 if Debug['E'] != 0 { 576 fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong)) 577 } 578 } 579 580 func dumpasmhdr() { 581 b, err := bio.Create(asmhdr) 582 if err != nil { 583 Fatalf("%v", err) 584 } 585 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 586 for _, n := range asmlist { 587 if isblanksym(n.Sym) { 588 continue 589 } 590 switch n.Op { 591 case OLITERAL: 592 fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, vconv(n.Val(), FmtSharp)) 593 594 case OTYPE: 595 t := n.Type 596 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 597 break 598 } 599 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 600 for _, t := range t.Fields().Slice() { 601 if !isblanksym(t.Sym) { 602 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 603 } 604 } 605 } 606 } 607 608 b.Close() 609 }