// makeLen returns the len builtin specialized to type func(T)int. func makeLen(T types.Type) *Builtin { lenParams := types.NewTuple(anonVar(T)) return &Builtin{ name: "len", sig: types.NewSignature(nil, nil, lenParams, lenResults, false), } }
func (p *importer) signature() *types.Signature { var recv *types.Var if p.int() != 0 { recv = p.param() } return types.NewSignature(nil, recv, p.tuple(), p.tuple(), p.int() != 0) }
// interfaceMethod returns a function and receiver pointer for the specified // interface and method pair. func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { llitab := fr.builder.CreateExtractValue(lliface, 0, "") recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) methodset := fr.types.MethodSet(ifacety) // TODO(axw) cache ordered method index index := -1 for i, m := range orderedMethodSet(methodset) { if m.Obj() == method { index = i break } } if index == -1 { panic("could not find method index") } llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") // Skip runtime type pointer. llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), }, "") llifn := fr.builder.CreateLoad(llifnptr, "") // Replace receiver type with unsafe.Pointer. recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) sig := method.Type().(*types.Signature) sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) fn = newValue(llifn, sig) return }
func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata { // If there's a receiver change the receiver to an // additional (first) parameter, and take the value of // the resulting signature instead. if recv := t.Recv(); recv != nil { params := t.Params() paramvars := make([]*types.Var, int(params.Len()+1)) paramvars[0] = recv for i := 0; i < int(params.Len()); i++ { paramvars[i+1] = params.At(i) } params = types.NewTuple(paramvars...) t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) return d.typeDebugDescriptor(t, name) } if dt, ok := d.types.At(t).(llvm.Metadata); ok { return dt } var returnType llvm.Metadata results := t.Results() switch n := results.Len(); n { case 0: returnType = d.DIType(nil) // void case 1: returnType = d.DIType(results.At(0).Type()) default: fields := make([]*types.Var, results.Len()) for i := range fields { f := results.At(i) // Structs may not have multiple fields // with the same name, excepting "_". if f.Name() == "" { f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type()) } fields[i] = f } returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "") } var paramTypes []llvm.Metadata params := t.Params() if params != nil && params.Len() > 0 { paramTypes = make([]llvm.Metadata, params.Len()+1) paramTypes[0] = returnType for i := range paramTypes[1:] { paramTypes[i+1] = d.DIType(params.At(i).Type()) } } else { paramTypes = []llvm.Metadata{returnType} } // TODO(axw) get position of type definition for File field return d.builder.CreateSubroutineType(llvm.DISubroutineType{ Parameters: paramTypes, }) }
// newMethod creates a new method of the specified name, package and receiver type. func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function { // TODO(adonovan): fix: hack: currently the only part of Signature // that is needed is the "pointerness" of Recv.Type, and for // now, we'll set it to always be false since we're only // concerned with rtype. Encapsulate this better. sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) fn := pkg.Prog.NewFunction(name, sig, "fake reflect method") fn.Pkg = pkg return fn }
// FindTests returns the list of packages that define at least one Test, // Example or Benchmark function (as defined by "go test"), and the // lists of all such functions. // func FindTests(pkgs []*Package) (testpkgs []*Package, tests, benchmarks, examples []*Function) { if len(pkgs) == 0 { return } prog := pkgs[0].Prog // The first two of these may be nil: if the program doesn't import "testing", // it can't contain any tests, but it may yet contain Examples. var testSig *types.Signature // func(*testing.T) var benchmarkSig *types.Signature // func(*testing.B) var exampleSig = types.NewSignature(nil, nil, nil, nil, false) // func() // Obtain the types from the parameters of testing.Main(). if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil { params := testingPkg.Func("Main").Signature.Params() testSig = funcField(params.At(1).Type()) benchmarkSig = funcField(params.At(2).Type()) } seen := make(map[*Package]bool) for _, pkg := range pkgs { if pkg.Prog != prog { panic("wrong Program") } // TODO(adonovan): use a stable order, e.g. lexical. for _, mem := range pkg.Members { if f, ok := mem.(*Function); ok && ast.IsExported(f.Name()) && strings.HasSuffix(prog.Fset.Position(f.Pos()).Filename, "_test.go") { switch { case testSig != nil && isTestSig(f, "Test", testSig): tests = append(tests, f) case benchmarkSig != nil && isTestSig(f, "Benchmark", benchmarkSig): benchmarks = append(benchmarks, f) case isTestSig(f, "Example", exampleSig): examples = append(examples, f) default: continue } if !seen[pkg] { seen[pkg] = true testpkgs = append(testpkgs, pkg) } } } } return }
// Signature = Parameters [ Result ] . // Result = Type | Parameters . // func (p *parser) parseSignature(recv *types.Var) *types.Signature { params, isVariadic := p.parseParameters() // optional result type var results []*types.Var if p.tok == '(' { var variadic bool results, variadic = p.parseParameters() if variadic { p.error("... not permitted on result type") } } return types.NewSignature(nil, recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic) }
// NamedType = TypeName Type { Method } . // Method = "func" "(" Param ")" Name ParamList ResultList ";" . func (p *parser) parseNamedType(n int) types.Type { obj := p.parseTypeName() pkg := obj.Pkg() typ := obj.Type() p.typeMap[n] = typ nt, ok := typ.(*types.Named) if !ok { // This can happen for unsafe.Pointer, which is a TypeName holding a Basic type. pt := p.parseType(pkg) if pt != typ { p.error("unexpected underlying type for non-named TypeName") } return typ } underlying := p.parseType(pkg) if nt.Underlying() == nil { nt.SetUnderlying(underlying.Underlying()) } for p.tok == scanner.Ident { // collect associated methods p.expectKeyword("func") p.expect('(') receiver, _ := p.parseParam(pkg) p.expect(')') name := p.parseName() params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) p.expect(';') sig := types.NewSignature(pkg.Scope(), receiver, params, results, isVariadic) nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) } return nt }
// FunctionType = ParamList ResultList . func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature { params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) return types.NewSignature(pkg.Scope(), nil, params, results, isVariadic) }
// makeWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // // The resulting method's receiver type is meth.Recv(). // // This function is versatile but quite subtle! Consider the // following axes of variation when making changes: // - optional receiver indirection // - optional implicit field selections // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. // // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) // func makeWrapper(prog *Program, sel *types.Selection) *Function { obj := sel.Obj().(*types.Func) // the declared function sig := sel.Type().(*types.Signature) // type of this wrapper var recv *types.Var // wrapper's receiver or thunk's params[0] name := obj.Name() var description string var start int // first regular param if sel.Kind() == types.MethodExpr { name += "$thunk" description = "thunk" recv = sig.Params().At(0) start = 1 } else { description = "wrapper" recv = sig.Recv() } description = fmt.Sprintf("%s for %s", description, sel.Obj()) if prog.mode&LogSource != 0 { defer logStack("make %s to (%s)", description, recv.Type())() } fn := &Function{ name: name, method: sel, object: obj, Signature: sig, Synthetic: description, Prog: prog, pos: obj.Pos(), } fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) indices := sel.Index() var v Value = fn.Locals[0] // spilled receiver if isPointer(sel.Recv()) { v = emitLoad(fn, v) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" if len(indices) == 1 && !isPointer(recvType(obj)) { var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", sig: types.NewSignature(nil, nil, types.NewTuple(anonVar(sel.Recv()), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(sel.Recv())), false), } c.Call.Args = []Value{ v, stringConst(deref(sel.Recv()).String()), stringConst(sel.Obj().Name()), } c.setType(v.Type()) v = fn.emit(&c) } } // Invariant: v is a pointer, either // value of *A receiver param, or // address of A spilled receiver. // We use pointer arithmetic (FieldAddr possibly followed by // Load) in preference to value extraction (Field possibly // preceded by Load). v = emitImplicitSelections(fn, v, indices[:len(indices)-1]) // Invariant: v is a pointer, either // value of implicit *C field, or // address of implicit C field. var c Call if r := recvType(obj); !isInterface(r) { // concrete method if !isPointer(r) { v = emitLoad(fn, v) } c.Call.Value = prog.declaredFunc(obj) c.Call.Args = append(c.Call.Args, v) } else { c.Call.Method = obj c.Call.Value = emitLoad(fn, v) } for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c) fn.finishBody() return fn }
func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignature(nil, recv, s.Params(), s.Results(), s.Variadic()) }