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