github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/pointer/util.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 pointer
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"log"
    11  	"os"
    12  	"os/exec"
    13  	"runtime"
    14  	"time"
    15  
    16  	"llvm.org/llgo/third_party/gotools/container/intsets"
    17  	"llvm.org/llgo/third_party/gotools/go/types"
    18  )
    19  
    20  // CanPoint reports whether the type T is pointerlike,
    21  // for the purposes of this analysis.
    22  func CanPoint(T types.Type) bool {
    23  	switch T := T.(type) {
    24  	case *types.Named:
    25  		if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
    26  			return true // treat reflect.Value like interface{}
    27  		}
    28  		return CanPoint(T.Underlying())
    29  
    30  	case *types.Pointer, *types.Interface, *types.Map, *types.Chan, *types.Signature, *types.Slice:
    31  		return true
    32  	}
    33  
    34  	return false // array struct tuple builtin basic
    35  }
    36  
    37  // CanHaveDynamicTypes reports whether the type T can "hold" dynamic types,
    38  // i.e. is an interface (incl. reflect.Type) or a reflect.Value.
    39  //
    40  func CanHaveDynamicTypes(T types.Type) bool {
    41  	switch T := T.(type) {
    42  	case *types.Named:
    43  		if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
    44  			return true // reflect.Value
    45  		}
    46  		return CanHaveDynamicTypes(T.Underlying())
    47  	case *types.Interface:
    48  		return true
    49  	}
    50  	return false
    51  }
    52  
    53  func isInterface(T types.Type) bool { return types.IsInterface(T) }
    54  
    55  // mustDeref returns the element type of its argument, which must be a
    56  // pointer; panic ensues otherwise.
    57  func mustDeref(typ types.Type) types.Type {
    58  	return typ.Underlying().(*types.Pointer).Elem()
    59  }
    60  
    61  // deref returns a pointer's element type; otherwise it returns typ.
    62  func deref(typ types.Type) types.Type {
    63  	if p, ok := typ.Underlying().(*types.Pointer); ok {
    64  		return p.Elem()
    65  	}
    66  	return typ
    67  }
    68  
    69  // A fieldInfo describes one subelement (node) of the flattening-out
    70  // of a type T: the subelement's type and its path from the root of T.
    71  //
    72  // For example, for this type:
    73  //     type line struct{ points []struct{x, y int} }
    74  // flatten() of the inner struct yields the following []fieldInfo:
    75  //    struct{ x, y int }                      ""
    76  //    int                                     ".x"
    77  //    int                                     ".y"
    78  // and flatten(line) yields:
    79  //    struct{ points []struct{x, y int} }     ""
    80  //    struct{ x, y int }                      ".points[*]"
    81  //    int                                     ".points[*].x
    82  //    int                                     ".points[*].y"
    83  //
    84  type fieldInfo struct {
    85  	typ types.Type
    86  
    87  	// op and tail describe the path to the element (e.g. ".a#2.b[*].c").
    88  	op   interface{} // *Array: true; *Tuple: int; *Struct: *types.Var; *Named: nil
    89  	tail *fieldInfo
    90  }
    91  
    92  // path returns a user-friendly string describing the subelement path.
    93  //
    94  func (fi *fieldInfo) path() string {
    95  	var buf bytes.Buffer
    96  	for p := fi; p != nil; p = p.tail {
    97  		switch op := p.op.(type) {
    98  		case bool:
    99  			fmt.Fprintf(&buf, "[*]")
   100  		case int:
   101  			fmt.Fprintf(&buf, "#%d", op)
   102  		case *types.Var:
   103  			fmt.Fprintf(&buf, ".%s", op.Name())
   104  		}
   105  	}
   106  	return buf.String()
   107  }
   108  
   109  // flatten returns a list of directly contained fields in the preorder
   110  // traversal of the type tree of t.  The resulting elements are all
   111  // scalars (basic types or pointerlike types), except for struct/array
   112  // "identity" nodes, whose type is that of the aggregate.
   113  //
   114  // reflect.Value is considered pointerlike, similar to interface{}.
   115  //
   116  // Callers must not mutate the result.
   117  //
   118  func (a *analysis) flatten(t types.Type) []*fieldInfo {
   119  	fl, ok := a.flattenMemo[t]
   120  	if !ok {
   121  		switch t := t.(type) {
   122  		case *types.Named:
   123  			u := t.Underlying()
   124  			if isInterface(u) {
   125  				// Debuggability hack: don't remove
   126  				// the named type from interfaces as
   127  				// they're very verbose.
   128  				fl = append(fl, &fieldInfo{typ: t})
   129  			} else {
   130  				fl = a.flatten(u)
   131  			}
   132  
   133  		case *types.Basic,
   134  			*types.Signature,
   135  			*types.Chan,
   136  			*types.Map,
   137  			*types.Interface,
   138  			*types.Slice,
   139  			*types.Pointer:
   140  			fl = append(fl, &fieldInfo{typ: t})
   141  
   142  		case *types.Array:
   143  			fl = append(fl, &fieldInfo{typ: t}) // identity node
   144  			for _, fi := range a.flatten(t.Elem()) {
   145  				fl = append(fl, &fieldInfo{typ: fi.typ, op: true, tail: fi})
   146  			}
   147  
   148  		case *types.Struct:
   149  			fl = append(fl, &fieldInfo{typ: t}) // identity node
   150  			for i, n := 0, t.NumFields(); i < n; i++ {
   151  				f := t.Field(i)
   152  				for _, fi := range a.flatten(f.Type()) {
   153  					fl = append(fl, &fieldInfo{typ: fi.typ, op: f, tail: fi})
   154  				}
   155  			}
   156  
   157  		case *types.Tuple:
   158  			// No identity node: tuples are never address-taken.
   159  			n := t.Len()
   160  			if n == 1 {
   161  				// Don't add a fieldInfo link for singletons,
   162  				// e.g. in params/results.
   163  				fl = append(fl, a.flatten(t.At(0).Type())...)
   164  			} else {
   165  				for i := 0; i < n; i++ {
   166  					f := t.At(i)
   167  					for _, fi := range a.flatten(f.Type()) {
   168  						fl = append(fl, &fieldInfo{typ: fi.typ, op: i, tail: fi})
   169  					}
   170  				}
   171  			}
   172  
   173  		default:
   174  			panic(t)
   175  		}
   176  
   177  		a.flattenMemo[t] = fl
   178  	}
   179  
   180  	return fl
   181  }
   182  
   183  // sizeof returns the number of pointerlike abstractions (nodes) in the type t.
   184  func (a *analysis) sizeof(t types.Type) uint32 {
   185  	return uint32(len(a.flatten(t)))
   186  }
   187  
   188  // shouldTrack reports whether object type T contains (recursively)
   189  // any fields whose addresses should be tracked.
   190  func (a *analysis) shouldTrack(T types.Type) bool {
   191  	if a.track == trackAll {
   192  		return true // fast path
   193  	}
   194  	track, ok := a.trackTypes[T]
   195  	if !ok {
   196  		a.trackTypes[T] = true // break cycles conservatively
   197  		// NB: reflect.Value, reflect.Type are pre-populated to true.
   198  		for _, fi := range a.flatten(T) {
   199  			switch ft := fi.typ.Underlying().(type) {
   200  			case *types.Interface, *types.Signature:
   201  				track = true // needed for callgraph
   202  			case *types.Basic:
   203  				// no-op
   204  			case *types.Chan:
   205  				track = a.track&trackChan != 0 || a.shouldTrack(ft.Elem())
   206  			case *types.Map:
   207  				track = a.track&trackMap != 0 || a.shouldTrack(ft.Key()) || a.shouldTrack(ft.Elem())
   208  			case *types.Slice:
   209  				track = a.track&trackSlice != 0 || a.shouldTrack(ft.Elem())
   210  			case *types.Pointer:
   211  				track = a.track&trackPtr != 0 || a.shouldTrack(ft.Elem())
   212  			case *types.Array, *types.Struct:
   213  				// No need to look at field types since they will follow (flattened).
   214  			default:
   215  				// Includes *types.Tuple, which are never address-taken.
   216  				panic(ft)
   217  			}
   218  			if track {
   219  				break
   220  			}
   221  		}
   222  		a.trackTypes[T] = track
   223  		if !track && a.log != nil {
   224  			fmt.Fprintf(a.log, "\ttype not tracked: %s\n", T)
   225  		}
   226  	}
   227  	return track
   228  }
   229  
   230  // offsetOf returns the (abstract) offset of field index within struct
   231  // or tuple typ.
   232  func (a *analysis) offsetOf(typ types.Type, index int) uint32 {
   233  	var offset uint32
   234  	switch t := typ.Underlying().(type) {
   235  	case *types.Tuple:
   236  		for i := 0; i < index; i++ {
   237  			offset += a.sizeof(t.At(i).Type())
   238  		}
   239  	case *types.Struct:
   240  		offset++ // the node for the struct itself
   241  		for i := 0; i < index; i++ {
   242  			offset += a.sizeof(t.Field(i).Type())
   243  		}
   244  	default:
   245  		panic(fmt.Sprintf("offsetOf(%s : %T)", typ, typ))
   246  	}
   247  	return offset
   248  }
   249  
   250  // sliceToArray returns the type representing the arrays to which
   251  // slice type slice points.
   252  func sliceToArray(slice types.Type) *types.Array {
   253  	return types.NewArray(slice.Underlying().(*types.Slice).Elem(), 1)
   254  }
   255  
   256  // Node set -------------------------------------------------------------------
   257  
   258  type nodeset struct {
   259  	intsets.Sparse
   260  }
   261  
   262  func (ns *nodeset) String() string {
   263  	var buf bytes.Buffer
   264  	buf.WriteRune('{')
   265  	var space [50]int
   266  	for i, n := range ns.AppendTo(space[:0]) {
   267  		if i > 0 {
   268  			buf.WriteString(", ")
   269  		}
   270  		buf.WriteRune('n')
   271  		fmt.Fprintf(&buf, "%d", n)
   272  	}
   273  	buf.WriteRune('}')
   274  	return buf.String()
   275  }
   276  
   277  func (ns *nodeset) add(n nodeid) bool {
   278  	return ns.Sparse.Insert(int(n))
   279  }
   280  
   281  func (x *nodeset) addAll(y *nodeset) bool {
   282  	return x.UnionWith(&y.Sparse)
   283  }
   284  
   285  // Profiling & debugging -------------------------------------------------------
   286  
   287  var timers = make(map[string]time.Time)
   288  
   289  func start(name string) {
   290  	if debugTimers {
   291  		timers[name] = time.Now()
   292  		log.Printf("%s...\n", name)
   293  	}
   294  }
   295  
   296  func stop(name string) {
   297  	if debugTimers {
   298  		log.Printf("%s took %s\n", name, time.Since(timers[name]))
   299  	}
   300  }
   301  
   302  // diff runs the command "diff a b" and reports its success.
   303  func diff(a, b string) bool {
   304  	var cmd *exec.Cmd
   305  	switch runtime.GOOS {
   306  	case "plan9":
   307  		cmd = exec.Command("/bin/diff", "-c", a, b)
   308  	default:
   309  		cmd = exec.Command("/usr/bin/diff", "-u", a, b)
   310  	}
   311  	cmd.Stdout = os.Stderr
   312  	cmd.Stderr = os.Stderr
   313  	return cmd.Run() == nil
   314  }