gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/golang.org/x/tools/go/ssa/interp/external.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 interp 6 7 // Emulated functions that we cannot interpret because they are 8 // external or because they use "unsafe" or "reflect" operations. 9 10 import ( 11 "go/types" 12 "math" 13 "os" 14 "runtime" 15 "strings" 16 "sync/atomic" 17 "time" 18 "unsafe" 19 20 "golang.org/x/tools/go/ssa" 21 ) 22 23 type externalFn func(fr *frame, args []value) value 24 25 // TODO(adonovan): fix: reflect.Value abstracts an lvalue or an 26 // rvalue; Set() causes mutations that can be observed via aliases. 27 // We have not captured that correctly here. 28 29 // Key strings are from Function.String(). 30 var externals = make(map[string]externalFn) 31 32 func init() { 33 // That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd]. 34 for k, v := range map[string]externalFn{ 35 "(*sync.Pool).Get": ext۰sync۰Pool۰Get, 36 "(*sync.Pool).Put": ext۰nop, 37 "(reflect.Value).Bool": ext۰reflect۰Value۰Bool, 38 "(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr, 39 "(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface, 40 "(reflect.Value).Elem": ext۰reflect۰Value۰Elem, 41 "(reflect.Value).Field": ext۰reflect۰Value۰Field, 42 "(reflect.Value).Float": ext۰reflect۰Value۰Float, 43 "(reflect.Value).Index": ext۰reflect۰Value۰Index, 44 "(reflect.Value).Int": ext۰reflect۰Value۰Int, 45 "(reflect.Value).Interface": ext۰reflect۰Value۰Interface, 46 "(reflect.Value).IsNil": ext۰reflect۰Value۰IsNil, 47 "(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid, 48 "(reflect.Value).Kind": ext۰reflect۰Value۰Kind, 49 "(reflect.Value).Len": ext۰reflect۰Value۰Len, 50 "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex, 51 "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys, 52 "(reflect.Value).NumField": ext۰reflect۰Value۰NumField, 53 "(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod, 54 "(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer, 55 "(reflect.Value).Set": ext۰reflect۰Value۰Set, 56 "(reflect.Value).String": ext۰reflect۰Value۰String, 57 "(reflect.Value).Type": ext۰reflect۰Value۰Type, 58 "(reflect.Value).Uint": ext۰reflect۰Value۰Uint, 59 "(reflect.error).Error": ext۰reflect۰error۰Error, 60 "(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits, 61 "(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem, 62 "(reflect.rtype).Field": ext۰reflect۰rtype۰Field, 63 "(reflect.rtype).In": ext۰reflect۰rtype۰In, 64 "(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind, 65 "(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField, 66 "(reflect.rtype).NumIn": ext۰reflect۰rtype۰NumIn, 67 "(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod, 68 "(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut, 69 "(reflect.rtype).Out": ext۰reflect۰rtype۰Out, 70 "(reflect.rtype).Size": ext۰reflect۰rtype۰Size, 71 "(reflect.rtype).String": ext۰reflect۰rtype۰String, 72 "bytes.init": ext۰nop, // avoid asm dependency 73 "bytes.Equal": ext۰bytes۰Equal, 74 "bytes.IndexByte": ext۰bytes۰IndexByte, 75 "hash/crc32.haveSSE42": ext۰crc32۰haveSSE42, 76 "internal/cpu.cpuid": ext۰cpu۰cpuid, 77 "math.Abs": ext۰math۰Abs, 78 "math.Exp": ext۰math۰Exp, 79 "math.Float32bits": ext۰math۰Float32bits, 80 "math.Float32frombits": ext۰math۰Float32frombits, 81 "math.Float64bits": ext۰math۰Float64bits, 82 "math.Float64frombits": ext۰math۰Float64frombits, 83 "math.Ldexp": ext۰math۰Ldexp, 84 "math.Log": ext۰math۰Log, 85 "math.Min": ext۰math۰Min, 86 "math.hasSSE4": ext۰math۰hasSSE4, 87 "os.runtime_args": ext۰os۰runtime_args, 88 "os.runtime_beforeExit": ext۰nop, 89 "os/signal.init": ext۰nop, 90 "reflect.New": ext۰reflect۰New, 91 "reflect.SliceOf": ext۰reflect۰SliceOf, 92 "reflect.TypeOf": ext۰reflect۰TypeOf, 93 "reflect.ValueOf": ext۰reflect۰ValueOf, 94 "reflect.Zero": ext۰reflect۰Zero, 95 "reflect.init": ext۰reflect۰Init, 96 "reflect.valueInterface": ext۰reflect۰valueInterface, 97 "runtime.Breakpoint": ext۰runtime۰Breakpoint, 98 "runtime.Caller": ext۰runtime۰Caller, 99 "runtime.Callers": ext۰runtime۰Callers, 100 "runtime.FuncForPC": ext۰runtime۰FuncForPC, 101 "runtime.GC": ext۰runtime۰GC, 102 "runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS, 103 "runtime.Goexit": ext۰runtime۰Goexit, 104 "runtime.Gosched": ext۰runtime۰Gosched, 105 "runtime.init": ext۰nop, 106 "runtime.KeepAlive": ext۰nop, 107 "runtime.NumCPU": ext۰runtime۰NumCPU, 108 "runtime.NumGoroutine": ext۰runtime۰NumGoroutine, 109 "runtime.ReadMemStats": ext۰runtime۰ReadMemStats, 110 "runtime.SetFinalizer": ext۰nop, // ignore 111 "(*runtime.Func).Entry": ext۰runtime۰Func۰Entry, 112 "(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine, 113 "(*runtime.Func).Name": ext۰runtime۰Func۰Name, 114 "runtime.environ": ext۰runtime۰environ, 115 "runtime.getgoroot": ext۰runtime۰getgoroot, 116 "strings.init": ext۰nop, // avoid asm dependency 117 "strings.Count": ext۰strings۰Count, 118 "strings.Index": ext۰strings۰Index, 119 "strings.IndexByte": ext۰strings۰IndexByte, 120 "sync.runtime_Semacquire": ext۰nop, // unimplementable 121 "sync.runtime_Semrelease": ext۰nop, // unimplementable 122 "sync.runtime_Syncsemcheck": ext۰nop, // unimplementable 123 "sync.runtime_notifyListCheck": ext۰nop, 124 "sync.runtime_registerPoolCleanup": ext۰nop, 125 "sync/atomic.AddInt32": ext۰atomic۰AddInt32, 126 "sync/atomic.AddUint32": ext۰atomic۰AddUint32, 127 "sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32, 128 "sync/atomic.CompareAndSwapUint32": ext۰atomic۰CompareAndSwapUint32, 129 "sync/atomic.LoadInt32": ext۰atomic۰LoadInt32, 130 "sync/atomic.LoadUint32": ext۰atomic۰LoadUint32, 131 "sync/atomic.StoreInt32": ext۰atomic۰StoreInt32, 132 "sync/atomic.StoreUint32": ext۰atomic۰StoreUint32, 133 "sync/atomic.AddInt64": ext۰atomic۰AddInt64, 134 "sync/atomic.AddUint64": ext۰atomic۰AddUint64, 135 "sync/atomic.CompareAndSwapInt64": ext۰atomic۰CompareAndSwapInt64, 136 "sync/atomic.CompareAndSwapUint64": ext۰atomic۰CompareAndSwapUint64, 137 "sync/atomic.LoadInt64": ext۰atomic۰LoadInt64, 138 "sync/atomic.LoadUint64": ext۰atomic۰LoadUint64, 139 "sync/atomic.StoreInt64": ext۰atomic۰StoreInt64, 140 "sync/atomic.StoreUint64": ext۰atomic۰StoreUint64, 141 "testing.callerEntry": ext۰testing۰callerEntry, 142 "testing.runExample": ext۰testing۰runExample, 143 "time.Sleep": ext۰time۰Sleep, 144 "time.now": ext۰time۰now, 145 } { 146 externals[k] = v 147 } 148 } 149 150 // wrapError returns an interpreted 'error' interface value for err. 151 func wrapError(err error) value { 152 if err == nil { 153 return iface{} 154 } 155 return iface{t: errorType, v: err.Error()} 156 } 157 158 func ext۰nop(fr *frame, args []value) value { return nil } 159 160 func ext۰sync۰Pool۰Get(fr *frame, args []value) value { 161 Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object() 162 _, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New") 163 164 if New := (*args[0].(*value)).(structure)[newIndex[0]]; New != nil { 165 return call(fr.i, fr, 0, New, nil) 166 } 167 return nil 168 } 169 170 func ext۰bytes۰Equal(fr *frame, args []value) value { 171 // func Equal(a, b []byte) bool 172 a := args[0].([]value) 173 b := args[1].([]value) 174 if len(a) != len(b) { 175 return false 176 } 177 for i := range a { 178 if a[i] != b[i] { 179 return false 180 } 181 } 182 return true 183 } 184 185 func ext۰bytes۰IndexByte(fr *frame, args []value) value { 186 // func IndexByte(s []byte, c byte) int 187 s := args[0].([]value) 188 c := args[1].(byte) 189 for i, b := range s { 190 if b.(byte) == c { 191 return i 192 } 193 } 194 return -1 195 } 196 197 func ext۰crc32۰haveSSE42(fr *frame, args []value) value { 198 return false 199 } 200 201 func ext۰math۰Float64frombits(fr *frame, args []value) value { 202 return math.Float64frombits(args[0].(uint64)) 203 } 204 205 func ext۰math۰Float64bits(fr *frame, args []value) value { 206 return math.Float64bits(args[0].(float64)) 207 } 208 209 func ext۰math۰Float32frombits(fr *frame, args []value) value { 210 return math.Float32frombits(args[0].(uint32)) 211 } 212 213 func ext۰math۰Abs(fr *frame, args []value) value { 214 return math.Abs(args[0].(float64)) 215 } 216 217 func ext۰math۰Exp(fr *frame, args []value) value { 218 return math.Exp(args[0].(float64)) 219 } 220 221 func ext۰math۰Float32bits(fr *frame, args []value) value { 222 return math.Float32bits(args[0].(float32)) 223 } 224 225 func ext۰math۰Min(fr *frame, args []value) value { 226 return math.Min(args[0].(float64), args[1].(float64)) 227 } 228 229 func ext۰math۰hasSSE4(fr *frame, args []value) value { 230 return false 231 } 232 233 func ext۰math۰Ldexp(fr *frame, args []value) value { 234 return math.Ldexp(args[0].(float64), args[1].(int)) 235 } 236 237 func ext۰math۰Log(fr *frame, args []value) value { 238 return math.Log(args[0].(float64)) 239 } 240 241 func ext۰os۰runtime_args(fr *frame, args []value) value { 242 return fr.i.osArgs 243 } 244 245 func ext۰runtime۰Breakpoint(fr *frame, args []value) value { 246 runtime.Breakpoint() 247 return nil 248 } 249 250 func ext۰runtime۰Caller(fr *frame, args []value) value { 251 // func Caller(skip int) (pc uintptr, file string, line int, ok bool) 252 skip := 1 + args[0].(int) 253 for i := 0; i < skip; i++ { 254 if fr != nil { 255 fr = fr.caller 256 } 257 } 258 var pc uintptr 259 var file string 260 var line int 261 var ok bool 262 if fr != nil { 263 fn := fr.fn 264 // TODO(adonovan): use pc/posn of current instruction, not start of fn. 265 // (Required to interpret the log package's tests.) 266 pc = uintptr(unsafe.Pointer(fn)) 267 posn := fn.Prog.Fset.Position(fn.Pos()) 268 file = posn.Filename 269 line = posn.Line 270 ok = true 271 } 272 return tuple{pc, file, line, ok} 273 } 274 275 func ext۰runtime۰Callers(fr *frame, args []value) value { 276 // Callers(skip int, pc []uintptr) int 277 skip := args[0].(int) 278 pc := args[1].([]value) 279 for i := 0; i < skip; i++ { 280 if fr != nil { 281 fr = fr.caller 282 } 283 } 284 i := 0 285 for fr != nil && i < len(pc) { 286 pc[i] = uintptr(unsafe.Pointer(fr.fn)) 287 i++ 288 fr = fr.caller 289 } 290 return i 291 } 292 293 func ext۰runtime۰FuncForPC(fr *frame, args []value) value { 294 // FuncForPC(pc uintptr) *Func 295 pc := args[0].(uintptr) 296 var fn *ssa.Function 297 if pc != 0 { 298 fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe! 299 } 300 var Func value 301 Func = structure{fn} // a runtime.Func 302 return &Func 303 } 304 305 func ext۰runtime۰environ(fr *frame, args []value) value { 306 // This function also implements syscall.runtime_envs. 307 return environ 308 } 309 310 func ext۰runtime۰getgoroot(fr *frame, args []value) value { 311 return os.Getenv("GOROOT") 312 } 313 314 func ext۰strings۰Count(fr *frame, args []value) value { 315 // Call compiled version to avoid asm dependency. 316 return strings.Count(args[0].(string), args[1].(string)) 317 } 318 319 func ext۰strings۰IndexByte(fr *frame, args []value) value { 320 // Call compiled version to avoid asm dependency. 321 return strings.IndexByte(args[0].(string), args[1].(byte)) 322 } 323 324 func ext۰strings۰Index(fr *frame, args []value) value { 325 // Call compiled version to avoid asm dependency. 326 return strings.Index(args[0].(string), args[1].(string)) 327 } 328 329 func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value { 330 // Ignore args[0]; don't let the interpreted program 331 // set the interpreter's GOMAXPROCS! 332 return runtime.GOMAXPROCS(0) 333 } 334 335 func ext۰runtime۰Goexit(fr *frame, args []value) value { 336 // TODO(adonovan): don't kill the interpreter's main goroutine. 337 runtime.Goexit() 338 return nil 339 } 340 341 func ext۰runtime۰GC(fr *frame, args []value) value { 342 runtime.GC() 343 return nil 344 } 345 346 func ext۰runtime۰Gosched(fr *frame, args []value) value { 347 runtime.Gosched() 348 return nil 349 } 350 351 func ext۰runtime۰NumCPU(fr *frame, args []value) value { 352 return runtime.NumCPU() 353 } 354 355 func ext۰runtime۰NumGoroutine(fr *frame, args []value) value { 356 return int(atomic.LoadInt32(&fr.i.goroutines)) 357 } 358 359 func ext۰runtime۰ReadMemStats(fr *frame, args []value) value { 360 // TODO(adonovan): populate args[0].(Struct) 361 return nil 362 } 363 364 func ext۰atomic۰LoadUint32(fr *frame, args []value) value { 365 // TODO(adonovan): fix: not atomic! 366 return (*args[0].(*value)).(uint32) 367 } 368 369 func ext۰atomic۰StoreUint32(fr *frame, args []value) value { 370 // TODO(adonovan): fix: not atomic! 371 *args[0].(*value) = args[1].(uint32) 372 return nil 373 } 374 375 func ext۰atomic۰LoadInt32(fr *frame, args []value) value { 376 // TODO(adonovan): fix: not atomic! 377 return (*args[0].(*value)).(int32) 378 } 379 380 func ext۰atomic۰StoreInt32(fr *frame, args []value) value { 381 // TODO(adonovan): fix: not atomic! 382 *args[0].(*value) = args[1].(int32) 383 return nil 384 } 385 386 func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []value) value { 387 // TODO(adonovan): fix: not atomic! 388 p := args[0].(*value) 389 if (*p).(int32) == args[1].(int32) { 390 *p = args[2].(int32) 391 return true 392 } 393 return false 394 } 395 396 func ext۰atomic۰CompareAndSwapUint32(fr *frame, args []value) value { 397 // TODO(adonovan): fix: not atomic! 398 p := args[0].(*value) 399 if (*p).(uint32) == args[1].(uint32) { 400 *p = args[2].(uint32) 401 return true 402 } 403 return false 404 } 405 406 func ext۰atomic۰AddInt32(fr *frame, args []value) value { 407 // TODO(adonovan): fix: not atomic! 408 p := args[0].(*value) 409 newv := (*p).(int32) + args[1].(int32) 410 *p = newv 411 return newv 412 } 413 414 func ext۰atomic۰AddUint32(fr *frame, args []value) value { 415 // TODO(adonovan): fix: not atomic! 416 p := args[0].(*value) 417 newv := (*p).(uint32) + args[1].(uint32) 418 *p = newv 419 return newv 420 } 421 422 func ext۰atomic۰LoadUint64(fr *frame, args []value) value { 423 // TODO(adonovan): fix: not atomic! 424 return (*args[0].(*value)).(uint64) 425 } 426 427 func ext۰atomic۰StoreUint64(fr *frame, args []value) value { 428 // TODO(adonovan): fix: not atomic! 429 *args[0].(*value) = args[1].(uint64) 430 return nil 431 } 432 433 func ext۰atomic۰LoadInt64(fr *frame, args []value) value { 434 // TODO(adonovan): fix: not atomic! 435 return (*args[0].(*value)).(int64) 436 } 437 438 func ext۰atomic۰StoreInt64(fr *frame, args []value) value { 439 // TODO(adonovan): fix: not atomic! 440 *args[0].(*value) = args[1].(int64) 441 return nil 442 } 443 444 func ext۰atomic۰CompareAndSwapInt64(fr *frame, args []value) value { 445 // TODO(adonovan): fix: not atomic! 446 p := args[0].(*value) 447 if (*p).(int64) == args[1].(int64) { 448 *p = args[2].(int64) 449 return true 450 } 451 return false 452 } 453 454 func ext۰atomic۰CompareAndSwapUint64(fr *frame, args []value) value { 455 // TODO(adonovan): fix: not atomic! 456 p := args[0].(*value) 457 if (*p).(uint64) == args[1].(uint64) { 458 *p = args[2].(uint64) 459 return true 460 } 461 return false 462 } 463 464 func ext۰atomic۰AddInt64(fr *frame, args []value) value { 465 // TODO(adonovan): fix: not atomic! 466 p := args[0].(*value) 467 newv := (*p).(int64) + args[1].(int64) 468 *p = newv 469 return newv 470 } 471 472 func ext۰atomic۰AddUint64(fr *frame, args []value) value { 473 // TODO(adonovan): fix: not atomic! 474 p := args[0].(*value) 475 newv := (*p).(uint64) + args[1].(uint64) 476 *p = newv 477 return newv 478 } 479 480 func ext۰cpu۰cpuid(fr *frame, args []value) value { 481 return tuple{uint32(0), uint32(0), uint32(0), uint32(0)} 482 } 483 484 // Pretend: type runtime.Func struct { entry *ssa.Function } 485 486 func ext۰runtime۰Func۰FileLine(fr *frame, args []value) value { 487 // func (*runtime.Func) FileLine(uintptr) (string, int) 488 f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function) 489 pc := args[1].(uintptr) 490 _ = pc 491 if f != nil { 492 // TODO(adonovan): use position of current instruction, not fn. 493 posn := f.Prog.Fset.Position(f.Pos()) 494 return tuple{posn.Filename, posn.Line} 495 } 496 return tuple{"", 0} 497 } 498 499 func ext۰runtime۰Func۰Name(fr *frame, args []value) value { 500 // func (*runtime.Func) Name() string 501 f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function) 502 if f != nil { 503 return f.String() 504 } 505 return "" 506 } 507 508 func ext۰runtime۰Func۰Entry(fr *frame, args []value) value { 509 // func (*runtime.Func) Entry() uintptr 510 f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function) 511 return uintptr(unsafe.Pointer(f)) 512 } 513 514 // This is a workaround for a bug in go/ssa/testmain.go: it creates 515 // InternalExamples even for Example functions with no Output comment. 516 // TODO(adonovan): fix (and redesign) testmain.go.. 517 func ext۰testing۰runExample(fr *frame, args []value) value { 518 // This is a stripped down runExample that simply calls the function. 519 // It does not capture and compare output nor recover from panic. 520 // 521 // func runExample(eg testing.InternalExample) bool { 522 // eg.F() 523 // return true 524 // } 525 F := args[0].(structure)[1] 526 call(fr.i, fr, 0, F, nil) 527 return true 528 } 529 530 func ext۰testing۰callerEntry(fr *frame, args []value) value { 531 return uintptr(0) // bogus implementation for now 532 } 533 534 func ext۰time۰now(fr *frame, args []value) value { 535 nano := time.Now().UnixNano() 536 return tuple{int64(nano / 1e9), int32(nano % 1e9), int64(0)} 537 } 538 539 func ext۰time۰Sleep(fr *frame, args []value) value { 540 time.Sleep(time.Duration(args[0].(int64))) 541 return nil 542 } 543 544 func valueToBytes(v value) []byte { 545 in := v.([]value) 546 b := make([]byte, len(in)) 547 for i := range in { 548 b[i] = in[i].(byte) 549 } 550 return b 551 }