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