github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 if exportname(n.Sym.Name) || initname(n.Sym.Name) { 86 exportsym(n) 87 } 88 if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 { 89 n.Sym.Flags |= SymAsm 90 asmlist = append(asmlist, n) 91 } 92 } 93 94 // Look for anything we need for the inline body 95 func reexportdeplist(ll Nodes) { 96 for _, n := range ll.Slice() { 97 reexportdep(n) 98 } 99 } 100 101 func reexportdep(n *Node) { 102 if n == nil { 103 return 104 } 105 106 //print("reexportdep %+hN\n", n); 107 switch n.Op { 108 case ONAME: 109 switch n.Class { 110 // methods will be printed along with their type 111 // nodes for T.Method expressions 112 case PFUNC: 113 if n.Left != nil && n.Left.Op == OTYPE { 114 break 115 } 116 117 // nodes for method calls. 118 if n.Type == nil || n.IsMethod() { 119 break 120 } 121 fallthrough 122 123 case PEXTERN: 124 if n.Sym != nil && !exportedsym(n.Sym) { 125 if Debug['E'] != 0 { 126 fmt.Printf("reexport name %v\n", n.Sym) 127 } 128 exportlist = append(exportlist, n) 129 } 130 } 131 132 // Local variables in the bodies need their type. 133 case ODCL: 134 t := n.Left.Type 135 136 if t != Types[t.Etype] && t != idealbool && t != idealstring { 137 if t.IsPtr() { 138 t = t.Elem() 139 } 140 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 141 if Debug['E'] != 0 { 142 fmt.Printf("reexport type %v from declaration\n", t.Sym) 143 } 144 exportlist = append(exportlist, t.Sym.Def) 145 } 146 } 147 148 case OLITERAL: 149 t := n.Type 150 if t != Types[n.Type.Etype] && t != idealbool && t != idealstring { 151 if t.IsPtr() { 152 t = t.Elem() 153 } 154 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 155 if Debug['E'] != 0 { 156 fmt.Printf("reexport literal type %v\n", t.Sym) 157 } 158 exportlist = append(exportlist, t.Sym.Def) 159 } 160 } 161 fallthrough 162 163 case OTYPE: 164 if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) { 165 if Debug['E'] != 0 { 166 fmt.Printf("reexport literal/type %v\n", n.Sym) 167 } 168 exportlist = append(exportlist, n) 169 } 170 171 // for operations that need a type when rendered, put the type on the export list. 172 case OCONV, 173 OCONVIFACE, 174 OCONVNOP, 175 ORUNESTR, 176 OARRAYBYTESTR, 177 OARRAYRUNESTR, 178 OSTRARRAYBYTE, 179 OSTRARRAYRUNE, 180 ODOTTYPE, 181 ODOTTYPE2, 182 OSTRUCTLIT, 183 OARRAYLIT, 184 OSLICELIT, 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 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 %L\n", s, t) 343 } 344 } 345 346 func dumpasmhdr() { 347 b, err := bio.Create(asmhdr) 348 if err != nil { 349 Fatalf("%v", err) 350 } 351 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 352 for _, n := range asmlist { 353 if isblanksym(n.Sym) { 354 continue 355 } 356 switch n.Op { 357 case OLITERAL: 358 fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) 359 360 case OTYPE: 361 t := n.Type 362 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 363 break 364 } 365 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 366 for _, t := range t.Fields().Slice() { 367 if !isblanksym(t.Sym) { 368 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 369 } 370 } 371 } 372 } 373 374 b.Close() 375 }