// lookup returns the address of the named variable identified by obj // that is local to function f or one of its enclosing functions. // If escaping, the reference comes from a potentially escaping pointer // expression and the referent must be heap-allocated. // func (f *Function) lookup(obj types.Object, escaping bool) Value { if v, ok := f.objects[obj]; ok { if escaping { // Walk up the chain of Captures. x := v for { if c, ok := x.(*Capture); ok { x = c.Outer } else { break } } // By construction, all captures are ultimately Allocs in the // naive SSA form. Parameters are pre-spilled to the stack. x.(*Alloc).Heap = true } return v // function-local var (address) } // Definition must be in an enclosing function; // plumb it through intervening closures. if f.Enclosing == nil { panic("no Value for type.Object " + obj.GetName()) } v := &Capture{f.Enclosing.lookup(obj, true)} // escaping f.objects[obj] = v f.FreeVars = append(f.FreeVars, v) return v }
// addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent registerization will eliminate spills where possible. // func (f *Function) addSpilledParam(obj types.Object) { name := obj.GetName() param := f.addParam(name, obj.GetType()) spill := &Alloc{ Name_: name + "~", // "~" means "spilled" Type_: pointer(obj.GetType()), } f.objects[obj] = spill f.Locals = append(f.Locals, spill) f.emit(spill) f.emit(&Store{Addr: spill, Val: param}) }
// addNamedLocal creates a local variable, adds it to function f and // returns it. Its name and type are taken from obj. Subsequent // calls to f.lookup(obj) will return the same local. // // Precondition: f.syntax != nil (i.e. a Go source function). // func (f *Function) addNamedLocal(obj types.Object) *Alloc { l := f.addLocal(obj.GetType()) l.Name_ = obj.GetName() f.objects[obj] = l return l }