github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/pointer/util.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 pointer 6 7 import ( 8 "bytes" 9 "fmt" 10 "log" 11 "os" 12 "os/exec" 13 "runtime" 14 "time" 15 16 "llvm.org/llgo/third_party/gotools/container/intsets" 17 "llvm.org/llgo/third_party/gotools/go/types" 18 ) 19 20 // CanPoint reports whether the type T is pointerlike, 21 // for the purposes of this analysis. 22 func CanPoint(T types.Type) bool { 23 switch T := T.(type) { 24 case *types.Named: 25 if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" { 26 return true // treat reflect.Value like interface{} 27 } 28 return CanPoint(T.Underlying()) 29 30 case *types.Pointer, *types.Interface, *types.Map, *types.Chan, *types.Signature, *types.Slice: 31 return true 32 } 33 34 return false // array struct tuple builtin basic 35 } 36 37 // CanHaveDynamicTypes reports whether the type T can "hold" dynamic types, 38 // i.e. is an interface (incl. reflect.Type) or a reflect.Value. 39 // 40 func CanHaveDynamicTypes(T types.Type) bool { 41 switch T := T.(type) { 42 case *types.Named: 43 if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" { 44 return true // reflect.Value 45 } 46 return CanHaveDynamicTypes(T.Underlying()) 47 case *types.Interface: 48 return true 49 } 50 return false 51 } 52 53 func isInterface(T types.Type) bool { return types.IsInterface(T) } 54 55 // mustDeref returns the element type of its argument, which must be a 56 // pointer; panic ensues otherwise. 57 func mustDeref(typ types.Type) types.Type { 58 return typ.Underlying().(*types.Pointer).Elem() 59 } 60 61 // deref returns a pointer's element type; otherwise it returns typ. 62 func deref(typ types.Type) types.Type { 63 if p, ok := typ.Underlying().(*types.Pointer); ok { 64 return p.Elem() 65 } 66 return typ 67 } 68 69 // A fieldInfo describes one subelement (node) of the flattening-out 70 // of a type T: the subelement's type and its path from the root of T. 71 // 72 // For example, for this type: 73 // type line struct{ points []struct{x, y int} } 74 // flatten() of the inner struct yields the following []fieldInfo: 75 // struct{ x, y int } "" 76 // int ".x" 77 // int ".y" 78 // and flatten(line) yields: 79 // struct{ points []struct{x, y int} } "" 80 // struct{ x, y int } ".points[*]" 81 // int ".points[*].x 82 // int ".points[*].y" 83 // 84 type fieldInfo struct { 85 typ types.Type 86 87 // op and tail describe the path to the element (e.g. ".a#2.b[*].c"). 88 op interface{} // *Array: true; *Tuple: int; *Struct: *types.Var; *Named: nil 89 tail *fieldInfo 90 } 91 92 // path returns a user-friendly string describing the subelement path. 93 // 94 func (fi *fieldInfo) path() string { 95 var buf bytes.Buffer 96 for p := fi; p != nil; p = p.tail { 97 switch op := p.op.(type) { 98 case bool: 99 fmt.Fprintf(&buf, "[*]") 100 case int: 101 fmt.Fprintf(&buf, "#%d", op) 102 case *types.Var: 103 fmt.Fprintf(&buf, ".%s", op.Name()) 104 } 105 } 106 return buf.String() 107 } 108 109 // flatten returns a list of directly contained fields in the preorder 110 // traversal of the type tree of t. The resulting elements are all 111 // scalars (basic types or pointerlike types), except for struct/array 112 // "identity" nodes, whose type is that of the aggregate. 113 // 114 // reflect.Value is considered pointerlike, similar to interface{}. 115 // 116 // Callers must not mutate the result. 117 // 118 func (a *analysis) flatten(t types.Type) []*fieldInfo { 119 fl, ok := a.flattenMemo[t] 120 if !ok { 121 switch t := t.(type) { 122 case *types.Named: 123 u := t.Underlying() 124 if isInterface(u) { 125 // Debuggability hack: don't remove 126 // the named type from interfaces as 127 // they're very verbose. 128 fl = append(fl, &fieldInfo{typ: t}) 129 } else { 130 fl = a.flatten(u) 131 } 132 133 case *types.Basic, 134 *types.Signature, 135 *types.Chan, 136 *types.Map, 137 *types.Interface, 138 *types.Slice, 139 *types.Pointer: 140 fl = append(fl, &fieldInfo{typ: t}) 141 142 case *types.Array: 143 fl = append(fl, &fieldInfo{typ: t}) // identity node 144 for _, fi := range a.flatten(t.Elem()) { 145 fl = append(fl, &fieldInfo{typ: fi.typ, op: true, tail: fi}) 146 } 147 148 case *types.Struct: 149 fl = append(fl, &fieldInfo{typ: t}) // identity node 150 for i, n := 0, t.NumFields(); i < n; i++ { 151 f := t.Field(i) 152 for _, fi := range a.flatten(f.Type()) { 153 fl = append(fl, &fieldInfo{typ: fi.typ, op: f, tail: fi}) 154 } 155 } 156 157 case *types.Tuple: 158 // No identity node: tuples are never address-taken. 159 n := t.Len() 160 if n == 1 { 161 // Don't add a fieldInfo link for singletons, 162 // e.g. in params/results. 163 fl = append(fl, a.flatten(t.At(0).Type())...) 164 } else { 165 for i := 0; i < n; i++ { 166 f := t.At(i) 167 for _, fi := range a.flatten(f.Type()) { 168 fl = append(fl, &fieldInfo{typ: fi.typ, op: i, tail: fi}) 169 } 170 } 171 } 172 173 default: 174 panic(t) 175 } 176 177 a.flattenMemo[t] = fl 178 } 179 180 return fl 181 } 182 183 // sizeof returns the number of pointerlike abstractions (nodes) in the type t. 184 func (a *analysis) sizeof(t types.Type) uint32 { 185 return uint32(len(a.flatten(t))) 186 } 187 188 // shouldTrack reports whether object type T contains (recursively) 189 // any fields whose addresses should be tracked. 190 func (a *analysis) shouldTrack(T types.Type) bool { 191 if a.track == trackAll { 192 return true // fast path 193 } 194 track, ok := a.trackTypes[T] 195 if !ok { 196 a.trackTypes[T] = true // break cycles conservatively 197 // NB: reflect.Value, reflect.Type are pre-populated to true. 198 for _, fi := range a.flatten(T) { 199 switch ft := fi.typ.Underlying().(type) { 200 case *types.Interface, *types.Signature: 201 track = true // needed for callgraph 202 case *types.Basic: 203 // no-op 204 case *types.Chan: 205 track = a.track&trackChan != 0 || a.shouldTrack(ft.Elem()) 206 case *types.Map: 207 track = a.track&trackMap != 0 || a.shouldTrack(ft.Key()) || a.shouldTrack(ft.Elem()) 208 case *types.Slice: 209 track = a.track&trackSlice != 0 || a.shouldTrack(ft.Elem()) 210 case *types.Pointer: 211 track = a.track&trackPtr != 0 || a.shouldTrack(ft.Elem()) 212 case *types.Array, *types.Struct: 213 // No need to look at field types since they will follow (flattened). 214 default: 215 // Includes *types.Tuple, which are never address-taken. 216 panic(ft) 217 } 218 if track { 219 break 220 } 221 } 222 a.trackTypes[T] = track 223 if !track && a.log != nil { 224 fmt.Fprintf(a.log, "\ttype not tracked: %s\n", T) 225 } 226 } 227 return track 228 } 229 230 // offsetOf returns the (abstract) offset of field index within struct 231 // or tuple typ. 232 func (a *analysis) offsetOf(typ types.Type, index int) uint32 { 233 var offset uint32 234 switch t := typ.Underlying().(type) { 235 case *types.Tuple: 236 for i := 0; i < index; i++ { 237 offset += a.sizeof(t.At(i).Type()) 238 } 239 case *types.Struct: 240 offset++ // the node for the struct itself 241 for i := 0; i < index; i++ { 242 offset += a.sizeof(t.Field(i).Type()) 243 } 244 default: 245 panic(fmt.Sprintf("offsetOf(%s : %T)", typ, typ)) 246 } 247 return offset 248 } 249 250 // sliceToArray returns the type representing the arrays to which 251 // slice type slice points. 252 func sliceToArray(slice types.Type) *types.Array { 253 return types.NewArray(slice.Underlying().(*types.Slice).Elem(), 1) 254 } 255 256 // Node set ------------------------------------------------------------------- 257 258 type nodeset struct { 259 intsets.Sparse 260 } 261 262 func (ns *nodeset) String() string { 263 var buf bytes.Buffer 264 buf.WriteRune('{') 265 var space [50]int 266 for i, n := range ns.AppendTo(space[:0]) { 267 if i > 0 { 268 buf.WriteString(", ") 269 } 270 buf.WriteRune('n') 271 fmt.Fprintf(&buf, "%d", n) 272 } 273 buf.WriteRune('}') 274 return buf.String() 275 } 276 277 func (ns *nodeset) add(n nodeid) bool { 278 return ns.Sparse.Insert(int(n)) 279 } 280 281 func (x *nodeset) addAll(y *nodeset) bool { 282 return x.UnionWith(&y.Sparse) 283 } 284 285 // Profiling & debugging ------------------------------------------------------- 286 287 var timers = make(map[string]time.Time) 288 289 func start(name string) { 290 if debugTimers { 291 timers[name] = time.Now() 292 log.Printf("%s...\n", name) 293 } 294 } 295 296 func stop(name string) { 297 if debugTimers { 298 log.Printf("%s took %s\n", name, time.Since(timers[name])) 299 } 300 } 301 302 // diff runs the command "diff a b" and reports its success. 303 func diff(a, b string) bool { 304 var cmd *exec.Cmd 305 switch runtime.GOOS { 306 case "plan9": 307 cmd = exec.Command("/bin/diff", "-c", a, b) 308 default: 309 cmd = exec.Command("/usr/bin/diff", "-u", a, b) 310 } 311 cmd.Stdout = os.Stderr 312 cmd.Stderr = os.Stderr 313 return cmd.Run() == nil 314 }