github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/pointer/reflect.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 file implements the generation and resolution rules for 10 // constraints arising from the use of reflection in the target 11 // program. See doc.go for explanation of the representation. 12 // 13 // For consistency, the names of all parameters match those of the 14 // actual functions in the "reflect" package. 15 // 16 // To avoid proliferation of equivalent labels, intrinsics should 17 // memoize as much as possible, like TypeOf and Zero do for their 18 // tagged objects. 19 // 20 // TODO(adonovan): this file is rather subtle. Explain how we derive 21 // the implementation of each reflect operator from its spec, 22 // including the subtleties of reflect.flag{Addr,RO,Indir}. 23 // [Hint: our implementation is as if reflect.flagIndir was always 24 // true, i.e. reflect.Values are pointers to tagged objects, there is 25 // no inline allocation optimization; and indirect tagged objects (not 26 // yet implemented) correspond to reflect.Values with 27 // reflect.flagAddr.] 28 // A picture would help too. 29 // 30 // TODO(adonovan): try factoring up the common parts of the majority of 31 // these constraints that are single input, single output. 32 33 import ( 34 "fmt" 35 exact "go/constant" 36 "go/types" 37 "reflect" 38 39 "golang.org/x/tools/go/ssa" 40 ) 41 42 func init() { 43 for name, fn := range map[string]intrinsic{ 44 // reflect.Value methods. 45 "(reflect.Value).Addr": ext۰reflect۰Value۰Addr, 46 "(reflect.Value).Bool": ext۰NoEffect, 47 "(reflect.Value).Bytes": ext۰reflect۰Value۰Bytes, 48 "(reflect.Value).Call": ext۰reflect۰Value۰Call, 49 "(reflect.Value).CallSlice": ext۰reflect۰Value۰CallSlice, 50 "(reflect.Value).CanAddr": ext۰NoEffect, 51 "(reflect.Value).CanInterface": ext۰NoEffect, 52 "(reflect.Value).CanSet": ext۰NoEffect, 53 "(reflect.Value).Cap": ext۰NoEffect, 54 "(reflect.Value).Close": ext۰NoEffect, 55 "(reflect.Value).Complex": ext۰NoEffect, 56 "(reflect.Value).Convert": ext۰reflect۰Value۰Convert, 57 "(reflect.Value).Elem": ext۰reflect۰Value۰Elem, 58 "(reflect.Value).Field": ext۰reflect۰Value۰Field, 59 "(reflect.Value).FieldByIndex": ext۰reflect۰Value۰FieldByIndex, 60 "(reflect.Value).FieldByName": ext۰reflect۰Value۰FieldByName, 61 "(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc, 62 "(reflect.Value).Float": ext۰NoEffect, 63 "(reflect.Value).Index": ext۰reflect۰Value۰Index, 64 "(reflect.Value).Int": ext۰NoEffect, 65 "(reflect.Value).Interface": ext۰reflect۰Value۰Interface, 66 "(reflect.Value).InterfaceData": ext۰NoEffect, 67 "(reflect.Value).IsNil": ext۰NoEffect, 68 "(reflect.Value).IsValid": ext۰NoEffect, 69 "(reflect.Value).Kind": ext۰NoEffect, 70 "(reflect.Value).Len": ext۰NoEffect, 71 "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex, 72 "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys, 73 "(reflect.Value).Method": ext۰reflect۰Value۰Method, 74 "(reflect.Value).MethodByName": ext۰reflect۰Value۰MethodByName, 75 "(reflect.Value).NumField": ext۰NoEffect, 76 "(reflect.Value).NumMethod": ext۰NoEffect, 77 "(reflect.Value).OverflowComplex": ext۰NoEffect, 78 "(reflect.Value).OverflowFloat": ext۰NoEffect, 79 "(reflect.Value).OverflowInt": ext۰NoEffect, 80 "(reflect.Value).OverflowUint": ext۰NoEffect, 81 "(reflect.Value).Pointer": ext۰NoEffect, 82 "(reflect.Value).Recv": ext۰reflect۰Value۰Recv, 83 "(reflect.Value).Send": ext۰reflect۰Value۰Send, 84 "(reflect.Value).Set": ext۰reflect۰Value۰Set, 85 "(reflect.Value).SetBool": ext۰NoEffect, 86 "(reflect.Value).SetBytes": ext۰reflect۰Value۰SetBytes, 87 "(reflect.Value).SetComplex": ext۰NoEffect, 88 "(reflect.Value).SetFloat": ext۰NoEffect, 89 "(reflect.Value).SetInt": ext۰NoEffect, 90 "(reflect.Value).SetLen": ext۰NoEffect, 91 "(reflect.Value).SetMapIndex": ext۰reflect۰Value۰SetMapIndex, 92 "(reflect.Value).SetPointer": ext۰reflect۰Value۰SetPointer, 93 "(reflect.Value).SetString": ext۰NoEffect, 94 "(reflect.Value).SetUint": ext۰NoEffect, 95 "(reflect.Value).Slice": ext۰reflect۰Value۰Slice, 96 "(reflect.Value).String": ext۰NoEffect, 97 "(reflect.Value).TryRecv": ext۰reflect۰Value۰Recv, 98 "(reflect.Value).TrySend": ext۰reflect۰Value۰Send, 99 "(reflect.Value).Type": ext۰NoEffect, 100 "(reflect.Value).Uint": ext۰NoEffect, 101 "(reflect.Value).UnsafeAddr": ext۰NoEffect, 102 103 // Standalone reflect.* functions. 104 "reflect.Append": ext۰reflect۰Append, 105 "reflect.AppendSlice": ext۰reflect۰AppendSlice, 106 "reflect.Copy": ext۰reflect۰Copy, 107 "reflect.ChanOf": ext۰reflect۰ChanOf, 108 "reflect.DeepEqual": ext۰NoEffect, 109 "reflect.Indirect": ext۰reflect۰Indirect, 110 "reflect.MakeChan": ext۰reflect۰MakeChan, 111 "reflect.MakeFunc": ext۰reflect۰MakeFunc, 112 "reflect.MakeMap": ext۰reflect۰MakeMap, 113 "reflect.MakeSlice": ext۰reflect۰MakeSlice, 114 "reflect.MapOf": ext۰reflect۰MapOf, 115 "reflect.New": ext۰reflect۰New, 116 "reflect.NewAt": ext۰reflect۰NewAt, 117 "reflect.PtrTo": ext۰reflect۰PtrTo, 118 "reflect.Select": ext۰reflect۰Select, 119 "reflect.SliceOf": ext۰reflect۰SliceOf, 120 "reflect.TypeOf": ext۰reflect۰TypeOf, 121 "reflect.ValueOf": ext۰reflect۰ValueOf, 122 "reflect.Zero": ext۰reflect۰Zero, 123 "reflect.init": ext۰NoEffect, 124 125 // *reflect.rtype methods 126 "(*reflect.rtype).Align": ext۰NoEffect, 127 "(*reflect.rtype).AssignableTo": ext۰NoEffect, 128 "(*reflect.rtype).Bits": ext۰NoEffect, 129 "(*reflect.rtype).ChanDir": ext۰NoEffect, 130 "(*reflect.rtype).ConvertibleTo": ext۰NoEffect, 131 "(*reflect.rtype).Elem": ext۰reflect۰rtype۰Elem, 132 "(*reflect.rtype).Field": ext۰reflect۰rtype۰Field, 133 "(*reflect.rtype).FieldAlign": ext۰NoEffect, 134 "(*reflect.rtype).FieldByIndex": ext۰reflect۰rtype۰FieldByIndex, 135 "(*reflect.rtype).FieldByName": ext۰reflect۰rtype۰FieldByName, 136 "(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc, 137 "(*reflect.rtype).Implements": ext۰NoEffect, 138 "(*reflect.rtype).In": ext۰reflect۰rtype۰In, 139 "(*reflect.rtype).IsVariadic": ext۰NoEffect, 140 "(*reflect.rtype).Key": ext۰reflect۰rtype۰Key, 141 "(*reflect.rtype).Kind": ext۰NoEffect, 142 "(*reflect.rtype).Len": ext۰NoEffect, 143 "(*reflect.rtype).Method": ext۰reflect۰rtype۰Method, 144 "(*reflect.rtype).MethodByName": ext۰reflect۰rtype۰MethodByName, 145 "(*reflect.rtype).Name": ext۰NoEffect, 146 "(*reflect.rtype).NumField": ext۰NoEffect, 147 "(*reflect.rtype).NumIn": ext۰NoEffect, 148 "(*reflect.rtype).NumMethod": ext۰NoEffect, 149 "(*reflect.rtype).NumOut": ext۰NoEffect, 150 "(*reflect.rtype).Out": ext۰reflect۰rtype۰Out, 151 "(*reflect.rtype).PkgPath": ext۰NoEffect, 152 "(*reflect.rtype).Size": ext۰NoEffect, 153 "(*reflect.rtype).String": ext۰NoEffect, 154 } { 155 intrinsicsByName[name] = fn 156 } 157 } 158 159 // -------------------- (reflect.Value) -------------------- 160 161 func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {} // TODO(adonovan) 162 163 // ---------- func (Value).Bytes() Value ---------- 164 165 // result = v.Bytes() 166 type rVBytesConstraint struct { 167 v nodeid // (ptr) 168 result nodeid // (indirect) 169 } 170 171 func (c *rVBytesConstraint) ptr() nodeid { return c.v } 172 func (c *rVBytesConstraint) presolve(h *hvn) { 173 h.markIndirect(onodeid(c.result), "rVBytes.result") 174 } 175 func (c *rVBytesConstraint) renumber(mapping []nodeid) { 176 c.v = mapping[c.v] 177 c.result = mapping[c.result] 178 } 179 180 func (c *rVBytesConstraint) String() string { 181 return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v) 182 } 183 184 func (c *rVBytesConstraint) solve(a *analysis, delta *nodeset) { 185 changed := false 186 for _, x := range delta.AppendTo(a.deltaSpace) { 187 vObj := nodeid(x) 188 tDyn, slice, indirect := a.taggedValue(vObj) 189 if indirect { 190 // TODO(adonovan): we'll need to implement this 191 // when we start creating indirect tagged objects. 192 panic("indirect tagged object") 193 } 194 195 tSlice, ok := tDyn.Underlying().(*types.Slice) 196 if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) { 197 if a.onlineCopy(c.result, slice) { 198 changed = true 199 } 200 } 201 } 202 if changed { 203 a.addWork(c.result) 204 } 205 } 206 207 func ext۰reflect۰Value۰Bytes(a *analysis, cgn *cgnode) { 208 a.addConstraint(&rVBytesConstraint{ 209 v: a.funcParams(cgn.obj), 210 result: a.funcResults(cgn.obj), 211 }) 212 } 213 214 // ---------- func (Value).Call(in []Value) []Value ---------- 215 216 // result = v.Call(in) 217 type rVCallConstraint struct { 218 cgn *cgnode 219 targets nodeid // (indirect) 220 v nodeid // (ptr) 221 arg nodeid // = in[*] 222 result nodeid // (indirect) 223 dotdotdot bool // interpret last arg as a "..." slice 224 } 225 226 func (c *rVCallConstraint) ptr() nodeid { return c.v } 227 func (c *rVCallConstraint) presolve(h *hvn) { 228 h.markIndirect(onodeid(c.targets), "rVCall.targets") 229 h.markIndirect(onodeid(c.result), "rVCall.result") 230 } 231 func (c *rVCallConstraint) renumber(mapping []nodeid) { 232 c.targets = mapping[c.targets] 233 c.v = mapping[c.v] 234 c.arg = mapping[c.arg] 235 c.result = mapping[c.result] 236 } 237 238 func (c *rVCallConstraint) String() string { 239 return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg) 240 } 241 242 func (c *rVCallConstraint) solve(a *analysis, delta *nodeset) { 243 if c.targets == 0 { 244 panic("no targets") 245 } 246 247 changed := false 248 for _, x := range delta.AppendTo(a.deltaSpace) { 249 vObj := nodeid(x) 250 tDyn, fn, indirect := a.taggedValue(vObj) 251 if indirect { 252 // TODO(adonovan): we'll need to implement this 253 // when we start creating indirect tagged objects. 254 panic("indirect tagged object") 255 } 256 257 tSig, ok := tDyn.Underlying().(*types.Signature) 258 if !ok { 259 continue // not a function 260 } 261 if tSig.Recv() != nil { 262 panic(tSig) // TODO(adonovan): rethink when we implement Method() 263 } 264 265 // Add dynamic call target. 266 if a.onlineCopy(c.targets, fn) { 267 a.addWork(c.targets) 268 // TODO(adonovan): is 'else continue' a sound optimisation here? 269 } 270 271 // Allocate a P/R block. 272 tParams := tSig.Params() 273 tResults := tSig.Results() 274 params := a.addNodes(tParams, "rVCall.params") 275 results := a.addNodes(tResults, "rVCall.results") 276 277 // Make a dynamic call to 'fn'. 278 a.store(fn, params, 1, a.sizeof(tParams)) 279 a.load(results, fn, 1+a.sizeof(tParams), a.sizeof(tResults)) 280 281 // Populate P by type-asserting each actual arg (all merged in c.arg). 282 for i, n := 0, tParams.Len(); i < n; i++ { 283 T := tParams.At(i).Type() 284 a.typeAssert(T, params, c.arg, false) 285 params += nodeid(a.sizeof(T)) 286 } 287 288 // Use R by tagging and copying each actual result to c.result. 289 for i, n := 0, tResults.Len(); i < n; i++ { 290 T := tResults.At(i).Type() 291 // Convert from an arbitrary type to a reflect.Value 292 // (like MakeInterface followed by reflect.ValueOf). 293 if isInterface(T) { 294 // (don't tag) 295 if a.onlineCopy(c.result, results) { 296 changed = true 297 } 298 } else { 299 obj := a.makeTagged(T, c.cgn, nil) 300 a.onlineCopyN(obj+1, results, a.sizeof(T)) 301 if a.addLabel(c.result, obj) { // (true) 302 changed = true 303 } 304 } 305 results += nodeid(a.sizeof(T)) 306 } 307 } 308 if changed { 309 a.addWork(c.result) 310 } 311 } 312 313 // Common code for direct (inlined) and indirect calls to (reflect.Value).Call. 314 func reflectCallImpl(a *analysis, cgn *cgnode, site *callsite, recv, arg nodeid, dotdotdot bool) nodeid { 315 // Allocate []reflect.Value array for the result. 316 ret := a.nextNode() 317 a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "rVCall.ret") 318 a.endObject(ret, cgn, nil) 319 320 // pts(targets) will be the set of possible call targets. 321 site.targets = a.addOneNode(tInvalid, "rvCall.targets", nil) 322 323 // All arguments are merged since they arrive in a slice. 324 argelts := a.addOneNode(a.reflectValueObj.Type(), "rVCall.args", nil) 325 a.load(argelts, arg, 1, 1) // slice elements 326 327 a.addConstraint(&rVCallConstraint{ 328 cgn: cgn, 329 targets: site.targets, 330 v: recv, 331 arg: argelts, 332 result: ret + 1, // results go into elements of ret 333 dotdotdot: dotdotdot, 334 }) 335 return ret 336 } 337 338 func reflectCall(a *analysis, cgn *cgnode, dotdotdot bool) { 339 // This is the shared contour implementation of (reflect.Value).Call 340 // and CallSlice, as used by indirect calls (rare). 341 // Direct calls are inlined in gen.go, eliding the 342 // intermediate cgnode for Call. 343 site := new(callsite) 344 cgn.sites = append(cgn.sites, site) 345 recv := a.funcParams(cgn.obj) 346 arg := recv + 1 347 ret := reflectCallImpl(a, cgn, site, recv, arg, dotdotdot) 348 a.addressOf(cgn.fn.Signature.Results().At(0).Type(), a.funcResults(cgn.obj), ret) 349 } 350 351 func ext۰reflect۰Value۰Call(a *analysis, cgn *cgnode) { 352 reflectCall(a, cgn, false) 353 } 354 355 func ext۰reflect۰Value۰CallSlice(a *analysis, cgn *cgnode) { 356 // TODO(adonovan): implement. Also, inline direct calls in gen.go too. 357 if false { 358 reflectCall(a, cgn, true) 359 } 360 } 361 362 func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {} // TODO(adonovan) 363 364 // ---------- func (Value).Elem() Value ---------- 365 366 // result = v.Elem() 367 type rVElemConstraint struct { 368 cgn *cgnode 369 v nodeid // (ptr) 370 result nodeid // (indirect) 371 } 372 373 func (c *rVElemConstraint) ptr() nodeid { return c.v } 374 func (c *rVElemConstraint) presolve(h *hvn) { 375 h.markIndirect(onodeid(c.result), "rVElem.result") 376 } 377 func (c *rVElemConstraint) renumber(mapping []nodeid) { 378 c.v = mapping[c.v] 379 c.result = mapping[c.result] 380 } 381 382 func (c *rVElemConstraint) String() string { 383 return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v) 384 } 385 386 func (c *rVElemConstraint) solve(a *analysis, delta *nodeset) { 387 changed := false 388 for _, x := range delta.AppendTo(a.deltaSpace) { 389 vObj := nodeid(x) 390 tDyn, payload, indirect := a.taggedValue(vObj) 391 if indirect { 392 // TODO(adonovan): we'll need to implement this 393 // when we start creating indirect tagged objects. 394 panic("indirect tagged object") 395 } 396 397 switch t := tDyn.Underlying().(type) { 398 case *types.Interface: 399 if a.onlineCopy(c.result, payload) { 400 changed = true 401 } 402 403 case *types.Pointer: 404 obj := a.makeTagged(t.Elem(), c.cgn, nil) 405 a.load(obj+1, payload, 0, a.sizeof(t.Elem())) 406 if a.addLabel(c.result, obj) { 407 changed = true 408 } 409 } 410 } 411 if changed { 412 a.addWork(c.result) 413 } 414 } 415 416 func ext۰reflect۰Value۰Elem(a *analysis, cgn *cgnode) { 417 a.addConstraint(&rVElemConstraint{ 418 cgn: cgn, 419 v: a.funcParams(cgn.obj), 420 result: a.funcResults(cgn.obj), 421 }) 422 } 423 424 func ext۰reflect۰Value۰Field(a *analysis, cgn *cgnode) {} // TODO(adonovan) 425 func ext۰reflect۰Value۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan) 426 func ext۰reflect۰Value۰FieldByName(a *analysis, cgn *cgnode) {} // TODO(adonovan) 427 func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan) 428 429 // ---------- func (Value).Index() Value ---------- 430 431 // result = v.Index() 432 type rVIndexConstraint struct { 433 cgn *cgnode 434 v nodeid // (ptr) 435 result nodeid // (indirect) 436 } 437 438 func (c *rVIndexConstraint) ptr() nodeid { return c.v } 439 func (c *rVIndexConstraint) presolve(h *hvn) { 440 h.markIndirect(onodeid(c.result), "rVIndex.result") 441 } 442 func (c *rVIndexConstraint) renumber(mapping []nodeid) { 443 c.v = mapping[c.v] 444 c.result = mapping[c.result] 445 } 446 447 func (c *rVIndexConstraint) String() string { 448 return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v) 449 } 450 451 func (c *rVIndexConstraint) solve(a *analysis, delta *nodeset) { 452 changed := false 453 for _, x := range delta.AppendTo(a.deltaSpace) { 454 vObj := nodeid(x) 455 tDyn, payload, indirect := a.taggedValue(vObj) 456 if indirect { 457 // TODO(adonovan): we'll need to implement this 458 // when we start creating indirect tagged objects. 459 panic("indirect tagged object") 460 } 461 462 var res nodeid 463 switch t := tDyn.Underlying().(type) { 464 case *types.Array: 465 res = a.makeTagged(t.Elem(), c.cgn, nil) 466 a.onlineCopyN(res+1, payload+1, a.sizeof(t.Elem())) 467 468 case *types.Slice: 469 res = a.makeTagged(t.Elem(), c.cgn, nil) 470 a.load(res+1, payload, 1, a.sizeof(t.Elem())) 471 472 case *types.Basic: 473 if t.Kind() == types.String { 474 res = a.makeTagged(types.Typ[types.Rune], c.cgn, nil) 475 } 476 } 477 if res != 0 && a.addLabel(c.result, res) { 478 changed = true 479 } 480 } 481 if changed { 482 a.addWork(c.result) 483 } 484 } 485 486 func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) { 487 a.addConstraint(&rVIndexConstraint{ 488 cgn: cgn, 489 v: a.funcParams(cgn.obj), 490 result: a.funcResults(cgn.obj), 491 }) 492 } 493 494 // ---------- func (Value).Interface() Value ---------- 495 496 // result = v.Interface() 497 type rVInterfaceConstraint struct { 498 v nodeid // (ptr) 499 result nodeid // (indirect) 500 } 501 502 func (c *rVInterfaceConstraint) ptr() nodeid { return c.v } 503 func (c *rVInterfaceConstraint) presolve(h *hvn) { 504 h.markIndirect(onodeid(c.result), "rVInterface.result") 505 } 506 func (c *rVInterfaceConstraint) renumber(mapping []nodeid) { 507 c.v = mapping[c.v] 508 c.result = mapping[c.result] 509 } 510 511 func (c *rVInterfaceConstraint) String() string { 512 return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v) 513 } 514 515 func (c *rVInterfaceConstraint) solve(a *analysis, delta *nodeset) { 516 changed := false 517 for _, x := range delta.AppendTo(a.deltaSpace) { 518 vObj := nodeid(x) 519 tDyn, payload, indirect := a.taggedValue(vObj) 520 if indirect { 521 // TODO(adonovan): we'll need to implement this 522 // when we start creating indirect tagged objects. 523 panic("indirect tagged object") 524 } 525 526 if isInterface(tDyn) { 527 if a.onlineCopy(c.result, payload) { 528 a.addWork(c.result) 529 } 530 } else { 531 if a.addLabel(c.result, vObj) { 532 changed = true 533 } 534 } 535 } 536 if changed { 537 a.addWork(c.result) 538 } 539 } 540 541 func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) { 542 a.addConstraint(&rVInterfaceConstraint{ 543 v: a.funcParams(cgn.obj), 544 result: a.funcResults(cgn.obj), 545 }) 546 } 547 548 // ---------- func (Value).MapIndex(Value) Value ---------- 549 550 // result = v.MapIndex(_) 551 type rVMapIndexConstraint struct { 552 cgn *cgnode 553 v nodeid // (ptr) 554 result nodeid // (indirect) 555 } 556 557 func (c *rVMapIndexConstraint) ptr() nodeid { return c.v } 558 func (c *rVMapIndexConstraint) presolve(h *hvn) { 559 h.markIndirect(onodeid(c.result), "rVMapIndex.result") 560 } 561 func (c *rVMapIndexConstraint) renumber(mapping []nodeid) { 562 c.v = mapping[c.v] 563 c.result = mapping[c.result] 564 } 565 566 func (c *rVMapIndexConstraint) String() string { 567 return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v) 568 } 569 570 func (c *rVMapIndexConstraint) solve(a *analysis, delta *nodeset) { 571 changed := false 572 for _, x := range delta.AppendTo(a.deltaSpace) { 573 vObj := nodeid(x) 574 tDyn, m, indirect := a.taggedValue(vObj) 575 tMap, _ := tDyn.Underlying().(*types.Map) 576 if tMap == nil { 577 continue // not a map 578 } 579 if indirect { 580 // TODO(adonovan): we'll need to implement this 581 // when we start creating indirect tagged objects. 582 panic("indirect tagged object") 583 } 584 585 obj := a.makeTagged(tMap.Elem(), c.cgn, nil) 586 a.load(obj+1, m, a.sizeof(tMap.Key()), a.sizeof(tMap.Elem())) 587 if a.addLabel(c.result, obj) { 588 changed = true 589 } 590 } 591 if changed { 592 a.addWork(c.result) 593 } 594 } 595 596 func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) { 597 a.addConstraint(&rVMapIndexConstraint{ 598 cgn: cgn, 599 v: a.funcParams(cgn.obj), 600 result: a.funcResults(cgn.obj), 601 }) 602 } 603 604 // ---------- func (Value).MapKeys() []Value ---------- 605 606 // result = v.MapKeys() 607 type rVMapKeysConstraint struct { 608 cgn *cgnode 609 v nodeid // (ptr) 610 result nodeid // (indirect) 611 } 612 613 func (c *rVMapKeysConstraint) ptr() nodeid { return c.v } 614 func (c *rVMapKeysConstraint) presolve(h *hvn) { 615 h.markIndirect(onodeid(c.result), "rVMapKeys.result") 616 } 617 func (c *rVMapKeysConstraint) renumber(mapping []nodeid) { 618 c.v = mapping[c.v] 619 c.result = mapping[c.result] 620 } 621 622 func (c *rVMapKeysConstraint) String() string { 623 return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v) 624 } 625 626 func (c *rVMapKeysConstraint) solve(a *analysis, delta *nodeset) { 627 changed := false 628 for _, x := range delta.AppendTo(a.deltaSpace) { 629 vObj := nodeid(x) 630 tDyn, m, indirect := a.taggedValue(vObj) 631 tMap, _ := tDyn.Underlying().(*types.Map) 632 if tMap == nil { 633 continue // not a map 634 } 635 if indirect { 636 // TODO(adonovan): we'll need to implement this 637 // when we start creating indirect tagged objects. 638 panic("indirect tagged object") 639 } 640 641 kObj := a.makeTagged(tMap.Key(), c.cgn, nil) 642 a.load(kObj+1, m, 0, a.sizeof(tMap.Key())) 643 if a.addLabel(c.result, kObj) { 644 changed = true 645 } 646 } 647 if changed { 648 a.addWork(c.result) 649 } 650 } 651 652 func ext۰reflect۰Value۰MapKeys(a *analysis, cgn *cgnode) { 653 // Allocate an array for the result. 654 obj := a.nextNode() 655 T := types.NewSlice(a.reflectValueObj.Type()) 656 a.addNodes(sliceToArray(T), "reflect.MapKeys result") 657 a.endObject(obj, cgn, nil) 658 a.addressOf(T, a.funcResults(cgn.obj), obj) 659 660 a.addConstraint(&rVMapKeysConstraint{ 661 cgn: cgn, 662 v: a.funcParams(cgn.obj), 663 result: obj + 1, // result is stored in array elems 664 }) 665 } 666 667 func ext۰reflect۰Value۰Method(a *analysis, cgn *cgnode) {} // TODO(adonovan) 668 func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {} // TODO(adonovan) 669 670 // ---------- func (Value).Recv(Value) Value ---------- 671 672 // result, _ = v.Recv() 673 type rVRecvConstraint struct { 674 cgn *cgnode 675 v nodeid // (ptr) 676 result nodeid // (indirect) 677 } 678 679 func (c *rVRecvConstraint) ptr() nodeid { return c.v } 680 func (c *rVRecvConstraint) presolve(h *hvn) { 681 h.markIndirect(onodeid(c.result), "rVRecv.result") 682 } 683 func (c *rVRecvConstraint) renumber(mapping []nodeid) { 684 c.v = mapping[c.v] 685 c.result = mapping[c.result] 686 } 687 688 func (c *rVRecvConstraint) String() string { 689 return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v) 690 } 691 692 func (c *rVRecvConstraint) solve(a *analysis, delta *nodeset) { 693 changed := false 694 for _, x := range delta.AppendTo(a.deltaSpace) { 695 vObj := nodeid(x) 696 tDyn, ch, indirect := a.taggedValue(vObj) 697 tChan, _ := tDyn.Underlying().(*types.Chan) 698 if tChan == nil { 699 continue // not a channel 700 } 701 if indirect { 702 // TODO(adonovan): we'll need to implement this 703 // when we start creating indirect tagged objects. 704 panic("indirect tagged object") 705 } 706 707 tElem := tChan.Elem() 708 elemObj := a.makeTagged(tElem, c.cgn, nil) 709 a.load(elemObj+1, ch, 0, a.sizeof(tElem)) 710 if a.addLabel(c.result, elemObj) { 711 changed = true 712 } 713 } 714 if changed { 715 a.addWork(c.result) 716 } 717 } 718 719 func ext۰reflect۰Value۰Recv(a *analysis, cgn *cgnode) { 720 a.addConstraint(&rVRecvConstraint{ 721 cgn: cgn, 722 v: a.funcParams(cgn.obj), 723 result: a.funcResults(cgn.obj), 724 }) 725 } 726 727 // ---------- func (Value).Send(Value) ---------- 728 729 // v.Send(x) 730 type rVSendConstraint struct { 731 cgn *cgnode 732 v nodeid // (ptr) 733 x nodeid 734 } 735 736 func (c *rVSendConstraint) ptr() nodeid { return c.v } 737 func (c *rVSendConstraint) presolve(*hvn) {} 738 func (c *rVSendConstraint) renumber(mapping []nodeid) { 739 c.v = mapping[c.v] 740 c.x = mapping[c.x] 741 } 742 743 func (c *rVSendConstraint) String() string { 744 return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x) 745 } 746 747 func (c *rVSendConstraint) solve(a *analysis, delta *nodeset) { 748 for _, x := range delta.AppendTo(a.deltaSpace) { 749 vObj := nodeid(x) 750 tDyn, ch, indirect := a.taggedValue(vObj) 751 tChan, _ := tDyn.Underlying().(*types.Chan) 752 if tChan == nil { 753 continue // not a channel 754 } 755 if indirect { 756 // TODO(adonovan): we'll need to implement this 757 // when we start creating indirect tagged objects. 758 panic("indirect tagged object") 759 } 760 761 // Extract x's payload to xtmp, then store to channel. 762 tElem := tChan.Elem() 763 xtmp := a.addNodes(tElem, "Send.xtmp") 764 a.typeAssert(tElem, xtmp, c.x, false) 765 a.store(ch, xtmp, 0, a.sizeof(tElem)) 766 } 767 } 768 769 func ext۰reflect۰Value۰Send(a *analysis, cgn *cgnode) { 770 params := a.funcParams(cgn.obj) 771 a.addConstraint(&rVSendConstraint{ 772 cgn: cgn, 773 v: params, 774 x: params + 1, 775 }) 776 } 777 778 func ext۰reflect۰Value۰Set(a *analysis, cgn *cgnode) {} // TODO(adonovan) 779 780 // ---------- func (Value).SetBytes(x []byte) ---------- 781 782 // v.SetBytes(x) 783 type rVSetBytesConstraint struct { 784 cgn *cgnode 785 v nodeid // (ptr) 786 x nodeid 787 } 788 789 func (c *rVSetBytesConstraint) ptr() nodeid { return c.v } 790 func (c *rVSetBytesConstraint) presolve(*hvn) {} 791 func (c *rVSetBytesConstraint) renumber(mapping []nodeid) { 792 c.v = mapping[c.v] 793 c.x = mapping[c.x] 794 } 795 796 func (c *rVSetBytesConstraint) String() string { 797 return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x) 798 } 799 800 func (c *rVSetBytesConstraint) solve(a *analysis, delta *nodeset) { 801 for _, x := range delta.AppendTo(a.deltaSpace) { 802 vObj := nodeid(x) 803 tDyn, slice, indirect := a.taggedValue(vObj) 804 if indirect { 805 // TODO(adonovan): we'll need to implement this 806 // when we start creating indirect tagged objects. 807 panic("indirect tagged object") 808 } 809 810 tSlice, ok := tDyn.Underlying().(*types.Slice) 811 if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) { 812 if a.onlineCopy(slice, c.x) { 813 a.addWork(slice) 814 } 815 } 816 } 817 } 818 819 func ext۰reflect۰Value۰SetBytes(a *analysis, cgn *cgnode) { 820 params := a.funcParams(cgn.obj) 821 a.addConstraint(&rVSetBytesConstraint{ 822 cgn: cgn, 823 v: params, 824 x: params + 1, 825 }) 826 } 827 828 // ---------- func (Value).SetMapIndex(k Value, v Value) ---------- 829 830 // v.SetMapIndex(key, val) 831 type rVSetMapIndexConstraint struct { 832 cgn *cgnode 833 v nodeid // (ptr) 834 key nodeid 835 val nodeid 836 } 837 838 func (c *rVSetMapIndexConstraint) ptr() nodeid { return c.v } 839 func (c *rVSetMapIndexConstraint) presolve(*hvn) {} 840 func (c *rVSetMapIndexConstraint) renumber(mapping []nodeid) { 841 c.v = mapping[c.v] 842 c.key = mapping[c.key] 843 c.val = mapping[c.val] 844 } 845 846 func (c *rVSetMapIndexConstraint) String() string { 847 return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val) 848 } 849 850 func (c *rVSetMapIndexConstraint) solve(a *analysis, delta *nodeset) { 851 for _, x := range delta.AppendTo(a.deltaSpace) { 852 vObj := nodeid(x) 853 tDyn, m, indirect := a.taggedValue(vObj) 854 tMap, _ := tDyn.Underlying().(*types.Map) 855 if tMap == nil { 856 continue // not a map 857 } 858 if indirect { 859 // TODO(adonovan): we'll need to implement this 860 // when we start creating indirect tagged objects. 861 panic("indirect tagged object") 862 } 863 864 keysize := a.sizeof(tMap.Key()) 865 866 // Extract key's payload to keytmp, then store to map key. 867 keytmp := a.addNodes(tMap.Key(), "SetMapIndex.keytmp") 868 a.typeAssert(tMap.Key(), keytmp, c.key, false) 869 a.store(m, keytmp, 0, keysize) 870 871 // Extract val's payload to vtmp, then store to map value. 872 valtmp := a.addNodes(tMap.Elem(), "SetMapIndex.valtmp") 873 a.typeAssert(tMap.Elem(), valtmp, c.val, false) 874 a.store(m, valtmp, keysize, a.sizeof(tMap.Elem())) 875 } 876 } 877 878 func ext۰reflect۰Value۰SetMapIndex(a *analysis, cgn *cgnode) { 879 params := a.funcParams(cgn.obj) 880 a.addConstraint(&rVSetMapIndexConstraint{ 881 cgn: cgn, 882 v: params, 883 key: params + 1, 884 val: params + 2, 885 }) 886 } 887 888 func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {} // TODO(adonovan) 889 890 // ---------- func (Value).Slice(v Value, i, j int) Value ---------- 891 892 // result = v.Slice(_, _) 893 type rVSliceConstraint struct { 894 cgn *cgnode 895 v nodeid // (ptr) 896 result nodeid // (indirect) 897 } 898 899 func (c *rVSliceConstraint) ptr() nodeid { return c.v } 900 func (c *rVSliceConstraint) presolve(h *hvn) { 901 h.markIndirect(onodeid(c.result), "rVSlice.result") 902 } 903 func (c *rVSliceConstraint) renumber(mapping []nodeid) { 904 c.v = mapping[c.v] 905 c.result = mapping[c.result] 906 } 907 908 func (c *rVSliceConstraint) String() string { 909 return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v) 910 } 911 912 func (c *rVSliceConstraint) solve(a *analysis, delta *nodeset) { 913 changed := false 914 for _, x := range delta.AppendTo(a.deltaSpace) { 915 vObj := nodeid(x) 916 tDyn, payload, indirect := a.taggedValue(vObj) 917 if indirect { 918 // TODO(adonovan): we'll need to implement this 919 // when we start creating indirect tagged objects. 920 panic("indirect tagged object") 921 } 922 923 var res nodeid 924 switch t := tDyn.Underlying().(type) { 925 case *types.Pointer: 926 if tArr, ok := t.Elem().Underlying().(*types.Array); ok { 927 // pointer to array 928 res = a.makeTagged(types.NewSlice(tArr.Elem()), c.cgn, nil) 929 if a.onlineCopy(res+1, payload) { 930 a.addWork(res + 1) 931 } 932 } 933 934 case *types.Array: 935 // TODO(adonovan): implement addressable 936 // arrays when we do indirect tagged objects. 937 938 case *types.Slice: 939 res = vObj 940 941 case *types.Basic: 942 if t == types.Typ[types.String] { 943 res = vObj 944 } 945 } 946 947 if res != 0 && a.addLabel(c.result, res) { 948 changed = true 949 } 950 } 951 if changed { 952 a.addWork(c.result) 953 } 954 } 955 956 func ext۰reflect۰Value۰Slice(a *analysis, cgn *cgnode) { 957 a.addConstraint(&rVSliceConstraint{ 958 cgn: cgn, 959 v: a.funcParams(cgn.obj), 960 result: a.funcResults(cgn.obj), 961 }) 962 } 963 964 // -------------------- Standalone reflect functions -------------------- 965 966 func ext۰reflect۰Append(a *analysis, cgn *cgnode) {} // TODO(adonovan) 967 func ext۰reflect۰AppendSlice(a *analysis, cgn *cgnode) {} // TODO(adonovan) 968 func ext۰reflect۰Copy(a *analysis, cgn *cgnode) {} // TODO(adonovan) 969 970 // ---------- func ChanOf(ChanDir, Type) Type ---------- 971 972 // result = ChanOf(dir, t) 973 type reflectChanOfConstraint struct { 974 cgn *cgnode 975 t nodeid // (ptr) 976 result nodeid // (indirect) 977 dirs []types.ChanDir 978 } 979 980 func (c *reflectChanOfConstraint) ptr() nodeid { return c.t } 981 func (c *reflectChanOfConstraint) presolve(h *hvn) { 982 h.markIndirect(onodeid(c.result), "reflectChanOf.result") 983 } 984 func (c *reflectChanOfConstraint) renumber(mapping []nodeid) { 985 c.t = mapping[c.t] 986 c.result = mapping[c.result] 987 } 988 989 func (c *reflectChanOfConstraint) String() string { 990 return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t) 991 } 992 993 func (c *reflectChanOfConstraint) solve(a *analysis, delta *nodeset) { 994 changed := false 995 for _, x := range delta.AppendTo(a.deltaSpace) { 996 tObj := nodeid(x) 997 T := a.rtypeTaggedValue(tObj) 998 999 if typeTooHigh(T) { 1000 continue 1001 } 1002 1003 for _, dir := range c.dirs { 1004 if a.addLabel(c.result, a.makeRtype(types.NewChan(dir, T))) { 1005 changed = true 1006 } 1007 } 1008 } 1009 if changed { 1010 a.addWork(c.result) 1011 } 1012 } 1013 1014 // dirMap maps reflect.ChanDir to the set of channel types generated by ChanOf. 1015 var dirMap = [...][]types.ChanDir{ 1016 0: {types.SendOnly, types.RecvOnly, types.SendRecv}, // unknown 1017 reflect.RecvDir: {types.RecvOnly}, 1018 reflect.SendDir: {types.SendOnly}, 1019 reflect.BothDir: {types.SendRecv}, 1020 } 1021 1022 func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) { 1023 // If we have access to the callsite, 1024 // and the channel argument is a constant (as is usual), 1025 // only generate the requested direction. 1026 var dir reflect.ChanDir // unknown 1027 if site := cgn.callersite; site != nil { 1028 if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok { 1029 v, _ := exact.Int64Val(c.Value) 1030 if 0 <= v && v <= int64(reflect.BothDir) { 1031 dir = reflect.ChanDir(v) 1032 } 1033 } 1034 } 1035 1036 params := a.funcParams(cgn.obj) 1037 a.addConstraint(&reflectChanOfConstraint{ 1038 cgn: cgn, 1039 t: params + 1, 1040 result: a.funcResults(cgn.obj), 1041 dirs: dirMap[dir], 1042 }) 1043 } 1044 1045 // ---------- func Indirect(v Value) Value ---------- 1046 1047 // result = Indirect(v) 1048 type reflectIndirectConstraint struct { 1049 cgn *cgnode 1050 v nodeid // (ptr) 1051 result nodeid // (indirect) 1052 } 1053 1054 func (c *reflectIndirectConstraint) ptr() nodeid { return c.v } 1055 func (c *reflectIndirectConstraint) presolve(h *hvn) { 1056 h.markIndirect(onodeid(c.result), "reflectIndirect.result") 1057 } 1058 func (c *reflectIndirectConstraint) renumber(mapping []nodeid) { 1059 c.v = mapping[c.v] 1060 c.result = mapping[c.result] 1061 } 1062 1063 func (c *reflectIndirectConstraint) String() string { 1064 return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v) 1065 } 1066 1067 func (c *reflectIndirectConstraint) solve(a *analysis, delta *nodeset) { 1068 changed := false 1069 for _, x := range delta.AppendTo(a.deltaSpace) { 1070 vObj := nodeid(x) 1071 tDyn, _, _ := a.taggedValue(vObj) 1072 var res nodeid 1073 if tPtr, ok := tDyn.Underlying().(*types.Pointer); ok { 1074 // load the payload of the pointer's tagged object 1075 // into a new tagged object 1076 res = a.makeTagged(tPtr.Elem(), c.cgn, nil) 1077 a.load(res+1, vObj+1, 0, a.sizeof(tPtr.Elem())) 1078 } else { 1079 res = vObj 1080 } 1081 1082 if a.addLabel(c.result, res) { 1083 changed = true 1084 } 1085 } 1086 if changed { 1087 a.addWork(c.result) 1088 } 1089 } 1090 1091 func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) { 1092 a.addConstraint(&reflectIndirectConstraint{ 1093 cgn: cgn, 1094 v: a.funcParams(cgn.obj), 1095 result: a.funcResults(cgn.obj), 1096 }) 1097 } 1098 1099 // ---------- func MakeChan(Type) Value ---------- 1100 1101 // result = MakeChan(typ) 1102 type reflectMakeChanConstraint struct { 1103 cgn *cgnode 1104 typ nodeid // (ptr) 1105 result nodeid // (indirect) 1106 } 1107 1108 func (c *reflectMakeChanConstraint) ptr() nodeid { return c.typ } 1109 func (c *reflectMakeChanConstraint) presolve(h *hvn) { 1110 h.markIndirect(onodeid(c.result), "reflectMakeChan.result") 1111 } 1112 func (c *reflectMakeChanConstraint) renumber(mapping []nodeid) { 1113 c.typ = mapping[c.typ] 1114 c.result = mapping[c.result] 1115 } 1116 1117 func (c *reflectMakeChanConstraint) String() string { 1118 return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ) 1119 } 1120 1121 func (c *reflectMakeChanConstraint) solve(a *analysis, delta *nodeset) { 1122 changed := false 1123 for _, x := range delta.AppendTo(a.deltaSpace) { 1124 typObj := nodeid(x) 1125 T := a.rtypeTaggedValue(typObj) 1126 tChan, ok := T.Underlying().(*types.Chan) 1127 if !ok || tChan.Dir() != types.SendRecv { 1128 continue // not a bidirectional channel type 1129 } 1130 1131 obj := a.nextNode() 1132 a.addNodes(tChan.Elem(), "reflect.MakeChan.value") 1133 a.endObject(obj, c.cgn, nil) 1134 1135 // put its address in a new T-tagged object 1136 id := a.makeTagged(T, c.cgn, nil) 1137 a.addLabel(id+1, obj) 1138 1139 // flow the T-tagged object to the result 1140 if a.addLabel(c.result, id) { 1141 changed = true 1142 } 1143 } 1144 if changed { 1145 a.addWork(c.result) 1146 } 1147 } 1148 1149 func ext۰reflect۰MakeChan(a *analysis, cgn *cgnode) { 1150 a.addConstraint(&reflectMakeChanConstraint{ 1151 cgn: cgn, 1152 typ: a.funcParams(cgn.obj), 1153 result: a.funcResults(cgn.obj), 1154 }) 1155 } 1156 1157 func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan) 1158 1159 // ---------- func MakeMap(Type) Value ---------- 1160 1161 // result = MakeMap(typ) 1162 type reflectMakeMapConstraint struct { 1163 cgn *cgnode 1164 typ nodeid // (ptr) 1165 result nodeid // (indirect) 1166 } 1167 1168 func (c *reflectMakeMapConstraint) ptr() nodeid { return c.typ } 1169 func (c *reflectMakeMapConstraint) presolve(h *hvn) { 1170 h.markIndirect(onodeid(c.result), "reflectMakeMap.result") 1171 } 1172 func (c *reflectMakeMapConstraint) renumber(mapping []nodeid) { 1173 c.typ = mapping[c.typ] 1174 c.result = mapping[c.result] 1175 } 1176 1177 func (c *reflectMakeMapConstraint) String() string { 1178 return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ) 1179 } 1180 1181 func (c *reflectMakeMapConstraint) solve(a *analysis, delta *nodeset) { 1182 changed := false 1183 for _, x := range delta.AppendTo(a.deltaSpace) { 1184 typObj := nodeid(x) 1185 T := a.rtypeTaggedValue(typObj) 1186 tMap, ok := T.Underlying().(*types.Map) 1187 if !ok { 1188 continue // not a map type 1189 } 1190 1191 mapObj := a.nextNode() 1192 a.addNodes(tMap.Key(), "reflect.MakeMap.key") 1193 a.addNodes(tMap.Elem(), "reflect.MakeMap.value") 1194 a.endObject(mapObj, c.cgn, nil) 1195 1196 // put its address in a new T-tagged object 1197 id := a.makeTagged(T, c.cgn, nil) 1198 a.addLabel(id+1, mapObj) 1199 1200 // flow the T-tagged object to the result 1201 if a.addLabel(c.result, id) { 1202 changed = true 1203 } 1204 } 1205 if changed { 1206 a.addWork(c.result) 1207 } 1208 } 1209 1210 func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) { 1211 a.addConstraint(&reflectMakeMapConstraint{ 1212 cgn: cgn, 1213 typ: a.funcParams(cgn.obj), 1214 result: a.funcResults(cgn.obj), 1215 }) 1216 } 1217 1218 // ---------- func MakeSlice(Type) Value ---------- 1219 1220 // result = MakeSlice(typ) 1221 type reflectMakeSliceConstraint struct { 1222 cgn *cgnode 1223 typ nodeid // (ptr) 1224 result nodeid // (indirect) 1225 } 1226 1227 func (c *reflectMakeSliceConstraint) ptr() nodeid { return c.typ } 1228 func (c *reflectMakeSliceConstraint) presolve(h *hvn) { 1229 h.markIndirect(onodeid(c.result), "reflectMakeSlice.result") 1230 } 1231 func (c *reflectMakeSliceConstraint) renumber(mapping []nodeid) { 1232 c.typ = mapping[c.typ] 1233 c.result = mapping[c.result] 1234 } 1235 1236 func (c *reflectMakeSliceConstraint) String() string { 1237 return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ) 1238 } 1239 1240 func (c *reflectMakeSliceConstraint) solve(a *analysis, delta *nodeset) { 1241 changed := false 1242 for _, x := range delta.AppendTo(a.deltaSpace) { 1243 typObj := nodeid(x) 1244 T := a.rtypeTaggedValue(typObj) 1245 if _, ok := T.Underlying().(*types.Slice); !ok { 1246 continue // not a slice type 1247 } 1248 1249 obj := a.nextNode() 1250 a.addNodes(sliceToArray(T), "reflect.MakeSlice") 1251 a.endObject(obj, c.cgn, nil) 1252 1253 // put its address in a new T-tagged object 1254 id := a.makeTagged(T, c.cgn, nil) 1255 a.addLabel(id+1, obj) 1256 1257 // flow the T-tagged object to the result 1258 if a.addLabel(c.result, id) { 1259 changed = true 1260 } 1261 } 1262 if changed { 1263 a.addWork(c.result) 1264 } 1265 } 1266 1267 func ext۰reflect۰MakeSlice(a *analysis, cgn *cgnode) { 1268 a.addConstraint(&reflectMakeSliceConstraint{ 1269 cgn: cgn, 1270 typ: a.funcParams(cgn.obj), 1271 result: a.funcResults(cgn.obj), 1272 }) 1273 } 1274 1275 func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {} // TODO(adonovan) 1276 1277 // ---------- func New(Type) Value ---------- 1278 1279 // result = New(typ) 1280 type reflectNewConstraint struct { 1281 cgn *cgnode 1282 typ nodeid // (ptr) 1283 result nodeid // (indirect) 1284 } 1285 1286 func (c *reflectNewConstraint) ptr() nodeid { return c.typ } 1287 func (c *reflectNewConstraint) presolve(h *hvn) { 1288 h.markIndirect(onodeid(c.result), "reflectNew.result") 1289 } 1290 func (c *reflectNewConstraint) renumber(mapping []nodeid) { 1291 c.typ = mapping[c.typ] 1292 c.result = mapping[c.result] 1293 } 1294 1295 func (c *reflectNewConstraint) String() string { 1296 return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ) 1297 } 1298 1299 func (c *reflectNewConstraint) solve(a *analysis, delta *nodeset) { 1300 changed := false 1301 for _, x := range delta.AppendTo(a.deltaSpace) { 1302 typObj := nodeid(x) 1303 T := a.rtypeTaggedValue(typObj) 1304 1305 // allocate new T object 1306 newObj := a.nextNode() 1307 a.addNodes(T, "reflect.New") 1308 a.endObject(newObj, c.cgn, nil) 1309 1310 // put its address in a new *T-tagged object 1311 id := a.makeTagged(types.NewPointer(T), c.cgn, nil) 1312 a.addLabel(id+1, newObj) 1313 1314 // flow the pointer to the result 1315 if a.addLabel(c.result, id) { 1316 changed = true 1317 } 1318 } 1319 if changed { 1320 a.addWork(c.result) 1321 } 1322 } 1323 1324 func ext۰reflect۰New(a *analysis, cgn *cgnode) { 1325 a.addConstraint(&reflectNewConstraint{ 1326 cgn: cgn, 1327 typ: a.funcParams(cgn.obj), 1328 result: a.funcResults(cgn.obj), 1329 }) 1330 } 1331 1332 func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) { 1333 ext۰reflect۰New(a, cgn) 1334 1335 // TODO(adonovan): also report dynamic calls to unsound intrinsics. 1336 if site := cgn.callersite; site != nil { 1337 a.warnf(site.pos(), "unsound: %s contains a reflect.NewAt() call", site.instr.Parent()) 1338 } 1339 } 1340 1341 // ---------- func PtrTo(Type) Type ---------- 1342 1343 // result = PtrTo(t) 1344 type reflectPtrToConstraint struct { 1345 cgn *cgnode 1346 t nodeid // (ptr) 1347 result nodeid // (indirect) 1348 } 1349 1350 func (c *reflectPtrToConstraint) ptr() nodeid { return c.t } 1351 func (c *reflectPtrToConstraint) presolve(h *hvn) { 1352 h.markIndirect(onodeid(c.result), "reflectPtrTo.result") 1353 } 1354 func (c *reflectPtrToConstraint) renumber(mapping []nodeid) { 1355 c.t = mapping[c.t] 1356 c.result = mapping[c.result] 1357 } 1358 1359 func (c *reflectPtrToConstraint) String() string { 1360 return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t) 1361 } 1362 1363 func (c *reflectPtrToConstraint) solve(a *analysis, delta *nodeset) { 1364 changed := false 1365 for _, x := range delta.AppendTo(a.deltaSpace) { 1366 tObj := nodeid(x) 1367 T := a.rtypeTaggedValue(tObj) 1368 1369 if typeTooHigh(T) { 1370 continue 1371 } 1372 1373 if a.addLabel(c.result, a.makeRtype(types.NewPointer(T))) { 1374 changed = true 1375 } 1376 } 1377 if changed { 1378 a.addWork(c.result) 1379 } 1380 } 1381 1382 func ext۰reflect۰PtrTo(a *analysis, cgn *cgnode) { 1383 a.addConstraint(&reflectPtrToConstraint{ 1384 cgn: cgn, 1385 t: a.funcParams(cgn.obj), 1386 result: a.funcResults(cgn.obj), 1387 }) 1388 } 1389 1390 func ext۰reflect۰Select(a *analysis, cgn *cgnode) {} // TODO(adonovan) 1391 1392 // ---------- func SliceOf(Type) Type ---------- 1393 1394 // result = SliceOf(t) 1395 type reflectSliceOfConstraint struct { 1396 cgn *cgnode 1397 t nodeid // (ptr) 1398 result nodeid // (indirect) 1399 } 1400 1401 func (c *reflectSliceOfConstraint) ptr() nodeid { return c.t } 1402 func (c *reflectSliceOfConstraint) presolve(h *hvn) { 1403 h.markIndirect(onodeid(c.result), "reflectSliceOf.result") 1404 } 1405 func (c *reflectSliceOfConstraint) renumber(mapping []nodeid) { 1406 c.t = mapping[c.t] 1407 c.result = mapping[c.result] 1408 } 1409 1410 func (c *reflectSliceOfConstraint) String() string { 1411 return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t) 1412 } 1413 1414 func (c *reflectSliceOfConstraint) solve(a *analysis, delta *nodeset) { 1415 changed := false 1416 for _, x := range delta.AppendTo(a.deltaSpace) { 1417 tObj := nodeid(x) 1418 T := a.rtypeTaggedValue(tObj) 1419 1420 if typeTooHigh(T) { 1421 continue 1422 } 1423 1424 if a.addLabel(c.result, a.makeRtype(types.NewSlice(T))) { 1425 changed = true 1426 } 1427 } 1428 if changed { 1429 a.addWork(c.result) 1430 } 1431 } 1432 1433 func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) { 1434 a.addConstraint(&reflectSliceOfConstraint{ 1435 cgn: cgn, 1436 t: a.funcParams(cgn.obj), 1437 result: a.funcResults(cgn.obj), 1438 }) 1439 } 1440 1441 // ---------- func TypeOf(v Value) Type ---------- 1442 1443 // result = TypeOf(i) 1444 type reflectTypeOfConstraint struct { 1445 cgn *cgnode 1446 i nodeid // (ptr) 1447 result nodeid // (indirect) 1448 } 1449 1450 func (c *reflectTypeOfConstraint) ptr() nodeid { return c.i } 1451 func (c *reflectTypeOfConstraint) presolve(h *hvn) { 1452 h.markIndirect(onodeid(c.result), "reflectTypeOf.result") 1453 } 1454 func (c *reflectTypeOfConstraint) renumber(mapping []nodeid) { 1455 c.i = mapping[c.i] 1456 c.result = mapping[c.result] 1457 } 1458 1459 func (c *reflectTypeOfConstraint) String() string { 1460 return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i) 1461 } 1462 1463 func (c *reflectTypeOfConstraint) solve(a *analysis, delta *nodeset) { 1464 changed := false 1465 for _, x := range delta.AppendTo(a.deltaSpace) { 1466 iObj := nodeid(x) 1467 tDyn, _, _ := a.taggedValue(iObj) 1468 if a.addLabel(c.result, a.makeRtype(tDyn)) { 1469 changed = true 1470 } 1471 } 1472 if changed { 1473 a.addWork(c.result) 1474 } 1475 } 1476 1477 func ext۰reflect۰TypeOf(a *analysis, cgn *cgnode) { 1478 a.addConstraint(&reflectTypeOfConstraint{ 1479 cgn: cgn, 1480 i: a.funcParams(cgn.obj), 1481 result: a.funcResults(cgn.obj), 1482 }) 1483 } 1484 1485 // ---------- func ValueOf(interface{}) Value ---------- 1486 1487 func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) { 1488 // TODO(adonovan): when we start creating indirect tagged 1489 // objects, we'll need to handle them specially here since 1490 // they must never appear in the PTS of an interface{}. 1491 a.copy(a.funcResults(cgn.obj), a.funcParams(cgn.obj), 1) 1492 } 1493 1494 // ---------- func Zero(Type) Value ---------- 1495 1496 // result = Zero(typ) 1497 type reflectZeroConstraint struct { 1498 cgn *cgnode 1499 typ nodeid // (ptr) 1500 result nodeid // (indirect) 1501 } 1502 1503 func (c *reflectZeroConstraint) ptr() nodeid { return c.typ } 1504 func (c *reflectZeroConstraint) presolve(h *hvn) { 1505 h.markIndirect(onodeid(c.result), "reflectZero.result") 1506 } 1507 func (c *reflectZeroConstraint) renumber(mapping []nodeid) { 1508 c.typ = mapping[c.typ] 1509 c.result = mapping[c.result] 1510 } 1511 1512 func (c *reflectZeroConstraint) String() string { 1513 return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ) 1514 } 1515 1516 func (c *reflectZeroConstraint) solve(a *analysis, delta *nodeset) { 1517 changed := false 1518 for _, x := range delta.AppendTo(a.deltaSpace) { 1519 typObj := nodeid(x) 1520 T := a.rtypeTaggedValue(typObj) 1521 1522 // TODO(adonovan): if T is an interface type, we need 1523 // to create an indirect tagged object containing 1524 // new(T). To avoid updates of such shared values, 1525 // we'll need another flag on indirect tagged objects 1526 // that marks whether they are addressable or 1527 // readonly, just like the reflect package does. 1528 1529 // memoize using a.reflectZeros[T] 1530 var id nodeid 1531 if z := a.reflectZeros.At(T); false && z != nil { 1532 id = z.(nodeid) 1533 } else { 1534 id = a.makeTagged(T, c.cgn, nil) 1535 a.reflectZeros.Set(T, id) 1536 } 1537 if a.addLabel(c.result, id) { 1538 changed = true 1539 } 1540 } 1541 if changed { 1542 a.addWork(c.result) 1543 } 1544 } 1545 1546 func ext۰reflect۰Zero(a *analysis, cgn *cgnode) { 1547 a.addConstraint(&reflectZeroConstraint{ 1548 cgn: cgn, 1549 typ: a.funcParams(cgn.obj), 1550 result: a.funcResults(cgn.obj), 1551 }) 1552 } 1553 1554 // -------------------- (*reflect.rtype) methods -------------------- 1555 1556 // ---------- func (*rtype) Elem() Type ---------- 1557 1558 // result = Elem(t) 1559 type rtypeElemConstraint struct { 1560 cgn *cgnode 1561 t nodeid // (ptr) 1562 result nodeid // (indirect) 1563 } 1564 1565 func (c *rtypeElemConstraint) ptr() nodeid { return c.t } 1566 func (c *rtypeElemConstraint) presolve(h *hvn) { 1567 h.markIndirect(onodeid(c.result), "rtypeElem.result") 1568 } 1569 func (c *rtypeElemConstraint) renumber(mapping []nodeid) { 1570 c.t = mapping[c.t] 1571 c.result = mapping[c.result] 1572 } 1573 1574 func (c *rtypeElemConstraint) String() string { 1575 return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t) 1576 } 1577 1578 func (c *rtypeElemConstraint) solve(a *analysis, delta *nodeset) { 1579 // Implemented by *types.{Map,Chan,Array,Slice,Pointer}. 1580 type hasElem interface { 1581 Elem() types.Type 1582 } 1583 changed := false 1584 for _, x := range delta.AppendTo(a.deltaSpace) { 1585 tObj := nodeid(x) 1586 T := a.nodes[tObj].obj.data.(types.Type) 1587 if tHasElem, ok := T.Underlying().(hasElem); ok { 1588 if a.addLabel(c.result, a.makeRtype(tHasElem.Elem())) { 1589 changed = true 1590 } 1591 } 1592 } 1593 if changed { 1594 a.addWork(c.result) 1595 } 1596 } 1597 1598 func ext۰reflect۰rtype۰Elem(a *analysis, cgn *cgnode) { 1599 a.addConstraint(&rtypeElemConstraint{ 1600 cgn: cgn, 1601 t: a.funcParams(cgn.obj), 1602 result: a.funcResults(cgn.obj), 1603 }) 1604 } 1605 1606 // ---------- func (*rtype) Field(int) StructField ---------- 1607 // ---------- func (*rtype) FieldByName(string) (StructField, bool) ---------- 1608 1609 // result = FieldByName(t, name) 1610 // result = Field(t, _) 1611 type rtypeFieldByNameConstraint struct { 1612 cgn *cgnode 1613 name string // name of field; "" for unknown 1614 t nodeid // (ptr) 1615 result nodeid // (indirect) 1616 } 1617 1618 func (c *rtypeFieldByNameConstraint) ptr() nodeid { return c.t } 1619 func (c *rtypeFieldByNameConstraint) presolve(h *hvn) { 1620 h.markIndirect(onodeid(c.result+3), "rtypeFieldByName.result.Type") 1621 } 1622 func (c *rtypeFieldByNameConstraint) renumber(mapping []nodeid) { 1623 c.t = mapping[c.t] 1624 c.result = mapping[c.result] 1625 } 1626 1627 func (c *rtypeFieldByNameConstraint) String() string { 1628 return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name) 1629 } 1630 1631 func (c *rtypeFieldByNameConstraint) solve(a *analysis, delta *nodeset) { 1632 // type StructField struct { 1633 // 0 __identity__ 1634 // 1 Name string 1635 // 2 PkgPath string 1636 // 3 Type Type 1637 // 4 Tag StructTag 1638 // 5 Offset uintptr 1639 // 6 Index []int 1640 // 7 Anonymous bool 1641 // } 1642 1643 for _, x := range delta.AppendTo(a.deltaSpace) { 1644 tObj := nodeid(x) 1645 T := a.nodes[tObj].obj.data.(types.Type) 1646 tStruct, ok := T.Underlying().(*types.Struct) 1647 if !ok { 1648 continue // not a struct type 1649 } 1650 1651 n := tStruct.NumFields() 1652 for i := 0; i < n; i++ { 1653 f := tStruct.Field(i) 1654 if c.name == "" || c.name == f.Name() { 1655 1656 // a.offsetOf(Type) is 3. 1657 if id := c.result + 3; a.addLabel(id, a.makeRtype(f.Type())) { 1658 a.addWork(id) 1659 } 1660 // TODO(adonovan): StructField.Index should be non-nil. 1661 } 1662 } 1663 } 1664 } 1665 1666 func ext۰reflect۰rtype۰FieldByName(a *analysis, cgn *cgnode) { 1667 // If we have access to the callsite, 1668 // and the argument is a string constant, 1669 // return only that field. 1670 var name string 1671 if site := cgn.callersite; site != nil { 1672 if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok { 1673 name = exact.StringVal(c.Value) 1674 } 1675 } 1676 1677 a.addConstraint(&rtypeFieldByNameConstraint{ 1678 cgn: cgn, 1679 name: name, 1680 t: a.funcParams(cgn.obj), 1681 result: a.funcResults(cgn.obj), 1682 }) 1683 } 1684 1685 func ext۰reflect۰rtype۰Field(a *analysis, cgn *cgnode) { 1686 // No-one ever calls Field with a constant argument, 1687 // so we don't specialize that case. 1688 a.addConstraint(&rtypeFieldByNameConstraint{ 1689 cgn: cgn, 1690 t: a.funcParams(cgn.obj), 1691 result: a.funcResults(cgn.obj), 1692 }) 1693 } 1694 1695 func ext۰reflect۰rtype۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan) 1696 func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan) 1697 1698 // ---------- func (*rtype) In/Out(i int) Type ---------- 1699 1700 // result = In/Out(t, i) 1701 type rtypeInOutConstraint struct { 1702 cgn *cgnode 1703 t nodeid // (ptr) 1704 result nodeid // (indirect) 1705 out bool 1706 i int // -ve if not a constant 1707 } 1708 1709 func (c *rtypeInOutConstraint) ptr() nodeid { return c.t } 1710 func (c *rtypeInOutConstraint) presolve(h *hvn) { 1711 h.markIndirect(onodeid(c.result), "rtypeInOut.result") 1712 } 1713 func (c *rtypeInOutConstraint) renumber(mapping []nodeid) { 1714 c.t = mapping[c.t] 1715 c.result = mapping[c.result] 1716 } 1717 1718 func (c *rtypeInOutConstraint) String() string { 1719 return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i) 1720 } 1721 1722 func (c *rtypeInOutConstraint) solve(a *analysis, delta *nodeset) { 1723 changed := false 1724 for _, x := range delta.AppendTo(a.deltaSpace) { 1725 tObj := nodeid(x) 1726 T := a.nodes[tObj].obj.data.(types.Type) 1727 sig, ok := T.Underlying().(*types.Signature) 1728 if !ok { 1729 continue // not a func type 1730 } 1731 1732 tuple := sig.Params() 1733 if c.out { 1734 tuple = sig.Results() 1735 } 1736 for i, n := 0, tuple.Len(); i < n; i++ { 1737 if c.i < 0 || c.i == i { 1738 if a.addLabel(c.result, a.makeRtype(tuple.At(i).Type())) { 1739 changed = true 1740 } 1741 } 1742 } 1743 } 1744 if changed { 1745 a.addWork(c.result) 1746 } 1747 } 1748 1749 func ext۰reflect۰rtype۰InOut(a *analysis, cgn *cgnode, out bool) { 1750 // If we have access to the callsite, 1751 // and the argument is an int constant, 1752 // return only that parameter. 1753 index := -1 1754 if site := cgn.callersite; site != nil { 1755 if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok { 1756 v, _ := exact.Int64Val(c.Value) 1757 index = int(v) 1758 } 1759 } 1760 a.addConstraint(&rtypeInOutConstraint{ 1761 cgn: cgn, 1762 t: a.funcParams(cgn.obj), 1763 result: a.funcResults(cgn.obj), 1764 out: out, 1765 i: index, 1766 }) 1767 } 1768 1769 func ext۰reflect۰rtype۰In(a *analysis, cgn *cgnode) { 1770 ext۰reflect۰rtype۰InOut(a, cgn, false) 1771 } 1772 1773 func ext۰reflect۰rtype۰Out(a *analysis, cgn *cgnode) { 1774 ext۰reflect۰rtype۰InOut(a, cgn, true) 1775 } 1776 1777 // ---------- func (*rtype) Key() Type ---------- 1778 1779 // result = Key(t) 1780 type rtypeKeyConstraint struct { 1781 cgn *cgnode 1782 t nodeid // (ptr) 1783 result nodeid // (indirect) 1784 } 1785 1786 func (c *rtypeKeyConstraint) ptr() nodeid { return c.t } 1787 func (c *rtypeKeyConstraint) presolve(h *hvn) { 1788 h.markIndirect(onodeid(c.result), "rtypeKey.result") 1789 } 1790 func (c *rtypeKeyConstraint) renumber(mapping []nodeid) { 1791 c.t = mapping[c.t] 1792 c.result = mapping[c.result] 1793 } 1794 1795 func (c *rtypeKeyConstraint) String() string { 1796 return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t) 1797 } 1798 1799 func (c *rtypeKeyConstraint) solve(a *analysis, delta *nodeset) { 1800 changed := false 1801 for _, x := range delta.AppendTo(a.deltaSpace) { 1802 tObj := nodeid(x) 1803 T := a.nodes[tObj].obj.data.(types.Type) 1804 if tMap, ok := T.Underlying().(*types.Map); ok { 1805 if a.addLabel(c.result, a.makeRtype(tMap.Key())) { 1806 changed = true 1807 } 1808 } 1809 } 1810 if changed { 1811 a.addWork(c.result) 1812 } 1813 } 1814 1815 func ext۰reflect۰rtype۰Key(a *analysis, cgn *cgnode) { 1816 a.addConstraint(&rtypeKeyConstraint{ 1817 cgn: cgn, 1818 t: a.funcParams(cgn.obj), 1819 result: a.funcResults(cgn.obj), 1820 }) 1821 } 1822 1823 // ---------- func (*rtype) Method(int) (Method, bool) ---------- 1824 // ---------- func (*rtype) MethodByName(string) (Method, bool) ---------- 1825 1826 // result = MethodByName(t, name) 1827 // result = Method(t, _) 1828 type rtypeMethodByNameConstraint struct { 1829 cgn *cgnode 1830 name string // name of method; "" for unknown 1831 t nodeid // (ptr) 1832 result nodeid // (indirect) 1833 } 1834 1835 func (c *rtypeMethodByNameConstraint) ptr() nodeid { return c.t } 1836 func (c *rtypeMethodByNameConstraint) presolve(h *hvn) { 1837 h.markIndirect(onodeid(c.result+3), "rtypeMethodByName.result.Type") 1838 h.markIndirect(onodeid(c.result+4), "rtypeMethodByName.result.Func") 1839 } 1840 func (c *rtypeMethodByNameConstraint) renumber(mapping []nodeid) { 1841 c.t = mapping[c.t] 1842 c.result = mapping[c.result] 1843 } 1844 1845 func (c *rtypeMethodByNameConstraint) String() string { 1846 return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name) 1847 } 1848 1849 // changeRecv returns sig with Recv prepended to Params(). 1850 func changeRecv(sig *types.Signature) *types.Signature { 1851 params := sig.Params() 1852 n := params.Len() 1853 p2 := make([]*types.Var, n+1) 1854 p2[0] = sig.Recv() 1855 for i := 0; i < n; i++ { 1856 p2[i+1] = params.At(i) 1857 } 1858 return types.NewSignature(nil, types.NewTuple(p2...), sig.Results(), sig.Variadic()) 1859 } 1860 1861 func (c *rtypeMethodByNameConstraint) solve(a *analysis, delta *nodeset) { 1862 for _, x := range delta.AppendTo(a.deltaSpace) { 1863 tObj := nodeid(x) 1864 T := a.nodes[tObj].obj.data.(types.Type) 1865 1866 isIface := isInterface(T) 1867 1868 // We don't use Lookup(c.name) when c.name != "" to avoid 1869 // ambiguity: >1 unexported methods could match. 1870 mset := a.prog.MethodSets.MethodSet(T) 1871 for i, n := 0, mset.Len(); i < n; i++ { 1872 sel := mset.At(i) 1873 if c.name == "" || c.name == sel.Obj().Name() { 1874 // type Method struct { 1875 // 0 __identity__ 1876 // 1 Name string 1877 // 2 PkgPath string 1878 // 3 Type Type 1879 // 4 Func Value 1880 // 5 Index int 1881 // } 1882 1883 var sig *types.Signature 1884 var fn *ssa.Function 1885 if isIface { 1886 sig = sel.Type().(*types.Signature) 1887 } else { 1888 fn = a.prog.MethodValue(sel) 1889 // move receiver to params[0] 1890 sig = changeRecv(fn.Signature) 1891 } 1892 1893 // a.offsetOf(Type) is 3. 1894 if id := c.result + 3; a.addLabel(id, a.makeRtype(sig)) { 1895 a.addWork(id) 1896 } 1897 if fn != nil { 1898 // a.offsetOf(Func) is 4. 1899 if id := c.result + 4; a.addLabel(id, a.objectNode(nil, fn)) { 1900 a.addWork(id) 1901 } 1902 } 1903 } 1904 } 1905 } 1906 } 1907 1908 func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) { 1909 // If we have access to the callsite, 1910 // and the argument is a string constant, 1911 // return only that method. 1912 var name string 1913 if site := cgn.callersite; site != nil { 1914 if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok { 1915 name = exact.StringVal(c.Value) 1916 } 1917 } 1918 1919 a.addConstraint(&rtypeMethodByNameConstraint{ 1920 cgn: cgn, 1921 name: name, 1922 t: a.funcParams(cgn.obj), 1923 result: a.funcResults(cgn.obj), 1924 }) 1925 } 1926 1927 func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) { 1928 // No-one ever calls Method with a constant argument, 1929 // so we don't specialize that case. 1930 a.addConstraint(&rtypeMethodByNameConstraint{ 1931 cgn: cgn, 1932 t: a.funcParams(cgn.obj), 1933 result: a.funcResults(cgn.obj), 1934 }) 1935 } 1936 1937 // typeHeight returns the "height" of the type, which is roughly 1938 // speaking the number of chan, map, pointer and slice type constructors 1939 // at the root of T; these are the four type kinds that can be created 1940 // via reflection. Chan and map constructors are counted as double the 1941 // height of slice and pointer constructors since they are less often 1942 // deeply nested. 1943 // 1944 // The solver rules for type constructors must somehow bound the set of 1945 // types they create to ensure termination of the algorithm in cases 1946 // where the output of a type constructor flows to its input, e.g. 1947 // 1948 // func f(t reflect.Type) { 1949 // f(reflect.PtrTo(t)) 1950 // } 1951 // 1952 // It does this by limiting the type height to k, but this still leaves 1953 // a potentially exponential (4^k) number of of types that may be 1954 // enumerated in pathological cases. 1955 // 1956 func typeHeight(T types.Type) int { 1957 switch T := T.(type) { 1958 case *types.Chan: 1959 return 2 + typeHeight(T.Elem()) 1960 case *types.Map: 1961 k := typeHeight(T.Key()) 1962 v := typeHeight(T.Elem()) 1963 if v > k { 1964 k = v // max(k, v) 1965 } 1966 return 2 + k 1967 case *types.Slice: 1968 return 1 + typeHeight(T.Elem()) 1969 case *types.Pointer: 1970 return 1 + typeHeight(T.Elem()) 1971 } 1972 return 0 1973 } 1974 1975 func typeTooHigh(T types.Type) bool { 1976 return typeHeight(T) > 3 1977 }