github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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  	"go/types"
    15  	"os"
    16  	"sync"
    17  
    18  	"github.com/powerman/golang-tools/go/types/typeutil"
    19  	"github.com/powerman/golang-tools/internal/typeparams"
    20  )
    21  
    22  // NewProgram returns a new SSA Program.
    23  //
    24  // mode controls diagnostics and checking during SSA construction.
    25  //
    26  func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
    27  	prog := &Program{
    28  		Fset:      fset,
    29  		imported:  make(map[string]*Package),
    30  		packages:  make(map[*types.Package]*Package),
    31  		thunks:    make(map[selectionKey]*Function),
    32  		bounds:    make(map[boundsKey]*Function),
    33  		mode:      mode,
    34  		canon:     newCanonizer(),
    35  		ctxt:      typeparams.NewContext(),
    36  		instances: make(map[*Function]*instanceSet),
    37  	}
    38  
    39  	h := typeutil.MakeHasher() // protected by methodsMu, in effect
    40  	prog.methodSets.SetHasher(h)
    41  
    42  	return prog
    43  }
    44  
    45  // memberFromObject populates package pkg with a member for the
    46  // typechecker object obj.
    47  //
    48  // For objects from Go source code, syntax is the associated syntax
    49  // tree (for funcs and vars only); it will be used during the build
    50  // phase.
    51  //
    52  func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
    53  	name := obj.Name()
    54  	switch obj := obj.(type) {
    55  	case *types.Builtin:
    56  		if pkg.Pkg != types.Unsafe {
    57  			panic("unexpected builtin object: " + obj.String())
    58  		}
    59  
    60  	case *types.TypeName:
    61  		pkg.Members[name] = &Type{
    62  			object: obj,
    63  			pkg:    pkg,
    64  		}
    65  
    66  	case *types.Const:
    67  		c := &NamedConst{
    68  			object: obj,
    69  			Value:  NewConst(obj.Val(), obj.Type()),
    70  			pkg:    pkg,
    71  		}
    72  		pkg.objects[obj] = c
    73  		pkg.Members[name] = c
    74  
    75  	case *types.Var:
    76  		g := &Global{
    77  			Pkg:    pkg,
    78  			name:   name,
    79  			object: obj,
    80  			typ:    types.NewPointer(obj.Type()), // address
    81  			pos:    obj.Pos(),
    82  		}
    83  		pkg.objects[obj] = g
    84  		pkg.Members[name] = g
    85  
    86  	case *types.Func:
    87  		sig := obj.Type().(*types.Signature)
    88  		if sig.Recv() == nil && name == "init" {
    89  			pkg.ninit++
    90  			name = fmt.Sprintf("init#%d", pkg.ninit)
    91  		}
    92  
    93  		// Collect type parameters if this is a generic function/method.
    94  		var tparams []*typeparams.TypeParam
    95  		for i, rtparams := 0, typeparams.RecvTypeParams(sig); i < rtparams.Len(); i++ {
    96  			tparams = append(tparams, rtparams.At(i))
    97  		}
    98  		for i, sigparams := 0, typeparams.ForSignature(sig); i < sigparams.Len(); i++ {
    99  			tparams = append(tparams, sigparams.At(i))
   100  		}
   101  
   102  		fn := &Function{
   103  			name:        name,
   104  			object:      obj,
   105  			Signature:   sig,
   106  			syntax:      syntax,
   107  			pos:         obj.Pos(),
   108  			Pkg:         pkg,
   109  			Prog:        pkg.Prog,
   110  			info:        pkg.info,
   111  			_TypeParams: tparams,
   112  		}
   113  		pkg.created.Add(fn)
   114  		if syntax == nil {
   115  			fn.Synthetic = "loaded from gc object file"
   116  		}
   117  		if len(tparams) > 0 {
   118  			fn.Prog.createInstanceSet(fn)
   119  		}
   120  		if len(tparams) > 0 && syntax != nil {
   121  			fn.Synthetic = "generic function"
   122  			// TODO(taking): Allow for the function to be built once type params are supported.
   123  			fn.syntax = nil // Treating as an external function temporarily.
   124  		}
   125  
   126  		pkg.objects[obj] = fn
   127  		if sig.Recv() == nil {
   128  			pkg.Members[name] = fn // package-level function
   129  		}
   130  
   131  	default: // (incl. *types.Package)
   132  		panic("unexpected Object type: " + obj.String())
   133  	}
   134  }
   135  
   136  // membersFromDecl populates package pkg with members for each
   137  // typechecker object (var, func, const or type) associated with the
   138  // specified decl.
   139  //
   140  func membersFromDecl(pkg *Package, decl ast.Decl) {
   141  	switch decl := decl.(type) {
   142  	case *ast.GenDecl: // import, const, type or var
   143  		switch decl.Tok {
   144  		case token.CONST:
   145  			for _, spec := range decl.Specs {
   146  				for _, id := range spec.(*ast.ValueSpec).Names {
   147  					if !isBlankIdent(id) {
   148  						memberFromObject(pkg, pkg.info.Defs[id], nil)
   149  					}
   150  				}
   151  			}
   152  
   153  		case token.VAR:
   154  			for _, spec := range decl.Specs {
   155  				for _, id := range spec.(*ast.ValueSpec).Names {
   156  					if !isBlankIdent(id) {
   157  						memberFromObject(pkg, pkg.info.Defs[id], spec)
   158  					}
   159  				}
   160  			}
   161  
   162  		case token.TYPE:
   163  			for _, spec := range decl.Specs {
   164  				id := spec.(*ast.TypeSpec).Name
   165  				if !isBlankIdent(id) {
   166  					memberFromObject(pkg, pkg.info.Defs[id], nil)
   167  				}
   168  			}
   169  		}
   170  
   171  	case *ast.FuncDecl:
   172  		id := decl.Name
   173  		if !isBlankIdent(id) {
   174  			memberFromObject(pkg, pkg.info.Defs[id], decl)
   175  		}
   176  	}
   177  }
   178  
   179  // creator tracks functions that have finished their CREATE phases.
   180  //
   181  // All Functions belong to the same Program. May have differing packages.
   182  //
   183  // creators are not thread-safe.
   184  type creator []*Function
   185  
   186  func (c *creator) Add(fn *Function) {
   187  	*c = append(*c, fn)
   188  }
   189  func (c *creator) At(i int) *Function { return (*c)[i] }
   190  func (c *creator) Len() int           { return len(*c) }
   191  
   192  // CreatePackage constructs and returns an SSA Package from the
   193  // specified type-checked, error-free file ASTs, and populates its
   194  // Members mapping.
   195  //
   196  // importable determines whether this package should be returned by a
   197  // subsequent call to ImportedPackage(pkg.Path()).
   198  //
   199  // The real work of building SSA form for each function is not done
   200  // until a subsequent call to Package.Build().
   201  //
   202  func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
   203  	p := &Package{
   204  		Prog:    prog,
   205  		Members: make(map[string]Member),
   206  		objects: make(map[types.Object]Member),
   207  		Pkg:     pkg,
   208  		info:    info,  // transient (CREATE and BUILD phases)
   209  		files:   files, // transient (CREATE and BUILD phases)
   210  	}
   211  
   212  	// Add init() function.
   213  	p.init = &Function{
   214  		name:      "init",
   215  		Signature: new(types.Signature),
   216  		Synthetic: "package initializer",
   217  		Pkg:       p,
   218  		Prog:      prog,
   219  		info:      p.info,
   220  	}
   221  	p.Members[p.init.name] = p.init
   222  	p.created.Add(p.init)
   223  
   224  	// CREATE phase.
   225  	// Allocate all package members: vars, funcs, consts and types.
   226  	if len(files) > 0 {
   227  		// Go source package.
   228  		for _, file := range files {
   229  			for _, decl := range file.Decls {
   230  				membersFromDecl(p, decl)
   231  			}
   232  		}
   233  	} else {
   234  		// GC-compiled binary package (or "unsafe")
   235  		// No code.
   236  		// No position information.
   237  		scope := p.Pkg.Scope()
   238  		for _, name := range scope.Names() {
   239  			obj := scope.Lookup(name)
   240  			memberFromObject(p, obj, nil)
   241  			if obj, ok := obj.(*types.TypeName); ok {
   242  				if named, ok := obj.Type().(*types.Named); ok {
   243  					for i, n := 0, named.NumMethods(); i < n; i++ {
   244  						memberFromObject(p, named.Method(i), nil)
   245  					}
   246  				}
   247  			}
   248  		}
   249  	}
   250  
   251  	if prog.mode&BareInits == 0 {
   252  		// Add initializer guard variable.
   253  		initguard := &Global{
   254  			Pkg:  p,
   255  			name: "init$guard",
   256  			typ:  types.NewPointer(tBool),
   257  		}
   258  		p.Members[initguard.Name()] = initguard
   259  	}
   260  
   261  	if prog.mode&GlobalDebug != 0 {
   262  		p.SetDebugMode(true)
   263  	}
   264  
   265  	if prog.mode&PrintPackages != 0 {
   266  		printMu.Lock()
   267  		p.WriteTo(os.Stdout)
   268  		printMu.Unlock()
   269  	}
   270  
   271  	if importable {
   272  		prog.imported[p.Pkg.Path()] = p
   273  	}
   274  	prog.packages[p.Pkg] = p
   275  
   276  	return p
   277  }
   278  
   279  // printMu serializes printing of Packages/Functions to stdout.
   280  var printMu sync.Mutex
   281  
   282  // AllPackages returns a new slice containing all packages in the
   283  // program prog in unspecified order.
   284  //
   285  func (prog *Program) AllPackages() []*Package {
   286  	pkgs := make([]*Package, 0, len(prog.packages))
   287  	for _, pkg := range prog.packages {
   288  		pkgs = append(pkgs, pkg)
   289  	}
   290  	return pkgs
   291  }
   292  
   293  // ImportedPackage returns the importable Package whose PkgPath
   294  // is path, or nil if no such Package has been created.
   295  //
   296  // A parameter to CreatePackage determines whether a package should be
   297  // considered importable. For example, no import declaration can resolve
   298  // to the ad-hoc main package created by 'go build foo.go'.
   299  //
   300  // TODO(adonovan): rethink this function and the "importable" concept;
   301  // most packages are importable. This function assumes that all
   302  // types.Package.Path values are unique within the ssa.Program, which is
   303  // false---yet this function remains very convenient.
   304  // Clients should use (*Program).Package instead where possible.
   305  // SSA doesn't really need a string-keyed map of packages.
   306  //
   307  func (prog *Program) ImportedPackage(path string) *Package {
   308  	return prog.imported[path]
   309  }