github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/create.go (about) 1 // Copyright 2013 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 ssa 6 7 // This file implements the CREATE phase of SSA construction. 8 // See builder.go for explanation. 9 10 import ( 11 "fmt" 12 "go/ast" 13 "go/token" 14 "os" 15 "sync" 16 17 "llvm.org/llgo/third_party/gotools/go/loader" 18 "llvm.org/llgo/third_party/gotools/go/types" 19 "llvm.org/llgo/third_party/gotools/go/types/typeutil" 20 ) 21 22 // Create returns a new SSA Program. An SSA Package is created for 23 // each transitively error-free package of iprog. 24 // 25 // Code for bodies of functions is not built until Build() is called 26 // on the result. 27 // 28 // mode controls diagnostics and checking during SSA construction. 29 // 30 func Create(iprog *loader.Program, mode BuilderMode) *Program { 31 prog := &Program{ 32 Fset: iprog.Fset, 33 imported: make(map[string]*Package), 34 packages: make(map[*types.Package]*Package), 35 thunks: make(map[selectionKey]*Function), 36 bounds: make(map[*types.Func]*Function), 37 mode: mode, 38 } 39 40 h := typeutil.MakeHasher() // protected by methodsMu, in effect 41 prog.methodSets.SetHasher(h) 42 prog.canon.SetHasher(h) 43 44 for _, info := range iprog.AllPackages { 45 // TODO(adonovan): relax this constraint if the 46 // program contains only "soft" errors. 47 if info.TransitivelyErrorFree { 48 prog.CreatePackage(info) 49 } 50 } 51 52 return prog 53 } 54 55 // memberFromObject populates package pkg with a member for the 56 // typechecker object obj. 57 // 58 // For objects from Go source code, syntax is the associated syntax 59 // tree (for funcs and vars only); it will be used during the build 60 // phase. 61 // 62 func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { 63 name := obj.Name() 64 switch obj := obj.(type) { 65 case *types.TypeName: 66 pkg.Members[name] = &Type{ 67 object: obj, 68 pkg: pkg, 69 } 70 71 case *types.Const: 72 c := &NamedConst{ 73 object: obj, 74 Value: NewConst(obj.Val(), obj.Type()), 75 pkg: pkg, 76 } 77 pkg.values[obj] = c.Value 78 pkg.Members[name] = c 79 80 case *types.Var: 81 g := &Global{ 82 Pkg: pkg, 83 name: name, 84 object: obj, 85 typ: types.NewPointer(obj.Type()), // address 86 pos: obj.Pos(), 87 } 88 pkg.values[obj] = g 89 pkg.Members[name] = g 90 91 case *types.Func: 92 sig := obj.Type().(*types.Signature) 93 if sig.Recv() == nil && name == "init" { 94 pkg.ninit++ 95 name = fmt.Sprintf("init#%d", pkg.ninit) 96 } 97 fn := &Function{ 98 name: name, 99 object: obj, 100 Signature: sig, 101 syntax: syntax, 102 pos: obj.Pos(), 103 Pkg: pkg, 104 Prog: pkg.Prog, 105 } 106 if syntax == nil { 107 fn.Synthetic = "loaded from gc object file" 108 } 109 110 pkg.values[obj] = fn 111 if sig.Recv() == nil { 112 pkg.Members[name] = fn // package-level function 113 } 114 115 default: // (incl. *types.Package) 116 panic("unexpected Object type: " + obj.String()) 117 } 118 } 119 120 // membersFromDecl populates package pkg with members for each 121 // typechecker object (var, func, const or type) associated with the 122 // specified decl. 123 // 124 func membersFromDecl(pkg *Package, decl ast.Decl) { 125 switch decl := decl.(type) { 126 case *ast.GenDecl: // import, const, type or var 127 switch decl.Tok { 128 case token.CONST: 129 for _, spec := range decl.Specs { 130 for _, id := range spec.(*ast.ValueSpec).Names { 131 if !isBlankIdent(id) { 132 memberFromObject(pkg, pkg.info.Defs[id], nil) 133 } 134 } 135 } 136 137 case token.VAR: 138 for _, spec := range decl.Specs { 139 for _, id := range spec.(*ast.ValueSpec).Names { 140 if !isBlankIdent(id) { 141 memberFromObject(pkg, pkg.info.Defs[id], spec) 142 } 143 } 144 } 145 146 case token.TYPE: 147 for _, spec := range decl.Specs { 148 id := spec.(*ast.TypeSpec).Name 149 if !isBlankIdent(id) { 150 memberFromObject(pkg, pkg.info.Defs[id], nil) 151 } 152 } 153 } 154 155 case *ast.FuncDecl: 156 id := decl.Name 157 if !isBlankIdent(id) { 158 memberFromObject(pkg, pkg.info.Defs[id], decl) 159 } 160 } 161 } 162 163 // CreatePackage constructs and returns an SSA Package from an 164 // error-free package described by info, and populates its Members 165 // mapping. 166 // 167 // Repeated calls with the same info return the same Package. 168 // 169 // The real work of building SSA form for each function is not done 170 // until a subsequent call to Package.Build(). 171 // 172 func (prog *Program) CreatePackage(info *loader.PackageInfo) *Package { 173 if p := prog.packages[info.Pkg]; p != nil { 174 return p // already loaded 175 } 176 177 p := &Package{ 178 Prog: prog, 179 Members: make(map[string]Member), 180 values: make(map[types.Object]Value), 181 Object: info.Pkg, 182 info: info, // transient (CREATE and BUILD phases) 183 } 184 185 // Add init() function. 186 p.init = &Function{ 187 name: "init", 188 Signature: new(types.Signature), 189 Synthetic: "package initializer", 190 Pkg: p, 191 Prog: prog, 192 } 193 p.Members[p.init.name] = p.init 194 195 // CREATE phase. 196 // Allocate all package members: vars, funcs, consts and types. 197 if len(info.Files) > 0 { 198 // Go source package. 199 for _, file := range info.Files { 200 for _, decl := range file.Decls { 201 membersFromDecl(p, decl) 202 } 203 } 204 } else { 205 // GC-compiled binary package. 206 // No code. 207 // No position information. 208 scope := p.Object.Scope() 209 for _, name := range scope.Names() { 210 obj := scope.Lookup(name) 211 memberFromObject(p, obj, nil) 212 if obj, ok := obj.(*types.TypeName); ok { 213 named := obj.Type().(*types.Named) 214 for i, n := 0, named.NumMethods(); i < n; i++ { 215 memberFromObject(p, named.Method(i), nil) 216 } 217 } 218 } 219 } 220 221 if prog.mode&BareInits == 0 { 222 // Add initializer guard variable. 223 initguard := &Global{ 224 Pkg: p, 225 name: "init$guard", 226 typ: types.NewPointer(tBool), 227 } 228 p.Members[initguard.Name()] = initguard 229 } 230 231 if prog.mode&GlobalDebug != 0 { 232 p.SetDebugMode(true) 233 } 234 235 if prog.mode&PrintPackages != 0 { 236 printMu.Lock() 237 p.WriteTo(os.Stdout) 238 printMu.Unlock() 239 } 240 241 if info.Importable { 242 prog.imported[info.Pkg.Path()] = p 243 } 244 prog.packages[p.Object] = p 245 246 return p 247 } 248 249 // printMu serializes printing of Packages/Functions to stdout. 250 var printMu sync.Mutex 251 252 // AllPackages returns a new slice containing all packages in the 253 // program prog in unspecified order. 254 // 255 func (prog *Program) AllPackages() []*Package { 256 pkgs := make([]*Package, 0, len(prog.packages)) 257 for _, pkg := range prog.packages { 258 pkgs = append(pkgs, pkg) 259 } 260 return pkgs 261 } 262 263 // ImportedPackage returns the importable SSA Package whose import 264 // path is path, or nil if no such SSA package has been created. 265 // 266 // Not all packages are importable. For example, no import 267 // declaration can resolve to the x_test package created by 'go test' 268 // or the ad-hoc main package created 'go build foo.go'. 269 // 270 func (prog *Program) ImportedPackage(path string) *Package { 271 return prog.imported[path] 272 }