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