...
▽

Source file src/cmd/compile/internal/escape/assign.go

Documentation: cmd/compile/internal/escape

     1  // Copyright 2018 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 escape
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  )
    11  
    12  // addr evaluates an addressable expression n and returns a hole
    13  // that represents storing into the represented location.
    14  func (e *escape) addr(n ir.Node) hole {
    15  	if n == nil || ir.IsBlank(n) {
    16  		// Can happen in select case, range, maybe others.
    17  		return e.discardHole()
    18  	}
    19  
    20  	k := e.heapHole()
    21  
    22  	switch n.Op() {
    23  	default:
    24  		base.Fatalf("unexpected addr: %v", n)
    25  	case ir.ONAME:
    26  		n := n.(*ir.Name)
    27  		if n.Class == ir.PEXTERN {
    28  			break
    29  		}
    30  		k = e.oldLoc(n).asHole()
    31  	case ir.OLINKSYMOFFSET:
    32  		break
    33  	case ir.ODOT:
    34  		n := n.(*ir.SelectorExpr)
    35  		k = e.addr(n.X)
    36  	case ir.OINDEX:
    37  		n := n.(*ir.IndexExpr)
    38  		e.discard(n.Index)
    39  		if n.X.Type().IsArray() {
    40  			k = e.addr(n.X)
    41  		} else {
    42  			e.mutate(n.X)
    43  		}
    44  	case ir.ODEREF:
    45  		n := n.(*ir.StarExpr)
    46  		e.mutate(n.X)
    47  	case ir.ODOTPTR:
    48  		n := n.(*ir.SelectorExpr)
    49  		e.mutate(n.X)
    50  	case ir.OINDEXMAP:
    51  		n := n.(*ir.IndexExpr)
    52  		e.discard(n.X)
    53  		// Keys used in map assignments must escape.
    54  		// See "Hashing Pointers" doc in internal/runtime/maps/map.go.
    55  		e.assignHeap(n.Index, "key of map put", n)
    56  	}
    57  
    58  	return k
    59  }
    60  
    61  func (e *escape) mutate(n ir.Node) {
    62  	e.expr(e.mutatorHole(), n)
    63  }
    64  
    65  func (e *escape) addrs(l ir.Nodes) []hole {
    66  	var ks []hole
    67  	for _, n := range l {
    68  		ks = append(ks, e.addr(n))
    69  	}
    70  	return ks
    71  }
    72  
    73  func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) {
    74  	e.expr(e.heapHole().note(where, why), src)
    75  }
    76  
    77  // assignList evaluates the assignment dsts... = srcs....
    78  func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) {
    79  	ks := e.addrs(dsts)
    80  	for i, k := range ks {
    81  		var src ir.Node
    82  		if i < len(srcs) {
    83  			src = srcs[i]
    84  		}
    85  
    86  		if dst := dsts[i]; dst != nil {
    87  			// Detect implicit conversion of uintptr to unsafe.Pointer when
    88  			// storing into reflect.{Slice,String}Header.
    89  			if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) {
    90  				e.unsafeValue(e.heapHole().note(where, why), src)
    91  				continue
    92  			}
    93  
    94  			// Filter out some no-op assignments for escape analysis.
    95  			if src != nil && isSelfAssign(dst, src) {
    96  				if base.Flag.LowerM != 0 {
    97  					base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where)
    98  				}
    99  				k = e.discardHole()
   100  			}
   101  		}
   102  
   103  		e.expr(k.note(where, why), src)
   104  	}
   105  
   106  	e.reassigned(ks, where)
   107  }
   108  
   109  // reassigned marks the locations associated with the given holes as
   110  // reassigned, unless the location represents a variable declared and
   111  // assigned exactly once by where.
   112  func (e *escape) reassigned(ks []hole, where ir.Node) {
   113  	if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil {
   114  		if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil {
   115  			// Zero-value assignment for variable declared without an
   116  			// explicit initial value. Assume this is its initialization
   117  			// statement.
   118  			return
   119  		}
   120  	}
   121  
   122  	for _, k := range ks {
   123  		loc := k.dst
   124  		// Variables declared by range statements are assigned on every iteration.
   125  		if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE {
   126  			continue
   127  		}
   128  		loc.reassigned = true
   129  	}
   130  }
   131  

View as plain text