github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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/compile/internal/types" 11 "cmd/internal/bio" 12 "cmd/internal/src" 13 "fmt" 14 "unicode" 15 "unicode/utf8" 16 ) 17 18 var ( 19 Debug_export int // if set, print debugging information about export data 20 ) 21 22 func exportf(bout *bio.Writer, format string, args ...interface{}) { 23 fmt.Fprintf(bout, format, args...) 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.Export() || n.Sym.Package() { 37 if n.Sym.Package() { 38 Fatalf("export/package mismatch: %v", n.Sym) 39 } 40 return 41 } 42 43 n.Sym.SetExport(true) 44 if Debug['E'] != 0 { 45 fmt.Printf("export symbol %v\n", n.Sym) 46 } 47 48 // Ensure original types are on exportlist before type aliases. 49 if IsAlias(n.Sym) { 50 exportlist = append(exportlist, asNode(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 *types.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.Type != nil && n.Type.IsKind(TFUNC) && n.IsMethod() { 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.Asm() { 94 n.Sym.SetAsm(true) 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 case PFUNC: 116 // methods will be printed along with their type 117 // nodes for T.Method expressions 118 if n.isMethodExpression() { 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.Types[t.Etype] && t != types.Idealbool && t != types.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, asNode(t.Sym.Def)) 150 } 151 } 152 153 case OLITERAL: 154 t := n.Type 155 if t != types.Types[n.Type.Etype] && t != types.Idealbool && t != types.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, asNode(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, asNode(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 []*types.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(bout *bio.Writer) { 226 if buildid != "" { 227 exportf(bout, "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(bout, "\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 types.CleanroomDo(func() { 251 Import(types.NewPkg("", ""), bufio.NewReader(©)) // must not die 252 }) 253 } else { 254 size = export(bout.Writer, Debug_export != 0) 255 } 256 exportf(bout, "\n$$\n") 257 258 if Debug_export != 0 { 259 fmt.Printf("export data size = %d bytes\n", size) 260 } 261 } 262 263 // importsym declares symbol s as an imported object representable by op. 264 // pkg is the package being imported 265 func importsym(pkg *types.Pkg, s *types.Sym, op Op) { 266 if asNode(s.Def) != nil && asNode(s.Def).Op != op { 267 pkgstr := fmt.Sprintf("during import %q", pkg.Path) 268 redeclare(s, pkgstr) 269 } 270 271 // mark the symbol so it is not reexported 272 if asNode(s.Def) == nil { 273 if exportname(s.Name) || initname(s.Name) { 274 s.SetExport(true) 275 } else { 276 s.SetPackage(true) // 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 // pkg is the package being imported 284 func pkgtype(pos src.XPos, pkg *types.Pkg, s *types.Sym) *types.Type { 285 importsym(pkg, s, OTYPE) 286 if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE { 287 t := types.New(TFORW) 288 t.Sym = s 289 s.Def = asTypesNode(typenodl(pos, t)) 290 asNode(s.Def).Name = new(Name) 291 } 292 293 if asNode(s.Def).Type == nil { 294 Fatalf("pkgtype %v", s) 295 } 296 return asNode(s.Def).Type 297 } 298 299 // importconst declares symbol s as an imported constant with type t and value n. 300 // pkg is the package being imported 301 func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) { 302 importsym(pkg, s, OLITERAL) 303 n = convlit(n, t) 304 305 if asNode(s.Def) != nil { // TODO: check if already the same. 306 return 307 } 308 309 if n.Op != OLITERAL { 310 yyerror("expression must be a constant") 311 return 312 } 313 314 if n.Sym != nil { 315 n1 := *n 316 n = &n1 317 } 318 319 n.Orig = newname(s) 320 n.Sym = s 321 declare(n, PEXTERN) 322 323 if Debug['E'] != 0 { 324 fmt.Printf("import const %v\n", s) 325 } 326 } 327 328 // importvar declares symbol s as an imported variable with type t. 329 // pkg is the package being imported 330 func importvar(pos src.XPos, pkg *types.Pkg, s *types.Sym, t *types.Type) { 331 importsym(pkg, s, ONAME) 332 if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME { 333 if eqtype(t, asNode(s.Def).Type) { 334 return 335 } 336 yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path) 337 } 338 339 n := newnamel(pos, s) 340 s.Importdef = pkg 341 n.Type = t 342 declare(n, PEXTERN) 343 344 if Debug['E'] != 0 { 345 fmt.Printf("import var %v %L\n", s, t) 346 } 347 } 348 349 // importalias declares symbol s as an imported type alias with type t. 350 // pkg is the package being imported 351 func importalias(pos src.XPos, pkg *types.Pkg, s *types.Sym, t *types.Type) { 352 importsym(pkg, s, OTYPE) 353 if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE { 354 if eqtype(t, asNode(s.Def).Type) { 355 return 356 } 357 yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path) 358 } 359 360 n := newnamel(pos, s) 361 n.Op = OTYPE 362 s.Importdef = pkg 363 n.Type = t 364 declare(n, PEXTERN) 365 366 if Debug['E'] != 0 { 367 fmt.Printf("import type %v = %L\n", s, t) 368 } 369 } 370 371 func dumpasmhdr() { 372 b, err := bio.Create(asmhdr) 373 if err != nil { 374 Fatalf("%v", err) 375 } 376 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 377 for _, n := range asmlist { 378 if n.Sym.IsBlank() { 379 continue 380 } 381 switch n.Op { 382 case OLITERAL: 383 fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) 384 385 case OTYPE: 386 t := n.Type 387 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 388 break 389 } 390 fmt.Fprintf(b, "#define %s__size %d\n", n.Sym.Name, int(t.Width)) 391 for _, f := range t.Fields().Slice() { 392 if !f.Sym.IsBlank() { 393 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, f.Sym.Name, int(f.Offset)) 394 } 395 } 396 } 397 } 398 399 b.Close() 400 }