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