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