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