github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/create.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
     6  
     7  // This file implements the CREATE phase of SSA construction.
     8  // See builder.go for explanation.
     9  
    10  import (
    11  	"fmt"
    12  	"go/ast"
    13  	"go/token"
    14  	"os"
    15  	"sync"
    16  
    17  	"llvm.org/llgo/third_party/gotools/go/loader"
    18  	"llvm.org/llgo/third_party/gotools/go/types"
    19  	"llvm.org/llgo/third_party/gotools/go/types/typeutil"
    20  )
    21  
    22  // Create returns a new SSA Program.  An SSA Package is created for
    23  // each transitively error-free package of iprog.
    24  //
    25  // Code for bodies of functions is not built until Build() is called
    26  // on the result.
    27  //
    28  // mode controls diagnostics and checking during SSA construction.
    29  //
    30  func Create(iprog *loader.Program, mode BuilderMode) *Program {
    31  	prog := &Program{
    32  		Fset:     iprog.Fset,
    33  		imported: make(map[string]*Package),
    34  		packages: make(map[*types.Package]*Package),
    35  		thunks:   make(map[selectionKey]*Function),
    36  		bounds:   make(map[*types.Func]*Function),
    37  		mode:     mode,
    38  	}
    39  
    40  	h := typeutil.MakeHasher() // protected by methodsMu, in effect
    41  	prog.methodSets.SetHasher(h)
    42  	prog.canon.SetHasher(h)
    43  
    44  	for _, info := range iprog.AllPackages {
    45  		// TODO(adonovan): relax this constraint if the
    46  		// program contains only "soft" errors.
    47  		if info.TransitivelyErrorFree {
    48  			prog.CreatePackage(info)
    49  		}
    50  	}
    51  
    52  	return prog
    53  }
    54  
    55  // memberFromObject populates package pkg with a member for the
    56  // typechecker object obj.
    57  //
    58  // For objects from Go source code, syntax is the associated syntax
    59  // tree (for funcs and vars only); it will be used during the build
    60  // phase.
    61  //
    62  func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
    63  	name := obj.Name()
    64  	switch obj := obj.(type) {
    65  	case *types.TypeName:
    66  		pkg.Members[name] = &Type{
    67  			object: obj,
    68  			pkg:    pkg,
    69  		}
    70  
    71  	case *types.Const:
    72  		c := &NamedConst{
    73  			object: obj,
    74  			Value:  NewConst(obj.Val(), obj.Type()),
    75  			pkg:    pkg,
    76  		}
    77  		pkg.values[obj] = c.Value
    78  		pkg.Members[name] = c
    79  
    80  	case *types.Var:
    81  		g := &Global{
    82  			Pkg:    pkg,
    83  			name:   name,
    84  			object: obj,
    85  			typ:    types.NewPointer(obj.Type()), // address
    86  			pos:    obj.Pos(),
    87  		}
    88  		pkg.values[obj] = g
    89  		pkg.Members[name] = g
    90  
    91  	case *types.Func:
    92  		sig := obj.Type().(*types.Signature)
    93  		if sig.Recv() == nil && name == "init" {
    94  			pkg.ninit++
    95  			name = fmt.Sprintf("init#%d", pkg.ninit)
    96  		}
    97  		fn := &Function{
    98  			name:      name,
    99  			object:    obj,
   100  			Signature: sig,
   101  			syntax:    syntax,
   102  			pos:       obj.Pos(),
   103  			Pkg:       pkg,
   104  			Prog:      pkg.Prog,
   105  		}
   106  		if syntax == nil {
   107  			fn.Synthetic = "loaded from gc object file"
   108  		}
   109  
   110  		pkg.values[obj] = fn
   111  		if sig.Recv() == nil {
   112  			pkg.Members[name] = fn // package-level function
   113  		}
   114  
   115  	default: // (incl. *types.Package)
   116  		panic("unexpected Object type: " + obj.String())
   117  	}
   118  }
   119  
   120  // membersFromDecl populates package pkg with members for each
   121  // typechecker object (var, func, const or type) associated with the
   122  // specified decl.
   123  //
   124  func membersFromDecl(pkg *Package, decl ast.Decl) {
   125  	switch decl := decl.(type) {
   126  	case *ast.GenDecl: // import, const, type or var
   127  		switch decl.Tok {
   128  		case token.CONST:
   129  			for _, spec := range decl.Specs {
   130  				for _, id := range spec.(*ast.ValueSpec).Names {
   131  					if !isBlankIdent(id) {
   132  						memberFromObject(pkg, pkg.info.Defs[id], nil)
   133  					}
   134  				}
   135  			}
   136  
   137  		case token.VAR:
   138  			for _, spec := range decl.Specs {
   139  				for _, id := range spec.(*ast.ValueSpec).Names {
   140  					if !isBlankIdent(id) {
   141  						memberFromObject(pkg, pkg.info.Defs[id], spec)
   142  					}
   143  				}
   144  			}
   145  
   146  		case token.TYPE:
   147  			for _, spec := range decl.Specs {
   148  				id := spec.(*ast.TypeSpec).Name
   149  				if !isBlankIdent(id) {
   150  					memberFromObject(pkg, pkg.info.Defs[id], nil)
   151  				}
   152  			}
   153  		}
   154  
   155  	case *ast.FuncDecl:
   156  		id := decl.Name
   157  		if !isBlankIdent(id) {
   158  			memberFromObject(pkg, pkg.info.Defs[id], decl)
   159  		}
   160  	}
   161  }
   162  
   163  // CreatePackage constructs and returns an SSA Package from an
   164  // error-free package described by info, and populates its Members
   165  // mapping.
   166  //
   167  // Repeated calls with the same info return the same Package.
   168  //
   169  // The real work of building SSA form for each function is not done
   170  // until a subsequent call to Package.Build().
   171  //
   172  func (prog *Program) CreatePackage(info *loader.PackageInfo) *Package {
   173  	if p := prog.packages[info.Pkg]; p != nil {
   174  		return p // already loaded
   175  	}
   176  
   177  	p := &Package{
   178  		Prog:    prog,
   179  		Members: make(map[string]Member),
   180  		values:  make(map[types.Object]Value),
   181  		Object:  info.Pkg,
   182  		info:    info, // transient (CREATE and BUILD phases)
   183  	}
   184  
   185  	// Add init() function.
   186  	p.init = &Function{
   187  		name:      "init",
   188  		Signature: new(types.Signature),
   189  		Synthetic: "package initializer",
   190  		Pkg:       p,
   191  		Prog:      prog,
   192  	}
   193  	p.Members[p.init.name] = p.init
   194  
   195  	// CREATE phase.
   196  	// Allocate all package members: vars, funcs, consts and types.
   197  	if len(info.Files) > 0 {
   198  		// Go source package.
   199  		for _, file := range info.Files {
   200  			for _, decl := range file.Decls {
   201  				membersFromDecl(p, decl)
   202  			}
   203  		}
   204  	} else {
   205  		// GC-compiled binary package.
   206  		// No code.
   207  		// No position information.
   208  		scope := p.Object.Scope()
   209  		for _, name := range scope.Names() {
   210  			obj := scope.Lookup(name)
   211  			memberFromObject(p, obj, nil)
   212  			if obj, ok := obj.(*types.TypeName); ok {
   213  				named := obj.Type().(*types.Named)
   214  				for i, n := 0, named.NumMethods(); i < n; i++ {
   215  					memberFromObject(p, named.Method(i), nil)
   216  				}
   217  			}
   218  		}
   219  	}
   220  
   221  	if prog.mode&BareInits == 0 {
   222  		// Add initializer guard variable.
   223  		initguard := &Global{
   224  			Pkg:  p,
   225  			name: "init$guard",
   226  			typ:  types.NewPointer(tBool),
   227  		}
   228  		p.Members[initguard.Name()] = initguard
   229  	}
   230  
   231  	if prog.mode&GlobalDebug != 0 {
   232  		p.SetDebugMode(true)
   233  	}
   234  
   235  	if prog.mode&PrintPackages != 0 {
   236  		printMu.Lock()
   237  		p.WriteTo(os.Stdout)
   238  		printMu.Unlock()
   239  	}
   240  
   241  	if info.Importable {
   242  		prog.imported[info.Pkg.Path()] = p
   243  	}
   244  	prog.packages[p.Object] = p
   245  
   246  	return p
   247  }
   248  
   249  // printMu serializes printing of Packages/Functions to stdout.
   250  var printMu sync.Mutex
   251  
   252  // AllPackages returns a new slice containing all packages in the
   253  // program prog in unspecified order.
   254  //
   255  func (prog *Program) AllPackages() []*Package {
   256  	pkgs := make([]*Package, 0, len(prog.packages))
   257  	for _, pkg := range prog.packages {
   258  		pkgs = append(pkgs, pkg)
   259  	}
   260  	return pkgs
   261  }
   262  
   263  // ImportedPackage returns the importable SSA Package whose import
   264  // path is path, or nil if no such SSA package has been created.
   265  //
   266  // Not all packages are importable.  For example, no import
   267  // declaration can resolve to the x_test package created by 'go test'
   268  // or the ad-hoc main package created 'go build foo.go'.
   269  //
   270  func (prog *Program) ImportedPackage(path string) *Package {
   271  	return prog.imported[path]
   272  }