github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/pointer/intrinsics14.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 pointer 8 9 // This package defines the treatment of intrinsics, i.e. library 10 // functions requiring special analytical treatment. 11 // 12 // Most of these are C or assembly functions, but even some Go 13 // functions require may special treatment if the analysis completely 14 // replaces the implementation of an API such as reflection. 15 16 // TODO(adonovan): support a means of writing analytic summaries in 17 // the target code, so that users can summarise the effects of their 18 // own C functions using a snippet of Go. 19 20 import ( 21 "fmt" 22 23 "golang.org/x/tools/go/ssa" 24 "golang.org/x/tools/go/types" 25 ) 26 27 // Instances of 'intrinsic' generate analysis constraints for calls to 28 // intrinsic functions. 29 // Implementations may exploit information from the calling site 30 // via cgn.callersite; for shared contours this is nil. 31 type intrinsic func(a *analysis, cgn *cgnode) 32 33 // Initialized in explicit init() to defeat (spurious) initialization 34 // cycle error. 35 var intrinsicsByName = make(map[string]intrinsic) 36 37 func init() { 38 // Key strings are from Function.String(). 39 // That little dot ۰ is an Arabic zero numeral (U+06F0), 40 // categories [Nd]. 41 for name, fn := range map[string]intrinsic{ 42 // Other packages. 43 "bytes.Equal": ext۰NoEffect, 44 "bytes.IndexByte": ext۰NoEffect, 45 "crypto/aes.decryptBlockAsm": ext۰NoEffect, 46 "crypto/aes.encryptBlockAsm": ext۰NoEffect, 47 "crypto/aes.expandKeyAsm": ext۰NoEffect, 48 "crypto/aes.hasAsm": ext۰NoEffect, 49 "crypto/md5.block": ext۰NoEffect, 50 "crypto/rc4.xorKeyStream": ext۰NoEffect, 51 "crypto/sha1.block": ext۰NoEffect, 52 "crypto/sha256.block": ext۰NoEffect, 53 "hash/crc32.castagnoliSSE42": ext۰NoEffect, 54 "hash/crc32.haveSSE42": ext۰NoEffect, 55 "math.Abs": ext۰NoEffect, 56 "math.Acos": ext۰NoEffect, 57 "math.Asin": ext۰NoEffect, 58 "math.Atan": ext۰NoEffect, 59 "math.Atan2": ext۰NoEffect, 60 "math.Ceil": ext۰NoEffect, 61 "math.Cos": ext۰NoEffect, 62 "math.Dim": ext۰NoEffect, 63 "math.Exp": ext۰NoEffect, 64 "math.Exp2": ext۰NoEffect, 65 "math.Expm1": ext۰NoEffect, 66 "math.Float32bits": ext۰NoEffect, 67 "math.Float32frombits": ext۰NoEffect, 68 "math.Float64bits": ext۰NoEffect, 69 "math.Float64frombits": ext۰NoEffect, 70 "math.Floor": ext۰NoEffect, 71 "math.Frexp": ext۰NoEffect, 72 "math.Hypot": ext۰NoEffect, 73 "math.Ldexp": ext۰NoEffect, 74 "math.Log": ext۰NoEffect, 75 "math.Log10": ext۰NoEffect, 76 "math.Log1p": ext۰NoEffect, 77 "math.Log2": ext۰NoEffect, 78 "math.Max": ext۰NoEffect, 79 "math.Min": ext۰NoEffect, 80 "math.Mod": ext۰NoEffect, 81 "math.Modf": ext۰NoEffect, 82 "math.Remainder": ext۰NoEffect, 83 "math.Sin": ext۰NoEffect, 84 "math.Sincos": ext۰NoEffect, 85 "math.Sqrt": ext۰NoEffect, 86 "math.Tan": ext۰NoEffect, 87 "math.Trunc": ext۰NoEffect, 88 "math/big.addMulVVW": ext۰NoEffect, 89 "math/big.addVV": ext۰NoEffect, 90 "math/big.addVW": ext۰NoEffect, 91 "math/big.bitLen": ext۰NoEffect, 92 "math/big.divWVW": ext۰NoEffect, 93 "math/big.divWW": ext۰NoEffect, 94 "math/big.mulAddVWW": ext۰NoEffect, 95 "math/big.mulWW": ext۰NoEffect, 96 "math/big.shlVU": ext۰NoEffect, 97 "math/big.shrVU": ext۰NoEffect, 98 "math/big.subVV": ext۰NoEffect, 99 "math/big.subVW": ext۰NoEffect, 100 "net.runtime_Semacquire": ext۰NoEffect, 101 "net.runtime_Semrelease": ext۰NoEffect, 102 "net.runtime_pollClose": ext۰NoEffect, 103 "net.runtime_pollOpen": ext۰NoEffect, 104 "net.runtime_pollReset": ext۰NoEffect, 105 "net.runtime_pollServerInit": ext۰NoEffect, 106 "net.runtime_pollSetDeadline": ext۰NoEffect, 107 "net.runtime_pollUnblock": ext۰NoEffect, 108 "net.runtime_pollWait": ext۰NoEffect, 109 "net.runtime_pollWaitCanceled": ext۰NoEffect, 110 "os.epipecheck": ext۰NoEffect, 111 "runtime.BlockProfile": ext۰NoEffect, 112 "runtime.Breakpoint": ext۰NoEffect, 113 "runtime.CPUProfile": ext۰NoEffect, // good enough 114 "runtime.Caller": ext۰NoEffect, 115 "runtime.Callers": ext۰NoEffect, // good enough 116 "runtime.FuncForPC": ext۰NoEffect, 117 "runtime.GC": ext۰NoEffect, 118 "runtime.GOMAXPROCS": ext۰NoEffect, 119 "runtime.Goexit": ext۰NoEffect, 120 "runtime.GoroutineProfile": ext۰NoEffect, 121 "runtime.Gosched": ext۰NoEffect, 122 "runtime.MemProfile": ext۰NoEffect, 123 "runtime.NumCPU": ext۰NoEffect, 124 "runtime.NumGoroutine": ext۰NoEffect, 125 "runtime.ReadMemStats": ext۰NoEffect, 126 "runtime.SetBlockProfileRate": ext۰NoEffect, 127 "runtime.SetCPUProfileRate": ext۰NoEffect, 128 "runtime.SetFinalizer": ext۰runtime۰SetFinalizer, 129 "runtime.Stack": ext۰NoEffect, 130 "runtime.ThreadCreateProfile": ext۰NoEffect, 131 "runtime.cstringToGo": ext۰NoEffect, 132 "runtime.funcentry_go": ext۰NoEffect, 133 "runtime.funcline_go": ext۰NoEffect, 134 "runtime.funcname_go": ext۰NoEffect, 135 "runtime.getgoroot": ext۰NoEffect, 136 "runtime/pprof.runtime_cyclesPerSecond": ext۰NoEffect, 137 "strings.IndexByte": ext۰NoEffect, 138 "sync.runtime_Semacquire": ext۰NoEffect, 139 "sync.runtime_Semrelease": ext۰NoEffect, 140 "sync.runtime_Syncsemacquire": ext۰NoEffect, 141 "sync.runtime_Syncsemcheck": ext۰NoEffect, 142 "sync.runtime_Syncsemrelease": ext۰NoEffect, 143 "sync.runtime_procPin": ext۰NoEffect, 144 "sync.runtime_procUnpin": ext۰NoEffect, 145 "sync.runtime_registerPool": ext۰NoEffect, 146 "sync/atomic.AddInt32": ext۰NoEffect, 147 "sync/atomic.AddInt64": ext۰NoEffect, 148 "sync/atomic.AddUint32": ext۰NoEffect, 149 "sync/atomic.AddUint64": ext۰NoEffect, 150 "sync/atomic.AddUintptr": ext۰NoEffect, 151 "sync/atomic.CompareAndSwapInt32": ext۰NoEffect, 152 "sync/atomic.CompareAndSwapUint32": ext۰NoEffect, 153 "sync/atomic.CompareAndSwapUint64": ext۰NoEffect, 154 "sync/atomic.CompareAndSwapUintptr": ext۰NoEffect, 155 "sync/atomic.LoadInt32": ext۰NoEffect, 156 "sync/atomic.LoadInt64": ext۰NoEffect, 157 "sync/atomic.LoadPointer": ext۰NoEffect, // ignore unsafe.Pointers 158 "sync/atomic.LoadUint32": ext۰NoEffect, 159 "sync/atomic.LoadUint64": ext۰NoEffect, 160 "sync/atomic.LoadUintptr": ext۰NoEffect, 161 "sync/atomic.StoreInt32": ext۰NoEffect, 162 "sync/atomic.StorePointer": ext۰NoEffect, // ignore unsafe.Pointers 163 "sync/atomic.StoreUint32": ext۰NoEffect, 164 "sync/atomic.StoreUintptr": ext۰NoEffect, 165 "syscall.Close": ext۰NoEffect, 166 "syscall.Exit": ext۰NoEffect, 167 "syscall.Getpid": ext۰NoEffect, 168 "syscall.Getwd": ext۰NoEffect, 169 "syscall.Kill": ext۰NoEffect, 170 "syscall.RawSyscall": ext۰NoEffect, 171 "syscall.RawSyscall6": ext۰NoEffect, 172 "syscall.Syscall": ext۰NoEffect, 173 "syscall.Syscall6": ext۰NoEffect, 174 "syscall.runtime_AfterFork": ext۰NoEffect, 175 "syscall.runtime_BeforeFork": ext۰NoEffect, 176 "syscall.setenv_c": ext۰NoEffect, 177 "time.Sleep": ext۰NoEffect, 178 "time.now": ext۰NoEffect, 179 "time.startTimer": ext۰time۰startTimer, 180 "time.stopTimer": ext۰NoEffect, 181 } { 182 intrinsicsByName[name] = fn 183 } 184 } 185 186 // findIntrinsic returns the constraint generation function for an 187 // intrinsic function fn, or nil if the function should be handled normally. 188 // 189 func (a *analysis) findIntrinsic(fn *ssa.Function) intrinsic { 190 // Consult the *Function-keyed cache. 191 // A cached nil indicates a normal non-intrinsic function. 192 impl, ok := a.intrinsics[fn] 193 if !ok { 194 impl = intrinsicsByName[fn.String()] // may be nil 195 196 if a.isReflect(fn) { 197 if !a.config.Reflection { 198 impl = ext۰NoEffect // reflection disabled 199 } else if impl == nil { 200 // Ensure all "reflect" code is treated intrinsically. 201 impl = ext۰NotYetImplemented 202 } 203 } 204 205 a.intrinsics[fn] = impl 206 } 207 return impl 208 } 209 210 // isReflect reports whether fn belongs to the "reflect" package. 211 func (a *analysis) isReflect(fn *ssa.Function) bool { 212 if a.reflectValueObj == nil { 213 return false // "reflect" package not loaded 214 } 215 reflectPackage := a.reflectValueObj.Pkg() 216 if fn.Pkg != nil && fn.Pkg.Pkg == reflectPackage { 217 return true 218 } 219 // Synthetic wrappers have a nil Pkg, so they slip through the 220 // previous check. Check the receiver package. 221 // TODO(adonovan): should synthetic wrappers have a non-nil Pkg? 222 if recv := fn.Signature.Recv(); recv != nil { 223 if named, ok := deref(recv.Type()).(*types.Named); ok { 224 if named.Obj().Pkg() == reflectPackage { 225 return true // e.g. wrapper of (reflect.Value).f 226 } 227 } 228 } 229 return false 230 } 231 232 // A trivial intrinsic suitable for any function that does not: 233 // 1) induce aliases between its arguments or any global variables; 234 // 2) call any functions; or 235 // 3) create any labels. 236 // 237 // Many intrinsics (such as CompareAndSwapInt32) have a fourth kind of 238 // effect: loading or storing through a pointer. Though these could 239 // be significant, we deliberately ignore them because they are 240 // generally not worth the effort. 241 // 242 // We sometimes violate condition #3 if the function creates only 243 // non-function labels, as the control-flow graph is still sound. 244 // 245 func ext۰NoEffect(a *analysis, cgn *cgnode) {} 246 247 func ext۰NotYetImplemented(a *analysis, cgn *cgnode) { 248 fn := cgn.fn 249 a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn) 250 } 251 252 // ---------- func runtime.SetFinalizer(x, f interface{}) ---------- 253 254 // runtime.SetFinalizer(x, f) 255 type runtimeSetFinalizerConstraint struct { 256 targets nodeid // (indirect) 257 f nodeid // (ptr) 258 x nodeid 259 } 260 261 func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f } 262 func (c *runtimeSetFinalizerConstraint) presolve(h *hvn) { 263 h.markIndirect(onodeid(c.targets), "SetFinalizer.targets") 264 } 265 func (c *runtimeSetFinalizerConstraint) renumber(mapping []nodeid) { 266 c.targets = mapping[c.targets] 267 c.f = mapping[c.f] 268 c.x = mapping[c.x] 269 } 270 271 func (c *runtimeSetFinalizerConstraint) String() string { 272 return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f) 273 } 274 275 func (c *runtimeSetFinalizerConstraint) solve(a *analysis, delta *nodeset) { 276 for _, fObj := range delta.AppendTo(a.deltaSpace) { 277 tDyn, f, indirect := a.taggedValue(nodeid(fObj)) 278 if indirect { 279 // TODO(adonovan): we'll need to implement this 280 // when we start creating indirect tagged objects. 281 panic("indirect tagged object") 282 } 283 284 tSig, ok := tDyn.Underlying().(*types.Signature) 285 if !ok { 286 continue // not a function 287 } 288 if tSig.Recv() != nil { 289 panic(tSig) 290 } 291 if tSig.Params().Len() != 1 { 292 continue // not a unary function 293 } 294 295 // Extract x to tmp. 296 tx := tSig.Params().At(0).Type() 297 tmp := a.addNodes(tx, "SetFinalizer.tmp") 298 a.typeAssert(tx, tmp, c.x, false) 299 300 // Call f(tmp). 301 a.store(f, tmp, 1, a.sizeof(tx)) 302 303 // Add dynamic call target. 304 if a.onlineCopy(c.targets, f) { 305 a.addWork(c.targets) 306 } 307 } 308 } 309 310 func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) { 311 // This is the shared contour, used for dynamic calls. 312 targets := a.addOneNode(tInvalid, "SetFinalizer.targets", nil) 313 cgn.sites = append(cgn.sites, &callsite{targets: targets}) 314 params := a.funcParams(cgn.obj) 315 a.addConstraint(&runtimeSetFinalizerConstraint{ 316 targets: targets, 317 x: params, 318 f: params + 1, 319 }) 320 } 321 322 // ---------- func time.startTimer(t *runtimeTimer) ---------- 323 324 // time.StartTimer(t) 325 type timeStartTimerConstraint struct { 326 targets nodeid // (indirect) 327 t nodeid // (ptr) 328 } 329 330 func (c *timeStartTimerConstraint) ptr() nodeid { return c.t } 331 func (c *timeStartTimerConstraint) presolve(h *hvn) { 332 h.markIndirect(onodeid(c.targets), "StartTimer.targets") 333 } 334 func (c *timeStartTimerConstraint) renumber(mapping []nodeid) { 335 c.targets = mapping[c.targets] 336 c.t = mapping[c.t] 337 } 338 339 func (c *timeStartTimerConstraint) String() string { 340 return fmt.Sprintf("time.startTimer(n%d)", c.t) 341 } 342 343 func (c *timeStartTimerConstraint) solve(a *analysis, delta *nodeset) { 344 for _, tObj := range delta.AppendTo(a.deltaSpace) { 345 t := nodeid(tObj) 346 347 // We model startTimer as if it was defined thus: 348 // func startTimer(t *runtimeTimer) { t.f(t.arg) } 349 350 // We hard-code the field offsets of time.runtimeTimer: 351 // type runtimeTimer struct { 352 // 0 __identity__ 353 // 1 i int32 354 // 2 when int64 355 // 3 period int64 356 // 4 f func(int64, interface{}) 357 // 5 arg interface{} 358 // } 359 f := t + 4 360 arg := t + 5 361 362 // store t.arg to t.f.params[0] 363 // (offset 1 => skip identity) 364 a.store(f, arg, 1, 1) 365 366 // Add dynamic call target. 367 if a.onlineCopy(c.targets, f) { 368 a.addWork(c.targets) 369 } 370 } 371 } 372 373 func ext۰time۰startTimer(a *analysis, cgn *cgnode) { 374 // This is the shared contour, used for dynamic calls. 375 targets := a.addOneNode(tInvalid, "startTimer.targets", nil) 376 cgn.sites = append(cgn.sites, &callsite{targets: targets}) 377 params := a.funcParams(cgn.obj) 378 a.addConstraint(&timeStartTimerConstraint{ 379 targets: targets, 380 t: params, 381 }) 382 }