1
2
3
4
5 package ir
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/types"
10 "cmd/internal/obj"
11 "cmd/internal/src"
12 "fmt"
13 )
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 type Func struct {
52 miniNode
53 Body Nodes
54 Iota int64
55
56 Nname *Name
57 OClosure *ClosureExpr
58
59 Shortname *types.Sym
60
61
62
63 Enter Nodes
64 Exit Nodes
65
66
67
68
69
70
71
72
73 Dcl []*Name
74
75
76
77
78
79
80
81 ClosureVars []*Name
82
83
84
85 Closures []*Func
86
87
88
89
90 Parents []ScopeID
91
92
93 Marks []Mark
94
95 FieldTrack map[*obj.LSym]struct{}
96 DebugInfo interface{}
97 LSym *obj.LSym
98
99 Inl *Inline
100
101
102
103
104 Closgen int32
105
106 Label int32
107
108 Endlineno src.XPos
109 WBPos src.XPos
110
111 Pragma PragmaFlag
112
113 flags bitset16
114
115
116
117
118
119
120
121
122 ABI obj.ABI
123
124
125
126
127 ABIRefs obj.ABISet
128
129 NumDefers int32
130 NumReturns int32
131
132
133
134
135 NWBRCalls *[]SymAndPos
136
137
138
139 WrappedFunc *Func
140 }
141
142 func NewFunc(pos src.XPos) *Func {
143 f := new(Func)
144 f.pos = pos
145 f.op = ODCLFUNC
146 f.Iota = -1
147
148
149 f.ABI = obj.ABIInternal
150 return f
151 }
152
153 func (f *Func) isStmt() {}
154
155 func (n *Func) copy() Node { panic(n.no("copy")) }
156 func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
157 func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
158
159 func (f *Func) Type() *types.Type { return f.Nname.Type() }
160 func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
161 func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
162 func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
163
164
165 type Inline struct {
166 Cost int32
167
168
169
170
171
172 Dcl []*Name
173 Body []Node
174
175
176
177
178 CanDelayResults bool
179 }
180
181
182 type Mark struct {
183
184
185 Pos src.XPos
186
187
188 Scope ScopeID
189 }
190
191
192 type ScopeID int32
193
194 const (
195 funcDupok = 1 << iota
196 funcWrapper
197 funcABIWrapper
198 funcNeedctxt
199 funcReflectMethod
200
201
202 funcIsHiddenClosure
203 funcIsDeadcodeClosure
204 funcHasDefer
205 funcNilCheckDisabled
206 funcInlinabilityChecked
207 funcExportInline
208 funcInstrumentBody
209 funcOpenCodedDeferDisallowed
210 funcClosureCalled
211 )
212
213 type SymAndPos struct {
214 Sym *obj.LSym
215 Pos src.XPos
216 }
217
218 func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
219 func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
220 func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 }
221 func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
222 func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 }
223 func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
224 func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 }
225 func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
226 func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
227 func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
228 func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 }
229 func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 }
230 func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
231 func (f *Func) ClosureCalled() bool { return f.flags&funcClosureCalled != 0 }
232
233 func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
234 func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
235 func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) }
236 func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
237 func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) }
238 func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
239 func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) }
240 func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
241 func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
242 func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
243 func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInline, b) }
244 func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) }
245 func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
246 func (f *Func) SetClosureCalled(b bool) { f.flags.set(funcClosureCalled, b) }
247
248 func (f *Func) SetWBPos(pos src.XPos) {
249 if base.Debug.WB != 0 {
250 base.WarnfAt(pos, "write barrier")
251 }
252 if !f.WBPos.IsKnown() {
253 f.WBPos = pos
254 }
255 }
256
257
258 func FuncName(f *Func) string {
259 if f == nil || f.Nname == nil {
260 return "<nil>"
261 }
262 return f.Sym().Name
263 }
264
265
266
267
268
269 func PkgFuncName(f *Func) string {
270 if f == nil || f.Nname == nil {
271 return "<nil>"
272 }
273 s := f.Sym()
274 pkg := s.Pkg
275
276 p := base.Ctxt.Pkgpath
277 if pkg != nil && pkg.Path != "" {
278 p = pkg.Path
279 }
280 if p == "" {
281 return s.Name
282 }
283 return p + "." + s.Name
284 }
285
286 var CurFunc *Func
287
288
289
290
291 func WithFunc(curfn *Func, do func()) {
292 oldfn, oldpos := CurFunc, base.Pos
293 defer func() { CurFunc, base.Pos = oldfn, oldpos }()
294
295 CurFunc, base.Pos = curfn, curfn.Pos()
296 do()
297 }
298
299 func FuncSymName(s *types.Sym) string {
300 return s.Name + "·f"
301 }
302
303
304 func MarkFunc(n *Name) {
305 if n.Op() != ONAME || n.Class != Pxxx {
306 base.FatalfAt(n.Pos(), "expected ONAME/Pxxx node, got %v (%v/%v)", n, n.Op(), n.Class)
307 }
308
309 n.Class = PFUNC
310 n.Sym().SetFunc(true)
311 }
312
313
314
315 func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
316 if base.Debug.Closure > 0 {
317 if clo.Esc() == EscHeap {
318 base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
319 } else {
320 base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
321 }
322 }
323 if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
324 base.ErrorfAt(clo.Pos(), "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
325 }
326 }
327
328
329
330 func IsTrivialClosure(clo *ClosureExpr) bool {
331 return len(clo.Func.ClosureVars) == 0
332 }
333
334
335 var globClosgen int32
336
337
338 func closureName(outerfn *Func) *types.Sym {
339 pkg := types.LocalPkg
340 outer := "glob."
341 prefix := "func"
342 gen := &globClosgen
343
344 if outerfn != nil {
345 if outerfn.OClosure != nil {
346 prefix = ""
347 }
348
349 pkg = outerfn.Sym().Pkg
350 outer = FuncName(outerfn)
351
352
353
354
355 if !IsBlank(outerfn.Nname) {
356 gen = &outerfn.Closgen
357 }
358 }
359
360 *gen++
361 return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
362 }
363
364
365
366
367
368 func NewClosureFunc(pos src.XPos, hidden bool) *Func {
369 fn := NewFunc(pos)
370 fn.SetIsHiddenClosure(hidden)
371
372 fn.Nname = NewNameAt(pos, BlankNode.Sym())
373 fn.Nname.Func = fn
374 fn.Nname.Defn = fn
375
376 fn.OClosure = NewClosureExpr(pos, fn)
377
378 return fn
379 }
380
381
382
383 func NameClosure(clo *ClosureExpr, outerfn *Func) {
384 fn := clo.Func
385 if fn.IsHiddenClosure() != (outerfn != nil) {
386 base.FatalfAt(clo.Pos(), "closure naming inconsistency: hidden %v, but outer %v", fn.IsHiddenClosure(), outerfn)
387 }
388
389 name := fn.Nname
390 if !IsBlank(name) {
391 base.FatalfAt(clo.Pos(), "closure already named: %v", name)
392 }
393
394 name.SetSym(closureName(outerfn))
395 MarkFunc(name)
396 }
397
398
399
400
401 func UseClosure(clo *ClosureExpr, pkg *Package) Node {
402 fn := clo.Func
403 name := fn.Nname
404
405 if IsBlank(name) {
406 base.FatalfAt(fn.Pos(), "unnamed closure func: %v", fn)
407 }
408
409
410 if fn.Typecheck() != 1 || name.Typecheck() != 1 {
411 base.FatalfAt(fn.Pos(), "missed typecheck: %v", fn)
412 }
413 if clo.Type() == nil || name.Type() == nil {
414 base.FatalfAt(fn.Pos(), "missing types: %v", fn)
415 }
416 if !types.Identical(clo.Type(), name.Type()) {
417 base.FatalfAt(fn.Pos(), "mismatched types: %v", fn)
418 }
419
420 if base.Flag.W > 1 {
421 s := fmt.Sprintf("new closure func: %v", fn)
422 Dump(s, fn)
423 }
424
425 if pkg != nil {
426 pkg.Decls = append(pkg.Decls, fn)
427 }
428
429 if false && IsTrivialClosure(clo) {
430
431
432
433
434
435 }
436
437 return clo
438 }
439
View as plain text