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