func TestStdlib(t *testing.T) { // Load, parse and type-check the program. t0 := time.Now() alloc0 := bytesAllocated() // Load, parse and type-check the program. ctxt := build.Default // copy ctxt.GOPATH = "" // disable GOPATH conf := loader.Config{ SourceImports: true, Build: &ctxt, } if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil { t.Errorf("FromArgs failed: %v", err) return } iprog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } t1 := time.Now() alloc1 := bytesAllocated() // Create SSA packages. var mode ssa2.BuilderMode // Comment out these lines during benchmarking. Approx SSA build costs are noted. mode |= ssa2.SanityCheckFunctions // + 2% space, + 4% time mode |= ssa2.GlobalDebug // +30% space, +18% time prog := ssa2.Create(iprog, mode) t2 := time.Now() // Build SSA. prog.BuildAll() t3 := time.Now() alloc3 := bytesAllocated() numPkgs := len(prog.AllPackages()) if want := 140; numPkgs < want { t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) } // Keep iprog reachable until after we've measured memory usage. if len(iprog.AllPackages) == 0 { print() // unreachable } allFuncs := ssautil.AllFunctions(prog) // Check that all non-synthetic functions have distinct names. byName := make(map[string]*ssa2.Function) for fn := range allFuncs { if fn.Synthetic == "" { str := fn.String() prev := byName[str] byName[str] = fn if prev != nil { t.Errorf("%s: duplicate function named %s", prog.Fset.Position(fn.Pos()), str) t.Errorf("%s: (previously defined here)", prog.Fset.Position(prev.Pos())) } } } // Dump some statistics. var numInstrs int for fn := range allFuncs { for _, b := range fn.Blocks { numInstrs += len(b.Instrs) } } // determine line count var lineCount int prog.Fset.Iterate(func(f *token.File) bool { lineCount += f.LineCount() return true }) // NB: when benchmarking, don't forget to clear the debug + // sanity builder flags for better performance. t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) t.Log("#Source lines: ", lineCount) t.Log("Load/parse/typecheck: ", t1.Sub(t0)) t.Log("SSA create: ", t2.Sub(t1)) t.Log("SSA build: ", t3.Sub(t2)) // SSA stats: t.Log("#Packages: ", numPkgs) t.Log("#Functions: ", len(allFuncs)) t.Log("#Instructions: ", numInstrs) t.Log("#MB AST+types: ", int64(alloc1-alloc0)/1e6) t.Log("#MB SSA: ", int64(alloc3-alloc1)/1e6) }
// TestSyntheticFuncs checks that the expected synthetic functions are // created, reachable, and not duplicated. func TestSyntheticFuncs(t *testing.T) { const input = `package P type T int func (T) f() int func (*T) g() int var ( // thunks a = T.f b = T.f c = (struct{T}).f d = (struct{T}).f e = (*T).g f = (*T).g g = (struct{*T}).g h = (struct{*T}).g // bounds i = T(0).f j = T(0).f k = new(T).g l = new(T).g // wrappers m interface{} = struct{T}{} n interface{} = struct{T}{} o interface{} = struct{*T}{} p interface{} = struct{*T}{} q interface{} = new(struct{T}) r interface{} = new(struct{T}) s interface{} = new(struct{*T}) t interface{} = new(struct{*T}) ) ` // Parse var conf loader.Config f, err := conf.ParseFile("<input>", input) if err != nil { t.Fatalf("parse: %v", err) } conf.CreateFromFiles(f.Name.Name, f) // Load iprog, err := conf.Load() if err != nil { t.Fatalf("Load: %v", err) } // Create and build SSA prog := ssa2.Create(iprog, 0) prog.BuildAll() // Enumerate reachable synthetic functions want := map[string]string{ "(*P.T).g$bound": "bound method wrapper for func (*P.T).g() int", "(P.T).f$bound": "bound method wrapper for func (P.T).f() int", "(*P.T).g$thunk": "thunk for func (*P.T).g() int", "(P.T).f$thunk": "thunk for func (P.T).f() int", "(struct{*P.T}).g$thunk": "thunk for func (*P.T).g() int", "(struct{P.T}).f$thunk": "thunk for func (P.T).f() int", "(*P.T).f": "wrapper for func (P.T).f() int", "(*struct{*P.T}).f": "wrapper for func (P.T).f() int", "(*struct{*P.T}).g": "wrapper for func (*P.T).g() int", "(*struct{P.T}).f": "wrapper for func (P.T).f() int", "(*struct{P.T}).g": "wrapper for func (*P.T).g() int", "(struct{*P.T}).f": "wrapper for func (P.T).f() int", "(struct{*P.T}).g": "wrapper for func (*P.T).g() int", "(struct{P.T}).f": "wrapper for func (P.T).f() int", "P.init": "package initializer", } for fn := range ssautil.AllFunctions(prog) { if fn.Synthetic == "" { continue } name := fn.String() wantDescr, ok := want[name] if !ok { t.Errorf("got unexpected/duplicate func: %q: %q", name, fn.Synthetic) continue } delete(want, name) if wantDescr != fn.Synthetic { t.Errorf("(%s).Synthetic = %q, want %q", name, fn.Synthetic, wantDescr) } } for fn, descr := range want { t.Errorf("want func: %q: %q", fn, descr) } }