1
2
3
4
5 package ir
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/types"
10 "cmd/internal/hash"
11 "cmd/internal/obj"
12 "cmd/internal/objabi"
13 "cmd/internal/src"
14 "encoding/base64"
15 "fmt"
16 "unicode/utf8"
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
52
53
54 type Func struct {
55
56
57 miniNode
58 Body Nodes
59
60 Nname *Name
61 OClosure *ClosureExpr
62
63
64
65
66
67
68 Dcl []*Name
69
70
71
72
73
74
75
76 ClosureVars []*Name
77
78
79
80 Closures []*Func
81
82
83 ClosureParent *Func
84
85
86
87
88 Parents []ScopeID
89
90
91 Marks []Mark
92
93 FieldTrack map[*obj.LSym]struct{}
94 DebugInfo any
95 LSym *obj.LSym
96
97 Inl *Inline
98
99
100
101 RangeParent *Func
102
103
104
105
106
107
108
109 funcLitGen int32
110 rangeLitGen int32
111 goDeferGen int32
112
113 Label int32
114
115 Endlineno src.XPos
116 WBPos src.XPos
117
118 Pragma PragmaFlag
119
120 flags bitset16
121
122
123
124
125
126
127
128
129 ABI obj.ABI
130
131
132
133
134 ABIRefs obj.ABISet
135
136 NumDefers int32
137 NumReturns int32
138
139
140
141
142 NWBRCalls *[]SymAndPos
143
144
145
146 WrappedFunc *Func
147
148
149
150 WasmImport *WasmImport
151
152
153 WasmExport *WasmExport
154 }
155
156
157 type WasmImport struct {
158 Module string
159 Name string
160 }
161
162
163 type WasmExport struct {
164 Name string
165 }
166
167
168
169
170
171
172
173
174 func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
175 name := NewNameAt(npos, sym, typ)
176 name.Class = PFUNC
177 sym.SetFunc(true)
178
179 fn := &Func{Nname: name}
180 fn.pos = fpos
181 fn.op = ODCLFUNC
182
183
184 fn.ABI = obj.ABIInternal
185 fn.SetTypecheck(1)
186
187 name.Func = fn
188
189 return fn
190 }
191
192 func (f *Func) isStmt() {}
193
194 func (n *Func) copy() Node { panic(n.no("copy")) }
195 func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
196 func (n *Func) doChildrenWithHidden(do func(Node) bool) bool { return doNodes(n.Body, do) }
197 func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
198 func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
199
200 func (f *Func) Type() *types.Type { return f.Nname.Type() }
201 func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
202 func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
203 func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
204
205
206 type Inline struct {
207 Cost int32
208
209
210
211
212
213 Dcl []*Name
214 HaveDcl bool
215
216
217
218 Properties string
219
220
221
222
223 CanDelayResults bool
224 }
225
226
227 type Mark struct {
228
229
230 Pos src.XPos
231
232
233 Scope ScopeID
234 }
235
236
237 type ScopeID int32
238
239 const (
240 funcDupok = 1 << iota
241 funcWrapper
242 funcABIWrapper
243 funcNeedctxt
244 funcHasDefer
245 funcNilCheckDisabled
246 funcInlinabilityChecked
247 funcNeverReturns
248 funcOpenCodedDeferDisallowed
249 funcClosureResultsLost
250 funcPackageInit
251 )
252
253 type SymAndPos struct {
254 Sym *obj.LSym
255 Pos src.XPos
256 }
257
258 func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
259 func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
260 func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 }
261 func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
262 func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
263 func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
264 func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
265 func (f *Func) NeverReturns() bool { return f.flags&funcNeverReturns != 0 }
266 func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
267 func (f *Func) ClosureResultsLost() bool { return f.flags&funcClosureResultsLost != 0 }
268 func (f *Func) IsPackageInit() bool { return f.flags&funcPackageInit != 0 }
269
270 func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
271 func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
272 func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) }
273 func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
274 func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
275 func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
276 func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
277 func (f *Func) SetNeverReturns(b bool) { f.flags.set(funcNeverReturns, b) }
278 func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
279 func (f *Func) SetClosureResultsLost(b bool) { f.flags.set(funcClosureResultsLost, b) }
280 func (f *Func) SetIsPackageInit(b bool) { f.flags.set(funcPackageInit, b) }
281
282 func (f *Func) SetWBPos(pos src.XPos) {
283 if base.Debug.WB != 0 {
284 base.WarnfAt(pos, "write barrier")
285 }
286 if !f.WBPos.IsKnown() {
287 f.WBPos = pos
288 }
289 }
290
291
292 func (f *Func) IsClosure() bool {
293 if f.OClosure == nil {
294 return false
295 }
296 return len(f.ClosureVars) > 0
297 }
298
299
300 func FuncName(f *Func) string {
301 if f == nil || f.Nname == nil {
302 return "<nil>"
303 }
304 return f.Sym().Name
305 }
306
307
308
309
310
311
312
313 func PkgFuncName(f *Func) string {
314 if f == nil || f.Nname == nil {
315 return "<nil>"
316 }
317 s := f.Sym()
318 pkg := s.Pkg
319 if pkg == nil {
320 return "<nil>." + s.Name
321 }
322 return pkg.Path + "." + s.Name
323 }
324
325
326
327 func LinkFuncName(f *Func) string {
328 if f == nil || f.Nname == nil {
329 return "<nil>"
330 }
331 s := f.Sym()
332 pkg := s.Pkg
333
334 return objabi.PathToPrefix(pkg.Path) + "." + s.Name
335 }
336
337
338
339 func ParseLinkFuncName(name string) (pkg, sym string, err error) {
340 pkg, sym = splitPkg(name)
341 if pkg == "" {
342 return "", "", fmt.Errorf("no package path in name")
343 }
344
345 pkg, err = objabi.PrefixToPath(pkg)
346 if err != nil {
347 return "", "", fmt.Errorf("malformed package path: %v", err)
348 }
349
350 return pkg, sym, nil
351 }
352
353
354 func modPathOK(r rune) bool {
355 if r < utf8.RuneSelf {
356 return r == '-' || r == '.' || r == '_' || r == '~' ||
357 '0' <= r && r <= '9' ||
358 'A' <= r && r <= 'Z' ||
359 'a' <= r && r <= 'z'
360 }
361 return false
362 }
363
364 func escapedImportPathOK(r rune) bool {
365 return modPathOK(r) || r == '+' || r == '/' || r == '%'
366 }
367
368
369
370 func splitPkg(name string) (pkgpath, sym string) {
371
372
373
374 lastSlashIdx := 0
375 for i, r := range name {
376
377
378
379
380
381 if !escapedImportPathOK(r) {
382 break
383 }
384 if r == '/' {
385 lastSlashIdx = i
386 }
387 }
388 for i := lastSlashIdx; i < len(name); i++ {
389 r := name[i]
390 if r == '.' {
391 return name[:i], name[i+1:]
392 }
393 }
394
395 return "", name
396 }
397
398 var CurFunc *Func
399
400
401
402
403 func WithFunc(curfn *Func, do func()) {
404 oldfn, oldpos := CurFunc, base.Pos
405 defer func() { CurFunc, base.Pos = oldfn, oldpos }()
406
407 CurFunc, base.Pos = curfn, curfn.Pos()
408 do()
409 }
410
411 func FuncSymName(s *types.Sym) string {
412 return s.Name + "·f"
413 }
414
415
416
417 func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
418 if base.Debug.Closure > 0 {
419 if clo.Esc() == EscHeap {
420 base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
421 } else {
422 base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
423 }
424 }
425 if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
426 base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
427 }
428 }
429
430
431 var globClosgen int32
432
433
434
435
436 func closureName(outerfn *Func, pos src.XPos, why Op, gen int) *types.Sym {
437 pkg := types.LocalPkg
438 outer := "glob."
439 var suffix string = "."
440 switch why {
441 default:
442 base.FatalfAt(pos, "closureName: bad Op: %v", why)
443 case OCLOSURE:
444 if outerfn.OClosure == nil {
445 suffix = ".func"
446 }
447 case ORANGE:
448 suffix = "-range"
449 case OGO:
450 suffix = ".gowrap"
451 case ODEFER:
452 suffix = ".deferwrap"
453 }
454
455
456
457
458 if !IsBlank(outerfn.Nname) {
459 pkg = outerfn.Sym().Pkg
460 outer = FuncName(outerfn)
461 }
462
463
464
465 var inlHash string
466 if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
467
468
469
470
471
472
473 h := hash.New32()
474 fmt.Fprint(h, inlIndex)
475 base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
476 if call.Parent >= 0 {
477 fmt.Fprint(h, " ", call.Parent)
478 }
479 })
480 inlHash = base64.StdEncoding.EncodeToString(h.Sum(nil)[:8])
481
482 outer = base.Ctxt.InlTree.InlinedFuncName(inlIndex)
483 if pkgPath := base.Ctxt.InlTree.InlinedFuncPkg(inlIndex); pkgPath != "" {
484 pkg = types.NewPkg(pkgPath, "")
485 }
486 }
487
488 if gen == 0 {
489 p := &globClosgen
490 if !IsBlank(outerfn.Nname) {
491 switch why {
492 case OCLOSURE:
493 p = &outerfn.funcLitGen
494 case ORANGE:
495 p = &outerfn.rangeLitGen
496 default:
497 p = &outerfn.goDeferGen
498 }
499 }
500 *p++
501 gen = int(*p)
502 }
503
504 name := fmt.Sprintf("%s%s%d", outer, suffix, gen)
505 if inlHash != "" {
506
507
508
509
510 name = obj.TrimInlineHash(name) + "#" + inlHash + "#"
511 }
512
513 return pkg.Lookup(name)
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534 func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package, gen int) *Func {
535 if outerfn == nil {
536 base.FatalfAt(fpos, "outerfn is nil")
537 }
538
539 fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why, gen), typ)
540 fn.SetDupok(outerfn.Dupok())
541
542 fn.Linksym().Set(obj.AttrContentAddressable, true)
543
544 clo := &ClosureExpr{Func: fn}
545 clo.op = OCLOSURE
546 clo.pos = cpos
547 clo.SetType(typ)
548 clo.SetTypecheck(1)
549 if why == ORANGE {
550 clo.Func.RangeParent = outerfn
551 if outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
552 clo.Func.RangeParent = outerfn.OClosure.Func.RangeParent
553 }
554 }
555 fn.OClosure = clo
556
557 fn.Nname.Defn = fn
558 pkg.Funcs = append(pkg.Funcs, fn)
559 fn.ClosureParent = outerfn
560
561 return fn
562 }
563
564
565 func IsFuncPCIntrinsic(n *CallExpr) bool {
566 if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
567 return false
568 }
569 fn := n.Fun.(*Name).Sym()
570 return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
571 fn.Pkg.Path == "internal/abi"
572 }
573
574
575
576
577
578
579 func IsIfaceOfFunc(n Node) *Func {
580 if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
581 if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
582 return name.Func
583 }
584 }
585 return nil
586 }
587
588
589
590
591
592
593
594
595
596
597 func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
598 if !n.Type().IsInterface() {
599 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
600 }
601
602 if fn := IsIfaceOfFunc(n); fn != nil {
603 name := fn.Nname
604 abi := fn.ABI
605 if abi != wantABI {
606 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
607 }
608 var e Node = NewLinksymExpr(pos, name.LinksymABI(abi), types.Types[types.TUINTPTR])
609 e = NewAddrExpr(pos, e)
610 e.SetType(types.Types[types.TUINTPTR].PtrTo())
611 e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
612 e.SetTypecheck(1)
613 return e
614 }
615
616
617 if wantABI != obj.ABIInternal {
618 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
619 }
620 var e Node = NewUnaryExpr(pos, OIDATA, n)
621 e.SetType(types.Types[types.TUINTPTR].PtrTo())
622 e.SetTypecheck(1)
623 e = NewStarExpr(pos, e)
624 e.SetType(types.Types[types.TUINTPTR])
625 e.SetTypecheck(1)
626 return e
627 }
628
629
630
631
632
633
634 func (fn *Func) DeclareParams(setNname bool) {
635 if fn.Dcl != nil {
636 base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
637 }
638
639 declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
640 for i, param := range params {
641 sym := param.Sym
642 if sym == nil || sym.IsBlank() {
643 sym = fn.Sym().Pkg.LookupNum(prefix, i)
644 }
645
646 name := NewNameAt(param.Pos, sym, param.Type)
647 name.Class = ctxt
648 name.Curfn = fn
649 fn.Dcl[offset+i] = name
650
651 if setNname {
652 param.Nname = name
653 }
654 }
655 }
656
657 sig := fn.Type()
658 params := sig.RecvParams()
659 results := sig.Results()
660
661 fn.Dcl = make([]*Name, len(params)+len(results))
662 declareParams(params, PPARAM, "~p", 0)
663 declareParams(results, PPARAMOUT, "~r", len(params))
664 }
665
666
667 func ContainsClosure(f, c *Func) bool {
668
669 if f == c || c.OClosure == nil {
670 return false
671 }
672
673 for p := c.ClosureParent; p != nil; p = p.ClosureParent {
674 if p == f {
675 return true
676 }
677 }
678 return false
679 }
680
View as plain text