github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/methods.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 defines utilities for population of method sets.
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"llvm.org/llgo/third_party/gotools/go/types"
    13  )
    14  
    15  // Method returns the Function implementing method sel, building
    16  // wrapper methods on demand.  It returns nil if sel denotes an
    17  // abstract (interface) method.
    18  //
    19  // Precondition: sel.Kind() == MethodVal.
    20  //
    21  // TODO(adonovan): rename this to MethodValue because of the
    22  // precondition, and for consistency with functions in source.go.
    23  //
    24  // Thread-safe.
    25  //
    26  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
    27  //
    28  func (prog *Program) Method(sel *types.Selection) *Function {
    29  	if sel.Kind() != types.MethodVal {
    30  		panic(fmt.Sprintf("Method(%s) kind != MethodVal", sel))
    31  	}
    32  	T := sel.Recv()
    33  	if isInterface(T) {
    34  		return nil // abstract method
    35  	}
    36  	if prog.mode&LogSource != 0 {
    37  		defer logStack("Method %s %v", T, sel)()
    38  	}
    39  
    40  	prog.methodsMu.Lock()
    41  	defer prog.methodsMu.Unlock()
    42  
    43  	return prog.addMethod(prog.createMethodSet(T), sel)
    44  }
    45  
    46  // LookupMethod returns the implementation of the method of type T
    47  // identified by (pkg, name).  It returns nil if the method exists but
    48  // is abstract, and panics if T has no such method.
    49  //
    50  func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
    51  	sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
    52  	if sel == nil {
    53  		panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
    54  	}
    55  	return prog.Method(sel)
    56  }
    57  
    58  // methodSet contains the (concrete) methods of a non-interface type.
    59  type methodSet struct {
    60  	mapping  map[string]*Function // populated lazily
    61  	complete bool                 // mapping contains all methods
    62  }
    63  
    64  // Precondition: !isInterface(T).
    65  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
    66  func (prog *Program) createMethodSet(T types.Type) *methodSet {
    67  	mset, ok := prog.methodSets.At(T).(*methodSet)
    68  	if !ok {
    69  		mset = &methodSet{mapping: make(map[string]*Function)}
    70  		prog.methodSets.Set(T, mset)
    71  	}
    72  	return mset
    73  }
    74  
    75  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
    76  func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function {
    77  	if sel.Kind() == types.MethodExpr {
    78  		panic(sel)
    79  	}
    80  	id := sel.Obj().Id()
    81  	fn := mset.mapping[id]
    82  	if fn == nil {
    83  		obj := sel.Obj().(*types.Func)
    84  
    85  		needsPromotion := len(sel.Index()) > 1
    86  		needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv())
    87  		if needsPromotion || needsIndirection {
    88  			fn = makeWrapper(prog, sel)
    89  		} else {
    90  			fn = prog.declaredFunc(obj)
    91  		}
    92  		if fn.Signature.Recv() == nil {
    93  			panic(fn) // missing receiver
    94  		}
    95  		mset.mapping[id] = fn
    96  	}
    97  	return fn
    98  }
    99  
   100  // RuntimeTypes returns a new unordered slice containing all
   101  // concrete types in the program for which a complete (non-empty)
   102  // method set is required at run-time.
   103  //
   104  // Thread-safe.
   105  //
   106  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
   107  //
   108  func (prog *Program) RuntimeTypes() []types.Type {
   109  	prog.methodsMu.Lock()
   110  	defer prog.methodsMu.Unlock()
   111  
   112  	var res []types.Type
   113  	prog.methodSets.Iterate(func(T types.Type, v interface{}) {
   114  		if v.(*methodSet).complete {
   115  			res = append(res, T)
   116  		}
   117  	})
   118  	return res
   119  }
   120  
   121  // declaredFunc returns the concrete function/method denoted by obj.
   122  // Panic ensues if there is none.
   123  //
   124  func (prog *Program) declaredFunc(obj *types.Func) *Function {
   125  	if v := prog.packageLevelValue(obj); v != nil {
   126  		return v.(*Function)
   127  	}
   128  	panic("no concrete method: " + obj.String())
   129  }
   130  
   131  // needMethodsOf ensures that runtime type information (including the
   132  // complete method set) is available for the specified type T and all
   133  // its subcomponents.
   134  //
   135  // needMethodsOf must be called for at least every type that is an
   136  // operand of some MakeInterface instruction, and for the type of
   137  // every exported package member.
   138  //
   139  // Precondition: T is not a method signature (*Signature with Recv()!=nil).
   140  //
   141  // Thread-safe.  (Called via emitConv from multiple builder goroutines.)
   142  //
   143  // TODO(adonovan): make this faster.  It accounts for 20% of SSA build time.
   144  //
   145  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
   146  //
   147  func (prog *Program) needMethodsOf(T types.Type) {
   148  	prog.methodsMu.Lock()
   149  	prog.needMethods(T, false)
   150  	prog.methodsMu.Unlock()
   151  }
   152  
   153  // Precondition: T is not a method signature (*Signature with Recv()!=nil).
   154  // Recursive case: skip => don't create methods for T.
   155  //
   156  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
   157  //
   158  func (prog *Program) needMethods(T types.Type, skip bool) {
   159  	// Each package maintains its own set of types it has visited.
   160  	if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
   161  		// needMethods(T) was previously called
   162  		if !prevSkip || skip {
   163  			return // already seen, with same or false 'skip' value
   164  		}
   165  	}
   166  	prog.runtimeTypes.Set(T, skip)
   167  
   168  	tmset := prog.MethodSets.MethodSet(T)
   169  
   170  	if !skip && !isInterface(T) && tmset.Len() > 0 {
   171  		// Create methods of T.
   172  		mset := prog.createMethodSet(T)
   173  		if !mset.complete {
   174  			mset.complete = true
   175  			n := tmset.Len()
   176  			for i := 0; i < n; i++ {
   177  				prog.addMethod(mset, tmset.At(i))
   178  			}
   179  		}
   180  	}
   181  
   182  	// Recursion over signatures of each method.
   183  	for i := 0; i < tmset.Len(); i++ {
   184  		sig := tmset.At(i).Type().(*types.Signature)
   185  		prog.needMethods(sig.Params(), false)
   186  		prog.needMethods(sig.Results(), false)
   187  	}
   188  
   189  	switch t := T.(type) {
   190  	case *types.Basic:
   191  		// nop
   192  
   193  	case *types.Interface:
   194  		// nop---handled by recursion over method set.
   195  
   196  	case *types.Pointer:
   197  		prog.needMethods(t.Elem(), false)
   198  
   199  	case *types.Slice:
   200  		prog.needMethods(t.Elem(), false)
   201  
   202  	case *types.Chan:
   203  		prog.needMethods(t.Elem(), false)
   204  
   205  	case *types.Map:
   206  		prog.needMethods(t.Key(), false)
   207  		prog.needMethods(t.Elem(), false)
   208  
   209  	case *types.Signature:
   210  		if t.Recv() != nil {
   211  			panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
   212  		}
   213  		prog.needMethods(t.Params(), false)
   214  		prog.needMethods(t.Results(), false)
   215  
   216  	case *types.Named:
   217  		// A pointer-to-named type can be derived from a named
   218  		// type via reflection.  It may have methods too.
   219  		prog.needMethods(types.NewPointer(T), false)
   220  
   221  		// Consider 'type T struct{S}' where S has methods.
   222  		// Reflection provides no way to get from T to struct{S},
   223  		// only to S, so the method set of struct{S} is unwanted,
   224  		// so set 'skip' flag during recursion.
   225  		prog.needMethods(t.Underlying(), true)
   226  
   227  	case *types.Array:
   228  		prog.needMethods(t.Elem(), false)
   229  
   230  	case *types.Struct:
   231  		for i, n := 0, t.NumFields(); i < n; i++ {
   232  			prog.needMethods(t.Field(i).Type(), false)
   233  		}
   234  
   235  	case *types.Tuple:
   236  		for i, n := 0, t.Len(); i < n; i++ {
   237  			prog.needMethods(t.At(i).Type(), false)
   238  		}
   239  
   240  	default:
   241  		panic(T)
   242  	}
   243  }