GoPLS Viewer

Home|gopls/go/ssa/create.go
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
5package ssa
6
7// This file implements the CREATE phase of SSA construction.
8// See builder.go for explanation.
9
10import (
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.
25func NewProgram(fset *token.FileSetmode 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        parameterizedtpWalker{seenmake(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.
52func memberFromObject(pkg *Packageobj types.Objectsyntax 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            objectobj,
63            pkg:    pkg,
64        }
65
66    case *types.Const:
67        c := &NamedConst{
68            objectobj,
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            objectobj,
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            typeparamstparams,
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.
133func membersFromDecl(pkg *Packagedecl 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(pkgpkg.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(pkgpkg.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(pkgpkg.info.Defs[id], nil)
160                }
161            }
162        }
163
164    case *ast.FuncDecl:
165        id := decl.Name
166        if !isBlankIdent(id) {
167            memberFromObject(pkgpkg.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.
177type creator []*Function
178
179func (c *creatorAdd(fn *Function) {
180    *c = append(*cfn)
181}
182func (c *creatorAt(i int) *Function { return (*c)[i] }
183func (c *creatorLen() 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().
194func (prog *ProgramCreatePackage(pkg *types.Packagefiles []*ast.Fileinfo *types.Infoimportable bool) *Package {
195    p := &Package{
196        Prog:    prog,
197        Membersmake(map[string]Member),
198        objectsmake(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        Signaturenew(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(pdecl)
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(pobjnil)
233            if objok := obj.(*types.TypeName); ok {
234                if namedok := obj.Type().(*types.Named); ok {
235                    for in := 0named.NumMethods(); i < ni++ {
236                        memberFromObject(pnamed.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.
272var printMu sync.Mutex
273
274// AllPackages returns a new slice containing all packages in the
275// program prog in unspecified order.
276func (prog *ProgramAllPackages() []*Package {
277    pkgs := make([]*Package0len(prog.packages))
278    for _pkg := range prog.packages {
279        pkgs = append(pkgspkg)
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.
297func (prog *ProgramImportedPackage(path string) *Package {
298    return prog.imported[path]
299}
300
MembersX
memberFromObject.BlockStmt.tparams
creator.Add
creator.At.i
memberFromObject.BlockStmt.c
Program.CreatePackage.BlockStmt.RangeStmt_5971.BlockStmt.BlockStmt.BlockStmt.i
membersFromDecl
memberFromObject.syntax
NewProgram.mode
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3927.spec
creator.Len.c
Program.CreatePackage.p
NewProgram
memberFromObject.BlockStmt.g
membersFromDecl.BlockStmt.id
NewProgram.prog
Program.CreatePackage.BlockStmt.RangeStmt_5740.BlockStmt.RangeStmt_5772.decl
Program.AllPackages.pkgs
NewProgram.fset
membersFromDecl.pkg
creator.Len
Program.CreatePackage.BlockStmt.RangeStmt_5971.BlockStmt.obj
Program.ImportedPackage
memberFromObject.BlockStmt.rtparams
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3927.BlockStmt.id
creator.At.c
Program.CreatePackage.BlockStmt.RangeStmt_5740.file
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3511.BlockStmt.RangeStmt_3549.id
creator.Add.c
Program.CreatePackage.BlockStmt.initguard
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3718.spec
memberFromObject.pkg
memberFromObject.name
memberFromObject.BlockStmt.fn
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3511.spec
Program.CreatePackage.BlockStmt.RangeStmt_5971.name
Program.AllPackages.prog
Program.ImportedPackage.prog
typeutil
Program.CreatePackage.pkg
Program.CreatePackage.BlockStmt.scope
memberFromObject
Program.CreatePackage
Program.CreatePackage.info
Program.AllPackages
memberFromObject.obj
Program.CreatePackage.files
Program.CreatePackage.BlockStmt.RangeStmt_5971.BlockStmt.BlockStmt.BlockStmt.n
creator.At
Program.CreatePackage.prog
NewProgram.h
printMu
Program.ImportedPackage.path
membersFromDecl.decl
membersFromDecl.BlockStmt.BlockStmt.RangeStmt_3718.BlockStmt.RangeStmt_3756.id
creator
creator.Add.fn
Program.CreatePackage.importable
Program.AllPackages.RangeStmt_7047.pkg
memberFromObject.BlockStmt.sigparams
Members
X