You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
6.3 KiB

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