github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/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 types.CleanroomDo(func() { 177 Import(types.NewPkg("", ""), bufio.NewReader(©)) // must not die 178 }) 179 } else { 180 size = export(bout.Writer, Debug_export != 0) 181 } 182 exportf("\n$$\n") 183 184 if Debug_export != 0 { 185 fmt.Printf("export data size = %d bytes\n", size) 186 } 187 } 188 189 // importsym declares symbol s as an imported object representable by op. 190 // pkg is the package being imported 191 func importsym(pkg *types.Pkg, s *types.Sym, op Op) { 192 if asNode(s.Def) != nil && asNode(s.Def).Op != op { 193 pkgstr := fmt.Sprintf("during import %q", pkg.Path) 194 redeclare(s, pkgstr) 195 } 196 197 // mark the symbol so it is not reexported 198 if asNode(s.Def) == nil { 199 if exportname(s.Name) || initname(s.Name) { 200 s.SetExport(true) 201 } else { 202 s.SetPackage(true) // package scope 203 } 204 } 205 } 206 207 // pkgtype returns the named type declared by symbol s. 208 // If no such type has been declared yet, a forward declaration is returned. 209 // pkg is the package being imported 210 func pkgtype(pkg *types.Pkg, s *types.Sym) *types.Type { 211 importsym(pkg, s, OTYPE) 212 if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE { 213 t := types.New(TFORW) 214 t.Sym = s 215 s.Def = asTypesNode(typenod(t)) 216 asNode(s.Def).Name = new(Name) 217 } 218 219 if asNode(s.Def).Type == nil { 220 Fatalf("pkgtype %v", s) 221 } 222 return asNode(s.Def).Type 223 } 224 225 // importconst declares symbol s as an imported constant with type t and value n. 226 // pkg is the package being imported 227 func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) { 228 importsym(pkg, s, OLITERAL) 229 n = convlit(n, t) 230 231 if asNode(s.Def) != nil { // TODO: check if already the same. 232 return 233 } 234 235 if n.Op != OLITERAL { 236 yyerror("expression must be a constant") 237 return 238 } 239 240 if n.Sym != nil { 241 n1 := *n 242 n = &n1 243 } 244 245 n.Orig = newname(s) 246 n.Sym = s 247 declare(n, PEXTERN) 248 249 if Debug['E'] != 0 { 250 fmt.Printf("import const %v\n", s) 251 } 252 } 253 254 // importvar declares symbol s as an imported variable with type t. 255 // pkg is the package being imported 256 func importvar(pkg *types.Pkg, s *types.Sym, t *types.Type) { 257 importsym(pkg, s, ONAME) 258 if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME { 259 if eqtype(t, asNode(s.Def).Type) { 260 return 261 } 262 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) 263 } 264 265 n := newname(s) 266 s.Importdef = pkg 267 n.Type = t 268 declare(n, PEXTERN) 269 270 if Debug['E'] != 0 { 271 fmt.Printf("import var %v %L\n", s, t) 272 } 273 } 274 275 // importalias declares symbol s as an imported type alias with type t. 276 // pkg is the package being imported 277 func importalias(pkg *types.Pkg, s *types.Sym, t *types.Type) { 278 importsym(pkg, s, OTYPE) 279 if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE { 280 if eqtype(t, asNode(s.Def).Type) { 281 return 282 } 283 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) 284 } 285 286 n := newname(s) 287 n.Op = OTYPE 288 s.Importdef = pkg 289 n.Type = t 290 declare(n, PEXTERN) 291 292 if Debug['E'] != 0 { 293 fmt.Printf("import type %v = %L\n", s, t) 294 } 295 } 296 297 func dumpasmhdr() { 298 b, err := bio.Create(asmhdr) 299 if err != nil { 300 Fatalf("%v", err) 301 } 302 fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name) 303 for _, n := range asmlist { 304 if n.Sym.IsBlank() { 305 continue 306 } 307 switch n.Op { 308 case OLITERAL: 309 fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val()) 310 311 case OTYPE: 312 t := n.Type 313 if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { 314 break 315 } 316 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 317 for _, t := range t.Fields().Slice() { 318 if !t.Sym.IsBlank() { 319 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset)) 320 } 321 } 322 } 323 } 324 325 b.Close() 326 }