github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 switch n.Op { 111 case ONAME: 112 switch n.Class { 113 // methods will be printed along with their type 114 // nodes for T.Method expressions 115 case PFUNC: 116 if n.Left != nil && n.Left.Op == OTYPE { 117 break 118 } 119 120 // nodes for method calls. 121 if n.Type == nil || n.IsMethod() { 122 break 123 } 124 fallthrough 125 126 case PEXTERN: 127 if n.Sym != nil && !exportedsym(n.Sym) { 128 if Debug['E'] != 0 { 129 fmt.Printf("reexport name %v\n", n.Sym) 130 } 131 exportlist = append(exportlist, n) 132 } 133 } 134 } 135 136 reexportdep(n.Left) 137 reexportdep(n.Right) 138 reexportdeplist(n.List) 139 reexportdeplist(n.Rlist) 140 reexportdeplist(n.Ninit) 141 reexportdeplist(n.Nbody) 142 } 143 144 // methodbyname sorts types by symbol name. 145 type methodbyname []*types.Field 146 147 func (x methodbyname) Len() int { return len(x) } 148 func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 149 func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name } 150 151 func dumpexport() { 152 if buildid != "" { 153 exportf("build id %q\n", buildid) 154 } 155 156 size := 0 // size of export section without enclosing markers 157 // The linker also looks for the $$ marker - use char after $$ to distinguish format. 158 exportf("\n$$B\n") // indicate binary export format 159 if debugFormat { 160 // save a copy of the export data 161 var copy bytes.Buffer 162 bcopy := bufio.NewWriter(©) 163 size = export(bcopy, Debug_export != 0) 164 bcopy.Flush() // flushing to bytes.Buffer cannot fail 165 if n, err := bout.Write(copy.Bytes()); n != size || err != nil { 166 Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err) 167 } 168 // export data must contain no '$' so that we can find the end by searching for "$$" 169 // TODO(gri) is this still needed? 170 if bytes.IndexByte(copy.Bytes(), '$') >= 0 { 171 Fatalf("export data contains $") 172 } 173 174 // verify that we can read the copied export data back in 175 // (use empty package map to avoid collisions) 176 savedPkgMap := pkgMap 177 savedPkgs := pkgs 178 pkgMap = make(map[string]*types.Pkg) 179 pkgs = nil 180 Import(mkpkg(""), bufio.NewReader(©)) // must not die 181 pkgs = savedPkgs 182 pkgMap = savedPkgMap 183 } else { 184 size = export(bout.Writer, Debug_export != 0) 185 } 186 exportf("\n$$\n") 187 188 if Debug_export != 0 { 189 fmt.Printf("export data size = %d bytes\n", size) 190 } 191 } 192 193 // importsym declares symbol s as an imported object representable by op. 194 // pkg is the package being imported 195 func importsym(pkg *types.Pkg, s *types.Sym, op Op) { 196 if asNode(s.Def) != nil && asNode(s.Def).Op != op { 197 pkgstr := fmt.Sprintf("during import %q", pkg.Path) 198 redeclare(s, pkgstr) 199 } 200 201 // mark the symbol so it is not reexported 202 if asNode(s.Def) == nil { 203 if exportname(s.Name) || initname(s.Name) { 204 s.SetExport(true) 205 } else { 206 s.SetPackage(true) // package scope 207 } 208 } 209 } 210 211 // pkgtype returns the named type declared by symbol s. 212 // If no such type has been declared yet, a forward declaration is returned. 213 // pkg is the package being imported 214 func pkgtype(pkg *types.Pkg, s *types.Sym) *types.Type { 215 importsym(pkg, s, OTYPE) 216 if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE { 217 t := types.New(TFORW) 218 t.Sym = s 219 s.Def = asTypesNode(typenod(t)) 220 asNode(s.Def).Name = new(Name) 221 } 222 223 if asNode(s.Def).Type == nil { 224 Fatalf("pkgtype %v", s) 225 } 226 return asNode(s.Def).Type 227 } 228 229 // importconst declares symbol s as an imported constant with type t and value n. 230 // pkg is the package being imported 231 func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) { 232 importsym(pkg, s, OLITERAL) 233 n = convlit(n, t) 234 235 if asNode(s.Def) != nil { // TODO: check if already the same. 236 return 237 } 238 239 if n.Op != OLITERAL { 240 yyerror("expression must be a constant") 241 return 242 } 243 244 if n.Sym != nil { 245 n1 := *n 246 n = &n1 247 } 248 249 n.Orig = newname(s) 250 n.Sym = s 251 declare(n, PEXTERN) 252 253 if Debug['E'] != 0 { 254 fmt.Printf("import const %v\n", s) 255 } 256 } 257 258 // importvar declares symbol s as an imported variable with type t. 259 // pkg is the package being imported 260 func importvar(pkg *types.Pkg, s *types.Sym, t *types.Type) { 261 importsym(pkg, s, ONAME) 262 if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME { 263 if eqtype(t, asNode(s.Def).Type) { 264 return 265 } 266 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) 267 } 268 269 n := newname(s) 270 s.Importdef = pkg 271 n.Type = t 272 declare(n, PEXTERN) 273 274 if Debug['E'] != 0 { 275 fmt.Printf("import var %v %L\n", s, t) 276 } 277 } 278 279 // importalias declares symbol s as an imported type alias with type t. 280 // pkg is the package being imported 281 func importalias(pkg *types.Pkg, s *types.Sym, t *types.Type) { 282 importsym(pkg, s, OTYPE) 283 if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE { 284 if eqtype(t, asNode(s.Def).Type) { 285 return 286 } 287 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) 288 } 289 290 n := newname(s) 291 n.Op = OTYPE 292 s.Importdef = pkg 293 n.Type = t 294 declare(n, PEXTERN) 295 296 if Debug['E'] != 0 { 297 fmt.Printf("import type %v = %L\n", s, t) 298 } 299 } 300 301 func dumpasmhdr() { 302 b, err := bio.Create(asmhdr) 303 if err != nil { 304 Fatalf("%v", err) 305 } 306 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 307 for _, n := range asmlist { 308 if isblanksym(n.Sym) { 309 continue 310 } 311 switch n.Op { 312 case OLITERAL: 313 fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) 314 315 case OTYPE: 316 t := n.Type 317 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 318 break 319 } 320 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 321 for _, t := range t.Fields().Slice() { 322 if !isblanksym(t.Sym) { 323 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 324 } 325 } 326 } 327 } 328 329 b.Close() 330 }