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.

239 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 defines utilities for population of method sets.
  6. import (
  7. "fmt"
  8. "go/types"
  9. )
  10. // MethodValue returns the Function implementing method sel, building
  11. // wrapper methods on demand. It returns nil if sel denotes an
  12. // abstract (interface) method.
  13. //
  14. // Precondition: sel.Kind() == MethodVal.
  15. //
  16. // Thread-safe.
  17. //
  18. // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
  19. //
  20. func (prog *Program) MethodValue(sel *types.Selection) *Function {
  21. if sel.Kind() != types.MethodVal {
  22. panic(fmt.Sprintf("Method(%s) kind != MethodVal", sel))
  23. }
  24. T := sel.Recv()
  25. if isInterface(T) {
  26. return nil // abstract method
  27. }
  28. if prog.mode&LogSource != 0 {
  29. defer logStack("Method %s %v", T, sel)()
  30. }
  31. prog.methodsMu.Lock()
  32. defer prog.methodsMu.Unlock()
  33. return prog.addMethod(prog.createMethodSet(T), sel)
  34. }
  35. // LookupMethod returns the implementation of the method of type T
  36. // identified by (pkg, name). It returns nil if the method exists but
  37. // is abstract, and panics if T has no such method.
  38. //
  39. func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
  40. sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
  41. if sel == nil {
  42. panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
  43. }
  44. return prog.MethodValue(sel)
  45. }
  46. // methodSet contains the (concrete) methods of a non-interface type.
  47. type methodSet struct {
  48. mapping map[string]*Function // populated lazily
  49. complete bool // mapping contains all methods
  50. }
  51. // Precondition: !isInterface(T).
  52. // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
  53. func (prog *Program) createMethodSet(T types.Type) *methodSet {
  54. mset, ok := prog.methodSets.At(T).(*methodSet)
  55. if !ok {
  56. mset = &methodSet{mapping: make(map[string]*Function)}
  57. prog.methodSets.Set(T, mset)
  58. }
  59. return mset
  60. }
  61. // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
  62. func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function {
  63. if sel.Kind() == types.MethodExpr {
  64. panic(sel)
  65. }
  66. id := sel.Obj().Id()
  67. fn := mset.mapping[id]
  68. if fn == nil {
  69. obj := sel.Obj().(*types.Func)
  70. needsPromotion := len(sel.Index()) > 1
  71. needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv())
  72. if needsPromotion || needsIndirection {
  73. fn = makeWrapper(prog, sel)
  74. } else {
  75. fn = prog.declaredFunc(obj)
  76. }
  77. if fn.Signature.Recv() == nil {
  78. panic(fn) // missing receiver
  79. }
  80. mset.mapping[id] = fn
  81. }
  82. return fn
  83. }
  84. // RuntimeTypes returns a new unordered slice containing all
  85. // concrete types in the program for which a complete (non-empty)
  86. // method set is required at run-time.
  87. //
  88. // Thread-safe.
  89. //
  90. // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
  91. //
  92. func (prog *Program) RuntimeTypes() []types.Type {
  93. prog.methodsMu.Lock()
  94. defer prog.methodsMu.Unlock()
  95. var res []types.Type
  96. prog.methodSets.Iterate(func(T types.Type, v interface{}) {
  97. if v.(*methodSet).complete {
  98. res = append(res, T)
  99. }
  100. })
  101. return res
  102. }
  103. // declaredFunc returns the concrete function/method denoted by obj.
  104. // Panic ensues if there is none.
  105. //
  106. func (prog *Program) declaredFunc(obj *types.Func) *Function {
  107. if v := prog.packageLevelValue(obj); v != nil {
  108. return v.(*Function)
  109. }
  110. panic("no concrete method: " + obj.String())
  111. }
  112. // needMethodsOf ensures that runtime type information (including the
  113. // complete method set) is available for the specified type T and all
  114. // its subcomponents.
  115. //
  116. // needMethodsOf must be called for at least every type that is an
  117. // operand of some MakeInterface instruction, and for the type of
  118. // every exported package member.
  119. //
  120. // Precondition: T is not a method signature (*Signature with Recv()!=nil).
  121. //
  122. // Thread-safe. (Called via emitConv from multiple builder goroutines.)
  123. //
  124. // TODO(adonovan): make this faster. It accounts for 20% of SSA build time.
  125. //
  126. // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
  127. //
  128. func (prog *Program) needMethodsOf(T types.Type) {
  129. prog.methodsMu.Lock()
  130. prog.needMethods(T, false)
  131. prog.methodsMu.Unlock()
  132. }
  133. // Precondition: T is not a method signature (*Signature with Recv()!=nil).
  134. // Recursive case: skip => don't create methods for T.
  135. //
  136. // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
  137. //
  138. func (prog *Program) needMethods(T types.Type, skip bool) {
  139. // Each package maintains its own set of types it has visited.
  140. if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
  141. // needMethods(T) was previously called
  142. if !prevSkip || skip {
  143. return // already seen, with same or false 'skip' value
  144. }
  145. }
  146. prog.runtimeTypes.Set(T, skip)
  147. tmset := prog.MethodSets.MethodSet(T)
  148. if !skip && !isInterface(T) && tmset.Len() > 0 {
  149. // Create methods of T.
  150. mset := prog.createMethodSet(T)
  151. if !mset.complete {
  152. mset.complete = true
  153. n := tmset.Len()
  154. for i := 0; i < n; i++ {
  155. prog.addMethod(mset, tmset.At(i))
  156. }
  157. }
  158. }
  159. // Recursion over signatures of each method.
  160. for i := 0; i < tmset.Len(); i++ {
  161. sig := tmset.At(i).Type().(*types.Signature)
  162. prog.needMethods(sig.Params(), false)
  163. prog.needMethods(sig.Results(), false)
  164. }
  165. switch t := T.(type) {
  166. case *types.Basic:
  167. // nop
  168. case *types.Interface:
  169. // nop---handled by recursion over method set.
  170. case *types.Pointer:
  171. prog.needMethods(t.Elem(), false)
  172. case *types.Slice:
  173. prog.needMethods(t.Elem(), false)
  174. case *types.Chan:
  175. prog.needMethods(t.Elem(), false)
  176. case *types.Map:
  177. prog.needMethods(t.Key(), false)
  178. prog.needMethods(t.Elem(), false)
  179. case *types.Signature:
  180. if t.Recv() != nil {
  181. panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
  182. }
  183. prog.needMethods(t.Params(), false)
  184. prog.needMethods(t.Results(), false)
  185. case *types.Named:
  186. // A pointer-to-named type can be derived from a named
  187. // type via reflection. It may have methods too.
  188. prog.needMethods(types.NewPointer(T), false)
  189. // Consider 'type T struct{S}' where S has methods.
  190. // Reflection provides no way to get from T to struct{S},
  191. // only to S, so the method set of struct{S} is unwanted,
  192. // so set 'skip' flag during recursion.
  193. prog.needMethods(t.Underlying(), true)
  194. case *types.Array:
  195. prog.needMethods(t.Elem(), false)
  196. case *types.Struct:
  197. for i, n := 0, t.NumFields(); i < n; i++ {
  198. prog.needMethods(t.Field(i).Type(), false)
  199. }
  200. case *types.Tuple:
  201. for i, n := 0, t.Len(); i < n; i++ {
  202. prog.needMethods(t.At(i).Type(), false)
  203. }
  204. default:
  205. panic(T)
  206. }
  207. }