1
2
3
4
5 package escape
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/typecheck"
11 "cmd/compile/internal/types"
12 "go/constant"
13 "go/token"
14 )
15
16 func isSliceSelfAssign(dst, src ir.Node) bool {
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 var dstX ir.Node
34 switch dst.Op() {
35 default:
36 return false
37 case ir.ODEREF:
38 dst := dst.(*ir.StarExpr)
39 dstX = dst.X
40 case ir.ODOTPTR:
41 dst := dst.(*ir.SelectorExpr)
42 dstX = dst.X
43 }
44 if dstX.Op() != ir.ONAME {
45 return false
46 }
47
48 switch src.Op() {
49 case ir.OSLICE, ir.OSLICE3, ir.OSLICESTR:
50
51 case ir.OSLICEARR, ir.OSLICE3ARR:
52
53
54
55
56
57
58
59
60
61 src := src.(*ir.SliceExpr)
62 if src.X.Op() == ir.OADDR {
63 return false
64 }
65 default:
66 return false
67 }
68
69 var baseX ir.Node
70 switch base := src.(*ir.SliceExpr).X; base.Op() {
71 default:
72 return false
73 case ir.ODEREF:
74 base := base.(*ir.StarExpr)
75 baseX = base.X
76 case ir.ODOTPTR:
77 base := base.(*ir.SelectorExpr)
78 baseX = base.X
79 }
80 if baseX.Op() != ir.ONAME {
81 return false
82 }
83
84 return dstX.(*ir.Name) == baseX.(*ir.Name)
85 }
86
87
88
89 func isSelfAssign(dst, src ir.Node) bool {
90 if isSliceSelfAssign(dst, src) {
91 return true
92 }
93
94
95
96
97
98
99
100
101
102
103
104 if dst == nil || src == nil || dst.Op() != src.Op() {
105 return false
106 }
107
108
109 switch dst.Op() {
110 case ir.ODOT, ir.ODOTPTR:
111
112 dst := dst.(*ir.SelectorExpr)
113 src := src.(*ir.SelectorExpr)
114 return ir.SameSafeExpr(dst.X, src.X)
115 case ir.OINDEX:
116 dst := dst.(*ir.IndexExpr)
117 src := src.(*ir.IndexExpr)
118 if mayAffectMemory(dst.Index) || mayAffectMemory(src.Index) {
119 return false
120 }
121 return ir.SameSafeExpr(dst.X, src.X)
122 default:
123 return false
124 }
125 }
126
127
128
129
130 func mayAffectMemory(n ir.Node) bool {
131
132
133
134
135
136
137
138
139
140
141 switch n.Op() {
142 case ir.ONAME, ir.OLITERAL, ir.ONIL:
143 return false
144
145 case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
146 n := n.(*ir.BinaryExpr)
147 return mayAffectMemory(n.X) || mayAffectMemory(n.Y)
148
149 case ir.OINDEX:
150 n := n.(*ir.IndexExpr)
151 return mayAffectMemory(n.X) || mayAffectMemory(n.Index)
152
153 case ir.OCONVNOP, ir.OCONV:
154 n := n.(*ir.ConvExpr)
155 return mayAffectMemory(n.X)
156
157 case ir.OLEN, ir.OCAP, ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
158 n := n.(*ir.UnaryExpr)
159 return mayAffectMemory(n.X)
160
161 case ir.ODOT, ir.ODOTPTR:
162 n := n.(*ir.SelectorExpr)
163 return mayAffectMemory(n.X)
164
165 case ir.ODEREF:
166 n := n.(*ir.StarExpr)
167 return mayAffectMemory(n.X)
168
169 default:
170 return true
171 }
172 }
173
174
175
176 func HeapAllocReason(n ir.Node) string {
177 if n == nil || n.Type() == nil {
178 return ""
179 }
180
181
182 if n.Op() == ir.ONAME {
183 n := n.(*ir.Name)
184 if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
185 return ""
186 }
187 }
188
189 if n.Type().Size() > ir.MaxStackVarSize {
190 return "too large for stack"
191 }
192 if n.Type().Alignment() > int64(types.PtrSize) {
193 return "too aligned for stack"
194 }
195
196 if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Size() > ir.MaxImplicitStackVarSize {
197 return "too large for stack"
198 }
199 if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Alignment() > int64(types.PtrSize) {
200 return "too aligned for stack"
201 }
202
203 if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() > ir.MaxImplicitStackVarSize {
204 return "too large for stack"
205 }
206 if n.Op() == ir.OMETHVALUE && typecheck.MethodValueType(n.(*ir.SelectorExpr)).Size() > ir.MaxImplicitStackVarSize {
207 return "too large for stack"
208 }
209
210 if n.Op() == ir.OMAKESLICE {
211 n := n.(*ir.MakeExpr)
212
213 r := &n.Cap
214 if n.Cap == nil {
215 r = &n.Len
216 }
217
218
219
220 if s := ir.StaticValue(*r); s.Op() == ir.OLITERAL {
221 lit, ok := s.(*ir.BasicLit)
222 if !ok || lit.Val().Kind() != constant.Int {
223 base.Fatalf("unexpected BasicLit Kind")
224 }
225 if constant.Compare(lit.Val(), token.GEQ, constant.MakeInt64(0)) {
226 *r = lit
227 }
228 }
229
230 elem := n.Type().Elem()
231 if elem.Size() == 0 {
232
233 return "zero-sized element"
234 }
235 if !ir.IsSmallIntConst(*r) {
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 return ""
251 }
252 if ir.Int64Val(*r) > ir.MaxImplicitStackVarSize/elem.Size() {
253 return "too large for stack"
254 }
255 }
256
257 return ""
258 }
259
View as plain text