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