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  }