// 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 alloc, ok := v.(*Alloc); ok && escaping { alloc.Heap = true } return v // function-local var (address) } // Definition must be in an enclosing function; // plumb it through intervening closures. if f.parent == nil { panic("no Value for type.Object " + obj.Name()) } outer := f.parent.lookup(obj, true) // escaping v := &FreeVar{ name: obj.Name(), typ: outer.Type(), pos: outer.Pos(), outer: outer, parent: f, } f.objects[obj] = v f.FreeVars = append(f.FreeVars, v) return v }
// isPackageLevel reports whether obj is a package-level object. func isPackageLevel(obj types.Object) bool { // TODO(adonovan): fix go/types bug: // obj.Parent().Parent() == obj.Pkg().Scope() // doesn't work because obj.Parent() gets mutated during // dot-imports. return obj.Pkg().Scope().Lookup(obj.Name()) == obj }
func (f *Function) addParamObj(obj types.Object) *Parameter { name := obj.Name() if name == "" { name = fmt.Sprintf("arg%d", len(f.Params)) } param := f.addParam(name, obj.Type(), obj.Pos()) param.object = obj return param }
// addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent lifting will eliminate spills where possible. // func (f *Function) addSpilledParam(obj types.Object) { param := f.addParamObj(obj) spill := &Alloc{Comment: obj.Name()} spill.setType(types.NewPointer(obj.Type())) spill.setPos(obj.Pos()) f.objects[obj] = spill f.Locals = append(f.Locals, spill) f.emit(spill) f.emit(&Store{Addr: spill, Val: param}) }
// memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax // tree (for funcs and vars only); it will be used during the build // phase. // func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { name := obj.Name() switch obj := obj.(type) { case *types.TypeName: pkg.Members[name] = &Type{ object: obj, pkg: pkg, } case *types.Const: c := &NamedConst{ object: obj, Value: NewConst(obj.Val(), obj.Type()), pkg: pkg, } pkg.values[obj] = c.Value pkg.Members[name] = c case *types.Var: g := &Global{ Pkg: pkg, name: name, object: obj, typ: types.NewPointer(obj.Type()), // address pos: obj.Pos(), } pkg.values[obj] = g pkg.Members[name] = g case *types.Func: fn := &Function{ name: name, object: obj, Signature: obj.Type().(*types.Signature), syntax: syntax, pos: obj.Pos(), Pkg: pkg, Prog: pkg.Prog, } if syntax == nil { fn.Synthetic = "loaded from gc object file" } pkg.values[obj] = fn if fn.Signature.Recv() == nil { pkg.Members[name] = fn // package-level function } default: // (incl. *types.Package) panic("unexpected Object type: " + obj.String()) } }
// 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. // func (f *Function) addNamedLocal(obj types.Object) *Alloc { l := f.addLocal(obj.Type(), obj.Pos()) l.Comment = obj.Name() f.objects[obj] = l return l }