github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/builder_test.go (about) 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 5 package ssa_test 6 7 import ( 8 "bytes" 9 "reflect" 10 "sort" 11 "strings" 12 "testing" 13 14 "llvm.org/llgo/third_party/gotools/go/loader" 15 "llvm.org/llgo/third_party/gotools/go/ssa" 16 "llvm.org/llgo/third_party/gotools/go/ssa/ssautil" 17 "llvm.org/llgo/third_party/gotools/go/types" 18 ) 19 20 func isEmpty(f *ssa.Function) bool { return f.Blocks == nil } 21 22 // Tests that programs partially loaded from gc object files contain 23 // functions with no code for the external portions, but are otherwise ok. 24 func TestImportFromBinary(t *testing.T) { 25 test := ` 26 package main 27 28 import ( 29 "bytes" 30 "io" 31 "testing" 32 ) 33 34 func main() { 35 var t testing.T 36 t.Parallel() // static call to external declared method 37 t.Fail() // static call to promoted external declared method 38 testing.Short() // static call to external package-level function 39 40 var w io.Writer = new(bytes.Buffer) 41 w.Write(nil) // interface invoke of external declared method 42 } 43 ` 44 45 // Create a single-file main package. 46 conf := loader.Config{ImportFromBinary: true} 47 f, err := conf.ParseFile("<input>", test) 48 if err != nil { 49 t.Error(err) 50 return 51 } 52 conf.CreateFromFiles("main", f) 53 54 iprog, err := conf.Load() 55 if err != nil { 56 t.Error(err) 57 return 58 } 59 60 prog := ssa.Create(iprog, ssa.SanityCheckFunctions) 61 mainPkg := prog.Package(iprog.Created[0].Pkg) 62 mainPkg.Build() 63 64 // The main package, its direct and indirect dependencies are loaded. 65 deps := []string{ 66 // directly imported dependencies: 67 "bytes", "io", "testing", 68 // indirect dependencies (partial list): 69 "errors", "fmt", "os", "runtime", 70 } 71 72 all := prog.AllPackages() 73 if len(all) <= len(deps) { 74 t.Errorf("unexpected set of loaded packages: %q", all) 75 } 76 for _, path := range deps { 77 pkg := prog.ImportedPackage(path) 78 if pkg == nil { 79 t.Errorf("package not loaded: %q", path) 80 continue 81 } 82 83 // External packages should have no function bodies (except for wrappers). 84 isExt := pkg != mainPkg 85 86 // init() 87 if isExt && !isEmpty(pkg.Func("init")) { 88 t.Errorf("external package %s has non-empty init", pkg) 89 } else if !isExt && isEmpty(pkg.Func("init")) { 90 t.Errorf("main package %s has empty init", pkg) 91 } 92 93 for _, mem := range pkg.Members { 94 switch mem := mem.(type) { 95 case *ssa.Function: 96 // Functions at package level. 97 if isExt && !isEmpty(mem) { 98 t.Errorf("external function %s is non-empty", mem) 99 } else if !isExt && isEmpty(mem) { 100 t.Errorf("function %s is empty", mem) 101 } 102 103 case *ssa.Type: 104 // Methods of named types T. 105 // (In this test, all exported methods belong to *T not T.) 106 if !isExt { 107 t.Fatalf("unexpected name type in main package: %s", mem) 108 } 109 mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type())) 110 for i, n := 0, mset.Len(); i < n; i++ { 111 m := prog.Method(mset.At(i)) 112 // For external types, only synthetic wrappers have code. 113 expExt := !strings.Contains(m.Synthetic, "wrapper") 114 if expExt && !isEmpty(m) { 115 t.Errorf("external method %s is non-empty: %s", 116 m, m.Synthetic) 117 } else if !expExt && isEmpty(m) { 118 t.Errorf("method function %s is empty: %s", 119 m, m.Synthetic) 120 } 121 } 122 } 123 } 124 } 125 126 expectedCallee := []string{ 127 "(*testing.T).Parallel", 128 "(*testing.common).Fail", 129 "testing.Short", 130 "N/A", 131 } 132 callNum := 0 133 for _, b := range mainPkg.Func("main").Blocks { 134 for _, instr := range b.Instrs { 135 switch instr := instr.(type) { 136 case ssa.CallInstruction: 137 call := instr.Common() 138 if want := expectedCallee[callNum]; want != "N/A" { 139 got := call.StaticCallee().String() 140 if want != got { 141 t.Errorf("call #%d from main.main: got callee %s, want %s", 142 callNum, got, want) 143 } 144 } 145 callNum++ 146 } 147 } 148 } 149 if callNum != 4 { 150 t.Errorf("in main.main: got %d calls, want %d", callNum, 4) 151 } 152 } 153 154 // TestRuntimeTypes tests that (*Program).RuntimeTypes() includes all necessary types. 155 func TestRuntimeTypes(t *testing.T) { 156 tests := []struct { 157 input string 158 want []string 159 }{ 160 // An exported package-level type is needed. 161 {`package A; type T struct{}; func (T) f() {}`, 162 []string{"*p.T", "p.T"}, 163 }, 164 // An unexported package-level type is not needed. 165 {`package B; type t struct{}; func (t) f() {}`, 166 nil, 167 }, 168 // Subcomponents of type of exported package-level var are needed. 169 {`package C; import "bytes"; var V struct {*bytes.Buffer}`, 170 []string{"*bytes.Buffer", "*struct{*bytes.Buffer}", "struct{*bytes.Buffer}"}, 171 }, 172 // Subcomponents of type of unexported package-level var are not needed. 173 {`package D; import "bytes"; var v struct {*bytes.Buffer}`, 174 nil, 175 }, 176 // Subcomponents of type of exported package-level function are needed. 177 {`package E; import "bytes"; func F(struct {*bytes.Buffer}) {}`, 178 []string{"*bytes.Buffer", "struct{*bytes.Buffer}"}, 179 }, 180 // Subcomponents of type of unexported package-level function are not needed. 181 {`package F; import "bytes"; func f(struct {*bytes.Buffer}) {}`, 182 nil, 183 }, 184 // Subcomponents of type of exported method of uninstantiated unexported type are not needed. 185 {`package G; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v x`, 186 nil, 187 }, 188 // ...unless used by MakeInterface. 189 {`package G2; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v interface{} = x{}`, 190 []string{"*bytes.Buffer", "*p.x", "p.x", "struct{*bytes.Buffer}"}, 191 }, 192 // Subcomponents of type of unexported method are not needed. 193 {`package I; import "bytes"; type X struct{}; func (X) G(struct {*bytes.Buffer}) {}`, 194 []string{"*bytes.Buffer", "*p.X", "p.X", "struct{*bytes.Buffer}"}, 195 }, 196 // Local types aren't needed. 197 {`package J; import "bytes"; func f() { type T struct {*bytes.Buffer}; var t T; _ = t }`, 198 nil, 199 }, 200 // ...unless used by MakeInterface. 201 {`package K; import "bytes"; func f() { type T struct {*bytes.Buffer}; _ = interface{}(T{}) }`, 202 []string{"*bytes.Buffer", "*p.T", "p.T"}, 203 }, 204 // Types used as operand of MakeInterface are needed. 205 {`package L; import "bytes"; func f() { _ = interface{}(struct{*bytes.Buffer}{}) }`, 206 []string{"*bytes.Buffer", "struct{*bytes.Buffer}"}, 207 }, 208 // MakeInterface is optimized away when storing to a blank. 209 {`package M; import "bytes"; var _ interface{} = struct{*bytes.Buffer}{}`, 210 nil, 211 }, 212 } 213 for _, test := range tests { 214 // Create a single-file main package. 215 conf := loader.Config{ImportFromBinary: true} 216 f, err := conf.ParseFile("<input>", test.input) 217 if err != nil { 218 t.Errorf("test %q: %s", test.input[:15], err) 219 continue 220 } 221 conf.CreateFromFiles("p", f) 222 223 iprog, err := conf.Load() 224 if err != nil { 225 t.Errorf("test 'package %s': Load: %s", f.Name.Name, err) 226 continue 227 } 228 prog := ssa.Create(iprog, ssa.SanityCheckFunctions) 229 prog.BuildAll() 230 231 var typstrs []string 232 for _, T := range prog.RuntimeTypes() { 233 typstrs = append(typstrs, T.String()) 234 } 235 sort.Strings(typstrs) 236 237 if !reflect.DeepEqual(typstrs, test.want) { 238 t.Errorf("test 'package %s': got %q, want %q", 239 f.Name.Name, typstrs, test.want) 240 } 241 } 242 } 243 244 // Tests that synthesized init functions are correctly formed. 245 // Bare init functions omit calls to dependent init functions and the use of 246 // an init guard. They are useful in cases where the client uses a different 247 // calling convention for init functions, or cases where it is easier for a 248 // client to analyze bare init functions. Both of these aspects are used by 249 // the llgo compiler for simpler integration with gccgo's runtime library, 250 // and to simplify the analysis whereby it deduces which stores to globals 251 // can be lowered to global initializers. 252 func TestInit(t *testing.T) { 253 tests := []struct { 254 mode ssa.BuilderMode 255 input, want string 256 }{ 257 {0, `package A; import _ "errors"; var i int = 42`, 258 `# Name: A.init 259 # Package: A 260 # Synthetic: package initializer 261 func init(): 262 0: entry P:0 S:2 263 t0 = *init$guard bool 264 if t0 goto 2 else 1 265 1: init.start P:1 S:1 266 *init$guard = true:bool 267 t1 = errors.init() () 268 *i = 42:int 269 jump 2 270 2: init.done P:2 S:0 271 return 272 273 `}, 274 {ssa.BareInits, `package B; import _ "errors"; var i int = 42`, 275 `# Name: B.init 276 # Package: B 277 # Synthetic: package initializer 278 func init(): 279 0: entry P:0 S:0 280 *i = 42:int 281 return 282 283 `}, 284 } 285 for _, test := range tests { 286 // Create a single-file main package. 287 var conf loader.Config 288 f, err := conf.ParseFile("<input>", test.input) 289 if err != nil { 290 t.Errorf("test %q: %s", test.input[:15], err) 291 continue 292 } 293 conf.CreateFromFiles(f.Name.Name, f) 294 295 iprog, err := conf.Load() 296 if err != nil { 297 t.Errorf("test 'package %s': Load: %s", f.Name.Name, err) 298 continue 299 } 300 prog := ssa.Create(iprog, test.mode) 301 mainPkg := prog.Package(iprog.Created[0].Pkg) 302 prog.BuildAll() 303 initFunc := mainPkg.Func("init") 304 if initFunc == nil { 305 t.Errorf("test 'package %s': no init function", f.Name.Name) 306 continue 307 } 308 309 var initbuf bytes.Buffer 310 _, err = initFunc.WriteTo(&initbuf) 311 if err != nil { 312 t.Errorf("test 'package %s': WriteTo: %s", f.Name.Name, err) 313 continue 314 } 315 316 if initbuf.String() != test.want { 317 t.Errorf("test 'package %s': got %s, want %s", f.Name.Name, initbuf.String(), test.want) 318 } 319 } 320 } 321 322 // TestSyntheticFuncs checks that the expected synthetic functions are 323 // created, reachable, and not duplicated. 324 func TestSyntheticFuncs(t *testing.T) { 325 const input = `package P 326 type T int 327 func (T) f() int 328 func (*T) g() int 329 var ( 330 // thunks 331 a = T.f 332 b = T.f 333 c = (struct{T}).f 334 d = (struct{T}).f 335 e = (*T).g 336 f = (*T).g 337 g = (struct{*T}).g 338 h = (struct{*T}).g 339 340 // bounds 341 i = T(0).f 342 j = T(0).f 343 k = new(T).g 344 l = new(T).g 345 346 // wrappers 347 m interface{} = struct{T}{} 348 n interface{} = struct{T}{} 349 o interface{} = struct{*T}{} 350 p interface{} = struct{*T}{} 351 q interface{} = new(struct{T}) 352 r interface{} = new(struct{T}) 353 s interface{} = new(struct{*T}) 354 t interface{} = new(struct{*T}) 355 ) 356 ` 357 // Parse 358 var conf loader.Config 359 f, err := conf.ParseFile("<input>", input) 360 if err != nil { 361 t.Fatalf("parse: %v", err) 362 } 363 conf.CreateFromFiles(f.Name.Name, f) 364 365 // Load 366 iprog, err := conf.Load() 367 if err != nil { 368 t.Fatalf("Load: %v", err) 369 } 370 371 // Create and build SSA 372 prog := ssa.Create(iprog, 0) 373 prog.BuildAll() 374 375 // Enumerate reachable synthetic functions 376 want := map[string]string{ 377 "(*P.T).g$bound": "bound method wrapper for func (*P.T).g() int", 378 "(P.T).f$bound": "bound method wrapper for func (P.T).f() int", 379 380 "(*P.T).g$thunk": "thunk for func (*P.T).g() int", 381 "(P.T).f$thunk": "thunk for func (P.T).f() int", 382 "(struct{*P.T}).g$thunk": "thunk for func (*P.T).g() int", 383 "(struct{P.T}).f$thunk": "thunk for func (P.T).f() int", 384 385 "(*P.T).f": "wrapper for func (P.T).f() int", 386 "(*struct{*P.T}).f": "wrapper for func (P.T).f() int", 387 "(*struct{*P.T}).g": "wrapper for func (*P.T).g() int", 388 "(*struct{P.T}).f": "wrapper for func (P.T).f() int", 389 "(*struct{P.T}).g": "wrapper for func (*P.T).g() int", 390 "(struct{*P.T}).f": "wrapper for func (P.T).f() int", 391 "(struct{*P.T}).g": "wrapper for func (*P.T).g() int", 392 "(struct{P.T}).f": "wrapper for func (P.T).f() int", 393 394 "P.init": "package initializer", 395 } 396 for fn := range ssautil.AllFunctions(prog) { 397 if fn.Synthetic == "" { 398 continue 399 } 400 name := fn.String() 401 wantDescr, ok := want[name] 402 if !ok { 403 t.Errorf("got unexpected/duplicate func: %q: %q", name, fn.Synthetic) 404 continue 405 } 406 delete(want, name) 407 408 if wantDescr != fn.Synthetic { 409 t.Errorf("(%s).Synthetic = %q, want %q", name, fn.Synthetic, wantDescr) 410 } 411 } 412 for fn, descr := range want { 413 t.Errorf("want func: %q: %q", fn, descr) 414 } 415 }