github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 types are on exportlist before type aliases. 49 if n.Sym.isAlias() { 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.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != 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 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 137 reexportdep(n.Left) 138 reexportdep(n.Right) 139 reexportdeplist(n.List) 140 reexportdeplist(n.Rlist) 141 reexportdeplist(n.Ninit) 142 reexportdeplist(n.Nbody) 143 } 144 145 // methodbyname sorts types by symbol name. 146 type methodbyname []*Field 147 148 func (x methodbyname) Len() int { return len(x) } 149 func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 150 func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name } 151 152 func dumpexport() { 153 if buildid != "" { 154 exportf("build id %q\n", buildid) 155 } 156 157 size := 0 // size of export section without enclosing markers 158 // The linker also looks for the $$ marker - use char after $$ to distinguish format. 159 exportf("\n$$B\n") // indicate binary export format 160 if debugFormat { 161 // save a copy of the export data 162 var copy bytes.Buffer 163 bcopy := bufio.NewWriter(©) 164 size = export(bcopy, Debug_export != 0) 165 bcopy.Flush() // flushing to bytes.Buffer cannot fail 166 if n, err := bout.Write(copy.Bytes()); n != size || err != nil { 167 Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err) 168 } 169 // export data must contain no '$' so that we can find the end by searching for "$$" 170 // TODO(gri) is this still needed? 171 if bytes.IndexByte(copy.Bytes(), '$') >= 0 { 172 Fatalf("export data contains $") 173 } 174 175 // verify that we can read the copied export data back in 176 // (use empty package map to avoid collisions) 177 savedPkgMap := pkgMap 178 savedPkgs := pkgs 179 pkgMap = make(map[string]*Pkg) 180 pkgs = nil 181 importpkg = mkpkg("") 182 Import(bufio.NewReader(©)) // must not die 183 importpkg = nil 184 pkgs = savedPkgs 185 pkgMap = savedPkgMap 186 } else { 187 size = export(bout.Writer, Debug_export != 0) 188 } 189 exportf("\n$$\n") 190 191 if Debug_export != 0 { 192 fmt.Printf("export data size = %d bytes\n", size) 193 } 194 } 195 196 // importsym declares symbol s as an imported object representable by op. 197 func importsym(s *Sym, op Op) { 198 if s.Def != nil && s.Def.Op != op { 199 pkgstr := fmt.Sprintf("during import %q", importpkg.Path) 200 redeclare(s, pkgstr) 201 } 202 203 // mark the symbol so it is not reexported 204 if s.Def == nil { 205 if exportname(s.Name) || initname(s.Name) { 206 s.Flags |= SymExport 207 } else { 208 s.Flags |= SymPackage // package scope 209 } 210 } 211 } 212 213 // pkgtype returns the named type declared by symbol s. 214 // If no such type has been declared yet, a forward declaration is returned. 215 func pkgtype(s *Sym) *Type { 216 importsym(s, OTYPE) 217 if s.Def == nil || s.Def.Op != OTYPE { 218 t := typ(TFORW) 219 t.Sym = s 220 s.Def = typenod(t) 221 s.Def.Name = new(Name) 222 } 223 224 if s.Def.Type == nil { 225 yyerror("pkgtype %v", s) 226 } 227 return s.Def.Type 228 } 229 230 // importconst declares symbol s as an imported constant with type t and value n. 231 func importconst(s *Sym, t *Type, n *Node) { 232 importsym(s, OLITERAL) 233 n = convlit(n, t) 234 235 if 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 func importvar(s *Sym, t *Type) { 260 importsym(s, ONAME) 261 if s.Def != nil && s.Def.Op == ONAME { 262 if eqtype(t, s.Def.Type) { 263 return 264 } 265 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) 266 } 267 268 n := newname(s) 269 s.Importdef = importpkg 270 n.Type = t 271 declare(n, PEXTERN) 272 273 if Debug['E'] != 0 { 274 fmt.Printf("import var %v %L\n", s, t) 275 } 276 } 277 278 // importalias declares symbol s as an imported type alias with type t. 279 func importalias(s *Sym, t *Type) { 280 importsym(s, OTYPE) 281 if s.Def != nil && s.Def.Op == OTYPE { 282 if eqtype(t, s.Def.Type) { 283 return 284 } 285 yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path) 286 } 287 288 n := newname(s) 289 n.Op = OTYPE 290 s.Importdef = importpkg 291 n.Type = t 292 declare(n, PEXTERN) 293 294 if Debug['E'] != 0 { 295 fmt.Printf("import type %v = %L\n", s, t) 296 } 297 } 298 299 func dumpasmhdr() { 300 b, err := bio.Create(asmhdr) 301 if err != nil { 302 Fatalf("%v", err) 303 } 304 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 305 for _, n := range asmlist { 306 if isblanksym(n.Sym) { 307 continue 308 } 309 switch n.Op { 310 case OLITERAL: 311 fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) 312 313 case OTYPE: 314 t := n.Type 315 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 316 break 317 } 318 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 319 for _, t := range t.Fields().Slice() { 320 if !isblanksym(t.Sym) { 321 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 322 } 323 } 324 } 325 } 326 327 b.Close() 328 }