]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/escape/assign.go
cmd/compile: restore zero-copy string->[]byte optimization
[gostls13.git] / src / cmd / compile / internal / escape / assign.go
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                 e.assignHeap(n.Index, "key of map put", n)
54         }
55
56         return k
57 }
58
59 func (e *escape) mutate(n ir.Node) {
60         e.expr(e.mutatorHole(), n)
61 }
62
63 func (e *escape) addrs(l ir.Nodes) []hole {
64         var ks []hole
65         for _, n := range l {
66                 ks = append(ks, e.addr(n))
67         }
68         return ks
69 }
70
71 func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) {
72         e.expr(e.heapHole().note(where, why), src)
73 }
74
75 // assignList evaluates the assignment dsts... = srcs....
76 func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) {
77         ks := e.addrs(dsts)
78         for i, k := range ks {
79                 var src ir.Node
80                 if i < len(srcs) {
81                         src = srcs[i]
82                 }
83
84                 if dst := dsts[i]; dst != nil {
85                         // Detect implicit conversion of uintptr to unsafe.Pointer when
86                         // storing into reflect.{Slice,String}Header.
87                         if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) {
88                                 e.unsafeValue(e.heapHole().note(where, why), src)
89                                 continue
90                         }
91
92                         // Filter out some no-op assignments for escape analysis.
93                         if src != nil && isSelfAssign(dst, src) {
94                                 if base.Flag.LowerM != 0 {
95                                         base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where)
96                                 }
97                                 k = e.discardHole()
98                         }
99                 }
100
101                 e.expr(k.note(where, why), src)
102         }
103
104         e.reassigned(ks, where)
105 }
106
107 // reassigned marks the locations associated with the given holes as
108 // reassigned, unless the location represents a variable declared and
109 // assigned exactly once by where.
110 func (e *escape) reassigned(ks []hole, where ir.Node) {
111         if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil {
112                 if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil {
113                         // Zero-value assignment for variable declared without an
114                         // explicit initial value. Assume this is its initialization
115                         // statement.
116                         return
117                 }
118         }
119
120         for _, k := range ks {
121                 loc := k.dst
122                 // Variables declared by range statements are assigned on every iteration.
123                 if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE {
124                         continue
125                 }
126                 loc.reassigned = true
127         }
128 }