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