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