github.com/euank/go@v0.0.0-20160829210321-495514729181/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 "unicode" 13 "unicode/utf8" 14 ) 15 16 var ( 17 Debug_export int // if set, print debugging information about export data 18 exportsize int 19 ) 20 21 func exportf(format string, args ...interface{}) { 22 n, _ := fmt.Fprintf(bout, format, args...) 23 exportsize += n 24 if Debug_export != 0 { 25 fmt.Printf(format, args...) 26 } 27 } 28 29 var asmlist []*Node 30 31 // Mark n's symbol as exported 32 func exportsym(n *Node) { 33 if n == nil || n.Sym == nil { 34 return 35 } 36 if n.Sym.Flags&(SymExport|SymPackage) != 0 { 37 if n.Sym.Flags&SymPackage != 0 { 38 Yyerror("export/package mismatch: %v", n.Sym) 39 } 40 return 41 } 42 43 n.Sym.Flags |= SymExport 44 45 if Debug['E'] != 0 { 46 fmt.Printf("export symbol %v\n", n.Sym) 47 } 48 exportlist = append(exportlist, n) 49 } 50 51 func exportname(s string) bool { 52 if r := s[0]; r < utf8.RuneSelf { 53 return 'A' <= r && r <= 'Z' 54 } 55 r, _ := utf8.DecodeRuneInString(s) 56 return unicode.IsUpper(r) 57 } 58 59 func initname(s string) bool { 60 return s == "init" 61 } 62 63 // exportedsym reports whether a symbol will be visible 64 // to files that import our package. 65 func exportedsym(sym *Sym) bool { 66 // Builtins are visible everywhere. 67 if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg { 68 return true 69 } 70 71 return sym.Pkg == localpkg && exportname(sym.Name) 72 } 73 74 func autoexport(n *Node, ctxt Class) { 75 if n == nil || n.Sym == nil { 76 return 77 } 78 if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { 79 return 80 } 81 if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method 82 return 83 } 84 85 // -A is for cmd/gc/mkbuiltin script, so export everything 86 if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) { 87 exportsym(n) 88 } 89 if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 { 90 n.Sym.Flags |= SymAsm 91 asmlist = append(asmlist, n) 92 } 93 } 94 95 // Look for anything we need for the inline body 96 func reexportdeplist(ll Nodes) { 97 for _, n := range ll.Slice() { 98 reexportdep(n) 99 } 100 } 101 102 func reexportdep(n *Node) { 103 if n == nil { 104 return 105 } 106 107 //print("reexportdep %+hN\n", n); 108 switch n.Op { 109 case ONAME: 110 switch n.Class { 111 // methods will be printed along with their type 112 // nodes for T.Method expressions 113 case PFUNC: 114 if n.Left != nil && n.Left.Op == OTYPE { 115 break 116 } 117 118 // nodes for method calls. 119 if n.Type == nil || n.Type.Recv() != nil { 120 break 121 } 122 fallthrough 123 124 case PEXTERN: 125 if n.Sym != nil && !exportedsym(n.Sym) { 126 if Debug['E'] != 0 { 127 fmt.Printf("reexport name %v\n", n.Sym) 128 } 129 exportlist = append(exportlist, n) 130 } 131 } 132 133 // Local variables in the bodies need their type. 134 case ODCL: 135 t := n.Left.Type 136 137 if t != Types[t.Etype] && t != idealbool && t != idealstring { 138 if t.IsPtr() { 139 t = t.Elem() 140 } 141 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 142 if Debug['E'] != 0 { 143 fmt.Printf("reexport type %v from declaration\n", t.Sym) 144 } 145 exportlist = append(exportlist, t.Sym.Def) 146 } 147 } 148 149 case OLITERAL: 150 t := n.Type 151 if t != Types[n.Type.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 literal type %v\n", t.Sym) 158 } 159 exportlist = append(exportlist, t.Sym.Def) 160 } 161 } 162 fallthrough 163 164 case OTYPE: 165 if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) { 166 if Debug['E'] != 0 { 167 fmt.Printf("reexport literal/type %v\n", n.Sym) 168 } 169 exportlist = append(exportlist, n) 170 } 171 172 // for operations that need a type when rendered, put the type on the export list. 173 case OCONV, 174 OCONVIFACE, 175 OCONVNOP, 176 ORUNESTR, 177 OARRAYBYTESTR, 178 OARRAYRUNESTR, 179 OSTRARRAYBYTE, 180 OSTRARRAYRUNE, 181 ODOTTYPE, 182 ODOTTYPE2, 183 OSTRUCTLIT, 184 OARRAYLIT, 185 OPTRLIT, 186 OMAKEMAP, 187 OMAKESLICE, 188 OMAKECHAN: 189 t := n.Type 190 191 switch t.Etype { 192 case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE: 193 if t.Sym == nil { 194 t = t.Elem() 195 } 196 } 197 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 198 if Debug['E'] != 0 { 199 fmt.Printf("reexport type for expression %v\n", t.Sym) 200 } 201 exportlist = append(exportlist, t.Sym.Def) 202 } 203 } 204 205 reexportdep(n.Left) 206 reexportdep(n.Right) 207 reexportdeplist(n.List) 208 reexportdeplist(n.Rlist) 209 reexportdeplist(n.Ninit) 210 reexportdeplist(n.Nbody) 211 } 212 213 // methodbyname sorts types by symbol name. 214 type methodbyname []*Field 215 216 func (x methodbyname) Len() int { return len(x) } 217 func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 218 func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name } 219 220 func dumpexport() { 221 if buildid != "" { 222 exportf("build id %q\n", buildid) 223 } 224 225 size := 0 // size of export section without enclosing markers 226 // The linker also looks for the $$ marker - use char after $$ to distinguish format. 227 exportf("\n$$B\n") // indicate binary export format 228 if debugFormat { 229 // save a copy of the export data 230 var copy bytes.Buffer 231 bcopy := bufio.NewWriter(©) 232 size = export(bcopy, Debug_export != 0) 233 bcopy.Flush() // flushing to bytes.Buffer cannot fail 234 if n, err := bout.Write(copy.Bytes()); n != size || err != nil { 235 Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err) 236 } 237 // export data must contain no '$' so that we can find the end by searching for "$$" 238 // TODO(gri) is this still needed? 239 if bytes.IndexByte(copy.Bytes(), '$') >= 0 { 240 Fatalf("export data contains $") 241 } 242 243 // verify that we can read the copied export data back in 244 // (use empty package map to avoid collisions) 245 savedPkgMap := pkgMap 246 savedPkgs := pkgs 247 pkgMap = make(map[string]*Pkg) 248 pkgs = nil 249 importpkg = mkpkg("") 250 Import(bufio.NewReader(©)) // must not die 251 importpkg = nil 252 pkgs = savedPkgs 253 pkgMap = savedPkgMap 254 } else { 255 size = export(bout.Writer, Debug_export != 0) 256 } 257 exportf("\n$$\n") 258 259 if Debug_export != 0 { 260 fmt.Printf("export data size = %d bytes\n", size) 261 } 262 } 263 264 // importsym declares symbol s as an imported object representable by op. 265 func importsym(s *Sym, op Op) { 266 if s.Def != nil && s.Def.Op != op { 267 pkgstr := fmt.Sprintf("during import %q", importpkg.Path) 268 redeclare(s, pkgstr) 269 } 270 271 // mark the symbol so it is not reexported 272 if s.Def == nil { 273 if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) { 274 s.Flags |= SymExport 275 } else { 276 s.Flags |= SymPackage // package scope 277 } 278 } 279 } 280 281 // pkgtype returns the named type declared by symbol s. 282 // If no such type has been declared yet, a forward declaration is returned. 283 func pkgtype(s *Sym) *Type { 284 importsym(s, OTYPE) 285 if s.Def == nil || s.Def.Op != OTYPE { 286 t := typ(TFORW) 287 t.Sym = s 288 s.Def = typenod(t) 289 s.Def.Name = new(Name) 290 } 291 292 if s.Def.Type == nil { 293 Yyerror("pkgtype %v", s) 294 } 295 return s.Def.Type 296 } 297 298 // importconst declares symbol s as an imported constant with type t and value n. 299 func importconst(s *Sym, t *Type, n *Node) { 300 importsym(s, OLITERAL) 301 n = convlit(n, t) 302 303 if s.Def != nil { // TODO: check if already the same. 304 return 305 } 306 307 if n.Op != OLITERAL { 308 Yyerror("expression must be a constant") 309 return 310 } 311 312 if n.Sym != nil { 313 n1 := *n 314 n = &n1 315 } 316 317 n.Orig = newname(s) 318 n.Sym = s 319 declare(n, PEXTERN) 320 321 if Debug['E'] != 0 { 322 fmt.Printf("import const %v\n", s) 323 } 324 } 325 326 // importvar declares symbol s as an imported variable with type t. 327 func importvar(s *Sym, t *Type) { 328 importsym(s, ONAME) 329 if s.Def != nil && s.Def.Op == ONAME { 330 if Eqtype(t, s.Def.Type) { 331 return 332 } 333 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) 334 } 335 336 n := newname(s) 337 s.Importdef = importpkg 338 n.Type = t 339 declare(n, PEXTERN) 340 341 if Debug['E'] != 0 { 342 fmt.Printf("import var %v %v\n", s, Tconv(t, FmtLong)) 343 } 344 } 345 346 // importtype and importer.importtype (bimport.go) need to remain in sync. 347 func importtype(pt *Type, t *Type) { 348 // override declaration in unsafe.go for Pointer. 349 // there is no way in Go code to define unsafe.Pointer 350 // so we have to supply it. 351 if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" { 352 t = Types[TUNSAFEPTR] 353 } 354 355 if pt.Etype == TFORW { 356 n := pt.Nod 357 copytype(pt.Nod, t) 358 pt.Nod = n // unzero nod 359 pt.Sym.Importdef = importpkg 360 pt.Sym.Lastlineno = lineno 361 declare(n, PEXTERN) 362 checkwidth(pt) 363 } else if !Eqtype(pt.Orig, t) { 364 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) 365 } 366 367 if Debug['E'] != 0 { 368 fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong)) 369 } 370 } 371 372 func dumpasmhdr() { 373 b, err := bio.Create(asmhdr) 374 if err != nil { 375 Fatalf("%v", err) 376 } 377 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 378 for _, n := range asmlist { 379 if isblanksym(n.Sym) { 380 continue 381 } 382 switch n.Op { 383 case OLITERAL: 384 fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, vconv(n.Val(), FmtSharp)) 385 386 case OTYPE: 387 t := n.Type 388 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 389 break 390 } 391 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 392 for _, t := range t.Fields().Slice() { 393 if !isblanksym(t.Sym) { 394 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 395 } 396 } 397 } 398 } 399 400 b.Close() 401 }