GoPLS Viewer

Home|gopls/go/pointer/gen.go
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
5package pointer
6
7// This file defines the constraint generation phase.
8
9// TODO(adonovan): move the constraint definitions and the store() etc
10// functions which add them (and are also used by the solver) into a
11// new file, constraints.go.
12
13import (
14    "fmt"
15    "go/token"
16    "go/types"
17    "strings"
18
19    "golang.org/x/tools/go/callgraph"
20    "golang.org/x/tools/go/ssa"
21    "golang.org/x/tools/internal/typeparams"
22)
23
24var (
25    tEface     = types.NewInterfaceType(nilnil).Complete()
26    tInvalid   = types.Typ[types.Invalid]
27    tUnsafePtr = types.Typ[types.UnsafePointer]
28)
29
30// ---------- Node creation ----------
31
32// nextNode returns the index of the next unused node.
33func (a *analysisnextNode() nodeid {
34    return nodeid(len(a.nodes))
35}
36
37// addNodes creates nodes for all scalar elements in type typ, and
38// returns the id of the first one, or zero if the type was
39// analytically uninteresting.
40//
41// comment explains the origin of the nodes, as a debugging aid.
42func (a *analysisaddNodes(typ types.Typecomment stringnodeid {
43    id := a.nextNode()
44    for _fi := range a.flatten(typ) {
45        a.addOneNode(fi.typcommentfi)
46    }
47    if id == a.nextNode() {
48        return 0 // type contained no pointers
49    }
50    return id
51}
52
53// addOneNode creates a single node with type typ, and returns its id.
54//
55// typ should generally be scalar (except for tagged.T nodes
56// and struct/array identity nodes).  Use addNodes for non-scalar types.
57//
58// comment explains the origin of the nodes, as a debugging aid.
59// subelement indicates the subelement, e.g. ".a.b[*].c".
60func (a *analysisaddOneNode(typ types.Typecomment stringsubelement *fieldInfonodeid {
61    id := a.nextNode()
62    a.nodes = append(a.nodes, &node{typtypsubelementsubelementsolvenew(solverState)})
63    if a.log != nil {
64        fmt.Fprintf(a.log"\tcreate n%d %s for %s%s\n",
65            idtypcommentsubelement.path())
66    }
67    return id
68}
69
70// setValueNode associates node id with the value v.
71// cgn identifies the context iff v is a local variable.
72func (a *analysissetValueNode(v ssa.Valueid nodeidcgn *cgnode) {
73    if cgn != nil {
74        a.localval[v] = id
75    } else {
76        a.globalval[v] = id
77    }
78    if a.log != nil {
79        fmt.Fprintf(a.log"\tval[%s] = n%d  (%T)\n"v.Name(), idv)
80    }
81
82    // Due to context-sensitivity, we may encounter the same Value
83    // in many contexts. We merge them to a canonical node, since
84    // that's what all clients want.
85
86    // Record the (v, id) relation if the client has queried pts(v).
87    if _ok := a.config.Queries[v]; ok {
88        t := v.Type()
89        ptrok := a.result.Queries[v]
90        if !ok {
91            // First time?  Create the canonical query node.
92            ptr = Pointer{aa.addNodes(t"query")}
93            a.result.Queries[v] = ptr
94        }
95        a.result.Queries[v] = ptr
96        a.copy(ptr.nida.sizeof(t))
97    }
98
99    // Record the (*v, id) relation if the client has queried pts(*v).
100    if _ok := a.config.IndirectQueries[v]; ok {
101        t := v.Type()
102        ptrok := a.result.IndirectQueries[v]
103        if !ok {
104            // First time? Create the canonical indirect query node.
105            ptr = Pointer{aa.addNodes(v.Type(), "query.indirect")}
106            a.result.IndirectQueries[v] = ptr
107        }
108        a.genLoad(cgnptr.nv0a.sizeof(t))
109    }
110
111    for _query := range a.config.extendedQueries[v] {
112        tnid := a.evalExtendedQuery(v.Type().Underlying(), idquery.ops)
113
114        if query.ptr.a == nil {
115            query.ptr.a = a
116            query.ptr.n = a.addNodes(t"query.extended")
117        }
118        a.copy(query.ptr.nnida.sizeof(t))
119    }
120}
121
122// endObject marks the end of a sequence of calls to addNodes denoting
123// a single object allocation.
124//
125// obj is the start node of the object, from a prior call to nextNode.
126// Its size, flags and optional data will be updated.
127func (a *analysisendObject(obj nodeidcgn *cgnodedata interface{}) *object {
128    // Ensure object is non-empty by padding;
129    // the pad will be the object node.
130    size := uint32(a.nextNode() - obj)
131    if size == 0 {
132        a.addOneNode(tInvalid"padding"nil)
133    }
134    objNode := a.nodes[obj]
135    o := &object{
136        sizesize// excludes padding
137        cgn:  cgn,
138        datadata,
139    }
140    objNode.obj = o
141
142    return o
143}
144
145// makeFunctionObject creates and returns a new function object
146// (contour) for fn, and returns the id of its first node.  It also
147// enqueues fn for subsequent constraint generation.
148//
149// For a context-sensitive contour, callersite identifies the sole
150// callsite; for shared contours, caller is nil.
151func (a *analysismakeFunctionObject(fn *ssa.Functioncallersite *callsitenodeid {
152    if a.log != nil {
153        fmt.Fprintf(a.log"\t---- makeFunctionObject %s\n"fn)
154    }
155
156    // obj is the function object (identity, params, results).
157    obj := a.nextNode()
158    cgn := a.makeCGNode(fnobjcallersite)
159    sig := fn.Signature
160    a.addOneNode(sig"func.cgnode"nil// (scalar with Signature type)
161    if recv := sig.Recv(); recv != nil {
162        a.addNodes(recv.Type(), "func.recv")
163    }
164    a.addNodes(sig.Params(), "func.params")
165    a.addNodes(sig.Results(), "func.results")
166    a.endObject(objcgnfn).flags |= otFunction
167
168    if a.log != nil {
169        fmt.Fprintf(a.log"\t----\n")
170    }
171
172    // Queue it up for constraint processing.
173    a.genq = append(a.genqcgn)
174
175    return obj
176}
177
178// makeTagged creates a tagged object of type typ.
179func (a *analysismakeTagged(typ types.Typecgn *cgnodedata interface{}) nodeid {
180    obj := a.addOneNode(typ"tagged.T"nil// NB: type may be non-scalar!
181    a.addNodes(typ"tagged.v")
182    a.endObject(objcgndata).flags |= otTagged
183    return obj
184}
185
186// makeRtype returns the canonical tagged object of type *rtype whose
187// payload points to the sole rtype object for T.
188//
189// TODO(adonovan): move to reflect.go; it's part of the solver really.
190func (a *analysismakeRtype(T types.Typenodeid {
191    if v := a.rtypes.At(T); v != nil {
192        return v.(nodeid)
193    }
194
195    // Create the object for the reflect.rtype itself, which is
196    // ordinarily a large struct but here a single node will do.
197    obj := a.nextNode()
198    a.addOneNode(T"reflect.rtype"nil)
199    a.endObject(objnilT)
200
201    id := a.makeTagged(a.reflectRtypePtrnilT)
202    a.nodes[id+1].typ = T // trick (each *rtype tagged object is a singleton)
203    a.addressOf(a.reflectRtypePtrid+1obj)
204
205    a.rtypes.Set(Tid)
206    return id
207}
208
209// rtypeValue returns the type of the *reflect.rtype-tagged object obj.
210func (a *analysisrtypeTaggedValue(obj nodeidtypes.Type {
211    tDynt_ := a.taggedValue(obj)
212    if tDyn != a.reflectRtypePtr {
213        panic(fmt.Sprintf("not a *reflect.rtype-tagged object: obj=n%d tag=%v payload=n%d"objtDynt))
214    }
215    return a.nodes[t].typ
216}
217
218// valueNode returns the id of the value node for v, creating it (and
219// the association) as needed.  It may return zero for uninteresting
220// values containing no pointers.
221func (a *analysisvalueNode(v ssa.Valuenodeid {
222    // Value nodes for locals are created en masse by genFunc.
223    if idok := a.localval[v]; ok {
224        return id
225    }
226
227    // Value nodes for globals are created on demand.
228    idok := a.globalval[v]
229    if !ok {
230        var comment string
231        if a.log != nil {
232            comment = v.String()
233        }
234        id = a.addNodes(v.Type(), comment)
235        if obj := a.objectNode(nilv); obj != 0 {
236            a.addressOf(v.Type(), idobj)
237        }
238        a.setValueNode(vidnil)
239    }
240    return id
241}
242
243// valueOffsetNode ascertains the node for tuple/struct value v,
244// then returns the node for its subfield #index.
245func (a *analysisvalueOffsetNode(v ssa.Valueindex intnodeid {
246    id := a.valueNode(v)
247    if id == 0 {
248        panic(fmt.Sprintf("cannot offset within n0: %s = %s"v.Name(), v))
249    }
250    return id + nodeid(a.offsetOf(v.Type(), index))
251}
252
253// isTaggedObject reports whether object obj is a tagged object.
254func (a *analysisisTaggedObject(obj nodeidbool {
255    return a.nodes[obj].obj.flags&otTagged != 0
256}
257
258// taggedValue returns the dynamic type tag, the (first node of the)
259// payload, and the indirect flag of the tagged object starting at id.
260// Panic ensues if !isTaggedObject(id).
261func (a *analysistaggedValue(obj nodeid) (tDyn types.Typev nodeidindirect bool) {
262    n := a.nodes[obj]
263    flags := n.obj.flags
264    if flags&otTagged == 0 {
265        panic(fmt.Sprintf("not a tagged object: n%d"obj))
266    }
267    return n.typobj + 1flags&otIndirect != 0
268}
269
270// funcParams returns the first node of the params (P) block of the
271// function whose object node (obj.flags&otFunction) is id.
272func (a *analysisfuncParams(id nodeidnodeid {
273    n := a.nodes[id]
274    if n.obj == nil || n.obj.flags&otFunction == 0 {
275        panic(fmt.Sprintf("funcParams(n%d): not a function object block"id))
276    }
277    return id + 1
278}
279
280// funcResults returns the first node of the results (R) block of the
281// function whose object node (obj.flags&otFunction) is id.
282func (a *analysisfuncResults(id nodeidnodeid {
283    n := a.nodes[id]
284    if n.obj == nil || n.obj.flags&otFunction == 0 {
285        panic(fmt.Sprintf("funcResults(n%d): not a function object block"id))
286    }
287    sig := n.typ.(*types.Signature)
288    id += 1 + nodeid(a.sizeof(sig.Params()))
289    if sig.Recv() != nil {
290        id += nodeid(a.sizeof(sig.Recv().Type()))
291    }
292    return id
293}
294
295// ---------- Constraint creation ----------
296
297// copy creates a constraint of the form dst = src.
298// sizeof is the width (in logical fields) of the copied type.
299func (a *analysiscopy(dstsrc nodeidsizeof uint32) {
300    if src == dst || sizeof == 0 {
301        return // trivial
302    }
303    if src == 0 || dst == 0 {
304        panic(fmt.Sprintf("ill-typed copy dst=n%d src=n%d"dstsrc))
305    }
306    for i := uint32(0); i < sizeofi++ {
307        a.addConstraint(&copyConstraint{dstsrc})
308        src++
309        dst++
310    }
311}
312
313// addressOf creates a constraint of the form id = &obj.
314// T is the type of the address.
315func (a *analysisaddressOf(T types.Typeidobj nodeid) {
316    if id == 0 {
317        panic("addressOf: zero id")
318    }
319    if obj == 0 {
320        panic("addressOf: zero obj")
321    }
322    if a.shouldTrack(T) {
323        a.addConstraint(&addrConstraint{idobj})
324    }
325}
326
327// load creates a load constraint of the form dst = src[offset].
328// offset is the pointer offset in logical fields.
329// sizeof is the width (in logical fields) of the loaded type.
330func (a *analysisload(dstsrc nodeidoffsetsizeof uint32) {
331    if dst == 0 {
332        return // load of non-pointerlike value
333    }
334    if src == 0 && dst == 0 {
335        return // non-pointerlike operation
336    }
337    if src == 0 || dst == 0 {
338        panic(fmt.Sprintf("ill-typed load dst=n%d src=n%d"dstsrc))
339    }
340    for i := uint32(0); i < sizeofi++ {
341        a.addConstraint(&loadConstraint{offsetdstsrc})
342        offset++
343        dst++
344    }
345}
346
347// store creates a store constraint of the form dst[offset] = src.
348// offset is the pointer offset in logical fields.
349// sizeof is the width (in logical fields) of the stored type.
350func (a *analysisstore(dstsrc nodeidoffset uint32sizeof uint32) {
351    if src == 0 {
352        return // store of non-pointerlike value
353    }
354    if src == 0 && dst == 0 {
355        return // non-pointerlike operation
356    }
357    if src == 0 || dst == 0 {
358        panic(fmt.Sprintf("ill-typed store dst=n%d src=n%d"dstsrc))
359    }
360    for i := uint32(0); i < sizeofi++ {
361        a.addConstraint(&storeConstraint{offsetdstsrc})
362        offset++
363        src++
364    }
365}
366
367// offsetAddr creates an offsetAddr constraint of the form dst = &src.#offset.
368// offset is the field offset in logical fields.
369// T is the type of the address.
370func (a *analysisoffsetAddr(T types.Typedstsrc nodeidoffset uint32) {
371    if !a.shouldTrack(T) {
372        return
373    }
374    if offset == 0 {
375        // Simplify  dst = &src->f0
376        //       to  dst = src
377        // (NB: this optimisation is defeated by the identity
378        // field prepended to struct and array objects.)
379        a.copy(dstsrc1)
380    } else {
381        a.addConstraint(&offsetAddrConstraint{offsetdstsrc})
382    }
383}
384
385// typeAssert creates a typeFilter or untag constraint of the form dst = src.(T):
386// typeFilter for an interface, untag for a concrete type.
387// The exact flag is specified as for untagConstraint.
388func (a *analysistypeAssert(T types.Typedstsrc nodeidexact bool) {
389    if isInterface(T) {
390        a.addConstraint(&typeFilterConstraint{Tdstsrc})
391    } else {
392        a.addConstraint(&untagConstraint{Tdstsrcexact})
393    }
394}
395
396// addConstraint adds c to the constraint set.
397func (a *analysisaddConstraint(c constraint) {
398    a.constraints = append(a.constraintsc)
399    if a.log != nil {
400        fmt.Fprintf(a.log"\t%s\n"c)
401    }
402}
403
404// copyElems generates load/store constraints for *dst = *src,
405// where src and dst are slices or *arrays.
406func (a *analysiscopyElems(cgn *cgnodetyp types.Typedstsrc ssa.Value) {
407    tmp := a.addNodes(typ"copy")
408    sz := a.sizeof(typ)
409    a.genLoad(cgntmpsrc1sz)
410    a.genStore(cgndsttmp1sz)
411}
412
413// ---------- Constraint generation ----------
414
415// genConv generates constraints for the conversion operation conv.
416func (a *analysisgenConv(conv *ssa.Convertcgn *cgnode) {
417    res := a.valueNode(conv)
418    if res == 0 {
419        return // result is non-pointerlike
420    }
421
422    tSrc := conv.X.Type()
423    tDst := conv.Type()
424
425    switch utSrc := tSrc.Underlying().(type) {
426    case *types.Slice:
427        // []byte/[]rune -> string?
428        return
429
430    case *types.Pointer:
431        // *T -> unsafe.Pointer?
432        if tDst.Underlying() == tUnsafePtr {
433            return // we don't model unsafe aliasing (unsound)
434        }
435
436    case *types.Basic:
437        switch tDst.Underlying().(type) {
438        case *types.Pointer:
439            // Treat unsafe.Pointer->*T conversions like
440            // new(T) and create an unaliased object.
441            if utSrc == tUnsafePtr {
442                obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion")
443                a.endObject(objcgnconv)
444                a.addressOf(tDstresobj)
445                return
446            }
447
448        case *types.Slice:
449            // string -> []byte/[]rune (or named aliases)?
450            if utSrc.Info()&types.IsString != 0 {
451                obj := a.addNodes(sliceToArray(tDst), "convert")
452                a.endObject(objcgnconv)
453                a.addressOf(tDstresobj)
454                return
455            }
456
457        case *types.Basic:
458            // All basic-to-basic type conversions are no-ops.
459            // This includes uintptr<->unsafe.Pointer conversions,
460            // which we (unsoundly) ignore.
461            return
462        }
463    }
464
465    panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s"tSrctDstconv.Parent()))
466}
467
468// genAppend generates constraints for a call to append.
469func (a *analysisgenAppend(instr *ssa.Callcgn *cgnode) {
470    // Consider z = append(x, y).   y is optional.
471    // This may allocate a new [1]T array; call its object w.
472    // We get the following constraints:
473    //     z = x
474    //     z = &w
475    //     *z = *y
476
477    x := instr.Call.Args[0]
478
479    z := instr
480    a.copy(a.valueNode(z), a.valueNode(x), 1// z = x
481
482    if len(instr.Call.Args) == 1 {
483        return // no allocation for z = append(x) or _ = append(x).
484    }
485
486    // TODO(adonovan): test append([]byte, ...string) []byte.
487
488    y := instr.Call.Args[1]
489    tArray := sliceToArray(instr.Call.Args[0].Type())
490
491    w := a.nextNode()
492    a.addNodes(tArray"append")
493    a.endObject(wcgninstr)
494
495    a.copyElems(cgntArray.Elem(), zy)        // *z = *y
496    a.addressOf(instr.Type(), a.valueNode(z), w//  z = &w
497}
498
499// genBuiltinCall generates constraints for a call to a built-in.
500func (a *analysisgenBuiltinCall(instr ssa.CallInstructioncgn *cgnode) {
501    call := instr.Common()
502    switch call.Value.(*ssa.Builtin).Name() {
503    case "append":
504        // Safe cast: append cannot appear in a go or defer statement.
505        a.genAppend(instr.(*ssa.Call), cgn)
506
507    case "copy":
508        tElem := call.Args[0].Type().Underlying().(*types.Slice).Elem()
509        a.copyElems(cgntElemcall.Args[0], call.Args[1])
510
511    case "panic":
512        a.copy(a.panicNodea.valueNode(call.Args[0]), 1)
513
514    case "recover":
515        if v := instr.Value(); v != nil {
516            a.copy(a.valueNode(v), a.panicNode1)
517        }
518
519    case "print":
520        // In the tests, the probe might be the sole reference
521        // to its arg, so make sure we create nodes for it.
522        if len(call.Args) > 0 {
523            a.valueNode(call.Args[0])
524        }
525
526    case "ssa:wrapnilchk":
527        a.copy(a.valueNode(instr.Value()), a.valueNode(call.Args[0]), 1)
528
529    default:
530        // No-ops: close len cap real imag complex print println delete.
531    }
532}
533
534// shouldUseContext defines the context-sensitivity policy.  It
535// returns true if we should analyse all static calls to fn anew.
536//
537// Obviously this interface rather limits how much freedom we have to
538// choose a policy.  The current policy, rather arbitrarily, is true
539// for intrinsics and accessor methods (actually: short, single-block,
540// call-free functions).  This is just a starting point.
541func (a *analysisshouldUseContext(fn *ssa.Functionbool {
542    if a.findIntrinsic(fn) != nil {
543        return true // treat intrinsics context-sensitively
544    }
545    if len(fn.Blocks) != 1 {
546        return false // too expensive
547    }
548    blk := fn.Blocks[0]
549    if len(blk.Instrs) > 10 {
550        return false // too expensive
551    }
552    if fn.Synthetic != "" && (fn.Pkg == nil || fn != fn.Pkg.Func("init")) {
553        return true // treat synthetic wrappers context-sensitively
554    }
555    for _instr := range blk.Instrs {
556        switch instr := instr.(type) {
557        case ssa.CallInstruction:
558            // Disallow function calls (except to built-ins)
559            // because of the danger of unbounded recursion.
560            if _ok := instr.Common().Value.(*ssa.Builtin); !ok {
561                return false
562            }
563        }
564    }
565    return true
566}
567
568// genStaticCall generates constraints for a statically dispatched function call.
569func (a *analysisgenStaticCall(caller *cgnodesite *callsitecall *ssa.CallCommonresult nodeid) {
570    fn := call.StaticCallee()
571
572    // Special cases for inlined intrinsics.
573    switch fn {
574    case a.runtimeSetFinalizer:
575        // Inline SetFinalizer so the call appears direct.
576        site.targets = a.addOneNode(tInvalid"SetFinalizer.targets"nil)
577        a.addConstraint(&runtimeSetFinalizerConstraint{
578            targetssite.targets,
579            x:       a.valueNode(call.Args[0]),
580            f:       a.valueNode(call.Args[1]),
581        })
582        return
583
584    case a.reflectValueCall:
585        // Inline (reflect.Value).Call so the call appears direct.
586        dotdotdot := false
587        ret := reflectCallImpl(acallersitea.valueNode(call.Args[0]), a.valueNode(call.Args[1]), dotdotdot)
588        if result != 0 {
589            a.addressOf(fn.Signature.Results().At(0).Type(), resultret)
590        }
591        return
592    }
593
594    // Ascertain the context (contour/cgnode) for a particular call.
595    var obj nodeid
596    if a.shouldUseContext(fn) {
597        obj = a.makeFunctionObject(fnsite// new contour
598    } else {
599        obj = a.objectNode(nilfn// shared contour
600    }
601    a.callEdge(callersiteobj)
602
603    sig := call.Signature()
604
605    // Copy receiver, if any.
606    params := a.funcParams(obj)
607    args := call.Args
608    if sig.Recv() != nil {
609        sz := a.sizeof(sig.Recv().Type())
610        a.copy(paramsa.valueNode(args[0]), sz)
611        params += nodeid(sz)
612        args = args[1:]
613    }
614
615    // Copy actual parameters into formal params block.
616    // Must loop, since the actuals aren't contiguous.
617    for iarg := range args {
618        sz := a.sizeof(sig.Params().At(i).Type())
619        a.copy(paramsa.valueNode(arg), sz)
620        params += nodeid(sz)
621    }
622
623    // Copy formal results block to actual result.
624    if result != 0 {
625        a.copy(resulta.funcResults(obj), a.sizeof(sig.Results()))
626    }
627}
628
629// genDynamicCall generates constraints for a dynamic function call.
630func (a *analysisgenDynamicCall(caller *cgnodesite *callsitecall *ssa.CallCommonresult nodeid) {
631    // pts(targets) will be the set of possible call targets.
632    site.targets = a.valueNode(call.Value)
633
634    // We add dynamic closure rules that store the arguments into
635    // the P-block and load the results from the R-block of each
636    // function discovered in pts(targets).
637
638    sig := call.Signature()
639    var offset uint32 = 1 // P/R block starts at offset 1
640    for iarg := range call.Args {
641        sz := a.sizeof(sig.Params().At(i).Type())
642        a.genStore(callercall.Valuea.valueNode(arg), offsetsz)
643        offset += sz
644    }
645    if result != 0 {
646        a.genLoad(callerresultcall.Valueoffseta.sizeof(sig.Results()))
647    }
648}
649
650// genInvoke generates constraints for a dynamic method invocation.
651func (a *analysisgenInvoke(caller *cgnodesite *callsitecall *ssa.CallCommonresult nodeid) {
652    if call.Value.Type() == a.reflectType {
653        a.genInvokeReflectType(callersitecallresult)
654        return
655    }
656
657    sig := call.Signature()
658
659    // Allocate a contiguous targets/params/results block for this call.
660    block := a.nextNode()
661    // pts(targets) will be the set of possible call targets
662    site.targets = a.addOneNode(sig"invoke.targets"nil)
663    p := a.addNodes(sig.Params(), "invoke.params")
664    r := a.addNodes(sig.Results(), "invoke.results")
665
666    // Copy the actual parameters into the call's params block.
667    for in := 0sig.Params().Len(); i < ni++ {
668        sz := a.sizeof(sig.Params().At(i).Type())
669        a.copy(pa.valueNode(call.Args[i]), sz)
670        p += nodeid(sz)
671    }
672    // Copy the call's results block to the actual results.
673    if result != 0 {
674        a.copy(resultra.sizeof(sig.Results()))
675    }
676
677    // We add a dynamic invoke constraint that will connect the
678    // caller's and the callee's P/R blocks for each discovered
679    // call target.
680    a.addConstraint(&invokeConstraint{call.Methoda.valueNode(call.Value), block})
681}
682
683// genInvokeReflectType is a specialization of genInvoke where the
684// receiver type is a reflect.Type, under the assumption that there
685// can be at most one implementation of this interface, *reflect.rtype.
686//
687// (Though this may appear to be an instance of a pattern---method
688// calls on interfaces known to have exactly one implementation---in
689// practice it occurs rarely, so we special case for reflect.Type.)
690//
691// In effect we treat this:
692//
693//    var rt reflect.Type = ...
694//    rt.F()
695//
696// as this:
697//
698//    rt.(*reflect.rtype).F()
699func (a *analysisgenInvokeReflectType(caller *cgnodesite *callsitecall *ssa.CallCommonresult nodeid) {
700    // Unpack receiver into rtype
701    rtype := a.addOneNode(a.reflectRtypePtr"rtype.recv"nil)
702    recv := a.valueNode(call.Value)
703    a.typeAssert(a.reflectRtypePtrrtyperecvtrue)
704
705    // Look up the concrete method.
706    fn := a.prog.LookupMethod(a.reflectRtypePtrcall.Method.Pkg(), call.Method.Name())
707
708    obj := a.makeFunctionObject(fnsite// new contour for this call
709    a.callEdge(callersiteobj)
710
711    // From now on, it's essentially a static call, but little is
712    // gained by factoring together the code for both cases.
713
714    sig := fn.Signature // concrete method
715    targets := a.addOneNode(sig"call.targets"nil)
716    a.addressOf(sigtargetsobj// (a singleton)
717
718    // Copy receiver.
719    params := a.funcParams(obj)
720    a.copy(paramsrtype1)
721    params++
722
723    // Copy actual parameters into formal P-block.
724    // Must loop, since the actuals aren't contiguous.
725    for iarg := range call.Args {
726        sz := a.sizeof(sig.Params().At(i).Type())
727        a.copy(paramsa.valueNode(arg), sz)
728        params += nodeid(sz)
729    }
730
731    // Copy formal R-block to actual R-block.
732    if result != 0 {
733        a.copy(resulta.funcResults(obj), a.sizeof(sig.Results()))
734    }
735}
736
737// genCall generates constraints for call instruction instr.
738func (a *analysisgenCall(caller *cgnodeinstr ssa.CallInstruction) {
739    call := instr.Common()
740
741    // Intrinsic implementations of built-in functions.
742    if _ok := call.Value.(*ssa.Builtin); ok {
743        a.genBuiltinCall(instrcaller)
744        return
745    }
746
747    var result nodeid
748    if v := instr.Value(); v != nil {
749        result = a.valueNode(v)
750    }
751
752    site := &callsite{instrinstr}
753    if call.StaticCallee() != nil {
754        a.genStaticCall(callersitecallresult)
755    } else if call.IsInvoke() {
756        a.genInvoke(callersitecallresult)
757    } else {
758        a.genDynamicCall(callersitecallresult)
759    }
760
761    caller.sites = append(caller.sitessite)
762
763    if a.log != nil {
764        // TODO(adonovan): debug: improve log message.
765        fmt.Fprintf(a.log"\t%s to targets %s from %s\n"sitesite.targetscaller)
766    }
767}
768
769// objectNode returns the object to which v points, if known.
770// In other words, if the points-to set of v is a singleton, it
771// returns the sole label, zero otherwise.
772//
773// We exploit this information to make the generated constraints less
774// dynamic.  For example, a complex load constraint can be replaced by
775// a simple copy constraint when the sole destination is known a priori.
776//
777// Some SSA instructions always have singletons points-to sets:
778//
779//    Alloc, Function, Global, MakeChan, MakeClosure,  MakeInterface,  MakeMap,  MakeSlice.
780//
781// Others may be singletons depending on their operands:
782//
783//    FreeVar, Const, Convert, FieldAddr, IndexAddr, Slice, SliceToArrayPointer.
784//
785// Idempotent.  Objects are created as needed, possibly via recursion
786// down the SSA value graph, e.g IndexAddr(FieldAddr(Alloc))).
787func (a *analysisobjectNode(cgn *cgnodev ssa.Valuenodeid {
788    switch v.(type) {
789    case *ssa.Global, *ssa.Function, *ssa.Const, *ssa.FreeVar:
790        // Global object.
791        objok := a.globalobj[v]
792        if !ok {
793            switch v := v.(type) {
794            case *ssa.Global:
795                obj = a.nextNode()
796                a.addNodes(mustDeref(v.Type()), "global")
797                a.endObject(objnilv)
798
799            case *ssa.Function:
800                obj = a.makeFunctionObject(vnil)
801
802            case *ssa.Const:
803                // not addressable
804
805            case *ssa.FreeVar:
806                // not addressable
807            }
808
809            if a.log != nil {
810                fmt.Fprintf(a.log"\tglobalobj[%s] = n%d\n"vobj)
811            }
812            a.globalobj[v] = obj
813        }
814        return obj
815    }
816
817    // Local object.
818    objok := a.localobj[v]
819    if !ok {
820        switch v := v.(type) {
821        case *ssa.Alloc:
822            obj = a.nextNode()
823            a.addNodes(mustDeref(v.Type()), "alloc")
824            a.endObject(objcgnv)
825
826        case *ssa.MakeSlice:
827            obj = a.nextNode()
828            a.addNodes(sliceToArray(v.Type()), "makeslice")
829            a.endObject(objcgnv)
830
831        case *ssa.MakeChan:
832            obj = a.nextNode()
833            a.addNodes(v.Type().Underlying().(*types.Chan).Elem(), "makechan")
834            a.endObject(objcgnv)
835
836        case *ssa.MakeMap:
837            obj = a.nextNode()
838            tmap := v.Type().Underlying().(*types.Map)
839            a.addNodes(tmap.Key(), "makemap.key")
840            elem := a.addNodes(tmap.Elem(), "makemap.value")
841
842            // To update the value field, MapUpdate
843            // generates store-with-offset constraints which
844            // the presolver can't model, so we must mark
845            // those nodes indirect.
846            for idend := elemelem+nodeid(a.sizeof(tmap.Elem())); id < endid++ {
847                a.mapValues = append(a.mapValuesid)
848            }
849            a.endObject(objcgnv)
850
851        case *ssa.MakeInterface:
852            tConc := v.X.Type()
853            obj = a.makeTagged(tConccgnv)
854
855            // Copy the value into it, if nontrivial.
856            if x := a.valueNode(v.X); x != 0 {
857                a.copy(obj+1xa.sizeof(tConc))
858            }
859
860        case *ssa.FieldAddr:
861            if xobj := a.objectNode(cgnv.X); xobj != 0 {
862                obj = xobj + nodeid(a.offsetOf(mustDeref(v.X.Type()), v.Field))
863            }
864
865        case *ssa.IndexAddr:
866            if xobj := a.objectNode(cgnv.X); xobj != 0 {
867                obj = xobj + 1
868            }
869
870        case *ssa.Slice:
871            obj = a.objectNode(cgnv.X)
872
873        case *ssa.SliceToArrayPointer:
874            // Going from a []T to a *[k]T for some k.
875            // A slice []T is treated as if it were a *T pointer.
876            obj = a.objectNode(cgnv.X)
877
878        case *ssa.Convert:
879            // TODO(adonovan): opt: handle these cases too:
880            // - unsafe.Pointer->*T conversion acts like Alloc
881            // - string->[]byte/[]rune conversion acts like MakeSlice
882        }
883
884        if a.log != nil {
885            fmt.Fprintf(a.log"\tlocalobj[%s] = n%d\n"v.Name(), obj)
886        }
887        a.localobj[v] = obj
888    }
889    return obj
890}
891
892// genLoad generates constraints for result = *(ptr + val).
893func (a *analysisgenLoad(cgn *cgnoderesult nodeidptr ssa.Valueoffsetsizeof uint32) {
894    if obj := a.objectNode(cgnptr); obj != 0 {
895        // Pre-apply loadConstraint.solve().
896        a.copy(resultobj+nodeid(offset), sizeof)
897    } else {
898        a.load(resulta.valueNode(ptr), offsetsizeof)
899    }
900}
901
902// genOffsetAddr generates constraints for a 'v=ptr.field' (FieldAddr)
903// or 'v=ptr[*]' (IndexAddr) instruction v.
904func (a *analysisgenOffsetAddr(cgn *cgnodev ssa.Valueptr nodeidoffset uint32) {
905    dst := a.valueNode(v)
906    if obj := a.objectNode(cgnv); obj != 0 {
907        // Pre-apply offsetAddrConstraint.solve().
908        a.addressOf(v.Type(), dstobj)
909    } else {
910        a.offsetAddr(v.Type(), dstptroffset)
911    }
912}
913
914// genStore generates constraints for *(ptr + offset) = val.
915func (a *analysisgenStore(cgn *cgnodeptr ssa.Valueval nodeidoffsetsizeof uint32) {
916    if obj := a.objectNode(cgnptr); obj != 0 {
917        // Pre-apply storeConstraint.solve().
918        a.copy(obj+nodeid(offset), valsizeof)
919    } else {
920        a.store(a.valueNode(ptr), valoffsetsizeof)
921    }
922}
923
924// genInstr generates constraints for instruction instr in context cgn.
925func (a *analysisgenInstr(cgn *cgnodeinstr ssa.Instruction) {
926    if a.log != nil {
927        var prefix string
928        if valok := instr.(ssa.Value); ok {
929            prefix = val.Name() + " = "
930        }
931        fmt.Fprintf(a.log"; %s%s\n"prefixinstr)
932    }
933
934    switch instr := instr.(type) {
935    case *ssa.DebugRef:
936        // no-op.
937
938    case *ssa.UnOp:
939        switch instr.Op {
940        case token.ARROW// <-x
941            // We can ignore instr.CommaOk because the node we're
942            // altering is always at zero offset relative to instr
943            tElem := instr.X.Type().Underlying().(*types.Chan).Elem()
944            a.genLoad(cgna.valueNode(instr), instr.X0a.sizeof(tElem))
945
946        case token.MUL// *x
947            a.genLoad(cgna.valueNode(instr), instr.X0a.sizeof(instr.Type()))
948
949        default:
950            // NOT, SUB, XOR: no-op.
951        }
952
953    case *ssa.BinOp:
954        // All no-ops.
955
956    case ssa.CallInstruction// *ssa.Call, *ssa.Go, *ssa.Defer
957        a.genCall(cgninstr)
958
959    case *ssa.ChangeType:
960        a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
961
962    case *ssa.Convert:
963        a.genConv(instrcgn)
964
965    case *ssa.Extract:
966        a.copy(a.valueNode(instr),
967            a.valueOffsetNode(instr.Tupleinstr.Index),
968            a.sizeof(instr.Type()))
969
970    case *ssa.FieldAddr:
971        a.genOffsetAddr(cgninstra.valueNode(instr.X),
972            a.offsetOf(mustDeref(instr.X.Type()), instr.Field))
973
974    case *ssa.IndexAddr:
975        a.genOffsetAddr(cgninstra.valueNode(instr.X), 1)
976
977    case *ssa.Field:
978        a.copy(a.valueNode(instr),
979            a.valueOffsetNode(instr.Xinstr.Field),
980            a.sizeof(instr.Type()))
981
982    case *ssa.Index:
983        _isstring := typeparams.CoreType(instr.X.Type()).(*types.Basic)
984        if !isstring {
985            a.copy(a.valueNode(instr), 1+a.valueNode(instr.X), a.sizeof(instr.Type()))
986        }
987
988    case *ssa.Select:
989        recv := a.valueOffsetNode(instr2// instr : (index, recvOk, recv0, ... recv_n-1)
990        for _st := range instr.States {
991            elemSize := a.sizeof(st.Chan.Type().Underlying().(*types.Chan).Elem())
992            switch st.Dir {
993            case types.RecvOnly:
994                a.genLoad(cgnrecvst.Chan0elemSize)
995                recv += nodeid(elemSize)
996
997            case types.SendOnly:
998                a.genStore(cgnst.Chana.valueNode(st.Send), 0elemSize)
999            }
1000        }
1001
1002    case *ssa.Return:
1003        results := a.funcResults(cgn.obj)
1004        for _r := range instr.Results {
1005            sz := a.sizeof(r.Type())
1006            a.copy(resultsa.valueNode(r), sz)
1007            results += nodeid(sz)
1008        }
1009
1010    case *ssa.Send:
1011        a.genStore(cgninstr.Chana.valueNode(instr.X), 0a.sizeof(instr.X.Type()))
1012
1013    case *ssa.Store:
1014        a.genStore(cgninstr.Addra.valueNode(instr.Val), 0a.sizeof(instr.Val.Type()))
1015
1016    case *ssa.Alloc, *ssa.MakeSlice, *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeInterface:
1017        v := instr.(ssa.Value)
1018        a.addressOf(v.Type(), a.valueNode(v), a.objectNode(cgnv))
1019
1020    case *ssa.ChangeInterface:
1021        a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1022
1023    case *ssa.TypeAssert:
1024        a.typeAssert(instr.AssertedTypea.valueNode(instr), a.valueNode(instr.X), true)
1025
1026    case *ssa.Slice:
1027        a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1028
1029    case *ssa.SliceToArrayPointer:
1030        // Going from a []T to a *[k]T (for some k) is a single `dst = src` constraint.
1031        // Both []T and *[k]T are modelled as an *IdArrayT where IdArrayT is the identity
1032        // node for an array of type T, i.e `type IdArrayT struct{elem T}`.
1033        a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1034
1035    case *ssa.If, *ssa.Jump:
1036        // no-op.
1037
1038    case *ssa.Phi:
1039        sz := a.sizeof(instr.Type())
1040        for _e := range instr.Edges {
1041            a.copy(a.valueNode(instr), a.valueNode(e), sz)
1042        }
1043
1044    case *ssa.MakeClosure:
1045        fn := instr.Fn.(*ssa.Function)
1046        a.copy(a.valueNode(instr), a.valueNode(fn), 1)
1047        // Free variables are treated like global variables.
1048        for ib := range instr.Bindings {
1049            a.copy(a.valueNode(fn.FreeVars[i]), a.valueNode(b), a.sizeof(b.Type()))
1050        }
1051
1052    case *ssa.RunDefers:
1053        // The analysis is flow insensitive, so we just "call"
1054        // defers as we encounter them.
1055
1056    case *ssa.Range:
1057        // Do nothing.  Next{Iter: *ssa.Range} handles this case.
1058
1059    case *ssa.Next:
1060        if !instr.IsString {
1061            // Assumes that Next is always directly applied to a Range result
1062            // for a map.
1063
1064            // Next results in a destination tuple (ok, dk, dv).
1065            // Recall a map is modeled as type *M where M = struct{sk K; sv V}.
1066            // Next copies from a src map struct{sk K; sv V} to a dst tuple (ok, dk, dv)
1067            //
1068            // When keys or value is a blank identifier in a range statement, e.g
1069            //   for _, v := range m { ... }
1070            // or
1071            //   for _, _ = range m { ... }
1072            // we skip copying from sk or dk as there is no use. dk and dv will have
1073            // Invalid types if they are blank identifiers. This means that the
1074            //   size( (ok, dk, dv) )  may differ from 1 + size(struct{sk K; sv V}).
1075            //
1076            // We encode Next using one load of size sz from an offset in src osrc to an
1077            // offset in dst odst. There are 4 cases to consider:
1078            //           odst       | osrc     | sz
1079            //   k, v  | 1          | 0        | size(sk) + size(sv)
1080            //   k, _  | 1          | 0        | size(sk)
1081            //   _, v  | 1+size(dk) | size(sk) | size(sv)
1082            //   _, _  | 1+size(dk) | size(sk) | 0
1083
1084            // get the source key and value size.  Note the source types
1085            // may be different than the 3-tuple types, but if this is the
1086            // case then the source is assignable to the destination.
1087            theMap := instr.Iter.(*ssa.Range).X
1088            tMap := theMap.Type().Underlying().(*types.Map)
1089
1090            sksize := a.sizeof(tMap.Key())
1091            svsize := a.sizeof(tMap.Elem())
1092
1093            // get the key size of the destination tuple.
1094            tTuple := instr.Type().(*types.Tuple)
1095            dksize := a.sizeof(tTuple.At(1).Type())
1096
1097            // Load from the map's (k,v) into the tuple's (ok, k, v).
1098            osrc := uint32(0// offset within map object
1099            odst := uint32(1// offset within tuple (initially just after 'ok bool')
1100            sz := uint32(0)   // amount to copy
1101
1102            // Is key valid?
1103            if tTuple.At(1).Type() != tInvalid {
1104                sz += sksize
1105            } else {
1106                odst += dksize
1107                osrc += sksize
1108            }
1109
1110            // Is value valid?
1111            if tTuple.At(2).Type() != tInvalid {
1112                sz += svsize
1113            }
1114
1115            a.genLoad(cgna.valueNode(instr)+nodeid(odst), theMaposrcsz)
1116        }
1117
1118    case *ssa.Lookup:
1119        if tMapok := instr.X.Type().Underlying().(*types.Map); ok {
1120            // CommaOk can be ignored: field 0 is a no-op.
1121            ksize := a.sizeof(tMap.Key())
1122            vsize := a.sizeof(tMap.Elem())
1123            a.genLoad(cgna.valueNode(instr), instr.Xksizevsize)
1124        }
1125
1126    case *ssa.MapUpdate:
1127        tmap := instr.Map.Type().Underlying().(*types.Map)
1128        ksize := a.sizeof(tmap.Key())
1129        vsize := a.sizeof(tmap.Elem())
1130        a.genStore(cgninstr.Mapa.valueNode(instr.Key), 0ksize)
1131        a.genStore(cgninstr.Mapa.valueNode(instr.Value), ksizevsize)
1132
1133    case *ssa.Panic:
1134        a.copy(a.panicNodea.valueNode(instr.X), 1)
1135
1136    default:
1137        panic(fmt.Sprintf("unimplemented: %T"instr))
1138    }
1139}
1140
1141func (a *analysismakeCGNode(fn *ssa.Functionobj nodeidcallersite *callsite) *cgnode {
1142    cgn := &cgnode{fnfnobjobjcallersitecallersite}
1143    a.cgnodes = append(a.cgnodescgn)
1144    return cgn
1145}
1146
1147// genRootCalls generates the synthetic root of the callgraph and the
1148// initial calls from it to the analysis scope, such as main, a test
1149// or a library.
1150func (a *analysisgenRootCalls() *cgnode {
1151    r := a.prog.NewFunction("<root>"new(types.Signature), "root of callgraph")
1152    root := a.makeCGNode(r0nil)
1153
1154    // TODO(adonovan): make an ssa utility to construct an actual
1155    // root function so we don't need to special-case site-less
1156    // call edges.
1157
1158    // For each main package, call main.init(), main.main().
1159    for _mainPkg := range a.config.Mains {
1160        main := mainPkg.Func("main")
1161        if main == nil {
1162            panic(fmt.Sprintf("%s has no main function"mainPkg))
1163        }
1164
1165        targets := a.addOneNode(main.Signature"root.targets"nil)
1166        site := &callsite{targetstargets}
1167        root.sites = append(root.sitessite)
1168        for _fn := range [2]*ssa.Function{mainPkg.Func("init"), main} {
1169            if a.log != nil {
1170                fmt.Fprintf(a.log"\troot call to %s:\n"fn)
1171            }
1172            a.copy(targetsa.valueNode(fn), 1)
1173        }
1174    }
1175
1176    return root
1177}
1178
1179// genFunc generates constraints for function fn.
1180func (a *analysisgenFunc(cgn *cgnode) {
1181    fn := cgn.fn
1182
1183    impl := a.findIntrinsic(fn)
1184
1185    if a.log != nil {
1186        fmt.Fprintf(a.log"\n\n==== Generating constraints for %s, %s\n"cgncgn.contour())
1187
1188        // Hack: don't display body if intrinsic.
1189        if impl != nil {
1190            fn2 := *cgn.fn // copy
1191            fn2.Locals = nil
1192            fn2.Blocks = nil
1193            fn2.WriteTo(a.log)
1194        } else {
1195            cgn.fn.WriteTo(a.log)
1196        }
1197    }
1198
1199    if impl != nil {
1200        impl(acgn)
1201        return
1202    }
1203
1204    if fn.Blocks == nil {
1205        // External function with no intrinsic treatment.
1206        // We'll warn about calls to such functions at the end.
1207        return
1208    }
1209
1210    if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 {
1211        // Body of generic function.
1212        // We'll warn about calls to such functions at the end.
1213        return
1214    }
1215
1216    if strings.HasPrefix(fn.Synthetic"instantiation wrapper ") {
1217        // instantiation wrapper of a generic function.
1218        // These may contain type coercions which are not currently supported.
1219        // We'll warn about calls to such functions at the end.
1220        return
1221    }
1222
1223    if a.log != nil {
1224        fmt.Fprintln(a.log"; Creating nodes for local values")
1225    }
1226
1227    a.localval = make(map[ssa.Value]nodeid)
1228    a.localobj = make(map[ssa.Value]nodeid)
1229
1230    // The value nodes for the params are in the func object block.
1231    params := a.funcParams(cgn.obj)
1232    for _p := range fn.Params {
1233        a.setValueNode(pparamscgn)
1234        params += nodeid(a.sizeof(p.Type()))
1235    }
1236
1237    // Free variables have global cardinality:
1238    // the outer function sets them with MakeClosure;
1239    // the inner function accesses them with FreeVar.
1240    //
1241    // TODO(adonovan): treat free vars context-sensitively.
1242
1243    // Create value nodes for all value instructions
1244    // since SSA may contain forward references.
1245    var space [10]*ssa.Value
1246    for _b := range fn.Blocks {
1247        for _instr := range b.Instrs {
1248            switch instr := instr.(type) {
1249            case *ssa.Range:
1250                // do nothing: it has a funky type,
1251                // and *ssa.Next does all the work.
1252
1253            case ssa.Value:
1254                var comment string
1255                if a.log != nil {
1256                    comment = instr.Name()
1257                }
1258                id := a.addNodes(instr.Type(), comment)
1259                a.setValueNode(instridcgn)
1260            }
1261
1262            // Record all address-taken functions (for presolver).
1263            rands := instr.Operands(space[:0])
1264            if callok := instr.(ssa.CallInstruction); ok && !call.Common().IsInvoke() {
1265                // Skip CallCommon.Value in "call" mode.
1266                // TODO(adonovan): fix: relies on unspecified ordering.  Specify it.
1267                rands = rands[1:]
1268            }
1269            for _rand := range rands {
1270                if atfok := (*rand).(*ssa.Function); ok {
1271                    a.atFuncs[atf] = true
1272                }
1273            }
1274        }
1275    }
1276
1277    // Generate constraints for instructions.
1278    for _b := range fn.Blocks {
1279        for _instr := range b.Instrs {
1280            a.genInstr(cgninstr)
1281        }
1282    }
1283
1284    a.localval = nil
1285    a.localobj = nil
1286}
1287
1288// genMethodsOf generates nodes and constraints for all methods of type T.
1289func (a *analysisgenMethodsOf(T types.Type) {
1290    itf := isInterface(T)
1291
1292    // TODO(adonovan): can we skip this entirely if itf is true?
1293    // I think so, but the answer may depend on reflection.
1294    mset := a.prog.MethodSets.MethodSet(T)
1295    for in := 0mset.Len(); i < ni++ {
1296        m := a.prog.MethodValue(mset.At(i))
1297        a.valueNode(m)
1298
1299        if !itf {
1300            // Methods of concrete types are address-taken functions.
1301            a.atFuncs[m] = true
1302        }
1303    }
1304}
1305
1306// generate generates offline constraints for the entire program.
1307func (a *analysisgenerate() {
1308    start("Constraint generation")
1309    if a.log != nil {
1310        fmt.Fprintln(a.log"==== Generating constraints")
1311    }
1312
1313    // Create a dummy node since we use the nodeid 0 for
1314    // non-pointerlike variables.
1315    a.addNodes(tInvalid"(zero)")
1316
1317    // Create the global node for panic values.
1318    a.panicNode = a.addNodes(tEface"panic")
1319
1320    // Create nodes and constraints for all methods of reflect.rtype.
1321    // (Shared contours are used by dynamic calls to reflect.Type
1322    // methods---typically just String().)
1323    if rtype := a.reflectRtypePtrrtype != nil {
1324        a.genMethodsOf(rtype)
1325    }
1326
1327    root := a.genRootCalls()
1328
1329    if a.config.BuildCallGraph {
1330        a.result.CallGraph = callgraph.New(root.fn)
1331    }
1332
1333    // Create nodes and constraints for all methods of all types
1334    // that are dynamically accessible via reflection or interfaces.
1335    for _T := range a.prog.RuntimeTypes() {
1336        a.genMethodsOf(T)
1337    }
1338
1339    // Generate constraints for functions as they become reachable
1340    // from the roots.  (No constraints are generated for functions
1341    // that are dead in this analysis scope.)
1342    for len(a.genq) > 0 {
1343        cgn := a.genq[0]
1344        a.genq = a.genq[1:]
1345        a.genFunc(cgn)
1346    }
1347
1348    // The runtime magically allocates os.Args; so should we.
1349    if os := a.prog.ImportedPackage("os"); os != nil {
1350        // In effect:  os.Args = new([1]string)[:]
1351        T := types.NewSlice(types.Typ[types.String])
1352        obj := a.addNodes(sliceToArray(T), "<command-line args>")
1353        a.endObject(objnil"<command-line args>")
1354        a.addressOf(Ta.objectNode(nilos.Var("Args")), obj)
1355    }
1356
1357    // Discard generation state, to avoid confusion after node renumbering.
1358    a.panicNode = 0
1359    a.globalval = nil
1360    a.localval = nil
1361    a.localobj = nil
1362
1363    stop("Constraint generation")
1364}
1365
MembersX
analysis.addOneNode.a
analysis.genConv
analysis.makeCGNode.callersite
analysis.genInvokeReflectType
analysis.genInvokeReflectType.RangeStmt_22054.arg
analysis.genRootCalls.r
analysis.genRootCalls.RangeStmt_35111.BlockStmt.site
analysis.setValueNode.RangeStmt_3278.query
analysis.setValueNode.RangeStmt_3278.BlockStmt.nid
analysis.genInstr.BlockStmt.RangeStmt_29500.BlockStmt.elemSize
analysis.genInstr.BlockStmt.RangeStmt_31312.i
analysis.makeCGNode.cgn
analysis.addNodes.RangeStmt_1197.fi
analysis.makeTagged.obj
analysis.genStaticCall.a
analysis.genStaticCall.site
analysis.genRootCalls.a
analysis.genFunc.RangeStmt_38242.b
analysis.setValueNode.BlockStmt.t
analysis.valueNode.BlockStmt.obj
analysis.genLoad.cgn
analysis.genLoad.obj
analysis.makeFunctionObject.fn
analysis.load.sizeof
analysis.shouldUseContext.fn
analysis.genInvoke.caller
analysis.genInvokeReflectType.a
analysis.addressOf
analysis.genCall
analysis.genStore.offset
analysis.typeAssert.dst
analysis.genInstr.BlockStmt.RangeStmt_31312.b
analysis.genInstr.BlockStmt.BlockStmt.odst
analysis.makeRtype.obj
analysis.genInvokeReflectType.RangeStmt_22054.BlockStmt.sz
analysis.genRootCalls.RangeStmt_35111.BlockStmt.RangeStmt_35408.fn
analysis.makeTagged.a
analysis.genInvokeReflectType.RangeStmt_22054.i
analysis.genLoad
analysis.addOneNode.subelement
analysis.isTaggedObject.a
analysis.copyElems.a
analysis.endObject.obj
analysis.endObject.data
analysis.load.dst
analysis.typeAssert.T
analysis.genConv.tDst
analysis.objectNode.a
analysis.genInstr.BlockStmt.RangeStmt_31062.e
analysis.genFunc.RangeStmt_37367.BlockStmt.RangeStmt_37399.BlockStmt.BlockStmt.comment
analysis.addNodes.a
analysis.rtypeTaggedValue.obj
analysis.addressOf.T
analysis.genConv.BlockStmt.BlockStmt.BlockStmt.obj
analysis.genInvoke.call
analysis.genStore.a
analysis.genRootCalls.RangeStmt_35111.BlockStmt.targets
analysis.setValueNode.a
analysis.makeFunctionObject.obj
analysis.store.i
analysis.addConstraint.a
analysis.genCall.a
analysis.genOffsetAddr.cgn
analysis.genOffsetAddr.offset
analysis.copyElems.typ
analysis.genAppend.tArray
analysis.shouldUseContext.a
analysis.genStaticCall.RangeStmt_18345.BlockStmt.sz
analysis.genInstr.BlockStmt.BlockStmt.osrc
analysis.genRootCalls.RangeStmt_35111.BlockStmt.main
analysis.genBuiltinCall
analysis.setValueNode.cgn
analysis.makeFunctionObject.cgn
analysis.makeTagged.cgn
analysis.rtypeTaggedValue
analysis.valueOffsetNode.index
analysis.copy.dst
analysis.copyElems.src
analysis.genStaticCall.args
analysis.genStore.val
analysis.generate.root
analysis.genConv.res
analysis.shouldUseContext.RangeStmt_16524.instr
analysis.genInstr.BlockStmt.RangeStmt_29500.st
analysis.genMethodsOf.a
analysis.genMethodsOf.n
analysis.makeRtype.id
analysis.offsetAddr.T
analysis.typeAssert.exact
analysis.genBuiltinCall.cgn
analysis.genInvoke.result
analysis.objectNode.BlockStmt.BlockStmt.xobj
analysis.genInstr.BlockStmt.BlockStmt.sz
analysis.genFunc.RangeStmt_37367.BlockStmt.RangeStmt_37399.instr
analysis.valueNode
analysis.valueNode.BlockStmt.comment
analysis.taggedValue.indirect
analysis.genAppend.w
analysis.genStore.ptr
analysis.genInstr.BlockStmt.prefix
analysis.genFunc.a
analysis.funcResults
analysis.genInvokeReflectType.targets
analysis.objectNode.BlockStmt.BlockStmt.elem
analysis.generate.BlockStmt.T
analysis.nextNode
analysis.makeTagged.typ
analysis.funcResults.id
analysis.copyElems.tmp
analysis.genStaticCall.sig
analysis.genInstr
analysis.generate.RangeStmt_39783.T
analysis.genMethodsOf.i
analysis.addOneNode
analysis.makeFunctionObject.a
analysis.makeRtype.v
analysis.copyElems
analysis.genBuiltinCall.instr
analysis.objectNode.v
analysis.genInstr.instr
analysis.generate.a
analysis.generate.BlockStmt.obj
analysis.setValueNode
analysis.taggedValue.tDyn
analysis.funcParams.a
analysis.genConv.a
analysis.genAppend.instr
analysis.genInstr.BlockStmt.BlockStmt.ksize
analysis.generate
analysis.endObject.cgn
analysis.taggedValue.a
analysis.taggedValue.v
analysis.genStaticCall.BlockStmt.ret
analysis.genInvokeReflectType.obj
analysis.genLoad.offset
analysis.genInstr.BlockStmt.RangeStmt_29883.BlockStmt.sz
analysis.genInstr.a
analysis.makeFunctionObject.recv
analysis.rtypeTaggedValue._
analysis.load.src
analysis.addConstraint.c
analysis.copyElems.cgn
analysis.copyElems.sz
analysis.genStaticCall.BlockStmt.sz
analysis.genInstr.BlockStmt.BlockStmt.theMap
analysis.genInstr.BlockStmt.recv
analysis.genMethodsOf.BlockStmt.m
analysis.addressOf.id
analysis.genInvoke.block
analysis.genCall.site
analysis.genStore
analysis.genInstr.BlockStmt.vsize
analysis.genMethodsOf
analysis.addNodes.id
analysis.valueOffsetNode.id
analysis.genDynamicCall.site
analysis.genDynamicCall.result
analysis.genInvokeReflectType.fn
analysis.genInstr.BlockStmt.BlockStmt.tElem
analysis.genFunc.RangeStmt_36930.p
analysis.addNodes
analysis.setValueNode.RangeStmt_3278.BlockStmt.t
analysis.endObject.a
analysis.valueNode.v
analysis.taggedValue
analysis.genDynamicCall.RangeStmt_19138.BlockStmt.sz
analysis.genCall.result
analysis.makeCGNode.obj
analysis.addOneNode.id
analysis.makeFunctionObject
analysis.genBuiltinCall.BlockStmt.tElem
analysis.genInvokeReflectType.call
analysis.taggedValue.flags
analysis.makeCGNode.fn
analysis.genMethodsOf.T
analysis.taggedValue.obj
analysis.genInvokeReflectType.result
analysis.objectNode
analysis.genRootCalls.root
analysis.genFunc.RangeStmt_37367.b
analysis.load
analysis.genConv.cgn
analysis.genDynamicCall.offset
analysis.genInvoke.p
analysis.genMethodsOf.itf
analysis.nextNode.a
analysis.endObject.o
analysis.copy.src
analysis.typeAssert.a
analysis.genInvoke.sig
analysis.genOffsetAddr
analysis.genInstr.BlockStmt.BlockStmt.svsize
analysis.genAppend
analysis.genFunc.RangeStmt_38242.BlockStmt.RangeStmt_38274.instr
analysis.genConv.tSrc
analysis.genCall.caller
analysis.genStore.sizeof
analysis.addOneNode.typ
analysis.genDynamicCall
analysis.makeTagged.data
analysis.offsetAddr.dst
analysis.genStaticCall.RangeStmt_18345.arg
analysis.genOffsetAddr.v
analysis.genCall.call
analysis.store.dst
analysis.copyElems.dst
analysis.genDynamicCall.sig
analysis.genDynamicCall.RangeStmt_19138.i
analysis.genInvoke.site
analysis.genInvoke.i
analysis.genInvoke.BlockStmt.sz
analysis.genInstr.BlockStmt.results
analysis.makeRtype
analysis.valueOffsetNode
analysis.genInvokeReflectType.sig
analysis.genInstr.BlockStmt.ksize
analysis.genInstr.BlockStmt.BlockStmt.vsize
analysis.valueNode.a
analysis.addressOf.obj
analysis.offsetAddr.offset
analysis.genAppend.z
analysis.genStaticCall.obj
analysis.genInvokeReflectType.recv
analysis.genLoad.a
analysis.genFunc.cgn
analysis.genFunc.RangeStmt_37367.BlockStmt.RangeStmt_37399.BlockStmt.rands
analysis.objectNode.cgn
analysis.genStore.cgn
analysis.makeCGNode.a
analysis.addOneNode.comment
analysis.makeRtype.a
analysis.addressOf.a
analysis.shouldUseContext
analysis.objectNode.BlockStmt.BlockStmt.id
analysis.makeCGNode
analysis.rtypeTaggedValue.tDyn
analysis.store
analysis.genStaticCall.params
analysis.genInvokeReflectType.caller
analysis.genFunc.impl
analysis.generate.os
typeparams
analysis.load.offset
analysis.genInvokeReflectType.params
analysis.genFunc.RangeStmt_37367.BlockStmt.RangeStmt_37399.BlockStmt.BlockStmt.id
analysis.addNodes.typ
analysis.makeFunctionObject.sig
analysis.isTaggedObject.obj
analysis.genConv.conv
analysis.genDynamicCall.a
analysis.genLoad.ptr
analysis.genInstr.BlockStmt.BlockStmt.sksize
analysis.genStaticCall.RangeStmt_18345.i
analysis.genLoad.sizeof
analysis.genOffsetAddr.ptr
analysis.genOffsetAddr.obj
analysis.genFunc.space
analysis.makeFunctionObject.callersite
analysis.makeRtype.T
analysis.typeAssert
analysis.objectNode.BlockStmt.BlockStmt.x
analysis.genOffsetAddr.a
analysis.genFunc
analysis.genRootCalls.RangeStmt_35111.mainPkg
analysis.genStaticCall.fn
analysis.genInvoke.a
analysis.genInvoke.n
analysis.genFunc.fn
analysis.makeTagged
analysis.funcParams
analysis.genStore.obj
analysis.copy.sizeof
analysis.offsetAddr
analysis.genBuiltinCall.BlockStmt.v
analysis.genStaticCall
analysis.genInvoke.r
analysis.objectNode.BlockStmt.BlockStmt.tConc
analysis.genFunc.params
analysis.setValueNode.v
analysis.setValueNode.id
analysis.valueOffsetNode.a
analysis.genStaticCall.call
analysis.genInvokeReflectType.rtype
analysis.genInstr.BlockStmt.sz
analysis.generate.rtype
analysis.genBuiltinCall.a
analysis.genStaticCall.BlockStmt.dotdotdot
analysis.genOffsetAddr.dst
analysis.copy.i
analysis.load.a
analysis.genAppend.a
analysis.genStaticCall.result
analysis.genInvokeReflectType.site
analysis.rtypeTaggedValue.a
analysis.isTaggedObject
analysis.funcParams.id
analysis.genCall.v
analysis.genLoad.result
analysis.genMethodsOf.mset
analysis.genRootCalls
analysis.store.a
analysis.store.src
analysis.offsetAddr.src
analysis.typeAssert.src
analysis.genDynamicCall.caller
analysis.genDynamicCall.RangeStmt_19138.arg
analysis.genInstr.cgn
analysis.copy.a
analysis.genDynamicCall.call
analysis.genInstr.BlockStmt.RangeStmt_29883.r
analysis.endObject
analysis.funcResults.a
analysis.offsetAddr.a
analysis.genInstr.BlockStmt.BlockStmt.dksize
analysis.genFunc.RangeStmt_37367.BlockStmt.RangeStmt_37399.BlockStmt.RangeStmt_38075.rand
analysis.addNodes.comment
analysis.endObject.size
analysis.rtypeTaggedValue.t
analysis.valueOffsetNode.v
analysis.store.sizeof
analysis.addConstraint
analysis.load.i
analysis.store.offset
analysis.genAppend.cgn
analysis.genBuiltinCall.call
analysis.genInvoke
analysis.copy
analysis.genStaticCall.caller
analysis.genCall.instr
Members
X