github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 "go/types" 15 "os" 16 "sync" 17 18 "github.com/powerman/golang-tools/go/types/typeutil" 19 "github.com/powerman/golang-tools/internal/typeparams" 20 ) 21 22 // NewProgram returns a new SSA Program. 23 // 24 // mode controls diagnostics and checking during SSA construction. 25 // 26 func NewProgram(fset *token.FileSet, mode BuilderMode) *Program { 27 prog := &Program{ 28 Fset: fset, 29 imported: make(map[string]*Package), 30 packages: make(map[*types.Package]*Package), 31 thunks: make(map[selectionKey]*Function), 32 bounds: make(map[boundsKey]*Function), 33 mode: mode, 34 canon: newCanonizer(), 35 ctxt: typeparams.NewContext(), 36 instances: make(map[*Function]*instanceSet), 37 } 38 39 h := typeutil.MakeHasher() // protected by methodsMu, in effect 40 prog.methodSets.SetHasher(h) 41 42 return prog 43 } 44 45 // memberFromObject populates package pkg with a member for the 46 // typechecker object obj. 47 // 48 // For objects from Go source code, syntax is the associated syntax 49 // tree (for funcs and vars only); it will be used during the build 50 // phase. 51 // 52 func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { 53 name := obj.Name() 54 switch obj := obj.(type) { 55 case *types.Builtin: 56 if pkg.Pkg != types.Unsafe { 57 panic("unexpected builtin object: " + obj.String()) 58 } 59 60 case *types.TypeName: 61 pkg.Members[name] = &Type{ 62 object: obj, 63 pkg: pkg, 64 } 65 66 case *types.Const: 67 c := &NamedConst{ 68 object: obj, 69 Value: NewConst(obj.Val(), obj.Type()), 70 pkg: pkg, 71 } 72 pkg.objects[obj] = c 73 pkg.Members[name] = c 74 75 case *types.Var: 76 g := &Global{ 77 Pkg: pkg, 78 name: name, 79 object: obj, 80 typ: types.NewPointer(obj.Type()), // address 81 pos: obj.Pos(), 82 } 83 pkg.objects[obj] = g 84 pkg.Members[name] = g 85 86 case *types.Func: 87 sig := obj.Type().(*types.Signature) 88 if sig.Recv() == nil && name == "init" { 89 pkg.ninit++ 90 name = fmt.Sprintf("init#%d", pkg.ninit) 91 } 92 93 // Collect type parameters if this is a generic function/method. 94 var tparams []*typeparams.TypeParam 95 for i, rtparams := 0, typeparams.RecvTypeParams(sig); i < rtparams.Len(); i++ { 96 tparams = append(tparams, rtparams.At(i)) 97 } 98 for i, sigparams := 0, typeparams.ForSignature(sig); i < sigparams.Len(); i++ { 99 tparams = append(tparams, sigparams.At(i)) 100 } 101 102 fn := &Function{ 103 name: name, 104 object: obj, 105 Signature: sig, 106 syntax: syntax, 107 pos: obj.Pos(), 108 Pkg: pkg, 109 Prog: pkg.Prog, 110 info: pkg.info, 111 _TypeParams: tparams, 112 } 113 pkg.created.Add(fn) 114 if syntax == nil { 115 fn.Synthetic = "loaded from gc object file" 116 } 117 if len(tparams) > 0 { 118 fn.Prog.createInstanceSet(fn) 119 } 120 if len(tparams) > 0 && syntax != nil { 121 fn.Synthetic = "generic function" 122 // TODO(taking): Allow for the function to be built once type params are supported. 123 fn.syntax = nil // Treating as an external function temporarily. 124 } 125 126 pkg.objects[obj] = fn 127 if sig.Recv() == nil { 128 pkg.Members[name] = fn // package-level function 129 } 130 131 default: // (incl. *types.Package) 132 panic("unexpected Object type: " + obj.String()) 133 } 134 } 135 136 // membersFromDecl populates package pkg with members for each 137 // typechecker object (var, func, const or type) associated with the 138 // specified decl. 139 // 140 func membersFromDecl(pkg *Package, decl ast.Decl) { 141 switch decl := decl.(type) { 142 case *ast.GenDecl: // import, const, type or var 143 switch decl.Tok { 144 case token.CONST: 145 for _, spec := range decl.Specs { 146 for _, id := range spec.(*ast.ValueSpec).Names { 147 if !isBlankIdent(id) { 148 memberFromObject(pkg, pkg.info.Defs[id], nil) 149 } 150 } 151 } 152 153 case token.VAR: 154 for _, spec := range decl.Specs { 155 for _, id := range spec.(*ast.ValueSpec).Names { 156 if !isBlankIdent(id) { 157 memberFromObject(pkg, pkg.info.Defs[id], spec) 158 } 159 } 160 } 161 162 case token.TYPE: 163 for _, spec := range decl.Specs { 164 id := spec.(*ast.TypeSpec).Name 165 if !isBlankIdent(id) { 166 memberFromObject(pkg, pkg.info.Defs[id], nil) 167 } 168 } 169 } 170 171 case *ast.FuncDecl: 172 id := decl.Name 173 if !isBlankIdent(id) { 174 memberFromObject(pkg, pkg.info.Defs[id], decl) 175 } 176 } 177 } 178 179 // creator tracks functions that have finished their CREATE phases. 180 // 181 // All Functions belong to the same Program. May have differing packages. 182 // 183 // creators are not thread-safe. 184 type creator []*Function 185 186 func (c *creator) Add(fn *Function) { 187 *c = append(*c, fn) 188 } 189 func (c *creator) At(i int) *Function { return (*c)[i] } 190 func (c *creator) Len() int { return len(*c) } 191 192 // CreatePackage constructs and returns an SSA Package from the 193 // specified type-checked, error-free file ASTs, and populates its 194 // Members mapping. 195 // 196 // importable determines whether this package should be returned by a 197 // subsequent call to ImportedPackage(pkg.Path()). 198 // 199 // The real work of building SSA form for each function is not done 200 // until a subsequent call to Package.Build(). 201 // 202 func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package { 203 p := &Package{ 204 Prog: prog, 205 Members: make(map[string]Member), 206 objects: make(map[types.Object]Member), 207 Pkg: pkg, 208 info: info, // transient (CREATE and BUILD phases) 209 files: files, // transient (CREATE and BUILD phases) 210 } 211 212 // Add init() function. 213 p.init = &Function{ 214 name: "init", 215 Signature: new(types.Signature), 216 Synthetic: "package initializer", 217 Pkg: p, 218 Prog: prog, 219 info: p.info, 220 } 221 p.Members[p.init.name] = p.init 222 p.created.Add(p.init) 223 224 // CREATE phase. 225 // Allocate all package members: vars, funcs, consts and types. 226 if len(files) > 0 { 227 // Go source package. 228 for _, file := range files { 229 for _, decl := range file.Decls { 230 membersFromDecl(p, decl) 231 } 232 } 233 } else { 234 // GC-compiled binary package (or "unsafe") 235 // No code. 236 // No position information. 237 scope := p.Pkg.Scope() 238 for _, name := range scope.Names() { 239 obj := scope.Lookup(name) 240 memberFromObject(p, obj, nil) 241 if obj, ok := obj.(*types.TypeName); ok { 242 if named, ok := obj.Type().(*types.Named); ok { 243 for i, n := 0, named.NumMethods(); i < n; i++ { 244 memberFromObject(p, named.Method(i), nil) 245 } 246 } 247 } 248 } 249 } 250 251 if prog.mode&BareInits == 0 { 252 // Add initializer guard variable. 253 initguard := &Global{ 254 Pkg: p, 255 name: "init$guard", 256 typ: types.NewPointer(tBool), 257 } 258 p.Members[initguard.Name()] = initguard 259 } 260 261 if prog.mode&GlobalDebug != 0 { 262 p.SetDebugMode(true) 263 } 264 265 if prog.mode&PrintPackages != 0 { 266 printMu.Lock() 267 p.WriteTo(os.Stdout) 268 printMu.Unlock() 269 } 270 271 if importable { 272 prog.imported[p.Pkg.Path()] = p 273 } 274 prog.packages[p.Pkg] = p 275 276 return p 277 } 278 279 // printMu serializes printing of Packages/Functions to stdout. 280 var printMu sync.Mutex 281 282 // AllPackages returns a new slice containing all packages in the 283 // program prog in unspecified order. 284 // 285 func (prog *Program) AllPackages() []*Package { 286 pkgs := make([]*Package, 0, len(prog.packages)) 287 for _, pkg := range prog.packages { 288 pkgs = append(pkgs, pkg) 289 } 290 return pkgs 291 } 292 293 // ImportedPackage returns the importable Package whose PkgPath 294 // is path, or nil if no such Package has been created. 295 // 296 // A parameter to CreatePackage determines whether a package should be 297 // considered importable. For example, no import declaration can resolve 298 // to the ad-hoc main package created by 'go build foo.go'. 299 // 300 // TODO(adonovan): rethink this function and the "importable" concept; 301 // most packages are importable. This function assumes that all 302 // types.Package.Path values are unique within the ssa.Program, which is 303 // false---yet this function remains very convenient. 304 // Clients should use (*Program).Package instead where possible. 305 // SSA doesn't really need a string-keyed map of packages. 306 // 307 func (prog *Program) ImportedPackage(path string) *Package { 308 return prog.imported[path] 309 }